/**************************************************************************** ** ** 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 functions of the coder package. ** ** The coder package is the part of the interpreter that creates the ** expressions. Its functions are called from the reader.
*/
/**************************************************************************** ** *F NewFunctionBody() . . . . . . . . . . . . . . create a new function body
*/
Obj NewFunctionBody(void)
{ return NewBag(T_BODY, sizeof(BodyHeader));
}
/**************************************************************************** ** *F ADDR_EXPR(<expr>) . . . . . . . . . . . absolute address of an expression ** ** 'ADDR_EXPR' returns the absolute address of the memory block of the ** expression <expr>. ** ** Note that it is *fatal* to apply 'ADDR_EXPR' to expressions of type ** 'EXPR_REF_LVAR' or 'EXPR_INT'.
*/ static Expr * ADDR_EXPR(CodeState * cs, Expr expr)
{
GAP_ASSERT(!(IS_REF_LVAR(expr) || IS_INTEXPR(expr))); return (Expr *)PTR_BAG(cs->currBody) + expr / sizeof(Expr);
}
/**************************************************************************** ** *F ADDR_STAT(<stat>) . . . . . . . . . . . . absolute address of a statement ** ** 'ADDR_STAT' returns the absolute address of the memory block of the ** statement <stat>.
*/ static Stat * ADDR_STAT(CodeState * cs, Stat stat)
{
GAP_ASSERT(!(IS_REF_LVAR(stat) || IS_INTEXPR(stat))); return (Stat *)PTR_BAG(cs->currBody) + stat / sizeof(Stat);
}
Stat NewStatOrExpr(CodeState * cs, UInt type, UInt size, UInt line)
{
Stat stat; // result
// this is where the new statement goes
stat = cs->OffsBody + sizeof(StatHeader);
// increase the offset
cs->OffsBody =
stat + ((size + sizeof(Stat) - 1) / sizeof(Stat)) * sizeof(Stat);
// make certain that the current body bag is large enough
Obj body = cs->currBody;
UInt bodySize = SIZE_BAG(body); if (bodySize == 0)
bodySize = cs->OffsBody; while (bodySize < cs->OffsBody)
bodySize *= 2;
ResizeBag(body, bodySize);
// enter type and size
StatHeader * header = STAT_HEADER(cs, stat);
header->line = line;
header->size = size; // check size fits inside header if (header->size != size) {
ErrorQuit("function too large for parser", 0, 0);
}
header->type = type;
RegisterStatWithHook(GET_GAPNAMEID_BODY(cs->currBody), line, type); // return the new statement return stat;
}
/**************************************************************************** ** *F NewExpr(cs, <type>, <size> ) . . . . . . . . . . . allocate a new *expression ** ** 'NewExpr' allocates a new expression memory block of the type <type> and ** <size> bytes. 'NewExpr' returns the identifier of the new expression.
*/ static Expr NewExpr(CodeState * cs, UInt type, UInt size)
{ return NewStat(cs, type, size);
}
/**************************************************************************** ** *V StackStat . . . . . . . . . . . . . . . . . . . . . . . statements stack *V CountStat . . . . . . . . . . . . . . . number of statements on the stack *F PushStat( <stat> ) . . . . . . . . . . . . push statement onto the stack *F PopStat() . . . . . . . . . . . . . . . . . pop statement from the stack ** ** 'StackStat' is the stack of statements that have been coded. ** ** 'CountStat' is the number of statements currently on the statements ** stack. ** ** 'PushStat' pushes the statement <stat> onto the statements stack. The ** stack is automatically resized if necessary. ** ** 'PopStat' returns the top statement from the statements stack and pops ** it. It is an error if the stack is empty.
*/ staticinline UInt CapacityStatStack(void)
{ return SIZE_BAG(CS(StackStat)) / sizeof(Stat) - 1;
}
void PushStat (
Stat stat )
{ // there must be a stack, it must not be underfull or overfull
GAP_ASSERT(CS(StackStat) != 0);
GAP_ASSERT(0 <= CS(CountStat));
GAP_ASSERT(CS(CountStat) <= CapacityStatStack());
GAP_ASSERT( stat != 0 );
// count up and put the statement onto the stack if (CS(CountStat) == CapacityStatStack()) {
ResizeBag(CS(StackStat), (2 * CS(CountStat) + 1) * sizeof(Stat));
}
// put
Stat * data = (Stat *)PTR_BAG(CS(StackStat)) + 1;
data[CS(CountStat)] = stat;
CS(CountStat)++;
}
static Stat PopStat ( void )
{
Stat stat;
// there must be a stack, it must not be underfull/empty or overfull
GAP_ASSERT(CS(StackStat) != 0);
GAP_ASSERT(1 <= CS(CountStat));
GAP_ASSERT(CS(CountStat) <= CapacityStatStack());
// get the top statement from the stack, and count down
CS(CountStat)--;
Stat * data = (Stat *)PTR_BAG(CS(StackStat)) + 1;
stat = data[CS(CountStat)];
// return the popped statement return stat;
}
static Stat PopSeqStat(CodeState * cs, UInt nr)
{
Stat body; // sequence, result
Stat stat; // single statement
UInt i; // loop variable
if (nr == 0 ) {
body = NewStat(cs, STAT_EMPTY, 0);
} // special case for a single statement elseif ( nr == 1 ) {
body = PopStat();
}
// general case else {
// allocate the sequence if ( 2 <= nr && nr <= 7 ) {
body = NewStat(cs, STAT_SEQ_STAT + (nr - 1), nr * sizeof(Stat));
} else {
body = NewStat(cs, STAT_SEQ_STAT, nr * sizeof(Stat));
}
// enter the statements into the sequence for ( i = nr; 1 <= i; i-- ) {
stat = PopStat();
WRITE_STAT(cs, body, i - 1, stat);
}
}
// return the sequence return body;
}
staticinline Stat
PopLoopStat(CodeState * cs, UInt baseType, UInt extra, UInt nr)
{ // fix up the case of no statements if (0 == nr) {
PushStat(NewStat(cs, STAT_EMPTY, 0));
nr = 1;
}
// collect the statements into a statement sequence if necessary elseif (3 < nr) {
PushStat(PopSeqStat(cs, nr));
nr = 1;
}
// allocate the compound statement
Stat stat = NewStat(cs, baseType + (nr - 1),
extra * sizeof(Expr) + nr * sizeof(Stat));
// enter the statements for (UInt i = nr; 1 <= i; i--) {
Stat stat1 = PopStat();
WRITE_STAT(cs, stat, i + extra - 1, stat1);
}
return stat;
}
/**************************************************************************** ** *V StackExpr . . . . . . . . . . . . . . . . . . . . . . . expressions stack *V CountExpr . . . . . . . . . . . . . . number of expressions on the stack *F PushExpr( <expr> ) . . . . . . . . . . . push expression onto the stack *F PopExpr() . . . . . . . . . . . . . . . . pop expression from the stack ** ** 'StackExpr' is the stack of expressions that have been coded. ** ** 'CountExpr' is the number of expressions currently on the expressions ** stack. ** ** 'PushExpr' pushes the expression <expr> onto the expressions stack. The ** stack is automatically resized if necessary. ** ** 'PopExpr' returns the top expressions from the expressions stack and pops ** it. It is an error if the stack is empty.
*/ staticinline UInt CapacityStackExpr(void)
{ return SIZE_BAG(CS(StackExpr)) / sizeof(Expr) - 1;
}
staticvoid PushExpr(Expr expr)
{ // there must be a stack, it must not be underfull or overfull
GAP_ASSERT(CS(StackExpr) != 0);
GAP_ASSERT(0 <= CS(CountExpr));
GAP_ASSERT(CS(CountExpr) <= CapacityStackExpr());
GAP_ASSERT( expr != 0 );
// count up and put the expression onto the stack if (CS(CountExpr) == CapacityStackExpr()) {
ResizeBag(CS(StackExpr), (2 * CS(CountExpr) + 1) * sizeof(Expr));
}
// there must be a stack, it must not be underfull/empty or overfull
GAP_ASSERT(CS(StackExpr) != 0);
GAP_ASSERT(1 <= CS(CountExpr));
GAP_ASSERT(CS(CountExpr) <= CapacityStackExpr());
// get the top expression from the stack, and count down
CS(CountExpr)--;
Expr * data = (Expr *)PTR_BAG(CS(StackExpr)) + 1;
expr = data[CS(CountExpr)];
// return the popped expression return expr;
}
/**************************************************************************** ** *F PushUnaryOp( <type> ) . . . . . . . . . . . . . . . . push unary operator ** ** 'PushUnaryOp' pushes a unary operator expression onto the expression ** stack. <type> is the type of the operator (currently only 'EXPR_NOT').
*/ staticvoid PushUnaryOp(CodeState * cs, UInt type)
{
Expr unop; // unary operator, result
Expr op; // operand
// allocate the unary operator
unop = NewExpr(cs, type, sizeof(Expr));
// enter the operand
op = PopExpr();
WRITE_EXPR(cs, unop, 0, op);
// push the unary operator
PushExpr( unop );
}
/**************************************************************************** ** *F PushBinaryOp( <type> ) . . . . . . . . . . . . . . push binary operator ** ** 'PushBinaryOp' pushes a binary operator expression onto the expression ** stack. <type> is the type of the operator.
*/ staticvoid PushBinaryOp(CodeState * cs, UInt type)
{
Expr binop; // binary operator, result
Expr opL; // left operand
Expr opR; // right operand
/**************************************************************************** ** *F CodeFuncCallOptionsBegin() . . . . . . . . . . . . . code options, begin *F CodeFuncCallOptionsBeginElmName(<rnam>). . . code options, begin element *F CodeFuncCallOptionsBeginElmExpr() . .. . . . .code options, begin element *F CodeFuncCallOptionsEndElm() . . .. . . . . . . code options, end element *F CodeFuncCallOptionsEndElmEmpty() .. . . . . . .code options, end element *F CodeFuncCallOptionsEnd(<nr>) . . . . . . . . . . . . . code options, end ** ** The net effect of all of these is to leave a record expression on the ** stack containing the options record. It will be picked up by ** CodeFuncCallEnd() **
*/ void CodeFuncCallOptionsBegin(CodeState * cs)
{
}
void CodeFuncCallOptionsBeginElmName(CodeState * cs, UInt rnam)
{ // push the record name as integer expressions
PushExpr( INTEXPR_INT( rnam ) );
}
void CodeFuncCallOptionsBeginElmExpr(CodeState * cs)
{ // The expression is on the stack where we want it
}
void CodeFuncCallOptionsEndElmEmpty(CodeState * cs)
{ // The default value is true
PushExpr(NewExpr(cs, EXPR_TRUE, 0));
}
void CodeFuncCallOptionsEnd(CodeState * cs, UInt nr)
{
Expr record; // record, result
Expr entry; // entry
Expr rnam; // position of an entry
UInt i; // loop variable
// allocate the record expression
record = NewExpr(cs, EXPR_REC, nr * 2 * sizeof(Expr));
// enter the entries for ( i = nr; 1 <= i; i-- ) {
entry = PopExpr();
rnam = PopExpr();
WRITE_EXPR(cs, record, 2 * (i - 1), rnam);
WRITE_EXPR(cs, record, 2 * (i - 1) + 1, entry);
}
// push the record
PushExpr( record );
}
/**************************************************************************** ** *F CodeBegin() . . . . . . . . . . . . . . . . . . . . . . . start the coder *F CodeEnd( <error> ) . . . . . . . . . . . . . . . . . . . stop the coder ** ** 'CodeBegin' starts the coder. It is called from the immediate ** interpreter when he encounters a construct that it cannot immediately ** interpret. ** ** 'CodeEnd' stops the coder. It is called from the immediate interpreter ** when he is done with the construct that it cannot immediately interpret. ** If <error> is non-zero, a syntax error was detected by the reader, and ** the coder should only clean up. ** ** ...only function expressions in between...
*/
/**************************************************************************** ** *F CodeFuncCallBegin() . . . . . . . . . . . . . . code function call, begin *F CodeFuncCallEnd( <funccall>, <options>, <nr> ) code function call, end ** ** 'CodeFuncCallBegin' is an action to code a function call. It is called ** by the reader when it encounters the parenthesis '(', i.e., *after* the ** function expression is read. ** ** 'CodeFuncCallEnd' is an action to code a function call. It is called by ** the reader when it encounters the parenthesis ')', i.e., *after* the ** argument expressions are read. <funccall> is 1 if this is a function ** call, and 0 if this is a procedure call. <nr> is the number of ** arguments. <options> is 1 if options were present after the ':' in which ** case the options have been read already.
*/ void CodeFuncCallBegin(CodeState * cs)
{
}
void CodeFuncCallEnd(CodeState * cs, UInt funccall, UInt options, UInt nr)
{
Expr call; // function call, result
Expr func; // function expression
Expr arg; // one argument expression
UInt i; // loop variable
Expr opts = 0; // record literal for the options
Expr wrapper; // wrapper for calls with options
// allocate the function call if ( funccall && nr <= 6 ) {
call = NewExpr(cs, EXPR_FUNCCALL_0ARGS + nr, SIZE_NARG_CALL(nr));
} elseif ( funccall /* && 6 < nr */ ) {
call = NewExpr(cs, EXPR_FUNCCALL_XARGS, SIZE_NARG_CALL(nr));
} elseif ( /* ! funccall && */ nr <=6 ) {
call = NewExpr(cs, STAT_PROCCALL_0ARGS + nr, SIZE_NARG_CALL(nr));
} else/* if ( ! funccall && 6 < nr ) */ {
call = NewExpr(cs, STAT_PROCCALL_XARGS, SIZE_NARG_CALL(nr));
}
// get the options record if any if (options)
opts = PopExpr();
// enter the argument expressions for ( i = nr; 1 <= i; i-- ) {
arg = PopExpr();
SET_ARGI_CALL(call, i, arg);
}
// enter the function expression
func = PopExpr();
SET_FUNC_CALL(call, func);
// wrap up the call with the options if (options)
{
wrapper =
NewExpr(cs, funccall ? EXPR_FUNCCALL_OPTS : STAT_PROCCALL_OPTS,
2 * sizeof(Expr));
WRITE_EXPR(cs, wrapper, 0, opts);
WRITE_EXPR(cs, wrapper, 1, call);
call = wrapper;
}
// push the function call if ( funccall ) {
PushExpr( call );
} else {
PushStat( call );
}
}
/**************************************************************************** ** *F CodeFuncExprBegin( <narg>, <nloc>, <nams> ) . . code function expr, begin *F CodeFuncExprEnd( <nr> ) . . . . . . . . . . code function expression, end ** ** 'CodeFuncExprBegin' is an action to code a function expression. It is ** called when the reader encounters the beginning of a function expression. ** <narg> is the number of arguments (-1 if the function takes a variable ** number of arguments), <nloc> is the number of locals, <nams> is a list of ** local variable names. ** ** 'CodeFuncExprEnd' is an action to code a function expression. It is ** called when the reader encounters the end of a function expression. <nr> ** is the number of statements in the body of the function.
*/ void CodeFuncExprBegin(CodeState * cs, Int narg, Int nloc,
Obj nams,
UInt gapnameid, Int startLine)
{
Obj fexp; // function expression bag
Bag body; // function body
Obj lvars;
LVarsHeader * hdr;
// give it a body
body = NewBag( T_BODY, 1024*sizeof(Stat) );
SET_BODY_FUNC( fexp, body );
CHANGED_BAG( fexp );
// record where we are reading from if (gapnameid)
SET_GAPNAMEID_BODY(body, gapnameid);
SET_STARTLINE_BODY(body, startLine);
cs->OffsBody = sizeof(BodyHeader);
// give it an environment
SET_ENVI_FUNC(fexp, cs->CodeLVars);
CHANGED_BAG(fexp);
MakeHighVars(cs->CodeLVars);
// switch to this function if (narg < 0)
narg = -narg;
// create new lvars, linking to the previous lvars
lvars = NewLVarsBag(narg + nloc);
hdr = (LVarsHeader *)ADDR_OBJ(lvars);
hdr->stat = 0;
hdr->func = fexp;
hdr->parent = cs->CodeLVars;
// ... and from now on put generated code into the new lvars / new body
cs->CodeLVars = lvars;
cs->currBody = body;
// allocate the top level statement sequence
NewStat(cs, STAT_SEQ_STAT, 8 * sizeof(Stat));
}
Expr CodeFuncExprEnd(CodeState * cs, UInt nr, BOOL pushExpr, Int endLine)
{
Expr expr; // function expression, result
Stat stat1; // single statement of body
Obj fexp; // function expression bag
UInt len; // length of func. expr. list
UInt i; // loop variable
// get the function expression
fexp = FUNC_LVARS(cs->CodeLVars);
// get the body of the function // push an additional return-void-statement if necessary // the function interpreters depend on each function ``returning'' if ( nr == 0 ) {
CodeReturnVoid(cs);
nr++;
} else {
stat1 = PopStat();
PushStat(stat1); // If we code a function where the body is already packed into nested // sequence statements, e.g., from reading in a syntax tree, we need // to find the last `real` statement of the last innermost sequence // statement to determine if there is already a return or not. while (STAT_SEQ_STAT <= TNUM_STAT_OR_EXPR(cs, stat1) &&
TNUM_STAT_OR_EXPR(cs, stat1) <= STAT_SEQ_STAT7) {
UInt size = STAT_HEADER(cs, stat1)->size / sizeof(Stat); // stat1 = READ_STAT(stat1, size - 1);
stat1 = ADDR_STAT(cs, stat1)[size - 1];
} if (TNUM_STAT_OR_EXPR(cs, stat1) != STAT_RETURN_VOID &&
TNUM_STAT_OR_EXPR(cs, stat1) != STAT_RETURN_OBJ) {
CodeReturnVoidWhichIsNotProfiled(cs);
nr++;
}
}
// if the body is a long sequence, pack the other statements if ( 7 < nr ) {
stat1 = PopSeqStat(cs, nr - 6);
PushStat( stat1 );
nr = 7;
}
// stuff the first statements into the first statement sequence // Making sure to preserve the line number and file name
StatHeader * header = STAT_HEADER(cs, OFFSET_FIRST_STAT);
header->size = nr*sizeof(Stat);
header->type = STAT_SEQ_STAT+nr-1; for ( i = 1; i <= nr; i++ ) {
stat1 = PopStat();
WRITE_STAT(cs, OFFSET_FIRST_STAT, nr - i, stat1);
}
// make the body values list (if any) immutable
Obj values = VALUES_BODY(cs->currBody); if (values)
MakeImmutable(values);
// make the body smaller
ResizeBag(BODY_FUNC(fexp), cs->OffsBody);
SET_ENDLINE_BODY(BODY_FUNC(fexp), endLine);
// switch back to the previous function
cs->CodeLVars = ENVI_FUNC(fexp);
cs->currBody = BODY_FUNC(FUNC_LVARS(cs->CodeLVars));
// restore the remembered offset
PopOffsBody(cs);
// if this was inside another function definition, make the expression // and store it in the function expression list of the outer function if (STATE(CurrLVars) != cs->CodeLVars) {
len = AddValueToBody(cs, fexp);
expr = NewExpr(cs, EXPR_FUNC, sizeof(Expr));
WRITE_EXPR(cs, expr, 0, len); if (pushExpr) {
PushExpr(expr);
} return expr;
}
// otherwise, make the function and store it in 'cs->CodeResult' else {
cs->CodeResult = MakeFunction(fexp);
}
return 0;
}
/**************************************************************************** ** *F CodeIfBegin() . . . . . . . . . . . code if-statement, begin of statement *F CodeIfElif() . . . . . . . . . . code if-statement, begin of elif-branch *F CodeIfElse() . . . . . . . . . . code if-statement, begin of else-branch *F CodeIfBeginBody() . . . . . . . . . . . code if-statement, begin of body *F CodeIfEndBody( <nr> ) . . . . . . . . . . code if-statement, end of body *F CodeIfEnd( <nr> ) . . . . . . . . . . code if-statement, end of statement ** ** 'CodeIfBegin' is an action to code an if-statement. It is called when ** the reader encounters the 'if', i.e., *before* the condition is read. ** ** 'CodeIfElif' is an action to code an if-statement. It is called when the ** reader encounters an 'elif', i.e., *before* the condition is read. ** ** 'CodeIfElse' is an action to code an if-statement. It is called when the ** reader encounters an 'else'. ** ** 'CodeIfBeginBody' is an action to code an if-statement. It is called ** when the reader encounters the beginning of the statement body of an ** 'if', 'elif', or 'else' branch, i.e., *after* the condition is read. ** ** 'CodeIfEndBody' is an action to code an if-statement. It is called when ** the reader encounters the end of the statements body of an 'if', 'elif', ** or 'else' branch. <nr> is the number of statements in the body. ** ** 'CodeIfEnd' is an action to code an if-statement. It is called when the ** reader encounters the end of the statement. <nr> is the number of 'if', ** 'elif', or 'else' branches.
*/ void CodeIfBegin(CodeState * cs)
{
}
Int CodeIfBeginBody(CodeState * cs)
{ // get and check the condition
Expr cond = PopExpr();
// if the condition is 'false', ignore the body if (TNUM_STAT_OR_EXPR(cs, cond) == EXPR_FALSE) { return 1; // signal interpreter to set IntrIgnoring to 1
} else { // put the condition expression back on the stack
PushExpr(cond); return 0;
}
}
Int CodeIfEndBody(CodeState * cs, UInt nr)
{ // collect the statements in a statement sequence if necessary
PushStat(PopSeqStat(cs, nr));
// get and check the condition
Expr cond = PopExpr();
PushExpr(cond);
// if the condition is 'true', signal interpreter to set IntrIgnoring to // 1, so that other branches of the if-statement are ignored return TNUM_STAT_OR_EXPR(cs, cond) == EXPR_TRUE;
}
void CodeIfEnd(CodeState * cs, UInt nr)
{
Stat stat; // if-statement, result
Expr cond; // condition of a branch
UInt hase; // has else branch
UInt i; // loop variable
// if all conditions were false, the if-statement is an empty statement if (nr == 0) {
PushStat(NewStat(cs, STAT_EMPTY, 0)); return;
}
// peek at the last condition
cond = PopExpr();
hase = (TNUM_STAT_OR_EXPR(cs, cond) == EXPR_TRUE);
PushExpr(cond);
// optimize 'if true then BODY; fi;' to just 'BODY;' if (nr == 1 && hase) { // drop the condition expression, leave the body statement
PopExpr(); return;
}
// allocate the if-statement if ( nr == 1 ) {
stat = NewStat(cs, STAT_IF, nr * (sizeof(Expr) + sizeof(Stat)));
} elseif ( nr == 2 && hase ) {
stat = NewStat(cs, STAT_IF_ELSE, nr * (sizeof(Expr) + sizeof(Stat)));
} elseif ( ! hase ) {
stat = NewStat(cs, STAT_IF_ELIF, nr * (sizeof(Expr) + sizeof(Stat)));
} else {
stat = NewStat(cs, STAT_IF_ELIF_ELSE,
nr * (sizeof(Expr) + sizeof(Stat)));
}
// enter the branches for ( i = nr; 1 <= i; i-- ) {
Stat body = PopStat();
cond = PopExpr();
WRITE_STAT(cs, stat, 2 * (i - 1), cond);
WRITE_STAT(cs, stat, 2 * (i - 1) + 1, body);
}
// push the if-statement
PushStat( stat );
}
/**************************************************************************** ** *F CodeForBegin() . . . . . . . . . code for-statement, begin of statement *F CodeForIn() . . . . . . . . . . . . . . . . code for-statement, 'in' read *F CodeForBeginBody() . . . . . . . . . . code for-statement, begin of body *F CodeForEndBody( <nr> ) . . . . . . . . . code for-statement, end of body *F CodeForEnd() . . . . . . . . . . . code for-statement, end of statement ** ** 'CodeForBegin' is an action to code a for-statement. It is called when ** the reader encounters the 'for', i.e., *before* the variable is read. ** ** 'CodeForIn' is an action to code a for-statement. It is called when the ** reader encounters the 'in', i.e., *after* the variable is read, but ** *before* the list expression is read. ** ** 'CodeForBeginBody' is an action to code a for-statement. It is called ** when the reader encounters the beginning of the statement body, i.e., ** *after* the list expression is read. ** ** 'CodeForEndBody' is an action to code a for-statement. It is called when ** the reader encounters the end of the statement body. <nr> is the number ** of statements in the body. ** ** 'CodeForEnd' is an action to code a for-statement. It is called when the ** reader encounters the end of the statement, i.e., immediately after ** 'CodeForEndBody'.
*/ void CodeForBegin(CodeState * cs)
{
}
void CodeForIn(CodeState * cs)
{
}
void CodeForBeginBody(CodeState * cs)
{
}
void CodeForEndBody(CodeState * cs, UInt nr)
{
Stat stat; // for-statement, result
UInt type; // type of for-statement
Expr var; // variable
Expr list; // list
// get the list expression
list = PopExpr();
// get the variable reference
var = PopExpr();
type = STAT_FOR;
// select the type of the for-statement if (TNUM_STAT_OR_EXPR(cs, list) == EXPR_RANGE) {
StatHeader * hdr = STAT_HEADER(cs, list); if (hdr->size == 2 * sizeof(Expr) && IS_REF_LVAR(var)) {
type = STAT_FOR_RANGE;
}
}
// allocate the for-statement
stat = PopLoopStat(cs, type, 2, nr);
// enter the list expression
WRITE_STAT(cs, stat, 1, list);
// enter the variable reference
WRITE_STAT(cs, stat, 0, var);
// push the for-statement
PushStat( stat );
}
void CodeForEnd(CodeState * cs)
{
}
/**************************************************************************** ** *F CodeAtomicBegin() . . . . . . . code atomic-statement, begin of statement *F CodeAtomicBeginBody() . . . . . . . code atomic-statement, begin of body *F CodeAtomicEndBody( <nr> ) . . . . . . code atomic-statement, end of body *F CodeAtomicEnd() . . . . . . . . . code atomic-statement, end of statement ** ** 'CodeAtomicBegin' is an action to code an atomic-statement. It is called ** when the reader encounters the 'atomic', i.e., *before* the condition is ** read. ** ** 'CodeAtomicBeginBody' is an action to code an atomic-statement. It is ** called when the reader encounters the beginning of the statement body, ** i.e., *after* the condition is read. ** ** 'CodeAtomicEndBody' is an action to code an atomic-statement. It is called ** when the reader encounters the end of the statement body. <nr> is the ** number of statements in the body. ** ** 'CodeAtomicEnd' is an action to code an atomic-statement. It is called ** when the reader encounters the end of the statement, i.e., immediate ** after 'CodeAtomicEndBody'.
*/ void CodeAtomicBegin(CodeState * cs)
{
}
void CodeAtomicEndBody(CodeState * cs, UInt nrstats)
{ #ifdef HPCGAP
Stat stat; // atomic-statement, result
Stat stat1; // single statement of body
UInt i; // loop variable
UInt nrexprs;
Expr e,qual;
// collect the statements into a statement sequence
stat1 = PopSeqStat(cs, nrstats);
nrexprs = INT_INTEXPR(PopExpr());
// allocate the atomic-statement
stat =
NewStat(cs, STAT_ATOMIC, sizeof(Stat) + nrexprs * 2 * sizeof(Stat));
// enter the statement sequence
WRITE_STAT(cs, stat, 0, stat1);
// enter the expressions for ( i = 2*nrexprs; 1 <= i; i -= 2 ) {
e = PopExpr();
qual = PopExpr();
WRITE_STAT(cs, stat, i, e);
WRITE_STAT(cs, stat, i - 1, qual);
}
// push the atomic-statement
PushStat( stat ); #else
Stat stat = PopSeqStat(cs, nrstats);
UInt nrexprs = INT_INTEXPR(PopExpr()); while (nrexprs--) {
PopExpr();
PopExpr();
}
PushStat( stat ); #endif
}
void CodeAtomicEnd(CodeState * cs)
{
}
/**************************************************************************** ** *F CodeQualifiedExprBegin(<qual>) . code readonly/readwrite expression start *F CodeQualifiedExprEnd() . . . . . . code readonly/readwrite expression end ** ** These functions code the beginning and end of the readonly/readwrite ** qualified expressions of an atomic statement.
*/ void CodeQualifiedExprBegin(CodeState * cs, UInt qual)
{
PushExpr(INTEXPR_INT(qual));
}
void CodeQualifiedExprEnd(CodeState * cs)
{
}
/**************************************************************************** ** *F CodeWhileBegin() . . . . . . . code while-statement, begin of statement *F CodeWhileBeginBody() . . . . . . . . code while-statement, begin of body *F CodeWhileEndBody( <nr> ) . . . . . . . code while-statement, end of body *F CodeWhileEnd() . . . . . . . . . code while-statement, end of statement ** ** 'CodeWhileBegin' is an action to code a while-statement. It is called ** when the reader encounters the 'while', i.e., *before* the condition is ** read. ** ** 'CodeWhileBeginBody' is an action to code a while-statement. It is ** called when the reader encounters the beginning of the statement body, ** i.e., *after* the condition is read. ** ** 'CodeWhileEndBody' is an action to code a while-statement. It is called ** when the reader encounters the end of the statement body. <nr> is the ** number of statements in the body. ** ** 'CodeWhileEnd' is an action to code a while-statement. It is called when ** the reader encounters the end of the statement, i.e., immediate after ** 'CodeWhileEndBody'.
*/ void CodeWhileBegin(CodeState * cs)
{
}
void CodeWhileBeginBody(CodeState * cs)
{
}
void CodeWhileEndBody(CodeState * cs, UInt nr)
{
Stat stat; // while-statement, result
Expr cond; // condition
// allocate the while-statement
stat = PopLoopStat(cs, STAT_WHILE, 1, nr);
// enter the condition
cond = PopExpr();
WRITE_STAT(cs, stat, 0, cond);
// push the while-statement
PushStat( stat );
}
void CodeWhileEnd(CodeState * cs)
{
}
/**************************************************************************** ** *F CodeRepeatBegin() . . . . . . . code repeat-statement, begin of statement *F CodeRepeatBeginBody() . . . . . . . code repeat-statement, begin of body *F CodeRepeatEndBody( <nr> ) . . . . . . code repeat-statement, end of body *F CodeRepeatEnd() . . . . . . . . . code repeat-statement, end of statement ** ** 'CodeRepeatBegin' is an action to code a repeat-statement. It is called ** when the reader encounters the 'repeat'. ** ** 'CodeRepeatBeginBody' is an action to code a repeat-statement. It is ** called when the reader encounters the beginning of the statement body, ** i.e., immediately after 'CodeRepeatBegin'. ** ** 'CodeRepeatEndBody' is an action to code a repeat-statement. It is ** called when the reader encounters the end of the statement body, i.e., ** *before* the condition is read. <nr> is the number of statements in the ** body. ** ** 'CodeRepeatEnd' is an action to code a repeat-statement. It is called ** when the reader encounters the end of the statement, i.e., *after* the ** condition is read.
*/ void CodeRepeatBegin(CodeState * cs)
{
}
void CodeRepeatBeginBody(CodeState * cs)
{
}
void CodeRepeatEndBody(CodeState * cs, UInt nr)
{ // leave the number of statements in the body on the expression stack
PushExpr( INTEXPR_INT(nr) );
}
void CodeRepeatEnd(CodeState * cs)
{
Stat stat; // repeat-statement, result
UInt nr; // number of statements in body
Expr cond; // condition
Expr tmp; // temporary
// get the condition
cond = PopExpr();
// get the number of statements in the body // 'CodeUntil' left this number on the expression stack (hack)
tmp = PopExpr();
nr = INT_INTEXPR( tmp );
// allocate the repeat-statement
stat = PopLoopStat(cs, STAT_REPEAT, 1, nr);
// enter the condition
WRITE_STAT(cs, stat, 0, cond);
// push the repeat-statement
PushStat( stat );
}
/**************************************************************************** ** *F CodeBreak() . . . . . . . . . . . . . . . . . . . . code break-statement ** ** 'CodeBreak' is the action to code a break-statement. It is called when ** the reader encounters a 'break;'.
*/ void CodeBreak(CodeState * cs)
{
Stat stat; // break-statement, result
// allocate the break-statement
stat = NewStat(cs, STAT_BREAK, 0 * sizeof(Expr));
// push the break-statement
PushStat( stat );
}
/**************************************************************************** ** *F CodeContinue() . . . . . . . . . . . . . . . . . code continue-statement ** ** 'CodeContinue' is the action to code a continue-statement. It is called ** when the reader encounters a 'continue;'.
*/ void CodeContinue(CodeState * cs)
{
Stat stat; // continue-statement, result
// allocate the continue-statement
stat = NewStat(cs, STAT_CONTINUE, 0 * sizeof(Expr));
// push the continue-statement
PushStat( stat );
}
/**************************************************************************** ** *F CodeReturnObj() . . . . . . . . . . . . . . . code return-value-statement ** ** 'CodeReturnObj' is the action to code a return-value-statement. It is ** called when the reader encounters a 'return <expr>;', but *after* reading ** the expression <expr>.
*/ void CodeReturnObj(CodeState * cs)
{
Stat stat; // return-statement, result
Expr expr; // expression
// allocate the return-statement
stat = NewStat(cs, STAT_RETURN_OBJ, sizeof(Expr));
// enter the expression
expr = PopExpr();
WRITE_STAT(cs, stat, 0, expr);
// push the return-statement
PushStat( stat );
}
/**************************************************************************** ** *F CodeReturnVoid() . . . . . . . . . . . . . . code return-void-statement ** ** 'CodeReturnVoid' is the action to code a return-void-statement. It is ** called when the reader encounters a 'return;'. ** ** 'CodeReturnVoidWhichIsNotProfiled' creates a return which will not ** be tracked by profiling. This is used for the implicit return put ** at the end of functions.
*/ void CodeReturnVoid(CodeState * cs)
{
Stat stat; // return-statement, result
// allocate the return-statement
stat = NewStat(cs, STAT_RETURN_VOID, 0 * sizeof(Expr));
// push the return-statement
PushStat( stat );
}
void CodeReturnVoidWhichIsNotProfiled(CodeState * cs)
{
Stat stat; // return-statement, result
// allocate the return-statement, without profile information
stat = NewStatOrExpr(cs, STAT_RETURN_VOID, 0 * sizeof(Expr), 0);
/**************************************************************************** ** *F CodeIntExpr( <val> ) . . . . . . . . . . code literal integer expression ** ** 'CodeIntExpr' is the action to code a literal integer expression. <val> ** is the integer as a GAP object.
*/ void CodeIntExpr(CodeState * cs, Obj val)
{
Expr expr; // expression, result
// if it is small enough code it immediately if ( IS_INTOBJ(val) ) {
expr = INTEXPR_INT( INT_INTOBJ(val) );
}
// otherwise stuff the value into the values list else {
GAP_ASSERT(TNUM_OBJ(val) == T_INTPOS || TNUM_OBJ(val) == T_INTNEG);
expr = NewExpr(cs, EXPR_INTPOS, sizeof(UInt)); Int ix = AddValueToBody(cs, val);
WRITE_EXPR(cs, expr, 0, ix);
}
/**************************************************************************** ** *F CodeCharExpr( <chr> ) . . . . . . . . code a literal character expression ** ** 'CodeCharExpr' is the action to code a literal character expression. ** <chr> is the C character.
*/ void CodeCharExpr(CodeState * cs, Char chr)
{
Expr litr; // literal expression, result
// allocate the character expression
litr = NewExpr(cs, EXPR_CHAR, sizeof(UInt));
WRITE_EXPR(cs, litr, 0, (UChar)chr);
// push the literal expression
PushExpr( litr );
}
/**************************************************************************** ** *F CodePermCycle( <nrx>, <nrc> ) . . . . code literal permutation expression *F CodePerm( <nrc> ) . . . . . . . . . . code literal permutation expression ** ** 'CodePermCycle' is an action to code a literal permutation expression. ** It is called when one cycles is read completely. <nrc> is the number of ** elements in that cycle. <nrx> is the number of that cycles (i.e., 1 for ** the first cycle, 2 for the second, and so on). ** ** 'CodePerm' is an action to code a literal permutation expression. It is ** called when the permutation is read completely. <nrc> is the number of ** cycles.
*/ void CodePermCycle(CodeState * cs, UInt nrx, UInt nrc)
{
Expr cycle; // cycle, result
Expr entry; // entry of cycle
UInt j; // loop variable
// allocate the new cycle
cycle = NewExpr(cs, EXPR_PERM_CYCLE, nrx * sizeof(Expr));
// enter the entries for ( j = nrx; 1 <= j; j-- ) {
entry = PopExpr();
WRITE_EXPR(cs, cycle, j - 1, entry);
}
// allocate the new permutation
perm = NewExpr(cs, EXPR_PERM, nrc * sizeof(Expr));
// enter the cycles for ( i = nrc; 1 <= i; i-- ) {
cycle = PopExpr();
WRITE_EXPR(cs, perm, i - 1, cycle);
}
// push the permutation
PushExpr( perm );
}
/**************************************************************************** ** *F CodeListExprBegin( <top> ) . . . . . . . . . code list expression, begin *F CodeListExprBeginElm( <pos> ) . . . . code list expression, begin element *F CodeListExprEndElm() . . . . . . . .. code list expression, end element *F CodeListExprEnd( <nr>, <range>, <top>, <tilde> ) . . code list expr, end
*/ void CodeListExprBegin(CodeState * cs, UInt top)
{
}
void CodeListExprBeginElm(CodeState * cs, UInt pos)
{ // push the literal integer value
PushExpr( INTEXPR_INT(pos) );
}
void CodeListExprEndElm(CodeState * cs)
{
}
void CodeListExprEnd(
CodeState * cs, UInt nr, UInt range, UInt top, UInt tilde)
{
Expr list; // list, result
Expr entry; // entry
Expr pos; // position of an entry
UInt i; // loop variable
// peek at the last position (which is the largest) if ( nr != 0 ) {
entry = PopExpr();
pos = PopExpr();
PushExpr( pos );
PushExpr( entry );
} else {
pos = INTEXPR_INT(0);
}
// allocate the list expression if ( ! range && ! (top && tilde) ) {
list = NewExpr(cs, EXPR_LIST, INT_INTEXPR(pos) * sizeof(Expr));
} elseif ( ! range && (top && tilde) ) {
list = NewExpr(cs, EXPR_LIST_TILDE, INT_INTEXPR(pos) * sizeof(Expr));
} else/* if ( range && ! (top && tilde) ) */ {
list = NewExpr(cs, EXPR_RANGE, INT_INTEXPR(pos) * sizeof(Expr));
}
// enter the entries for ( i = nr; 1 <= i; i-- ) {
entry = PopExpr();
pos = PopExpr();
WRITE_EXPR(cs, list, INT_INTEXPR(pos) - 1, entry);
}
// the maximal index must be less than INT_INTOBJ_MAX and INT_MAX, so // simply hardcode it to 1<<28
MAX_FLOAT_INDEX = (1<<28) - 2,
}; static UInt NextFloatExprNumber = 3;
static UInt CheckForCommonFloat(constChar * str)
{ // skip leading zeros while (*str == '0')
str++; // might be zero literal if (*str == '.') { // skip point
str++; // skip more zeroes while (*str == '0')
str++; // if we've got to end of string we've got zero. if (!IsDigit(*str)) return FLOAT_0_INDEX;
} if (*str++ != '1') return 0; // might be one literal if (*str++ != '.') return 0; // skip zeros while (*str == '0')
str++; if (*str == '\0') return FLOAT_1_INDEX; if (IsDigit(*str)) return 0; // must now be an exponent character
assert(IsAlpha(*str)); // skip it
str++; /*skip + and - in exponent */ if (*str == '+' || *str == '-')
str++; // skip leading zeros in the exponent while (*str == '0')
str++; // if there's anything but leading zeros this isn't a one literal if (*str == '\0') return FLOAT_1_INDEX; else return 0;
}
// convert an integer expression to a record name
expr = PopExpr(); if ( IS_INTEXPR(expr) ) {
PushExpr( INTEXPR_INT( RNamIntg( INT_INTEXPR(expr) ) ) );
} else {
PushExpr( expr );
}
}
void CodeRecExprEndElm(CodeState * cs)
{
}
void CodeRecExprEnd(CodeState * cs, UInt nr, UInt top, UInt tilde)
{
Expr record; // record, result
Expr entry; // entry
Expr rnam; // position of an entry
UInt i; // loop variable
// allocate the record expression if ( ! (top && tilde) ) {
record = NewExpr(cs, EXPR_REC, nr * 2 * sizeof(Expr));
} else/* if ( (top && tilde) ) */ {
record = NewExpr(cs, EXPR_REC_TILDE, nr * 2 * sizeof(Expr));
}
// enter the entries for ( i = nr; 1 <= i; i-- ) {
entry = PopExpr();
rnam = PopExpr();
WRITE_EXPR(cs, record, 2 * (i - 1), rnam);
WRITE_EXPR(cs, record, 2 * (i - 1) + 1, entry);
}
// push the record
PushExpr( record );
}
/**************************************************************************** ** *F CodeAssLVar( <lvar> ) . . . . . . . . . . . . . code assignment to local ** ** 'CodeAssLVar' is the action to code an assignment to the local variable ** <lvar> (given by its index). It is called by the reader *after* the ** right hand side expression is read. ** ** An assignment to a local variable is represented by a bag with two ** subexpressions. The *first* is the local variable, the *second* is the ** right hand side expression.
*/ void CodeAssLVar(CodeState * cs, UInt lvar)
{
Stat ass; // assignment, result
Expr rhsx; // right hand side expression
// allocate the assignment
ass = NewStat(cs, STAT_ASS_LVAR, 2 * sizeof(Stat));
// enter the right hand side expression
rhsx = PopExpr();
WRITE_STAT(cs, ass, 1, rhsx);
// enter the local variable
WRITE_STAT(cs, ass, 0, lvar);
// push the assignment
PushStat( ass );
}
/**************************************************************************** ** *F CodeUnbLVar( <lvar> ) . . . . . . . . . . . code unbind a local variable
*/ void CodeUnbLVar(CodeState * cs, UInt lvar)
{
Stat ass; // unbind, result
// allocate the unbind
ass = NewStat(cs, STAT_UNB_LVAR, sizeof(Stat));
// enter the local variable
WRITE_STAT(cs, ass, 0, lvar);
// push the unbind
PushStat( ass );
}
/**************************************************************************** ** *F CodeRefLVar( <lvar> ) . . . . . . . . . . . . . . code reference to local ** ** 'CodeRefLVar' is the action to code a reference to the local variable ** <lvar> (given by its index). It is called by the reader when it ** encounters a local variable. ** ** A reference to a local variable is represented immediately (see ** 'REF_LVAR_LVAR').
*/ void CodeRefLVar(CodeState * cs, UInt lvar)
{
Expr ref; // reference, result
// allocate the isbound
ref = NewExpr(cs, EXPR_ISB_LVAR, sizeof(Expr));
// enter the local variable
WRITE_EXPR(cs, ref, 0, lvar);
// push the isbound
PushExpr( ref );
}
/**************************************************************************** ** *F CodeAssHVar( <hvar> ) . . . . . . . . . . . . . code assignment to higher ** ** 'CodeAssHVar' is the action to code an assignment to the higher variable ** <hvar> (given by its level and index). It is called by the reader ** *after* the right hand side expression is read. ** ** An assignment to a higher variable is represented by a statement bag with ** two subexpressions. The *first* is the higher variable, the *second* is ** the right hand side expression.
*/ void CodeAssHVar(CodeState * cs, UInt hvar)
{
Stat ass; // assignment, result
Expr rhsx; // right hand side expression
// allocate the assignment
ass = NewStat(cs, STAT_ASS_HVAR, 2 * sizeof(Stat));
// enter the right hand side expression
rhsx = PopExpr();
WRITE_STAT(cs, ass, 1, rhsx);
// enter the higher variable
WRITE_STAT(cs, ass, 0, hvar);
// allocate the unbind
ass = NewStat(cs, STAT_UNB_HVAR, sizeof(Stat));
// enter the higher variable
WRITE_STAT(cs, ass, 0, hvar);
// push the unbind
PushStat( ass );
}
/**************************************************************************** ** *F CodeRefHVar( <hvar> ) . . . . . . . . . . . . . code reference to higher ** ** 'CodeRefHVar' is the action to code a reference to the higher variable ** <hvar> (given by its level and index). It is called by the reader when ** it encounters a higher variable. ** ** A reference to a higher variable is represented by an expression bag with ** one subexpression. This is the higher variable.
*/ void CodeRefHVar(CodeState * cs, UInt hvar)
{
Expr ref; // reference, result
// allocate the reference
ref = NewExpr(cs, EXPR_REF_HVAR, sizeof(Expr));
// enter the higher variable
WRITE_EXPR(cs, ref, 0, hvar);
// allocate the isbound
ref = NewExpr(cs, EXPR_ISB_HVAR, sizeof(Expr));
// enter the higher variable
WRITE_EXPR(cs, ref, 0, hvar);
// push the isbound
PushExpr( ref );
}
/**************************************************************************** ** *F CodeAssGVar( <gvar> ) . . . . . . . . . . . . . code assignment to global ** ** 'CodeAssGVar' is the action to code an assignment to the global variable ** <gvar>. It is called by the reader *after* the right hand side ** expression is read. ** ** An assignment to a global variable is represented by a statement bag with ** two subexpressions. The *first* is the global variable, the *second* is ** the right hand side expression.
*/ void CodeAssGVar(CodeState * cs, UInt gvar)
{
Stat ass; // assignment, result
Expr rhsx; // right hand side expression
// allocate the assignment
ass = NewStat(cs, STAT_ASS_GVAR, 2 * sizeof(Stat));
// enter the right hand side expression
rhsx = PopExpr();
WRITE_STAT(cs, ass, 1, rhsx);
// enter the global variable
WRITE_STAT(cs, ass, 0, gvar);
// push the assignment
PushStat( ass );
}
/**************************************************************************** ** *F CodeUnbGVar( <gvar> ) . . . . . . . . . . . . . . . code unbind of global
*/ void CodeUnbGVar(CodeState * cs, UInt gvar)
{
Stat ass; // unbind, result
// allocate the unbind
ass = NewStat(cs, STAT_UNB_GVAR, sizeof(Stat));
// enter the global variable
WRITE_STAT(cs, ass, 0, gvar);
¤ 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.148Bemerkung:
(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.