remstart
Maths parser!  (,), *, /, +, -, p[i], e, s[in], c[os], t[an], sq[r]t, a[b]s
by qwe
remend
 
REM types
type equations
v as float
o as string
endtype
 
REM arrays
dim e(256) as equations
 
REM global variables
global error_msg$ = ""
global answer# = 0.0
global option_display_steps = 1
global x_value# = 0.0
 
REM cut straight to plotter
`gosub graphing
 
gosub clear
REM MAIN DO LOOP
do
	ink rgb(0,255,128),0
	previous_equation$ = equation$
	input "Enter equation:    ", equation$
	if equation$ = "" then equation$ = previous_equation$
 
	if equation$ = "help" then gosub help		    : equation$ = "no solve"
	if equation$ = "plot" then use_same_stats = 0 : gosub graphing : equation$ = "no solve"
	if equation$ = "clear" then gosub clear       :  equation$ = "no solve"
	if equation$ <> "no solve"
		error_msg$ = ""
		answer# = get_answer("("+equation$+")", 0)
		ink rgb(0,255,255),0
		print "The answer is :    " + str$(answer#)
		ink rgb(255,0,0),0
		if error_msg$ <> "" then print error_msg$
		print
	endif
loop
end
 
clear:
CLS
REM instructions
ink rgb(255,64,64),0
print "Maths parser by qwe"
print "Handles (, ), *, /, +, -, !, [p]i, [e], [s]in, [c]os, [t]an, sq[r]t, a[b]s, [E]"
ink rgb(255,255,128),0
print "Type 'help' for help"
print "Type 'plot' for graphing"
print "Type 'clear' to clean screen"
print "Type in an equation to solve it.  Use '`' for negative symbol"
print
return
 
help:
	ink rgb(255,128,255),0
	print "Type in an equation and press enter to see the answer"
	print "Valid characters are: (, ), +, -, *, /, ^, !"
	print "'p' is treated as pi, 'e' is treated as e, '`' is the negative symbol"
	print "'s' 'c' 't' and 'r' are treated as sine, cosine, tangent, and square root"
	print " - They can be entered as r(#), r(equation), or r# ( e.g. r(4), r(3+1), r4 )"
	print "'a' is treated as the previous answer, 'b' as absolute value, 'E' as sci. not."
	print
	print "'help' brings up this menu. 'plot' brings up the graphing utility"
	print
return
 
function get_answer(e$, option_replace_x)
	REM set variables
	length = len(e$)
	array_count = 0
	REM clear array
	for i = 0 to 255
		e(i).o = ""
		e(i).v = 0.0
	next i
	REM translate string equation into array
	for i = 1 to length
		s$ = mid$(e$, i)
 
		if s$="(" or s$=")" or s$="+" or s$="-" or s$="*" or s$="/" or s$="^" or s$="p" or s$ = "e" or s$ = "s" or s$ = "c" or s$ = "t" or s$ = "r" or s$ = "a" or s$ = "b" or s$ = "x" or s$ = "!" or s$ = "E"
			if add_value$ = ""
			else
				e(array_count).v = val(add_value$)
				add_value$ = ""
				inc array_count
			endif
 
			e(array_count).o = s$
			inc array_count
		else
			if s$ = "`" then s$ = "-"
			add_value$ = add_value$ + s$
			if mid$(e$, i+1) = "(" and add_value$ = "-" then add_value$ = "-1"
		endif
	next i
	REM special features
	add_implicit_multiplications()
	set_pi_and_e_values()
	if option_replace_x = 1 then set_x_value()
	add_implicit_a()
	uh_oh = check_for_brackets_error()
 
	if uh_oh = 1 then exitfunction 0.0
 
	REM find out how many bracketed sections there are
	for i = 0 to 255
		if e(i).o = "(" then total_brackets = total_brackets + 1
	next i
	REM solve each level of brackets
	if total_brackets > 0
		for lvl = total_brackets to 1 step -1
			display_equation_array()
			length = solve_level(lvl)
		next lvl
	endif
	REM give answer, store answer in global variable
	localanswer#=e(0).v
	answer#=e(0).v
endfunction localanswer#
 
function display_equation_array()
	ink rgb(192,192,192),0
	done=0
	pos = 0
 
	repeat
		`see what brakcet level computer is at
		if e(pos).o = "(" then inc bracket_level
		if e(pos).o = ")" then dec bracket_level
 
		`once reaches last bracket, no more no more
		if bracket_level = 0 then done = 1
 
		`add each array element to string
		if e(pos).o = ""
			display$ = display$ + str$(e(pos).v)
		else
			display$ = display$ + e(pos).o
		endif
 
		inc pos
	until done=1
 
	`take off first and last brackets
	length = len(display$)
	display$ = left$(display$, length-1)
	display$ = right$(display$, length-2)
	`display string
	if option_display_steps = 1
		print display$
	endif
endfunction
 
function solve_level(lvl)
	for i = 0 to 255
		if e(i).o = "(" then inc count_brackets
		`when computer comes to specified level
		if count_brackets = lvl
			`do operations
			solve_factorial(i)
			solve_sci_not(i)
 
			solve_special(i, "s")
			solve_special(i, "c")
			solve_special(i, "t")
			solve_special(i, "r")
			solve_special(i, "b")
 
			solve_segment(i, "^", "{")
			solve_segment(i, "*", "/")
			solve_segment(i, "-", "+")
			`now the segment is simplified to one value
			`now we can eliminate brackets around this value
			e(i).v = e(i+1).v
			e(i).o = ""
			eliminate_slot(i+1)
			eliminate_slot(i+1)
 
			dec count_brackets
		endif
	next i
endfunction length
 
function solve_sci_not(i)
	pos = i
	repeat
		`increase position along array and get its operator value
		inc pos
		s$ = e(pos).o
		`if operator is what we want, perform operation and pull out previous and next slots
		if e(pos).o = "E"
			e(pos).v = e(pos-1).v * (10.0 ^ e(pos+1).v)
			e(pos).o = ""
			eliminate_slot(pos+1)
			eliminate_slot(pos-1)
			dec pos
		endif
	until s$ = ")"
endfunction
 
function solve_factorial(i)
	pos = i
	repeat
		`increase position along array and get its operator value
		inc pos
		s$ = e(pos).o
		`if operator is what we want, perform operation and pull out previous and next slots
		if e(pos).o = "!"
			e(pos).v = factorial(e(pos-1).v)
			e(pos).o = ""
			eliminate_slot(pos-1)
			dec pos
		endif
	until s$ = ")"
endfunction
 
function factorial(num#)
	ans# = 1.0
	for i = 1 to num#
		ans# = ans# * i
	next i
endfunction ans#
 
function solve_special(i, o$)
	pos = i
	repeat
		`increase position along array and get its operator value
		inc pos
		s$ = e(pos).o
		`if operator is what we want, perform operation and pull out previous and next slots
		if e(pos).o = o$
			if o$ = "s" then e(pos).v = sin(e(pos+1).v)
			if o$ = "c" then e(pos).v = cos(e(pos+1).v)
			if o$ = "t" then e(pos).v = tan(e(pos+1).v)
			if o$ = "r" then e(pos).v = sqrt(e(pos+1).v)
			if o$ = "b" then e(pos).v = abs(e(pos+1).v)
 
			eliminate_slot(pos+1)
			e(pos).o = ""
		endif
	until s$ = ")"
endfunction
 
function solve_segment(i, oa$, ob$)
	pos = i
	repeat
		`increase position along array and get its operator value
		inc pos
		s$ = e(pos).o
		`if operator is what we want, perform operation and pull out previous and next slots
		if e(pos).o = oa$ or e(pos).o = ob$
			if e(pos).o = "^" then e(pos).v = e(pos-1).v ^ e(pos+1).v
			if e(pos).o = "*" then e(pos).v = e(pos-1).v * e(pos+1).v
			if e(pos).o = "/" then e(pos).v = e(pos-1).v / e(pos+1).v
			if e(pos).o = "+" then e(pos).v = e(pos-1).v + e(pos+1).v
			if e(pos).o = "-" then e(pos).v = e(pos-1).v - e(pos+1).v
 
			if e(pos).o = "/" and e(pos+1).v = 0 then error_msg$ = "Error: Divide by zero"
 
			e(pos).o = ""
			eliminate_slot(pos+1)
			eliminate_slot(pos-1)
			dec pos `position along array is dec'd because previous position was just pulled out
		endif
	until s$ = ")"
endfunction
 
function add_slot(pos_add, add$)
	for pos = 255 to pos_add step -1
		e(pos).o = e(pos-1).o
		e(pos).v = e(pos-1).v
	next pos
	e(pos_add).o = add$
	e(pos_add).v = 0.0
endfunction
 
function eliminate_slot(pos_remove)
	for pos = pos_remove to 254
		e(pos).o = e(pos+1).o
		e(pos).v = e(pos+1).v
	next pos
endfunction
 
function set_pi_and_e_values()
	for i = 0 to 255
		if e(i).o = "p" then e(i).o = "": e(i).v = 3.1415927
		if e(i).o = "e" then e(i).o = "": e(i).v = 2.7182818
		if e(i).o = "a" then e(i).o = "": e(i).v = answer#
	next i
endfunction
 
function set_x_value()
	for i = 0 to 255
		if e(i).o = "x" then e(i).o = "": e(i).v = x_value#
	next i
endfunction
 
function add_implicit_a()
	if e(1).o = "+" or e(1).o = "-" or e(1).o = "*" or e(1).o = "/" or e(1).o = "^"
		add_slot(1, "a")
	endif
	set_pi_and_e_values()
endfunction
 
function add_implicit_multiplications()
	for i = 1 to 255
		if e(i).o = "(" or e(i).o = "s" or e(i).o = "c" or e(i).o = "t" or e(i).o = "r" or e(i).o = "p" or e(i).o = "b" or e(i).o = "a" or e(i).o = "e" or e(i).o = "x"
			if e(i-1).o = "" or e(i-1).o = ")" or e(i-1).o = "!" or e(i-1).o = "p" or e(i-1).o = "e" or e(i-1).o = "a" or e(i-1).o = "x"
				add_slot(i, "*")
			endif
		endif
		if e(i).o = ")" or e(i).o = "!"
			if e(i+1).o = "" or e(i).o = "s" or e(i).o = "c" or e(i).o = "t" or e(i).o = "r" or e(i).o = "p" or e(i).o = "b" or e(i).o = "a" or e(i).o = "e" or e(i).o = "x"
				add_slot(i+1, "*")
			endif
		endif
		if e(i).o = ""
			if e(i-1).o = "p" or e(i-1).o = "e" or e(i-1).o = "a" or e(i-1).o = ")" or e(i-1).o = "x"
				add_slot(i, "*")
			endif
		endif
	next i
endfunction
 
function check_for_brackets_error()
	for i = 0 to 255
		if e(i).o = "(" and e(i+1).o = ")"  then error_msg$ = "Error: empty brackets" : uh_oh = 1
	next i
 
	for i = 0 to 255
		if e(i).o = "(" then inc count_start_brackets
		if e(i).o = ")" then inc count_end_brackets
	next i
	if count_start_brackets <> count_end_brackets then error_msg$ = "Error: Start brackets don't match end brackets" : uh_oh = 1
endfunction uh_oh
 
function emptybox(xa,ya,xb,yb)
	line xa,ya,xa,yb
	line xa,yb,xb,yb
	line xb,yb,xb,ya
	line xb,ya,xa,ya
endfunction
 
graphing:
	CLS
	REM Get window stats
	if use_same_stats = 0
		ink rgb(128,255,128),0
		print "Press enter 7 times to leave default and just enter equation"
		print
		ink rgb(255,255,128),0
		print "Default window size is 400 pixels"
		print
		ink rgb(192,192,128),0
		input "Enter window x size (pixels): ", x_pixel_size : if x_pixel_size = 0 then x_pixel_size = 400
		input "Enter window y size (pixels): ", y_pixel_size : if y_pixel_size = 0 then y_pixel_size = 400
		print
		ink rgb(255,255,128),0
		print "Default value for window x/y unit size is 20 (-10 to 10) on each axis"
		print
		ink rgb(192,192,128),0
		input "Enter window X size in units: ", x_max# : x_max# = x_max# / 2.0 : if x_max# = 0 then x_max# = 10
		input "Enter window Y size in units: ", y_max# : y_max# = y_max# / 2.0 : if y_max# = 0 then y_max# = 10
		print
		input "Enter x grid value (enter for none): ", grid_x#
		input "Enter y grid value (enter for none): ", grid_y#
		print
		input "Connect dots of grid? (0 or 1): ", option_connect
		print
	endif
	ink rgb(128,255,128),0
	input "Enter equation: ", equation$
	CLS
 
	sync on
 
	REM get some variables
	x_min# = -1 * x_max#
	y_min# = -1 * y_max#
	total_x_unit_size# = abs(x_min#) + x_max#
	total_y_unit_size# = abs(y_min#) + y_max#
	option_display_steps = 0
	winxpos = 320 - x_pixel_size/2
	winypos = 240 - y_pixel_size/2
 
	REM draw window
	if grid_x# > 0.001
		`draw x grid
		ink rgb(64,64,64),0
		x_ratio# = grid_x# / total_x_unit_size#
		x_interval# = x_ratio# * (x_pixel_size + 0.0)
		current_x# = 0.0
		repeat
			line int(current_x#) + winxpos, 0 + winypos, int(current_x#) + winxpos, y_pixel_size + winypos
			inc current_x#, x_interval#
		until int(current_x#) > x_pixel_size
	endif
	if grid_y# > 0.001
		`draw y grid
		ink rgb(64,64,64),0
		y_ratio# = grid_y# / total_y_unit_size#
		y_interval# = y_ratio# * (y_pixel_size + 0.0)
		current_y# = 0.0
		repeat
			line 0 + winxpos, int(current_y#) + winypos, x_pixel_size + winxpos, int(current_y#) + winypos
			inc current_y#, y_interval#
		until int(current_y#) > y_pixel_size
	endif
	`draw border
	ink rgb(255,255,255),0
	emptybox(0 + winxpos,0 + winypos,x_pixel_size + winxpos,y_pixel_size + winypos)
	`draw x and y axis
	ink rgb(192,192,192),0
	line 0 + winxpos, y_pixel_size/2 + winypos, x_pixel_size + winxpos, y_pixel_size/2 + winypos
	line x_pixel_size/2 + winxpos, 0 + winypos, x_pixel_size/2 + winxpos, y_pixel_size + winypos
	`get plot stats to display
	length_msg$ = str$(x_min#) + " <-> " + str$(x_max#)
	height_msg$ = str$(y_min#) + " <-> " + str$(y_max#)
 
	error_msg$ = ""
	previous_x = 0
	previous_y = 0
	REM Draw each x,y coordinate
	for x_pixel = 1 to x_pixel_size
		`find which x value in units we're to solve for
		x_unit# = (x_pixel + 0.0) / (x_pixel_size + 0.0)
		x_unit# = x_unit# * (total_x_unit_size# + 0.0)
		x_unit# = x_unit# + (x_min# + 0.0)
 
		`find y value in units
		x_value# = x_unit#
		y_unit# = get_answer("("+equation$+")", 1)
 
		`find y value in pixels
		y_pixel# = y_unit# * -1.0
		y_pixel# = y_pixel# / (total_y_unit_size#)
		y_pixel# = y_pixel# * (y_pixel_size + 0.0)
		y_pixel# = y_pixel# + ((y_pixel_size + 0.0) / 2.0)
 
		y_pixel = y_pixel#
		`draw point
		if x_pixel = 1 then previous_x = x_pixel: previous_y = y_pixel
		if y_pixel < y_pixel_size
			if option_connect
				ink rgb(255,255,128),0
				line x_pixel + winxpos, y_pixel + winypos, previous_x + winxpos, previous_y + winypos
			else
				dot x_pixel + winxpos, y_pixel + winypos, rgb(255,255,128)
			endif
		endif
 
		previous_x = x_pixel
		previous_y = y_pixel
	next x
	` cover up line if it went outside of graph
	ink rgb(32,32,32),0
	box 0, y_pixel_size + winypos + 1, 640, 480
	box 0, 0, 640, winypos
	box 0, 0, winxpos, 480
	box winxpos + x_pixel_size + 1, 0, 640, 480
	` show graph stats
	ink rgb(128,255,128),0
	center text x_pixel_size/2 + winxpos, y_pixel_size + winypos, length_msg$
	center text x_pixel_size + 50 + winxpos, y_pixel_size/2 + winypos, height_msg$
	ink rgb(255,255,255),0
	center text x_pixel_size/2 + winxpos, y_pixel_size + 50 + winypos, equation$
 
	ink rgb(255,64,64),0
	if error_msg$ <> "" then center text x_pixel_size/2 + winxpos, y_pixel_size + 100 + winypos, error_msg$
 
	ink rgb(0,255,255),0
	center text x_pixel_size/2 + winxpos, winypos - 40, "[RShift] returns to equation solver"
	center text x_pixel_size/2 + winxpos, winypos - 28, "[\] runs grapher again"
	center text x_pixel_size/2 + winxpos, winypos - 16, "[Backspace] runs grapher keeping same window stats"
 
	sync
	sync off
 
	done=0
	redo_grapher=0
	use_same_stats=0
	repeat
		if keystate(54) then done=1
		if keystate(43) then done=1: redo_grapher=1
		if keystate(14) then done=1: redo_grapher=1: use_same_stats=1
	until done=1
	if redo_grapher then gosub graphing
	if redo_grapher_same_stats then gosub graphing
	option_display_steps = 1
	gosub clear
return