if (fp->sp->type == PROCEDURE)
execerror(fp->sp->name, "(proc) returns value");
d = pop(); /* preserve function return value */
ret();
push(d);
}
procret() /* return from a procedure */
{
if (fp->sp->type == FUNCTION)
execerror(fp->sp->name(func) returns no value");
ret();
}
Функция ret
удаляет аргументы из стека, сохраняет указатель на образ стека fp
и устанавливает счетчик команд:
ret() /* common return from func or proc */
{
int i;
for (i = 0; i < fp->nargs; i++)
pop(); /* pop arguments */
pc = (Inst*)fp->retpc;
--fp;
returning = 1;
}
Некоторые программы интерпретатора нуждаются в небольших поправках для учета ситуаций, когда происходит возврат во вложенных операторах. Решение не элегантно, но верно и состоит во введении признака с именем returning
, который принимает значение 1 при обнаружении оператора return
. Выполнение, организуемое функциями ifcode
, whilecode
, execute
, завершается раньше, если установлен признак returning
; в функции call
он обнуляется.
ifcode() {
Datum d;
Inst *savepc = pc; /* then part */
execute(savepc+3); /* condition */
d = pop();
if (d.val)
execute(*((Inst**)(savepc)));
else if (*((Inst**)(savepc+1))) /* else part? */
execute(*((Inst**)(savepc+1)));
if (!returning)
pc = *((Inst**)(savepc+2)); /* next stmt */
}
whilecode() {
Datum d;
Inst *savepc = pc;
execute(savepc+2); /* condition */
d = pop();
while (d.val) {
execute(*((Inst**)(savepc))); /* body */
if (returning)
break;
execute(savepc+2); /* condition */
d = pop();
}
if (!returning)
pc = *((Inst**)(savepc+1)); /* next stmt */
}
execute(p)
Inst *p;
{
for (pc = p; *pc != STOP && !returning; )
(*((++pc)[-1]))();
}
Аргументы выбираются для получения значения или присваивания с помощью функции getarg
, которая следит за сбалансированностью стека:
double *getarg() /* return pointer to argument */
{
int nargs = (int)*pc++;
if (nargs > fp->nargs)
execerror(fp->sp->name, "not enough arguments");
return &fp->argn[nargs - fp->nargs].val;
}
arg() /* push argument onto stack */
{
Datum d;
d.val = *getarg();
push(d);
}
argassign() /* store top of stack in argument */
{
Datum d;
d = pop();
push(d); /* leave value on stack */
*getarg() = d.val;
}
Функции prstr
и prexpr
печатают строки и числа:
prstr() /* print string value */
{
printf("%s", (char*)*pc++);
}
prexpr() /* print numeric value */
{
Datum d;
d = pop();
printf("%.8g d.val);
}
Функция varread
читает переменные. Она возвращает 0 при обнаружении конца файла и 1 — в противном случае, а также устанавливает значение указанной переменной:
varread() /* read into variable */
{
Datum d;
extern FILE *fin;
Symbol *var = (Symbol*)*pc++;
Again:
switch (fscanf(fin, "%lf", &var->u.val)) {
case EOF:
if (moreinput())
goto Again;
d.val = var->u.val = 0.0;
break;
case 0:
execerror("non-number read into", var->name);
break;
default:
d.val = 1.0;
break;
}
var->type = VAR;
push(d);
}
Обнаружив конец файла для текущего входного потока, функция varread
обратится к moreinput
, которая откроет следующий файл, заданный в качестве аргумента (если он есть). В функции moreinput
обработка входной информации имеет некоторые нюансы, здесь не рассматриваемые; речь о них идет в приложении 3.
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии