// The next macro is used in loop bodies to handle 'break', 'continue' and // 'return' statements. Note that here, during execution, `status` can only // take on the value STATUS_BREAK, STATUS_CONTINUE, STATUS_RETURN, and // STATUS_END; while STATUS_EOF, STATUS_ERROR, STATUS_QUIT, STATUS_QQUIT are // impossible. // // The checks are arranged so that the most frequent cases (i.e. a statement // which is not break/continue/return) is handled first. #define EXEC_STAT_IN_LOOP(stat) \
{ \
ExecStatus status = EXEC_STAT(stat); \ if (status != STATUS_END) { \ if (status == STATUS_CONTINUE) \ continue; \ return (status == STATUS_RETURN) ? STATUS_RETURN : STATUS_END; \
} \
}
/**************************************************************************** ** *FExecSeqStat(<stat>)............executeastatementsequence ** **'ExecSeqStat'executesthestatementsequence<stat>. ** **Thisisdonebyexecutingthestatementsoneafteranother.Ifa **leave-statement('break'or'return')isexecutedinsideoneofthe **statements,thentheexecutionofthestatementsequenceisterminated **andthenon-zeroleave-valueisreturned(totellthecallingexecutor **thataleave-statementwasexecuted).Ifnoleave-statementisexecuted, **then0isreturned. ** **Astatementsequencewith<n>statementsisastatementoftype **'STAT_SEQ_STAT'with<n>slots.Thefirstpointstothefirststatement, **thesecondpointstothesecondstatement,andsoon.
*/ static ALWAYS_INLINE ExecStatus ExecSeqStatHelper(Stat stat, UInt nr)
{ // loop over the statements for (UInt i = 1; i <= nr; i++) { // execute the <i>-th statement
ExecStatus status = EXEC_STAT(READ_STAT(stat, i - 1)); if (status != STATUS_END) { return status;
}
}
return STATUS_END;
}
static ExecStatus ExecSeqStat(Stat stat)
{ // get the number of statements
UInt nr = SIZE_STAT( stat ) / sizeof(Stat); return ExecSeqStatHelper(stat, nr);
}
static ALWAYS_INLINE ExecStatus ExecForHelper(Stat stat, UInt nr)
{
UInt var; // variable
UInt vart; // variable type
Obj list; // list to loop over
Obj elm; // one element of the list
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
UInt i; // loop variable
GAP_ASSERT(1 <= nr && nr <= 3);
// get the variable (initialize them first to please 'lint') const Stat varstat = READ_STAT(stat, 0); if (IS_REF_LVAR(varstat)) {
var = LVAR_REF_LVAR(varstat);
vart = 'l';
} elseif (TNUM_EXPR(varstat) == EXPR_REF_HVAR) {
var = READ_EXPR(varstat, 0);
vart = 'h';
} else/* if ( TNUM_EXPR( varstat ) == EXPR_REF_GVAR ) */ {
var = READ_EXPR(varstat, 0);
vart = 'g';
}
// evaluate the list
list = EVAL_EXPR(READ_STAT(stat, 1));
// get the body
body1 = READ_STAT(stat, 2);
body2 = (nr >= 2) ? READ_STAT(stat, 3) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 4) : 0;
// special case for lists if ( IS_SMALL_LIST( list ) ) {
// loop over the list, skipping unbound entries
i = 1; while ( i <= LEN_LIST(list) ) {
// get the element and assign it to the variable
elm = ELMV0_LIST( list, i );
i++; if ( elm == 0 ) continue; if ( vart == 'l' ) ASS_LVAR( var, elm ); elseif ( vart == 'h' ) ASS_HVAR( var, elm ); elseif ( vart == 'g' ) AssGVar( var, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
}
// general case else {
Obj nfun; // function for NextIterator
Obj dfun; // function for IsDoneIterator
// get the iterator
list = CALL_1ARGS( ITERATOR, list );
if (IS_PREC_OR_COMOBJ(list) && CALL_1ARGS(STD_ITER, list) == True) { // this can avoid method selection overhead on iterator
dfun = ElmPRec( list, RNamName("IsDoneIterator") );
nfun = ElmPRec( list, RNamName("NextIterator") );
} else {
dfun = IS_DONE_ITER;
nfun = NEXT_ITER;
}
// loop over the iterator while ( CALL_1ARGS( dfun, list ) == False ) {
// get the element and assign it to the variable
elm = CALL_1ARGS( nfun, list ); if ( vart == 'l' ) ASS_LVAR( var, elm ); elseif ( vart == 'h' ) ASS_HVAR( var, elm ); elseif ( vart == 'g' ) AssGVar( var, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
/**************************************************************************** ** *FExecForRange(<stat>)................executeafor-loop ** **'ExecForRange'executesthefor-loop<stat>,whichisafor-loopwhose **loopvariableisalocalvariableandwhoselistisaliteralrange **expression. ** **Thisisdonebyevaluatingthelist-expression,checkingthatit **evaluatestoalist,andthenloopingovertheentriesinthelist, **executingthebodyforeachelementofthelist.Ifaleave-statement **('break'or'return')isexecutedinsidethebody,thentheexecutionof **thefor-loopisterminatedand0isreturnediftheleave-statementwasa **break-statementorthenon-zeroleave-valueisreturnedifthe **leave-statementwasareturn-statement(totellthecallingexecutorthat **areturn-statementwasexecuted).Ifnoleave-statementwasexecuted, **then0isreturned. ** **Ashortfor-loopwith<n>statementsinitsbodyisastatementoftype **'STAT_FOR_RANGE'with<n>+2slots.Thefirstslotpointstoanassignment **bagfortheloopvariable,thesecondslotpointstothelist-expression, **andtheremainingslotspointstothestatements.
*/ static ALWAYS_INLINE ExecStatus ExecForRangeHelper(Stat stat, UInt nr)
{
UInt lvar; // local variable Int first; // first value of range Int last; // last value of range
Obj elm; // one element of the list
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop Int i; // loop variable
GAP_ASSERT(1 <= nr && nr <= 3);
// get the variable (initialize them first to please 'lint')
lvar = LVAR_REF_LVAR(READ_STAT(stat, 0));
// evaluate the range
VisitStatIfHooked(READ_STAT(stat, 1));
elm = EVAL_EXPR(READ_EXPR(READ_STAT(stat, 1), 0));
first = GetSmallIntEx("Range", elm, "<first>");
elm = EVAL_EXPR(READ_EXPR(READ_STAT(stat, 1), 1));
last = GetSmallIntEx("Range", elm, "<last>");
// get the body
body1 = READ_STAT(stat, 2);
body2 = (nr >= 2) ? READ_STAT(stat, 3) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 4) : 0;
// loop over the range for ( i = first; i <= last; i++ ) {
// get the element and assign it to the variable
elm = INTOBJ_INT( i );
ASS_LVAR( lvar, elm );
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the statements in the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
}
j = 0; for (i = 1; i <= nrexprs; i++) {
o = EVAL_EXPR(READ_STAT(stat, 2*i)); if (IS_BAG_REF(o)) {
tolock[j] = o;
LockQual qual = INT_INTEXPR(READ_STAT(stat, 2*i-1)); if (qual == LOCK_QUAL_READWRITE)
lockmode[j] = LOCK_MODE_READWRITE; elseif (qual == LOCK_QUAL_READONLY)
lockmode[j] = LOCK_MODE_READONLY; else// if (qual == LOCK_QUAL_NONE)
lockmode[j] = LOCK_MODE_DEFAULT;
j++;
}
}
nrexprs = j;
GetLockStatus(nrexprs, tolock, lockstatus);
j = 0; for (i = 0; i < nrexprs; i++) { switch (lockstatus[i]) { case LOCK_STATUS_UNLOCKED:
tolock[j] = tolock[i];
lockmode[j] = lockmode[i];
j++; break; case LOCK_STATUS_READONLY_LOCKED: if (lockmode[i] == LOCK_MODE_READWRITE)
ErrorMayQuit("Attempt to change from read to write lock", 0, 0); break; case LOCK_STATUS_READWRITE_LOCKED: break;
}
}
lockSP = LockObjects(j, tolock, lockmode); if (lockSP >= 0) {
status = EXEC_STAT(READ_STAT(stat, 0));
PopRegionLocks(lockSP);
} else {
status = 0;
ErrorMayQuit("Cannot lock required regions", 0, 0);
} return status;
} #endif
/**************************************************************************** ** *FExecWhile(<stat>).................executeawhile-loop ** **'ExecWhile'executesthewhile-loop<stat>. ** **Thisisdonebyexecutingthebodywhiletheconditionevaluatesto **'true'.Ifaleave-statement('break'or'return')isexecutedinside **thebody,thentheexecutionofthewhile-loopisterminatedand0is **returnediftheleave-statementwasabreak-statementorthenon-zero **leave-valueisreturnediftheleave-statementwasareturn-statement(to **tellthecallingexecutorthatareturn-statementwasexecuted).Ifno **leave-statementwasexecuted,then0isreturned. ** **Awhile-loopwith<n>statementsinitsbodyisastatementoftype **'STAT_WHILE'with<n>+1slots.Thefirstslotpointstothecondition, **thesecondslotpointstothefirststatement,thethirdslotpointsto **thesecondstatement,andsoon.
*/ static ALWAYS_INLINE ExecStatus ExecWhileHelper(Stat stat, UInt nr)
{
Expr cond; // condition
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
GAP_ASSERT(1 <= nr && nr <= 3);
// get the condition and the body
cond = READ_STAT(stat, 0);
body1 = READ_STAT(stat, 1);
body2 = (nr >= 2) ? READ_STAT(stat, 2) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 3) : 0;
// while the condition evaluates to 'true', execute the body while ( EVAL_BOOL_EXPR( cond ) != False ) {
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
/**************************************************************************** ** *FExecRepeat(<stat>)................executearepeat-loop ** **'ExecRepeat'executestherepeat-loop<stat>. ** **Thisisdonebyexecutingthebodyuntiltheconditionevaluatesto **'true'.Ifaleave-statement('break'or'return')isexecutedinside **thebody,thentheexecutionoftherepeat-loopisterminatedand0is **returnediftheleave-statementwasabreak-statementorthenon-zero **leave-valueisreturnediftheleave-statementwasareturn-statement(to **tellthecallingexecutorthatareturn-statementwasexecuted).Ifno **leave-statementwasexecuted,then0isreturned. ** **Arepeat-loopwith<n>statementsinitsbodyisastatementoftype **'STAT_REPEAT'with<n>+1slots.Thefirstslotpointstothecondition **secondslotpointstothefirststatement,thethirdslotpointstothe **secondstatement,andsoon.
*/ static ALWAYS_INLINE ExecStatus ExecRepeatHelper(Stat stat, UInt nr)
{
Expr cond; // condition
Stat body1; // first stat. of body of loop
Stat body2; // second stat. of body of loop
Stat body3; // third stat. of body of loop
// get the condition and the body
cond = READ_STAT(stat, 0);
body1 = READ_STAT(stat, 1);
body2 = (nr >= 2) ? READ_STAT(stat, 2) : 0;
body3 = (nr >= 3) ? READ_STAT(stat, 3) : 0;
// execute the body until the condition evaluates to 'true' do {
#if !defined(HAVE_SIGNAL) // test for an interrupt if ( HaveInterrupt() ) {
ErrorReturnVoid("user interrupt", 0, 0, "you can 'return;'");
} #endif
// execute the body
EXEC_STAT_IN_LOOP(body1); if (nr >= 2)
EXEC_STAT_IN_LOOP(body2); if (nr >= 3)
EXEC_STAT_IN_LOOP(body3);
selected = InfoCheckLevel(selectors, level); if (selected == True) {
// Get the number of arguments to be printed
narg = NARG_SIZE_INFO(SIZE_STAT(stat)) - 2;
// set up a list
args = NEW_PLIST( T_PLIST, narg );
SET_LEN_PLIST( args, narg );
// evaluate the objects to be printed into the list for (i = 1; i <= narg; i++) {
// These two statements must not be combined into one because of // the risk of a garbage collection during the evaluation // of arg, which may happen after the pointer to args has been // extracted
arg = EVAL_EXPR(ARGI_INFO(stat, i+2));
SET_ELM_PLIST(args, i, arg);
CHANGED_BAG(args);
}
// and print them
InfoDoPrint(selectors, level, args);
} return STATUS_END;
}
// change the entries in 'ExecStatFuncs' back to the original if ( BreakLoopPending() ) {
UnInterruptExecStat();
}
#ifdef HPCGAP // and now for something completely different
HandleInterrupts(1, stat); #else // ensure global interrupt flag syLastIntr is cleared
HaveInterrupt();
// and now for something completely different #ifdef USE_GASMAN if (SyStorOverrun != SY_STOR_OVERRUN_CLEAR) { Int printError = (SyStorOverrun == SY_STOR_OVERRUN_TO_REPORT);
SyStorOverrun = SY_STOR_OVERRUN_CLEAR; // reset if (printError) {
ErrorReturnVoid("reached the pre-set memory limit\n" "(change it with the -o command line option)", 0, 0, "you can 'return;'");
}
} else #endif
ErrorReturnVoid( "user interrupt", 0, 0, "you can 'return;'" ); #endif
// continue at the interrupted statement return EXEC_STAT( stat );
}
/**************************************************************************** ** *FInterruptExecStat()........interrupttheexecutionofstatements ** **'InterruptExecStat'interruptstheexecutionofstatementsatthenext **possiblemoment.Itiscalledfrom'SyAnsIntr'ifaninterruptsignalis **received.Itisnevercalledonsystemsthatdonotsupportsignals.On **thosesystemstheexecutorstest'SyIsIntr'atregularintervals. ** **'InterruptExecStat'changesallentriesintheexecutordispatchtable **'ExecStatFuncs'topointto'ExecIntrStat',whichchangestheentries **back,calls'Error',andredispatchesafterareturnfromthebreak-loop.
*/ void InterruptExecStat ( void )
{ // remember the original entries from the table 'ExecStatFuncs'
STATE(CurrExecStatFuncs) = IntrExecStatFuncs;
}
// change the entries in 'ExecStatFuncs' back to the original if ( BreakLoopPending() ) {
UnInterruptExecStat();
// check for user interrupt if ( HaveInterrupt() ) {
Pr("Noticed user interrupt, but you are back in main loop anyway.\n", 0, 0);
} #ifdef USE_GASMAN // and check if maximal memory was overrun if (SyStorOverrun != SY_STOR_OVERRUN_CLEAR) { if (SyStorOverrun == SY_STOR_OVERRUN_TO_REPORT) {
Pr("GAP has exceeded the permitted memory (-o option),\n", 0, 0);
Pr("the maximum is now enlarged to %d kB.\n", (Int)SyStorMax, 0);
}
SyStorOverrun = SY_STOR_OVERRUN_CLEAR; // reset
} #endif
}
}
// print the opening parenthesis
Pr("%<( %>", 0, 0);
// print the expressions that evaluate to the actual arguments for ( i = 1; i <= NARG_SIZE_INFO( SIZE_STAT(stat) ); i++ ) {
PrintExpr( ARGI_INFO(stat,i) ); if ( i != NARG_SIZE_INFO( SIZE_STAT(stat) ) ) {
Pr("%<, %>", 0, 0);
}
}
// print the closing parenthesis
Pr(" %2<);", 0, 0);
}
for ( i = 0; i < ARRAY_SIZE(ExecStatFuncs); i++ )
IntrExecStatFuncs[i] = ExecIntrStat; for (i = FIRST_NON_INTERRUPT_STAT; i <= LAST_NON_INTERRUPT_STAT; i++)
IntrExecStatFuncs[i] = ExecStatFuncs[i];
/**************************************************************************** ** *FInitInfoStats().................tableofinitfunctions
*/ 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 = "stats",
.initKernel = InitKernel,
.initModuleState = InitModuleState,
};
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.