v0.60: Array pass by reference works in compiler

- Evaluating 'naked' array name `A` gives pointer to payload (same as `&A` or even `&A[0]`)
- Improved loading message in VM
- Got array pass-by-reference to work in compiler
- Fixed eval stack leak in array initialization code generated by compiler
This commit is contained in:
Bobbi Webber-Manners 2018-05-03 19:53:40 -04:00 committed by GitHub
parent 456c7259d7
commit 92164c3274
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 198 additions and 80 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
eightball

Binary file not shown.

View File

@ -2033,6 +2033,8 @@ unsigned char createintvar(char *name,
emit(VM_NEQL);
emitldi(rtPC - 11);
emit(VM_BRNCH);
emit(VM_DROP);
emit(VM_DROP);
} else {
if (type == TYPE_WORD) {
v = alloc1(sizeof(var_t) + (sz + 2) * sizeof(int));
@ -2203,37 +2205,56 @@ unsigned char setintvar(char *name, int idx, int value)
error(ERR_SUBSCR);
return 1;
}
bodyptr =
(void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
bodyptr = (void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
if (compile) {
/* *** Index is on the stack (Y), and initializer is on the stack (X) *** */
emit(VM_SWAP);
if ((ptr->type & 0x0f) == TYPE_WORD) {
//emitldi(2);
//emit(VM_MUL);
emitldi(1);
emit(VM_LSH);
emitldi((int) ((int *) bodyptr));
/*
* If the array size field is -1, this means the bodyptr is a
* pointer to a pointer to the body (rather than pointer to
* the body), so it needs to be dereferenced one more time.
*/
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDRWORD);
}
emit(VM_ADD);
if (local && compilingsub) {
emit(VM_STRWORD);
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_STAWORD);
} else {
emit(VM_STRWORD);
}
} else {
emit(VM_STAWORD);
}
} else {
emitldi((int) ((int *) bodyptr));
/*
* If the array size field is -1, this means the bodyptr is a
* pointer to a pointer to the body (rather than pointer to
* the body), so it needs to be dereferenced one more time.
*/
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDRWORD);
}
emit(VM_ADD);
if (local && compilingsub) {
emit(VM_STRBYTE);
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_STABYTE);
} else {
emit(VM_STRBYTE);
}
} else {
emit(VM_STABYTE);
}
}
} else {
if ((idx < 0) || (idx >=
*(int *) ((unsigned char *) ptr + sizeof(var_t) +
sizeof(int)))) {
if ((idx < 0) || (idx >= *(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)))) {
error(ERR_SUBSCR);
return 1;
}
@ -2353,55 +2374,73 @@ unsigned char getintvar(char *name,
} else {
/*
* Arrays
* Note the special case:
* For an array A, &A is the same as &A[0]
* Note the special cases, for an array A:
* 1) &A is the same as &A[0]
* 2) A is the same as &A[0]
* This second case is needed to make the eval() work propertly
* for array pass-by-reference.
*/
if (idx == -1) {
if (address) {
idx = 0;
if (compile) {
emitldi(0);
}
} else {
/* Means [..] subscript was never provided */
error(ERR_SUBSCR);
return 1;
/* Means [..] subscript was never provided */
address = 1;
idx = 0;
if (compile) {
emitldi(0);
}
}
bodyptr =
(void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
bodyptr = (void *) *(int *) ((unsigned char *) ptr + sizeof(var_t));
if (compile) {
/* *** Index is on the stack (X) *** */
if ((ptr->type & 0x0f) == TYPE_WORD) {
//emitldi(2);
//emit(VM_MUL);
emitldi(1);
emit(VM_LSH);
emitldi((int) ((int *) bodyptr));
/*
* If the array size field is -1, this means the bodyptr is a
* pointer to a pointer to the body (rather than pointer to
* the body), so it needs to be dereferenced one more time.
*/
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDRWORD);
}
emit(VM_ADD);
if (!address) {
if (local && compilingsub) {
emit(VM_LDRWORD);
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDAWORD);
} else {
emit(VM_LDRWORD);
}
} else {
emit(VM_LDAWORD);
}
}
} else {
emitldi((int) ((int *) bodyptr));
/*
* If the array size field is -1, this means the bodyptr is a
* pointer to a pointer to the body (rather than pointer to
* the body), so it needs to be dereferenced one more time.
*/
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDRWORD);
}
emit(VM_ADD);
if (!address) {
if (local && compilingsub) {
emit(VM_LDRBYTE);
if (*(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)) == -1) {
emit(VM_LDABYTE);
} else {
emit(VM_LDRBYTE);
}
} else {
emit(VM_LDABYTE);
}
}
}
} else {
if ((idx < 0) || (idx >=
*(int *) ((unsigned char *) ptr + sizeof(var_t) +
sizeof(int)))) {
if ((idx < 0) || (idx >= *(int *) ((unsigned char *) ptr + sizeof(var_t) + sizeof(int)))) {
error(ERR_SUBSCR);
return 1;
}
@ -2604,7 +2643,7 @@ unsigned char doendif()
* - LET_MODE - assignment to existing variable
* - FOR_MODE - entry to for loop
*
* Handles parsing the following text (formore == 0):
* Handles parsing the following text (mode != FOR_MODE):
* "var = expr"
* "var[expr1] = expr2"
* or (mode == FOR_MODE):
@ -3170,8 +3209,6 @@ unsigned char dosubr()
}
}
/* TODO: Handle pass by reference for arrays */
/*
* Set up the variables for the formal parameters,
* pointing back to the storage already allocated on
@ -3182,7 +3219,7 @@ unsigned char dosubr()
v = varslocal;
while (v) {
if (v->name[0] != '-') {
if (type == TYPE_WORD) {
if (arraymode || (type == TYPE_WORD)) {
*(int *) ((unsigned char *) v + sizeof(var_t)) += 2;
} else {
*(int *) ((unsigned char *) v + sizeof(var_t)) += 1;
@ -3191,12 +3228,33 @@ unsigned char dosubr()
v = v->next;
}
v = alloc1(sizeof(var_t) + sizeof(int));
if (arraymode) {
v = alloc1(sizeof(var_t) + 2 * sizeof(int));
} else {
v = alloc1(sizeof(var_t) + sizeof(int));
}
*(int *) ((unsigned char *) v + sizeof(var_t)) = 4; // Skip over return address and frame pointer
strncpy(v->name, name, VARNUMCHARS);
v->type = ((arraymode & 0x0f) << 4) | type;
v->next = NULL;
if (arraymode) {
/*
* Array pass-by-reference.
*
* In this case the pointer to the array body was pushed to the
* call stack by the caller, and the var_t record records the
* pointer to this pointer!
*
* Array size is not used in compiled code, so set it to -1 to
* indicate array-pass-by-reference. Code in setintvar() and
* getintvar() uses this to work out that it has to do an extra
* dereference.
*/
*(int *) ((unsigned char *) v + sizeof(var_t) + sizeof(int)) = -1;
}
if (varsend) {
varsend->next = v;
}
@ -3430,14 +3488,12 @@ unsigned char docall()
/*
* Pass scalar value
*/
if (!compile) {
/* Back to old frame for lookup */
varslocal = oldvarslocal;
}
if (eval(0, &arg)) {
/* No expression found */
varslocal = newvarslocal;
error(ERR_ARG);
return RET_ERROR;
}
@ -3458,36 +3514,32 @@ unsigned char docall()
/*
* Array pass-by-reference
*/
for (j = 0; j < VARNUMCHARS; ++j) {
name2[j] = 0;
}
j = 0;
while (txtPtr && (isalphach(*txtPtr)
|| isdigitch(*txtPtr))) {
if (j < VARNUMCHARS) {
name2[j] = *txtPtr;
if (!compile) {
for (j = 0; j < VARNUMCHARS; ++j) {
name2[j] = 0;
}
j = 0;
while (txtPtr && (isalphach(*txtPtr)
|| isdigitch(*txtPtr))) {
if (j < VARNUMCHARS) {
name2[j] = *txtPtr;
}
++txtPtr;
++j;
}
++txtPtr;
++j;
}
if (!compile) {
/* Back to old frame for lookup */
varslocal = oldvarslocal;
}
array = findintvar(name2, &local);
if (!array) {
error(ERR_VAR);
return RET_ERROR;
}
/* j holds number of dimensions */
j = (array->type & 0xf0) >> 4;
if (((array->type & 0x0f) != type) || (j == 0)) {
error(ERR_TYPE);
return RET_ERROR;
}
if (compile) {
/* TODO: Handle pass by reference for arrays for compiled code */
} else {
array = findintvar(name2, &local);
if (!array) {
error(ERR_VAR);
return RET_ERROR;
}
/* j holds number of dimensions */
j = (array->type & 0xf0) >> 4;
if (((array->type & 0x0f) != type) || (j == 0)) {
error(ERR_TYPE);
return RET_ERROR;
}
/* Back to new frame to create var */
varslocal = newvarslocal;
createintvar(name,
@ -3495,7 +3547,16 @@ unsigned char docall()
j,
*(getptrtoscalarword(array) + 1),
0, *getptrtoscalarword(array));
}
} else {
if (eval(0, &arg)) {
/* No expression found */
error(ERR_ARG);
return RET_ERROR;
}
emit(VM_PSHWORD);
argbytes += 2;
}
}
eatspace();
if (*txtPtr == ',') {

Binary file not shown.

View File

@ -37,7 +37,7 @@
/* */
/**************************************************************************/
#define VERSIONSTR "0.59"
#define VERSIONSTR "0.60"
void print(char *str);

Binary file not shown.

View File

@ -209,6 +209,7 @@ void execute_instruction()
unsigned int delay;
#endif
// print("--->PC "); printhex(pc); print(" eval stk: "); printhex(evalptr); print("\n");
#ifdef DEBUGREGS
unsigned int i;
print("\n");
@ -756,9 +757,10 @@ void load()
int main()
{
print("EightBallVM v" VERSIONSTR "\n");
print("Bobbi, 2018\n\n");
print("(c)Bobbi, 2018\n\n");
print("Loading bytecode: ");
load();
print("Done\n");
#ifdef A2E
videomode(VIDEOMODE_80COL);
clrscr();

View File

@ -1,26 +1,26 @@
' Sieve of Eratosthenes
byte A[400] = 1
call doall(20)
byte A[20*20] = 1
call doall(20, A)
end
sub doall(word nr)
sub doall(word nr, byte array[])
word n = nr * nr
pr.msg "Sieve of Eratosthenes ..."
pr.msg "nr is "; pr.dec nr; pr.nl
call sieve(n, nr)
call printresults(n)
call sieve(n, nr, array)
call printresults(n, array)
return 0
endsub
sub sieve(word n, word nr)
sub sieve(word n, word nr, byte AA[])
pr.msg "Sieve"
word i = 0; word j = 0
for i = 2 : (nr - 1)
if A[i]
if AA[i]
j = i * i
while (j < n)
A[j] = 0
AA[j] = 0
j = j + i
endwhile
endif
@ -28,10 +28,10 @@ sub sieve(word n, word nr)
return 0
endsub
sub printresults(word n)
sub printresults(word n, byte AA[])
word i = 0
for i = 2 : (n - 1)
if A[i]
if AA[i]
if i > 2
pr.msg ", "
endif

BIN
test.d64

Binary file not shown.

BIN
test.dsk

Binary file not shown.

View File

@ -189,10 +189,6 @@ call expect(iw==555)
call noret()
call expect(iw==9876)
pr.msg " Recursive:"; pr.nl
call recurse1(5, &iw)
call expect(iw==120)
'------------------
' Subroutine params
'------------------
@ -237,6 +233,24 @@ word a2=&ib
call ppb1(110, a2)
call expect(ib==110)
pr.msg " Recursive:"; pr.nl
call recurse1(5, &iw)
call expect(iw==120)
pr.msg " Array pass by ref:"; pr.nl
word AA[10]=0
call setwarray(AA, 10)
call sumwarray(AA, 10)
call expect(iw==45)
byte BB[10]=0
call setbarray(BB, 10)
call sumbarray(BB, 10)
call expect(iw==45)
call pbrfirstlevel(AA)
call expect(AA[3]==123)
'------------------
' Invoke func
'------------------
@ -376,6 +390,47 @@ sub recurse1(word x, word addr)
endif
endsub
sub setwarray(word A[], word len)
word i=0
for i=0:len-1
A[i] = i
endfor
endsub
sub sumwarray(word A[], word len)
word i=0
iw=0
for i=0:len-1
iw=iw+A[i]
endfor
endsub
sub setbarray(byte A[], word len)
word i=0
for i=0:len-1
A[i] = i
endfor
endsub
sub sumbarray(byte A[], word len)
word i=0
iw=0
for i=0:len-1
iw=iw+A[i]
endfor
endsub
sub pbrfirstlevel(word XX[])
call pbrsecondlevel(XX)
endsub
sub pbrsecondlevel(word XX[])
byte i=0
for i=0:9
XX[i]=123
endfor
endsub
sub recurse2(word x)
if x==0
return 1;