fastspin C compiler

David BetzDavid Betz Posts: 13,229
edited 2019-02-14 - 02:18:59 in Propeller 2
I just started trying to compile my embedded BASIC interpreter for the P2 and ran into this error when compiling one of the source files:
db_system.h(23) error: syntax error, unexpected identifier `GetLineHandler'

The line in question is the reference to GetLineHandler in the System structure definition below. VMVALUE is just an integer typedef. Am I using a feature that is not yet supported by the fastspin C compiler?
/* line input handler */
typedef int GetLineHandler(void *cookie, char *buf, int len, VMVALUE *pLineNumber);

/* system context */
typedef struct {
    jmp_buf errorTarget;        /* error target */
    GetLineHandler *getLine;    /* function to get a line of input */
    void *getLineCookie;        /* cookie for the getLine function */
    int lineNumber;             /* current line number */
    uint8_t *freeSpace;         /* base of free space */
    uint8_t *freeMark;          /* top of permanently allocated storage */
    uint8_t *freeNext;          /* next free space available */
    uint8_t *freeTop;           /* top of free space */
    char lineBuf[MAXLINE];      /* current input line */
    char *linePtr;              /* pointer to the current character */
} System;
In case you want to try this yourself I've attached the sources. My first attempt at compiling it was using the command:
fastspin -2 -D PROPELLER_GCC *.c
That would eventually generate errors because it is including duplicates of the OS interface functions but I thought it was an easy way to start.
«1345

Comments

  • That's probably a bug in the fastspin parser. The declaration:
    typedef int (*GetLineHandler)(void *cookie, char *buf, int len, VMVALUE *pLineNumber);
    
    does work, and I think it should be equivalent.

    Thanks for the bug report!
  • David BetzDavid Betz Posts: 13,229
    edited 2019-02-14 - 02:36:12
    Thanks! Here is another error:
    db_compiler.h(93) error: syntax error, unexpected type name `Block', expecting identifier or __using or '{'
    
    From this code:
    /* block structure */
    typedef struct Block Block;
    struct Block {
        BlockType type;
        union {
            struct {
                int nxt;
                int end;
            } IfBlock;
            struct {
                int end;
            } ElseBlock;
            struct {
                int nxt;
                int end;
            } ForBlock;
            struct {
                int nxt;
                int end;
            } DoBlock;
        } u;
    };
    
    I'm not sure why I defined it this way since there is no reference to the Block typedef in the structure but I do this elsewhere where there are recursive references.
  • That's the kind of C that makes me want C++ !
    Prop Info and Apps: http://www.rayslogic.com/
  • David BetzDavid Betz Posts: 13,229
    edited 2019-02-14 - 12:47:52
    Rayman wrote: »
    That's the kind of C that makes me want C++ !
    How would C++ be different? I guess you don't need the separate typedef. That's convenient but not that much of an advantage. Anyway, there are some things in C++ that I like but a lot I don't. :smile:

    Edit: Actually, the more I think of it this *is* one of the big advantages of C++. It's a pain having to split a declaration into two pieces and type the structure tag three times. C++ was certainly an improvement here! I could have left out the typedef line entirely.

  • I think even in C you can write
    typedef struct { ... } Block;
    
    and then you won't need a separate typedef line.
    David
    PropWare: C++ HAL (Hardware Abstraction Layer) for PropGCC; Robust build system using CMake; Integrated Simple Library, libpropeller, and libPropelleruino (Arduino port); Instructions for Eclipse and JetBrain's CLion; Example projects; Doxygen documentation
    CI Server: http://david.zemon.name:8111/?guest=1
  • DavidZemon wrote: »
    I think even in C you can write
    typedef struct { ... } Block;
    
    and then you won't need a separate typedef line.
    That only works if you don't reference the type name inside of the structure definition. I often do that for structures like this:
    /* label structure */
    typedef struct Label Label;
    struct Label {
        Label *next;
        int placed;
        int fixups;
        int offset;
        char name[1];
    };
    
    So I sometimes just use that pattern for all structure definitions.

  • Thanks for the bug reports, David. I've fixed those problems in the latest code in github. Unfortunately the ebasic build now hangs because fastspin gets confused by two static functions with the same name in different files. Obviously that should work, and I'm going to try to figure out how to fix it -- but it's not trivial :(.
  • ersmith wrote: »
    Thanks for the bug reports, David. I've fixed those problems in the latest code in github. Unfortunately the ebasic build now hangs because fastspin gets confused by two static functions with the same name in different files. Obviously that should work, and I'm going to try to figure out how to fix it -- but it's not trivial :(.
    Thanks for the fixes! I'll try them tonight when I get home from work. Also, I'll rename one of the duplicate functions. Even though that *should* work, it would probably be better if I didn't use the same name twice.

  • I just tried the new version and got this result:
    Davids-Mac-mini:ebasic3 dbetz$ fastspin -2 -D PROPELLER_GCC *.c
    Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
    Version 3.9.20-beta-7ed0e6c6 Compiled on: Feb 14 2019
    db_compiler.c
    warning: : Preprocessor warnings:
    /Users/dbetz/work/ebasic3/db_compiler.c:1: warning: Converted [CR+LF] to [LF]
        /* db_compiler.c - a simple basic compiler
    
    db_edit.c
    db_expr.c
    db_generate.c
    db_image.c
    db_scan.c
    
    And it hung after that. There are more files in the directory. Any idea why it stopped? The full set of files is:
    db_compiler.c
    db_edit.c
    db_expr.c
    db_generate.c
    db_image.c
    db_scan.c
    db_statement.c
    db_symbols.c
    db_system.c
    db_vmdebug.c
    db_vmint.c
    ebasic.c
    editbuf.c
    osint_propgcc.c
    simple_vsnprintf.c
    
  • I think the hang is the bug I mentioned earlier, that fastspin gets confused by multiple static functions with the same name. In this case the confusion manifests itself as a linked list that ends up pointing to itself.
  • ersmith wrote: »
    I think the hang is the bug I mentioned earlier, that fastspin gets confused by multiple static functions with the same name. In this case the confusion manifests itself as a linked list that ends up pointing to itself.
    Do you recall the names of the static functions that are used in multiple files?

  • David Betz wrote: »
    ersmith wrote: »
    I think the hang is the bug I mentioned earlier, that fastspin gets confused by multiple static functions with the same name. In this case the confusion manifests itself as a linked list that ends up pointing to itself.
    Do you recall the names of the static functions that are used in multiple files?

    NextToken(ParseContext *C) and NextToken(System *sys), I think.
  • ersmith wrote: »
    David Betz wrote: »
    ersmith wrote: »
    I think the hang is the bug I mentioned earlier, that fastspin gets confused by multiple static functions with the same name. In this case the confusion manifests itself as a linked list that ends up pointing to itself.
    Do you recall the names of the static functions that are used in multiple files?

    NextToken(ParseContext *C) and NextToken(System *sys), I think.
    Thanks! I'll rename one of them. I think one is for parsing editor commands and the other for parsing the program. I can't recall why they couldn't both use the same function.

  • I renamed one of my NextToken functions and it no longer hangs when I try to compile ebasic3 but it also gives lots of warnings when I pass literal strings to functions that take char* arguments. I don't get this with any of the other compilers I've been using including GCC. Does the C standard say that literal strings are supposed to be const? It actually makes sense but I haven't seen this warning before so I wonder if the standard leaves out the const attribute.
  • It looks like there may be a problem with pointer arithmetic. Here is code that I think should work but I get an error on the pointer assignment.
    typedef struct {
      int a,b,c;
    } MyStruct;
    
    void test(void)
    {
        MyStruct buf[4];
        MyStruct *p;
        p = buf - 1;
    }
    
  • I compiled the code shown below with GCC. It issued a warning for ptr2, but not for ptr or ptr1. It also issued a warning when writing into a literal string, but it didn't generate an error. The warning was that I was doing an assignment of a read only location. I did get an error from trying to write to ptr1.

    I looked at the assembly, and the compiler puts literal strings in a section called "rdata". So it appears that this is what's causing the warning.
    void main(void)
    {
        char *ptr = "test";
        const char *ptr1 = "test1";
        char *ptr2 = (const char *)"test2";
        "test3"[2] = 0;
        ptr1[2] = 0;
    }
    

  • David Betz wrote: »
    I renamed one of my NextToken functions and it no longer hangs when I try to compile ebasic3 but it also gives lots of warnings when I pass literal strings to functions that take char* arguments. I don't get this with any of the other compilers I've been using including GCC. Does the C standard say that literal strings are supposed to be const? It actually makes sense but I haven't seen this warning before so I wonder if the standard leaves out the const attribute.

    Yes, the C standard does say that string literals are "const", and gcc used to warn about this but i guess so many programs pass literal strings to "char *" that they disabled that warning (even if -Wall is given you still have to explicitly give -Wwrite-strings to get it). I should probably take the same route, or at least provide a compiler option to disable those warnings.

    Note that even without the warning strings really are consts, e.g. the program below will segfault on Linux when compiled with gcc or clang:
    #include <stdio.h>
    
    void printit(char *msg)
    {
        msg[0] = 'j';  // causes a segmentation fault
        printf("message=%s\n", msg);
    }
    
    int main()
    {
        printit("hello, world");
        return 0;
    }
    

  • ersmith wrote: »
    David Betz wrote: »
    I renamed one of my NextToken functions and it no longer hangs when I try to compile ebasic3 but it also gives lots of warnings when I pass literal strings to functions that take char* arguments. I don't get this with any of the other compilers I've been using including GCC. Does the C standard say that literal strings are supposed to be const? It actually makes sense but I haven't seen this warning before so I wonder if the standard leaves out the const attribute.

    Yes, the C standard does say that string literals are "const", and gcc used to warn about this but i guess so many programs pass literal strings to "char *" that they disabled that warning (even if -Wall is given you still have to explicitly give -Wwrite-strings to get it). I should probably take the same route, or at least provide a compiler option to disable those warnings.

    Note that even without the warning strings really are consts, e.g. the program below will segfault on Linux when compiled with gcc or clang:
    #include <stdio.h>
    
    void printit(char *msg)
    {
        msg[0] = 'j';  // causes a segmentation fault
        printf("message=%s\n", msg);
    }
    
    int main()
    {
        printit("hello, world");
        return 0;
    }
    
    Hmmm... It's unfortunate that GCC doesn't issue a warning without the explicit compiler option. I've assumed that I can find all questionable code by using -Wall. Are there any other warnings that get skipped with -Wall that you know of?

  • Maybe the const attribute for literal strings was added in a recent revision of the C standard? I found this reference and another as well that I can no longer locate that says string literals are of type char[].

    https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-and-c
  • David Betz wrote: »
    It looks like there may be a problem with pointer arithmetic. Here is code that I think should work but I get an error on the pointer assignment.
    typedef struct {
      int a,b,c;
    } MyStruct;
    
    void test(void)
    {
        MyStruct buf[4];
        MyStruct *p;
        p = buf - 1;
    }
    

    Yes, looks like automatic casting of arrays to pointers is broken. I'll look into it. Thanks for the bug report!
  • David Betz wrote: »
    Maybe the const attribute for literal strings was added in a recent revision of the C standard? I found this reference and another as well that I can no longer locate that says string literals are of type char[].

    https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-and-c

    Huh. I guess my memory is going as I'm getting older :). Well, that makes things easier, I can just get rid of the warning completely. Thanks!
  • ersmith wrote: »
    David Betz wrote: »
    Maybe the const attribute for literal strings was added in a recent revision of the C standard? I found this reference and another as well that I can no longer locate that says string literals are of type char[].

    https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-and-c

    Huh. I guess my memory is going as I'm getting older :). Well, that makes things easier, I can just get rid of the warning completely. Thanks!
    I have mixed feelings about this because it really does make more sense for literal strings to be const. I will probably change my code to reflect that even though it isn't strictly necessary.

  • David Betz wrote: »
    ersmith wrote: »
    David Betz wrote: »
    Maybe the const attribute for literal strings was added in a recent revision of the C standard? I found this reference and another as well that I can no longer locate that says string literals are of type char[].

    https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-and-c

    Huh. I guess my memory is going as I'm getting older :). Well, that makes things easier, I can just get rid of the warning completely. Thanks!
    I have mixed feelings about this because it really does make more sense for literal strings to be const. I will probably change my code to reflect that even though it isn't strictly necessary.
    I just spent some time switching to using "const char[]" as the type for literal strings and ran into what I think might be a bug. If I have the following two statements in my program I don't get an error even though the parameter is const in the prototype but not in the function definition.
    String *AddString(ParseContext *c, const char *value);
    
    String *AddString(ParseContext *c, char *value)
    {
    ...
    }
    
  • Bus error, not segmentation fault, the memory for the string is validly mapped, but write cycle for it is invalid.
  • I'm getting the following error:
    /Users/dbetz/work/ebasic3/bug.c(11) error: Method reference on non-class expression
    
    when trying to compile this code:
    static struct {
      char *name;
      int value;
    } keywords[] = {
    { "foo", 1 },
    { "bar", 2 },
    };
    
    char *test(int i)
    {
        return keywords[1].name;
    }
    
    The odd thing is that the error goes away if I remove "static" from the declaration of the keywords array.

  • I get warnings about signed vs. unsigned comparisons with this code.
    /Users/dbetz/work/ebasic3/bug.c(4) warning: signed/unsigned comparison may not work properly
    
    I don't see that with GCC but I understand why it's happening. Should I really have to cast the result of the sizeof operator when using it like this?
    void main(void)
    {
        int i;
        for (i = 0; i < sizeof(long); ++i)
            ;
    }
    
  • David BetzDavid Betz Posts: 13,229
    edited 2019-02-16 - 18:32:24
    After working around the structure array indexing problem I mentioned above I am now able to compile all of my code without any errors and only a few warnings. However, I'm now at a point where I need more library functions. At the present I'm stopped by the lack of tolower but I'm sure there will be others. I see you've gotten at least some of your library code from dLibs. Can you point me to your source of that code so I can try pulling in more functions?
  • David BetzDavid Betz Posts: 13,229
    edited 2019-02-16 - 18:35:38
    David Betz wrote: »
    After working around the structure array indexing problem I mentioned above I am now able to compile all of my code without any errors and only a few warnings. However, I'm now at a point where I need more library functions. At the present I'm stopped by the lack of tolower but I'm sure there will be others. I see you've gotten at least some of your library code from dLibs. Can you point me to your source of that code so I can try pulling in more functions?
    I added toupper.c and tolower.c from your proplib project as well as limits.h and sys/syslimits.h and modified ctype.h to use the toupper.c and tolower.c source files instead of expecting the definitions to be in ctype.c. I then get a compiler crash building tolower.c. I've attached my current source code.
    fastspin -o ebasic3 -2 -D PROPELLER_GCC ebasic.c db_compiler.c db_edit.c db_expr.c db_generate.c db_image.c db_scan.c db_statement.c db_symbols.c db_system.c db_vmdebug.c db_vmint.c editbuf.c osint_propgcc.c
    Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
    Version 3.9.20 Compiled on: Feb 16 2019
    ebasic.c
    warning: : Preprocessor warnings:
    /Users/dbetz/work/ebasic3/ebasic.c:1: warning: Converted [CR+LF] to [LF]
        #include <stdio.h>
    
    db_compiler.c
    db_edit.c
    db_expr.c
    db_generate.c
    db_image.c
    db_scan.c
    db_statement.c
    db_symbols.c
    db_system.c
    db_vmdebug.c
    db_vmint.c
    editbuf.c
    osint_propgcc.c
    /Users/dbetz/work/ebasic3/db_edit.c(215) warning: different types in arms of ?
    /Users/dbetz/work/ebasic3/db_vmdebug.c(87) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(94) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(102) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(108) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(113) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(120) warning: signed/unsigned comparison may not work properly
    /Users/dbetz/work/ebasic3/db_vmdebug.c(126) warning: signed/unsigned comparison may not work properly
    memcpy.c
    memmove.c
    strcpy.c
    strcmp.c
    strchr.c
    memset.c
    strlen.c
    atoi.c
    ctype.c
    isxdigit.c
    tolower.c
    make: *** [ebasic3] Segmentation fault: 11
    
  • Ummm.... I just did an update from GitHub and now I'm getting lots of internal errors:
    /Users/dbetz/work/ebasic3/ebasic.c(31) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/ebasic.c(31) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/ebasic.c(60) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/ebasic.c(60) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/db_edit.c(215) warning: different types in arms of ?
    /Users/dbetz/work/ebasic3/db_expr.c(481) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/db_expr.c(481) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/db_expr.c(489) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/db_expr.c(489) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/db_expr.c(501) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/db_expr.c(501) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/db_expr.c(509) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/db_expr.c(509) error: Internal error, unable to find function address
    /Users/dbetz/work/ebasic3/db_generate.c(129) error: Internal error expecting function call
    /Users/dbetz/work/ebasic3/db_generate.c(129) error: Internal error, unable to find function address
    
  • David Betz wrote: »
    I get warnings about signed vs. unsigned comparisons with this code.
    /Users/dbetz/work/ebasic3/bug.c(4) warning: signed/unsigned comparison may not work properly
    
    I don't see that with GCC but I understand why it's happening. Should I really have to cast the result of the sizeof operator when using it like this?
    That warning is mostly a reminder to me that I should properly implement signed and unsigned comparison. I haven't dug through the standard yet to see what I'm allowed to get away with; ideally I'd like to have the comparison work "properly" so that -1 < UINT_MAX will return "true", but I'm not sure if the standard permits this or if it requires that the comparison be done in unsigned (in which case we'd get (((unsigned)-1) < UINT_MAX) which is "false").

    For now feel free to comment out that WARNING line in frontends/basiclang.c (another thing I have to get around to, the type checking code is shared between BASIC and C and should go in its own file).

    Thanks,
    Eric
Sign In or Register to comment.