/**************************************************************************** ** ** 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.
*/
/**************************************************************************** ** *V CompFastIntArith . . option to emit code that handles small ints. faster
*/ staticInt CompFastIntArith;
/**************************************************************************** ** *V CompFastPlainLists . option to emit code that handles plain lists faster
*/ staticInt CompFastPlainLists;
/**************************************************************************** ** *V CompFastListFuncs . . option to emit code that inlines calls to functions
*/ staticInt CompFastListFuncs;
/**************************************************************************** ** *V CompCheckTypes . . . . option to emit code that assumes all types are ok.
*/ staticInt CompCheckTypes;
/**************************************************************************** ** *V CompCheckListElements . option to emit code that assumes list elms exist
*/ staticInt 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.
*/ staticInt CompPass;
/**************************************************************************** ** *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;
/**************************************************************************** ** *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;
staticvoid 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) elseif ( IS_LVAR_CVAR(cvar)
&& TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) ) != W_HIGHER ) {
TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) ) = type;
}
}
staticInt 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 elseif ( IS_TEMP_CVAR(cvar) ) { return TNUM_TEMP_INFO( info, TEMP_CVAR(cvar) );
}
// get the type of a lvar elseif ( IS_LVAR_CVAR(cvar) ) { return TNUM_LVAR_INFO( info, LVAR_CVAR(cvar) );
}
static Bag NewInfoCVars(void)
{
Bag old;
Bag new;
old = INFO_FEXP( CURR_FUNC() ); new = NewBag( TNUM_BAG(old), SIZE_BAG(old) ); returnnew;
}
staticvoid 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);
}
}
staticvoid 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);
}
}
staticBOOL 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) ) { returnFALSE;
}
} for ( i = 1; i <= NTEMP_INFO(dst) && i <= NTEMP_INFO(src); i++ ) { if ( TNUM_TEMP_INFO(dst,i) != TNUM_TEMP_INFO(src,i) ) { returnFALSE;
}
} returnTRUE;
}
/**************************************************************************** ** *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(constChar * 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;
}
staticvoid 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;
staticvoid 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;
}
}
staticInt 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;
/**************************************************************************** ** *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;
staticvoid 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;
}
/**************************************************************************** ** *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 '%'.
*/ staticInt EmitIndent;
staticInt EmitIndent2;
staticvoid Emit(constchar * fmt, ...)
{ Int narg; // number of arguments
va_list ap; // argument list pointer Int dint; // integer argument
CVar cvar; // C variable argument constChar * p; // loop variable constChar * 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);
}
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
// 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 ) );
// 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 ) );
// 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 ) );
// 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 ) );
¤ 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.0.17Bemerkung:
(vorverarbeitet)
¤
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.