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)
{
--> --------------------

--> maximum size reached

--> --------------------

93%


¤ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet)  ¤

*© 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 ist noch experimentell.