Actually, it is not the static array that is the problem. It seems to be the return statement. If I change it to this it works.
return token[0] == '\0' ? NULL : &token[0];
Thanks. That's fixed in the current github. Now ebasic is running into some kind of problem inside VM_printf. I think it may be a bug in the varargs handling; I've already found (and fixed) one issue, but there must be something else because my bug fix didn't change anything in ebasic's behavior .
Thanks for the fix. I'm surprised that varargs would be broken since you must use it in your __builtin_printf function too don't you?
Thanks for the fix. I'm surprised that varargs would be broken since you must use it in your __builtin_printf function too don't you?
No, __builtin_printf is built in to the compiler and parses the format string at compile time (so only the code for formats like %d and %f that are actually used need to be included). I do have some simple tests for varargs that work, so there's some interaction in the ebasic code that fastspin isn't handling properly I think.
Thanks for the fix. I'm surprised that varargs would be broken since you must use it in your __builtin_printf function too don't you?
No, __builtin_printf is built in to the compiler and parses the format string at compile time (so only the code for formats like %d and %f that are actually used need to be included). I do have some simple tests for varargs that work, so there's some interaction in the ebasic code that fastspin isn't handling properly I think.
I notice that VM_printf uses a local array as a buffer and assumes it can use its name as an alias for a pointer to the first element. Is that possibly the problem or has that feature been implemented now?
BTW, I apologize for the ugly code in ebasic3. I'll work on cleaning it up once I get it working. It's messy because I tried to shoehorn it into the P1 using either CMM or XMMC with a 64K EEPROM. While I did get it to work it wasn't really useful in those modes. It works pretty well with XMMC and SPI flash chip like the one on the C3.
I notice that VM_printf uses a local array as a buffer and assumes it can use its name as an alias for a pointer to the first element. Is that possibly the problem or has that feature been implemented now?
That should be working now in the current github, but maybe there's something I missed. My current suspect is that the varargs code is interacting badly with some other variable setup code. Do you use alloca() anywhere? That introduces some other special cases. Anyway, I'll try to track it down, but it may take me a while.
No need to apologize for any of your code! It's actually pretty easy to follow, and you use slightly different idioms than I tend to which is good because it's exercising different parts of the compiler. Thanks for your help!
I found it... it was an optimizer bug; the optimizer didn't know that wrlong x, ptra++ changed ptra, so it was moving some of the push instructions for the varargs call around when it shouldn't have. That's fixed now. So it gets further, now it's failing somewhere in the parser.
I found it... it was an optimizer bug; the optimizer didn't know that wrlong x, ptra++ changed ptra, so it was moving some of the push instructions for the varargs call around when it shouldn't have. That's fixed now. So it gets further, now it's failing somewhere in the parser.
Thanks! I just pushed some changes. The line editor now seems to work when compiled with fastspin. I'm not sure what's going wrong in the compiler. I'll look at that next.
This is sort of interesting. Here is an error message that the parser prints:
run
error: Expecting a primary expression
line 0
for x=1 to 10
s
Notice that the last line contains an "s". It should be a "^". The code that prints this error message is here. Notice that the "^" is a constant string. I'm not sure how it would end up displaying as "s".
/* ParseError - report a parsing error */
void ParseError(ParseContext *c, const char *fmt, ...)
{
va_list ap;
/* print the error message */
va_start(ap, fmt);
VM_printf("error: ");
VM_vprintf(fmt, ap);
VM_putchar('\n');
va_end(ap);
/* show the context */
VM_printf(" line %d\n", c->lineNumber);
VM_printf(" %s\n", c->sys->lineBuf);
VM_printf(" %*s\n", c->tokenOffset, "^");
/* exit until we fix the compiler so it can recover from parse errors */
longjmp(c->sys->errorTarget, 1);
}
Edit: Oh wait, now I see it is printed by the format "%*s". Maybe the "s" that gets printed is the "s" in the format. That would mean that the format is being parsed incorrectly.
Edit2: This is failing because simple_vsprintf doesn't know about "*" in a format string. This has nothing to do with your compiler. Sorry for the false alarm.
/* GetToken - get the next token */
int GetToken(ParseContext *c)
{
int tkn;
/* check for a saved token */
if ((tkn = c->savedToken) != T_NONE)
c->savedToken = T_NONE;
/* otherwise, get the next token */
else
tkn = GetToken1(c);
/* return the token */
return tkn;
}
It takes the first clause of the if statement even when c->savedToken is equal to T_NONE rather than taking the else clause.
Another odd thing is that enum values don't seem to reset back to zero at the start of each enum statement. And there are multiple instances of them in the "con" section of the generated .p2asm file. I guess that doesn't hurt since they all have the same values but it probably takes longer to assemble.
/* GetToken - get the next token */
int GetToken(ParseContext *c)
{
int tkn;
/* check for a saved token */
if ((tkn = c->savedToken) != T_NONE)
c->savedToken = T_NONE;
/* otherwise, get the next token */
else
tkn = GetToken1(c);
/* return the token */
return tkn;
}
It takes the first clause of the if statement even when c->savedToken is equal to T_NONE rather than taking the else clause.
I think now that I'm probably wrong about this. I think the problem is that T_NONE is not equal to zero. I initialize the ParseContext structure to all zeros with memset and assume that that field will be equal to T_NONE. I suppose that's probably not a good practice but I think other compilers guarantee that all enum symbols start at zero for a given enum statement.
I manually defined T_NONE to zero and now it's starting to work:
loadp2 ebasic -t -p /dev/cu.usbserial-P2EEQXU -b 115200 -CHIP
Unsupported baudrate 921600. Use ( Entering terminal mode. Press Ctrl-] to exit. )
ebasic3 v0.01
10 print "Hi"
list
10 print "Hi"
OK
run
Hi
OK
Another odd thing is that enum values don't seem to reset back to zero at the start of each enum statement. And there are multiple instances of them in the "con" section of the generated .p2asm file. I guess that doesn't hurt since they all have the same values but it probably takes longer to assemble.
Thanks for noticing this, the enum reset is fixed in github now.
Another odd thing is that enum values don't seem to reset back to zero at the start of each enum statement. And there are multiple instances of them in the "con" section of the generated .p2asm file. I guess that doesn't hurt since they all have the same values but it probably takes longer to assemble.
Thanks for noticing this, the enum reset is fixed in github now.
Some stuff seems to be working now but memory is getting corrupted either in the compiler or the interpreter. If I run a simple program that just prints "Hello" it works the first time but not the second time. I tracked it down to something corrupting the userCmds array in ebasic.c. It will take some time to figure out what's happening because a lot of code has executed during the first run and any of that could have caused the problem. Also, more complicated programs like for loops don't seem to work even the first time.
Here is another possible issue. In the following structure definition it seems that the field "globals" and the field "strings" have the same offset.
/* parse context */
typedef struct {
System *sys; /* system context */
uint8_t *freeMark; /* saved position for reclaiming compiler memory */
uint8_t *nextGlobal; /* next global heap space location */
uint8_t *nextLocal; /* next local heap space location */
size_t heapSize; /* size of heap space in bytes */
size_t maxHeapUsed; /* maximum amount of heap space allocated so far */
int (*getLine)(void *cookie, char *buf, int len, VMVALUE *pLineNumber);
/* scan - function to get a line of input */
void *getLineCookie; /* scan - cookie for the getLine function */
int lineNumber; /* scan - current line number */
int savedToken; /* scan - lookahead token */
int tokenOffset; /* scan - offset to the start of the current token */
char token[MAXTOKEN]; /* scan - current token string */
VMVALUE value; /* scan - current token integer value */
int inComment; /* scan - inside of a slash/star comment */
SymbolTable globals; /* parse - global variables and constants */
String *strings; /* parse - string constants */
Label *labels; /* parse - local labels */
CodeType codeType; /* parse - type of code under construction */
Symbol *codeSymbol; /* parse - symbol table entry of code under construction */
SymbolTable arguments; /* parse - arguments of current function definition */
SymbolTable locals; /* parse - local variables of current function definition */
int localOffset; /* parse - offset to next available local variable */
Block blockBuf[10]; /* parse - stack of nested blocks */
Block *bptr; /* parse - current block */
Block *btop; /* parse - top of block stack */
uint8_t *cptr; /* generate - next available code staging buffer position */
uint8_t *ctop; /* generate - top of code staging buffer */
uint8_t *codeBuf; /* generate - code staging buffer */
ImageHdr *image; /* header of image being constructed */
} ParseContext;
Thanks for putting up with all the bugs and helping with the C debugging!
I just pushed another fix to a similar issue (offsets not being computed properly when variables are declared). That may get us a bit further.
Thanks! That got me a lot further. It looks like it compiled a simple loop correctly. It just doesn't execute it right. Now on to debugging the interpreter!
for (i = 0; i < sizeof(VMVALUE); ++i) {
bytes[i] = VMCODEBYTE(lc + i + 1);
VM_printf("%02x ", bytes[i]);
}
VM_printf("%s ", op->name);
for (i = 0; i < sizeof(VMVALUE); ++i)
VM_printf("%02x", bytes[i]);
VM_printf("\n");
It prints something like this:
19 00 00 A5 44 LIT 0000788A
The code is supposed to print the 4 byte value in the bytes array twice but the second time it prints different values.
Hmmm, that was an interesting bug -- the bytes[] array was being kept in a register because it was only 4 bytes long, instead of being put on the stack. I think that should be fixed now; the listing looks more reasonable, at least. For me I'm currently seeing that variables aren't being set; when I do "a=4" it doesn't seem to change the value of a.
Hmmm, that was an interesting bug -- the bytes[] array was being kept in a register because it was only 4 bytes long, instead of being put on the stack. I think that should be fixed now; the listing looks more reasonable, at least. For me I'm currently seeing that variables aren't being set; when I do "a=4" it doesn't seem to change the value of a.
Thanks,
Eric
Thanks for the fix. I saw the variable problem too. I'll look into it tonight.
Thanks for the fix. I saw the variable problem too. I'll look into it tonight.
One problem was that function pointer comparisons weren't working. That's fixed now and simple assignments seem to work. But a for loop doesn't. I'll have to look at it later.
Thanks for the fix. I saw the variable problem too. I'll look into it tonight.
One problem was that function pointer comparisons weren't working. That's fixed now and simple assignments seem to work. But a for loop doesn't. I'll have to look at it later.
It's always possible that there is a bug in ebasic itself. I did find one bug already while trying to get it to work with fastspin. Don't feel as though you need to spend time trying to get it to work. I'm happy to continue with my efforts and let you know if I find any real issues with fastspin.
The latest version of fastspin in GitHub seems to work quite well! I've pushed the latest sources to GitHub.
ebasic3 v0.01
10 for x=1 to 10
20 print x, x*x
30 next x
run
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
10 100
OK
list
10 for x=1 to 10
20 print x, x*x
30 next x
OK
Comments
That should be working now in the current github, but maybe there's something I missed. My current suspect is that the varargs code is interacting badly with some other variable setup code. Do you use alloca() anywhere? That introduces some other special cases. Anyway, I'll try to track it down, but it may take me a while.
No need to apologize for any of your code! It's actually pretty easy to follow, and you use slightly different idioms than I tend to which is good because it's exercising different parts of the compiler. Thanks for your help!
Edit: Oh wait, now I see it is printed by the format "%*s". Maybe the "s" that gets printed is the "s" in the format. That would mean that the format is being parsed incorrectly.
Edit2: This is failing because simple_vsprintf doesn't know about "*" in a format string. This has nothing to do with your compiler. Sorry for the false alarm.
Thanks for noticing this, the enum reset is fixed in github now.
I just pushed another fix to a similar issue (offsets not being computed properly when variables are declared). That may get us a bit further.
Thanks,
Eric