[INTERPRETER]

* NEW: GOSUB can be recursive now, by saving the control variables, and
  restoring them on RETURN.

[COMPILER]
* NEW: GOSUB can be used on any top-level labels.


git-svn-id: svn://localhost/gambas/trunk@4534 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Benoît Minisini 2012-03-04 23:43:07 +00:00
parent 6bd3a8a3a8
commit 8dfb763782
4 changed files with 62 additions and 32 deletions

View file

@ -337,7 +337,7 @@ void TRANS_control_exit()
if (goto_info[i].gosub)
{
if (label->ctrl_id || goto_info[i].pos > label->pos)
if (label->ctrl_id)
THROW("Forbidden GOSUB");
}
else
@ -1074,7 +1074,7 @@ void TRANS_catch(void)
void TRANS_label(void)
{
CLASS_SYMBOL *sym;
int sym_index, i;
int sym_index;
TRANS_LABEL *label;
sym_index = PATTERN_index(*JOB->current);
@ -1101,6 +1101,7 @@ void TRANS_label(void)
/* on saute le ':' */
JOB->current++;
/*
// A new set of control stack slots must be used for a GOSUB subroutine
for (i = 0; i < ARRAY_count(goto_info); i++)
@ -1111,6 +1112,7 @@ void TRANS_label(void)
return;
}
}
*/
}

View file

@ -849,19 +849,29 @@ _NEW:
_GOSUB:
if (!GP)
{
ALLOC_ZERO(&GP, sizeof(STACK_GOSUB), "EXEC_loop");
}
STACK_GOSUB *gp;
VALUE *ctrl;
int i;
if (!GP)
ARRAY_create(&GP);
if (GP->level == MAX_GOSUB_LEVEL)
{
ALLOC_ZERO(&GP->next, sizeof(STACK_GOSUB), "EXEC_loop");
GP->next->prev = GP;
GP = GP->next;
gp = ARRAY_add(&GP);
gp->pc = PC - FP->code;
if (FP->n_ctrl)
{
ALLOC(&gp->ctrl, sizeof(VALUE) * FP->n_ctrl, "EXEC_loop._GOSUB");
ctrl = &BP[FP->n_local];
for (i = 0; i < FP->n_ctrl; i++)
{
gp->ctrl[i] = ctrl[i];
ctrl[i].type = T_NULL;
}
}
else
gp->ctrl = NULL;
}
GP->pc[GP->level++] = PC - FP->code;
/*-----------------------------------------------*/
@ -903,6 +913,9 @@ _RETURN:
static const void *return_jump[] = { &&__RETURN_GOSUB, &&__RETURN_VALUE, &&__RETURN_VOID };
TYPE type;
STACK_GOSUB *gp;
VALUE *ctrl;
int i, n;
goto *return_jump[GET_UX()];
@ -910,18 +923,29 @@ _RETURN:
if (!GP)
goto __RETURN_VOID;
n = ARRAY_count(GP);
if (n == 0)
goto __RETURN_VOID;
if (GP->level == 0)
gp = &GP[n - 1];
PC = FP->code + gp->pc + 2;
if (FP->n_ctrl)
{
STACK_GOSUB *prev = GP->prev;
IFREE(GP, "EXEC_loop");
GP = prev;
if (!prev)
goto __RETURN_VOID;
ctrl = &BP[FP->n_local];
for (i = 0; i < FP->n_ctrl; i++)
{
RELEASE(&ctrl[i]);
ctrl[i] = gp->ctrl[i];
}
FREE(&gp->ctrl, "EXEC_loop._RETURN");
}
GP->level--;
PC = FP->code + GP->pc[GP->level] + 2;
if (n == 1)
ARRAY_delete(&GP);
else
ARRAY_remove_last(&GP);
goto _MAIN;
__RETURN_VALUE:

View file

@ -268,12 +268,19 @@ STACK_BACKTRACE *STACK_get_backtrace(void)
void STACK_free_gosub_stack(STACK_GOSUB *gosub)
{
int i, j;
STACK_GOSUB *p;
while (gosub)
if (FP->n_ctrl)
{
p = gosub;
gosub = gosub->next;
IFREE(p, "STACK_free_gosub_stack");
for (i = 0, p = gosub; i < ARRAY_count(gosub); i++, p++)
{
for (j = 0; j < FP->n_ctrl; j++)
RELEASE(&p->ctrl[j]);
FREE(&p->ctrl, "STACK_free_gosub_stack");
}
}
}
ARRAY_delete(&gosub);
}

View file

@ -36,16 +36,13 @@ typedef
PACKED
STACK_BACKTRACE;
#define MAX_GOSUB_LEVEL 119
//#define MAX_GOSUB_LEVEL 119
typedef
struct _STACK_GOSUB {
ushort level;
ushort pc[MAX_GOSUB_LEVEL];
struct _STACK_GOSUB *next;
struct _STACK_GOSUB *prev;
ushort pc;
VALUE *ctrl;
}
PACKED
STACK_GOSUB;
typedef