Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/src/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 173 kB image not shown  

Quelle  compiler.c

  Sprache: C
 

/****************************************************************************
**
**  This file is part of GAP, a system for computational discrete algebra.
**
**  Copyright of GAP belongs to its developers, whose names are too numerous
**  to list here. Please refer to the COPYRIGHT file for details.
**
**  SPDX-License-Identifier: GPL-2.0-or-later
**
**  This file contains the GAP to C compiler.
*/


#include "compiler.h"

#include "ariths.h"
#include "bool.h"
#include "calls.h"
#include "code.h"
#include "error.h"
#include "exprs.h"
#include "gvars.h"
#include "integer.h"
#include "io.h"
#include "lists.h"
#include "modules.h"
#include "plist.h"
#include "records.h"
#include "stats.h"
#include "stringobj.h"
#include "sysopt.h"
#include "sysstr.h"
#include "vars.h"

#include <stdarg.h>


/****************************************************************************
**
*F * * * * * * * * * * * * * compilation flags  * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  CompFastIntArith  . . option to emit code that handles small ints. faster
*/

static Int CompFastIntArith;


/****************************************************************************
**
*V  CompFastPlainLists  . option to emit code that handles plain lists faster
*/

static Int CompFastPlainLists;


/****************************************************************************
**
*V  CompFastListFuncs . . option to emit code that inlines calls to functions
*/

static Int CompFastListFuncs;


/****************************************************************************
**
*V  CompCheckTypes . . . . option to emit code that assumes all types are ok.
*/

static Int CompCheckTypes;


/****************************************************************************
**
*V  CompCheckListElements .  option to emit code that assumes list elms exist
*/

static Int CompCheckListElements;


/****************************************************************************
**
*V  CompPass  . . . . . . . . . . . . . . . . . . . . . . . . . compiler pass
**
**  'CompPass' holds the number of the current pass.
**
**  The compiler does two passes over the source.
**
**  In the first pass it only collects information but emits no code.
**
**  It finds  out which global  variables and record names  are used, so that
**  the  compiler can output  code to define  and initialize global variables
**  'G_<name>' resp. 'R_<name>' to hold their identifiers.
**
**  It finds out   which arguments and local  variables  are used  as  higher
**  variables  from inside local functions,  so that  the compiler can output
**  code to allocate and manage a stack frame for them.
**
**  It finds out how many temporary variables are used, so that the compiler
**  can output code to define corresponding local variables.
**
**  In the second pass it emits code.
**
**  The only difference between the  first pass and  the second pass is  that
**  'Emit'  emits  no code  during the first  pass.   While  this causes many
**  unnecessary  computations during the first pass,  the  advantage is that
**  the two passes are guaranteed to do exactly the same computations.
*/

static Int CompPass;


/****************************************************************************
**
*F * * * * * * * * * * * * temp, C, local functions * * * * * * * * * * * * *
*/



/****************************************************************************
**
*T  CVar  . . . . . . . . . . . . . . . . . . . . . . .  type for C variables
**
**  A C variable represents the result of compiling an expression.  There are
**  three cases (distinguished by the least significant two bits).
**
**  If the  expression is an  immediate integer  expression, the  C  variable
**  contains the value of the immediate integer expression.
**
**  If the  expression is an immediate reference  to a  local variable, the C
**  variable contains the index of the local variable.
**
**  Otherwise the expression  compiler emits code  that puts the value of the
**  expression into a  temporary variable,  and  the C variable contains  the
**  index of that temporary variable.
*/

typedef UInt           CVar;

#define IS_INTG_CVAR(c) ((((UInt)(c)) & 0x03) == 0x01)
#define INTG_CVAR(c)    (((Int)(c)) >> 2)
#define CVAR_INTG(i)    ((((UInt)(i)) << 2) + 0x01)

#define IS_TEMP_CVAR(c) ((((UInt)(c)) & 0x03) == 0x02)
#define TEMP_CVAR(c)    (((UInt)(c)) >> 2)
#define CVAR_TEMP(l)    ((((UInt)(l)) << 2) + 0x02)

#define IS_LVAR_CVAR(c) ((((UInt)(c)) & 0x03) == 0x03)
#define LVAR_CVAR(c)    (((UInt)(c)) >> 2)
#define CVAR_LVAR(l)    ((((UInt)(l)) << 2) + 0x03)


/****************************************************************************
**
*F  SetInfoCVar( <cvar>, <type> ) . . . . . . .  set the type of a C variable
*F  GetInfoCVar( <cvar> ) . . . . . . . . . . .  get the type of a C variable
*F  HasInfoCVar( <cvar>, <type> ) . . . . . . . test the type of a C variable
**
*F  NewInfoCVars()  . . . . . . . . . allocate a new info bag for C variables
*F  CopyInfoCVars( <dst>, <src> ) . .  copy between info bags for C variables
*F  MergeInfoCVars( <dst>, <src> )  . . . merge two info bags for C variables
*F  IsEqInfoCVars( <dst>, <src> ) . . . compare two info bags for C variables
**
**  With each function we  associate a C  variables information bag.  In this
**  bag we store  the number of the  function, the number of local variables,
**  the  number of local  variables that  are used  as higher variables,  the
**  number  of temporaries  used,  the current  number  of used temporaries.
**
**  Furthermore for  each local variable and  temporary we store what we know
**  about this local variable or temporary, i.e., whether the variable has an
**  assigned value, whether that value is an integer, a boolean, etc.
**
**  'SetInfoCVar' sets the    information   for  the  C variable      <cvar>.
**  'GetInfoCVar' gets   the   information  for   the  C    variable  <cvar>.
**  'HasInfoCVar' returns true if the C variable <cvar> has the type <type>.
**
**  'NewInfoCVars'  creates    a    new    C  variables     information  bag.
**  'CopyInfoCVars' copies the C  variables information from <src> to  <dst>.
**  'MergeInfoCVars' merges the C variables information  from <src> to <dst>,
**  i.e., if there are two paths to a  certain place in  the source and <dst>
**  is the information gathered  along one path  and <src> is the information
**  gathered along the other path, then  'MergeInfoCVars' stores in <dst> the
**  information for   that   point  (independent   of  the  path  travelled).
**  'IsEqInfoCVars' returns   true  if <src>    and <dst> contain   the  same
**  information.
**
**  Note that  the numeric  values for the  types  are defined such  that  if
**  <type1> implies <type2>, then <type1> is a bitwise superset of <type2>.
*/

typedef UInt4           LVar;

#define INFO_FEXP(fexp)         PROF_FUNC(fexp)
#define SET_INFO_FEXP(fexp,x)   SET_PROF_FUNC(fexp,x)
#define NEXT_INFO(info)         PTR_BAG(info)[1]
#define NR_INFO(info)           (*((Int*)(PTR_BAG(info)+2)))
#define NLVAR_INFO(info)        (*((Int*)(PTR_BAG(info)+3)))
#define NHVAR_INFO(info)        (*((Int*)(PTR_BAG(info)+4)))
#define NTEMP_INFO(info)        (*((Int*)(PTR_BAG(info)+5)))
#define CTEMP_INFO(info)        (*((Int*)(PTR_BAG(info)+6)))
#define TNUM_LVAR_INFO(info,i)  (*((Int*)(PTR_BAG(info)+7+(i))))

#define TNUM_TEMP_INFO(info,i)  \
    (*((Int*)(PTR_BAG(info)+7+NLVAR_INFO(info)+(i))))

#define SIZE_INFO(nlvar,ntemp)  (sizeof(Int) * (1 + 7 + (nlvar) + (ntemp)))

#define W_UNUSED                0       // TEMP is currently unused
#define W_HIGHER                (1<<0) // LVAR is used as higher variable
#define W_UNKNOWN               ((1<<1) | W_HIGHER)
#define W_UNBOUND               ((1<<2) | W_UNKNOWN)
#define W_BOUND                 ((1<<3) | W_UNKNOWN)
#define W_INT                   ((1<<4) | W_BOUND)
#define W_INT_SMALL             ((1<<5) | W_INT)
#define W_INT_POS               ((1<<6) | W_INT)
#define W_BOOL                  ((1<<7) | W_BOUND)
#define W_FUNC                  ((1<<8) | W_BOUND)
#define W_LIST                  ((1<<9) | W_BOUND)

#define W_INT_SMALL_POS         (W_INT_SMALL | W_INT_POS)

static void SetInfoCVar(CVar cvar, UInt type)
{
    Bag                 info;           // its info bag

    // get the information bag
    info = INFO_FEXP( CURR_FUNC() );

    // set the type of a temporary
    if ( IS_TEMP_CVAR(cvar) ) {
        TNUM_TEMP_INFO( info, TEMP_CVAR(cvar) ) = type;
    }

    // set the type of a lvar (but do not change if it is a higher variable)
    else if ( IS_LVAR_CVAR(cvar)
           && TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) ) != W_HIGHER ) {
        TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) ) = type;
    }
}

static Int GetInfoCVar(CVar cvar)
{
    Bag                 info;           // its info bag

    // get the information bag
    info = INFO_FEXP( CURR_FUNC() );

    // get the type of an integer
    if ( IS_INTG_CVAR(cvar) ) {
        return ((0 < INTG_CVAR(cvar)) ? W_INT_SMALL_POS : W_INT_SMALL);
    }

    // get the type of a temporary
    else if ( IS_TEMP_CVAR(cvar) ) {
        return TNUM_TEMP_INFO( info, TEMP_CVAR(cvar) );
    }

    // get the type of a lvar
    else if ( IS_LVAR_CVAR(cvar) ) {
        return TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) );
    }

    // hmm, avoid warning by compiler
    else {
        return 0;
    }
}

static Int HasInfoCVar(CVar cvar, Int type)
{
    return ((GetInfoCVar( cvar ) & type) == type);
}


static Bag NewInfoCVars(void)
{
    Bag                 old;
    Bag                 new;
    old = INFO_FEXP( CURR_FUNC() );
    new = NewBag( TNUM_BAG(old), SIZE_BAG(old) );
    return new;
}

static void CopyInfoCVars(Bag dst, Bag src)
{
    Int                 i;
    if ( SIZE_BAG(dst) < SIZE_BAG(src) )  ResizeBag( dst, SIZE_BAG(src) );
    if ( SIZE_BAG(src) < SIZE_BAG(dst) )  ResizeBag( src, SIZE_BAG(dst) );
    NR_INFO(dst)    = NR_INFO(src);
    NLVAR_INFO(dst) = NLVAR_INFO(src);
    NHVAR_INFO(dst) = NHVAR_INFO(src);
    NTEMP_INFO(dst) = NTEMP_INFO(src);
    CTEMP_INFO(dst) = CTEMP_INFO(src);
    for ( i = 1; i <= NLVAR_INFO(src); i++ ) {
        TNUM_LVAR_INFO(dst,i) = TNUM_LVAR_INFO(src,i);
    }
    for ( i = 1; i <= NTEMP_INFO(dst) && i <= NTEMP_INFO(src); i++ ) {
        TNUM_TEMP_INFO(dst,i) = TNUM_TEMP_INFO(src,i);
    }
}

static void MergeInfoCVars(Bag dst, Bag src)
{
    Int                 i;
    if ( SIZE_BAG(dst) < SIZE_BAG(src) )  ResizeBag( dst, SIZE_BAG(src) );
    if ( SIZE_BAG(src) < SIZE_BAG(dst) )  ResizeBag( src, SIZE_BAG(dst) );
    if ( NTEMP_INFO(dst)<NTEMP_INFO(src) )  NTEMP_INFO(dst)=NTEMP_INFO(src);
    for ( i = 1; i <= NLVAR_INFO(src); i++ ) {
        TNUM_LVAR_INFO(dst,i) &= TNUM_LVAR_INFO(src,i);
    }
    for ( i = 1; i <= NTEMP_INFO(dst) && i <= NTEMP_INFO(src); i++ ) {
        TNUM_TEMP_INFO(dst,i) &= TNUM_TEMP_INFO(src,i);
    }
}

static BOOL IsEqInfoCVars(Bag dst, Bag src)
{
    Int                 i;
    if ( SIZE_BAG(dst) < SIZE_BAG(src) )  ResizeBag( dst, SIZE_BAG(src) );
    if ( SIZE_BAG(src) < SIZE_BAG(dst) )  ResizeBag( src, SIZE_BAG(dst) );
    for ( i = 1; i <= NLVAR_INFO(src); i++ ) {
        if ( TNUM_LVAR_INFO(dst,i) != TNUM_LVAR_INFO(src,i) ) {
            return FALSE;
        }
    }
    for ( i = 1; i <= NTEMP_INFO(dst) && i <= NTEMP_INFO(src); i++ ) {
        if ( TNUM_TEMP_INFO(dst,i) != TNUM_TEMP_INFO(src,i) ) {
            return FALSE;
        }
    }
    return TRUE;
}


/****************************************************************************
**
*F  NewTemp( <name> ) . . . . . . . . . . . . . . .  allocate a new temporary
*F  FreeTemp( <temp> )  . . . . . . . . . . . . . . . . . .  free a temporary
**
**  'NewTemp' allocates  a  new  temporary   variable (<name>  is   currently
**  ignored).
**
**  'FreeTemp' frees the temporary <temp>.
**
**  Currently  allocations and deallocations   of  temporaries are done  in a
**  strict nested (laff -- last allocated, first freed) order.  This means we
**  do not have to search for unused temporaries.
*/

typedef UInt4           Temp;

static Temp NewTemp(const Char * name)
{
    Temp                temp;           // new temporary, result
    Bag                 info;           // information bag

    // get the information bag
    info = INFO_FEXP( CURR_FUNC() );

    // take the next available temporary
    CTEMP_INFO( info )++;
    temp = CTEMP_INFO( info );

    // maybe make room for more temporaries
    if ( NTEMP_INFO( info ) < temp ) {
        if ( SIZE_BAG(info) < SIZE_INFO( NLVAR_INFO(info), temp ) ) {
            ResizeBag( info, SIZE_INFO( NLVAR_INFO(info), temp+7 ) );
        }
        NTEMP_INFO( info ) = temp;
    }
    TNUM_TEMP_INFO( info, temp ) = W_UNKNOWN;

    // return the temporary
    return temp;
}

static void FreeTemp(Temp temp)
{
    Bag                 info;           // information bag

    // get the information bag
    info = INFO_FEXP( CURR_FUNC() );

    // check that deallocations happens in the correct order
    if ( temp != CTEMP_INFO( info ) && CompPass == 2 ) {
        Pr("PROBLEM: freeing t_%d, should be t_%d\n",(Int)temp,CTEMP_INFO(info));
    }

    // free the temporary
    TNUM_TEMP_INFO( info, temp ) = W_UNUSED;
    CTEMP_INFO( info )--;
}


/****************************************************************************
**
*F  CompSetUseHVar( <hvar> )  . . . . . . . . register use of higher variable
*F  CompGetUseHVar( <hvar> )  . . . . . . . . get use mode of higher variable
*F  GetLevlHVar( <hvar> ) . . . . . . . . . . .  get level of higher variable
*F  GetIndxHVar( <hvar> ) . . . . . . . . . . .  get index of higher variable
**
**  'CompSetUseHVar'  register (during pass 1)   that the variable <hvar>  is
**  used  as   higher  variable, i.e.,  is  referenced   from inside  a local
**  function.  Such variables  must be allocated  in  a stack frame  bag (and
**  cannot be mapped to C variables).
**
**  'CompGetUseHVar' returns nonzero if the variable <hvar> is used as higher
**  variable.
**
**  'GetLevlHVar' returns the level of the  higher variable <hvar>, i.e., the
**  number of  frames  that must be  walked upwards   for the  one containing
**  <hvar>.  This may be properly  smaller than 'LEVEL_HVAR(<hvar>)', because
**  only those compiled functions that have local variables  that are used as
**  higher variables allocate a stack frame.
**
**  'GetIndxHVar' returns the index of the higher  variable <hvar>, i.e., the
**  position of <hvar> in the stack frame.  This may be properly smaller than
**  'INDEX_HVAR(<hvar>)', because only those  local variable that are used as
**  higher variables are allocated in a stack frame.
*/

typedef UInt4           HVar;

static void CompSetUseHVar(HVar hvar)
{
    Bag                 info;           // its info bag
    Int                 i;              // loop variable

    // only mark in pass 1
    if ( CompPass != 1 )  return;

    // walk up
    info = INFO_FEXP( CURR_FUNC() );
    for ( i = 1; i <= (hvar >> 16); i++ ) {
        info = NEXT_INFO( info );
    }

    // set mark
    if ( TNUM_LVAR_INFO( info, (hvar & 0xFFFF) ) != W_HIGHER ) {
        TNUM_LVAR_INFO( info, (hvar & 0xFFFF) ) = W_HIGHER;
        NHVAR_INFO(info) = NHVAR_INFO(info) + 1;
    }

}

static Int CompGetUseHVar(HVar hvar)
{
    Bag                 info;           // its info bag
    Int                 i;              // loop variable

    // walk up
    info = INFO_FEXP( CURR_FUNC() );
    for ( i = 1; i <= (hvar >> 16); i++ ) {
        info = NEXT_INFO( info );
    }

    // get mark
    return (TNUM_LVAR_INFO( info, (hvar & 0xFFFF) ) == W_HIGHER);
}

static UInt GetLevlHVar(HVar hvar)
{
    UInt                levl;           // level of higher variable
    Bag                 info;           // its info bag
    Int                 i;              // loop variable

    // walk up
    levl = 0;
    info = INFO_FEXP( CURR_FUNC() );
    levl++;
    for ( i = 1; i <= (hvar >> 16); i++ ) {
        info = NEXT_INFO( info );
          levl++;
    }

    // return level (the number steps to go up)
    return levl - 1;
}

static UInt GetIndxHVar(HVar hvar)
{
    UInt                indx;           // index of higher variable
    Bag                 info;           // its info bag
    Int                 i;              // loop variable

    // walk up
    info = INFO_FEXP( CURR_FUNC() );
    for ( i = 1; i <= (hvar >> 16); i++ ) {
        info = NEXT_INFO( info );
    }

    // walk right
    indx = 0;
    for ( i = 1; i <= (hvar & 0xFFFF); i++ ) {
        if ( TNUM_LVAR_INFO( info, i ) == W_HIGHER )  indx++;
    }

    // return the index
    return indx;
}


/****************************************************************************
**
*F  CompSetUseGVar( <gvar>, <mode> )  . . . . register use of global variable
*F  CompGetUseGVar( <gvar> )  . . . . . . . . get use mode of global variable
**
**  'CompSetUseGVar' registers (during pass 1) the use of the global variable
**  with identifier <gvar>.
**
**  'CompGetUseGVar'  returns the bitwise OR  of all the <mode> arguments for
**  the global variable with identifier <gvar>.
**
**  Currently the interpretation of the <mode> argument is as follows
**
**  If '<mode> &  COMP_USE_GVAR_ID' is nonzero, then  the produced code shall
**  define  and initialize 'G_<name>'    with  the identifier of  the  global
**  variable (which may  be different from  <gvar>  by the time the  compiled
**  code is actually run).
**
**  If '<mode> & COMP_USE_GVAR_COPY' is nonzero, then the produced code shall
**  define  and initialize 'GC_<name>' as a  copy of  the global variable
**  (see 'InitCopyGVar' in 'gvars.h').
**
**  If '<mode> & COMP_USE_GVAR_FOPY' is nonzero, then the produced code shall
**  define and  initialize  'GF_<name>' as   a  function copy  of the  global
**  variable (see 'InitFopyGVar' in 'gvars.h').
*/

typedef UInt    GVar;

#define COMP_USE_GVAR_ID        (1 << 0)
#define COMP_USE_GVAR_COPY      (1 << 1)
#define COMP_USE_GVAR_FOPY      (1 << 2)

static Bag CompInfoGVar;

static void CompSetUseGVar(GVar gvar, UInt mode)
{
    // only mark in pass 1
    if ( CompPass != 1 )  return;

    // resize if necessary
    if ( SIZE_OBJ(CompInfoGVar)/sizeof(UInt) <= gvar ) {
        ResizeBag( CompInfoGVar, sizeof(UInt)*(gvar+1) );
    }

    // or with <mode>
    ((UInt*)PTR_BAG(CompInfoGVar))[gvar] |= mode;
}

static UInt CompGetUseGVar(GVar gvar)
{
    return ((UInt*)PTR_BAG(CompInfoGVar))[gvar];
}


/****************************************************************************
**
*F  CompSetUseRNam( <rnam>, <mode> )  . . . . . . register use of record name
*F  CompGetUseRNam( <rnam> )  . . . . . . . . . . get use mode of record name
**
**  'CompSetUseRNam' registers  (during pass  1) the use   of the record name
**  with identifier <rnam>.  'CompGetUseRNam'  returns the bitwise OR  of all
**  the <mode> arguments for the global variable with identifier <rnam>.
**
**  Currently the interpretation of the <mode> argument is as follows
**
**  If '<mode> & COMP_USE_RNAM_ID'  is nonzero, then  the produced code shall
**  define and initialize  'R_<name>' with the  identifier of the record name
**  (which may be  different from <rnam> when the  time the  compiled code is
**  actually run).
*/

typedef UInt    RNam;

#define COMP_USE_RNAM_ID        (1 << 0)

static Bag CompInfoRNam;

static void CompSetUseRNam(RNam rnam, UInt mode)
{
    // only mark in pass 1
    if ( CompPass != 1 )  return;

    // resize if necessary
    if ( SIZE_OBJ(CompInfoRNam)/sizeof(UInt) <= rnam ) {
        ResizeBag( CompInfoRNam, sizeof(UInt)*(rnam+1) );
    }

    // or with <mode>
    ((UInt*)PTR_BAG(CompInfoRNam))[rnam] |= mode;
}

static UInt CompGetUseRNam(RNam rnam)
{
    return ((UInt*)PTR_BAG(CompInfoRNam))[rnam];
}


/****************************************************************************
**
*F  Emit( <fmt>, ... )  . . . . . . . . . . . . . . . . . . . . . . emit code
**
**  'Emit' outputs the   string  <fmt> and the  other  arguments,  which must
**  correspond  to the '%'  format elements  in  <fmt>.  Nothing  is actually
**  outputted if 'CompPass' is not 2.
**
**  'Emit' supports the following '%' format elements:
**  - '%d' formats an integer,
**  - '%g' formats a GAP string,
**  - '%C' does the same but uses only valid C escapes,
**  - '%n' formats a name ('_' is converted to '__', special characters are
**         converted to '_<hex1><hex2>')
**  - '%c' formats a C variable ('INTOBJ_INT(<int>)' for integers, 'a_<name>'
**         for arguments, 'l_<name>' for locals, 't_<nr>' for temporaries),
**  - '%i' formats a C variable as an integer ('<int>' for integers, and for
**         everything else the same as INT_INTOBJ(%c) would produce
**  - '%%' outputs a single '%'.
*/

static Int EmitIndent;

static Int EmitIndent2;

static void Emit(const char * fmt, ...)
{
    Int                 narg;           // number of arguments
    va_list             ap;             // argument list pointer
    Int                 dint;           // integer argument
    CVar                cvar;           // C variable argument
    const Char *        p;              // loop variable
    const Char *        hex = "0123456789ABCDEF";

    // are we in pass 2?
    if ( CompPass != 2 )  return;

    // get the information bag
    narg = NARG_FUNC( CURR_FUNC() );
    if (narg < 0) {
        narg = -narg;
    }

    // loop over the format string
    va_start( ap, fmt );
    for ( p = fmt; *p != '\0'; p++ ) {

        // print an indent, except for preprocessor commands
        if ( *fmt != '#' ) {
            if ( 0 < EmitIndent2 && *p == '}' ) EmitIndent2--;
            while ( 0 < EmitIndent2-- )  Pr(" ", 0, 0);
        }

        // format an argument
        if ( *p == '%' ) {
            p++;

            // emit an integer
            if ( *p == 'd' ) {
                dint = va_arg( ap, Int );
                Pr("%d", dint, 0);
            }

            // emit a GAP string
            else if ( *p == 'g' || *p == 'C' ) {
                const Char f[] = { '%', *p, 0 };
                Obj str = va_arg( ap, Obj );
                Pr(f, (Int)str, 0);
            }

            // emit a name
            else if ( *p == 'n' ) {
                Obj str = va_arg( ap, Obj );
                UInt i = 0;
                Char c;
                while ((c = CONST_CSTR_STRING(str)[i++])) {
                    if ( IsAlpha(c) || IsDigit(c) ) {
                        Pr("%c", (Int)c, 0);
                    }
                    else if ( c == '_' ) {
                        Pr("__", 0, 0);
                    }
                    else {
                        Pr("_%c%c",hex[((UInt)c)/16],hex[((UInt)c)%16]);
                    }
                }
            }

            // emit a C variable
            else if ( *p == 'c' ) {
                cvar = va_arg( ap, CVar );
                if ( IS_INTG_CVAR(cvar) ) {
                    Int x = INTG_CVAR(cvar);
                    if (x >= -(1 << 28) && x < (1 << 28))
                        Pr("INTOBJ_INT(%d)", x, 0);
                    else
                        Pr("ObjInt_Int8(%d)", x, 0);
                }
                else if ( IS_TEMP_CVAR(cvar) ) {
                    Pr("t_%d", TEMP_CVAR(cvar), 0);
                }
                else if ( LVAR_CVAR(cvar) <= narg ) {
                    Emit( "a_%n", NAME_LVAR( LVAR_CVAR(cvar) ) );
                }
                else {
                    Emit( "l_%n", NAME_LVAR( LVAR_CVAR(cvar) ) );
                }
            }

            // emit a C variable
            else if ( *p == 'i' ) {
                cvar = va_arg( ap, CVar );
                if ( IS_INTG_CVAR(cvar) ) {
                    Pr("%d", INTG_CVAR(cvar), 0);
                }
                else if ( IS_TEMP_CVAR(cvar) ) {
                    Pr("Int_ObjInt(t_%d)", TEMP_CVAR(cvar), 0);
                }
                else if ( LVAR_CVAR(cvar) <= narg ) {
                    Emit( "Int_ObjInt(a_%n)", NAME_LVAR( LVAR_CVAR(cvar) ) );
                }
                else {
                    Emit( "Int_ObjInt(l_%n)", NAME_LVAR( LVAR_CVAR(cvar) ) );
                }
            }

            // emit a '%'
            else if ( *p == '%' ) {
                Pr("%%", 0, 0);
            }

            // what
            else {
                Pr("%%illegal format statement", 0, 0);
            }

        }

        else if ( *p == '{' ) {
            Pr("{", 0, 0);
            EmitIndent++;
        }
        else if ( *p == '}' ) {
            Pr("}", 0, 0);
            EmitIndent--;
        }
        else if ( *p == '\n' ) {
            Pr("\n", 0, 0);
            EmitIndent2 = EmitIndent;
        }

        else {
            Pr("%c", (Int)(*p), 0);
        }

    }
    va_end( ap );

}


/****************************************************************************
**
*F * * * * * * * * * * * * * * compile checks * * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  CompCheckBound( <obj>, <name> ) emit code to check that <obj> has a value
*/

static void CompCheckBound(CVar obj, Obj name)
{
    if ( ! HasInfoCVar( obj, W_BOUND ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_BOUND( %c, \"%g\" );\n", obj, name );
        }
        SetInfoCVar( obj, W_BOUND );
    }
}


/****************************************************************************
**
*F  CompCheckFuncResult( <obj> )  . emit code to check that <obj> has a value
*/

static void CompCheckFuncResult(CVar obj)
{
    if ( ! HasInfoCVar( obj, W_BOUND ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_FUNC_RESULT( %c );\n", obj );
        }
        SetInfoCVar( obj, W_BOUND );
    }
}


/****************************************************************************
**
*F  CompCheckIntSmall( <obj> )   emit code to check that <obj> is a small int
*/

static void CompCheckIntSmall(CVar obj)
{
    if ( ! HasInfoCVar( obj, W_INT_SMALL ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_INT_SMALL( %c );\n", obj );
        }
        SetInfoCVar( obj, W_INT_SMALL );
    }
}



/****************************************************************************
**
*F  CompCheckIntSmallPos( <obj> ) emit code to check that <obj> is a position
*/

static void CompCheckIntSmallPos(CVar obj)
{
    if ( ! HasInfoCVar( obj, W_INT_SMALL_POS ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_INT_SMALL_POS( %c );\n", obj );
        }
        SetInfoCVar( obj, W_INT_SMALL_POS );
    }
}

/****************************************************************************
**
*F  CompCheckIntPos( <obj> ) emit code to check that <obj> is a position
*/

static void CompCheckIntPos(CVar obj)
{
    if ( ! HasInfoCVar( obj, W_INT_POS ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_INT_POS( %c );\n", obj );
        }
        SetInfoCVar( obj, W_INT_POS );
    }
}


/****************************************************************************
**
*F  CompCheckBool( <obj> )  . . .  emit code to check that <obj> is a boolean
*/

static void CompCheckBool(CVar obj)
{
    if ( ! HasInfoCVar( obj, W_BOOL ) ) {
        if ( CompCheckTypes ) {
            Emit( "CHECK_BOOL( %c );\n", obj );
        }
        SetInfoCVar( obj, W_BOOL );
    }
}


/****************************************************************************
**
*F * * * * * * * * * * * *  compile expressions * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  CompExpr( <expr> )  . . . . . . . . . . . . . . . . compile an expression
**
**  'CompExpr' compiles the expression <expr> and returns the C variable that
**  will contain the result.
*/

static CVar (*CompExprFuncs[256])(Expr expr);


static CVar CompExpr(Expr expr)
{
    return (* CompExprFuncs[ TNUM_EXPR(expr) ])( expr );
}


/****************************************************************************
**
*F  CompUnknownExpr( <expr> ) . . . . . . . . . . . .  log unknown expression
*/

static CVar CompUnknownExpr(Expr expr)
{
    Emit( "CANNOT COMPILE EXPRESSION OF TNUM %d;\n", TNUM_EXPR(expr) );
    return 0;
}



/****************************************************************************
**
*F  CompBoolExpr( <expr> )  . . . . . . . compile bool expr and return C bool
*/

static CVar (*CompBoolExprFuncs[256])(Expr expr);

static CVar CompBoolExpr(Expr expr)
{
    return (* CompBoolExprFuncs[ TNUM_EXPR(expr) ])( expr );
}


/****************************************************************************
**
*F  CompUnknownBool( <expr> ) . . . . . . . . . .  use 'CompExpr' and convert
*/

static CVar CompUnknownBool(Expr expr)
{
    CVar                res;            // result
    CVar                val;            // value of expression

    // allocate a new temporary for the result
    res = CVAR_TEMP( NewTemp( "res" ) );

    // compile the expression and check that the value is boolean
    val = CompExpr( expr );
    CompCheckBool( val );

    // emit code to store the C boolean value in the result
    Emit( "%c = (Obj)(UInt)(%c != False);\n", res, val );

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( res, W_BOOL );

    // free the temporary
    if ( IS_TEMP_CVAR( val ) )  FreeTemp( TEMP_CVAR( val ) );

    return res;
}

/****************************************************************************
**
*V  G_Length  . . . . . . . . . . . . . . . . . . . . . . . function 'Length'
*/

static GVar G_Length;


/****************************************************************************
**
*F  CompFunccall0to6Args( <expr> )  . . . EXPR_FUNCCALL_0ARGS...EXPR_FUNCCALL_6ARGS
*/

static CVar CompRefGVarFopy(Expr expr);


static CVar CompFunccall0to6Args(Expr expr)
{
    CVar                result;         // result, result
    CVar                func;           // function
    CVar                args [8];       // arguments
    Int                 narg;           // number of arguments
    Int                 i;              // loop variable

    // special case to inline 'Length'
    if ( CompFastListFuncs
      && TNUM_EXPR( FUNC_CALL(expr) ) == EXPR_REF_GVAR
      && READ_EXPR( FUNC_CALL(expr), 0 ) == G_Length
      && NARG_SIZE_CALL(SIZE_EXPR(expr)) == 1 ) {
        result = CVAR_TEMP( NewTemp( "result" ) );
        args[1] = CompExpr( ARGI_CALL(expr,1) );
        if ( CompFastPlainLists ) {
            Emit( "C_LEN_LIST_FPL( %c, %c )\n", result, args[1] );
        }
        else {
            Emit( "C_LEN_LIST( %c, %c )\n", result, args[1] );
        }
        SetInfoCVar( result, W_INT_SMALL );
        if ( IS_TEMP_CVAR( args[1] ) )  FreeTemp( TEMP_CVAR( args[1] ) );
        return result;
    }

    // allocate a temporary for the result
    result = CVAR_TEMP( NewTemp( "result" ) );

    // compile the reference to the function
    if ( TNUM_EXPR( FUNC_CALL(expr) ) == EXPR_REF_GVAR ) {
        func = CompRefGVarFopy( FUNC_CALL(expr) );
    }
    else {
        func = CompExpr( FUNC_CALL(expr) );
    }

    // compile the argument expressions
    narg = NARG_SIZE_CALL(SIZE_EXPR(expr));
    for ( i = 1; i <= narg; i++ ) {
        args[i] = CompExpr( ARGI_CALL(expr,i) );
    }

    // emit the code for the function call
    Emit( "if ( TNUM_OBJ( %c ) == T_FUNCTION ) {\n", func );
    Emit( "%c = CALL_%dARGS( %c", result, narg, func );
    for ( i = 1; i <= narg; i++ ) {
        Emit( ", %c", args[i] );
    }
    Emit( " );\n" );
    Emit( "}\n" );
    Emit( "else {\n" );
    Emit( "%c = DoOperation2Args( CallFuncListOper, %c, NewPlistFromArgs(", result, func);
    if (narg >= 1) {
        Emit( " %c", args[1] );
    }
    for ( i = 2; i <= narg; i++ ) {
        Emit( ", %c", args[i] );
    }
    Emit( " ) );\n" );
    Emit( "}\n" );

    // emit code for the check (sets the information for the result)
    CompCheckFuncResult( result );

    // free the temporaries
    for ( i = narg; 1 <= i; i-- ) {
        if ( IS_TEMP_CVAR( args[i] ) )  FreeTemp( TEMP_CVAR( args[i] ) );
    }
    if ( IS_TEMP_CVAR( func ) )  FreeTemp( TEMP_CVAR( func ) );

    return result;
}


/****************************************************************************
**
*F  CompFunccallXArgs( <expr> ) . . . . . . . . . . . . . EXPR_FUNCCALL_XARGS
*/

static CVar CompFunccallXArgs(Expr expr)
{
    CVar                result;         // result, result
    CVar                func;           // function
    CVar                argl;           // argument list
    CVar                argi;           // <i>-th argument
    UInt                narg;           // number of arguments
    UInt                i;              // loop variable

    // allocate a temporary for the result
    result = CVAR_TEMP( NewTemp( "result" ) );

    // compile the reference to the function
    if ( TNUM_EXPR( FUNC_CALL(expr) ) == EXPR_REF_GVAR ) {
        func = CompRefGVarFopy( FUNC_CALL(expr) );
    }
    else {
        func = CompExpr( FUNC_CALL(expr) );
    }

    // compile the argument expressions
    narg = NARG_SIZE_CALL(SIZE_EXPR(expr));
    argl = CVAR_TEMP( NewTemp( "argl" ) );
    Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", argl, narg );
    Emit( "SET_LEN_PLIST( %c, %d );\n", argl, narg );
    for ( i = 1; i <= narg; i++ ) {
        argi = CompExpr( ARGI_CALL( expr, i ) );
        Emit( "SET_ELM_PLIST( %c, %d, %c );\n", argl, i, argi );
        if ( ! HasInfoCVar( argi, W_INT_SMALL ) ) {
            Emit( "CHANGED_BAG( %c );\n", argl );
        }
        if ( IS_TEMP_CVAR( argi ) )  FreeTemp( TEMP_CVAR( argi ) );
    }

    // emit the code for the function call
    Emit( "if ( TNUM_OBJ( %c ) == T_FUNCTION ) {\n", func );
    Emit( "%c = CALL_XARGS( %c, %c );\n", result, func, argl );
    Emit( "}\n" );
    Emit( "else {\n" );
    Emit( "%c = DoOperation2Args( CallFuncListOper, %c, %c );\n", result, func, argl );
    Emit( "}\n" );

    // emit code for the check (sets the information for the result)
    CompCheckFuncResult( result );

    // free the temporaries
    if ( IS_TEMP_CVAR( argl ) )  FreeTemp( TEMP_CVAR( argl ) );
    if ( IS_TEMP_CVAR( func ) )  FreeTemp( TEMP_CVAR( func ) );

    return result;
}

/****************************************************************************
**
*F  CompFunccallXArgs( <expr> ) . . . . . . . . . . . . .  EXPR_FUNCCALL_OPTS
*/

static CVar CompFunccallOpts(Expr expr)
{
  CVar opts = CompExpr(READ_STAT(expr, 0));
  GVar pushOptions;
  GVar popOptions;
  CVar result;
  pushOptions = GVarName("PushOptions");
  popOptions = GVarName("PopOptions");
  CompSetUseGVar(pushOptions, COMP_USE_GVAR_FOPY);
  CompSetUseGVar(popOptions, COMP_USE_GVAR_FOPY);
  Emit("CALL_1ARGS( GF_PushOptions, %c );\n", opts);
  if (IS_TEMP_CVAR( opts) ) FreeTemp( TEMP_CVAR( opts ));
  result = CompExpr(READ_STAT(expr, 1));
  Emit("CALL_0ARGS( GF_PopOptions );\n");
  return result;
}


/****************************************************************************
**
*F  CompFuncExpr( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_FUNC
*/

static CVar CompFuncExpr(Expr expr)
{
    CVar                func;           // function, result
    CVar                tmp;            // dummy body

    Obj                 fexp;           // function expression
    Int                 nr;             // number of the function

    // get the number of the function
    fexp = GET_VALUE_FROM_CURRENT_BODY(READ_EXPR(expr, 0));
    nr   = NR_INFO( INFO_FEXP( fexp ) );

    // allocate a new temporary for the function
    func = CVAR_TEMP( NewTemp( "func" ) );

    // make the function (all the pieces are in global variables)
    Int narg = NARG_FUNC(fexp);
    Emit( "%c = NewFunction( NameFunc[%d], %d", func, nr, narg );
    if (narg != 0) {
        Obj nams = NAMS_FUNC(fexp);
        if (narg < 0)
            narg = -narg;
        Emit( ", NewPlistFromArgs(" );
        Emit( "MakeImmString(\"%g\")", ELM_PLIST(nams, 1) );
        for (Int i = 2; i <= narg; i++) {
            Emit( ", MakeImmString(\"%g\")", ELM_PLIST(nams, i) );
        }
        Emit( ")" );
    }
    else {
        Emit( ", 0" );
    }
    Emit( ", HdlrFunc%d );\n", nr );

    // this should probably be done by 'NewFunction'
    Emit( "SET_ENVI_FUNC( %c, STATE(CurrLVars) );\n", func );
    tmp = CVAR_TEMP( NewTemp( "body" ) );
    Emit( "%c = NewFunctionBody();\n", tmp );
    Emit( "SET_STARTLINE_BODY(%c, %d);\n", tmp, GET_STARTLINE_BODY(BODY_FUNC(fexp)));
    Emit( "SET_ENDLINE_BODY(%c, %d);\n", tmp, GET_ENDLINE_BODY(BODY_FUNC(fexp)));
    Emit( "SET_FILENAME_BODY(%c, FileName);\n",tmp);
    Emit( "SET_BODY_FUNC(%c, %c);\n", func, tmp );
    FreeTemp( TEMP_CVAR( tmp ) );

    // we know that the result is a function
    SetInfoCVar( func, W_FUNC );

    // return the number of the C variable that will hold the function
    return func;
}


/****************************************************************************
**
*F  CompOr( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_OR
*/

static CVar CompOr(Expr expr)
{
    CVar                val;            // or, result
    CVar                left;           // left operand
    CVar                right;          // right operand
    Bag                 only_left;      // info after evaluating only left

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the left expression
    left = CompBoolExpr(READ_EXPR(expr, 0));
    Emit( "%c = (%c ? True : False);\n", val, left );
    Emit( "if ( %c == False ) {\n", val );
    only_left = NewInfoCVars();
    CopyInfoCVars( only_left, INFO_FEXP(CURR_FUNC()) );

    // compile the right expression
    right = CompBoolExpr(READ_EXPR(expr, 1));
    Emit( "%c = (%c ? True : False);\n", val, right );
    Emit( "}\n" );

    // we know that the result is boolean
    MergeInfoCVars( INFO_FEXP(CURR_FUNC()), only_left );
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompOrBool( <expr> ) . . . . . . . . . . . . . . . . . . . . . .  EXPR_OR
*/

static CVar CompOrBool(Expr expr)
{
    CVar                val;            // or, result
    CVar                left;           // left operand
    CVar                right;          // right operand
    Bag                 only_left;      // info after evaluating only left

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the left expression
    left = CompBoolExpr(READ_EXPR(expr, 0));
    Emit( "%c = %c;\n", val, left );
    Emit( "if ( ! %c ) {\n", val );
    only_left = NewInfoCVars();
    CopyInfoCVars( only_left, INFO_FEXP(CURR_FUNC()) );

    // compile the right expression
    right = CompBoolExpr(READ_EXPR(expr, 1));
    Emit( "%c = %c;\n", val, right );
    Emit( "}\n" );

    // we know that the result is boolean (should be 'W_CBOOL')
    MergeInfoCVars( INFO_FEXP(CURR_FUNC()), only_left );
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompAnd( <expr> ) . . . . . . . . . . . . . . . . . . . . . . .  EXPR_AND
*/

static CVar CompAnd(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right1;         // right operand 1
    CVar                right2;         // right operand 2
    Bag                 only_left;      // info after evaluating only left

    // allocate a temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the left expression
    left = CompExpr(READ_EXPR(expr, 0));
    only_left = NewInfoCVars();
    CopyInfoCVars( only_left, INFO_FEXP(CURR_FUNC()) );

    // emit the code for the case that the left value is 'false'
    Emit( "if ( %c == False ) {\n", left );
    Emit( "%c = %c;\n", val, left );
    Emit( "}\n" );

    // emit the code for the case that the left value is 'true'
    Emit( "else if ( %c == True ) {\n", left );
    right1 = CompExpr(READ_EXPR(expr, 1));
    CompCheckBool( right1 );
    Emit( "%c = %c;\n", val, right1 );
    Emit( "}\n" );

    // emit the code for the case that the left value is a filter
    Emit( "else if (IS_FILTER( %c ) ) {\n", left );
    right2 = CompExpr(READ_EXPR(expr, 1));
    Emit( "%c = NewAndFilter( %c, %c );\n", val, left, right2 );
    Emit( "}\n" );

    // signal an error
    Emit( "else {\n" );
    Emit( "RequireArgumentEx(0, %c, \"<expr>\",\n"
            "\"must be 'true' or 'false' or a filter\" );\n", left );
    Emit( "}\n" );

    // we know precious little about the result
    MergeInfoCVars( INFO_FEXP(CURR_FUNC()), only_left );
    SetInfoCVar( val, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( right2 ) )  FreeTemp( TEMP_CVAR( right2 ) );
    if ( IS_TEMP_CVAR( right1 ) )  FreeTemp( TEMP_CVAR( right1 ) );
    if ( IS_TEMP_CVAR( left   ) )  FreeTemp( TEMP_CVAR( left   ) );

    return val;
}


/****************************************************************************
**
*F  CompAndBool( <expr> ) . . . . . . . . . . . . . . . . . . . . .  EXPR_AND
*/

static CVar CompAndBool(Expr expr)
{
    CVar                val;            // or, result
    CVar                left;           // left operand
    CVar                right;          // right operand
    Bag                 only_left;      // info after evaluating only left

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the left expression
    left = CompBoolExpr(READ_EXPR(expr, 0));
    Emit( "%c = %c;\n", val, left );
    Emit( "if ( %c ) {\n", val );
    only_left = NewInfoCVars();
    CopyInfoCVars( only_left, INFO_FEXP(CURR_FUNC()) );

    // compile the right expression
    right = CompBoolExpr(READ_EXPR(expr, 1));
    Emit( "%c = %c;\n", val, right );
    Emit( "}\n" );

    // we know that the result is boolean (should be 'W_CBOOL')
    MergeInfoCVars( INFO_FEXP(CURR_FUNC()), only_left );
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompNot( <expr> ) . . . . . . . . . . . . . . . . . . . . . . .  EXPR_NOT
*/

static CVar CompNot(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the operand
    left = CompBoolExpr(READ_EXPR(expr, 0));

    // invert the operand
    Emit( "%c = (%c ? False : True);\n", val, left );

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( left ) )  FreeTemp( TEMP_CVAR( left ) );

    return val;
}


/****************************************************************************
**
*F  CompNotBoot( <expr> ) . . . . . . . . . . . . . . . . . . . . .  EXPR_NOT
*/

static CVar CompNotBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the operand
    left = CompBoolExpr(READ_EXPR(expr, 0));

    // invert the operand
    Emit( "%c = (Obj)(UInt)( ! ((Int)%c) );\n", val, left );

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( left ) )  FreeTemp( TEMP_CVAR( left ) );

    return val;
}


/****************************************************************************
**
*F  CompEq( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_EQ
*/

static CVar CompEq(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit("%c = ((((Int)%c) == ((Int)%c)) ? True : False);\n", val, left, right);
    }
    else {
        Emit( "%c = (EQ( %c, %c ) ? True : False);\n", val, left, right );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompEqBool( <expr> ) . . . . . . . . . . . . . . . . . . . . . .  EXPR_EQ
*/

static CVar CompEqBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) == ((Int)%c));\n", val, left, right);
    }
    else {
        Emit( "%c = (Obj)(UInt)(EQ( %c, %c ));\n", val, left, right );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompNe( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_NE
*/

static CVar CompNe(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit("%c = ((((Int)%c) == ((Int)%c)) ? False : True);\n", val, left, right);
    }
    else {
        Emit( "%c = (EQ( %c, %c ) ? False : True);\n", val, left, right );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompNeBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_NE
*/

static CVar CompNeBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) != ((Int)%c));\n", val, left, right );
    }
    else {
        Emit( "%c = (Obj)(UInt)( ! EQ( %c, %c ));\n", val, left, right );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompLt( <expr> )  . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_LT
*/

static CVar CompLt(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = ((((Int)%c) < ((Int)%c)) ? True : False);\n", val, left, right );
    }
    else {
        Emit( "%c = (LT( %c, %c ) ? True : False);\n", val, left, right );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompLtBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_LT
*/

static CVar CompLtBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) < ((Int)%c));\n", val, left, right );
    }
    else {
        Emit( "%c = (Obj)(UInt)(LT( %c, %c ));\n", val, left, right );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompGe( <expr> )  . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_GE
*/

static CVar CompGe(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
         Emit("%c = ((((Int)%c) < ((Int)%c)) ? False : True);\n", val, left, right);
    }
    else {
        Emit( "%c = (LT( %c, %c ) ? False : True);\n", val, left, right );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompGeBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_GE
*/

static CVar CompGeBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) >= ((Int)%c));\n", val, left, right );
    }
    else {
        Emit( "%c = (Obj)(UInt)(! LT( %c, %c ));\n", val, left, right );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompGt( <expr> )  . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_GT
*/

static CVar CompGt(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit("%c = ((((Int)%c) < ((Int)%c)) ? True : False);\n", val, right, left);
    }
    else {
        Emit( "%c = (LT( %c, %c ) ? True : False);\n", val, right, left );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompGtBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_GT
*/

static CVar CompGtBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) < ((Int)%c));\n", val, right, left );
    }
    else {
        Emit( "%c = (Obj)(UInt)(LT( %c, %c ));\n", val, right, left );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompLe( <expr> )  . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_LE
*/

static CVar CompLe(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit("%c = ((((Int)%c) < ((Int)%c)) ?  False : True);\n", val, right, left);
    }
    else {
        Emit( "%c = (LT( %c, %c ) ?  False : True);\n", val, right, left );
    }

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompLeBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_LE
*/

static CVar CompLeBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "%c = (Obj)(UInt)(((Int)%c) >= ((Int)%c));\n", val, right, left );
    }
    else {
        Emit( "%c = (Obj)(UInt)(! LT( %c, %c ));\n", val, right, left );
    }

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompIn( <expr> )  . . . . . . . . . . . . . . . . . . . . . . . . .  EXPR_IN
*/

static CVar CompIn(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    Emit( "%c = (IN( %c, %c ) ?  True : False);\n", val, left, right );

    // we know that the result is boolean
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompInBool( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_IN
*/

static CVar CompInBool(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    Emit( "%c = (Obj)(UInt)(IN( %c, %c ));\n", val, left, right );

    // we know that the result is boolean (should be 'W_CBOOL')
    SetInfoCVar( val, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompSum( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . . . EXPR_SUM
*/

static CVar CompSum(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "C_SUM_INTOBJS( %c, %c, %c )\n", val, left, right );
    }
    else if ( CompFastIntArith ) {
        Emit( "C_SUM_FIA( %c, %c, %c )\n", val, left, right );
    }
    else {
        Emit( "C_SUM( %c, %c, %c )\n", val, left, right );
    }

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) && HasInfoCVar(right,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompAInv( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_AINV
*/

static CVar CompAInv(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the operands
    left = CompExpr(READ_EXPR(expr, 0));

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) ) {
        Emit( "C_AINV_INTOBJS( %c, %c )\n", val, left );
    }
    else if ( CompFastIntArith ) {
        Emit( "C_AINV_FIA( %c, %c )\n", val, left );
    }
    else {
        Emit( "C_AINV( %c, %c )\n", val, left );
    }

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompDiff( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_DIFF
*/

static CVar CompDiff(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "C_DIFF_INTOBJS( %c, %c, %c )\n", val, left, right );
    }
    else if ( CompFastIntArith ) {
        Emit( "C_DIFF_FIA( %c, %c, %c )\n", val, left, right );
    }
    else {
        Emit( "C_DIFF( %c, %c, %c )\n", val, left, right );
    }

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) && HasInfoCVar(right,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompProd( <expr> )  . . . . . . . . . . . . . . . . . . . . . . .  EXPR_PROD
*/

static CVar CompProd(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    if ( HasInfoCVar(left,W_INT_SMALL) && HasInfoCVar(right,W_INT_SMALL) ) {
        Emit( "C_PROD_INTOBJS( %c, %c, %c )\n", val, left, right );
    }
    else if ( CompFastIntArith ) {
        Emit( "C_PROD_FIA( %c, %c, %c )\n", val, left, right );
    }
    else {
        Emit( "C_PROD( %c, %c, %c )\n", val, left, right );
    }

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) && HasInfoCVar(right,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompQuo( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . . . EXPR_QUO
*/

static CVar CompQuo(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    Emit( "%c = QUO( %c, %c );\n", val, left, right );

    // set the information for the result
    SetInfoCVar( val, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompMod( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . . . EXPR_MOD
*/

static CVar CompMod(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    Emit( "%c = MOD( %c, %c );\n", val, left, right );

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) && HasInfoCVar(right,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompPow( <expr> ) . . . . . . . . . . . . . . . . . . . . . . . . . EXPR_POW
*/

static CVar CompPow(Expr expr)
{
    CVar                val;            // result
    CVar                left;           // left operand
    CVar                right;          // right operand

    // allocate a new temporary for the result
    val = CVAR_TEMP( NewTemp( "val" ) );

    // compile the two operands
    left  = CompExpr( READ_EXPR(expr, 0) );
    right = CompExpr( READ_EXPR(expr, 1) );

    // emit the code
    Emit( "%c = POW( %c, %c );\n", val, left, right );

    // set the information for the result
    if ( HasInfoCVar(left,W_INT) && HasInfoCVar(right,W_INT) ) {
        SetInfoCVar( val, W_INT );
    }
    else {
        SetInfoCVar( val, W_BOUND );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( right ) )  FreeTemp( TEMP_CVAR( right ) );
    if ( IS_TEMP_CVAR( left  ) )  FreeTemp( TEMP_CVAR( left  ) );

    return val;
}


/****************************************************************************
**
*F  CompIntExpr( <expr> ) . . . . . . . . . . . . . . .  EXPR_INT/EXPR_INTPOS
**
**  This is complicated by the need to produce code that will compile
**  correctly in 32 or 64 bit and with or without GMP.
**
**  The problem is that when we compile the code, we know the integer
**  representation of the stored literal in the compiling process but NOT the
**  representation which will apply to the compiled code or the endianness
**
**  The solution to this is macros: C_SET_LIMB4(bag, limbnumber, value)
**                                  C_SET_LIMB8(bag, limbnumber, value)
**
**  we compile using the one appropriate for the compiling system, but their
**  definition depends on the limb size of the target system.
**
*/

void C_SET_LIMB4(Obj bag, UInt limbnumber, UInt4 value)
{
#ifdef SYS_IS_64_BIT
    UInt8 * p;
    if (limbnumber % 2) {
        p = ((UInt8 *)ADDR_OBJ(bag)) + (limbnumber - 1) / 2;
        *p = (*p & 0xFFFFFFFFUL) | ((UInt8)value << 32);
    }
    else {
        p = ((UInt8 *)ADDR_OBJ(bag)) + limbnumber / 2;
        *p = (*p & 0xFFFFFFFF00000000UL) | (UInt8)value;
    }
#else
    ((UInt4 *)ADDR_OBJ(bag))[limbnumber] = value;
#endif
}


void C_SET_LIMB8(Obj bag, UInt limbnumber, UInt8 value)
{
#ifdef SYS_IS_64_BIT
    ((UInt8 *)ADDR_OBJ(bag))[limbnumber] = value;
#else
    ((UInt4 *)ADDR_OBJ(bag))[2 * limbnumber] = (UInt4)(value & 0xFFFFFFFFUL);
    ((UInt4 *)ADDR_OBJ(bag))[2 * limbnumber + 1] = (UInt4)(value >> 32);
#endif
}


static CVar CompIntExpr(Expr expr)
{
    CVar                val;
    Int                 siz;
    Int                 i;
    UInt                typ;

    if ( IS_INTEXPR(expr) ) {
        return CVAR_INTG( INT_INTEXPR(expr) );
    }
    else {
        // get the actual integer
        Obj obj = EVAL_EXPR(expr);

        val = CVAR_TEMP( NewTemp( "val" ) );
        siz = SIZE_OBJ(obj);
        typ = TNUM_OBJ(obj);
        if ( typ == T_INTPOS ) {
            Emit( "%c = NewWordSizedBag(T_INTPOS, %d);\n", val, siz);
            SetInfoCVar(val, W_INT_POS);
        }
        else {
            GAP_ASSERT(typ == T_INTNEG);
            Emit( "%c = NewWordSizedBag(T_INTNEG, %d);\n", val, siz);
            SetInfoCVar(val, W_INT);
        }

        for ( i = 0; i < siz/sizeof(UInt); i++ ) {
            UInt limb = CONST_ADDR_INT(obj)[i];
#ifdef SYS_IS_64_BIT
            Emit("C_SET_LIMB8( %c, %d, %dLL);\n", val, i, limb);
#else
            Emit("C_SET_LIMB4( %c, %d, %dL);\n", val, i, limb);
#endif
        }
        if (siz <= 8) {
            Emit("#ifdef SYS_IS_64_BIT");
            Emit("%c = C_NORMALIZE_64BIT(%c);\n", val,val);
            Emit("#endif");
        }
        return val;
    }
}

/****************************************************************************
**
*F  CompTildeExpr( <expr> )  . . . . . . . . . . . . . . . . . . EXPR_TILDE
*/

static CVar CompTildeExpr(Expr expr)
{
    Emit( "if ( ! STATE(Tilde) ) {\n");
    Emit( "    ErrorMayQuit(\"'~' does not have a value here\", 0, 0);\n" );
    Emit( "}\n" );
    CVar                val;            // value, result

    // allocate a new temporary for the 'true' value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code
    Emit( "%c = STATE(Tilde);\n", val );

    // return '~'
    return val;
}

/****************************************************************************
**
*F  CompTrueExpr( <expr> )  . . . . . . . . . . . . . . . . . . . EXPR_TRUE
*/

static CVar CompTrueExpr(Expr expr)
{
    CVar                val;            // value, result

    // allocate a new temporary for the 'true' value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code
    Emit( "%c = True;\n", val );

    // we know that the result is boolean ;-)
    SetInfoCVar( val, W_BOOL );

    // return 'true'
    return val;
}


/****************************************************************************
**
*F  CompFalseExpr( <expr> ) . . . . . . . . . . . . . . . . . .  EXPR_FALSE
*/

static CVar CompFalseExpr(Expr expr)
{
    CVar                val;            // value, result

    // allocate a new temporary for the 'false' value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code
    Emit( "%c = False;\n", val );

    // we know that the result is boolean ;-)
    SetInfoCVar( val, W_BOOL );

    // return 'false'
    return val;
}


/****************************************************************************
**
*F  CompCharExpr( <expr> )  . . . . . . . . . . . . . . . . . . . EXPR_CHAR
*/

static CVar CompCharExpr(Expr expr)
{
    CVar                val;            // result

    // allocate a new temporary for the char value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code
    Emit( "%c = ObjsChar[%d];\n", val, READ_EXPR(expr, 0));

    // we know that we have a value
    SetInfoCVar( val, W_BOUND );

    // return the value
    return val;
}


/****************************************************************************
**
*F  CompPermExpr( <expr> )  . . . . . . . . . . . . . . . . . . . EXPR_PERM
*/

static CVar CompPermExpr(Expr expr)
{
    CVar                perm;           // result
    CVar                lcyc;           // one cycle as list
    CVar                lprm;           // perm as list of list cycles
    CVar                val;            // one point
    Int                 i;
    Int                 j;
    Int                 n;
    Int                 csize;
    Expr                cycle;

    // check for the identity
    if ( SIZE_EXPR(expr) == 0 ) {
        perm = CVAR_TEMP( NewTemp( "idperm" ) );
        Emit( "%c = IdentityPerm;\n", perm );
        SetInfoCVar( perm, W_BOUND );
        return perm;
    }

    // for each cycle create a list
    perm = CVAR_TEMP( NewTemp( "perm" ) );
    lcyc = CVAR_TEMP( NewTemp( "lcyc" ) );
    lprm = CVAR_TEMP( NewTemp( "lprm" ) );

    // start with the identity permutation
    Emit( "%c = IdentityPerm;\n", perm );

    // loop over the cycles
    n = SIZE_EXPR(expr)/sizeof(Expr);
    Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", lprm, n );
    Emit( "SET_LEN_PLIST( %c, %d );\n", lprm, n );

    for ( i = 1;  i <= n;  i++ ) {
        cycle = READ_EXPR(expr, i - 1);
        csize = SIZE_EXPR(cycle)/sizeof(Expr);
        Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", lcyc, csize );
        Emit( "SET_LEN_PLIST( %c, %d );\n", lcyc, csize );
        Emit( "SET_ELM_PLIST( %c, %d, %c );\n", lprm, i, lcyc );
        Emit( "CHANGED_BAG( %c );\n", lprm );

        // loop over the entries of the cycle
        for ( j = 1;  j <= csize;  j++ ) {
            val = CompExpr(READ_EXPR(cycle, j - 1));
            Emit( "SET_ELM_PLIST( %c, %d, %c );\n", lcyc, j, val );
            Emit( "CHANGED_BAG( %c );\n", lcyc );
            if ( IS_TEMP_CVAR(val) )  FreeTemp( TEMP_CVAR(val) );
        }
    }
    Emit( "%c = Array2Perm( %c );\n", perm, lprm );

    // free the temporaries
    FreeTemp( TEMP_CVAR(lprm) );
    FreeTemp( TEMP_CVAR(lcyc) );

    return perm;
}


/****************************************************************************
**
*F  CompListExpr( <expr> )  . . . . . . . . . . . . . . . . . . . EXPR_LIST
*/

static CVar CompListExpr1(Expr expr);
static void CompListExpr2(CVar list, Expr expr);
static CVar CompRecExpr1(Expr expr);
static void CompRecExpr2(CVar rec, Expr expr);

static CVar CompListExpr(Expr expr)
{
    CVar                list;           // list, result

    // compile the list expression
    list = CompListExpr1( expr );
    CompListExpr2( list, expr );

    return list;
}


/****************************************************************************
**
*F  CompListTildeExpr( <expr> ) . . . . . . . . . . . . . . EXPR_LIST_TILDE
*/

static CVar CompListTildeExpr(Expr expr)
{
    CVar                list;           // list value, result
    CVar                tilde;          // old value of tilde

    // remember the old value of '~'
    tilde = CVAR_TEMP( NewTemp( "tilde" ) );
    Emit( "%c = STATE(Tilde);\n", tilde );

    // create the list value
    list = CompListExpr1( expr );

    // assign the list to '~'
    Emit( "STATE(Tilde) = %c;\n", list );

    // evaluate the subexpressions into the list value
    CompListExpr2( list, expr );

    // restore old value of '~'
    Emit( "STATE(Tilde) = %c;\n", tilde );
    if ( IS_TEMP_CVAR( tilde ) )  FreeTemp( TEMP_CVAR( tilde ) );

    // return the list value
    return list;
}


/****************************************************************************
**
*F  CompListExpr1( <expr> ) . . . . . . . . . . . . . . . . . . . . . . local
*/

static CVar CompListExpr1(Expr expr)
{
    CVar                list;           // list, result
    Int                 len;            // logical length of the list

    // get the length of the list
    len = SIZE_EXPR( expr ) / sizeof(Expr);

    // allocate a temporary for the list
    list = CVAR_TEMP( NewTemp( "list" ) );

    // emit the code to make the list
    Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", list, len );
    Emit( "SET_LEN_PLIST( %c, %d );\n", list, len );

    // we know that <list> is a list
    SetInfoCVar( list, W_LIST );

    // return the list
    return list;
}


/****************************************************************************
**
*F  CompListExpr2( <list>, <expr> ) . . . . . . . . . . . . . . . . . . local
*/

static void CompListExpr2(CVar list, Expr expr)
{
    CVar                sub;            // subexpression
    Int                 len;            // logical length of the list
    Int                 i;              // loop variable

    // get the length of the list
    len = SIZE_EXPR( expr ) / sizeof(Expr);

    // emit the code to fill the list
    for ( i = 1; i <= len; i++ ) {

        // if the subexpression is empty
        if (READ_EXPR(expr, i - 1) == 0) {
            continue;
        }

        // special case if subexpression is a list expression
        else if (TNUM_EXPR(READ_EXPR(expr, i - 1)) == EXPR_LIST) {
            sub = CompListExpr1(READ_EXPR(expr, i - 1));
            Emit( "SET_ELM_PLIST( %c, %d, %c );\n", list, i, sub );
            Emit( "CHANGED_BAG( %c );\n", list );
            CompListExpr2(sub, READ_EXPR(expr, i - 1));
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

        // special case if subexpression is a record expression
        else if (TNUM_EXPR(READ_EXPR(expr, i - 1)) == EXPR_REC) {
            sub = CompRecExpr1(READ_EXPR(expr, i - 1));
            Emit( "SET_ELM_PLIST( %c, %d, %c );\n", list, i, sub );
            Emit( "CHANGED_BAG( %c );\n", list );
            CompRecExpr2(sub, READ_EXPR(expr, i - 1));
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

        // general case
        else {
            sub = CompExpr(READ_EXPR(expr, i - 1));
            Emit( "SET_ELM_PLIST( %c, %d, %c );\n", list, i, sub );
            if ( ! HasInfoCVar( sub, W_INT_SMALL ) ) {
                Emit( "CHANGED_BAG( %c );\n", list );
            }
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

    }

}


/****************************************************************************
**
*F  CompRangeExpr( <expr> ) . . . . . . . . . . . . . . . . . .  EXPR_RANGE
*/

static CVar CompRangeExpr(Expr expr)
{
    CVar                range;          // range, result
    CVar                first;          // first  element
    CVar                second;         // second element
    CVar                last;           // last   element

    // allocate a new temporary for the range
    range = CVAR_TEMP( NewTemp( "range" ) );

    // evaluate the expressions
    if ( SIZE_EXPR(expr) == 2 * sizeof(Expr) ) {
        first  = CompExpr( READ_EXPR(expr, 0) );
        second = 0;
        last   = CompExpr( READ_EXPR(expr, 1) );
    }
    else {
        first  = CompExpr( READ_EXPR(expr, 0) );
        second = CompExpr( READ_EXPR(expr, 1) );
        last   = CompExpr( READ_EXPR(expr, 2) );
    }

    // emit the code
    if ( SIZE_EXPR(expr) == 2 * sizeof(Expr) ) {
        Emit( "%c = Range2Check( %c, %c );\n",
              range, first, last );
    }
    else {
        Emit( "%c = Range3Check( %c, %c, %c );\n",
              range, first, second, last );
    }

    // we know that the result is a list
    SetInfoCVar( range, W_LIST );

    // free the temporaries
    if ( SIZE_EXPR(expr) == 2 * sizeof(Expr) ) {
        if ( IS_TEMP_CVAR( last   ) )  FreeTemp( TEMP_CVAR( last   ) );
        if ( IS_TEMP_CVAR( first  ) )  FreeTemp( TEMP_CVAR( first  ) );
    }
    else {
        if ( IS_TEMP_CVAR( last   ) )  FreeTemp( TEMP_CVAR( last   ) );
        if ( IS_TEMP_CVAR( second ) )  FreeTemp( TEMP_CVAR( second ) );
        if ( IS_TEMP_CVAR( first  ) )  FreeTemp( TEMP_CVAR( first  ) );
    }

    // return the range
    return range;
}


/****************************************************************************
**
*F  CompStringExpr( <expr> )  . . . . . . . . . . compile a string expression
*/

static CVar CompStringExpr(Expr expr)
{
    CVar                string;         // string value, result
    Obj                 str;            // the actual string object

    // allocate a new temporary for the string
    string = CVAR_TEMP( NewTemp( "string" ) );

    // get the string of this expression
    str = EVAL_EXPR(expr);

    // create the string and copy the stuff
    Emit( "%c = MakeString( \"%C\" );\n", string, str);

    // we know that the result is a list
    SetInfoCVar( string, W_LIST );

    // return the string
    return string;
}


/****************************************************************************
**
*F  CompRecExpr( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_REC
*/

static CVar CompRecExpr(Expr expr)
{
    CVar                rec;            // record value, result

    // compile the record expression
    rec = CompRecExpr1( expr );
    CompRecExpr2( rec, expr );

    return rec;
}


/****************************************************************************
**
*F  CompRecTildeExpr( <expr> )  . . . . . . . . . . . . . .  EXPR_REC_TILDE
*/

static CVar CompRecTildeExpr(Expr expr)
{
    CVar                rec;            // record value, result
    CVar                tilde;          // old value of tilde

    // remember the old value of '~'
    tilde = CVAR_TEMP( NewTemp( "tilde" ) );
    Emit( "%c = STATE(Tilde);\n", tilde );

    // create the record value
    rec = CompRecExpr1( expr );

    // assign the record value to the variable '~'
    Emit( "STATE(Tilde) = %c;\n", rec );

    // evaluate the subexpressions into the record value
    CompRecExpr2( rec, expr );

    // restore the old value of '~'
    Emit( "STATE(Tilde) = %c;\n", tilde );
    if ( IS_TEMP_CVAR( tilde ) )  FreeTemp( TEMP_CVAR( tilde ) );

    // return the record value
    return rec;
}


/****************************************************************************
**
*F  CompRecExpr1( <expr> )  . . . . . . . . . . . . . . . . . . . . . . local
*/

static CVar CompRecExpr1(Expr expr)
{
    CVar                rec;            // record value, result
    Int                 len;            // number of components

    // get the number of components
    len = SIZE_EXPR( expr ) / (2*sizeof(Expr));

    // allocate a new temporary for the record
    rec = CVAR_TEMP( NewTemp( "rec" ) );

    // emit the code to allocate the new record object
    Emit( "%c = NEW_PREC( %d );\n", rec, len );

    // we know that we have a value
    SetInfoCVar( rec, W_BOUND );

    // return the record
    return rec;
}


/****************************************************************************
**
*F  CompRecExpr2( <rec>, <expr> ) . . . . . . . . . . . . . . . . . . . local
*/

static void CompRecExpr2(CVar rec, Expr expr)
{
    CVar                rnam;           // name of component
    CVar                sub;            // value of subexpression
    Int                 len;            // number of components
    Expr                tmp;            // temporary variable
    Int                 i;              // loop variable

    // get the number of components
    len = SIZE_EXPR( expr ) / (2*sizeof(Expr));

    // handle the subexpressions
    for ( i = 1; i <= len; i++ ) {

        // handle the name
        tmp = READ_EXPR(expr, 2 * i - 2);
        rnam = CVAR_TEMP( NewTemp( "rnam" ) );
        if ( IS_INTEXPR(tmp) ) {
            CompSetUseRNam( (UInt)INT_INTEXPR(tmp), COMP_USE_RNAM_ID );
            Emit( "%c = (Obj)R_%n;\n",
                  rnam, NAME_RNAM((UInt)INT_INTEXPR(tmp)) );
        }
        else {
            sub = CompExpr( tmp );
            Emit( "%c = (Obj)RNamObj( %c );\n", rnam, sub );
        }

        // if the subexpression is empty (cannot happen for records)
        tmp = READ_EXPR(expr, 2 * i - 1);
        if ( tmp == 0 ) {
            if ( IS_TEMP_CVAR( rnam ) )  FreeTemp( TEMP_CVAR( rnam ) );
            continue;
        }

        // special case if subexpression is a list expression
        else if ( TNUM_EXPR( tmp ) == EXPR_LIST ) {
            sub = CompListExpr1( tmp );
            Emit( "AssPRec( %c, (UInt)%c, %c );\n", rec, rnam, sub );
            CompListExpr2( sub, tmp );
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

        // special case if subexpression is a record expression
        else if ( TNUM_EXPR( tmp ) == EXPR_REC ) {
            sub = CompRecExpr1( tmp );
            Emit( "AssPRec( %c, (UInt)%c, %c );\n", rec, rnam, sub );
            CompRecExpr2( sub, tmp );
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

        // general case
        else {
            sub = CompExpr( tmp );
            Emit( "AssPRec( %c, (UInt)%c, %c );\n", rec, rnam, sub );
            if ( IS_TEMP_CVAR( sub ) )  FreeTemp( TEMP_CVAR( sub ) );
        }

        if ( IS_TEMP_CVAR( rnam ) )  FreeTemp( TEMP_CVAR( rnam ) );
    }
    Emit( "SortPRecRNam( %c );\n", rec );

}


/****************************************************************************
**
*F  CompRefLVar( <expr> ) . . . . . . .  EXPR_REF_LVAR
*/

static CVar CompRefLVar(Expr expr)
{
    CVar                val;            // value, result
    LVar                lvar;           // local variable

    lvar = LVAR_REF_LVAR(expr);

    // emit the code to get the value
    if ( CompGetUseHVar( lvar ) ) {
        val = CVAR_TEMP( NewTemp( "val" ) );
        Emit( "%c = OBJ_LVAR( %d );\n", val, GetIndxHVar(lvar) );
    }
    else {
        val = CVAR_LVAR(lvar);
    }

    // emit code to check that the variable has a value
    CompCheckBound( val, NAME_LVAR(lvar) );

    // return the value
    return val;
}


/****************************************************************************
**
*F  CompIsbLVar( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_ISB_LVAR
*/

static CVar CompIsbLVar(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                val;            // value
    LVar                lvar;           // local variable

    // get the local variable
    lvar = (LVar)(READ_EXPR(expr, 0));

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // emit the code to get the value
    if ( CompGetUseHVar( lvar ) ) {
        val = CVAR_TEMP( NewTemp( "val" ) );
        Emit( "%c = OBJ_LVAR( %d );\n", val, GetIndxHVar(lvar) );
    }
    else {
        val = CVAR_LVAR(lvar);
    }

    // emit the code to check that the variable has a value
    Emit( "%c = ((%c != 0) ? True : False);\n", isb, val );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( val ) )  FreeTemp( TEMP_CVAR( val ) );

    return isb;
}


/****************************************************************************
**
*F  CompRefHVar( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_REF_HVAR
*/

static CVar CompRefHVar(Expr expr)
{
    CVar                val;            // value, result
    HVar                hvar;           // higher variable

    // get the higher variable
    hvar = (HVar)(READ_EXPR(expr, 0));
    CompSetUseHVar( hvar );

    // allocate a new temporary for the value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code to get the value
    Emit( "%c = OBJ_HVAR( (%d << 16) | %d );\n",
          val, GetLevlHVar(hvar), GetIndxHVar(hvar) );

    // emit the code to check that the variable has a value
    CompCheckBound( val, NAME_HVAR(hvar) );

    // return the value
    return val;
}


/****************************************************************************
**
*F  CompIsbHVar( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_ISB_HVAR
*/

static CVar CompIsbHVar(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                val;            // value
    HVar                hvar;           // higher variable

    // get the higher variable
    hvar = (HVar)(READ_EXPR(expr, 0));
    CompSetUseHVar( hvar );

    // allocate new temporaries for the value and the result
    val = CVAR_TEMP( NewTemp( "val" ) );
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // emit the code to get the value
    Emit( "%c = OBJ_HVAR( (%d << 16) | %d );\n",
          val, GetLevlHVar(hvar), GetIndxHVar(hvar) );

    // emit the code to check that the variable has a value
    Emit( "%c = ((%c != 0) ? True : False);\n", isb, val );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( val ) )  FreeTemp( TEMP_CVAR( val ) );

    return isb;
}


/****************************************************************************
**
*F  CompRefGVar( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_REF_GVAR
*/

static CVar CompRefGVar(Expr expr)
{
    CVar                val;            // value, result
    GVar                gvar;           // higher variable

    // get the global variable
    gvar = (GVar)(READ_EXPR(expr, 0));
    CompSetUseGVar( gvar, COMP_USE_GVAR_COPY );

    // allocate a new global variable for the value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code to get the value
    Emit( "%c = GC_%n;\n", val, NameGVar(gvar) );

    // emit the code to check that the variable has a value
    CompCheckBound( val, NameGVar(gvar) );

    // return the value
    return val;
}


/****************************************************************************
**
*F  CompRefGVarFopy( <expr> ) . . . . . . . . . . . . . . . . . . . . . local
*/

static CVar CompRefGVarFopy(Expr expr)
{
    CVar                val;            // value, result
    GVar                gvar;           // higher variable

    // get the global variable
    gvar = (GVar)(READ_EXPR(expr, 0));
    CompSetUseGVar( gvar, COMP_USE_GVAR_FOPY );

    // allocate a new temporary for the value
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code to get the value
    Emit( "%c = GF_%n;\n", val, NameGVar(gvar) );

    // we know that the object in a function copy is a function
    SetInfoCVar( val, W_FUNC );

    // return the value
    return val;
}


/****************************************************************************
**
*F  CompIsbGVar( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_ISB_GVAR
*/

static CVar CompIsbGVar(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                val;            // value, result
    GVar                gvar;           // higher variable

    // get the global variable
    gvar = (GVar)(READ_EXPR(expr, 0));
    CompSetUseGVar( gvar, COMP_USE_GVAR_COPY );

    // allocate new temporaries for the value and the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );
    val = CVAR_TEMP( NewTemp( "val" ) );

    // emit the code to get the value
    Emit( "%c = GC_%n;\n", val, NameGVar(gvar) );

    // emit the code to check that the variable has a value
    Emit( "%c = ((%c != 0) ? True : False);\n", isb, val );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( val ) )  FreeTemp( TEMP_CVAR( val ) );

    return isb;
}


/****************************************************************************
**
*F  CompElmList( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_ELM_LIST
*/

static CVar CompElmList(Expr expr)
{
    CVar                elm;            // element, result
    CVar                list;           // list
    CVar                pos;            // position

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the list expression (checking is done by 'ELM_LIST')
    list = CompExpr(READ_EXPR(expr, 0));

    // compile and check the position expression
    pos = CompExpr(READ_EXPR(expr, 1));
    CompCheckIntPos( pos );

    // emit the code to get the element
    if (        CompCheckListElements &&   CompFastPlainLists ) {
        Emit( "C_ELM_LIST_FPL( %c, %c, %c )\n", elm, list, pos );
    }
    else if (   CompCheckListElements && ! CompFastPlainLists ) {
        Emit( "C_ELM_LIST( %c, %c, %c );\n", elm, list, pos );
    }
    else if ( ! CompCheckListElements &&   CompFastPlainLists ) {
        Emit( "C_ELM_LIST_NLE_FPL( %c, %c, %c );\n", elm, list, pos );
    }
    else {
        Emit( "C_ELM_LIST_NLE( %c, %c, %c );\n", elm, list, pos );
    }

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );

    // return the element
    return elm;
}


/****************************************************************************
**
*F  CompElmsList( <expr> )  . . . . . . . . . . . . . . . . . . . EXPR_ELMS_LIST
*/

static CVar CompElmsList(Expr expr)
{
    CVar                elms;           // elements, result
    CVar                list;           // list
    CVar                poss;           // positions

    // allocate a new temporary for the elements
    elms = CVAR_TEMP( NewTemp( "elms" ) );

    // compile the list expression (checking is done by 'ElmsListCheck')
    list = CompExpr(READ_EXPR(expr, 0));

    // compile the position expression (checking done by 'ElmsListCheck')
    poss = CompExpr(READ_EXPR(expr, 1));

    // emit the code to get the element
    Emit( "%c = ElmsListCheck( %c, %c );\n", elms, list, poss );

    // we know that the elements are a list
    SetInfoCVar( elms, W_LIST );

    // free the temporaries
    if ( IS_TEMP_CVAR( poss ) )  FreeTemp( TEMP_CVAR( poss ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );

    // return the elements
    return elms;
}


/****************************************************************************
**
*F  CompElmListLev( <expr> )  . . . . . . . . . . . . . . . .  EXPR_ELM_LIST_LEV
*/

static CVar CompElmListLev(Expr expr)
{
    CVar                lists;          // lists
    CVar                pos;            // position
    UInt                level;          // level

    // compile the lists expression
    lists = CompExpr(READ_EXPR(expr, 0));

    // compile and check the position expression
    pos = CompExpr(READ_EXPR(expr, 1));
    CompCheckIntSmallPos( pos );

    // get the level
    level = READ_EXPR(expr, 2);

    // emit the code to select the elements from several lists (to <lists>)
    Emit( "ElmListLevel( %c, %c, %d );\n", lists, pos, level );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos   ) )  FreeTemp( TEMP_CVAR( pos   ) );

    // return the lists
    return lists;
}


/****************************************************************************
**
*F  CompElmsListLev( <expr> ) . . . . . . . . . . . . . . . . EXPR_ELMS_LIST_LEV
*/

static CVar CompElmsListLev(Expr expr)
{
    CVar                lists;          // lists
    CVar                poss;           // positions
    UInt                level;          // level

    // compile the lists expression
    lists = CompExpr(READ_EXPR(expr, 0));

    // compile the position expression (checking done by 'ElmsListLevel')
    poss = CompExpr(READ_EXPR(expr, 1));

    // get the level
    level = READ_EXPR(expr, 2);

    // emit the code to select the elements from several lists (to <lists>)
    Emit( "ElmsListLevelCheck( %c, %c, %d );\n", lists, poss, level );

    // free the temporaries
    if ( IS_TEMP_CVAR( poss  ) )  FreeTemp( TEMP_CVAR( poss  ) );

    // return the lists
    return lists;
}


/****************************************************************************
**
*F  CompIsbList( <expr> ) . . . . . . . . . . . . . . . . . . . .  EXPR_ISB_LIST
*/

static CVar CompIsbList(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                list;           // list
    CVar                pos;            // position

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the list expression (checking is done by 'ISB_LIST')
    list = CompExpr(READ_EXPR(expr, 0));

    // compile and check the position expression
    pos = CompExpr(READ_EXPR(expr, 1));
    CompCheckIntPos( pos );

    // emit the code to test the element
    Emit( "%c = C_ISB_LIST( %c, %c );\n", isb, list, pos );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );

    // return the element
    return isb;
}


/****************************************************************************
**
*F  CompElmRecName( <expr> )  . . . . . . . . . . . . . . . .  EXPR_ELM_REC_NAME
*/

static CVar CompElmRecName(Expr expr)
{
    CVar                elm;            // element, result
    CVar                record;         // the record, left operand
    UInt                rnam;           // the name, right operand

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the record expression (checking is done by 'ELM_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = READ_EXPR(expr, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code to select the element of the record
    Emit( "%c = ELM_REC( %c, R_%n );\n", elm, record, NAME_RNAM(rnam) );

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    // return the element
    return elm;
}


/****************************************************************************
**
*F  CompElmRecExpr( <expr> )  . . . . . . . . . . . . . . . .  EXPR_ELM_REC_EXPR
*/

static CVar CompElmRecExpr(Expr expr)
{
    CVar                elm;            // element, result
    CVar                record;         // the record, left operand
    CVar                rnam;           // the name, right operand

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the record expression (checking is done by 'ELM_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // compile the record name expression
    rnam = CompExpr(READ_EXPR(expr, 1));

    // emit the code to select the element of the record
    Emit( "%c = ELM_REC( %c, RNamObj(%c) );\n", elm, record, rnam );

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    // return the element
    return elm;
}


/****************************************************************************
**
*F  CompIsbRecName( <expr> )  . . . . . . . . . . . . . . . .  EXPR_ISB_REC_NAME
*/

static CVar CompIsbRecName(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                record;         // the record, left operand
    UInt                rnam;           // the name, right operand

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the record expression (checking is done by 'ISB_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = READ_EXPR(expr, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code to test the element
    Emit( "%c = (ISB_REC( %c, R_%n ) ? True : False);\n",
          isb, record, NAME_RNAM(rnam) );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    return isb;
}


/****************************************************************************
**
*F  CompIsbRecExpr( <expr> )  . . . . . . . . . . . . . . . .  EXPR_ISB_REC_EXPR
*/

static CVar CompIsbRecExpr(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                record;         // the record, left operand
    CVar                rnam;           // the name, right operand

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the record expression (checking is done by 'ISB_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // compile the record name expression
    rnam = CompExpr(READ_EXPR(expr, 1));

    // emit the code to test the element
    Emit( "%c = (ISB_REC( %c, RNamObj(%c) ) ? True : False);\n",
          isb, record, rnam );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    return isb;
}


/****************************************************************************
**
*F  CompElmPosObj( <expr> ) . . . . . . . . . . . . . . . . . .  EXPR_ELM_POSOBJ
*/

static CVar CompElmPosObj(Expr expr)
{
    CVar                elm;            // element, result
    CVar                list;           // list
    CVar                pos;            // position

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the list expression (checking is done by 'ELM_LIST')
    list = CompExpr(READ_EXPR(expr, 0));

    // compile and check the position expression
    pos = CompExpr(READ_EXPR(expr, 1));
    CompCheckIntSmallPos( pos );

    // emit the code to get the element
    Emit( "%c = ElmPosObj( %c, %i );\n", elm, list, pos );

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );

    // return the element
    return elm;
}


/****************************************************************************
**
*F  CompIsbPosObj( <expr> ) . . . . . . . . . . . . . . . . . .  EXPR_ISB_POSOBJ
*/

static CVar CompIsbPosObj(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                list;           // list
    CVar                pos;            // position

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the list expression (checking is done by 'ISB_LIST')
    list = CompExpr(READ_EXPR(expr, 0));

    // compile and check the position expression
    pos = CompExpr(READ_EXPR(expr, 1));
    CompCheckIntSmallPos( pos );

    // emit the code to test the element
    Emit( "%c = IsbPosObj( %c, %i ) ? True : False;\n", isb, list, pos );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );

    // return the element
    return isb;
}


/****************************************************************************
**
*F  CompElmObjName( <expr> )  . . . . . . . . . . . . . . . EXPR_ELM_COMOBJ_NAME
*/

static CVar CompElmComObjName(Expr expr)
{
    CVar                elm;            // element, result
    CVar                record;         // the record, left operand
    UInt                rnam;           // the name, right operand

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the record expression (checking is done by 'ELM_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = READ_EXPR(expr, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code to select the element of the record
    Emit( "%c = ElmComObj( %c, R_%n );\n", elm, record, NAME_RNAM(rnam) );

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    // return the element
    return elm;
}



/****************************************************************************
**
*F  CompElmComObjExpr( <expr> ) . . . . . . . . . . . . . . EXPR_ELM_COMOBJ_EXPR
*/

static CVar CompElmComObjExpr(Expr expr)
{
    CVar                elm;            // element, result
    CVar                record;         // the record, left operand
    CVar                rnam;           // the name, right operand

    // allocate a new temporary for the element
    elm = CVAR_TEMP( NewTemp( "elm" ) );

    // compile the record expression (checking is done by 'ELM_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = CompExpr(READ_EXPR(expr, 1));

    // emit the code to select the element of the record
    Emit( "%c = ElmComObj( %c, RNamObj(%c) );\n", elm, record, rnam );

    // we know that we have a value
    SetInfoCVar( elm, W_BOUND );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    // return the element
    return elm;
}


/****************************************************************************
**
*F  CompIsbComObjName( <expr> ) . . . . . . . . . . . . . . EXPR_ISB_COMOBJ_NAME
*/

static CVar CompIsbComObjName(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                record;         // the record, left operand
    UInt                rnam;           // the name, right operand

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the record expression (checking is done by 'ISB_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = READ_EXPR(expr, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code to test the element
    Emit( "%c = IsbComObj( %c, R_%n ) ? True : False;\n",
          isb, record, NAME_RNAM(rnam) );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    return isb;
}


/****************************************************************************
**
*F  CompIsbComObjExpr( <expr> ) . . . . . . . . . . . . . . EXPR_ISB_COMOBJ_EXPR
*/

static CVar CompIsbComObjExpr(Expr expr)
{
    CVar                isb;            // isbound, result
    CVar                record;         // the record, left operand
    UInt                rnam;           // the name, right operand

    // allocate a new temporary for the result
    isb = CVAR_TEMP( NewTemp( "isb" ) );

    // compile the record expression (checking is done by 'ISB_REC')
    record = CompExpr(READ_EXPR(expr, 0));

    // get the name (stored immediately in the expression)
    rnam = CompExpr(READ_EXPR(expr, 1));

    // emit the code to test the element
    Emit( "%c = IsbComObj( %c, RNamObj(%c) ) ? True : False;\n",
          isb, record, rnam );

    // we know that the result is boolean
    SetInfoCVar( isb, W_BOOL );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );

    return isb;
}


/****************************************************************************
**
*F * * * * * * * * * * * * * compile statements * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  CompStat( <stat> )  . . . . . . . . . . . . . . . . . compile a statement
**
**  'CompStat' compiles the statement <stat>.
*/

static void (*CompStatFuncs[256])(Stat stat);

static void CompStat(Stat stat)
{
    (* CompStatFuncs[ TNUM_STAT(stat) ])( stat );
}


/****************************************************************************
**
*F  CompUnknownStat( <stat> ) . . . . . . . . . . . . . . . . signal an error
*/

static void CompUnknownStat(Stat stat)
{
    Emit( "CANNOT COMPILE STATEMENT OF TNUM %d;\n", TNUM_STAT(stat) );
}


/****************************************************************************
**
*V  G_Add . . . . . . . . . . . . . . . . . . . . . . . . . .  function 'Add'
*/

static GVar G_Add;


/****************************************************************************
**
*F  CompProccall0to6Args( <stat> )  . . . STAT_PROCCALL_0ARGS...STAT_PROCCALL_6ARGS
*/

static void CompProccall0to6Args(Stat stat)
{
    CVar                func;           // function
    CVar                args[8];        // arguments
    UInt                narg;           // number of arguments
    UInt                i;              // loop variable

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // special case to inline 'Add'
    if ( CompFastListFuncs
      && TNUM_EXPR( FUNC_CALL(stat) ) == EXPR_REF_GVAR
      && READ_EXPR( FUNC_CALL(stat), 0 ) == G_Add
      && NARG_SIZE_CALL(SIZE_EXPR(stat)) == 2 ) {
        args[1] = CompExpr( ARGI_CALL(stat,1) );
        args[2] = CompExpr( ARGI_CALL(stat,2) );
        if ( CompFastPlainLists ) {
            Emit( "C_ADD_LIST_FPL( %c, %c )\n", args[1], args[2] );
        }
        else {
            Emit( "C_ADD_LIST( %c, %c )\n", args[1], args[2] );
        }
        if ( IS_TEMP_CVAR( args[2] ) )  FreeTemp( TEMP_CVAR( args[2] ) );
        if ( IS_TEMP_CVAR( args[1] ) )  FreeTemp( TEMP_CVAR( args[1] ) );
        return;
    }

    // compile the reference to the function
    if ( TNUM_EXPR( FUNC_CALL(stat) ) == EXPR_REF_GVAR ) {
        func = CompRefGVarFopy( FUNC_CALL(stat) );
    }
    else {
        func = CompExpr( FUNC_CALL(stat) );
    }

    // compile the argument expressions
    narg = NARG_SIZE_CALL(SIZE_STAT(stat));
    for ( i = 1; i <= narg; i++ ) {
        args[i] = CompExpr( ARGI_CALL(stat,i) );
    }

    // emit the code for the procedure call
    Emit( "if ( TNUM_OBJ( %c ) == T_FUNCTION ) {\n", func );
    Emit( "CALL_%dARGS( %c", narg, func );
    for ( i = 1; i <= narg; i++ ) {
        Emit( ", %c", args[i] );
    }
    Emit( " );\n" );
    Emit( "}\n" );
    Emit( "else {\n" );
    Emit( "DoOperation2Args( CallFuncListOper, %c, NewPlistFromArgs(", func);
    if (narg >= 1) {
        Emit( " %c", args[1] );
    }
    for ( i = 2; i <= narg; i++ ) {
        Emit( ", %c", args[i] );
    }
    Emit( " ) );\n" );
    Emit( "}\n" );

    // free the temporaries
    for ( i = narg; 1 <= i; i-- ) {
        if ( IS_TEMP_CVAR( args[i] ) )  FreeTemp( TEMP_CVAR( args[i] ) );
    }
    if ( IS_TEMP_CVAR( func ) )  FreeTemp( TEMP_CVAR( func ) );
}


/****************************************************************************
**
*F  CompProccallXArgs . . . . . . . . . . . . . . . . . . .  STAT_PROCCALL_XARGS
*/

static void CompProccallXArgs(Stat stat)
{
    CVar                func;           // function
    CVar                argl;           // argument list
    CVar                argi;           // <i>-th argument
    UInt                narg;           // number of arguments
    UInt                i;              // loop variable

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the reference to the function
    if ( TNUM_EXPR( FUNC_CALL(stat) ) == EXPR_REF_GVAR ) {
        func = CompRefGVarFopy( FUNC_CALL(stat) );
    }
    else {
        func = CompExpr( FUNC_CALL(stat) );
    }

    // compile the argument expressions
    narg = NARG_SIZE_CALL(SIZE_STAT(stat));
    argl = CVAR_TEMP( NewTemp( "argl" ) );
    Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", argl, narg );
    Emit( "SET_LEN_PLIST( %c, %d );\n", argl, narg );
    for ( i = 1; i <= narg; i++ ) {
        argi = CompExpr( ARGI_CALL( stat, i ) );
        Emit( "SET_ELM_PLIST( %c, %d, %c );\n", argl, i, argi );
        if ( ! HasInfoCVar( argi, W_INT_SMALL ) ) {
            Emit( "CHANGED_BAG( %c );\n", argl );
        }
        if ( IS_TEMP_CVAR( argi ) )  FreeTemp( TEMP_CVAR( argi ) );
    }

    // emit the code for the procedure call
    Emit( "if ( TNUM_OBJ( %c ) == T_FUNCTION ) {\n", func );
    Emit( "CALL_XARGS( %c, %c );\n", func, argl );
    Emit( "}\n" );
    Emit( "else {\n" );
    Emit( "DoOperation2Args( CallFuncListOper, %c, %c );\n", func, argl );
    Emit( "}\n" );

    // free the temporaries
    if ( IS_TEMP_CVAR( argl ) )  FreeTemp( TEMP_CVAR( argl ) );
    if ( IS_TEMP_CVAR( func ) )  FreeTemp( TEMP_CVAR( func ) );
}

/****************************************************************************
**
*F  CompProccallXArgs( <expr> ) . . . . . . . . . . . . . .  STAT_PROCCALL_OPTS
*/

static void CompProccallOpts(Stat stat)
{
  CVar opts = CompExpr(READ_STAT(stat, 0));
  GVar pushOptions;
  GVar popOptions;
  pushOptions = GVarName("PushOptions");
  popOptions = GVarName("PopOptions");
  CompSetUseGVar(pushOptions, COMP_USE_GVAR_FOPY);
  CompSetUseGVar(popOptions, COMP_USE_GVAR_FOPY);
  Emit("CALL_1ARGS( GF_PushOptions, %c );\n", opts);
  if (IS_TEMP_CVAR( opts) ) FreeTemp( TEMP_CVAR( opts ));
  CompStat(READ_STAT(stat, 1));
  Emit("CALL_0ARGS( GF_PopOptions );\n");
}


/****************************************************************************
**
*F  CompSeqStat( <stat> ) . . . . . . . . . . . . .  STAT_SEQ_STAT...STAT_SEQ_STAT7
*/

static void CompSeqStat(Stat stat)
{
    UInt                nr;             // number of statements
    UInt                i;              // loop variable

    // get the number of statements
    nr = SIZE_STAT( stat ) / sizeof(Stat);

    // compile the statements
    for ( i = 1; i <= nr; i++ ) {
        CompStat(READ_STAT(stat, i - 1));
    }
}


/****************************************************************************
**
*F  CompIf( <stat> )  . . . . . . . . STAT_IF/STAT_IF_ELSE/STAT_IF_ELIF/STAT_IF_ELIF_ELSE
*/

static void CompIf(Stat stat)
{
    CVar                cond;           // condition
    UInt                nr;             // number of branches
    Bag                 info_in;        // information at branch begin
    Bag                 info_out;       // information at branch end
    UInt                i;              // loop variable

    // get the number of branches
    nr = SIZE_STAT( stat ) / (2*sizeof(Stat));

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* if " );
        PrintExpr(READ_EXPR(stat, 0));
        Emit( " then */\n" );
    }

    // compile the expression
    cond = CompBoolExpr(READ_STAT(stat, 0));

    // emit the code to test the condition
    Emit( "if ( %c ) {\n", cond );
    if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );

    // remember what we know after evaluating the first condition
    info_in = NewInfoCVars();
    CopyInfoCVars( info_in, INFO_FEXP(CURR_FUNC()) );

    // compile the body
    CompStat(READ_STAT(stat, 1));

    // remember what we know after executing the first body
    info_out = NewInfoCVars();
    CopyInfoCVars( info_out, INFO_FEXP(CURR_FUNC()) );

    // emit the rest code
    Emit( "\n}\n" );

    // loop over the 'elif' branches
    for ( i = 2; i <= nr; i++ ) {

        // do not handle 'else' branch here
        if (i == nr && TNUM_EXPR(READ_STAT(stat, 2 * (i - 1))) == EXPR_TRUE)
            break;

        // print a comment
        if ( CompPass == 2 ) {
            Emit( "\n/* elif " );
            PrintExpr(READ_EXPR(stat, 2 * (i - 1)));
            Emit( " then */\n" );
        }

        // emit the 'else' to connect this branch to the 'if' branch
        Emit( "else {\n" );

        // this is what we know if we enter this branch
        CopyInfoCVars( INFO_FEXP(CURR_FUNC()), info_in );

        // compile the expression
        cond = CompBoolExpr(READ_STAT(stat, 2 * (i - 1)));

        // emit the code to test the condition
        Emit( "if ( %c ) {\n", cond );
        if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );

        // remember what we know after evaluating all previous conditions
        CopyInfoCVars( info_in, INFO_FEXP(CURR_FUNC()) );

        // compile the body
        CompStat(READ_STAT(stat, 2 * (i - 1) + 1));

        // remember what we know after executing one of the previous bodies
        MergeInfoCVars( info_out, INFO_FEXP(CURR_FUNC()) );

        // emit the rest code
        Emit( "\n}\n" );

    }

    // handle 'else' branch
    if ( i == nr ) {

        // print a comment
        if ( CompPass == 2 ) {
            Emit( "\n/* else */\n" );
        }

        // emit the 'else' to connect this branch to the 'if' branch
        Emit( "else {\n" );

        // this is what we know if we enter this branch
        CopyInfoCVars( INFO_FEXP(CURR_FUNC()), info_in );

        // compile the body
        CompStat(READ_STAT(stat, 2 * (i - 1) + 1));

        // remember what we know after executing one of the previous bodies
        MergeInfoCVars( info_out, INFO_FEXP(CURR_FUNC()) );

        // emit the rest code
        Emit( "\n}\n" );

    }

    // fake empty 'else' branch
    else {

        // this is what we know if we enter this branch
        CopyInfoCVars( INFO_FEXP(CURR_FUNC()), info_in );

        // remember what we know after executing one of the previous bodies
        MergeInfoCVars( info_out, INFO_FEXP(CURR_FUNC()) );

    }

    // close all unbalanced parenthesis
    for ( i = 2; i <= nr; i++ ) {
        if (i == nr && TNUM_EXPR(READ_STAT(stat, 2 * (i - 1))) == EXPR_TRUE)
            break;
        Emit( "}\n" );
    }
    Emit( "/* fi */\n" );

    // put what we know into the current info
    CopyInfoCVars( INFO_FEXP(CURR_FUNC()), info_out );

}


/****************************************************************************
**
*F  CompFor( <stat> ) . . . . . . . STAT_FOR...STAT_FOR3/STAT_FOR_RANGE...STAT_FOR_RANGE3
*/

static void CompFor(Stat stat)
{
    UInt                var;            // loop variable
    Char                vart;           // variable type
    CVar                list;           // list to loop over
    CVar                islist;         // is the list a proper list
    CVar                first;          // first loop index
    CVar                last;           // last  loop index
    CVar                lidx;           // loop index variable
    CVar                elm;            // element of list
    Int                 pass;           // current pass
    Bag                 prev;           // previous temp-info
    Int                 i;              // loop variable

    // handle 'for <lvar> in [<first>..<last>] do'
    if ( IS_REF_LVAR( READ_STAT(stat, 0) )
      && ! CompGetUseHVar( LVAR_REF_LVAR( READ_STAT(stat, 0) ) )
      && TNUM_EXPR( READ_STAT(stat, 1) ) == EXPR_RANGE
      && SIZE_EXPR( READ_STAT(stat, 1) ) == 2*sizeof(Expr) ) {

        // print a comment
        if ( CompPass == 2 ) {
            Emit( "\n/* for " );
            PrintExpr(READ_EXPR(stat, 0));
            Emit( " in " );
            PrintExpr(READ_EXPR(stat, 1));
            Emit( " do */\n" );
        }

        // get the local variable
        var = LVAR_REF_LVAR(READ_STAT(stat, 0));

        // allocate a new temporary for the loop variable
        lidx = CVAR_TEMP( NewTemp( "lidx" ) );

        // compile and check the first and last value
        first = CompExpr(READ_EXPR(READ_STAT(stat, 1), 0));
        CompCheckIntSmall( first );

        // compile and check the last value
        // if the last value is in a local variable,
        // we must copy it into a temporary,
        // because the local variable may change its value in the body
        last = CompExpr(READ_EXPR(READ_STAT(stat, 1), 1));
        CompCheckIntSmall( last  );
        if ( IS_LVAR_CVAR(last) ) {
            elm = CVAR_TEMP( NewTemp( "last" ) );
            Emit( "%c = %c;\n", elm, last );
            last = elm;
        }

        // find the invariant temp-info
        pass = CompPass;
        CompPass = 99;
        prev = NewInfoCVars();
        do {
            CopyInfoCVars( prev, INFO_FEXP(CURR_FUNC()) );
            if ( HasInfoCVar( first, W_INT_SMALL_POS ) ) {
                SetInfoCVar( CVAR_LVAR(var), W_INT_SMALL_POS );
            }
            else {
                SetInfoCVar( CVAR_LVAR(var), W_INT_SMALL );
            }
            for ( i = 2; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
                CompStat(READ_STAT(stat, i));
            }
            MergeInfoCVars( INFO_FEXP(CURR_FUNC()), prev );
        } while ( ! IsEqInfoCVars( INFO_FEXP(CURR_FUNC()), prev ) );
        CompPass = pass;

        // emit the code for the loop
        Emit( "for ( %c = %c;\n",                lidx, first );
        Emit( "      ((Int)%c) <= ((Int)%c);\n", lidx, last  );
        Emit( "      %c = (Obj)(((UInt)%c)+4) ", lidx, lidx  );
        Emit( ") {\n" );

        // emit the code to copy the loop index into the loop variable
        Emit( "%c = %c;\n", CVAR_LVAR(var), lidx );

        // set what we know about the loop variable
        if ( HasInfoCVar( first, W_INT_SMALL_POS ) ) {
            SetInfoCVar( CVAR_LVAR(var), W_INT_SMALL_POS );
        }
        else {
            SetInfoCVar( CVAR_LVAR(var), W_INT_SMALL );
        }

        // compile the body
        for ( i = 2; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
            CompStat(READ_STAT(stat, i));
        }

        // emit the end code
        Emit( "\n}\n" );
        Emit( "/* od */\n" );

        // free the temporaries
        if ( IS_TEMP_CVAR( last  ) )  FreeTemp( TEMP_CVAR( last  ) );
        if ( IS_TEMP_CVAR( first ) )  FreeTemp( TEMP_CVAR( first ) );
        if ( IS_TEMP_CVAR( lidx  ) )  FreeTemp( TEMP_CVAR( lidx  ) );

    }

    // handle other loops
    else {

        // print a comment
        if ( CompPass == 2 ) {
            Emit( "\n/* for " );
            PrintExpr(READ_EXPR(stat, 0));
            Emit( " in " );
            PrintExpr(READ_EXPR(stat, 1));
            Emit( " do */\n" );
        }

        // get the variable (initialize them first to please 'lint')
        if ( IS_REF_LVAR( READ_STAT(stat, 0) )
          && ! CompGetUseHVar( LVAR_REF_LVAR( READ_STAT(stat, 0) ) ) ) {
            var = LVAR_REF_LVAR( READ_STAT(stat, 0) );
            vart = 'l';
        }
        else if (IS_REF_LVAR(READ_STAT(stat, 0))) {
            var = LVAR_REF_LVAR(READ_STAT(stat, 0));
            vart = 'm';
        }
        else if (TNUM_EXPR(READ_STAT(stat, 0)) == EXPR_REF_HVAR) {
            var = READ_EXPR(READ_STAT(stat, 0), 0);
            vart = 'h';
        }
        else /* if ( TNUM_EXPR( READ_STAT(stat, 0) ) == EXPR_REF_GVAR ) */ {
            var = READ_EXPR(READ_STAT(stat, 0), 0);
            CompSetUseGVar( var, COMP_USE_GVAR_ID );
            vart = 'g';
        }

        // allocate a new temporary for the loop variable
        lidx   = CVAR_TEMP( NewTemp( "lidx"   ) );
        elm    = CVAR_TEMP( NewTemp( "elm"    ) );
        islist = CVAR_TEMP( NewTemp( "islist" ) );

        // compile and check the first and last value
        list = CompExpr(READ_STAT(stat, 1));

        // SL Patch added to try and avoid a bug
        if (IS_LVAR_CVAR(list))
          {
            CVar copylist;
            copylist = CVAR_TEMP( NewTemp( "copylist" ) );
            Emit("%c = %c;\n",copylist, list);
            list = copylist;
          }
        // end of SL patch

        // find the invariant temp-info
        pass = CompPass;
        CompPass = 99;
        prev = NewInfoCVars();
        do {
            CopyInfoCVars( prev, INFO_FEXP(CURR_FUNC()) );
            if ( vart == 'l' ) {
                SetInfoCVar( CVAR_LVAR(var), W_BOUND );
            }
            for ( i = 2; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
                CompStat(READ_STAT(stat, i));
            }
            MergeInfoCVars( INFO_FEXP(CURR_FUNC()), prev );
        } while ( ! IsEqInfoCVars( INFO_FEXP(CURR_FUNC()), prev ) );
        CompPass = pass;

        // emit the code for the loop
        // (plenty ugly because of iterator handling)
        Emit( "if ( IS_SMALL_LIST(%c) ) {\n", list );
        Emit( "%c = (Obj)(UInt)1;\n", islist );
        Emit( "%c = INTOBJ_INT(1);\n", lidx );
        Emit( "}\n" );
        Emit( "else {\n" );
        Emit( "%c = (Obj)(UInt)0;\n", islist );
        Emit( "%c = CALL_1ARGS( GF_ITERATOR, %c );\n", lidx, list );
        Emit( "}\n" );
        Emit( "while ( 1 ) {\n" );
        Emit( "if ( %c ) {\n", islist );
        Emit( "if ( LEN_LIST(%c) < %i )  break;\n", list, lidx );
        Emit( "%c = ELMV0_LIST( %c, %i );\n", elm, list, lidx );
        Emit( "%c = (Obj)(((UInt)%c)+4);\n", lidx, lidx );
        Emit( "if ( %c == 0 )  continue;\n", elm );
        Emit( "}\n" );
        Emit( "else {\n" );
        Emit( "if ( CALL_1ARGS( GF_IS_DONE_ITER, %c ) != False )  break;\n",
              lidx );
        Emit( "%c = CALL_1ARGS( GF_NEXT_ITER, %c );\n", elm, lidx );
        Emit( "}\n" );

        // emit the code to copy the loop index into the loop variable
        if ( vart == 'l' ) {
            Emit( "%c = %c;\n",
                  CVAR_LVAR(var), elm );
        }
        else if ( vart == 'm' ) {
            Emit( "ASS_LVAR( %d, %c );\n",
                  GetIndxHVar(var), elm );
        }
        else if ( vart == 'h' ) {
            Emit( "ASS_HVAR( (%d << 16) | %d, %c );\n",
                  GetLevlHVar(var), GetIndxHVar(var), elm );
        }
        else if ( vart == 'g' ) {
            Emit( "AssGVar( G_%n, %c );\n",
                  NameGVar(var), elm );
        }

        // set what we know about the loop variable
        if ( vart == 'l' ) {
            SetInfoCVar( CVAR_LVAR(var), W_BOUND );
        }

        // compile the body
        for ( i = 2; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
            CompStat(READ_STAT(stat, i));
        }

        // emit the end code
        Emit( "\n}\n" );
        Emit( "/* od */\n" );

        // free the temporaries
        if ( IS_TEMP_CVAR( list   ) )  FreeTemp( TEMP_CVAR( list   ) );
        if ( IS_TEMP_CVAR( islist ) )  FreeTemp( TEMP_CVAR( islist ) );
        if ( IS_TEMP_CVAR( elm    ) )  FreeTemp( TEMP_CVAR( elm    ) );
        if ( IS_TEMP_CVAR( lidx   ) )  FreeTemp( TEMP_CVAR( lidx   ) );

    }

}


/****************************************************************************
**
*F  CompWhile( <stat> ) . . . . . . . . . . . . . . . . .  STAT_WHILE...STAT_WHILE3
*/

static void CompWhile(Stat stat)
{
    CVar                cond;           // condition
    Int                 pass;           // current pass
    Bag                 prev;           // previous temp-info
    UInt                i;              // loop variable

    // find an invariant temp-info
    // the emits are probably not needed
    pass = CompPass;
    CompPass = 99;
    Emit( "while ( 1 ) {\n" );
    prev = NewInfoCVars();
    do {
        CopyInfoCVars( prev, INFO_FEXP(CURR_FUNC()) );
        cond = CompBoolExpr(READ_STAT(stat, 0));
        Emit( "if ( ! %c ) break;\n", cond );
        if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );
        for ( i = 1; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
            CompStat(READ_STAT(stat, i));
        }
        MergeInfoCVars( INFO_FEXP(CURR_FUNC()), prev );
    } while ( ! IsEqInfoCVars( INFO_FEXP(CURR_FUNC()), prev ) );
    Emit( "}\n" );
    CompPass = pass;

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* while " );
        PrintExpr(READ_EXPR(stat, 0));
        Emit( " do */\n" );
    }

    // emit the code for the loop
    Emit( "while ( 1 ) {\n" );

    // compile the condition
    cond = CompBoolExpr(READ_STAT(stat, 0));
    Emit( "if ( ! %c ) break;\n", cond );
    if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );

    // compile the body
    for ( i = 1; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
        CompStat(READ_STAT(stat, i));
    }

    // that's it
    Emit( "\n}\n" );
    Emit( "/* od */\n" );

}


/****************************************************************************
**
*F  CompRepeat( <stat> )  . . . . . . . . . . . . . . .  STAT_REPEAT...STAT_REPEAT3
*/

static void CompRepeat(Stat stat)
{
    CVar                cond;           // condition
    Int                 pass;           // current pass
    Bag                 prev;           // previous temp-info
    UInt                i;              // loop variable

    // find an invariant temp-info
    // the emits are probably not needed
    pass = CompPass;
    CompPass = 99;
    Emit( "do {\n" );
    prev = NewInfoCVars();
    do {
        CopyInfoCVars( prev, INFO_FEXP(CURR_FUNC()) );
        for ( i = 1; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
            CompStat(READ_STAT(stat, i));
        }
        cond = CompBoolExpr(READ_STAT(stat, 0));
        Emit( "if ( %c ) break;\n", cond );
        if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );
        MergeInfoCVars( INFO_FEXP(CURR_FUNC()), prev );
    } while ( ! IsEqInfoCVars( INFO_FEXP(CURR_FUNC()), prev ) );
    Emit( "} while ( 1 );\n" );
    CompPass = pass;

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* repeat */\n" );
    }

    // emit the code for the loop
    Emit( "do {\n" );

    // compile the body
    for ( i = 1; i < SIZE_STAT(stat)/sizeof(Stat); i++ ) {
        CompStat(READ_STAT(stat, i));
    }

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* until " );
        PrintExpr(READ_EXPR(stat, 0));
        Emit( " */\n" );
    }

    // compile the condition
    cond = CompBoolExpr(READ_STAT(stat, 0));
    Emit( "if ( %c ) break;\n", cond );
    if ( IS_TEMP_CVAR( cond ) )  FreeTemp( TEMP_CVAR( cond ) );

    // that's it
    Emit( "} while ( 1 );\n" );
}


/****************************************************************************
**
*F  CompBreak( <stat> ) . . . . . . . . . . . . . . . . . . . . . . . STAT_BREAK
*/

static void CompBreak(Stat stat)
{
    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    Emit( "break;\n" );
}

/****************************************************************************
**
*F  CompContinue( <stat> ) . . . . . . . . . . . . . . . . . . . . STAT_CONTINUE
*/

static void CompContinue(Stat stat)
{
    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    Emit( "continue;\n" );
}


/****************************************************************************
**
*F  CompReturnObj( <stat> ) . . . . . . . . . . . . . . . . . .  STAT_RETURN_OBJ
*/

static void CompReturnObj(Stat stat)
{
    CVar                obj;            // returned object

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the expression
    obj = CompExpr(READ_STAT(stat, 0));

    // emit code to remove stack frame
    Emit( "SWITCH_TO_OLD_FRAME(oldFrame);\n" );

    // emit code to return from function
    Emit( "return %c;\n", obj );

    // free the temporary
    if ( IS_TEMP_CVAR( obj ) )  FreeTemp( TEMP_CVAR( obj ) );
}


/****************************************************************************
**
*F  CompReturnVoid( <stat> )  . . . . . . . . . . . . . . . . . STAT_RETURN_VOID
*/

static void CompReturnVoid(Stat stat)
{
    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // emit code to remove stack frame
    Emit( "SWITCH_TO_OLD_FRAME(oldFrame);\n" );

    // emit code to return from function
    Emit( "return 0;\n" );
}


/****************************************************************************
**
*F  CompAssLVar( <stat> ) . . . . . . . . . . . .  STAT_ASS_LVAR...T_ASS_LVAR_16
*/

static void CompAssLVar(Stat stat)
{
    LVar                lvar;           // local variable
    CVar                rhs;            // right hand side

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the right hand side expression
    rhs = CompExpr(READ_STAT(stat, 1));

    // emit the code for the assignment
    lvar = (LVar)(READ_STAT(stat, 0));
    if ( CompGetUseHVar( lvar ) ) {
        Emit( "ASS_LVAR( %d, %c );\n", GetIndxHVar(lvar), rhs );
    }
    else {
        Emit( "%c = %c;\n", CVAR_LVAR(lvar), rhs );
        SetInfoCVar( CVAR_LVAR(lvar), GetInfoCVar( rhs ) );
    }

    // free the temporary
    if ( IS_TEMP_CVAR( rhs ) )  FreeTemp( TEMP_CVAR( rhs ) );
}


/****************************************************************************
**
*F  CompUnbLVar( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_UNB_LVAR
*/

static void CompUnbLVar(Stat stat)
{
    LVar                lvar;           // local variable

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // emit the code for the assignment
    lvar = (LVar)(READ_STAT(stat, 0));
    if ( CompGetUseHVar( lvar ) ) {
        Emit( "ASS_LVAR( %d, 0 );\n", GetIndxHVar(lvar) );
    }
    else {
        Emit( "%c = 0;\n", CVAR_LVAR( lvar ) );
        SetInfoCVar( lvar, W_UNBOUND );
    }
}


/****************************************************************************
**
*F  CompAssHVar( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_ASS_HVAR
*/

static void CompAssHVar(Stat stat)
{
    HVar                hvar;           // higher variable
    CVar                rhs;            // right hand side

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the right hand side expression
    rhs = CompExpr(READ_STAT(stat, 1));

    // emit the code for the assignment
    hvar = (HVar)(READ_STAT(stat, 0));
    CompSetUseHVar( hvar );
    Emit( "ASS_HVAR( (%d << 16) | %d, %c );\n",
          GetLevlHVar(hvar), GetIndxHVar(hvar), rhs );

    // free the temporary
    if ( IS_TEMP_CVAR( rhs ) )  FreeTemp( TEMP_CVAR( rhs ) );
}


/****************************************************************************
**
*F  CompUnbHVar( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_UNB_HVAR
*/

static void CompUnbHVar(Stat stat)
{
    HVar                hvar;           // higher variable

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // emit the code for the assignment
    hvar = (HVar)(READ_STAT(stat, 0));
    CompSetUseHVar( hvar );
    Emit( "ASS_HVAR( (%d << 16) | %d, 0 );\n",
          GetLevlHVar(hvar), GetIndxHVar(hvar) );
}


/****************************************************************************
**
*F  CompAssGVar( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_ASS_GVAR
*/

static void CompAssGVar(Stat stat)
{
    GVar                gvar;           // global variable
    CVar                rhs;            // right hand side

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the right hand side expression
    rhs = CompExpr(READ_STAT(stat, 1));

    // emit the code for the assignment
    gvar = (GVar)(READ_STAT(stat, 0));
    CompSetUseGVar( gvar, COMP_USE_GVAR_ID );
    Emit( "AssGVar( G_%n, %c );\n", NameGVar(gvar), rhs );

    // free the temporary
    if ( IS_TEMP_CVAR( rhs ) )  FreeTemp( TEMP_CVAR( rhs ) );
}


/****************************************************************************
**
*F  CompUnbGVar( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_UNB_GVAR
*/

static void CompUnbGVar(Stat stat)
{
    GVar                gvar;           // global variable

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // emit the code for the assignment
    gvar = (GVar)(READ_STAT(stat, 0));
    CompSetUseGVar( gvar, COMP_USE_GVAR_ID );
    Emit( "AssGVar( G_%n, 0 );\n", NameGVar(gvar) );
}


/****************************************************************************
**
*F  CompAssList( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_ASS_LIST
*/

static void CompAssList(Stat stat)
{
    CVar                list;           // list
    CVar                pos;            // position
    CVar                rhs;            // right hand side

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expression
    list = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    pos = CompExpr(READ_STAT(stat, 1));
    CompCheckIntPos( pos );

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code
    if ( CompFastPlainLists ) {
        if ( HasInfoCVar( rhs, W_INT_SMALL ) ) {
            Emit( "C_ASS_LIST_FPL_INTOBJ( %c, %c, %c )\n", list, pos, rhs );
        }
        else {
            Emit( "C_ASS_LIST_FPL( %c, %c, %c )\n", list, pos, rhs );
        }
    }
    else {
        Emit( "C_ASS_LIST( %c, %c, %c );\n", list, pos, rhs );
    }

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs  ) )  FreeTemp( TEMP_CVAR( rhs  ) );
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );
}


/****************************************************************************
**
*F  CompAsssList( <stat> )  . . . . . . . . . . . . . . . . . . . STAT_ASSS_LIST
*/

static void CompAsssList(Stat stat)
{
    CVar                list;           // list
    CVar                poss;           // positions
    CVar                rhss;           // right hand sides

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expression
    list = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    poss = CompExpr(READ_STAT(stat, 1));

    // compile the right hand side
    rhss = CompExpr(READ_STAT(stat, 2));

    // emit the code
    Emit( "AsssListCheck( %c, %c, %c );\n", list, poss, rhss );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhss ) )  FreeTemp( TEMP_CVAR( rhss ) );
    if ( IS_TEMP_CVAR( poss ) )  FreeTemp( TEMP_CVAR( poss ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );
}


/****************************************************************************
**
*F  CompAssListLev( <stat> )  . . . . . . . . . . . . . . . .  STAT_ASS_LIST_LEV
*/

static void CompAssListLev(Stat stat)
{
    CVar                lists;          // lists
    CVar                pos;            // position
    CVar                rhss;           // right hand sides
    UInt                level;          // level

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expressions
    lists = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    pos = CompExpr(READ_STAT(stat, 1));
    CompCheckIntSmallPos( pos );

    // compile the right hand sides
    rhss = CompExpr(READ_STAT(stat, 2));

    // get the level
    level = READ_STAT(stat, 3);

    // emit the code
    Emit( "AssListLevel( %c, %c, %c, %d );\n", lists, pos, rhss, level );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhss  ) )  FreeTemp( TEMP_CVAR( rhss  ) );
    if ( IS_TEMP_CVAR( pos   ) )  FreeTemp( TEMP_CVAR( pos   ) );
    if ( IS_TEMP_CVAR( lists ) )  FreeTemp( TEMP_CVAR( lists ) );
}


/****************************************************************************
**
*F  CompAsssListLev( <stat> ) . . . . . . . . . . . . . . . . STAT_ASSS_LIST_LEV
*/

static void CompAsssListLev(Stat stat)
{
    CVar                lists;          // list
    CVar                poss;           // positions
    CVar                rhss;           // right hand sides
    UInt                level;          // level

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expressions
    lists = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    poss = CompExpr(READ_STAT(stat, 1));

    // compile the right hand side
    rhss = CompExpr(READ_STAT(stat, 2));

    // get the level
    level = READ_STAT(stat, 3);

    // emit the code
    Emit( "AsssListLevelCheck( %c, %c, %c, %d );\n",
          lists, poss, rhss, level );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhss  ) )  FreeTemp( TEMP_CVAR( rhss ) );
    if ( IS_TEMP_CVAR( poss  ) )  FreeTemp( TEMP_CVAR( poss ) );
    if ( IS_TEMP_CVAR( lists ) )  FreeTemp( TEMP_CVAR( lists ) );
}


/****************************************************************************
**
*F  CompUnbList( <stat> ) . . . . . . . . . . . . . . . . . . . .  STAT_UNB_LIST
*/

static void CompUnbList(Stat stat)
{
    CVar                list;           // list, left operand
    CVar                pos;            // position, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expression
    list = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    pos = CompExpr(READ_STAT(stat, 1));
    CompCheckIntPos( pos );

    // emit the code
    Emit( "C_UNB_LIST( %c, %c );\n", list, pos );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );
}


/****************************************************************************
**
*F  CompAssRecName( <stat> )  . . . . . . . . . . . . . . . .  STAT_ASS_REC_NAME
*/

static void CompAssRecName(Stat stat)
{
    CVar                record;         // record, left operand
    UInt                rnam;           // name, left operand
    CVar                rhs;            // rhs, right operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = READ_STAT(stat, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code for the assignment
    Emit( "ASS_REC( %c, R_%n, %c );\n", record, NAME_RNAM(rnam), rhs );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs    ) )  FreeTemp( TEMP_CVAR( rhs    ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompAssRecExpr( <stat> )  . . . . . . . . . . . . . . . .  STAT_ASS_REC_EXPR
*/

static void CompAssRecExpr(Stat stat)
{
    CVar                record;         // record, left operand
    CVar                rnam;           // name, left operand
    CVar                rhs;            // rhs, right operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = CompExpr(READ_STAT(stat, 1));

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code for the assignment
    Emit( "ASS_REC( %c, RNamObj(%c), %c );\n", record, rnam, rhs );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs    ) )  FreeTemp( TEMP_CVAR( rhs    ) );
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompUnbRecName( <stat> )  . . . . . . . . . . . . . . . .  STAT_UNB_REC_NAME
*/

static void CompUnbRecName(Stat stat)
{
    CVar                record;         // record, left operand
    UInt                rnam;           // name, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = READ_STAT(stat, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code for the assignment
    Emit( "UNB_REC( %c, R_%n );\n", record, NAME_RNAM(rnam) );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompUnbRecExpr( <stat> )  . . . . . . . . . . . . . . . .  STAT_UNB_REC_EXPR
*/

static void CompUnbRecExpr(Stat stat)
{
    CVar                record;         // record, left operand
    CVar                rnam;           // name, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name expression
    rnam = CompExpr(READ_STAT(stat, 1));

    // emit the code for the assignment
    Emit( "UNB_REC( %c, RNamObj(%c) );\n", record, rnam );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompAssPosObj( <stat> ) . . . . . . . . . . . . . . . . . .  STAT_ASS_POSOBJ
*/

static void CompAssPosObj(Stat stat)
{
    CVar                list;           // list
    CVar                pos;            // position
    CVar                rhs;            // right hand side

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expression
    list = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    pos = CompExpr(READ_STAT(stat, 1));
    CompCheckIntSmallPos( pos );

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code
    Emit( "AssPosObj( %c, %i, %c );\n", list, pos, rhs );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs  ) )  FreeTemp( TEMP_CVAR( rhs  ) );
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );
}


/****************************************************************************
**
*F  CompUnbPosObj( <stat> ) . . . . . . . . . . . . . . . . . .  STAT_UNB_POSOBJ
*/

static void CompUnbPosObj(Stat stat)
{
    CVar                list;           // list, left operand
    CVar                pos;            // position, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the list expression
    list = CompExpr(READ_STAT(stat, 0));

    // compile and check the position expression
    pos = CompExpr(READ_STAT(stat, 1));
    CompCheckIntSmallPos( pos );

    // emit the code
    Emit( "UnbPosObj( %c, %i );\n", list, pos );

    // free the temporaries
    if ( IS_TEMP_CVAR( pos  ) )  FreeTemp( TEMP_CVAR( pos  ) );
    if ( IS_TEMP_CVAR( list ) )  FreeTemp( TEMP_CVAR( list ) );
}


/****************************************************************************
**
*F  CompAssComObjName( <stat> ) . . . . . . . . . . . . . . STAT_ASS_COMOBJ_NAME
*/

static void CompAssComObjName(Stat stat)
{
    CVar                record;         // record, left operand
    UInt                rnam;           // name, left operand
    CVar                rhs;            // rhs, right operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = READ_STAT(stat, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code for the assignment
    Emit( "AssComObj( %c, R_%n, %c );\n", record, NAME_RNAM(rnam), rhs );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs    ) )  FreeTemp( TEMP_CVAR( rhs    ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompAssComObjExpr( <stat> ) . . . . . . . . . . . . . . STAT_ASS_COMOBJ_EXPR
*/

static void CompAssComObjExpr(Stat stat)
{
    CVar                record;         // record, left operand
    CVar                rnam;           // name, left operand
    CVar                rhs;            // rhs, right operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = CompExpr(READ_STAT(stat, 1));

    // compile the right hand side
    rhs = CompExpr(READ_STAT(stat, 2));

    // emit the code for the assignment
    Emit( "AssComObj( %c, RNamObj(%c), %c );\n", record, rnam, rhs );

    // free the temporaries
    if ( IS_TEMP_CVAR( rhs    ) )  FreeTemp( TEMP_CVAR( rhs    ) );
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompUnbComObjName( <stat> ) . . . . . . . . . . . . . . STAT_UNB_COMOBJ_NAME
*/

static void CompUnbComObjName(Stat stat)
{
    CVar                record;         // record, left operand
    UInt                rnam;           // name, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name (stored immediately in the statement)
    rnam = READ_STAT(stat, 1);
    CompSetUseRNam( rnam, COMP_USE_RNAM_ID );

    // emit the code for the assignment
    Emit( "UnbComObj( %c, R_%n );\n", record, NAME_RNAM(rnam) );

    // free the temporaries
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}


/****************************************************************************
**
*F  CompUnbComObjExpr( <stat> ) . . . . . . . . . . . . . . STAT_UNB_COMOBJ_EXPR
*/

static void CompUnbComObjExpr(Stat stat)
{
    CVar                record;         // record, left operand
    UInt                rnam;           // name, left operand

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    // compile the record expression
    record = CompExpr(READ_STAT(stat, 0));

    // get the name expression
    rnam = CompExpr(READ_STAT(stat, 1));

    // emit the code for the assignment
    Emit( "UnbComObj( %c, RNamObj(%c) );\n", record, rnam );

    // free the temporaries
    if ( IS_TEMP_CVAR( rnam   ) )  FreeTemp( TEMP_CVAR( rnam   ) );
    if ( IS_TEMP_CVAR( record ) )  FreeTemp( TEMP_CVAR( record ) );
}

/****************************************************************************
**
*F  CompEmpty( <stat> )  . . . . . . . . . . . . . . . . . . . . . . . T_EMPY
*/

static void CompEmpty(Stat stat)
{
    // do nothing
}

/****************************************************************************
**
*F  CompInfo( <stat> )  . . . . . . . . . . . . . . . . . . . . . . .  STAT_INFO
*/

static void CompInfo(Stat stat)
{
    CVar                tmp;
    CVar                sel;
    CVar                lev;
    CVar                lst;
    Int                 narg;
    Int                 i;

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    sel = CompExpr( ARGI_INFO( stat, 1 ) );
    lev = CompExpr( ARGI_INFO( stat, 2 ) );
    lst = CVAR_TEMP( NewTemp( "lst" ) );
    tmp = CVAR_TEMP( NewTemp( "tmp" ) );
    Emit( "%c = InfoCheckLevel( %c, %c );\n", tmp, sel, lev );
    Emit( "if ( %c == True ) {\n", tmp );
    if ( IS_TEMP_CVAR( tmp ) )  FreeTemp( TEMP_CVAR( tmp ) );
    narg = NARG_SIZE_INFO(SIZE_STAT(stat))-2;
    Emit( "%c = NEW_PLIST( T_PLIST, %d );\n", lst, narg );
    Emit( "SET_LEN_PLIST( %c, %d );\n", lst, narg );
    for ( i = 1;  i <= narg;  i++ ) {
        tmp = CompExpr( ARGI_INFO( stat, i+2 ) );
        Emit( "SET_ELM_PLIST( %c, %d, %c );\n", lst, i, tmp );
        Emit( "CHANGED_BAG(%c);\n", lst );
        if ( IS_TEMP_CVAR( tmp ) )  FreeTemp( TEMP_CVAR( tmp ) );
    }
    Emit( "InfoDoPrint( %c, %c, %c );\n", sel, lev, lst );
    Emit( "}\n" );

    // free the temporaries
    if ( IS_TEMP_CVAR( lst ) )  FreeTemp( TEMP_CVAR( lst ) );
    if ( IS_TEMP_CVAR( lev ) )  FreeTemp( TEMP_CVAR( lev ) );
    if ( IS_TEMP_CVAR( sel ) )  FreeTemp( TEMP_CVAR( sel ) );
}


/****************************************************************************
**
*F  CompAssert2( <stat> ) . . . . . . . . . . . . . . . . . .  STAT_ASSERT_2ARGS
*/

static void CompAssert2(Stat stat)
{
    CVar                lev;            // the level
    CVar                cnd;            // the condition

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    lev = CompExpr(READ_STAT(stat, 0));
    Emit( "if ( STATE(CurrentAssertionLevel) >= %i ) {\n", lev );
    cnd = CompBoolExpr(READ_STAT(stat, 1));
    Emit( "if ( ! %c ) {\n", cnd );
    Emit( "AssertionFailure();\n" );
    Emit( "}\n" );
    Emit( "}\n" );

    // free the temporaries
    if ( IS_TEMP_CVAR( cnd ) )  FreeTemp( TEMP_CVAR( cnd ) );
    if ( IS_TEMP_CVAR( lev ) )  FreeTemp( TEMP_CVAR( lev ) );
}


/****************************************************************************
**
*F  CompAssert3( <stat> ) . . . . . . . . . . . . . . . . . .  STAT_ASSERT_3ARGS
*/

static void CompAssert3(Stat stat)
{
    CVar                lev;            // the level
    CVar                cnd;            // the condition
    CVar                msg;            // the message

    // print a comment
    if ( CompPass == 2 ) {
        Emit( "\n/* " ); PrintStat( stat ); Emit( " */\n" );
    }

    lev = CompExpr(READ_STAT(stat, 0));
    Emit( "if ( STATE(CurrentAssertionLevel) >= %i ) {\n", lev );
    cnd = CompBoolExpr(READ_STAT(stat, 1));
    Emit( "if ( ! %c ) {\n", cnd );
    msg = CompExpr(READ_STAT(stat, 2));
    Emit( "AssertionFailureWithMessage(%c);\n", msg );
    Emit( "}\n" );
    Emit( "}\n" );

    // free the temporaries
    if ( IS_TEMP_CVAR( msg ) )  FreeTemp( TEMP_CVAR( msg ) );
    if ( IS_TEMP_CVAR( cnd ) )  FreeTemp( TEMP_CVAR( cnd ) );
    if ( IS_TEMP_CVAR( lev ) )  FreeTemp( TEMP_CVAR( lev ) );
}



/****************************************************************************
**
*F * * * * * * * * * * * * * * start compiling  * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*F  CompFunc( <func> )  . . . . . . . . . . . . . . . . .  compile a function
**
**  'CompFunc' compiles the function <func>, i.e., it emits  the code for the
**  handler of the function <func> and the handlers of all its subfunctions.
*/

static Obj CompFunctions;

static void CompFunc(Obj func)
{
    Bag                 info;           // info bag for this function
    Int                 narg;           // number of arguments
    Int                 nloc;           // number of locals
    Bag                 oldFrame;       // old frame
    Int                 i;              // loop variable
    Int                 prevarargs;     // we have varargs with a prefix

    // get the number of arguments and locals
    narg = NARG_FUNC(func);
    prevarargs = 0;
    if(narg < -1) prevarargs = 1;
    if (narg < 0) {
        narg = -narg;
    }

    nloc = NLOC_FUNC(func);

    // in the first pass allocate the info bag
    if ( CompPass == 1 ) {

        UInt nr = PushPlist( CompFunctions, func );

        info = NewKernelBuffer(SIZE_INFO(narg+nloc,8));
        NEXT_INFO(info)  = INFO_FEXP( CURR_FUNC() );
        NR_INFO(info)    = nr;
        NLVAR_INFO(info) = narg + nloc;
        NHVAR_INFO(info) = 0;
        NTEMP_INFO(info) = 0;

        SET_INFO_FEXP(func, info);
        CHANGED_BAG(func);

    }

    // switch to this function (so that 'CONST_ADDR_STAT' and 'CONST_ADDR_EXPR' work)
    oldFrame = SWITCH_TO_NEW_LVARS(func, narg, nloc);

    // get the info bag
    info = INFO_FEXP( CURR_FUNC() );

    // compile the inner functions
    Obj values = VALUES_BODY(BODY_FUNC(func));
    if (values) {
        UInt len = LEN_PLIST(values);
        for (i = 1; i <= len; i++) {
            Obj val = ELM_PLIST(values, i);
            if (IS_FUNC(val))
                CompFunc(val);
        }
    }

    // emit the code for the function header and the arguments
    Emit( "\n/* handler for function %d */\n", NR_INFO(info));
    if ( narg == 0 ) {
        Emit( "static Obj  HdlrFunc%d (\n", NR_INFO(info) );
        Emit( " Obj  self )\n" );
        Emit( "{\n" );
    }
    else if ( narg <= 6 && !prevarargs ) {
        Emit( "static Obj  HdlrFunc%d (\n", NR_INFO(info) );
        Emit( " Obj  self,\n" );
        for ( i = 1; i < narg; i++ ) {
            Emit( " Obj  %c,\n", CVAR_LVAR(i) );
        }
        Emit( " Obj  %c )\n", CVAR_LVAR(narg) );
        Emit( "{\n" );
    }
    else {
        Emit( "static Obj  HdlrFunc%d (\n", NR_INFO(info) );
        Emit( " Obj  self,\n" );
        Emit( " Obj  args )\n" );
        Emit( "{\n" );
        for ( i = 1; i <= narg; i++ ) {
            Emit( "Obj  %c;\n", CVAR_LVAR(i) );
        }
    }

    // emit the code for the local variables
    for ( i = 1; i <= nloc; i++ ) {
        if ( ! CompGetUseHVar( i+narg ) ) {
            Emit( "Obj %c = 0;\n", CVAR_LVAR(i+narg) );
        }
    }

    // emit the code for the temporaries
    for ( i = 1; i <= NTEMP_INFO(info); i++ ) {
        Emit( "Obj %c = 0;\n", CVAR_TEMP(i) );
    }

    for ( i = 1; i <= nloc; i++ ) {
        if ( ! CompGetUseHVar( i+narg ) ) {
            Emit( "(void)%c;\n", CVAR_LVAR(i+narg) );
        }
    }

    // emit the code for the higher variables
    Emit( "Bag oldFrame;\n" );

    // emit the code to get the arguments for xarg functions
    if ( 6 < narg ) {
        Emit( "CHECK_NR_ARGS( %d, args )\n", narg );
        for ( i = 1; i <= narg; i++ ) {
            Emit( "%c = ELM_PLIST( args, %d );\n", CVAR_LVAR(i), i );
        }
    }

   if ( prevarargs ) {
        Emit( "CHECK_NR_AT_LEAST_ARGS( %d, args )\n", narg );
        for ( i = 1; i < narg; i++ ) {
            Emit( "%c = ELM_PLIST( args, %d );\n", CVAR_LVAR(i), i );
        }
        Emit( "Obj x_temp_range = Range2Check(INTOBJ_INT(%d), INTOBJ_INT(LEN_PLIST(args)));\n", narg);
        Emit( "%c = ELMS_LIST(args , x_temp_range);\n", CVAR_LVAR(narg));
    }

    // emit the code to switch to a new frame for outer functions
    Emit( "\n/* allocate new stack frame */\n" );
    Emit( "SWITCH_TO_NEW_FRAME(self,%d,0,oldFrame);\n",NHVAR_INFO(info));
    if (NHVAR_INFO(info) > 0) {
        Emit("MakeHighVars(STATE(CurrLVars));\n");
    }
    for ( i = 1; i <= narg; i++ ) {
        if ( CompGetUseHVar( i ) ) {
            Emit( "ASS_LVAR( %d, %c );\n",GetIndxHVar(i),CVAR_LVAR(i));
        }
    }

    // we know all the arguments have values
    for ( i = 1; i <= narg; i++ ) {
        SetInfoCVar( CVAR_LVAR(i), W_BOUND );
    }
    for ( i = narg+1; i <= narg+nloc; i++ ) {
        SetInfoCVar( CVAR_LVAR(i), W_UNBOUND );
    }

    // compile the body
    CompStat( OFFSET_FIRST_STAT );

    Emit( "}\n" );

    // switch back to old frame
    SWITCH_TO_OLD_LVARS( oldFrame );
}


/****************************************************************************
**
*F  CompileFunc( <filename>, <func>, <name>, <crc>, <magic2> ) . . compile
**
**  The meaning of the arguments is as follows:
**  - 'filename': the file the generated C code should be written to.
**  - 'func': a function generated by parsing the input GAP file via
**    'READ_AS_FUNC' resp. 'ReadEvalFile'.
**  - 'name' is the designated name for the entry function of the kernel
**    extension generated by the compiler, e.g. `Init__type1`.
**  - 'crc' is a checksum of the content of the input file.
**  - 'magic2' is a string used as name for the module. Typically this is the
**     name of GAP source file being compiled; but for compiled GAP code
**     that is statically linked into the kernel, the placeholder GAPROOT is
**     used in there, e.g. in `GAPROOT/lib/oper1.g`.
*/

Int CompileFunc(Obj filename, Obj func, Obj name, Int crc, Obj magic2)
{
    Int                 i;              // loop variable
    UInt                col;
    UInt                compFunctionsNr;

    // open the output file
    TypOutputFile output = { 0 };
    if (!OpenOutput(&output, CONST_CSTR_STRING(filename), FALSE)) {
        return 0;
    }
    col = SyNrCols;
    SyNrCols = 255;

    // create 'CompInfoGVar' and 'CompInfoRNam'
    CompInfoGVar = NewKernelBuffer(sizeof(UInt) * 1024);
    CompInfoRNam = NewKernelBuffer(sizeof(UInt) * 1024);

    // create the list to collection the function expressions
    CompFunctions = NEW_PLIST( T_PLIST, 8 );

    // first collect information about variables
    CompPass = 1;
    CompFunc( func );

    // ok, lets emit some code now
    CompPass = 2;
    compFunctionsNr = LEN_PLIST( CompFunctions );

    // emit code to include the interface files
    Emit( "/* C file produced by GAC */\n" );
    Emit( "#include \"compiled.h\"\n" );
    Emit( "#define FILE_CRC  \"%d\"\n", crc );

    // emit code for global variables
    Emit( "\n/* global variables used in handlers */\n" );
    for ( i = 1; i < SIZE_OBJ(CompInfoGVar)/sizeof(UInt); i++ ) {
        if ( CompGetUseGVar( i ) ) {
            Emit( "static GVar G_%n;\n", NameGVar(i) );
        }
        if ( CompGetUseGVar( i ) & COMP_USE_GVAR_COPY ) {
            Emit( "static Obj  GC_%n;\n", NameGVar(i) );
        }
        if ( CompGetUseGVar( i ) & COMP_USE_GVAR_FOPY ) {
            Emit( "static Obj  GF_%n;\n", NameGVar(i) );
        }
    }

    // emit code for record names
    Emit( "\n/* record names used in handlers */\n" );
    for ( i = 1; i < SIZE_OBJ(CompInfoRNam)/sizeof(UInt); i++ ) {
        if ( CompGetUseRNam( i ) ) {
            Emit( "static RNam R_%n;\n", NAME_RNAM(i) );
        }
    }

    // emit code for the functions
    Emit( "\n/* information for the functions */\n" );
    Emit( "static Obj  NameFunc[%d];\n", compFunctionsNr+1 );
    Emit( "static Obj FileName;\n" );


    // now compile the handlers
    CompFunc( func );

    // emit the code for PostRestore
    Emit( "\n/* 'PostRestore' restore gvars, rnams, functions */\n" );
    Emit( "static Int PostRestore ( StructInitInfo * module )\n" );
    Emit( "{\n" );
    Emit( "\n/* global variables used in handlers */\n" );
    for ( i = 1; i < SIZE_OBJ(CompInfoGVar)/sizeof(UInt); i++ ) {
        if ( CompGetUseGVar( i ) ) {
            Emit( "G_%n = GVarName( \"%g\" );\n",
                   NameGVar(i), NameGVar(i) );
        }
    }
    Emit( "\n/* record names used in handlers */\n" );
    for ( i = 1; i < SIZE_OBJ(CompInfoRNam)/sizeof(UInt); i++ ) {
        if ( CompGetUseRNam( i ) ) {
            Emit( "R_%n = RNamName( \"%g\" );\n",
                  NAME_RNAM(i), NAME_RNAM(i) );
        }
    }
    Emit( "\n/* information for the functions */\n" );
    for ( i = 1; i <= compFunctionsNr; i++ ) {
        Obj n = NAME_FUNC(ELM_PLIST(CompFunctions,i));
        if ( n != 0 && IsStringConv(n) ) {
            Emit( "NameFunc[%d] = MakeImmString(\"%C\");\n", i, n );
        }
        else {
            Emit( "NameFunc[%d] = 0;\n", i );
        }
    }
    Emit( "\n" );
    Emit( "return 0;\n" );
    Emit( "\n}\n" );
    Emit( "\n" );

    // emit the code for InitKernel
    Emit( "\n/* 'InitKernel' sets up data structures, fopies, copies, handlers */\n" );
    Emit( "static Int InitKernel ( StructInitInfo * module )\n" );
    Emit( "{\n" );
    Emit( "\n/* global variables used in handlers */\n" );
    for ( i = 1; i < SIZE_OBJ(CompInfoGVar)/sizeof(UInt); i++ ) {
        if ( CompGetUseGVar( i ) & COMP_USE_GVAR_COPY ) {
            Emit( "InitCopyGVar( \"%g\", &GC_%n );\n",
                  NameGVar(i), NameGVar(i) );
        }
        if ( CompGetUseGVar( i ) & COMP_USE_GVAR_FOPY ) {
            Emit( "InitFopyGVar( \"%g\", &GF_%n );\n",
                  NameGVar(i), NameGVar(i) );
        }
    }
    Emit( "\n/* information for the functions */\n" );
    Emit( "InitGlobalBag( &FileName, \"%g:FileName(\"FILE_CRC\")\" );\n",
          magic2 );
    for ( i = 1; i <= compFunctionsNr; i++ ) {
        Emit( "InitHandlerFunc( HdlrFunc%d, \"%g:HdlrFunc%d(\"FILE_CRC\")\" );\n",
              i, magic2, i );
        Emit( "InitGlobalBag( &(NameFunc[%d]), \"%g:NameFunc[%d](\"FILE_CRC\")\" );\n",
               i, magic2, i );
    }
    Emit( "\n" );
    Emit( "return 0;\n" );
    Emit( "\n}\n" );

    // emit the code for InitLibrary
    Emit( "\n/* 'InitLibrary' sets up gvars, rnams, functions */\n" );
    Emit( "static Int InitLibrary ( StructInitInfo * module )\n" );
    Emit( "{\n" );
    Emit( "Obj func1;\n" );
    Emit( "Obj body1;\n" );
    Emit( "\n/* Complete Copy/Fopy registration */\n" );
    Emit( "UpdateCopyFopyInfo();\n" );
    Emit( "FileName = MakeImmString( \"%g\" );\n", magic2 );
    Emit( "PostRestore(module);\n" );
    Emit( "\n/* create all the functions defined in this module */\n" );
    Emit( "func1 = NewFunction(NameFunc[1],%d,0,HdlrFunc1);\n", NARG_FUNC(ELM_PLIST(CompFunctions,1)) );
    Emit( "SET_ENVI_FUNC( func1, STATE(CurrLVars) );\n" );
    Emit( "body1 = NewFunctionBody();\n" );
    Emit( "SET_BODY_FUNC( func1, body1 );\n" );
    Emit( "CHANGED_BAG( func1 );\n");
    Emit( "CALL_0ARGS( func1 );\n" );
    Emit( "\n" );
    Emit( "return 0;\n" );
    Emit( "\n}\n" );

    // emit the initialization code
    Emit( "\n/* <name> returns the description of this module */\n" );
    Emit( "static StructInitInfo module = {\n" );
    if (streq("Init_Dynamic", CONST_CSTR_STRING(name))) {
        Emit( ".type        = MODULE_DYNAMIC,\n" );
    }
    else {
        Emit( ".type        = MODULE_STATIC,\n" );
    }
    Emit( ".name        = \"%g\",\n", magic2 );
    Emit( ".crc         = %d,\n",     crc );
    Emit( ".initKernel  = InitKernel,\n" );
    Emit( ".initLibrary = InitLibrary,\n" );
    Emit( ".postRestore = PostRestore,\n" );
    Emit( "};\n" );
    Emit( "\n" );
    Emit( "StructInitInfo * %n ( void )\n", name );
    Emit( "{\n" );
    Emit( "return &module;\n" );
    Emit( "}\n" );
    Emit( "\n/* compiled code ends here */\n" );

    // close the output file
    SyNrCols = col;
    CloseOutput(&output);

    return compFunctionsNr;
}


/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
*/

static Int InitKernel (
    StructInitInfo *    module )
{
    Int                 i;              // loop variable

    CompFastIntArith = 1;
    CompFastListFuncs = 1;
    CompFastPlainLists = 1;
    CompCheckTypes = 1;
    CompCheckListElements = 1;
    CompPass = 0;

    // register global bags with the garbage collector
    InitGlobalBag( &CompInfoGVar,  "src/compiler.c:CompInfoGVar"  );
    InitGlobalBag( &CompInfoRNam,  "src/compiler.c:CompInfoRNam"  );
    InitGlobalBag( &CompFunctions, "src/compiler.c:CompFunctions" );

    // enter the expression compilers into the table
    for ( i = 0; i < 256; i++ ) {
        CompExprFuncs[ i ] = CompUnknownExpr;
    }

    CompExprFuncs[ EXPR_FUNCCALL_0ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_1ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_2ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_3ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_4ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_5ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_6ARGS  ] = CompFunccall0to6Args;
    CompExprFuncs[ EXPR_FUNCCALL_XARGS  ] = CompFunccallXArgs;
    CompExprFuncs[ EXPR_FUNC       ] = CompFuncExpr;

    CompExprFuncs[ EXPR_OR              ] = CompOr;
    CompExprFuncs[ EXPR_AND             ] = CompAnd;
    CompExprFuncs[ EXPR_NOT             ] = CompNot;
    CompExprFuncs[ EXPR_EQ              ] = CompEq;
    CompExprFuncs[ EXPR_NE              ] = CompNe;
    CompExprFuncs[ EXPR_LT              ] = CompLt;
    CompExprFuncs[ EXPR_GE              ] = CompGe;
    CompExprFuncs[ EXPR_GT              ] = CompGt;
    CompExprFuncs[ EXPR_LE              ] = CompLe;
    CompExprFuncs[ EXPR_IN              ] = CompIn;

    CompExprFuncs[ EXPR_SUM             ] = CompSum;
    CompExprFuncs[ EXPR_AINV            ] = CompAInv;
    CompExprFuncs[ EXPR_DIFF            ] = CompDiff;
    CompExprFuncs[ EXPR_PROD            ] = CompProd;
    CompExprFuncs[ EXPR_QUO             ] = CompQuo;
    CompExprFuncs[ EXPR_MOD             ] = CompMod;
    CompExprFuncs[ EXPR_POW             ] = CompPow;

    CompExprFuncs[ EXPR_INT         ] = CompIntExpr;
    CompExprFuncs[ EXPR_INTPOS        ] = CompIntExpr;
    CompExprFuncs[ EXPR_TRUE       ] = CompTrueExpr;
    CompExprFuncs[ EXPR_FALSE      ] = CompFalseExpr;
    CompExprFuncs[ EXPR_TILDE      ] = CompTildeExpr;
    CompExprFuncs[ EXPR_CHAR       ] = CompCharExpr;
    CompExprFuncs[ EXPR_PERM       ] = CompPermExpr;
    CompExprFuncs[ EXPR_PERM_CYCLE      ] = CompUnknownExpr;
    CompExprFuncs[ EXPR_LIST       ] = CompListExpr;
    CompExprFuncs[ EXPR_LIST_TILDE ] = CompListTildeExpr;
    CompExprFuncs[ EXPR_RANGE      ] = CompRangeExpr;
    CompExprFuncs[ EXPR_STRING     ] = CompStringExpr;
    CompExprFuncs[ EXPR_REC        ] = CompRecExpr;
    CompExprFuncs[ EXPR_REC_TILDE  ] = CompRecTildeExpr;

    CompExprFuncs[ EXPR_REF_LVAR         ] = CompRefLVar;
    CompExprFuncs[ EXPR_ISB_LVAR        ] = CompIsbLVar;
    CompExprFuncs[ EXPR_REF_HVAR        ] = CompRefHVar;
    CompExprFuncs[ EXPR_ISB_HVAR        ] = CompIsbHVar;
    CompExprFuncs[ EXPR_REF_GVAR        ] = CompRefGVar;
    CompExprFuncs[ EXPR_ISB_GVAR        ] = CompIsbGVar;

    CompExprFuncs[ EXPR_ELM_LIST        ] = CompElmList;
    CompExprFuncs[ EXPR_ELMS_LIST       ] = CompElmsList;
    CompExprFuncs[ EXPR_ELM_LIST_LEV    ] = CompElmListLev;
    CompExprFuncs[ EXPR_ELMS_LIST_LEV   ] = CompElmsListLev;
    CompExprFuncs[ EXPR_ISB_LIST        ] = CompIsbList;
    CompExprFuncs[ EXPR_ELM_REC_NAME    ] = CompElmRecName;
    CompExprFuncs[ EXPR_ELM_REC_EXPR    ] = CompElmRecExpr;
    CompExprFuncs[ EXPR_ISB_REC_NAME    ] = CompIsbRecName;
    CompExprFuncs[ EXPR_ISB_REC_EXPR    ] = CompIsbRecExpr;

    CompExprFuncs[ EXPR_ELM_POSOBJ      ] = CompElmPosObj;
    CompExprFuncs[ EXPR_ISB_POSOBJ      ] = CompIsbPosObj;
    CompExprFuncs[ EXPR_ELM_COMOBJ_NAME ] = CompElmComObjName;
    CompExprFuncs[ EXPR_ELM_COMOBJ_EXPR ] = CompElmComObjExpr;
    CompExprFuncs[ EXPR_ISB_COMOBJ_NAME ] = CompIsbComObjName;
    CompExprFuncs[ EXPR_ISB_COMOBJ_EXPR ] = CompIsbComObjExpr;

    CompExprFuncs[ EXPR_FUNCCALL_OPTS   ] = CompFunccallOpts;

    // enter the boolean expression compilers into the table
    for ( i = 0; i < 256; i++ ) {
        CompBoolExprFuncs[ i ] = CompUnknownBool;
    }

    CompBoolExprFuncs[ EXPR_OR              ] = CompOrBool;
    CompBoolExprFuncs[ EXPR_AND             ] = CompAndBool;
    CompBoolExprFuncs[ EXPR_NOT             ] = CompNotBool;
    CompBoolExprFuncs[ EXPR_EQ              ] = CompEqBool;
    CompBoolExprFuncs[ EXPR_NE              ] = CompNeBool;
    CompBoolExprFuncs[ EXPR_LT              ] = CompLtBool;
    CompBoolExprFuncs[ EXPR_GE              ] = CompGeBool;
    CompBoolExprFuncs[ EXPR_GT              ] = CompGtBool;
    CompBoolExprFuncs[ EXPR_LE              ] = CompLeBool;
    CompBoolExprFuncs[ EXPR_IN              ] = CompInBool;

    // enter the statement compilers into the table
    for ( i = 0; i < 256; i++ ) {
        CompStatFuncs[ i ] = CompUnknownStat;
    }

    CompStatFuncs[ STAT_PROCCALL_0ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_1ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_2ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_3ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_4ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_5ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_6ARGS  ] = CompProccall0to6Args;
    CompStatFuncs[ STAT_PROCCALL_XARGS  ] = CompProccallXArgs;

    CompStatFuncs[ STAT_SEQ_STAT        ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT2       ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT3       ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT4       ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT5       ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT6       ] = CompSeqStat;
    CompStatFuncs[ STAT_SEQ_STAT7       ] = CompSeqStat;
    CompStatFuncs[ STAT_IF              ] = CompIf;
    CompStatFuncs[ STAT_IF_ELSE         ] = CompIf;
    CompStatFuncs[ STAT_IF_ELIF         ] = CompIf;
    CompStatFuncs[ STAT_IF_ELIF_ELSE    ] = CompIf;
    CompStatFuncs[ STAT_FOR             ] = CompFor;
    CompStatFuncs[ STAT_FOR2            ] = CompFor;
    CompStatFuncs[ STAT_FOR3            ] = CompFor;
    CompStatFuncs[ STAT_FOR_RANGE       ] = CompFor;
    CompStatFuncs[ STAT_FOR_RANGE2      ] = CompFor;
    CompStatFuncs[ STAT_FOR_RANGE3      ] = CompFor;
    CompStatFuncs[ STAT_WHILE           ] = CompWhile;
    CompStatFuncs[ STAT_WHILE2          ] = CompWhile;
    CompStatFuncs[ STAT_WHILE3          ] = CompWhile;
    CompStatFuncs[ STAT_REPEAT          ] = CompRepeat;
    CompStatFuncs[ STAT_REPEAT2         ] = CompRepeat;
    CompStatFuncs[ STAT_REPEAT3         ] = CompRepeat;
    CompStatFuncs[ STAT_BREAK           ] = CompBreak;
    CompStatFuncs[ STAT_CONTINUE        ] = CompContinue;
    CompStatFuncs[ STAT_RETURN_OBJ      ] = CompReturnObj;
    CompStatFuncs[ STAT_RETURN_VOID     ] = CompReturnVoid;

    CompStatFuncs[ STAT_ASS_LVAR        ] = CompAssLVar;
    CompStatFuncs[ STAT_UNB_LVAR        ] = CompUnbLVar;
    CompStatFuncs[ STAT_ASS_HVAR        ] = CompAssHVar;
    CompStatFuncs[ STAT_UNB_HVAR        ] = CompUnbHVar;
    CompStatFuncs[ STAT_ASS_GVAR        ] = CompAssGVar;
    CompStatFuncs[ STAT_UNB_GVAR        ] = CompUnbGVar;

    CompStatFuncs[ STAT_ASS_LIST        ] = CompAssList;
    CompStatFuncs[ STAT_ASSS_LIST       ] = CompAsssList;
    CompStatFuncs[ STAT_ASS_LIST_LEV    ] = CompAssListLev;
    CompStatFuncs[ STAT_ASSS_LIST_LEV   ] = CompAsssListLev;
    CompStatFuncs[ STAT_UNB_LIST        ] = CompUnbList;
    CompStatFuncs[ STAT_ASS_REC_NAME    ] = CompAssRecName;
    CompStatFuncs[ STAT_ASS_REC_EXPR    ] = CompAssRecExpr;
    CompStatFuncs[ STAT_UNB_REC_NAME    ] = CompUnbRecName;
    CompStatFuncs[ STAT_UNB_REC_EXPR    ] = CompUnbRecExpr;

    CompStatFuncs[ STAT_ASS_POSOBJ      ] = CompAssPosObj;
    CompStatFuncs[ STAT_UNB_POSOBJ      ] = CompUnbPosObj;
    CompStatFuncs[ STAT_ASS_COMOBJ_NAME ] = CompAssComObjName;
    CompStatFuncs[ STAT_ASS_COMOBJ_EXPR ] = CompAssComObjExpr;
    CompStatFuncs[ STAT_UNB_COMOBJ_NAME ] = CompUnbComObjName;
    CompStatFuncs[ STAT_UNB_COMOBJ_EXPR ] = CompUnbComObjExpr;

    CompStatFuncs[ STAT_INFO            ] = CompInfo;
    CompStatFuncs[ STAT_ASSERT_2ARGS    ] = CompAssert2;
    CompStatFuncs[ STAT_ASSERT_3ARGS    ] = CompAssert3;
    CompStatFuncs[ STAT_EMPTY           ] = CompEmpty;

    CompStatFuncs[ STAT_PROCCALL_OPTS   ] = CompProccallOpts;
    return 0;
}


/****************************************************************************
**
*F  PostRestore( <module> ) . . . . . . . . . . . . . after restore workspace
*/

static Int PostRestore (
    StructInitInfo *    module )
{
    // get the identifiers of 'Length' and 'Add' (for inlining)
    G_Length = GVarName( "Length" );
    G_Add    = GVarName( "Add"    );

    return 0;
}


/****************************************************************************
**
*F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
*/

static Int InitLibrary (
    StructInitInfo *    module )
{
    return PostRestore( module );
}


/****************************************************************************
**
*F  InitInfoCompiler() . . . . . . . . . . . . . . .  table of init functions
*/

static StructInitInfo module = {
    // init struct using C99 designated initializers; for a full list of
    // fields, please refer to the definition of StructInitInfo
    .type = MODULE_BUILTIN,
    .name = "compiler",
    .initKernel = InitKernel,
    .initLibrary = InitLibrary,
    .postRestore = PostRestore
};

StructInitInfo * InitInfoCompiler ( void )
{
    return &module;
}

Messung V0.5 in Prozent
C=80 H=86 G=82

¤ Dauer der Verarbeitung: 0.124 Sekunden  (vorverarbeitet am  2026-04-28) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.