mirror of
https://github.com/bobbimanners/EightBall.git
synced 2024-06-01 06:41:33 +00:00
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:
parent
456c7259d7
commit
92164c3274
BIN
8ball20.prg
BIN
8ball20.prg
Binary file not shown.
BIN
8ball64.prg
BIN
8ball64.prg
Binary file not shown.
BIN
8ballvm20.prg
BIN
8ballvm20.prg
Binary file not shown.
BIN
8ballvm64.prg
BIN
8ballvm64.prg
Binary file not shown.
BIN
ebvm.system
BIN
ebvm.system
Binary file not shown.
189
eightball.c
189
eightball.c
|
@ -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 == ',') {
|
||||
|
|
BIN
eightball.system
BIN
eightball.system
Binary file not shown.
|
@ -37,7 +37,7 @@
|
|||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#define VERSIONSTR "0.59"
|
||||
#define VERSIONSTR "0.60"
|
||||
|
||||
void print(char *str);
|
||||
|
||||
|
|
BIN
eightballvm
BIN
eightballvm
Binary file not shown.
|
@ -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();
|
||||
|
|
20
sieve4.8b
20
sieve4.8b
|
@ -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
|
||||
|
|
63
unittest.8b
63
unittest.8b
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user