#define TRY_IF_NO_ERROR \ if (!rs->s.NrError) { \ volatileInt recursionDepth = GetRecursionDepth(); \ if (_setjmp(STATE(ReadJmpError))) { \
SetRecursionDepth(recursionDepth); \
rs->s.NrError++; \
} \
} \ if (!rs->s.NrError)
struct ReaderState {
ScannerState s;
IntrState intr;
// 'StackNams' is a stack of local variables names lists. A new names // list is pushed onto this stack when the reader begins to read a new // function expression (after reading the argument list and the local // variables list), and popped again when the reader has finished reading // the function expression (after reading the 'end').
Obj StackNams;
// 'ReadTop' is 0 if the reader is currently not reading a list or record // expression. 'ReadTop' is 1 if the reader is currently reading an // outmost list or record expression. 'ReadTop' is larger than 1 if the // reader is currently reading a nested list or record expression.
UInt ReadTop;
// 'ReadTilde' is 1 if the reader has read a reference to a '~' symbol // within the current outmost list or record expression.
UInt ReadTilde;
// 'CurrLHSGVar' is the current left hand side of an assignment. It is // used to prevent undefined global variable warnings, when reading a // recursive function.
UInt CurrLHSGVar;
// 'LoopNesting' records how many nested loops are active. Initially it // is 0 and is incremented each time we enter a loop, and decremented when // we exit one. It is used to determine whether 'break' and 'continue' // statements are valid.
UInt LoopNesting;
};
static UInt GlobalComesFromEnclosingForLoop(ReaderState * rs, UInt var)
{ for (UInt i = 0; i < rs->CurrentGlobalForLoopDepth; i++) { if (i == ARRAY_SIZE(rs->CurrentGlobalForLoopVariables)) return0; if (rs->CurrentGlobalForLoopVariables[i] == var) return1;
} return0;
}
// `Match_` is a thin wrapper around the scanner's Match() function, in which // we can track the start line of each interpreter "instruction". This // information is then used for profiling. staticvoid Match_(ReaderState * rs,
UInt symbol, constChar * msg,
TypSymbolSet skipto)
{ if (rs->intr.startLine == 0 && symbol != S_ILLEGAL) {
rs->intr.startLine = rs->s.SymbolStartLine[0];
}
Match(&rs->s, symbol, msg, skipto);
}
// match either a semicolon or a dual semicolon staticvoid MatchSemicolon(ReaderState * rs, TypSymbolSet skipto)
{
Match_(rs, rs->s.Symbol == S_DUALSEMICOLON ? S_DUALSEMICOLON : S_SEMICOLON, ";", skipto);
}
// Search the plist 'nams' for a string equal to 'value' between and // including index 'start' and 'end' and return its index; return 0 if not // found. static UInt findValueInNams(Obj nams, constChar * val, UInt start, UInt end)
{
GAP_ASSERT(LEN_PLIST(nams) < MAX_FUNC_LVARS); for (UInt i = start; i <= end; i++) { if (streq(CONST_CSTR_STRING(ELM_PLIST(nams, i)), val)) { return i;
}
} // not found return0;
}
GAP_STATIC_ASSERT(sizeof(LHSRef) <= 8, "LHSRef is too big");
/**************************************************************************** **
*/ static UInt EvalRef(ReaderState * rs, const LHSRef ref, Int needExpr)
{
TRY_IF_NO_ERROR
{ switch (ref.type) { case R_LVAR:
IntrRefLVar(&rs->intr, ref.var); break; case R_HVAR:
IntrRefHVar(&rs->intr, ref.var); break; case R_DVAR:
IntrRefDVar(&rs->intr, ref.var, ref.nest0); break; case R_GVAR:
IntrRefGVar(&rs->intr, ref.var); break; case R_ELM_LIST: if (ref.level == 0)
IntrElmList(&rs->intr, ref.narg); else
IntrElmListLevel(&rs->intr, ref.narg, ref.level); return ref.level; case R_ELMS_LIST: if (ref.level == 0)
IntrElmsList(&rs->intr); else
IntrElmsListLevel(&rs->intr, ref.level); return ref.level + 1; case R_ELM_POSOBJ:
IntrElmPosObj(&rs->intr); break; case R_ELM_REC_NAME:
IntrElmRecName(&rs->intr, ref.rnam); break; case R_ELM_REC_EXPR:
IntrElmRecExpr(&rs->intr); break; case R_ELM_COMOBJ_NAME:
IntrElmComObjName(&rs->intr, ref.rnam); break; case R_ELM_COMOBJ_EXPR:
IntrElmComObjExpr(&rs->intr); break; case R_FUNCCALL:
IntrFuncCallEnd(&rs->intr, needExpr, 0, ref.narg); break; case R_FUNCCALL_OPTS:
IntrFuncCallEnd(&rs->intr, needExpr, 1, ref.narg); break; case R_INVALID: default: // This should never be reached
Panic("Parse error in EvalRef");
}
} return0;
}
staticvoid AssignRef(ReaderState * rs, const LHSRef ref)
{
TRY_IF_NO_ERROR
{ switch (ref.type) { case R_LVAR:
IntrAssLVar(&rs->intr, ref.var); break; case R_HVAR:
IntrAssHVar(&rs->intr, ref.var); break; case R_DVAR:
IntrAssDVar(&rs->intr, ref.var, ref.nest0); break; case R_GVAR:
IntrAssGVar(&rs->intr, ref.var); break; case R_ELM_LIST: if (ref.level == 0)
IntrAssList(&rs->intr, ref.narg); else
IntrAssListLevel(&rs->intr, ref.narg, ref.level); break; case R_ELMS_LIST: if (ref.level == 0)
IntrAsssList(&rs->intr); else
IntrAsssListLevel(&rs->intr, ref.level); break; case R_ELM_POSOBJ:
IntrAssPosObj(&rs->intr); break; case R_ELM_REC_NAME:
IntrAssRecName(&rs->intr, ref.rnam); break; case R_ELM_REC_EXPR:
IntrAssRecExpr(&rs->intr); break; case R_ELM_COMOBJ_NAME:
IntrAssComObjName(&rs->intr, ref.rnam); break; case R_ELM_COMOBJ_EXPR:
IntrAssComObjExpr(&rs->intr); break; case R_INVALID: case R_FUNCCALL: case R_FUNCCALL_OPTS: default: // This should never be reached
Panic("Parse error in AssignRef");
}
}
}
staticvoid UnbindRef(ReaderState * rs, const LHSRef ref)
{
TRY_IF_NO_ERROR
{ switch (ref.type) { case R_LVAR:
IntrUnbLVar(&rs->intr, ref.var); break; case R_HVAR:
IntrUnbHVar(&rs->intr, ref.var); break; case R_DVAR:
IntrUnbDVar(&rs->intr, ref.var, ref.nest0); break; case R_GVAR:
IntrUnbGVar(&rs->intr, ref.var); break; case R_ELM_LIST:
IntrUnbList(&rs->intr, ref.narg); break; case R_ELM_POSOBJ:
IntrUnbPosObj(&rs->intr); break; case R_ELM_REC_NAME:
IntrUnbRecName(&rs->intr, ref.rnam); break; case R_ELM_REC_EXPR:
IntrUnbRecExpr(&rs->intr); break; case R_ELM_COMOBJ_NAME:
IntrUnbComObjName(&rs->intr, ref.rnam); break; case R_ELM_COMOBJ_EXPR:
IntrUnbComObjExpr(&rs->intr); break; case R_INVALID: case R_ELMS_LIST: case R_FUNCCALL: case R_FUNCCALL_OPTS: default:
SyntaxError(&rs->s, "Illegal operand for 'Unbind'");
}
}
}
staticvoid IsBoundRef(ReaderState * rs, const LHSRef ref)
{
TRY_IF_NO_ERROR
{ switch (ref.type) { case R_LVAR:
IntrIsbLVar(&rs->intr, ref.var); break; case R_HVAR:
IntrIsbHVar(&rs->intr, ref.var); break; case R_DVAR:
IntrIsbDVar(&rs->intr, ref.var, ref.nest0); break; case R_GVAR:
IntrIsbGVar(&rs->intr, ref.var); break; case R_ELM_LIST:
IntrIsbList(&rs->intr, ref.narg); break; case R_ELM_POSOBJ:
IntrIsbPosObj(&rs->intr); break; case R_ELM_REC_NAME:
IntrIsbRecName(&rs->intr, ref.rnam); break; case R_ELM_REC_EXPR:
IntrIsbRecExpr(&rs->intr); break; case R_ELM_COMOBJ_NAME:
IntrIsbComObjName(&rs->intr, ref.rnam); break; case R_ELM_COMOBJ_EXPR:
IntrIsbComObjExpr(&rs->intr); break; case R_INVALID: case R_ELMS_LIST: case R_FUNCCALL: case R_FUNCCALL_OPTS: default:
SyntaxError(&rs->s, "Illegal operand for 'IsBound'");
}
}
}
Obj nams; // list of names of local vars.
Obj lvars; // environment
UInt nest; // nesting level of a higher var.
Obj lvars0; // environment
UInt nest0; // nesting level of a higher var.
UInt indx; // index of a local variable Char varname[MAX_VALUE_LEN]; // copy of variable name
// all variables must begin with an identifier if (rs->s.Symbol != S_IDENT) {
SyntaxError(&rs->s, "Identifier expected"); return ref;
}
// try to look up the variable on the stack of local variables const UInt countNams = LEN_PLIST(rs->StackNams); for (nest = 0; nest < countNams; nest++) { if (nest >= MAX_FUNC_EXPR_NESTING) {
Pr("Warning: abandoning search for %s at %dth higher frame\n",
(Int)rs->s.Value, MAX_FUNC_EXPR_NESTING); break;
}
nams = ELM_PLIST(rs->StackNams, countNams - nest);
indx = findValueInNams(nams, rs->s.Value, 1, LEN_PLIST(nams)); if (indx != 0) {
ref.type = (nest == 0) ? R_LVAR : R_HVAR;
ref.var = (nest << MAX_FUNC_LVARS_BITS) + indx; break;
}
}
// try to look up the variable on the error stack; // the outer loop runs up the calling stack, while the inner loop runs // up the static definition stack for each call function
lvars0 = STATE(ErrorLVars);
nest0 = 0; while (ref.type == R_INVALID && lvars0 != 0 && !IsBottomLVars(lvars0)) {
lvars = lvars0;
nest = 0; while (ref.type == R_INVALID && lvars != 0 && !IsBottomLVars(lvars)) {
nams = NAMS_FUNC(FUNC_LVARS(lvars)); if (nams != 0) {
indx = findValueInNams(nams, rs->s.Value, 1, LEN_PLIST(nams)); if (indx) {
ref.type = R_DVAR;
ref.var = (nest << MAX_FUNC_LVARS_BITS) + indx;
ref.nest0 = nest0; break;
}
}
lvars = ENVI_FUNC(FUNC_LVARS(lvars));
nest++; if (nest >= MAX_FUNC_EXPR_NESTING) {
Pr("Warning: abandoning search for %s at %dth higher " "frame\n",
(Int)rs->s.Value, MAX_FUNC_EXPR_NESTING); break;
}
}
lvars0 = PARENT_LVARS(lvars0);
nest0++;
}
// get the variable as a global variable if (ref.type == R_INVALID) {
ref.type = R_GVAR; // we do not want to call GVarName on this value until after we // have checked if this is the argument to a lambda function
gap_strlcpy(varname, rs->s.Value, sizeof(varname));
}
// match away the identifier, now that we know the variable
Match_(rs, S_IDENT, "identifier", follow);
// If this isn't a lambda function, look up the name if (rs->s.Symbol != S_MAPTO && ref.type == R_GVAR) {
ref.var = GVarName(varname);
}
return ref;
}
// Helper function to be called after `ReadVar`, before any further tokens // have been consumed via calls to `Match`. staticvoid CheckUnboundGlobal(ReaderState * rs, LHSRef ref)
{ // only warn if we are accessing a global variable if (ref.type != R_GVAR) return;
// only warn if inside a function if (LEN_PLIST(rs->StackNams) == 0) return;
// allow use in left hand side (LHS) of an assignment if (ref.var == rs->CurrLHSGVar) return;
// only warn if the global variable does not exist ... if (ValGVar(ref.var) != 0) return;
// ... and isn't an auto var ... if (ExprGVar(ref.var) != 0) return;
// ... and was not "declared" via DeclareGlobalName if (IsDeclaredGVar(ref.var)) return;
// don't warn if we are skipping/ignoring code if (rs->intr.ignoring) return;
// if the global was used as loop variable in an enclosing for loop, that // means it will be assigned before execution gets here, so don't warn. if (GlobalComesFromEnclosingForLoop(rs, ref.var)) return;
// check if the user disabled this warning if (WarnOnUnboundGlobalsRNam == 0)
WarnOnUnboundGlobalsRNam = RNamName("WarnOnUnboundGlobals"); if (GAPInfo && IS_REC(GAPInfo) &&
ISB_REC(GAPInfo, WarnOnUnboundGlobalsRNam) &&
ELM_REC(GAPInfo, WarnOnUnboundGlobalsRNam) == False) return;
// don't warn if we are compiling code if (SyCompilePlease) return;
// Need to pass an offset, because we have already parsed more tokens
SyntaxWarningWithOffset(&rs->s, "Unbound global variable", 2);
}
// if this was actually the beginning of a function literal, then we are // in the wrong function if (rs->s.Symbol == S_MAPTO) { if (mode == 'r' || mode == 'x')
ReadFuncExprAbbrevSingle(rs, follow); else
SyntaxError(&rs->s, "Function literal in impossible context"); return;
}
// Check if the variable is a constant if (ref.type == R_GVAR && IsConstantGVar(ref.var) && ValGVar(ref.var)) { // deal with references if (mode == 'r' || (mode == 'x' && rs->s.Symbol != S_ASSIGN)) {
Obj val = ValAutoGVar(ref.var);
TRY_IF_NO_ERROR { if (val == True) {
IntrTrueExpr(&rs->intr); return;
} elseif (val == False) {
IntrFalseExpr(&rs->intr); return;
} elseif (IS_INTOBJ(val)) {
IntrIntObjExpr(&rs->intr, val); return;
}
}
}
}
// check whether this is an unbound global variable if (mode != 'i') // Not inside 'IsBound'
CheckUnboundGlobal(rs, ref);
// followed by one or more selectors while (IS_IN(rs->s.Symbol, S_LPAREN | S_LBRACK | S_LBRACE | S_DOT)) {
// so the prefix was a reference
UInt level = EvalRef(rs, ref, 1);
ref = ReadSelector(rs, follow, level);
}
// if we need a reference if (mode == 'r' || (mode == 'x' && rs->s.Symbol != S_ASSIGN)) { Int needExpr = mode == 'r' || !IS_IN(rs->s.Symbol, S_SEMICOLON);
EvalRef(rs, ref, needExpr);
}
// if we need a statement elseif (mode == 's' || (mode == 'x' && rs->s.Symbol == S_ASSIGN)) { if (ref.type == R_FUNCCALL || ref.type == R_FUNCCALL_OPTS) {
TRY_IF_NO_ERROR {
IntrFuncCallEnd(&rs->intr, 0, ref.type == R_FUNCCALL_OPTS, ref.narg);
}
} else {
Match_(rs, S_ASSIGN, "found an expression when a statement was", follow);
UInt currLHSGVar = rs->CurrLHSGVar; if ( LEN_PLIST(rs->StackNams) == 0 || !rs->intr.coding ) {
rs->CurrLHSGVar = (ref.type == R_GVAR ? ref.var : 0);
}
ReadExpr(rs, follow, 'r');
AssignRef(rs, ref);
rs->CurrLHSGVar = currLHSGVar;
}
}
// if we need an unbind elseif ( mode == 'u' ) { if (rs->s.Symbol != S_RPAREN) {
SyntaxError(&rs->s, "'Unbind': argument should be followed by ')'");
}
UnbindRef(rs, ref);
}
// if we need an isbound else/* if ( mode == 'i' ) */ {
IsBoundRef(rs, ref);
}
// that was the permutation
TRY_IF_NO_ERROR { IntrPerm(&rs->intr, nrc ); }
}
/**************************************************************************** ** *FReadListExpr(<follow>)..................readalist ** **'ReadListExpr'readsalistliteralexpression.Incaseofanerrorit **skipsallsymbolsuptoonecontainedin<follow>. ** **<List>:='['[<Expr>]{','[<Expr>]}']' **|'['<Expr>[','<Expr>]'..'<Expr>']'
*/ staticvoid ReadListExpr(ReaderState * rs, TypSymbolSet follow)
{ volatile UInt pos; // actual position of element volatile UInt nr; // number of elements volatile UInt range; // is the list expression a range
/**************************************************************************** ** **ArgListrepresentsthereturnvalueofReadFuncArgList
*/ typedefstruct { Int narg; // number of arguments
Obj nams; // list of local variables names BOOL isvarg; // does function have varargs? #ifdef HPCGAP
Obj locks; // locks of the function (HPC-GAP) #endif
} ArgList;
static ArgList ReadFuncArgList(ReaderState * rs,
TypSymbolSet follow, BOOL isAtomic,
UInt symbol, constChar * symbolstr)
{ Int narg; // number of arguments
Obj nams; // list of local variables names #ifdef HPCGAP
LockQual lockqual;
Bag locks = 0; // locks of the function #endif BOOL isvarg = FALSE; // does function have varargs?
#ifdef HPCGAP if (isAtomic)
locks = NEW_STRING(4); #endif
// make and push the new local variables list (args and locals)
narg = 0;
nams = NEW_PLIST(T_PLIST, 0); if (rs->s.Symbol != symbol) { goto start;
}
while (rs->s.Symbol == S_COMMA) { if (isvarg) {
SyntaxError(&rs->s, "Only final argument can be variadic");
}
Match_(rs, S_COMMA, ",", follow);
start: #ifdef HPCGAP
lockqual = LOCK_QUAL_NONE; #endif if (rs->s.Symbol == S_READWRITE) { if (!isAtomic) {
SyntaxError(&rs->s, "'readwrite' argument of non-atomic function");
} #ifdef HPCGAP else {
lockqual = LOCK_QUAL_READWRITE;
} #endif
Match_(rs, S_READWRITE, "readwrite", follow);
} elseif (rs->s.Symbol == S_READONLY) { if (!isAtomic) {
SyntaxError(&rs->s, "'readonly' argument of non-atomic function");
} #ifdef HPCGAP else {
lockqual = LOCK_QUAL_READONLY;
} #endif
Match_(rs, S_READONLY, "readonly", follow);
} if (rs->s.Symbol == S_IDENT && findValueInNams(nams, rs->s.Value, 1, narg)) {
SyntaxError(&rs->s, "Name used for two arguments");
}
narg += 1;
PushPlist(nams, MakeImmString(rs->s.Value)); #ifdef HPCGAP if (isAtomic) {
GrowString(locks, narg);
SET_LEN_STRING(locks, narg);
CHARS_STRING(locks)[narg - 1] = lockqual;
} #endif if (LEN_PLIST(nams) >= MAX_FUNC_LVARS) {
SyntaxError(&rs->s, "Too many function arguments");
}
Match_(rs, S_IDENT,"identifier",symbol|S_LOCAL|STATBEGIN|S_END|follow); if (rs->s.Symbol == S_DOTDOT) {
SyntaxError(&rs->s, "Three dots required for variadic argument list");
} if (rs->s.Symbol == S_DOTDOTDOT) {
isvarg = TRUE;
Match_(rs, S_DOTDOTDOT, "...", follow);
}
}
Match_(rs, symbol, symbolstr, S_LOCAL|STATBEGIN|S_END|follow);
// Special case for function(arg) if (narg == 1 && streq("arg", CONST_CSTR_STRING(ELM_PLIST(nams, narg)))) {
isvarg = TRUE;
}
while (1) { if (rs->s.Symbol == S_IDENT) { if (findValueInNams(nams, rs->s.Value, narg + 1, narg + nloc)) {
SyntaxError(&rs->s, "Name used for two locals");
} if (findValueInNams(nams, rs->s.Value, 1, narg)) {
SyntaxError(&rs->s, "Name used for argument and local");
}
nloc += 1;
PushPlist(nams, MakeImmString(rs->s.Value)); if (LEN_PLIST(nams) >= MAX_FUNC_LVARS) {
SyntaxError(&rs->s, "Too many function arguments and locals");
}
}
Match_(rs, S_IDENT, "identifier", STATBEGIN | S_END | follow);
if (rs->s.Symbol != S_COMMA) break;
// init to avoid strange message in case of empty string
rs->s.Value[0] = '\0';
Match_(rs, S_COMMA, ",", follow);
}
MatchSemicolon(rs, STATBEGIN | S_END | follow);
return nloc;
}
/**************************************************************************** ** *FReadFuncExpr(<follow>)..........readafunctiondefinition ** **'ReadFuncExpr'readsafunctionliteralexpression.Incaseofanerror **itskipsallsymbolsuptoonecontainedin<follow>. ** **<Function>:='function('<ArgList>')' **['local'<Ident>{','<Ident>}';'] **<Statements> **'end'
*/ staticvoid ReadFuncExpr(ReaderState * rs, TypSymbolSet follow, Char mode)
{ Int startLine; // line number of function keyword BOOL isAtomic = FALSE; // is this an atomic function?
UInt nloc = 0; // number of locals
ArgList args;
// begin the function
startLine = GetInputLineNumber(rs->s.input); if (rs->s.Symbol == S_ATOMIC) {
Match_(rs, S_ATOMIC, "atomic", follow);
isAtomic = TRUE;
} elseif (mode == 'a') { // in this case the atomic keyword was matched away by ReadAtomic // before we realised we were reading an atomic function
isAtomic = TRUE;
}
Match_(rs, S_FUNCTION, "function", follow);
Match_(rs, S_LPAREN, "(", S_IDENT|S_RPAREN|S_LOCAL|STATBEGIN|S_END|follow);
/**************************************************************************** ** *FReadLiteral(<follow>,<mode>)..............readanatom ** **'ReadLiteral'readsaliteralexpression.Incaseofanerroritskips **allsymbolsuptoonecontainedin<follow>. ** **<Literal>:=<Int> **|<Float> **|'true' **|'false' **|'~' **|<Char> **|<Perm> **|<String> **|<List> **|<Record> **|<Function> ** **<Int>:=0|1|..|9{0|1|..|9} ** **<Char>:='<anycharacter>' ** **<String>:="{<anycharacter>}"
*/ staticvoid ReadLiteral(ReaderState * rs, TypSymbolSet follow, Char mode)
{ if (rs->s.Symbol == S_DOT) { // HACK: The only way a dot could turn up here is in a floating point // literal that starts with '.'. Call back to the scanner to deal // with this.
ScanForFloatAfterDotHACK(&rs->s);
}
// 'od'
Match_(rs, S_OD, "while parsing a 'while' loop: statement or 'od'", follow);
TRY_IF_NO_ERROR {
IntrWhileEnd(&rs->intr, rs->StackNams);
}
}
/**************************************************************************** ** *FReadAtomic(<follow>)...............readanatomicblock ** **'ReadAtomic'readsanatomicblock.Incaseofanerroritskipsall **symbolsuptoonecontainedin<follow>. ** **<Statement>:='atomic'<QualifiedExpr>{','<QualifiedExpr}'do' **<Statements> **'od'';' ** **ThesefunctionsonlydosomethingmeaningfulinsideHPC-GAP;inplainGAP, **theyaresimplyplaceholders.
*/ staticvoid ReadAtomic(ReaderState * rs, TypSymbolSet follow)
{ volatile UInt nrs; // number of statements in body volatile UInt nexprs; // number of statements in body #ifdef HPCGAP volatileint lockSP; // lock stack
lockSP = RegionLockSP(); #endif
Match_(rs, S_ATOMIC, "atomic", follow); // Might just be an atomic function literal as an expression if (rs->s.Symbol == S_FUNCTION) {
ReadFuncExpr(rs, follow, 'a'); return;
}
// 'od'
Match_(rs, S_OD, "while parsing an atomic block: statement or 'od'", follow);
TRY_IF_NO_ERROR {
IntrAtomicEnd(&rs->intr, rs->StackNams);
} #ifdef HPCGAP /* This is a no-op if IntrAtomicEnd(&rs->intr) succeeded, otherwise it restores
* locks to where they were before. */
PopRegionLocks(lockSP); #endif
}
/**************************************************************************** ** *FReadRepeat(<follow>).............readarepeatstatement ** **'ReadRepeat'readsarepeat-loop.Incaseofanerroritskipsall **symbolsuptoonecontainedin<follow>. ** **<Statement>:='repeat' **<Statements> **'until'<Expr>';'
*/ staticvoid ReadRepeat(ReaderState * rs, TypSymbolSet follow)
{ volatile UInt nrs; // number of statements in body
// At this point we have the stack upside down, so invert it const UInt countNams = LEN_PLIST(stackNams); for (UInt i = 1; i <= countNams/2; i++) { const UInt j = countNams + 1 -i;
Obj tmpA = ELM_PLIST(stackNams, i);
Obj tmpB = ELM_PLIST(stackNams, j);
SET_ELM_PLIST(stackNams, i, tmpB);
SET_ELM_PLIST(stackNams, j, tmpA);
}
}
// remember the old execution state and start an execution environment
Bag oldLVars =
context ? SWITCH_TO_OLD_LVARS(context) : SWITCH_TO_BOTTOM_LVARS();
switch (rs->s.Symbol) { // read an expression or an assignment or a procedure call case S_IDENT: ReadExpr(rs, S_SEMICOLON|S_EOF, 'x' ); break;
// otherwise read a statement -- first handle some which are different on // the top level than inside a function, if/else or loop case S_QUIT: ReadQuit(rs, S_SEMICOLON|S_EOF ); break; case S_QQUIT: ReadQUIT(rs, S_SEMICOLON|S_EOF ); break; case S_HELP:
ReadHelp(rs, S_SEMICOLON | S_EOF);
rs->s.Symbol = S_SEMICOLON; // fake a trailing semicolon break; case S_PRAGMA:
ReadPragma(rs, S_SEMICOLON | S_EOF);
rs->s.Symbol = S_SEMICOLON; // fake a trailing semicolon break;
// otherwise try to read a generic statement default: if (!TryReadStatement(rs, S_SEMICOLON | S_EOF)) { // not a statement, but perhaps it is an expression
ReadExpr(rs, S_SEMICOLON | S_EOF, 'r');
}
}
// every statement must be terminated by a semicolon if (!IS_IN(rs->s.Symbol, S_SEMICOLON)) {
SyntaxError(&rs->s, "; expected");
}
// check for dual semicolon if (dualSemicolon)
*dualSemicolon = (rs->s.Symbol == S_DUALSEMICOLON);
// end the interpreter
status = IntrEnd(&rs->intr, rs->s.NrError > 0, evalResult);
// restore the execution environment
SWITCH_TO_OLD_LVARS(oldLVars);
#ifdef HPCGAP if (rs->s.NrError > 0) {
PopRegionLocks(lockSP); if (TLS(CurrentHashLock))
HashUnlock(TLS(CurrentHashLock));
} #endif
GAP_ASSERT(rs->LoopNesting == 0);
// switch back to the old reader context
memcpy( STATE(ReadJmpError), readJmpError, sizeof(jmp_buf) );
STATE(Tilde) = tilde;
STATE(ErrorLVars) = errorLVars;
ClearError();
// return whether a return-statement or a quit-statement were executed return status;
}
// check for local variables
nams = NEW_PLIST(T_PLIST, 0);
PushPlist(rs->StackNams, nams);
nloc = 0; if (rs->s.Symbol == S_LOCAL) {
nloc = ReadLocals(rs, 0, nams);
}
// fake the 'function ()'
IntrFuncExprBegin(&rs->intr, 0, nloc, nams,
GetInputLineNumber(input));
// read the statements
GAP_ASSERT(rs->LoopNesting == 0);
nr = ReadStats(rs, S_SEMICOLON | S_EOF);
GAP_ASSERT(rs->LoopNesting == 0);
// we now want to be at <end-of-file> if (rs->s.Symbol != S_EOF) {
FlushRestOfInputLine(input);
SyntaxError(&rs->s, "<end-of-file> expected");
}
// fake the 'end;'
TRY_IF_NO_ERROR {
IntrFuncExprEnd(&rs->intr, nr, GetInputLineNumber(input));
}
// end the interpreter
status = IntrEnd(&rs->intr, rs->s.NrError > 0, evalResult);
// restore the execution environment
SWITCH_TO_OLD_LVARS(oldLVars);
// switch back to the old reader context
memcpy( STATE(ReadJmpError), readJmpError, sizeof(jmp_buf) ); #ifdef HPCGAP
PopRegionLocks(lockSP); if (TLS(CurrentHashLock))
HashUnlock(TLS(CurrentHashLock)); #endif
STATE(Tilde) = tilde;
ClearError();
// return whether a return-statement or a quit-statement were executed return status;
}
/**************************************************************************** ** *FCall0ArgsInNewReader(Objf)............callaGAPfunction ** **Thecurrentreadercontextissavedandanewoneisstarted.
*/
Obj Call0ArgsInNewReader(Obj f)
{ // remember the old state volatile UInt userHasQuit = STATE(UserHasQuit); volatile Obj oldLvars; volatile Obj result = 0;
/**************************************************************************** ** *FInitInfoRead().................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 = "read",
.initKernel = InitKernel,
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.103Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
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.