mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-11 07:14:04 +09:00
basic: fix: would crap out when 'REM' is not a first statement of a line
This commit is contained in:
1
assets/tbas/doc/statements.tex
Normal file
1
assets/tbas/doc/statements.tex
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
96
assets/tbas/doc/syntax.txt
Normal file
96
assets/tbas/doc/syntax.txt
Normal file
@@ -0,0 +1,96 @@
|
||||
(* quick reference to EBNF *)
|
||||
(* { word } = word is repeated 0 or more times *)
|
||||
(* [ word ] = word is optional (repeated 0 or 1 times) *)
|
||||
|
||||
line =
|
||||
linenumber , stmt , {":" , stmt}
|
||||
| linenumber , "REM" , ? basically anything ? ;
|
||||
linenumber = digits ;
|
||||
|
||||
stmt =
|
||||
"REM" , ? anything ?
|
||||
| "IF" , expr_sans_asgn , "THEN" , stmt , ["ELSE" , stmt]
|
||||
| "DEFUN" , [ident] , "(" , [ident , {" , " , ident}] , ")" , "=" , expr
|
||||
| "ON" , expr_sans_asgn , ("GOTO" | "GOSUB") , expr_sans_asgn , {"," , expr_sans_asgn}
|
||||
| "(" , stmt , ")"
|
||||
| expr ; (* if the statement is 'lit' and contains only one word, treat it as function_call e.g. NEXT for FOR loop *)
|
||||
|
||||
expr = (* this basically blocks some funny attemps such as using DEFUN as anon function because everything is global in BASIC *)
|
||||
lit
|
||||
| "(" , expr , ")"
|
||||
| "IF" , expr_sans_asgn , "THEN" , expr , ["ELSE" , expr]
|
||||
| kywd , expr - "(" (* also deals with FOR statement *)
|
||||
(* at this point, if OP is found in paren-level 0, skip function_call *)
|
||||
| function_call
|
||||
| expr , op , expr
|
||||
| op_uni , expr ;
|
||||
|
||||
expr_sans_asgn = ? identical to expr except errors out whenever "=" is found ? ;
|
||||
|
||||
function_call =
|
||||
ident , "(" , [expr , {argsep , expr} , [argsep]] , ")"
|
||||
| ident , expr , {argsep , expr} , [argsep] ;
|
||||
kywd = ? words that exists on the list of predefined function that are not operators ? ;
|
||||
|
||||
(* don't bother looking at these, because you already know the stuff *)
|
||||
|
||||
argsep = "," | ";" ;
|
||||
ident = alph , [digits] ; (* variable and function names *)
|
||||
lit = alph , [digits] | num | string ; (* ident + numbers and string literals *)
|
||||
op = "^" | "*" | "/" | "MOD" | "+" | "-" | "<<" | ">>" | "<" | ">" | "<="
|
||||
| "=<" | ">=" | "=>" | "==" | "<>" | "><" | "BAND" | "BXOR" | "BOR"
|
||||
| "AND" | "OR" | "TO" | "STEP" | "!" | "~" | "#" | "=" ;
|
||||
op_uni = "-" | "+" ;
|
||||
|
||||
alph = letter | letter , alph ;
|
||||
digits = digit | digit , digits ;
|
||||
hexdigits = hexdigit | hexdigit , hexdigits ;
|
||||
bindigits = bindigit | bindigit , bindigits ;
|
||||
num = digits | digits , "." , [digits] | "." , digits
|
||||
| ("0x"|"0X") , hexdigits
|
||||
| ("0b"|"0B") , bindigits ; (* sorry, no e-notation! *)
|
||||
visible = ? ASCII 0x20 to 0x7E ? ;
|
||||
string = '"' , (visible | visible , stringlit) , '"' ;
|
||||
|
||||
letter = "A" | "B" | "C" | "D" | "E" | "F" | "G"
|
||||
| "H" | "I" | "J" | "K" | "L" | "M" | "N"
|
||||
| "O" | "P" | "Q" | "R" | "S" | "T" | "U"
|
||||
| "V" | "W" | "X" | "Y" | "Z" | "a" | "b"
|
||||
| "c" | "d" | "e" | "f" | "g" | "h" | "i"
|
||||
| "j" | "k" | "l" | "m" | "n" | "o" | "p"
|
||||
| "q" | "r" | "s" | "t" | "u" | "v" | "w"
|
||||
| "x" | "y" | "z" | "_" ;
|
||||
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
|
||||
hexdigit = "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b"
|
||||
| "c" | "d" | "e" | "f" | "0" | "1" | "2" | "3" | "4" | "5" | "6"
|
||||
| "7" | "8" | "9" ;
|
||||
bindigit = "0" | "1" ;
|
||||
|
||||
(* all possible token states: lit num op bool qot paren sep *)
|
||||
|
||||
IF (type: function, value: IF)
|
||||
1. cond
|
||||
2. true
|
||||
[3. false]
|
||||
|
||||
FOR (type: function, value: FOR)
|
||||
1. expr (normally (=) but not necessarily)
|
||||
|
||||
DEFUN (type: function, value: DEFUN)
|
||||
1. funcname
|
||||
1. arg0
|
||||
[2. arg1]
|
||||
[3. argN...]
|
||||
2. stmt
|
||||
|
||||
ON (type: function, value: ON)
|
||||
1. testvalue
|
||||
2. functionname (type: lit)
|
||||
3. arg0
|
||||
[4. arg1]
|
||||
[5. argN...]
|
||||
|
||||
FUNCTION_CALL (type: function, value: PRINT or something)
|
||||
1. arg0
|
||||
2. arg1
|
||||
[3. argN...]
|
||||
117
assets/tbas/doc/tokeniser.gv
Normal file
117
assets/tbas/doc/tokeniser.gv
Normal file
@@ -0,0 +1,117 @@
|
||||
digraph g {
|
||||
concentrate=true;
|
||||
splines=true;
|
||||
newrank=true;
|
||||
overlap=false;
|
||||
|
||||
LITERAL [shape=box]
|
||||
QUOTE [shape=box]
|
||||
PAREN [shape=box]
|
||||
SEP [shape=diamond]
|
||||
OPERATOR [shape=diamond]
|
||||
OPERATOR2 [shape=diamond] // needs second pass to rename it as "OPERATOR"
|
||||
NUMBER [shape=diamond]
|
||||
numbersep [style=filled]
|
||||
NUMBER2 [shape=diamond] // needs second pass to rename it as "NUMBER"
|
||||
limbo [style=filled]
|
||||
escape [style=filled]
|
||||
quote_end [style=filled]
|
||||
start [shape=Mdiamond]
|
||||
error [shape=Msquare,style=filled]
|
||||
|
||||
|
||||
subgraph clusternum {
|
||||
shape=none;
|
||||
NUMBER; NUMBER2; numbersep;
|
||||
}
|
||||
|
||||
subgraph clusterops {
|
||||
shape=none;
|
||||
OPERATOR; OPERATOR2;
|
||||
}
|
||||
|
||||
|
||||
start -> LITERAL
|
||||
|
||||
LITERAL -> QUOTE [label="\""]
|
||||
LITERAL -> PAREN [label="()[]"]
|
||||
LITERAL -> limbo [label=_]
|
||||
LITERAL -> SEP [label=","]
|
||||
LITERAL -> OPERATOR [label="^*/+->=<"]
|
||||
LITERAL -> LITERAL [label=otherwise]
|
||||
|
||||
NUMBER -> NUMBER [label="0..9_"]
|
||||
NUMBER -> numbersep [label="xXbB."]
|
||||
NUMBER -> QUOTE [label="\""]
|
||||
NUMBER -> limbo [label=" "]
|
||||
NUMBER -> PAREN [label="()[]"]
|
||||
NUMBER -> SEP [label=","]
|
||||
NUMBER -> OPERATOR [label="^*/+->=<"]
|
||||
NUMBER -> LITERAL [label=otherwise]
|
||||
|
||||
numbersep -> NUMBER2 [label="0..9_"]
|
||||
numbersep -> error [label=otherwise]
|
||||
|
||||
NUMBER2 -> NUMBER2 [label="0..9_"]
|
||||
NUMBER2 -> QUOTE [label="\""]
|
||||
NUMBER2 -> limbo [label=" "]
|
||||
NUMBER2 -> PAREN [label="()[]"]
|
||||
NUMBER2 -> SEP [label=","]
|
||||
NUMBER2 -> OPERATOR [label="^*/+->=<"]
|
||||
NUMBER2 -> LITERAL [label=otherwise]
|
||||
|
||||
OPERATOR -> OPERATOR2 [label=">=<"]
|
||||
OPERATOR -> error [label="^*/+-"]
|
||||
OPERATOR -> NUMBER [label="0..9"]
|
||||
OPERATOR -> QUOTE [label="\""]
|
||||
OPERATOR -> limbo [label=" "]
|
||||
OPERATOR -> PAREN [label="()[]"]
|
||||
OPERATOR -> SEP [label=","]
|
||||
OPERATOR -> LITERAL [label=otherwise]
|
||||
|
||||
OPERATOR2 -> error [label="^*/+->=<"]
|
||||
OPERATOR2 -> NUMBER [label="0..9"]
|
||||
OPERATOR2 -> QUOTE [label="\""]
|
||||
OPERATOR2 -> limbo [label=" "]
|
||||
OPERATOR2 -> PAREN [label="()[]"]
|
||||
OPERATOR2 -> SEP [label=","]
|
||||
OPERATOR2 -> LITERAL [label=otherwise]
|
||||
|
||||
QUOTE -> quote_end [label="\""]
|
||||
QUOTE -> escape [label="\\"]
|
||||
QUOTE -> QUOTE [label=otherwise]
|
||||
|
||||
escape -> QUOTE [label=any]
|
||||
|
||||
quote_end -> limbo [label=_]
|
||||
quote_end -> QUOTE [label="\""]
|
||||
quote_end -> PAREN [label="()[]"]
|
||||
quote_end -> SEP [label=","]
|
||||
quote_end -> NUMBER [label="0..9"]
|
||||
quote_end -> OPERATOR [label="^*/+->=<"]
|
||||
quote_end -> LITERAL [label=otherwise]
|
||||
|
||||
limbo -> limbo [label=_]
|
||||
limbo -> QUOTE [label="\""]
|
||||
limbo -> PAREN [label="()[]"]
|
||||
limbo -> SEP [label=","]
|
||||
limbo -> NUMBER [label="0..9"]
|
||||
limbo -> OPERATOR [label="^*/+->=<"]
|
||||
limbo -> LITERAL [label=otherwise]
|
||||
|
||||
PAREN -> limbo [label=_]
|
||||
PAREN -> QUOTE [label="\""]
|
||||
PAREN -> PAREN [label="()[]"]
|
||||
PAREN -> SEP [label=","]
|
||||
PAREN -> NUMBER [label="0..9"]
|
||||
PAREN -> OPERATOR [label="^*/+->=<"]
|
||||
PAREN -> LITERAL [label=otherwise]
|
||||
|
||||
SEP -> limbo [label=_]
|
||||
SEP -> QUOTE [label="\""]
|
||||
SEP -> PAREN [label="()[]"]
|
||||
SEP -> SEP [label=","]
|
||||
SEP -> NUMBER [label="0..9"]
|
||||
SEP -> OPERATOR [label="^*/+->=<"]
|
||||
SEP -> LITERAL [label=otherwise]
|
||||
}
|
||||
Reference in New Issue
Block a user