Shop Learn P1 Docs P2 Docs
Homespun Spin compiler 0.31: Now open source - Page 8 — Parallax Forums

Homespun Spin compiler 0.31: Now open source

168101112

Comments

  • BaggersBaggers Posts: 3,018
    edited 2008-10-11 09:56
    mpark, cool feature, also is there any way to add access to a function in the Top object from a child object? [noparse]:D[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-11 14:49
    Baggers,
    That's one of the things this does. mpark showed a 3 level program so you could see how the pointers are passed upwards from the middle to the top and from the middle to the bottom. In your case, you would just have a middle and bottom object.

    mpark,
    Thank you. Thank you. Your compiler along with BradC's IDE allows me to do native development on my MacBook.
  • BaggersBaggers Posts: 3,018
    edited 2008-10-11 15:33
    Mike,
    What I was talking about was slightly different, as the top object never has an OBJ to begin with.
    eg.

    'topobject spin
    con
    _clkmode = xtal1+pll16x
    _xinfreq = 6_000_000
    obj
      nextobj : "nextobj"
    pub main
      repeat 
        nextobj.function
    
    pub routine_in_top_spin
      'do something
    

    'nextobj spin
    
    pub function
      'do stuff
      topobject.routine_in_top_spin
      'do other stuff
    


    ie, there's no way to access topobject functions ?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-11 15:54
    No, there's no way to access the main object from child objects.

    I suppose it would be possible to define a special pseudofunction (like CLKFREQ) that would return the pointer to the topmost object. It's kind of like a GOTO. People rail against languages (like Spin) that don't have it, unhappy with having to rework their logic to use the existing control structures, complaining that there are things they need that they can't do without a GOTO. Truthfully, there are things that are hard to do without GOTOs, but, when they're added, people write the most awful code using GOTOs where they're not needed and making things hard to understand and hard to debug.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-11 16:06
    mpark,
    I'm still having problems with the -L option in MacOS. I've tried "-b -L \Applications\MonoApps\PropLib\ PodiumTest.spin" and "-b -L /Applications/MonoApps/PropLib/ PodiumTest.spin" with the current directory set to the directory with PodiumTest.spin in it. In both cases, I get a message that there's no source file name supplied. I checked carefully that there's a space before the PodiumTest.spin and after the -L. Any suggestions?
  • hippyhippy Posts: 1,981
    edited 2008-10-11 16:12
    As this allows pointers to objects which can then be passed around, it would be possible to move everything down a level so the top object is really just an umbrella object. It may not be that hard to create some name ( "self" or "this" ? ) which refers to the current object and pass that from the top.

    I'm intrigued as to how this is implemented and works. That's not to say it doesn't but the problem I foresaw was adjusting the interpreter's 'vBase' ( pointer to base of global vars for current object ) when entering a called object.

    We have access from bytecode to adjust vBase directly which a compiler can generate and support methods can be created by the compiler behind the scenes so it does look entirely possible to do.

    Added : If objects are static ( which they all are ) it's even easier to do ...

    An "x=top.method(y)" call is no different to any other call to a sub-object. They key is in the method jump table entry in the object which makes the call. It would be the same as any other entry but would need a value used to adjust vBase to be correct for the top object vars rather than for a sub-object vars and that should be easy enough to do - normally the adjustment is a positive 16-bit value, simply make it 16-bit negative and rely on wrap-round.

    To allow entirely dynamic object pointers and calls is really just an exercise in updating the method jump table at run-time to point to the correct object and adjust vBase. I never went beyond the theory of that though.

    Post Edited (hippy) : 10/11/2008 4:47:57 PM GMT
  • mparkmpark Posts: 1,266
    edited 2008-10-11 17:52
    Mike,

    Please try the attached special build of Homespun. It'll print out exactly what Homespun thinks its arguments are, like so:
    args[noparse][[/noparse]0] = -b
    args[noparse][[/noparse]1] = -L
    args[noparse][[/noparse]2] ...

    Please copy its output into a reply here and hopefully·I can start to·figure out where I've gone wrong.


    m


    Edit: removed attachment, as Mike has resolved his problem.

    Post Edited (mpark) : 10/12/2008 2:07:23 AM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-11 18:01
    Well, now it works. Go figure! I get:

    Homespun Spin Compiler 0.21x
    args[noparse][[/noparse] 0 ] = -b
    args[noparse][[/noparse] 1 ] = -L
    args[noparse][[/noparse] 2 ] = /Applications/MonoApps/PropLib/
    args[noparse][[/noparse] 3 ] = PodiumTest.spin
    parsing PodiumTest.spin
    parsing /Applications/MonoApps/PropLib/TV_Text.spin
    parsing /Applications/MonoApps/PropLib/tv.spin
    compiling PodiumTest.spin
    compiling /Applications/MonoApps/PropLib/TV_Text.spin
    compiling /Applications/MonoApps/PropLib/tv.spin
    writing PodiumTest.binary
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-11 18:20
    For those that are interested, attached are the scripts that I'm using. There's a free editor for the Mac called TextWrangler from Bare Bones Software (www.barebones.com) that provides for both MacOS scripts and Unix scripts. The "Compile Spin" script goes in TextWrangler's Scripts folder and calls mpark's Spin compiler using Mono. The two "Download" scripts go in TextWrangler's Unix Scripts folder and download a binary file to an attached Propeller's RAM or EEPROM depending on the script. These require Python (included with MacOS) and an open source package called "Cocoa Dialog" (cocoadialog.sourceforge.net/index.html).

    The Compile Script requires that the compiler be at "/Applications/MonoApps" and be called "homespun.exe". The basic library should be in a folder called "PropLib" in "/Applications/MonoApps". I happen to have the Prop Tool installed under Windows and just copied over the installed Spin library from that.

    If you want something different, feel free to modify the scripts.
  • mparkmpark Posts: 1,266
    edited 2008-10-11 23:59
    Have you tried again with 0.21? It should work (the only difference between 0.21 and 0.21x is the echoing of arguments), but one never knows.
    If 0.21 works, let's delete 0.21x and never mention it again.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-12 01:08
    Yes, 0.21 seems to work. It could have been something I had done with my script. I certainly won't divulge 0.21x. Thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2008-10-12 04:09
    mpark,
    I was putting together a modified version of DongleBasic for a special project and got an error message during compilation. The Propeller Tool compiles this just fine. The error messages were:
    
    Homespun Spin Compiler 0.21
    parsing PodiumBasic.spin
    parsing BB_definitions.spin
    parsing BB_i2cSpiInit.spin
    parsing BB_massStorage.spin
    parsing BB_i2cSpiLdr.spin
    parsing BB_FullDuplexSerial.spin
    Error: PodiumBasic.spin (656,21): no Nud
      if spaces <> "="
                      ^
    
    


    All the necessary files are attached. The .binary file is from the Propeller Tool.
  • mparkmpark Posts: 1,266
    edited 2008-10-12 06:38
    Version 0.22 in first post.

    Mike, thanks for the bug report. I also discovered a bug in the command line parsing. I don't know if it was related to your previous problem, but I wouldn't be surprised. Anyhoo, 0.22 corrects both bugs. Who knows what new bugs I've introduced.
  • Cluso99Cluso99 Posts: 18,063
    edited 2008-10-12 09:20
    Michael,

    Just tried v0.22 and note that under Vista is stopped working bringing up a Vista screen saying the program was not responding. I had entered "homespun022 /?". Same happens with "homespun022 ?". Yes I forgot you removed the "/" and needed to use "-?".

    The dump (listing) is fantastic. Is it possible to include the comment only source lines?

    Homespun compiles and executes my debugger and ram interpreters correctly. I have not tried the new features such as #ifdefine but they are exactly what I am looking for, so just·waiting for·the IDE. I hate commandline usage.

    I was looking to see if you had any #include filename option. The PropTool is too restrictive. In my opinion, an include just includes whatever it finds in the file, no restrictions or checking. Then the compiler will do it's job. This allows routines, text (alternate languages) etc, to be placed in an external file. The file may be included more than once. Do you have anything like this?

    Macro's would be a great addition later.·Only simple to allow for the things required in LMM such as jumps.

    Great work,
    Ray smile.gifsmile.gif

    Post Edited (Cluso99) : 10/12/2008 9:30:48 AM GMT
  • mparkmpark Posts: 1,266
    edited 2008-10-12 23:24
    Hmmm, I suppose I should do more error-checking, but I'm so lazy! I stopped using "/" for options because some OSes use "/" in paths; conceivably, "/?" might mean something on some computer. Just making excuses now.

    I doubt I'll be making any significant changes to the listing, I'm afraid. I'll keep your request in mind, but see "I'm so lazy!" above. I think of it as a memory dump with some annotations, rather than a listing with memory contents, if you see what I mean. So I only keep track of source code that has an effect on memory.

    #include would be nice. Unfortunately the way I did things makes #include difficult. When the inevitable rewrite comes, I'll be sure to make provisions for including files.

    Meanwhile, you could petition Praxis to incorporate a preprocessor like Ariba's PreSpin in his IDE.
  • PraxisPraxis Posts: 333
    edited 2008-10-23 15:42
    Hi mpark,

    What are your thoughts about supporting hex numbers this format 0x00, 0x0000 etc etc?

    Praxis
  • mparkmpark Posts: 1,266
    edited 2008-10-23 15:59
    For input? I hadn't given it any thought. "0x" feels out of place with the non-alpha prefixes ($, %, %%), so my first thought would be to leave things alone.

    What are *your* thoughts?
  • hippyhippy Posts: 1,981
    edited 2008-10-23 16:27
    My thoughts for all compilers is that they should accept all common non-decimal number syntaxes, so $AB, 0xAB, &hAB, h'AB' ( 0ABh is debatable ), for binary, %101, 0b101, &b101, b'101', for nibbles, %%123, 0q123, &q123, q'123'.

    I reject C's notion that a leading zero indicates an octal number; urgh, horrible.

    My belief is that programmers should be free to use whatever they are familiar with or want to use providing it doesn't conflict with the core language. It's a pain moving between languages ( Spin, C, VB ) and having to remember which syntax it should be today. Maybe not a big pain, but why have any when it's so easy to avoid ?
  • PraxisPraxis Posts: 333
    edited 2008-10-23 16:39
    hippy pretty much summed up my thoughts[noparse]:)[/noparse]
  • mparkmpark Posts: 1,266
    edited 2008-10-23 17:41
    I reject the notion that any of those q-notations is a common non-decimal number syntax!

    Also, the examples with & mean something completely different in C/C++, so reinterpreting them as numbers will likely cause more confusion.

    But I must confess that I find myself trying to use 0x in Spin and $ in C#, so I'm not entirely unsympathetic!
  • PraxisPraxis Posts: 333
    edited 2008-10-23 17:48
    Same here with the 0x into spin, years of habit I guess.
  • Cluso99Cluso99 Posts: 18,063
    edited 2008-10-24 03:33
    I am with you hippy, especially 0x and $.

    All languages are trying in some circumstances to merge the syntax, and anything to help is an improvement.
  • agodwinagodwin Posts: 72
    edited 2008-10-25 15:52
    I have a bug that's probably a bad pointer, and wanted to know memory locations of things, so I stuck my code through Homespun. It was mostly fine, but choked on the library object Numbers (from the Proptool suite - called by Stack Length).
    I can't say I blame it - I can barely parse this line myself (66)

          if not Val := IChar and (Char == IChar)
    
    



    but presumably it's valid Spin.

    Like others here, I'm pretty impressed overall by Homespun and might move to it as a main tool (I've been longing to ditch the IDE and get back to makefiles and Linux) but I'll add a wishlist item .. could you print a call tree, please, and count the stack usage as you go down it ? I'd really like a more scientific method of choosing stack than 'tighten until it breaks than back off half a turn'.

    Cheers,

    -adrian
  • mparkmpark Posts: 1,266
    edited 2008-10-25 22:16
    That's weird. The crux of the problem can be reduced to "NOT val := IChar". Proptool parses it as "NOT (val := IChar)", but according to the operator precedence table in the manual, "NOT" has higher precedence than ":=", so it should parse as "(NOT val) := IChar" (which doesn't make sense, and that's why Homespun complains).

    As a check, the "AND" operator has lower precedence than "NOT", and "NOT val AND IChar" is parsed as "(NOT val) AND IChar", as I would expect.

    So in summary, I'm baffled. Hopefully Brad or someone can set me straight.
  • BradCBradC Posts: 2,601
    edited 2008-10-26 02:15
    mpark said...
    That's weird. The crux of the problem can be reduced to "NOT val := IChar". Proptool parses it as "NOT (val := IChar)", but according to the operator precedence table in the manual, "NOT" has higher precedence than ":=", so it should parse as "(NOT val) := IChar" (which doesn't make sense, and that's why Homespun complains).

    As a check, the "AND" operator has lower precedence than "NOT", and "NOT val AND IChar" is parsed as "(NOT val) AND IChar", as I would expect.

    So in summary, I'm baffled. Hopefully Brad or someone can set me straight.

    bstc compiles it ok.

    Having a look at the parser code, I recall having to special case assignment and unary operators with regard to their treatment of precedence.
    I ended up writing 3 different math parser algorithms until I got it to behave the same as proptool. There were a *lot* of corner cases to do with unary operators.

    Something like
    X := ! - - - || NOT 23 + - - 6 // ^^ 4
    caused me massive headaches (and not just to look at!).

    <edit>
    Ok, I've been back through the code and noticed that I don't pop the operator stack for a unary operator, precedence or no. I seem to remember having to do this to cope with some oddity of the NOT operator, so that's probably it.
    </edit>

    65                            if not Val := IChar and (Char == IChar)                                                          
     '  look for indicator character (if required)
    Addr : 00DC:          CC 24  : Memory Op Long DBASE + READ Address = 0024
    Addr : 00DE:             78  : Variable Operation Local Offset - 6 Read
    Addr : 00DF:          CC 24  : Memory Op Long DBASE + READ Address = 0024
    Addr : 00E1:             FC  : Math Op ==    
    Addr : 00E2:             F0  : Math Op AND   
    Addr : 00E3:          76 80  : Variable Operation Local Offset - 5 Assign Write Push
    Addr : 00E5:             FF  : Math Op NOT   
    Addr : 00E6: JZ Label000C
    Addr : 00E6:          0A 05  : jz Address = 00ED 5
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pull my finger!

    Post Edited (BradC) : 10/26/2008 9:12:24 AM GMT
  • agodwinagodwin Posts: 72
    edited 2008-10-26 09:36
    Or maybe it was a typo for 'ifnot', which should be parsed as
       if not ((Val := IChar) and (Char == IChar))
    
    
  • BradCBradC Posts: 2,601
    edited 2008-10-26 10:01
    agodwin said...
    Or maybe it was a typo for 'ifnot', which should be parsed as
       if not ((Val := IChar) and (Char == IChar))
    
    


    Not sure it really matters a great deal, but given it's in Parallax library code and therefore likely well tested I suspect it's what was intended.
    Here are three variants for you to compare should you wish to.

    4                        If Not Val := IChar And (IChar == Char)
    Addr : 0018:             40  : Variable Operation Global Offset - 0 Read
    Addr : 0019:             40  : Variable Operation Global Offset - 0 Read
    Addr : 001A:             68  : Variable Operation Local Offset - 2 Read
    Addr : 001B:             FC  : Math Op ==    
    Addr : 001C:             F0  : Math Op AND   
    Addr : 001D:          66 80  : Variable Operation Local Offset - 1 Assign Write Push
    Addr : 001F:             FF  : Math Op NOT   
    Addr : 0020: JZ Label0002
    Addr : 0020:          0A 00  : jz Address = 0022 0
    Addr : 0022: Label0002
    Addr : 0022: Label0003
    5                        If Not ((Val := IChar) and (IChar == Char))
    Addr : 0022:             40  : Variable Operation Global Offset - 0 Read
    Addr : 0023:          66 80  : Variable Operation Local Offset - 1 Assign Write Push
    Addr : 0025:             40  : Variable Operation Global Offset - 0 Read
    Addr : 0026:             68  : Variable Operation Local Offset - 2 Read
    Addr : 0027:             FC  : Math Op ==    
    Addr : 0028:             F0  : Math Op AND   
    Addr : 0029:             FF  : Math Op NOT   
    Addr : 002A: JZ Label0004
    Addr : 002A:          0A 00  : jz Address = 002C 0
    Addr : 002C: Label0004
    Addr : 002C: Label0005
    6                        ifnot Val := IChar and (IChar == Char)
    Addr : 002C:             40  : Variable Operation Global Offset - 0 Read
    Addr : 002D:             40  : Variable Operation Global Offset - 0 Read
    Addr : 002E:             68  : Variable Operation Local Offset - 2 Read
    Addr : 002F:             FC  : Math Op ==    
    Addr : 0030:             F0  : Math Op AND   
    Addr : 0031:          66 80  : Variable Operation Local Offset - 1 Assign Write Push
    Addr : 0033: JNZ Label0006
    Addr : 0033:          0B 00  : jnz Address = 0035 0
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pull my finger!
  • agodwinagodwin Posts: 72
    edited 2008-10-26 11:44
    Looking at the Numbers code, I think it should be doing

    
     'found a character that's not a valid digit, and haven't yet seen $,% etc. 
    
      Val := IChar and (Char == IChar)  'set Val to 1 if Ichar is defined and this is it
    
      if Val == 0                
        N :=  (Char == '-')                         'otherwise,  check for a minus sign                    
    
    
    
    



    which is the first one, or indeed, more efficiently, ifnot. (Whether the test is worthwhile is another question - the assumption would be that if a number has a prefix, it's more common for it to be an indicator than a minus, and the code is a little faster for that case.)

    I'm not sure about the precedence issue : surely if ':=' is the lowest precedence, its argument should be completely evaluated before its operation, which is what the layout above does.
  • mparkmpark Posts: 1,266
    edited 2008-10-26 17:10
    agodwin said...
    I'm not sure about the precedence issue : surely if ':=' is the lowest precedence, its argument should be completely evaluated before its operation, which is what the layout above does.
    If ':=' is lowest precedence, all of its arguments should be evaluated first, left and right sides. That's what happens for any other (non-assignment) operator. In this case, the LHS is "NOT Val", which is not an lvalue. What Proptool is doing is wrong, wrong I tell you! <froth>

    Seriously, unless someone can convince me otherwise, this looks like a bug in the Proptool parser, but I guess it's the de facto "correct" behavior now. I'll have to hold my nose and try to figure out how to duplicate it in Homespun.

    For now, a workaround is to edit the offending line to read "if not (val ...)".

    ·
  • BradCBradC Posts: 2,601
    edited 2008-10-26 17:32
    mpark said...
    If ':=' is lowest precedence, all of its arguments should be evaluated first, left and right sides. That's what happens for any other (non-assignment) operator. In this case, the LHS is "NOT Val", which is not an lvalue. What Proptool is doing is wrong, wrong I tell you! <froth>

    Assignment operators seem to behave differently if they are not being used as the beginning of an expression (as a pure assignment). In this case, being an if statement the result is being left on the stack. It's not being used as an assignment as such, all it's doing is pushing a variable on the stack (albeit by reading one and writing to another).

    ..it could be written as

    Val := IChar
    If Not IChar and (IChar == Char)

    and have precisely the same result (albeit with more code). The end result is still.

    Push IChar == Char
    Push IChar
    and
    not
    if

    You _could_ leave the NOT out and just use IFNOT (it'd be smaller and faster) but both are valid as far as I can see.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Pull my finger!
Sign In or Register to comment.