Shop OBEX P1 Docs P2 Docs Learn Events
fastspin C compiler - Page 3 — Parallax Forums

fastspin C compiler

135

Comments

  • ersmith wrote: »
    David Betz wrote: »
    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?

  • David Betz wrote: »
    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.

  • ersmith wrote: »
    David Betz wrote: »
    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.
  • David Betz wrote: »
    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 don't think the problem is with VM_printf. I added this line to the start of ebasic.c and it works fine.
        VM_printf("ebasic3 %s %d\n", "v0.01", 123);
    
    I'll keep looking.
  • 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.
  • ersmith wrote: »
    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.

  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-23 03:24
    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.
  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-23 04:01
    I just pushed a change to simple_vsnprintf.c to support the '*' printf format modifier.
    ebasic3 v0.01
    10 for x=1
    list
    10  for x=1
    OK
    run
    error: Expecting 'TO', found '<EOL>'
      line 0
         for x=1
    
        ^        
    OK
    
  • Hmmm... It still doesn't work because the spaces from the '*' are placed to the right of the "^" not the left. I'll have to look into this further.
  • I don't think this code is compiling correctly:
    /* 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.
  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-24 04:26
    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.
  • David Betz wrote: »
    I don't think this code is compiling correctly:
    /* 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
    
  • David Betz wrote: »
    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.
  • ersmith wrote: »
    David Betz wrote: »
    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.
    Thanks for the quick fix!

  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-24 18:16
    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;
    
  • Here is a simple example of this problem. It produces the following output:
    c 00000BE8, &c->globals 00000BEC, &c->strings 00000BEC
    
    Notice that &c->globals is the same as &c->strings.
    typedef int VMVALUE;
    
    typedef struct SymbolTable SymbolTable;
    typedef struct Symbol Symbol;
    typedef struct String String;
    
    /* string structure */
    struct String {
        String *next;
        VMVALUE value;
        char data[1];
    };
    
    /* symbol table */
    struct SymbolTable {
        Symbol *head;
        Symbol **pTail;
        int count;
    };
    
    /* symbol structure */
    struct Symbol {
        Symbol *next;
        VMVALUE value;
        char name[1];
    };
    
    /* parse context */
    typedef struct {
        int foo;
        SymbolTable globals;            /* parse - global variables and constants */
        String *strings;                /* parse - string constants */
        int bar;
    } ParseContext;
    
    void main(void)
    {
        ParseContext context;
        ParseContext *c = &context;
        
        waitcnt(getcnt() + clkfreq * 1);
        __builtin_printf("c %08x, &c->globals %08x, &c->strings %08x\n", c, &c->globals, &c->strings);
    }
    
  • Thanks for the bug report, David. I think I've fixed that problem now.
  • ersmith wrote: »
    Thanks for the bug report, David. I think I've fixed that problem now.
    Thanks! That gets me past that problem. Now on to the next one! :smile:
  • 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.
  • ersmith wrote: »
    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!

  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-25 04:02
    I'm getting some strange behavior from this code:
                    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.

    Thanks,
    Eric
  • ersmith wrote: »
    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.

  • David Betz wrote: »
    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.

  • ersmith wrote: »
    David Betz wrote: »
    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.
  • David BetzDavid Betz Posts: 14,511
    edited 2019-02-25 23:14
    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
    
Sign In or Register to comment.