Version 2:
Runtime Download (http://cl.ly/3H3o3o2M1p0I0S2K3W3x)
Videos:
Demo Video - 14 min long (http://www.youtube.com/watch?v=g4a4oHXweL0)
Graphic Bouncing demo (http://www.youtube.com/watch?v=adJQMprjTEI)
Command List- Print(text) - Prints text
- Str$(number) - Turns a number to a string
- Ticks - Gets the amount of ticks since program opened
- Key - Returns the ascii value of the last key pressed or depressed
- LoadImage(Image Name, Identification name) - Loads an image from outside.
- CreateSprite(Identification Name) - Makes a sprite from a loaded image, returns sprite num
- MoveSprite(SpriteNum, X, Y) - Moves a sprite
- SpriteX(SpriteNum) - Gets X position of a sprite
- SpriteY(SpriteNum) - Gets Y position of a sprite
- KeyIsPressed(Ascii Value of Key) - Determines if that key is pressed, returns True or false
- KeyUp - Returns ascii value for the up arrow key
- KeyDown - Returns ascii value for the down arrow key
- KeyLeft - Returns ascii value for the left arrow key
- KeyRight - Returns ascii value for the right arrow key
Mini manual:
Making Variables//Either form can be use
Let x = 1
or
x = 1
Let x$ = "test"
or
x$ = "test"
Variable Equations//+=, -=, *=, and /= are supported
x = x + 5
or
x += 5
Complex Equations//Complex equations are handled with ease.
x = (5 * (3 + 1) / 6 * 18) - 3
If Statement//If statements and nested if statements work well.
If x < 5 Then
x+=1
End If
For Statement//For and nested for statements work.
For i = 1 to 5
x+=1
next
Version 1:
Gan's Runtime Video Demo (http://www.youtube.com/watch?v=qKZPKYQgnSE)
Hey guys, this is my top secret incredibly confidential my-eyes-only project.
Started this last weekend, spent 2 days thinking about it, 1 night dreaming about it, and 2 days making it. Then I procrastinated all week long.
Finally this weekend I got it into a useable state.
Yeah I cloned the Sc language. Mainly cause of people's familiarity with it.
So how about some details of this runtime:
- Supports number and string variables
- Can do complex equations of both strings and numbers. Especially with lots of parenthesis
- Supports if statements that can also do complex equations and compare strings and numbers
- Allows the use of AND and OR in if statements
- Isn't case sensitive. You can write things in all caps if you want
- So far two commands work. STR$(5) which makes "5" and print("test") which outputs text
- If statement clusters work perfectly
How it works:
Three main things. The first is the parser.
It takes the code as a string, separates it into smart keywords, cleans out unnecessary stuff, lowercases the code, then compares each keyword string and attaches an identifier number to it.
Then there's the runtime.
The smart keywords go straight to the runtime that goes line by line running stuff. To detect what it's suppose to do, it looks at the number identifiers. It doesn't use any unreliable slow string comparisons when running code.
Finally, probably the most important part is the solver. When the runtime comes upon something that needs solved, it sends those keywords to the solver. The solver will go through, solve parenthesis, */+-, true/false equations, commands, and anything that gets in it's way. It was the hardest thing to make and is just like a large calculator. It can handle numbers, strings, and variables.
Surprisingly this whole thing isn't very large, is fairly readable, and incredibly versatile. Of course, I think there's a lot optimizations and cleaning I can do. Also there isn't any bug detection. If you aren't a perfect coder then the code's not gonna run. Though I think I can add something that'll tell you which line contains a bug.
Now before you guys get certain thoughts, I just gotta say.
I made this cause I thought it would be fun. At the moment I have no plans.
If you guys want I can open source it or something. Otherwise I'll probably just stick it in some folder until I make something that can make use of it.
So what are your thoughts?
EDIT: Pics!
The project in Xcode 4.
(http://cl.ly/1f2G110s090l3e192d1b/Screen_shot_2011-03-09_at_8.19.46_PM.png)
The coding and output window:
(http://cl.ly/3Z303f2m450H3S0m0T0I/Screen_shot_2011-03-13_at_1.55.12_PM.png)
Complex equations!
(http://cl.ly/0d2K0u3K3C1R0i302M2f/Screen_shot_2011-03-13_at_2.00.05_PM.png)
I'm interested in a speed test. Can you support a ticks function? Just add a bit of code in your variable handler. Then we can run a standardized speed test.
LET x = ticks
FOR i = 1 to 100000
LET q = q + 1
NEXT
PRINT STR$(ticks-x)
Use the latest build of SilverCreator to run the test on your Mac. Do it from a real built program, not the "Run" menu. The standalone runtime is slightly faster (it does not record some information such as line numbers which are used by SC to help you debug). Compile yours as well.
So basically - there are no trees, although the representation in memory for some things is tree-like, it uses recursion to do the heavy lifting. This may be a bottleneck but it was also the easiest to program and understand.
Ah yeah. Before I recoded my solver, it relied solely on recursion. It'd constantly loop through the equation looking for things to solve. Made it incredibly slow. Now the parser takes care of that and there's no recursion in the solver, just a straight shot through.
At first I thought taking out recursion that it'd be quite a bit more complicated and less friendly but, that's not true. It actually is kinda easier, most of everything is chunked together in the parser instead of part in the parser, part in the solver.
Here's a little description of how it works:
User types in:Parser breaks that up into: let, x, =, 1,+,5,-,3,*,2
X is identified as a variable. This line is marked as a variable setting line. Everything after = is identified as the equation.
The parser takes that equation and sticks it into an equation parser. Which looks through and breaks the equation into equation objects:
Eq1 is 3*2
Eq2 is 1+5
Eq3 is Eq2 - Eq1
Then it realizes that the equation is all broken down into tree form and returns Eq3 as the base.
So after the parser, the runtime runs each line of code.
It realizes that the line is setting a variable, it takes the variable and the equation, Eq3, and it calls the solve function of Eq3.
Eq3 is the base so it calls solve on Eq2 and Eq1. Looks like:
Eq3 = Eq2 - Eq1
Eq3 = 6 - Eq1
Eq3 = 6 - 6
Returns 0.
Then the runtime takes the returned 0 and stores it in the variable.
There's no searching for stuff to solve, it just knows what to solve.
@Matt: I gotta say man, I'm pretty impressed. I'm not sure if you're aware of this, but the way you handled the interpreter is in essence the "standard" (and supposedly best) way too do it. At least according to my laymans understanding. Many kudos.
Thanks.
I've worked on it a bit more. So...
New Features- LET is no longer require, can be used but makes no difference.
- +=, -=, *=, and /= have been added.
Here's the download: Gan's Runtime (http://cl.ly/3d210b2m1w3j2j2c3n2y)
Mini manual:
Making Variables//Either form can be use
Let x = 1
or
x = 1
Let x$ = "test"
or
x$ = "test"
Variable Equations//+=, -=, *=, and /= are supported
x = x + 5
or
x += 5
Complex Equations//Complex equations are handled with ease.
x = (5 * (3 + 1) / 6 * 18) - 3
If Statement//If statements and nested if statements work well.
If x < 5 Then
x+=1
End If
For Statement//For and nested for statements work.
For i = 1 to 5
x+=1
next
I'm thinking of adding support for comments, more commands, and rudimentary debugging but I'm not sure. But since I don't have plans for this, I'm really not sure what would be the point.
This is all very interesting.
The talk about trees (and the pseudocode) reminded me of my own script interpreter experiment, which manages nested expressions by rewriting them in a pre-compiler phase:
becomes
PS_EXP1 = 4+5
PS_EXP2 = 3 * PS_EXP1
x = 2/ PS_EXP2
Of course, this isn't very thoughtful, and my interpreter doesn't manage operator precedence.
One interesting script interpreter written by a teenager that I found out about a few months ago is "nscript". It is very well written (very readable and concise) and uses good, well-known algorithms.
Note that it is stack-based, unlike most programming languages discussed here.
Printing the sum of 253 and 561 is written, in nscript, as:
It is hosted at https://github.com/nikki93/nscript
@Matt: can you put the source code of your interpreter on this site so we can look at it ?
@Gan good.
Of course, modern scripting languages are compiled to bytecode, like the SilverCreator of today.
Someone mentioned METAL, a BASIC I like, although people sometimes say it's "old" because the last version dates to 2001.
METAL compiles programs to an internal bytecode system, and outputs bytecode assembly listings using a special option.
This:
x = 1 + 1
if x > 0 then
print x
endif
Gives this:
* 0 < 0> [ 0]: NumTokenAddr 0
* c < 0> [ 1]: NumConst 1.000000
* 18 < 0> [ 2]: NumConst 1.000000
* 24 < 0> [ 3]: AddNum
* 28 < 0> [ 4]: AsnNum
* 2c < 1> [ 5]: NumToken 0
* 38 < 1> [ 6]: NumConst 0.000000
* 44 < 1> [ 7]: LGreaNum
* 48 < 1> [ 8]: BranFalse 4
* 54 < 2> [ 9]: KeyWPS
* 58 < 2> [ 10]: NumToken 0
* 64 < 2> [ 11]: IPAddP3
* 68 < 2> [ 12]: KeyW 1
* 74 < 2> [ 13]: NOP
Clearly, a stack is involved, and it seems everything is floating-point by default.
Also note that METAL has an "accept tokens with space" option. This allows variable names to contain spaces (!), so that the above can be written:
my variable = 1 + 1
if my variable > 0 then
print my variable
endif
Made another little demo. Just of a graphic bouncing around the screen:
Gan's Runtime Bouncing Graphic (http://www.youtube.com/watch?v=adJQMprjTEI)
Here's the code:
StartupLoadImage("guy.png","guy")
guy=CreateSprite("guy")
speed = 60
xvel = speed
yvel = speed
TimerMoveSprite(guy, spritex(guy)+xvel,spritey(guy)+yvel)
If spritex(guy) > 440-45 Then
xvel = -speed
End If
If spritey(guy) > 403-45 Then
yvel = -speed
End If
If spritex(guy) < 0 Then
xvel = speed
End If
If spritey(guy) < 0 Then
yvel = speed
End If
Just realized I forgot to program in an Else for the IF-statements. Also might program an Else-If statement. If it's not too complicated.
Also thinking of arrays. Arrays would be nice. Not quite sure how I'd set it up...
Probably just like variables, to make one:
myArray = NewArray(object1,object2,object3)
Then to get or set:
myArray[1] = 5
or
var1 = myArray[1]
Then to add an object:
AddObject(myArray, myObject)
Then to remove an object:
RemoveObject(myArray, IndexOfObject)
Ideas... ideas.
OK, Twiddle wasn't accurate enough. I needed to pass a string (script location) and a graphics object (always Nil unless we're in the Paint event). Even with these, and the manipulation of the string in Twiddle the increase in time is inconsequential.
But now here's the big news. If I add more code to Twiddle it gets slower even though i'm just pasting the same two lines over and over again without using any new variables!
Function Twiddle(farts as uint32, g as Graphics, location as string) As variant
dim q As Integer
dim previousloc as string
previousloc=scriptlocation
scriptlocation=location
q = WasteTime + farts
WasteTime = q - 1
WasteTime = q + 1
[REPEAT THE ABOVE TWO LINES SOME NUMBER OF TIMES IN THE CODE]
ScriptLocation=previousloc
return nil
End Function
If I just copy and paste those two lines a few more times the method gets slower, but we're only calling it 1,000,000 times total and I'm using a Mac Pro!
So for some reason calling a method is slow but only when the method has more and more code??? Even if the code is doing piss all and should be no problem for a Mac Pro???
Nope this isn't directly correct either and now I'm confused as hell.
nevermind that, sleep deprivation, ran one test in RB Debugger instead of real compiled app
so I haven't figured out SHlT, pretty much