// How to write a simple interpreter in JavaScript
// Peter_Olson, 30 Oct 2014
functionBasicParser(options){
this.init(options);
}
BasicParser.mParameterTypes={
c: "command",
f: "function",
o: "operator",
n: "number",
s: "string",
l: "line number",// checked
q: "line number range",
v: "variable",// checked,
r: "letter or range",
a: "any parameter",
"n0?": "optional parameter with default null",
"#": "stream"
};
// first letter: c=command, f=function, o=operator, x=additional keyword for command
// following are arguments: n=number, s=string, l=line number (checked), v=variable (checked), r=letter or range, a=any, n0?=optional parameter with default null, #=stream, #0?=optional stream with default 0; suffix ?=optional (optionals must be last); last *=any number of arguments may follow
BasicParser.mKeywords={
abs: "f n",// ABS(<numeric expression>)
after: "c",// => afterGosub
afterGosub: "c n n?",// AFTER <timer delay>[,<timer number>] GOSUB <line number> / (special, cannot check optional first n, and line number)
and: "o",// <argument> AND <argument>
asc: "f s",// ASC(<string expression>)
atn: "f n",// ATN(<numeric expression>)
auto: "c n0? n0?",// AUTO [<line number>][,<increment>]
bin$: "f n n?",// BIN$(<unsigned integer expression>[,<integer expression>])
border: "c n n?",// BORDER <color>[,<color>]
"break": "x",// see: ON BREAK...
call: "c n *",// CALL <address expression>[,<list of: parameter>]
cat: "c",// CAT
chain: "c s n?",// CHAIN <filename>[,<line number expression>] or: => chainMerge
chainMerge: "c s n? *",// CHAIN MERGE <filename>[,<line number expression>][,DELETE <line number range>] / (special)
chr$: "f n",// CHR$(<integer expression>)
cint: "f n",// CINT(<numeric expression>)
clear: "c",// CLEAR or: => clearInput
clearInput: "c",// CLEAR INPUT
clg: "c n?",// CLG[<ink>]
closein: "c",// CLOSEIN
closeout: "c",// CLOSEOUT
cls: "c #0?",// CLS[#<stream expression>]
cont: "c",// CONT
copychr$: "f #",// COPYCHR$(#<stream expression>)
cos: "f n",// COS(<numeric expression>)
creal: "f n",// CREAL(<numeric expression>)
cursor: "c #0? n0? n?",// CURSOR [<system switch>][,<user switch>] (either parameter can be omitted but not both)
data: "c n0*",// DATA <list of: constant> (rather 0*, insert dummy null, if necessary)
dec$: "f n s",// DEC$(<numeric expression>,<format template>)
def: "c s *",// DEF FN[<space>]<function name>[(<formal parameters>)]=<expression> / (not checked from this)
defint: "c r r*",// DEFINT <list of: letter range>
defreal: "c r r*",// DEFREAL <list of: letter range>
defstr: "c r r*",// DEFSTR <list of: letter range>
deg: "c",// DEG
"delete": "c q?",// DELETE [<line number range>] / (not checked from this)
derr: "f",// DERR
di: "c",// DI
dim: "c v *",// DIM <list of: subscripted variable>
draw: "c n n n0? n?",// DRAW <x coordinate>,<y coordinate>[,[<ink>][,<ink mode>]]
drawr: "c n n n0? n?",// DRAWR <x offset>,<y offset>[,[<ink>][,<ink mode>]]
edit: "c l",// EDIT <line number>
ei: "c",// EI
"else": "c",// see: IF (else belongs to "if", but can also be used as command)
end: "c",// END
ent: "c n *",// ENT <envelope number>[,<envelope section][,<envelope section>]... (up to 5) / section: <number of steps>,<step size>,<pause time> or: =<tone period>,<pause time>
env: "c n *",// ENV <envelope number>[,<envelope section][,<envelope section>]... (up to 5) / section: <number of steps>,<step size>,<pause time> or: =<hardware envelope>,<envelope period>
eof: "f",// EOF
erase: "c v *",// ERASE <list of: variable name> (array names without indices or dimensions)
erl: "f",// ERL
err: "f",// ERR
error: "c n",// ERROR <integer expression>
every: "c",// => everyGosub
everyGosub: "c n n?",// EVERY <timer delay>[,<timer number>] GOSUB <line number> / (special, cannot check optional first n, and line number)
exp: "f n",// EXP(<numeric expression>)
fill: "c n",// FILL <ink>
fix: "f n",// FIX(<numeric expression>)
fn: "f",// see DEF FN / (FN can also be separate from <function name>)
"for": "c",// FOR <simple variable>=<start> TO <end> [STEP <size>]
list: "c q0? #0?",// LIST [<line number range>][,#<stream expression>] (not checked from this, we cannot check multiple optional args; here we have stream as last parameter)
load: "c s n?",// LOAD <filename>[,<address expression>]
locate: "c #0? n n",// LOCATE [#<stream expression>,]<x coordinate>,<y coordinate>
log: "f n",// LOG(<numeric expression>)
log10: "f n",// LOG10(<numeric expression>)
lower$: "f s",// LOWER$(<string expression>)
mask: "c n0? n?",// MASK [<integer expression>][,<first point setting>] / (either of the parameters may be omitted, but not both)
max: "f n *",// MAX(<list of: numeric expression>)
memory: "c n",// MEMORY <address expression>
merge: "c s",// MERGE <filename>
mid$: "f s n n?",// MID$(<string expression>,<start position>[,<sub-string length>]) / (start position=1..255, sub-string length=0..255)
mid$Assign: "f s n n?",// MID$(<string variable>,<insertion point>[,<new string length>])=<new string expression> / (mid$ as assign)
min: "f n *",// MIN(<list of: numeric expression>)
mod: "o",// <argument> MOD <argument>
mode: "c n",// MODE <integer expression>
move: "c n n n0? n?",// MOVE <x coordinate>,<y coordinate>[,[<ink>][,<ink mode>]]
mover: "c n n n0? n?",// MOVER <x offset>,<y offset>[,[<ink>][,<ink mode>]]
"new": "c",// NEW
next: "c v*",// NEXT [<list of: variable>]
not: "o",// NOT <argument>
on: "c",// => onBreakCont, on break gosub, on break stop, on error goto, on <ex> gosub, on <ex> goto, on sq(n) gosub
onBreakCont: "c",// ON BREAK CONT / (special)
onBreakGosub: "c l",// ON BREAK GOSUB <line number> / (special)
onBreakStop: "c",// ON BREAK STOP / (special)
onErrorGoto: "c l",// ON ERROR GOTO <line number> / (special)
onGosub: "c l l*",// ON <selector> GOSUB <list of: line number> / (special; n not checked from this)
onGoto: "c l l*",// ON <selector> GOTO <list of: line number> / (special; n not checked from this)
onSqGosub: "c l",// ON SQ(<channel>) GOSUB <line number> / (special)
openin: "c s",// OPENIN <filename>
openout: "c s",// OPENOUT <filename>
or: "o",// <argument> OR <argument>
origin: "c n n n? n? n? n?",// ORIGIN <x>,<y>[,<left>,<right>,<top>,<bottom>]
out: "c n n",// OUT <port number>,<integer expression>