LoginLogin

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.

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

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
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
And here's a screenshot

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)
	loop
I'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:
Spoiler The image was edited to dramatize the issue.
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.

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
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.
So YAY variable assignment and declaration is now possible.

Just a sidenote: Here's what it takes to make a basic style interpreter: Pre-Constants
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.
	
	
System Types
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
Support Functions (This will get even bigger !)
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


Sub-Layer Functions
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_$
Without all of the previous none of this would work or atleast a large portion of it would throw errors or do nothing
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





This is the crazyness I've been working towards for a while.

tfw you specifically put a cap on the code lengths before it scrolls and you totally did it well

tfw you specifically put a cap on the code lengths before it scrolls and you totally did it well
Wait 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.