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.
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.
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?
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.
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.
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.
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.
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:
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.
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.
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.
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.
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 ?
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'.
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.
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
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
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.
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 ...)".
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.
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.propgfx.co.uk/forum/·home of the PropGFX Lite
·
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.
What I was talking about was slightly different, as the top object never has an OBJ to begin with.
eg.
ie, there's no way to access topobject functions ?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.propgfx.co.uk/forum/·home of the PropGFX Lite
·
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.
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?
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
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
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
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.
If 0.21 works, let's delete 0.21x and never mention it again.
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:
All the necessary files are attached. The .binary file is from the Propeller Tool.
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.
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
Post Edited (Cluso99) : 10/12/2008 9:30:48 AM GMT
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.
What are your thoughts about supporting hex numbers this format 0x00, 0x0000 etc etc?
Praxis
What are *your* thoughts?
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 ?
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!
All languages are trying in some circumstances to merge the syntax, and anything to help is an improvement.
I can't say I blame it - I can barely parse this line myself (66)
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
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>
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pull my finger!
Post Edited (BradC) : 10/26/2008 9:12:24 AM GMT
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.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pull my finger!
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.
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 ...)".
·
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!