I've made progress!
I now have some of the smilebasic commands wrapped and working (directly)
Interpretation isn't built yet but calling some of the functions that i've wrapped directly work
Here's the result of colored text (It is using smilebasic's color constants)
more to come soon. :D
TinySB Interpreter in the works
Root / Talk About Programs / [.]
CoinzReturnsCreated:
TinySB
========what is it========
TinySB is a tiny version of smilebasic, it will run on WINDOWS
It is in development because atleast (1) user/s has told me they would use it.
Some limitations will apply.
Here is a pastebin showing some commands in progress:
http://pastebin.com/bkmdjmhr
What will it do?
To start with, it will do text parsing, gcolor parsing, including hex.
It will do locate, and setcursor commands as well.
Cls commands.
Sync (Vsync)
The main function will be graphics/sprites/text/input.
It will support all 4 bg layers as well as all 5 GRP's
It will support loading and saving of NATIVE DAT file formats.
No sound will be implemented except perhaps mml if I can figure out how though that may be *difficult* considering I would need some kind of library.
It will also support sprites.
It will support touch screen emulation. How accurately I don't know.
This will be a work in progress but I can most likely finish a large portion of it in under 3 days.
It will not be able to load native GRP files at this time.
Not ALL commands will be supported but I will try to support as many as possible.
To run files you'll have to type run and the filename, which will be stored in a plaintext file I suppose.
The file will have to be parsed first, unless I invent some kind of smart search.
i'm unsure how acurate math parsing will be.
As it's going to run interpreted chances are it may in some cases run SLOWER than SmileBasic, but if you have a beefy machine or if you don't ask too much of it, it should be able to run most things.
Porting your game to it would be possible but you'd have to omit certain commands.
most Math commands will be implemented if I can get them to work exactly as they do on SB.
For now only dat files of the int type are supported but I'll extend that to support reals as well as color once the base project is completed.
That's about it.
Anymore questions? Yes I'm really doing this. No it won't be easy but it certainly will move quickly. This is easier than making a game, in some cases.
I will create update posts as this progresses, no download available as I just started this this evening.
Update
Hype Hype Hype.
I don't want anyone to freak out yet, but there is a possibility that this project's development may lead to a faster development of a gameboy emulator for SmileBasic. by RaichuBender.
I have full faith an emulator is fully feasible, so long as SmileBasic can handle the framerates.
Processing of SmileBasic commands isn't implemented yet, nor is program flow control structure such as:
if, else, and, or, for, xor, to ,gosub, goto, return, dim, var, etc.
Those commands will be some of the last to be implemented due to their complexity ranges...although simplified versions of them may be implemented for early parsing testing and development.
Commands like left$, right$, cut$, copystring$ mid$, etc will be very easy to implement.
Nested for loops and statements as well as data statements may be difficult to implement.
It may be a week or two at this rate before a version of TinySB is released even if I have a demo running.
I want the first release to be as useful as possible.
Soo today I just started toying with the idea of you know.. simulated arrays.
In playbasic, for TinySB
and I kind of solved it.
so..
Yeah arrays are gonna be a thing in the early version hooray!
here's the NON smilebasic code, aka the code in playbasic that will be responsible, I have a few more algorithms to write for the 3D array to 1D index and 4D array to 1D index, but after this I should be able to use these functions for all types of arrays (not just one type) IE, strings, ints, etc
And here's a screenshot
Spoiler
; PROJECT : Project2 ; AUTHOR : GimmeMoreCoinz ; CREATED : 5/18/2016 ; --------------------------------------------------------------------- type two_dimensional entries$(); internal_name$ //a list of these in another array will be provided, along with their indexes in the main array X_width //used to get the index Y_depth //used to check array boundaries endtype type one_dimensional entries$(); internal_name$ //a list of these in another array will be provided, along with their indexes in the main array max_length //used to get the index endtype dim a(100) as two_dimensional a(1).X_width=100 c=get_index2D(5, 5, X_width) a(1).entries$(c)="does it work" d=get_index2D(5, 5, X_width) output$ = a(1).entries$(d) print output$ sync waitkey waitnokey function get_index2D(x, y, X_width) index2D = (y*X_width)+x endfunction index2D function get_index1D(index) index1D = index endfunction index1D
Update: 3D array strings are re-dimmable in the function layer now.
This isn't a joke.
I just have to do:
2D string arrays (make them resizable)
1D string arrays (make them resizable--easy)
3D int arrays (make them resizable)
2D int arrays (make them resizable)
1D int arrays (make them resizable--easy)
And then for the time being arrays will be done. Floats will be last.
After that, I suppose it's onto the variables next.
Please do understand I'm only coding the support functions at this time, not the functionality for TinySB to actually do anything with them though,
testing the support functions outside of the interpreter is fun! That is to say the functions act as a software abstraction layer and I can still type them in directly (Hey I know what I'm doing I'm the one building it)
On that note, does anyone have a rip of all the SmileBasic Sounds and music I can make use of?
I may actually be able to get the pitch feature of beeps to work in TinySB if someone can provide me with a soundpack.
Thanks!
Update: 3D array strings are re-dimmable in the function layer now. This isn't a joke. I just have to do: 2D string arrays (make them resizable) 1D string arrays (make them resizable--easy) 3D int arrays (make them resizable) 2D int arrays (make them resizable) 1D int arrays (make them resizable--easy) And then for the time being arrays will be done. Floats will be last. After that, I suppose it's onto the variables next. Please do understand I'm only coding the support functions at this time, not the functionality for TinySB to actually do anything with them though, testing the support functions outside of the interpreter is fun! That is to say the functions act as a software abstraction layer and I can still type them in directly (Hey I know what I'm doing I'm the one building it) On that note, does anyone have a rip of all the SmileBasic Sounds and music I can make use of? I may actually be able to get the pitch feature of beeps to work in TinySB if someone can provide me with a soundpack. Thanks!http://12me21.github.io/songs_firefox for music, idk about sounds though.
Update:
I've got BG layers Implemented ... sort of.
The tiles themselves are hard coded (basically they exist as a place holder tiles for whichever GRP is mapped to the bg layer)
So far with the BGOFS and BGPUT commands, along with a function called DRAWBGS' which will happen every frame since that is what SmileBasic does, it's looking pretty good.
So i've finished with the 1D ints, the 2D ints, the 3D ints, and same with 1D strings 2D strings, and 3D strings.
I've got BG layers sort of implemented (as functions)
The function layer is coming along.
What's missing!
ALOT!! ALOT is missing. At this point it's just a toy engine, it can't interprete anything yet.
That's why in the screenshots you might notice the code is still (rather directly referencing functions or declaring variable names directly)
It's now possible though (to use the functions to get the array values and store things like the BGOffset into arrays) again using functions that do it because interpretation doesn't exist yet... but that's ok it can emulate some of what SmileBasic does.
and guess what! Just this afternoon I finished up some of the G_color commands. they technically work if something were to be thrown at them they'd return rgb color codes (which are used to change text color and background color)
Soo it's coming along clickity clickity clackity !!
EDIT
Just to show off, here's a screenshot of 2 BG's more filled in , moving independently in the function engine:
Research:
So it looks like the color command doesn't ever accept an RGB parameter.. that is strange to me.
Gcolor maybe?
Nah it's more complex you have to use fontdef or something to get font colors outside SmileBasic's normal constants.
Update
Finally something interesting happened.
The image speaks for itself, I have colored text foregrounds and backgrounds working (globally) now using the text constants I programmed first
I seem to have a handle on this! that's surprising.
EDIT have to post this omg:
This just looks cool
Update
It's about time alright people what's working what isn't
Working:
BGOFS(layer, X, Y) Equivalent to BGOFS layer, X, Y
Color_#(#TCOLOR, #TCOLOR) equivalent to (Color HexValueOrTColor value, HexvalueOrTColor value)
COLOR_1#(#TCOLOR) equivalent to Color (HexvalueOrTColor value)
COLOR_2#(#TCOLOR) equivalent to Color( , HexvalueorTcolor value) <notice the comma
Locate(X, Y) Equivalent to locate(X, Y) lol
vsync_empty() or Vsync_ equivalent to Vsync without a value
Vsync(value) equivalent to giving a value to vsync
Cls (not wrapped yet but pretty darn obvious)
BGCLR(layer) equivalent to BGCLR layer
BGCLR() equivalent to BGCLR (clears all layers)
BGSHOW(layer) equivalent to BGSHOW Layer
BGHIDE(layer) equivalent to BGHIDE layer
print_string (equivalent to print) <--This is special because it uses global text color settings to print the colored strings
Gcolor_#( #color) equivalent to Gcolor #value like Gcolor #RED
A few other color commands and BG commands have been wrapped but aren't fully functional yet
BGPUT(layer, TileX, TileY, tilenumber) Equivalent to BGPUT layer, X, Y, BGDATA
Aside from all the cool wrapper functions I have DIM isn't integrated yet.
Inc obviously exists but isn't wrapped yet. It will probably look something like Inc(variable_name$) which will be wrapped
to another function that parses strings, or variable math etc.
I hope soon to get goto and gosub working as well as @LABELS and on X Goto or On X Gosub though i'd rather get
sprites and text out of the way!
So yeah this has been a success (so far) and I have a lot more functions to wrap SmileBasic commands into before I can build the interpreter.
Keep your hopes up, this is going well.
I will eventually have more commands working, and once I have enough I can build the interpreter itself which will read the commands
like SmileBasic reads them
(That is if you typed BGCLR 3 it would clear BGLAYER 3)
Sprite commands will be kind of last but they're coming.
I hope everyone is ready. I may add BGMUSIC because I have a dump now thanks to some people.
4D array support won't come yet I did too much of that.
Things to look foreward to
*Basic Sprites
*Variable and assignment declarations (eventually), although arrays are pretty much ready.
*BGVAR is already built in but functions to wrap it aren't yet. Keep waiting.
*BGLOAD and BGSAVE are coming next ->Target array. That is why I did arrays first. Rejoice! This will be easy (with arrays completed as data structures)
*Input. Although , it will take a different form than expected for temporary times.
Oh yes, BGPAGE and BGSCREEN are coming as well because now that I've implemented BG's it isn't so hard.
*Button command is coming. I will use an external text file so you can map the buttons to whatever you want on your keyboard.
*TouchScreen Input coming soon.
*BGSCREEN to define bg's to be drawn on bottom screen and not top will come.
*Loading of PNG's (in place of GRPS) is coming, all you'd have to then do is convert your PNG to a grp when exporting.
This won't be able to export your project to NATIVE SmileBasic code. But it will be able to *Run* native SmileBasic code.
**Not all commands will be supported but I really intend to support anything I can.
That's it for now! Phew.. what a fun night this was coding all this.
I'm still at it.. I ran into the dumbest bug. Nothing new to report sadly, the pace seems to be crashing down as I keep running into bugs.
Oh well, I made backups of the most stable version.
Should anything happen or my files get corrupt I can hope to god they can be re opened safely.
MOST of the program stack is complete.
It runs this now:
put("@loop") //This might happen after label parsing.. //put a color command in the stack put("COLOR #TRED, #TGREEN"); //put a locate in the stack put("locate(5, 9)") //put a print in the stack put("Print hello") //here we're going to try parsing the first loop put("goto @loop") //Call the Psub to create the label indexes find_labels() do if pc>program_stack_size locate(9,25) print_string( "END OF PROGRAM at " +str$(pc) ) frame_render() //render the frame including bg/sprite etc sync waitkey waitnokey end Endif parse_command(pc) frame_render() //render the frame including bg/sprite etc step_() //step the program stack sync cls rgb(0,0,0) loopI've done good. I still need to implement things like CLS and stuff, but the parsing is coming along. Print is parsed (but it needs further parsing down the road) Assignment operators just aren't coded in yet but you can use put now in the engine OUTSIDE Runtime to inject valid commands into the program stack It autoincrements the program stack size for you so you don't have to think about it. This will be a more than helpful debug tool. I have a loop that calls step()_ step starts from 1 to the end of the program stack YOU KNOW WHAT THAT MEANS!! if it finds a label like @mylabel and later a call like @gosub (not tested yet) it should essentially push something onto the program stack (the pc address to return to) and then when it finds return it should POP it off the stack and go back to the last pc address in the array (after the array is resized) so the stack array resizes dynamically to avoid having issues with the runtime. Uhm I think I've basically got the bare bones of the engine completed and it runs real code now. Hooray.
Cool!
Update
I decided to get to work on the variable and string stack (the single use variables and strings)
First, this happened:
After that things kind of went smoothly.
The variable stack isn't even working. It's behaving oddly.
I can't figure out why but I'm on it.
So I guess I'm adding normal variables now.
Parsing assignment of variables, strings, and arrays will be after this.
Math assignment of variables won't be ready for a while so INC and DEC will be implemented until the math stack is complete.
A run command will be implemented in the early release so that you can do something like run "C:/Myfile.txt"
and it will try to run it as if it's a SmileBasic exe.
No news yet on when that will be ready but probably a few more days as I have quite the free time chunks.
Spoiler
The image was edited to dramatize the issue.Update
Well, I've done it again. I took TinySB one step further and got the variable stack implemented.
Here this is using the function layer (not the interpreter layer) to demonstrate the variable stack works.
This means I can safely do variable assignment and address any variable on the stack safely.
Here's some interesting debug information about the programming running inside PlayBasic emulating SmileBasic.
I've made line segment correlations between the code and the debug window as well as the printed screen:
Why does this matter
So YAY variable assignment and declaration is now possible.
Spoiler
To make it simple think about what it would be like if you did something like: A=A+1 Without a decent variable stack or one that malfunctions, you'd end up with a whole bunch of the same variable called A But since the search is only ever linear, it would only ever set A to itself. A=A would be the result with a bad parser. What does a good parser make a difference in? Pretty much.. it makes programming possible. The math stack wouldn't even be possible without this. Unless you want to print out literal equations only.Just a sidenote:
Here's what it takes to make a basic style interpreter:
Pre-Constants
System Types
Support Functions (This will get even bigger !)
Sub-Layer Functions
Without all of the previous none of this would work or atleast a large portion of it would throw errors or do nothing
This is the crazyness I've been working towards for a while.
Spoiler
; PROJECT : TinySBRunTime ; EDITED : 2016-05-20 ; --------------------------------------------------------------------- #Include "SaveBitmap" //Define the constant colors oldschool style :) Dim constant_colors$(18) //Define the constant rgb values oldschool style :) Dim rgb_colors(18) constant_colors$(1)="#AQUA" constant_colors$(2)="#BLACK" constant_colors$(3)="#BLUE" constant_colors$(4)="#CYAN" constant_colors$(5)="#FUCHSIA" constant_colors$(6)="#GRAY" constant_colors$(7)="#GREEN" constant_colors$(8)="#LIME" constant_colors$(9)="#MAGENTA" constant_colors$(10)="#MAROON" constant_colors$(11)="#NAVY" constant_colors$(12)="#OLIVE" constant_colors$(13)="#PURPLE" constant_colors$(14)="#RED" constant_colors$(15)="#SILVER" constant_colors$(16)="#TEAL" constant_colors$(17)="#WHITE" constant_colors$(18)="#YELLOW" rgb_colors(1)=rgb(0, 248, 248) rgb_colors(2)=rgb(0, 0, 0) rgb_colors(3)=rgb(0, 0, 255) rgb_colors(4)=rgb(0, 0, 248) rgb_colors(5)=rgb(248, 0, 248) rgb_colors(6)=rgb(128, 128, 128) rgb_colors(7)=rgb(0, 128, 0) rgb_colors(8)=rgb(0, 248, 0) rgb_colors(9)=rgb(248, 0, 248) rgb_colors(10)=rgb(128, 0, 0) rgb_colors(11)=rgb(0, 0, 128) rgb_colors(12)=rgb(128, 128, 0) rgb_colors(13)=rgb(128, 0, 128) rgb_colors(14)=rgb(248, 0, 0) rgb_colors(15)=rgb(192, 192, 192) rgb_colors(16)=rgb(0, 128, 128) rgb_colors(17)=rgb(248, 248, 248) rgb_colors(18)=rgb(248, 248, 0) //Define the text color indexes as rgb values dim constant_Tcolors$(15) constant_Tcolors$(1) = "#TBLACK" //1 constant_Tcolors$(2) = "#TMAROON" //2 constant_Tcolors$(3) = "#TRED" //3 constant_Tcolors$(4) = "#TGREEN" //4 constant_Tcolors$(5) = "#TLIME" //5 constant_Tcolors$(6) = "#TOLIVE" //6 constant_Tcolors$(7) = "#TYELLOW" //7 constant_Tcolors$(8) = "#TNAVY" //8 constant_Tcolors$(9) = "#TBLUE" //9 constant_Tcolors$(10) = "#TPURPLE" //10 constant_Tcolors$(11) = "#TMAGENTA" //11 constant_Tcolors$(12) = "#TTEAL" //12 constant_Tcolors$(13) = "#TCYAN" //13 constant_Tcolors$(14) = "#TGRAY" //14 constant_Tcolors$(15) = "#TWHITE" //15 //Set the rgb values in the mirror rgb array //We may as well just copy the values by their color names from the rgb_colors array dim constant_Tcolors(15) constant_Tcolors(1) = rgb_colors(2) //#BLACK constant_Tcolors(2) = rgb_colors(10) //#MAROON constant_Tcolors(3) = rgb_colors(14) //#RED constant_Tcolors(4) = rgb_colors(7) //#GREEN constant_Tcolors(5) = rgb_colors(8) //#LIME constant_Tcolors(6) = rgb_colors(12) //#OLIVE constant_Tcolors(7) = rgb_colors(18) //#YELLOW constant_Tcolors(8) = rgb_colors(11) //#NAVY constant_Tcolors(9) = rgb_colors(3) //#BLUE constant_Tcolors(10) = rgb_colors(13) //#PURPLE constant_Tcolors(11) = rgb_colors(9) //#MAGENTA constant_Tcolors(12) = rgb_colors(16) //#TEAL constant_Tcolors(13) = rgb_colors(4) //#CYAN constant_Tcolors(14) = rgb_colors(6) //#GRAY constant_Tcolors(15) = rgb_colors(17) //#WHITE //Define tile_image constants make them all random color squares Dim tiles(1024) for t=0 to 1024 tiles(t)=newfximage(16, 16) rendertoimage tiles(t) cls rndrgb() ink rgb(0,0,0) circle 8, 8, 8, 1 next t ink rgb(255, 255, 255) global global_textbackground=5 global global_textforeground=6 global global_textcursorX=0 //These work I think on 8 by 8 global global_textcursorY=0 //Create the color tiles dim TXTBG(15) for t=1 to 15 TXTBG(t) = newimage(16, 16) rendertoimage TXTBG(t) cls constant_Tcolors(t) next t rendertoscreen dim graphics_page(2) for t=1 to 2 graphics_page(t)=newfximage(getscreenwidth(), getscreenheight() ) imagemaskcolour graphics_page(t),rgb(0,0,0) //Black next t //Just a BIG note when dealing with text. //IF YOU EVER want to draw text to an image, for one reason or another using FX images is unreliable //ORRRR Playbasic is just fucked in the head. global text_page = newimage(getscreenwidth(), getscreenheight() ) imagemaskcolour text_page, rgb(0, 0, 0) ; black rendertoimage text_page Print "HELLO THERE" // This line breaks if the type of image text_page is an FXIMAGE //Not only that.. rendertoscreen drawimage text_page, 0, 0, 0 //drawimage text_page, 0, 0, 0 cls //When using CLS or ACLS sometimes we want to only clear the txt not the graphics. //To do this we need to draw the text onto our text_page damnit //easy change the print command to draw on this page //Integrate a framerender function //draw everything in it global currentGPAGEDSP=1 //Which Gpage to render global currentGPAGEDRT=1 //Which Gpage to draw to dim commands$(100); //probably more than this but this goes in pre constants commands$(1)="BGPUT" //PUT tiles on a bg Layer commands$(2)="BGOFS" //BGOFFSET commands$(3)="BGSHOW" //Show a bg layer commands$(4)="BGHIDE" //Hide a bg layer commands$(5)="COLOR" //text colors commands$(6)="GCOLOR" //drawing ink color commands$(7)="LOCATE" //set the text cursor commands$(8)="Print" //needs parsing sometimes can accept any $ parameter, may only need parsing if + str$() is present commands$(9)="INC" //Increment commands$(10)="DEC" //Decrement commands$(11)="BGCLR" //accepts parameter or no parameters commands$(12)="DIM " //requires a parameter with parameters commands$(13)="CLS" //requires no parameters commands$(14)="GCLS" // Clears the screen graphics only. may need a seperate graphics screen painted under everything. //Am I really doing this? Ehhhhyeeeep I think so o.o //a list of constant math operands we may need them in case we do math parsing down the road //Just good to have. dim operands$(7) operands$(1)="+" operands$(2)="-" operands$(3)="/" operands$(4)="*" operands$(5)="=" operands$(6)=">" operands$(7)="<" //Program stack stuff dim program_stack$(1) dim return_stack(1) global return_stack_size=1 global return_stack_index=0 //This is the current stack index global last_call=0 //This is the last index in the stack that was called global label_list_size=1 global pc = 0 //This is the program counter it'll be in charge of stepping our program global program_stack_size=1 //the program stack size dim labels$(1) dim label_pointers(1) //The PC pointer is the most important in program flow control //Inside of TinySB as it takes care of running one command at a time smoothly. //To see how it progresses see step. //A function to read the program in should resize the Program_stack$() to the same amount //as there are readable string line numbers.
Spoiler
; PROJECT : TinySBRunTime ; EDITED : 2016-05-20 ; --------------------------------------------------------------------- //====Guide //===_STR means String //===_INT means Integer //===_REL means Real //==Strings1D, 2D, 3D are arrays of arrays of the string arrays user creates //==INTS1D, 2D, 3D are arrays of arrays of the integer arrays user creates //String Array Types type one_dimensionalSTR entries$(8129); //Static size, about the same as SB internal_name$ //a list of these in another array will be provided, along with their indexes in the main array total_length //used to get the index endtype type two_dimensionalSTR entries$(5000*5000); internal_name$ //a list of these in another array will be provided, along with their indexes in the main array X_width //used to get the index Y_depth //used to check array boundaries endtype type three_dimensionalSTR entries$(500*500*500); internal_name$ //a list of these in another array will be provided, along with their indexes in the main array X_width //used to get the index Y_depth //used to check array boundaries Z_depth endtype //Integer Array Types type one_dimensional_INT entries(8129) ; //Static size about the same as SB internal_name$ //a list of these in another array will be provided, along with their indexes in the main array total_length //used to get the index endtype type two_dimensional_INT entries(5000*5000) internal_name$ //a list of these in another array will be provided, along with their indexes in the main array X_width //used to get the index Y_depth //used to check array boundaries endtype type three_dimensional_INT entries(500*500*500) internal_name$ //a list of these in another array will be provided, along with their indexes in the main array X_width //used to get the index Y_depth //used to check array boundaries Z_depth endtype //Addition of user declared single variables //Addition of user decclared single strings //Let's do this type _variable name$ value value_$ //For temporary storage of last conversion to string Ie str$() endtype type _string name$ value_$ value //for temporary storage of last conversion to value ie val(mystring$) endtype // ===End of declarations //==End global variable_str_size=1 //The size of the user string stack global variable_int_size=1 //The size of the user variable stack dim variable_strings(variable_str_size) as _string dim variable_ints(variable_int_size) as _variable //the type for a BGlayer. type BGLAYER BGImage width height BGVARS(8) BGROTANGLE OFFSETX OFFSETY VISIBLE endtype dim Strings1D(1) as one_dimensionalSTR dim Strings2D(1) as two_dimensionalSTR dim Strings3D(1) as three_dimensionalSTR Dim INTS1D(1) as one_dimensional_INT dim INTS2D(1) as two_dimensional_INT dim INTS3D(1) as three_dimensional_INT dim BGLAYERS(4) as BGLAYER for t=1 to 4 BGLAYERS(t).BGImage=newfximage(127*16, 127*16) imagemaskcolour BGLAYERS(t).BGImage, rgb(0, 0,0 ) BGLAYERS(t).width = 127 BGLAYERS(t).height = 127 BGLAYERS(t).BGROTANGLE =0 BGLAYERS(t).OFFSETX = 0 BGLAYERS(t).OFFSETY = 0 //Used for BGSHOW and BGHIDE BGLAYERS(t).VISIBLE = FALSE next t
Spoiler
; PROJECT : TinySBRunTime ; EDITED : 2016-05-20 ; --------------------------------------------------------------------- //psub POW(num,power) //n=1 //for i=1 to power //n=n*num //next i //endpsub n //This is called after whatever is meant to be parsed is parsed //That is to say any math etc will be parsed before print is called not during psub print_string(mystring$) //parse(mystring$) I will comment this out for now so that print_string can be called directly print_S(mystring$) //Ths calls print_S because it actually prints the colors properly endpsub //This should print the string after parsing psub print_S(mystring$) rendertoimage text_page//let's just make sure we're rendering to the screen ok? //first we have to print the text background color templength = len(mystring$) //We're going to paint the tiles for the text background first if len(mystring$) >0 //This patches the bug where random square is drawn when no text is present during blank print call. for t=0 to templength DrawTXTBG(global_textbackground, global_textcursorX+(t/2), global_textcursorY) next t endif ink constant_Tcolors(global_textforeground) //Set the ink color to the right value curs_x = (global_textcursorX-1)*16 curs_y = (global_textcursorY-1)*16 setcursor curs_x, curs_y print mystring$ //Finally we print the string setting the color first rendertoscreen endpsub //Color parsing. I'll seperate these and use a seperate function when parsing to figure out which case to use //Then pass the correctly formatted data to whichever case matches. psub gcolor_rgb(color) #print "nothing" endpsub psub gcolor_#(color$) for t=1 to 18 if color$=constant_colors$(t) ink rgb_colors(t) exitfor endif next t endpsub //this function deals with if both the parameters use #T psub color_#(colorTXT$, colorBG$) //we'll get both the colors at once , even if they're closer this is a faster search than trying to search twice //in the case that one color may be found right away //we're only losing 1/2 the processing time with this search than independently searching each one out for t=1 to 15 if colorTXT$ = constant_Tcolors$(t) color1= Constant_tcolors(t) set_global_textforeground(t) //This is the global text foreground value we're sending this to to the main system endif if colorBG$ = constant_Tcolors$(t) color2= Constant_tcolors(t) colorindex=t //added this so that it can be used to quickly get the color tile the rgb value won't be needed //Good to have it as a constant anyways for setting text colors set_global_textbackground(t) //This is the global color value, we're sending this to the main system endif next t endpsub color1, color2, colorindex //this function deals with if just the first parameter is given using #T psub color_1#(colorTXT$) for t=1 to 15 if colorTXT$ = constant_Tcolors$(t) color1= Constant_tcolors(t) set_global_textforeground(t) //this is the global foreground text color. We're sending this to the system! endif next t endpsub color1 //This function deals with if just the second parameter was given using #T psub color_2#(ColorBG$) for t=1 to 15 if ColorBG$ = constant_Tcolors$(t) color2 = Constant_tcolors(t) colorindex=t set_global_textbackground(t) //This is the global background text color. SEND IT TO THE SYSTEM :D endif next t endpsub color2, colorindex psub gcolor_hex(color$) endpsub psub bgscreen(layer, width, height) endpsub //Case to clear just one BG layer psub bgclr(layer) select layer case 0: rendertoimage BGLAYERS(1).BGImage case 1: rendertoimage BGLAYERS(2).BGImage case 2: rendertoimage BGLAYERS(3).BGImage case 3: rendertoimage BGLAYERS(4).BGImage default: rendertoimage BGLAYERS(1).BGImage endselect cls rendertoscreen endpsub //Case to clear all BG layers psub bgclrall() for t=1 to 4 rendertoimage BGLAYERS(t).BGImage cls next t rendertoscreen endpsub psub locate(x, y) setcursor (x-1)*16, (y-1)*16 //Since this modifies the text cursor the entire system should know about it global_textcursorX=x global_textcursorY=y endpsub psub BGOFS(layer, NewOFFSETX, NewOFFSETY) select layer case 0: BGLAYERS(1).OFFSETX = NewOFFSETX BGLAYERS(1).OFFSETY = NewOFFSETY case 1: BGLAYERS(2).OFFSETX = NewOFFSETX BGLAYERS(2).OFFSETY = NewOFFSETY case 2: BGLAYERS(3).OFFSETX = NewOFFSETX BGLAYERS(3).OFFSETY = NewOFFSETY case 3: BGLAYERS(4).OFFSETX = NewOFFSETX BGLAYERS(4).OFFSETY = NewOFFSETY default: BGLAYERS(1).OFFSETX = NewOFFSETX BGLAYERS(1).OFFSETY = NewOFFSETY endselect endpsub psub BGPUT(Layer,X,Y,Screen_data) select layer case 0: rendertoimage BGLAYERS(1).BGImage case 1: rendertoimage BGLAYERS(2).BGImage case 2: rendertoimage BGLAYERS(3).BGImage case 3: rendertoimage BGLAYERS(4).BGImage default: rendertoimage BGLAYERS(1).BGImage endselect drawimage tiles(Screen_data), (x-1)*16, (y-1)*16, 1 rendertoscreen endpsub psub DRAWBGS() for t=1 to 4 X_OFFS = BGLAYERS(t).OFFSETX Y_OFFS = BGLAYERS(t).OFFSETY //Get the visible flag of the BG layer VISIBLE = BGLAYERS(t).VISIBLE //Only draw the bg layer if visible is true if VISIBLE=true then Drawimage BGLAYERS(t).BGImage, X_OFFS, Y_OFFS, 1 next t endpsub psub BGhide(layer) BGLAYERS(layer).Visible = false endpsub psub Bgshow(layer) BGLAYERS(layer).Visible = true endpsub psub vsync(value) sync wait value endpsub psub vsync_novalue() sync endpsub //These functions deal with arrays that are virtualized. psub get_index1D(index) index1D = index endpsub index1D psub get_index2D(x, y, X_width) index2D = (y*X_width)+x endpsub index2D psub get_index3D(x, y, z, X_width, Y_depth) index3D = (z * X_width * Y_depth) + (y * X_width) + x endpsub index3D //This resizes an array of string type in 3 dimensions. psub resize_array3DSTR(array_index, X_width, Y_depth, Z_depth, old_X_width, old_Y_depth, old_Z_depth) dim temparray$(old_X_width, old_Y_depth, old_Z_depth) //we're making a copy dim temparray_$(old_x_width, old_Y_depth, old_Z_depth) temparray$() = copyarray3DSTR(array_index, temparray_$(), old_X_width, old_Y_depth, old_Z_depth) _type = 3 //type 3 is string allocate_size3D(X_width, Y_depth, Z_depth, array_index, _type) //Next we need to copy the old contents to the new 3D array. copyOld3DNew3DSTR(array_index, temparray$(), X_width, Y_depth, Z_depth, old_X_width, old_Y_depth, old_Z_depth) //and that should be it endpsub //This resizes an array of string type in 2 dimensions. psub resize_array2DSTR(array_index, X_width, Y_depth, old_X_width, old_Y_depth) dim temparray$(old_X_width, old_Y_depth) //we're making a copy dim temparray_$(old_x_width, old_Y_depth) temparray$() = copyarray2DSTR(array_index, temparray_$(), old_X_width, old_Y_depth) _type = 3 //type 3 is string allocate_size2D(X_width, Y_depth, array_index, _type) //Next we need to copy the old contents to the new 3D array. copyOld2DNew2DSTR(array_index, temparray$(), X_width, Y_depth, old_X_width, old_Y_depth) //and that should be it endpsub psub resize_array1DSTR(array_index, new_length) STRINGS1D(array_index).total_length = new_length endpsub //This resizes an array of int type in 3 dimensions. psub resize_array3DINT(array_index, X_width, Y_depth, Z_depth, old_X_width, old_Y_depth, old_Z_depth) dim temparray(old_X_width, old_Y_depth, old_Z_depth) //we're making a copy dim temparray_(old_x_width, old_Y_depth, old_Z_depth) temparray() = copyarray3DINT(array_index, temparray_(), old_X_width, old_Y_depth, old_Z_depth) //Next the program needs to resize the array properties. I'll use a function for that too. it's easier. _type = 1 //type 1 is int allocate_size3D(X_width, Y_depth, Z_depth, array_index, _type) //Next we need to copy the old contents to the new 3D array. copyOld3DNew3DINT(array_index, temparray(), X_width, Y_depth, Z_depth, old_X_width, old_Y_depth, old_Z_depth) //and that should be it endpsub //This resizes an array of int type in 2 dimensions. psub resize_array2DINT(array_index, X_width, Y_depth, old_X_width, old_Y_depth) dim temparray(old_X_width, old_Y_depth) //we're making a copy dim temparray_(old_x_width, old_Y_depth) temparray() = copyarray2DINT(array_index, temparray_(), old_X_width, old_Y_depth) //Next the program needs to resize the array properties. I'll use a function for that too. it's easier. _type = 1 //type 1 is int allocate_size2D(X_width, Y_depth, array_index, _type) //Next we need to copy the old contents to the new 3D array. copyOld2DNew2DINT(array_index, temparray(), X_width, Y_depth, old_X_width, old_Y_depth) //and that should be it endpsub psub resize_array1DINT(array_index, new_length) INTS1D(array_index).total_length = new_length endpsub //The below function requires both arrays have the same X, Y, Z sizing. psub copyarray3DSTR(array_index, temparray$(), sizeX, sizeY, sizeZ ) for x=0 to SizeX for y=0 to SizeY for z=0 to SizeZ sourceindex = get_index3D(x, y, z, SizeX, SizeY) temparray$(x, y, z) = Strings3D(array_index).entries$(sourceindex) next z next y next x endpsub temparray$() //Copy the 2D string array safely to a temp array psub copyarray2DSTR(array_index, temparray$(), sizeX, sizeY) for x=0 to SizeX for y=0 to SizeY sourceindex = get_index2D(x, y, SizeX) temparray$(x, y) = Strings3D(array_index).entries$(sourceindex) next y next x endpsub temparray$() //Copy the 3D int array safely to a temp array psub copyarray3DINT(array_index, temparray(), sizeX, sizeY, sizeZ ) for x=0 to SizeX for y=0 to SizeY for z=0 to SizeZ sourceindex = get_index3D(x, y, z, SizeX, SizeY) temparray(x, y, z) = INTS3D(array_index).entries(sourceindex) next z next y next x endpsub temparray() //Copy the 2D int array safely to a temp array psub copyarray2DINT(array_index, temparray(), sizeX, sizeY) for x=0 to SizeX for y=0 to SizeY sourceindex = get_index2D(x, y, SizeX) temparray(x, y) = INTS2D(array_index).entries(sourceindex) next y next x endpsub temparray() //This doesn't resize an array it only changes the internal size definition psub allocate_size3D(X, Y, Z, index, _type) select _type case 1: INTS3D(index).X_width = X INTS3D(index).Y_depth = Y INTS3D(index).Z_depth = Z case 2: case 3: Strings3D(index).X_width = X Strings3D(index).Y_depth = Y Strings3D(index).Z_depth = Z endselect endpsub //This doesn't resize an array it only changes the internal size definition psub allocate_size2D(X, Y, index, _type) select _type case 1: INTS2D(index).X_width = X INTS2D(index).Y_depth = Y case 2: case 3: Strings2D(index).X_width = X Strings2D(index).Y_depth = Y endselect endpsub //Function deals with 3D string arrays psub copyOld3DNew3DSTR(array_index, temparray$(), X_width, Y_depth, Z_depth, old_X_width, old_Y_depth, old_Z_depth) for x=0 to old_X_width for y=0 to old_Y_depth for z=0 to old_Z_depth //Here the indexes will be different for a differently dimensioned 3D String array as a 1D array so we need //to do a translation based on the new Width and Height of the array Old_Index = get_index3D(x, y, z, old_X_width, old_Y_depth) New_Index = get_index3D(x, y, z, X_width, Y_depth) //Ok we have our indexes, let's hope this isn't too costly. old_string$ = temparray$(x, y, z) Strings3D(array_index).entries$(New_Index) = old_string$ //and that's it, we've copied back the data. //This function should be used with CopyArray3DSTR only. next z next y next x endpsub //Function deals with 2d String arrays psub copyOLD2DNew2DSTR(array_index, temparray$(), X_width, Y_depth, old_X_width, old_y_depth) for x=0 to old_X_width for y=0 to old_y_width //Here the indexes will be different for a differently dimensioned 2D String array as a 1D array so we need //to do a translation based on the new Width and Height of the array Old_Index = get_index2D(x, y, Old_X_width) New_Index = get_index2D(x, y, X_width) //We have our indexes, coding this i feel craazy old_string$ = temparray$(x, y) Strings2D(array_index).entries$(New_Index) = old_string$ //tada done //Skip hop and away we go next y next x endpsub //Function deals with 3D Integer arrays psub CopyOld3DNew3DINT(array_index, temparray(), X_width, Y_depth, Z_depth, old_X_width, old_y_depth, old_z_depth) for x=0 to old_X_width for y=0 to old_y_depth for z=0 to old_z_depth //Here the indexes will be different for a differently dimensioned 3d INT array as 1D array so //We have to do a translation based on the new Width and Height of the array yep yep Old_Index = get_index3D(x, y, z, old_X_width, old_y_depth) New_Index = get_index3D(x, y , z, X_width, y_depth) //Got indexes? Great! Next we just copy and it doesn't seem costly old_value = temparray(x, y, z) INTS3D(array_index).entries(New_Index) = old_value //and done //~Tada 3D array copying and safety. next z next y next x endpsub //Function deals with 2D Integer arrays psub CopyOld2DNew2DINT(array_index, temparray(), X_width, Y_depth, old_X_width, old_y_depth) for x=0 to old_X_width for y=0 to old_y_depth //Here the indexes will be different for a differently dimensioned 3d INT array as 1D array so //We have to do a translation based on the new Width and Height of the array yep yep Old_Index = get_index2D(x, y, old_X_width) New_Index = get_index2D(x, y , X_width) //Got indexes? Great! Next we just copy and it doesn't seem costly old_value = temparray(x, y) INTS2D(array_index).entries(New_Index) = old_value //and done //~Tada 2D array copying and safety. next y next x endpsub psub get3DSTRByname(total_entries, arrayname$) for t=1 to total_entries if Strings3D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex psub get2DSTRByname(total_entries, arrayname$) for t=1 to total_entries if Strings2D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex psub get1DSTRByname(total_entries, arrayname$) for t=1 to total_entries if Strings1D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex psub get3DINTByname(total_entries, arrayname$) for t=1 to total_entries if INTS3D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex psub get2DINTByname(total_entries, arrayname$) for t=1 to total_entries if INTS2D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex psub get1DINTByname(total_entries, arrayname$) for t=1 to total_entries if INTS1D(t).internal_name$=arrayname$ arrayindex=t exitfor endif next t endpsub arrayindex //Variable handler functions for strings and variable //This returns the variable value of a user declared single variable by it's index psub return_int_VBYIndex(V_index) // If the stack isn't big enough return the correct error and exit this call. if variable_int_size<V_index error(1, V_index) return endif //now that we've actually made sure it's within the range of the array size //We do this and return value value = variable_ints(V_index).value //Get the actual value endpsub value //Make a simpler function that just returns the variable value by name. //This is used for parsing to because it will actually get a value of 0 //if the variable doesn't exist or hasn't been declared //Somewhat dangerous because it doesn't even exist on the stack still!! //In most cases finding the variable name for the first time //Should be enough to put it on the stack. psub get_int_VB(name$) V_value = 0 //set V_value to 0 //If un initialized it will initialize to zero to reduce errors //First search for it by name index = return_int_VByName(name$) //Second get the value if index >0 then V_value = return_int_VBYIndex(index) endpsub V_value //Make it so the variable stack can be resized //This resizes the variable stack and makes dynamic allocation of variable management possible //DO NOT use this, use inc_Vstack() instead for all dynamic resizing of the variable stack psub resize_int_V(new_size) redim variable_ints(new_size) as _variable endpsub psub inc_Vstack() variable_int_size +=1 //this should be valid resize_int_V(variable_int_size) //Resize the stack dynamically. endpsub //Get the index of a variable on the user declared variable stack by it's string name internally psub return_int_VByName(searchname$) V_index = 0 //Act as a false flag for t=1 to variable_int_size if variable_ints(t).value_$ = searchname$ V_index = t //resolve the linear search exitfor //end the for loop endif next t endpsub V_index psub set_int_V(V_index, V_value) variable_ints(V_index).value = V_value //set the value all there is to it endpsub psub set_int_N(V_index, V_name$) variable_ints(V_index).value_$=V_name$ endpsub //Used to test if the variable exists by name on the stack //The reason we're creating this is so we know whether or not to create a new variable on the stack psub variable_exists(V_name$) V_EXISTS = FALSE //Search to see if the variable exists //If it doesn't return false if V_index <= getarrayelements(variable_ints(), 1) V_index = return_int_VByName(V_name$) else V_index=0 endif if V_index >0 then V_EXISTS = true // Now we know the variable exists on the stack endpsub V_EXISTS //The below function adds a variable to the stack conditionally. psub set_int_VB(V_name$, V_value) //Cleanly checks if the variable exists, if it does just set it. Case_A = variable_exists(V_name$) if Case_A=true //Patches >> just fixed this the parameters were in reverse order set_int_V( return_int_VByname(V_name$),V_value) return //Exit the psub because no further processing is needed saves time //This case is evaluated first to save time because in most cases the variable already exists. else //Call inc_Vstack() inc_Vstack() //Just increase the variable stack by 1 to make room for the newly declared variable set_int_V(get_Vstack_size() ,V_value ) //Safer because it gets the size of the stack indirectly rather than directly //Set the variable name to set_int_N(get_Vstack_size(), V_name$) //This should hopefully allow getting later endif endpsub psub get_Vstack_size() A = variable_int_size //Hopefully this wraps the global value and returns it endpsub A //This is a psub that will actually get the value of a variable psub DrawTXTBG(colorindex, X, Y) PosX=(X-1)*16 PosY=(Y-1)*16 drawimage TXTBG(colorindex), PosX, PosY, 0 endpsub //This sets the global text background color psub set_global_textbackground(value) global_textbackground=value endpsub //This sets the global text foreground color psub set_global_textforeground(value) global_textforeground=value endpsub psub cls_() rendertoimage text_page cls rendertoscreen endpsub psub gcls() rendertoimage graphics_page(currentGPAGEDSP) cls endpsub
Spoiler
; PROJECT : TinySBRunTime ; EDITED : 2016-05-20 ; --------------------------------------------------------------------- //NYI not yet implemented Psub parse(mystring$) endpsub psub get_color#(color$) endpsub //This does a few things, it draws the text page on the screen and the bg layers including ones shown/hidden psub frame_render() rendertoscreen DRAWBGS() render_TEXTPAGE() endpsub //Draw the textpage onto the screen psub render_TEXTPAGE() drawimage text_page, 0, 0, 1 endpsub //This should be in charge of stepping the program stack foreward psub step_() inc pc //Increment the program counter endpsub //Used for utility to resize the stack of the program psub resize_stack(value) redim program_stack$(value) endpsub psub resize_labels(value) redim labels$(value) //the labels themselves matter redim label_pointers(value) //take care of the pointers to these are important endpsub psub getlabelbyvalue(value) endpsub labels$(value) psub add_returnstack(pc_pointer) //first increase the return stack size by 1 inc return_stack_size //We also have to resize the return stack array now resize_Rstack(return_stack_size) return_stack(return_stack_size)=pc //the address or line number to return to after the jump pc = pc_pointer //the address or line number we are jumping to by directly modifying the pc pointer. //the logic is simple instead of parsing where we are if we see return we pop a value off the stack //and go back to the last pc address endpsub //This should literally take care of gosub psub gosub_(label_name$) index = findlabelbystring(label_name$) if index>0 add_returnstack(index) endif endpsub psub goto_(label_name$) index = findlabelbystring(label_name$) address = label_pointers(index) if index>0 jump_pc(address) //changed value to address this would have been broken endif endpsub psub remove_returnstack() //first decrement the return stack size by 1 dec return_stack_size //we have to also resize it resize_Rstack(return_stack_size) //next store the pc address from the jump below us pc = return_stack(return_stack_size) //the logic is simple, we're going back to the last place we had saved (line number) //to continue execution. //As you'd expect in this way we can have 5 or even 10 different lines to eventually return to endpsub psub findlabelbystring(str_$) for t=0 to getarrayelements( labels$() ) if str_$ = labels$(t) index=t exitfor endif next t endpsub index psub resize_Rstack(value) redim return_stack(value) endpsub //this takes care of jumping to the line number or index of the program to run //Probably used by goto and other commands like it psub jump_pc(value) pc = value endpsub //utility for testing //puts an item in the program stack, //increments stack counter psub put(command$) program_stack$(program_stack_size) = command$ inc program_stack_size //increments the program stack size resize_stack(program_stack_size) endpsub Psub find_labels() dim label_strings$(1) //it should auto resize current_label = 1 //set the temporary current label counter so we actually have a label counter //pre parsing labels so we know what their line numbers are for t=1 to program_stack_size //Go through the whoollle stack entry_string$ = program_stack$(t) //Lots of nested ifs here. basically just check the label string if left$(entry_string$, 1)="@" //Ok we found one, let's see if we can get the full string of the label we need to store it Tokens=SplitToArray(entry_string$," ",label_strings$(),1) if len(label_strings$(1))>0 and left$(label_strings$(1), 1)="@" //Just double check that the @ symbol is there. //and this adds the label to our list add_label(label_strings$(1), t, current_label) inc current_label //don't forget to increment this or we'll over write //a previously saved or stored label //and now gosub/goto should work if called endif endif next t endpsub //This function handles dynamically adding new labels to the label list pre-parsing //This is never used during runtime and it better not ever be ;) psub add_label(label$, pc_index, current_label) //A little safety to make sure it doesn't break things and //that this array stays within it's indexes if current_label > label_list_size resize_labels(current_label) endif //end of safety labels$(current_label) = label$ //the actual label's name label_pointers(current_label) = pc_index //the pc address it's on endpsub Psub parse_command(index) dim command_strings$(20) dim command_strings_$(20) Tokens=SplitToArray(program_stack$(index),", ",command_strings$(),1) //Parse the color command for g=1 to Tokens if command_strings$(g) ="COLOR" //Tokens=SplitToArray(command_strings$(g+1),",",command_strings_$(),1) color_1$ = command_strings$(g+1) color_2$ = command_strings$(g+2) color_#(color_1$, color_2$) exitfor endif //Kind of parse the print command if command_strings$(g) = "Print" output_string$ = "" for a = 2 to Tokens if a>2 then output_string$ = output_string$ +" "+ command_strings$(a) if a=2 or a=Tokens then output_string$ = output_string$ + command_strings$(a) //locate(10, g) next a //Hopefully this makes print able to print more ?? print_string(output_string$) endif if command_strings$(g) = "goto" //We'll get the goto label first goto_label$ = command_strings$(g+1) //Next we're going to see if it has an @ if left$(goto_label$, 1)="@" //we're dealing with a correct label goto_(goto_label$) //and this should change the pc address! exitfor //now exit the for loop endif endif if command_strings$(g) = "locate" //we'll try to get the X and Y out of this X$ = command_strings$(g+1) Y$ = command_strings$(g+2) //if right$(X$, 1)="," then X$=left$(X$, len(X$)-1) x = val(X$) y = val(Y$) //locate(5, 15) //print_string(X$) //locate(5, 16) //print_string(Y$) locate(x, y)// actually try to use the command //locate(20, 7) exitfor endif next g endpsub psub error(value, param1) select errornum case 1: error_$ = "The global variable stack size is less than the intended index of user variable " error_$=error_$+str$(variable_int_size) +" < " +str$(param1) default: error_$ = "Generic Error!" //PlaceHolder in case a real error can not be resolved. endselect endpsub error_$
Spoiler
; PROJECT : TinySBRunTime ; AUTHOR : Microsoft ; CREATED : 2016-05-16 ; EDITED : 2016-05-20 ; --------------------------------------------------------------------- SETFPS 60 //A Tiny SB TestLoop for tx=0 to 127 for ty=0 to 127 BGPUT(2, tx, ty, tiles(tx+ty) ) if mod(tx, 8)=<12 and mod(ty, 2)=0 then BGPUT(3, tx, ty, tiles(tx+ty*2) ) next ty next tx Bg3ofX=0 Bg3ofY=0 Bg2ofX=0 Bg2ofY=0 BGSHOW(3) BGSHOW(4) main: inc Bg3OfY inc Bg2OfX BGOFS(2, bg2Ofx, 1) BGOFS(3, 1, Bg3ofY) locate(5, 5) color_#("#TRED", "#TGREEN"); print_string("Hi this is a test"); color_#("#TYELLOW", "#TTEAL"); locate(5, 6) print_string("Another color test!! WOOO!!") locate(5, 7) color_#("#TGREEN", "#TMAROON") print_string("And just to be cool") locate(5, 8) color_#("#TNAVY", "#TGRAY") print_string("Cool right") print "Global Text Background is " +str$(global_textbackground) + "And Global Text Foreground is " +str$(global_textforeground); //frame_render() put("@loop") //This might happen after label parsing.. //put a color command in the stack put("COLOR #TRED, #TGREEN"); //put a locate in the stack put("locate 20, 7") //put a print in the stack put("Print hello") put("COLOR #TTEAL #TYELLOW") put("locate 20, 8") put("Print this is A+ PLUSSER YEAHHH HOOO") put("locate 20, 9") put("Print"); //here we're going to try parsing the first loop put("goto @loop") //Call the Psub to create the label indexes find_labels() cls rgb(0,0,0) set_int_VB("hi" , 25) set_int_VB("hithere", 10) ink rgb(255, 255, 255) print get_int_VB("hi"); print get_int_VB("hithere"); set_int_VB("hithere", 15); print "New value is " + str$( get_int_VB("hithere") ) set_int_VB("A", 1999); set_int_VB("A", get_int_VB("A") +1 ); print get_int_VB("A"); sync waitkey waitnokey do if pc>program_stack_size locate(9,25) print_string( "END OF PROGRAM at " +str$(pc) ) frame_render() //render the frame including bg/sprite etc sync waitkey waitnokey end Endif frame_render() //render the frame including bg/sprite etc parse_command(pc) step_() //step the program stack sync cls rgb(0,0,0) loop
tfw you specifically put a cap on the code lengths before it scrolls and you totally did it wellWait whaaaat. Is it hard to view
Update
Alright, I have started on the math stack. Sort of.
It's a bit messy but it can get the inner most parenthesis recursively.
The next step is solving math within the parenthesis.
I'm not using tokens per say.. but this method is fairly interesting.
The way it works is we have a function called getchar which returns a single character in a target string based on it's location in the string.
Then, we have another function which checks that string against a single character to match it.
This match string function is going to be the most useful despite it's simplicity.
The function then loops, and starts with a starting pointer and ending pointer, as well as a variable called rightneeded.
Rightneeded keeps track of how many right parenthesis we need based on left parenthesis found.
The logic is quite intuitive but wouldn't be the most obvious solution to start with.
So what it does is, it has two nested loops.
The first nested loop finds the first occurence of the character "("
The next nested loop finds the first occurence of the ")" character.
While it is searching for the first occurence of the ")" character,
if it finds a "(" character then it will increase the variable rightneeded.
If it finds another ")" character than it will decrement the variable rightneeded.
Finally there is a nested if statement inside the main loop body
The nested if statement has two ifs, the first for if the ")" character is found.
Upon finding it, it also needs to seperately check if the rightneeded varaible is less than or equal to 0
If it is, we basically found a pair.
The reason we do it this way is so that we can recursively send the same string to the function (again!)
and get back the next location of the next set of outer most brackets.
Only thing is... it finds sets.
So for now the expression A=(5+1)
Would throw 3, 7
And display
"(5+1)"
as the found string.
this is infact exactly the functionality we need for the math stack.
It allows us to break down complex cases of bracket sets into simpler forms.
Also, we can deal with "(5+1)" NOW, and worry about the rest of the equasion later.
Which is exactly what we want.
We can later make a function that checks if there's any parenthesis left in the expression at all.
If there are, we can check for operands first and whether they occur before or after the parenthesis.
Basically we can assume that if something isn't an alphanumeric character, or an operand that it's a number.
That said, we can take our parenthesis string and in theory split it by it's operands into tokens.
this means we can actually tokenize the parenthesis string without worrying about the whole input string from the getgo.
We can then perform calculations on the tokens and return a replaced version of the input string.
Since I'm using recursion we can then assume that if you remove the parenthesis from the first set.
That the function will find the next set!
So we can make an iterative loop that gets the parenthesis strings, checks if there are any parenthesis left,
and then send the innermost calculations to the math stack.
This is the *easy* part.
But atleast this is a large chunk of the start of the issue.
Here's the code in PlayBasic that i've made which does this.
I'm going to for simplicity sake code the entire math stack outside the main TinySB project and then import the code in directly when it's ready.
; PROJECT : TinySB Math Stack Parser ; AUTHOR : ; CREATED : 2016-05-22 ; EDITED : 2016-05-22 ; --------------------------------------------------------------------- //Here are some functions in attempts to write the beginning of the math parser //First we need a linear character search //First we need to look for parenthesis and count how many there are mystring$ = "(((A)))+(5-1)" a_string$,st,nd = parenthesis(mystring$) print "The string was " + a_string$ print "The start and end are: " +str$(st) + " " + str$(nd) b_string$ = mid$(mystring$, st+1, nd-2) c_string$,st,nd = parenthesis(b_string$) print "The sub string of the string is " +c_string$ print "The start an end are: " +str$(st) + " " +str$(nd) waitkey waitnokey function parenthesis(ln$) ptr = 0 endptr = 0 leftneeded=0 rightneeded=0 //left and right parenthesis needed //Find the first set of parenthesis found_end = false while (true) inc ptr while getchar(ptr, ln$)="(" for t=ptr to len(ln$) if getchar(t, ln$)="(" then inc rightneeded if getchar(t, ln$)=")" dec rightneeded if rightneeded = 0 endptr = t //set the pointer to t found_end = true exitfor endif endif next t if found_end=true then exitwhile endwhile if found_end=true then exitwhile endwhile endfunction ln$, ptr, endptr //return what's inside the parenthesis //this function returns the next character function getchar(ptr, ln$) chr_$ = mid$(ln$, ptr, 1) endfunction chr_$ //return a single character
Alright, so good news.
I've created a recursive function that uses the other recursive function to get what is within the brackets.
This can probably be used within another function to preserve the source string although I just need to replace the brackets
in the source string with null characters such as ""
Maybe, it's simpler than I thought and I just overcomplicated it in my head..
Recursion is really very powerful 0_0
Here's a screenshot of the progress, and somehow I'm doing this even though I don't even really fully understand the subject.