CSPIN - A C-to-Spin Converter

2

Comments

  • Dave HeinDave Hein Posts: 5,307
    edited April 2011 Vote Up0Vote Down
    Parallax hasn't mentioned PMC since they discussed it on the forum over a year ago. Their conclusion at that time was that they would work on it after they completed the bug fixes and enhancements to the Prop tool. They haven't sent out a new version of the Prop tool, so I would assume that they haven't started working on PMC.

    However, they might surprise us and release a new Prop tool with all the bug fixes and enhancements that everyone's been asking for, and with PMC included. And they may have decided to make PMC ANSI compliant.:)
  • davidsaundersdavidsaunders Posts: 1,556
    edited April 2011 Vote Up0Vote Down
    Humanoido wrote:
    Unfortunately, the lack of a front end interface has restricted the use of these languages to only a few people who still remember how to use the old DOS command line interface. Using the CLI would be possible if someone was able to provide exact instructions. So far, I don't see that. Also, using a CLI is not easy
    There is nothing easier than using a CLI, once you learn to use them. The difficulty is that a lot of people do not take the time to learn to use the CLI for there OS. I very often use CMD.EXE (Windows), COMMAND.COM (DOS), command.prg (Atari TOS), Amiga Shell (Amiga OS, AROS), bash (unixins, Haiku OS), to great effect, especially for compilers and file utils. I understand and agree with the advantage of a GUI for most other apps (including editors).
    PASM The simplest programming language for the propeller.
    Low Power for everything, max average whole house draw for a day is 2.4KW/hour total:
    That is 400 watts per hour to produce for the 6 good power hours (minimum in late December/early January) from solar, now how to use less.
  • Heater.Heater. Posts: 19,813
    edited April 2011 Vote Up0Vote Down
    Humanoido,
    Also, using a CLI is not easy

    Using a DOS box is Windows is tough.
    A typical command shell in Unix/Linux is actually useful.
    Yes, it takes a bit of trouble and time to make the best of it. The BASH shell for example has enough features that I might never learn them all.
    But, like learning to read and write, once you have the hang of it it's much easier for many tasks than poking at pictures.

    I've just been fighting with the Eclipse IDE for a certain micro-controller. I swear building programs for that chip is easier from the command line than struggling with Eclipse.

    On the other hand, the Prop Tool and BST IDE's are dead easy to use for the limited things they can do.
  • Dave HeinDave Hein Posts: 5,307
    edited May 2011 Vote Up0Vote Down
    Here's the latest version of cspin. It fixes a couple of problems with the increment portion of for loops, and it fixes a problem dereferencing pointers to struct pointers (i.e. struct **). It also handles the "~" binary complement operator, which I had failed to support previously.
  • Dr_AculaDr_Acula Posts: 5,482
    edited September 2011 Vote Up0Vote Down
    This is a fascinating little thread.

    Over on another thread we have been brainstorming running C on a cog and there were some discussions on using other languages.

    I wonder if cspin could be combined with this online tool to convert C to Basic and vice versa http://www.developerfusion.com/tools/convert/vb-to-csharp/

    I know that is vb.net and C# with all the complexities, but it can also handle super simple C and Basic syntax too. Binary numbers can be written as something like
    const long c = Convert.ToInt32("1100101", 2);

    Could the cspin convert that to spin?

    If you can convert spin to c to basic then if one considers a compiler to cog code, only one needs to be written. (whether it is spin to pasm, c to pasm or basic to pasm).

    addit - I see Dave has been contributing to that other thread while I have been writing on this one.

    I was quite excited to find this thread as it is another tool in the toolbox and if we combine all the tools we have we can do some cool things. I've been intrigued by the idea of 'simple spin to pasm' which produces a compiled version of spin, which ought to run faster than an interpreted version.
    Answers: 1) A quadcopter. 2) Very high. 3) The internet. 4) A lot. 5) No.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,322
    edited December 2013 Vote Up0Vote Down
    In the C program being converted to Spin, how do you reference methods in an external Spin object? I can't seem to figure out to to get cspin to declare something in an OBJ section.

    Thanks,
    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Dave HeinDave Hein Posts: 5,307
    edited December 2013 Vote Up0Vote Down
    Yes, that's a deficiency in cspin. I include Spin code bracketed by comment lines starting with "/*SPIN" and "SPIN*/", and then use sed to remove the comments from the generated Spin files. If you specify the -m option it will add lines for the top object, which include a reference to the clib object.

    To reference a method in another object I use something like i2c_ReadByte, and then use sed to change "i2c_" to "i2c.". It would fairly easy to make cspin do this automatically.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,322
    edited December 2013 Vote Up0Vote Down
    That illustrates one of the problems with C that Spin makes easy. The inclusion of header files might appear to make C modular, but in reality it's monolithic, since the inclusion is just a cut-and-paste operation. Consequently, I would be in favor of compromising the C syntax just a little with an include of the form:
    #include "float.spin" as fp
    

    Then the public methods in float.spin could be called using your syntax as:
    a = fp_fmul(x, 8.123)
    

    which gets translated to:
    OBJ
    
      fp : "float"
    
    PUB main
    
      a := fp.fmul(x, 8.123)
    

    In contrast with real C, this treats float.spin as a separate namespace, masqueraded by the fp_ prefix to make its method names look unique.

    Granted, the as addendum could be omitted, but that would entail referring to objects by their full file name every time, which wouldn't work anyway, since some might have embedded spaces.

    But how much does this compromise the learning experience if the objective is to teach C? That's a real conundrum.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • ersmithersmith Posts: 2,082
    edited December 2013 Vote Up0Vote Down
    Using C++ objects for Spin objects would make this easier, perhaps, although trying to do a complete C++ to Spin translation would be a pain. A subset of C++ would probably work though.

    Of course the other alternative is to go the other way and convert Spin to C++.
  • Dave HeinDave Hein Posts: 5,307
    edited December 2013 Vote Up0Vote Down
    Phil, I like your suggestions, except that I want to stay within standard C. So instead of "#include "float.spin" as fp" I would prefer something like "#include "float.h" //as fp". The comment "//as fp" in an include directive could tell cspin to generate an OBJ entry, and to convert all occurrences of "fp_" to "fp.". I'll look into it.

    BTW, it has always been on my TODO list to automatically handle floating point expressions by automatically generating the floating point method calls. However, that would require parsing expressions, which I currently don't do.

    Eric, it would be cleaner for cspin to handle a subset of C++ so that there would be a 1:1 conversion between objects. I'm not very conversant in C++, so I'm a little leery about tackling that. And yes, spin2cpp is an excellent way to integrate C and Spin code, but sometimes it's more convenient to convert C to Spin. I've used cspin quite a bit for converting C programs to run as Spin programs under spinix.
  • trodosstrodoss Posts: 577
    edited January 2014 Vote Up0Vote Down
    Dave,
    I had a chance to try the latest code and it seems to work well.
    Would you be willing to share the code for CSPIN, or do you have plans for making it a bigger project (one where others could help contribute)?
  • Dave HeinDave Hein Posts: 5,307
    edited January 2014 Vote Up0Vote Down
    Yes, I'll post the source code after I've written up some documentation on how it works.
  • David BetzDavid Betz Posts: 11,517
    edited January 2014 Vote Up0Vote Down
    Dave Hein wrote: »
    And yes, spin2cpp is an excellent way to integrate C and Spin code, but sometimes it's more convenient to convert C to Spin. I've used cspin quite a bit for converting C programs to run as Spin programs under spinix.
    Doesn't spinix just load .binary files? Is there any reason you can't just compile your C programs with propgcc and convert them to binary for use with spinix?
  • Dave HeinDave Hein Posts: 5,307
    edited January 2014 Vote Up0Vote Down
    The previous versions of spinix would allow for multiple programs to run at the same time. It did this by allocating some memory, and then relocating the binary executable to a starting address other than zero. This can't be done with C programs, so spinix could run only one C program starting at 0, along with Spin programs starting at non-zero addresses.

    The other issue is that spinix passes command-line parameters through ARGC and ARGV, and also patches the exit routine to return control back to the shell. This works with LMM C programs, but not with CMM programs.

    The latest version of spinix no longer has a resident kernel, and it only runs one program at a time. So the relocatable issue no longer exists. but the issue with CMM programs is still there. So Spin code could be converted to LMM C as long as the executable fits in hub RAM.
  • David BetzDavid Betz Posts: 11,517
    edited January 2014 Vote Up0Vote Down
    Dave Hein wrote: »
    The previous versions of spinix would allow for multiple programs to run at the same time. It did this by allocating some memory, and then relocating the binary executable to a starting address other than zero. This can't be done with C programs, so spinix could run only one C program starting at 0, along with Spin programs starting at non-zero addresses.

    The other issue is that spinix passes command-line parameters through ARGC and ARGV, and also patches the exit routine to return control back to the shell. This works with LMM C programs, but not with CMM programs.

    The latest version of spinix no longer has a resident kernel, and it only runs one program at a time. So the relocatable issue no longer exists. but the issue with CMM programs is still there. So Spin code could be converted to LMM C as long as the executable fits in hub RAM.
    Why can't you patch CMM programs?

    Also, how do you patch Spin programs to run from a different address? That sounds like it might make it pretty easy for me to allow Spin programs to be run from xbasic programs.
  • Dave HeinDave Hein Posts: 5,307
    edited January 2014 Vote Up0Vote Down
    LMM programs provide hooks to set the initial stack address, define an ARGV list and specify an exit routine. CMM doesn't allow for this. However, it would be possible by linking in a different startup routine. I just haven't bothered trying to figure out how to do this.

    Relocating a Spin program just requires adding the offset address to the 5 Spin state variables in the Spin header. The 5 state variables are PBASE, VBASE, DBASE, PCURR and DCURR. These are located in the last 5 words of the 16-byte header at the beginning of a Spin binary file.
  • jazzedjazzed Posts: 11,803
    edited January 2014 Vote Up0Vote Down
    Dave Hein wrote: »
    Relocating a Spin program just requires adding the offset address to the 5 Spin state variables in the Spin header. The 5 state variables are PBASE, VBASE, DBASE, PCURR and DCURR. These are located in the last 5 words of the 16-byte header at the beginning of a Spin binary file.

    Yes. This is why it would be fairly trivial to include spin byte-code programs into another language ... as long as the spin doesn't try doing too much with fixed addresses. Being able to do bounds checking would help of course.
  • David BetzDavid Betz Posts: 11,517
    edited January 2014 Vote Up0Vote Down
    Dave Hein wrote: »
    LMM programs provide hooks to set the initial stack address, define an ARGV list and specify an exit routine. CMM doesn't allow for this. However, it would be possible by linking in a different startup routine. I just haven't bothered trying to figure out how to do this.
    Have you asked Eric about this? He might be willing to modify the CMM kernel to be compatible with the LMM kernel.
    Relocating a Spin program just requires adding the offset address to the 5 Spin state variables in the Spin header. The 5 state variables are PBASE, VBASE, DBASE, PCURR and DCURR. These are located in the last 5 words of the 16-byte header at the beginning of a Spin binary file.
    Thanks! I'll have to try playing with that.
  • trodosstrodoss Posts: 577
    edited February 2014 Vote Up0Vote Down
    Dave Hein wrote: »
    Yes, I'll post the source code after I've written up some documentation on how it works.

    Hi Dave,

    Didn't know if you have had time to look at this or not but thought I would check.

    Thanks!
  • Dave HeinDave Hein Posts: 5,307
    edited February 2014 Vote Up0Vote Down
    Here's the source for version 0.68. It contains a couple of enhancements that allow embedding inline Spin code and declare Spin objects. Inline Spin is entered by using the keywords "INLINE SPIN" within C comments. Spin objects are defined by using the following syntax:

    // SPIN OBJECT prefix : "SpinFileName"

    Any function reference that starts with "prefix_" will be converted to "prefix.".

    Cspin is built under Cygwin or Linux by running the buildit.sh script. Look at the readme.txt file for more information.
  • Dave HeinDave Hein Posts: 5,307
    edited February 2014 Vote Up0Vote Down
    I forgot to mention that the SPIN OBJECT directive works along with function prototypes to determine which functions need the object prefix. Any function prototype that follows the SPIN OBJECT directive will be prepended with "prefix.". The SPIN OBJECT directive is cancelled by not including an object specification. The prefix_ construct is only needed for functions that may have a conflicting name, such as the start and stop method names that are used in Spin objects. Here's an example of how the SPIN OBJECT directive is used:
    // SPIN OBJECT ser : "cserial"
    int ser_kbhit(void);
    
    // SPIN OBJECT i2c : "Basic_I2C_Driver"
    int ReadLong();
    int WriteLong();
    int WriteWait();
    int Initialize();
    
    // SPIN OBJECT
    void SomethingWrong(char *str);
    void AddEquate(char *ptr1, char *ptr2);
    int Match(char *ptr1, char *ptr2);
    char *GetNextItem(char *ptr);
    
    In this example ser_kbhit was used because kbhit is defined locally in the file. It will be converted to ser.kbhit. ReadLong, WriteLong, WriteWait and Initialize will be prepended with "i2c.". The functions SomethingWrong, AddEquate, Match and GetNextItem are local to the file, and do not require an object prefix.

    The SPIN OBJECT directive can be used with a header file that contains function prototypes as follows:
    // SPIN OBJECT subs : "my_subs"
    #include "my_subs.h"
    
  • trodosstrodoss Posts: 577
    edited February 2014 Vote Up0Vote Down
    Dave,
    Thanks for posting the code! the "INLINE SPIN" directive in comments looks like it will be very useful as well.
  • Dave HeinDave Hein Posts: 5,307
    edited May 2014 Vote Up0Vote Down
    Here is version 0.80 of cspin. This version contains the following changes:

    - Added support for function pointers
    - Increased supported array dimensions from 1 to 10
    - Implemented conditional assignment using (cond ? expr1 : expr2 )
    - Improved the #if directive to handle expressions
    - Added the "-w#" option to control insertion of whitespace
    - Fixed the handling of array initialization
    - Fixed the formating of opening parens and unary negation
    - Fixed a problem with parsing within comments
    - Fixed a problem with getting the pointer of a struct array element
    - Added the C library functions tolower, toupper, rand, srand, sleep and usleep

    cspin can be built under cygwin or linux by running the buildit.sh script file. The source for cspin is located in the src directory, and the clib Spin objects used by the generated code are located in the clib directory. clibsd.spin supports SD file I/O, and clib.spin is the original clib object without SD support.
  • jazzedjazzed Posts: 11,803
    edited May 2014 Vote Up0Vote Down
    Thanks Dave.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,322
    edited May 2014 Vote Up0Vote Down
    This is shaping up nicely, Dave. If CSPIN is compiled under Cygwin, does it also have to run under Cygwin, or can a Windows-compatible .exe be created?

    Thanks,
    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • jazzedjazzed Posts: 11,803
    edited May 2014 Vote Up0Vote Down
    Would be better if it's possible build and run with mingw/msys because there are zero strings attached in that environment.

    I'm getting crashes at the moment though.
  • Dave HeinDave Hein Posts: 5,307
    edited May 2014 Vote Up0Vote Down
    In earlier versions I built cspin with the watcom compiler, and distributed the executable. I haven't used the watcom compiler for a while, but I can try building with it again. I've never used mingw, so that I would need to load it onto my system to try it.
  • Dave HeinDave Hein Posts: 5,307
    edited May 2014 Vote Up0Vote Down
    I've attached a Windows executable file in cspin_exe.zip. I built it using the Watcom compiler, so it doesn't require any extra DLLs like the cygwin version does. I did have to disable the "dir" command that is used in the interactive mode. I'll look into this some more to figure out how to do directory listings in Watcom C.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,322
    edited May 2014 Vote Up0Vote Down
    Thanks, Dave!

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • AntoineDoinelAntoineDoinel Posts: 280
    edited May 2014 Vote Up0Vote Down
    I suppose self-compiling is out of question... well, actually I tried, but got too many circular references for mutually included objects. :frown: But I don't think it was going to be small enough to leave enough free memory anyway.

    However it compiles (and works) using propgcc xmm-single. I get 210KB with -Os. :smile:

    Unfortunately there is no tool yet for xmm to launch anything but autorun.pex, so it have to be started by propeller-load.

    Great work Dave, thanks.
Sign In or Register to comment.