So I have a program that is compiling and running, passing my limited unit tests.
I add the following routine:
sub returnstmt() ' return from a subroutine
curline = gstackln(gsp)
textp = gstacktp(gsp)
gsp = gsp - 1
initlex2()
end sub
And now when I compile, I get:
QuoteERROR: parameters mismatch for procedure myrnd
params given : #long@0
OPTIONS:
myrnd() returns integer
WORD: parenexpr
IN: expression
LINE: 238
FILE: "main source"
Program here - if you comment out the sub starting at line 187, it compiles fine:
'Ed Davis. Tiny Basic that can play Star Trek
'Supports: end, list, load, new, run, save
'gosub/return, goto, if, input, print, multi-statement lines (:)
'a single numeric array: @(n), and rnd(n)
$Filename "int.exe"
includepath "$\inc\"
include "console.inc"
#lookahead
% c_maxlines = 7000
% c_maxvars = 26
% c_at_max = 1000
% c_g_stack = 100
% false = 0
% true = 1
dim pgm(c_maxlines) as string ' program stored here
dim vars(c_maxvars) as integer ' variable store
dim gstackln(c_g_stack) as integer ' gosub line stack
dim gstacktp(c_g_stack) as integer ' gosub textp stack
dim gsp as integer ' gosub stack index
dim atarry(c_at_max) as integer ' the @ array
dim tok as string, toktype as string ' current token, and it's type
dim thelin as string, thech as string ' current program line, current character
dim intch as integer ' current character as an integer
dim curline as integer, textp as integer ' position in current line
dim num as integer ' last number read by scanner
dim errors as boolean
dim timestart as double
main()
sub main()
gsp = 0
do
errors = false
print("> ")
pgm(0) = myinput()
if pgm(0) <> "" then
initlex(0)
if toktype = "number" then
validlinenum()
pgm(num) = mid(pgm(0), textp, len(pgm(0)) - textp + 1)
else
if not docmd() then exit sub
end if
end if
loop
end sub
function docmd() as boolean
do
if accept("bye") or accept("quit") then
return false
elseif accept("end") or accept("stop") then
return true
elseif accept("list") then
liststmt(): return true
elseif accept("run") then
runstmt()
' elseif accept("gosub") then
' gosubstmt()
elseif accept("goto") then
gotostmt()
elseif accept("if") then
ifstmt()
elseif accept("input") then
inputstmt()
elseif accept("print") or accept("?") then
printstmt()
' elseif accept("return") then
' returnstmt()
elseif accept("@") then
arrassn()
elseif accept(":") then
' just continue
elseif toktype = "ident" then
assign()
elseif tok = "" then
' handled below
else
print "unknown command: " tok cr: return true
end if
if errors then return true
if curline > c_maxlines then return true
while tok = ""
if curline = 0 or curline >= c_maxlines then return true
initlex(curline + 1)
end while
loop
end function
sub gosubstmt() ' for gosub: save the line and column
gsp = gsp + 1
gstackln(gsp) = curline
gstacktp(gsp) = textp
gotostmt()
end sub
sub assign()
dim var as integer
var = getvarindex(): nexttok()
expect("=")
vars(var) = expression(0)
end sub
sub arrassn() ' array assignment: @(expr) = expr
dim n as integer, atndx as integer
atndx = parenexpr()
if tok <> "=" then
print "Array Assign: Expecting '=', found: " & tok & cr: errors = true
else
nexttok() ' skip the "="
n = expression(0)
atarry(atndx) = n
end if
end sub
sub ifstmt()
dim b as boolean
if expression(0) = 0 then skiptoeol(): exit sub
b = accept("then") ' "then" is optional
if toktype = "number" then gotostmt()
end sub
sub inputstmt() ' "input" [string ","] var
dim var as integer
dim st as string
if toktype = "string" then
print(mid(tok, 2))
nexttok()
expect(",")
else
print("? ")
end if
var = getvarindex: nexttok()
st = myinput()
if left(st, 1) >= "0" and left(st, 1) <= "9" then
vars(var) = Convert.ToInt32(val(st))
else
vars(var) = asc(st) ' turn characters into their ascii value
end if
end sub
sub liststmt()
dim i as integer
for i = 1 to c_maxlines
if pgm(i) <> "" then print i & " " & pgm(i) & cr
next i
print cr
end sub
sub printstmt
dim printnl as boolean
printnl = true
while tok <> ":" and tok <> ""
printnl = true
if toktype = "string" then
print mid(tok, 2)
nexttok()
else
print ltrim(str(expression(0)))
end if
if accept(",") then
print " "
printnl = false
elseif accept(";") then
printnl = false
else
exit do
end if
end while
if printnl then print " " cr
end sub
sub returnstmt() ' return from a subroutine
curline = gstackln(gsp)
textp = gstacktp(gsp)
gsp = gsp - 1
initlex2()
end sub
sub runstmt()
clearvars()
initlex(1)
end sub
sub gotostmt()
num = expression(0)
validlinenum()
initlex(num)
end sub
sub validlinenum()
if num <= 0 or num > c_maxlines then print "Line number out of range" & cr: errors = true
end sub
sub clearvars()
dim i as integer
for i = 1 to c_maxvars
vars(i) = 0
next i
gsp = 0
end sub
function parenexpr() as integer
dim n as integer
expect("("): if errors then return 0
n = expression(0)
expect(")")
return n
end function
function expression(minprec as integer) as integer
dim n as integer
' handle numeric operands - numbers and unary operators
if accept("-") then
n = -expression(4)
elseif accept("+") then
n = expression(4)
elseif tok = "(" then
n = parenexpr()
elseif accept("rnd") then
n = myrnd(parenexpr())
elseif toktype = "number" then
n = num: nexttok()
elseif toktype = "ident" then
n = vars(getvarindex()): nexttok()
elseif accept("@") then
n = atarry(parenexpr())
else
print "syntax error: expecting an operand, found: " tok & cr: errors = true: return 0
end if
do ' while binary operator and precedence of tok >= minprec
if minprec <= 1 and tok = "=" then
nexttok(): n = Convert.ToInt32(n = expression(2))
elseif minprec <= 1 and tok = "<" then
nexttok(): n = Convert.ToInt32(n < expression(2))
elseif minprec <= 1 and tok = ">" then
nexttok(): n = Convert.ToInt32(n > expression(2))
elseif minprec <= 1 and tok = "<>" then
nexttok(): n = Convert.ToInt32(n <> expression(2))
elseif minprec <= 1 and tok = "<=" then
nexttok(): n = Convert.ToInt32(n <= expression(2))
elseif minprec <= 1 and tok = ">=" then
nexttok(): n = Convert.ToInt32(n >= expression(2))
elseif minprec <= 2 and tok = "+" then
nexttok(): n = n + expression(3)
elseif minprec <= 2 and tok = "-" then
nexttok(): n = n - expression(3)
elseif minprec <= 3 and tok = "*" then
nexttok(): n = n * expression(4)
elseif minprec <= 3 and tok = "/" then
nexttok(): n = n \ expression(4)
else
exit do
end if
loop
return n
end function
function getvarindex() as integer
if toktype <> "ident" then print "Not a variable:" & tok cr: errors = true: return 0
return asc(left(tok, 1)) - asc("a")
end function
sub expect(s as string)
if accept(s) then exit sub
print "expected: " s cr: errors = true
end sub
function accept(s as string) as boolean
if tok = s then nexttok(): return true
return false
end function
sub initlex(n as integer)
curline = n
textp = 1
initlex2()
end sub
sub initlex2()
thelin = pgm(curline)
thech = " ": intch = asc(thech)
nexttok()
end sub
sub skiptoeol()
tok = "": toktype = "": thech = "": intch = -1
textp = len(thelin) + 1
end sub
sub nexttok()
tok = "": toktype = ""
do
if thech = "" then exit sub
if intch > asc(" ") then exit do
getch()
loop
toktype = "punct"
tok = thech + mid(thelin, textp, 1)
if tok = ">=" or tok = "<=" or tok = "<>" then
getch(): getch(): exit sub
end if
tok = left(tok, 1)
if instr("()*+,-/:;<=>?@", tok) > 0 then getch(): exit sub
if tok = chr(34) then readstr(): exit sub ' double quote
if (intch >= asc("a") and intch <= asc("z")) or (intch >= asc("A") and intch <= asc("Z")) then
readident()
if tok = "rem" then skiptoeol()
exit sub
end if
if intch >= asc("0") and intch <= asc("9") then readint(): exit sub
if tok = chr(39) then skiptoeol(): exit sub 'single quote
toktype = ""
print "What?" chr(intch) thelin cr: getch(): errors = true
getkey()
end sub
' leave the " as the beginning of the string, so it won't get confused with other tokens
' especially in the print routines
sub readstr()
toktype = "string"
getch()
do
if thech = "" then print "String not terminated" cr: errors = true: exit sub
if thech = chr(34) then exit do
tok = tok + thech
getch()
loop
getch()
end sub
sub readint()
tok = "": toktype = "number"
do
if intch = -1 then exit do
if intch >= asc("0") and intch <= asc("9") then
tok = tok + thech
getch()
else
exit do
end if
loop
num = val(tok)
end sub
sub readident()
tok = "": toktype = "ident"
do
if intch = -1 then exit do
if (intch >= asc("a") and intch <= asc("z")) or (intch >= asc("A") and intch <= asc("Z")) then
tok = tok + lcase(thech)
getch()
else
exit do
end if
loop
end sub
sub getch()
' Any more text on this line?
if textp > len(thelin) then thech = "": intch = -1: exit sub
thech = mid(thelin, textp, 1)
intch = asc(thech)
textp = textp + 1
end sub
function myinput() as string
string s
s = input()
s = left(s, len(s) - 2)
return s
end function
function myrnd(limit as integer) as integer
static ulong rnd_next = 1
rnd_next = rnd_next * 1103515245 + 12345
return mod((rnd_next / 65536), limit)
'print("limit: " limit " tmp: " tmp " mod(tmp, limit): " mod(tmp, limit) cr)
'print "limit: " limit " tmp: " tmp " mod(tmp, limit): " cr
'print "limit: " & limit & " tmp: " & tmp & " mod(tmp, limit): " & mod(tmp, limit) & cr
end function