interpreter
interpreter
i was trying to create a scripting lang. i have searched the forum but did not get what i really wanted. i know how to execute functions like messagebox by getting their args etc. the only thing i was thinking how to do is assigning variables. for example user writes declare a long(or whatever) my program can catch that declare and know that user is trying to delcare a varible, but how do i create a variable with the provided name and type and if user further types a = 20 then how do i assign the value to the correct variable?
You might want to check out this one:
http://compilers.iecc.com/crenshaw/
it shows you basically how to build a compiler from scratch..
allthough the source is originally made in Pascal, and the assembler
output is in 68K (IIRC), you can fairly easy convert it to PB and x86 ASM.
I have been following some chapters, and I've got a nice little parser,
handling complex math instructions and variable assignment..
I just wish my x86 ASM was better.. hehe
[edit]
I didn't see that the thread was about interpreters.. lol
but the link is still valid, as Crenshaw covers the basic interpreting as well..
[/edit]
http://compilers.iecc.com/crenshaw/
it shows you basically how to build a compiler from scratch..

allthough the source is originally made in Pascal, and the assembler
output is in 68K (IIRC), you can fairly easy convert it to PB and x86 ASM.
I have been following some chapters, and I've got a nice little parser,
handling complex math instructions and variable assignment..
I just wish my x86 ASM was better.. hehe
[edit]
I didn't see that the thread was about interpreters.. lol
but the link is still valid, as Crenshaw covers the basic interpreting as well..
[/edit]
Last edited by LarsG on Sat Nov 13, 2004 4:13 pm, edited 1 time in total.
AMD Athlon XP2400, 512 MB RAM, Hercules 3D Prophet 9600 256MB RAM, WinXP
PIII 800MHz, 320 MB RAM, Nvidia Riva Tnt 2 Mach 64 (32MB), WinXP + Linux
17" iMac, 1.8 GHz G5, 512 MB DDR-RAM, 80 GB HD, 64 MB Geforce FX 5200, SuperDrive, OSX
this example code is getting from example code of smallbasic
it is writing with the langage smallbasic...
another basic is ddsbasic finding on web or in linux distrib ... it's writing in c an is it small (5kb) easy to traduc in pb
excuse my bad english, i'm french
patrick
it is writing with the langage smallbasic...
another basic is ddsbasic finding on web or in linux distrib ... it's writing in c an is it small (5kb) easy to traduc in pb
excuse my bad english, i'm french

patrick
Code: Select all
' TinyBASIC, by Nicholas Christopoulos
' A SmallBASIC example :)
DIM variables(26) ' variables (one for each letter)
DIM stack(10) ' executor's stack (GOSUB/FOR-NEXT/WHILE-WEND)
DIM labels(), program()
DEF varidx(name) = asc(left(name))-65
ip = -1 ' next command to execute (-1 = none, -2 = error)
sp = 0 ' stack pointer
CLS
print cat(2);"TinyBASIC v1";cat(-2)
print "A 450-line (with expression parser) SmallBASIC example"
print
print "Type HELP for catalog."
print "Type QUIT to exit..."
print
print "READY"
print
repeat
input "> ", inpstr
inpstr = trim(upper(inpstr))
cmd = trim(leftof(inpstr+" ", " ")) ' get command name
if len(cmd)
par = trim(rightof(inpstr, " "))
if isnumber(cmd) ' store command
addcmd val(cmd), par
else ' execute command
execute cmd, par
fi
fi
until cmd="QUIT"
end
' Store command to memory
sub addcmd(num, cmd)
local i, ins, rep
ins = len(labels): rep = -1
for i = 0 to len(labels)-1
if labels(i) = num then rep=i:exit
if labels(i) > num then ins=i:exit
next
if rep = -1 ' new record
if len(cmd) ' no error, insert (or append)
insert labels, ins, num
insert program, ins, cmd
fi
else
if len(cmd) ' replace
program(rep) = cmd
else ' erase
delete labels, rep
delete program, rep
fi
fi
end
' set value to a variable
sub setvar(varname, varval)
local idx
if len(varname)>1
TBError "ILLEGAL VARIABLES NAME, USE ONE-CHAR NAMES"
else
idx = varidx(varname)
varval = trim(varval)
if left(varvar) = chr(34) ' it is a string
variables(idx) = disclose(varval)
else ' it is an expression
variables(idx) = tbeval(varval)
fi
fi
end
' execute a TB command
sub execute(cmd, par)
local idx, i, var, vstr
local parA, tstr, fstr, f, num
if cmd in ["END", "NEW"]
' new program or end of program; syntax: NEW or END
ip = -1
sp = 0
if cmd="NEW"
erase labels, commands ' clear program
dim variables(26) ' clear variables
print:print "* DONE *":print
fi
elif cmd in ["QUIT", "REM"]
' do nothing
elif cmd="LET"
' assigns a value to a variable; syntax: LET variable = expression
sinput par; var, "=", vstr
setvar var, vstr
elif cmd="LIST"
' prints the program, syntax: LIST
if len(labels)
for i=0 to len(labels)-1
print using "####: &"; labels(i); program(i)
next
else
TBError "NO PROGRAM IN MEMORY"
fi
elif cmd="RUN"
' run the program, syntax: RUN
ip = 0
while ip<len(labels)
last_ip = ip
cmd = trim(leftof(program(ip)+" ", " "))
par = trim(rightof(program(ip), " "))
execute cmd, par
if ip = -2
print "* ERROR AT ";labels(last_ip);" *"
sp = 0
exit
elif ip = -1
print:print "* DONE *":print
sp = 0
exit
else
ip = ip + 1
fi
wend
elif cmd="INPUT"
' get a value form console, syntax: INPUT [prompt,] variable
split par, ",", para, chr(34)+chr(34) use trim(x)
if len(para) = 0
ip = -2
else
if len(para) = 2
idx = 1
input disclose(para(i)); vstr
else
idx = 0
input "? ", vstr
fi
setvar para(idx), vstr
fi
elif cmd="PRINT"
' print to console, syntax: PRINT [var1 [, varN]]
split par, ",", para, chr(34)+chr(34)+"()" use trim(x)
for vstr in para
if left(vstr)=chr(34) ' print string
print disclose(vstr); " ";
else ' print number (expression)
print tbeval(vstr); " ";
fi
next
print
elif cmd in ["GOTO", "GOSUB"]
' Syntax: GOTO line or GOSUB line
search labels, val(par), idx
if idx = -1
TBError "LABEL "+par+" DOES NOT EXIST"
else
if cmd="GOSUB"
stack(sp) = ["R", ip] ' "R" = a 'return' command must read it
sp = sp + 1
fi
ip = idx-1
fi
elif cmd="RETURN"
' syntax: RETURN
if sp > 0
sp = sp - 1
if stack(sp)(0) = "R" ' later you can add code for FOR and WHILE
ip = stack(sp)(1)
else
TBError "STACK MESS"
fi
else
TBError "STACK UNDERFLOW"
fi
elif cmd="IF"
' IF! what else?. Syntax: IF expression THEN line [ ELSE line ]
sinput par; vstr, " THEN ", tstr, " ELSE ", fstr
if tbeval(vstr)
execute "GOTO",tstr
elif len(fstr)
execute "GOTO",fstr
fi
elif cmd="SAVE"
f=disclose(par)
if len(f)=0
TBError "MISSING: FILENAME"
else
if isarray(labels)
if instr(f, ".TBAS")=0 THEN f=f+".tbas" ELSE f=leftoflast(f, ".TBAS")+".tbas"
open f for output as #1
for i=0 to len(labels)-1
print #1; labels(i); " "; program(i)
next
close #1
print:print "* DONE *":print
else
TBError "NO PROGRAM IN MEMORY"
fi
fi
elif cmd="LOAD"
f=disclose(par)
if len(f)=0
TBError "MISSING: FILENAME"
else
ip = -1
sp = 0
erase labels, commands ' clear program
dim variables(26) ' clear variables
if instr(f, ".TBAS")=0 THEN f=f+".tbas" ELSE f=leftoflast(f, ".TBAS")+".tbas"
open f for input as #1
while not eof(1)
line input #1; vstr
num = leftof (vstr, " ")
par = rightof(vstr, " ")
addcmd val(num), par
wend
close #1
print:print "* DONE *":print
fi
elif cmd="FILES"
print files("*.tbas")
elif cmd="HELP"
PRINT
print " ";cat(2);"TinyBASIC, v1";cat(-2)
PRINT
print " * All variables are real numbers."
print " * There are 26 variables, one for each letter"
print " * INPUT return real number (not string)"
print " * IF-THEN accepts only line-numbers (IF x THEN line ELSE line)"
print " * PRINT uses only , as separator"
PRINT
print " HELP";tab(15);"This screen"
print " NEW";tab(15);"New program"
print " RUN";tab(15);"Run program"
print " LIST";tab(15);"Prints program to screen"
print " SAVE";tab(15);"Saves program to disk"
print " LOAD";tab(15);"Loads a program from disk"
print " FILES";tab(15);"Prints the list of TB programs"
print " REM";tab(15);"Remarks"
print " GOTO";tab(15);"Transfers control to ..."
print " LET";tab(15);"Assigns a value to a variable"
print " PRINT";tab(15);"Prints an expression"
print " INPUT";tab(15);"Inputs a value"
print " IF";tab(15);" "
print " GOSUB";tab(15);" "
print " RETURN";tab(15);" "
print " END";tab(15);"Terminate the program"
PRINT
else
TBError "BAD COMMAND"
fi
end
' Run-time error
sub TBError(errmsg)
PRINT
print chr(7);"* ";errmsg;" *"
PRINT
ip = -2
end
' ==== expression parser ====
' evaluate an expression
def TBEval(expr)
local result, rmn, c
result = 0
expr = ltrim(expr)
if len(expr) then logical result, expr
TBEval = result
end
' number
def valueof(byref expr)
local c, i, v
for i=1 to len(expr)
c = mid(expr, i, 1)
if not (c in "0123456789.") then exit
next
if i < len(expr)
v = left(expr, i-1)
expr = mid(expr, i)
else
v = expr
expr = ""
fi
valueof = val(v)
end
' operators: ( ) or value
sub parenth(byref l, byref expr)
local op, vname
op = left(expr)
if op = "("
expr = mid(expr, 2)
logical l, expr
if left(expr)=")" then expr = mid(expr, 2)
else
if op in "0123456789."
l = valueof(expr)
' elif, check for function
else ' variable
l = variables(varidx(expr))
expr = if(len(expr)>1, mid(expr, 2), "")
fi
fi
end
' unary operators: - + NOT
sub unary(byref l, byref expr)
local op
if left(expr,3) = "NOT"
op="NOT"
expr = mid(expr,4)
elif left(expr,1) in ["-", "+"]
op=left(expr)
expr=mid(expr,2)
fi
parenth l, expr
if op="NOT"
l = NOT l
elif op="-"
l = -l
elif op="+"
' ignore it
fi
end
' operators: * /
sub muldiv(byref l, byref expr)
local op, r
unary l, expr
while left(expr) in "*/"
op = left(expr)
expr = mid(expr, 2)
unary r, expr
if op = "*"
l *= r
elif op = "/"
if r=0
TBError "DIVISION BY ZERO"
else
l /= r
fi
fi
wend
end
' operators: + -
sub addsub(byref l, byref expr)
local op, r
muldiv l, expr
while left(expr) in "+-"
op = left(expr)
expr = mid(expr, 2)
muldiv r, expr
if op = "+"
l += r
elif op = "-"
l -= r
fi
wend
end
' returns the logical operator
func getlogopr(expr)
local idx, op3, op2, op1
op3=["AND"]
op2=["OR", "<=", ">=", "=<", "=>", "<>"]
op1=["=", ">", "<"]
search op3, left(expr,3), idx
if idx >= 0 then getlogopr=op3(idx):exit
search op2, left(expr,2), idx
if idx >= 0 then getlogopr=op2(idx):exit
search op1, left(expr,1), idx
if idx >= 0 then getlogopr=op1(idx):exit
getlogopr=""
end
' logical and comparation operators
sub logical(byref l, byref expr)
local op, r
addsub l, expr
while getlogopr(expr) <> ""
op = getlogopr(expr)
expr = mid(expr, len(op)+1)
addsub r, expr
if op = "AND"
l = l AND r
elif op = "OR"
l = l OR r
elif op = "="
l = (l = r)
elif op = "<"
l = l < r
elif op = ">"
l = l > r
elif op = ">=" or op = "=>"
l = l >= r
elif op = "<=" or op = "=<"
l = l <= r
elif op = "<>"
l = l <> r
fi
wend
end
a+
pat
pat