I have developed the code in parallel in two different BASICs so for comparison and if you want to try a translation...
Here is SmallBASIC version of SNH Interpreter:
'SNH Interpreter.bas for SmallBASIC 0.12.9 (B+=MGA) 2017-07-31
' Strings Now Handled
CONST CHARWIDTH = TXTW("W")
CONST CELLSPERLINE = XMAX/CHARWIDTH
memsize = 20000
DIM m$(memsize)
numChars = "-.1234567890"
cmdChars = "W?ABCDFMIENP[X]%^/*~+=<>()!&|"
allChars = numChars + cmdChars
WHILE 1
CLS
anyfile = FILES("*SNH.txt")
? "SNH (Strings Now Handled) Files:":?
IF LEN(anyfile) > 0 THEN
FOR i = 0 TO ubound(anyfile)
? i, anyfile(i)
NEXT
? : INPUT "number > files quits, Enter file NUMBER to run (any else quits) > ", flnm
IF ISNUMBER(flnm) AND flnm >= 0 AND flnm <= UBOUND(anyfile)
getfile = anyfile(flnm)
TLOAD getfile, source, 1
CLS : runSource
ELSE
STOP
END IF
ELSE
? "Sorry, no files to run, press any..." : STOP
END IF
WEND
SUB runSource 'NOTE watch out for locals!
ERASE m$
DIM m$(memsize)
'note: anything above first {}
bs = INSTR(source, "{") : be = INSTR(bs + 1, source, "}")
WHILE bs AND be
ix = VAL(MID(source, bs + 1, be - bs - 1))
IF ix < 1 THEN EXIT LOOP
bs = INSTR(be + 1, source, "{")
ti = MID(source, be + 1, bs - be - 1)
tEnd = INSTR(ti, ";")
IF tEnd = 0 THEN ? "Missing ; for {";ix;"}." : PAUSE : EXIT SUB
ti = MID(ti, 1, tEnd - 1)
m$(ix) = ti
be = INSTR(bs + 1, source, "}")
IF be = 0 THEN ? "Unmatched { } pairs." : PAUSE : EXIT SUB
WEND
source = MID(source, be + 1)
source = UCASE(source)
'? "Source after {}:"
'let's clean the code up, check bracket balance
bktCnt = 0 : ifCnt = 0 : code = ""
FOR i = 1 TO LEN(source)
char = MID(source, i, 1)
'check to see if this is a valid instruction character
IF INSTR(allChars, char) THEN
code = code + char
'count brackets
IF char = "[" THEN bktCnt = bktCnt + 1
IF char = "]" THEN bktCnt = bktCnt - 1
if char = "I" Then ifCnt = ifCnt + 1
if char = "N" then ifCnt = ifCnt - 1
END IF
NEXT
IF bktCnt THEN 'mismatched brackets
? "Uneven brackets" : PAUSE : EXIT SUB
ELSEIF ifCnt THEN
? "Uneven I N counts" : PAUSE : EXIT SUB
ELSE
'? code 'check
END IF
cmd = "" : ds = "" : err = ""
FOR i = 1 TO LEN(code) 'loop through the code
c = MID(code, i, 1) 'get the instruction we're on
IF INSTR("-.1234567890", c) THEN ds = ds + c
IF INSTR(cmdChars, c) OR i = len(code) THEN 'hit next command or end
IF cmd <> "" THEN 'execute unfinished command
d = VAL(ds)
'exec last cmd
SELECT CASE cmd
CASE "A" : m$(1) = m$(d)
CASE "B" : m$(2) = m$(d)
CASE "C" : m$(3) = m$(d)
CASE "D" : m$(4) = m$(d)
CASE "F"
SELECT CASE m$(1) 'the function name m$(2) 1st para...
CASE "NOT" : IF VAL(m$(2)) <> 0 THEN m$(d) = "0" ELSE m$(d) = "1"
CASE "RND" : m$(d) = STR(RND)
CASE "INT" : m$(d) = STR(INT(VAL(m$(2))))
CASE "CTR": spacesNeeded = (CELLSPERLINE - LEN(m$(2)))/2
? SPACE(spacesNeeded) + m$(2);
CASE "CLS": CLS
CASE "COLOR": COLOR VAL(m$(2)), VAL(m$(3))
CASE "LEN": m$(d) = STR(LEN(m$(2)))
CASE "MID1": m$(d) = MID(m$(2), VAL(m$(3)))
CASE "MID2": m$(d) = MID(m$(2), VAL(m$(3)), VAL(m$(4)))
CASE "INSTR1": m$(d) = STR(INSTR(m$(2), m$(3)))
CASE "INSTR2": m$(d) = STR(INSTR(VAL(m$(2)), m$(3), m$(4)))
CASE "LOCATE": LOCATE VAL(m$(2)), VAL(m$(3))
END SELECT
CASE "M" : m$(d) = m$(0)
CASE "W" : ? m$(d);
CASE "?" : INPUT test
IF ISNUMBER(test) THEN test = STR(test)
m$(d) = test
END SELECT
cmd = "" : ds = ""
END IF 'if cmd <> ""
'handle current cmd
IF INSTR("ABCDFMW?", c) THEN 'get d first
cmd = c
ELSEIF c = "I" : IF m$(0) = 0 then Findi
IF err <> "" THEN ? err : PAUSE : EXIT SUB
ELSEIF c = "E" THEN
Findi
IF err <> "" THEN ? err : PAUSE : EXIT SUB
ELSEIF c = "P" THEN
?
ELSEIF c = "X" THEN
bktCnt = 1 'count the bracket we're on
i = i + 1 'move the code pointer to the next char
WHILE bktCnt <> 0
'count nested loops till we find the matching one
IF MID(code, i, 1) = "]" THEN bktCnt = bktCnt - 1
IF MID(code, i, 1) = "[" THEN bktCnt = bktCnt + 1
i = i + 1 'search forward
WEND
i = i - 1
ELSEIF c = "]" THEN ' end a loop if loop index is 0
bktCnt = -1 'count the bracket we're on
i = i - 1 'move the code pointer back a char
WHILE bktCnt <> 0
'count nested loops till we fine the matching one
IF MID(code, i, 1) = "]" THEN bktCnt = bktCnt - 1
IF MID(code, i, 1) = "[" THEN bktCnt = bktCnt + 1
i = i - 1 'search backwards
WEND
i = i + 1
ELSEIF c = "%" THEN : m$(0) = STR(VAL(m$(1)) % VAL(m$(2)))
ELSEIF c = "^" THEN : m$(0) = STR(VAL(m$(1)) ^ Val(m$(2)))
ELSEIF c = "/" THEN : m$(0) = STR(VAL(m$(1)) / VAL(m$(2)))
ELSEIF c = "*" THEN : m$(0) = STR(VAL(m$(1)) * VAL(m$(2)))
ELSEIF c = "~" THEN : m$(0) = STR(VAL(m$(1)) - VAL(m$(2)))
ELSEIF c = "+" THEN : m$(0) = STR(VAL(m$(1)) + VAL(m$(2)))
ELSEIF c = "=" THEN : m$(0) = STR(VAL(m$(1)) = VAL(m$(2)))
ELSEIF c = "<" THEN : m$(0) = STR(VAL(m$(1)) < VAL(m$(2)))
ELSEIF c = ">" THEN : m$(0) = STR(VAL(m$(1)) > VAL(m$(2)))
ELSEIF c = "(" THEN : m$(0) = STR(VAL(m$(1)) <= VAL(m$(2)))
ELSEIF c = ")" THEN : m$(0) = STR(VAL(m$(1)) >= VAL(m$(2)))
ELSEIF c = "!" THEN : m$(0) = STR(VAL(m$(1)) <> VAL(m$(2)))
ELSEIF c = "&" THEN : m$(0) = STR(VAL(m$(1)) AND VAL(m$(2)))
ELSEIF c = "|" THEN : m$(0) = STR(VAL(m$(1)) OR VAL(m$(2)))
END IF
END IF ' ran into next command
'? mid(code, i, 1); :input temp
NEXT
?:? "Run is done, hit any..." : PAUSE
END SUB
SUB Findi
'code, i, err are global
LOCAL cnt, c1, j
cnt = 1
FOR j = i + 1 TO LEN(code)
c1 = MID(code, j, 1)
IF c1 = "N" THEN
cnt = cnt - 1
IF cnt = 0 THEN i = j : EXIT SUB
ELSEIF c1 = "I" THEN
cnt = cnt + 1
ELSEIF c1 = "E" and cnt = 1 THEN
i = j : EXIT SUB
END IF
NEXT
err = "Could not find N"
END SUB
And here is the QB64 v1,1 (Walter's fork) version:
'SNH Interpreter.bas for QB64 fork (B+=MGA) 2017-08-01 trans
RANDOMIZE TIMER
_TITLE "Strings Now Hamdled, the SNH Interpreter (tiny)"
SCREEN 12: COLOR 7, 0: CLS
'for directory stuff
CONST ListMAX% = 20
COMMON SHARED dirList$()
COMMON SHARED DIRCount% 'returns file count if desired
DIM dirList$(ListMAX%)
CONST numChars$ = "-.1234567890"
CONST cmdChars$ = "W?ABCDFMIENP[X]%^/*~+=><()!&|"
CONST allChars$ = numChars$ + cmdChars$
CONST memsize% = 20000
COMMON SHARED m$()
COMMON SHARED source$, code$, err$
DIM m$(memsize%)
NotBeenHere% = 1
'PRINT "COMMAND$ = "; COMMAND$
'INPUT "OK, press enter "; temp$
WHILE 1
source$ = ""
COLOR 7, 0: CLS
ERASE dirList$
DIM dirList$(ListMAX%)
loadDirList "*SNH.txt"
IF _FILEEXISTS(COMMAND$) AND RIGHT$(UCASE$(COMMAND$), 7) = "SNH.TXT" AND NotBeenHere% = 1 THEN
filename$ = COMMAND$: NotBeenHere% = 0
ELSEIF DIRCount% THEN
FOR i% = 1 TO DIRCount%
PRINT i%, dirList$(i%)
NEXT
PRINT: INPUT "0 quits, Enter line number of SNH Filename you desire "; ln%
IF ln% < 1 OR ln% > DIRCount% THEN END
filename$ = dirList$(ln%)
ELSE
PRINT "No *SNH.txt files found."
SLEEP: END
END IF
OPEN filename$ FOR INPUT AS #1
DO
LINE INPUT #1, fline$
source$ = source$ + fline$
'PRINT fline$
'INPUT " OK, enter"; temp$
LOOP UNTIL EOF(1)
CLOSE #1
runSource
WEND
SUB runSource
ERASE m$
DIM m$(memsize%)
'note: anything above first {} is comment and ignored
'First get m$ (string memory array) loaded with data values
FOR i% = 1 TO LEN(source$)
c$ = MID$(source$, i%, 1)
IF c$ = "{" THEN
bs% = i%
WHILE MID$(source$, i%, 1) <> "}"
i% = i% + 1
IF i% = LEN(source$) THEN PRINT "Missing }": SLEEP: EXIT SUB
WEND
ix% = VAL(MID$(source$, bs% + 1, i% - bs% - 1))
IF ix% < 1 THEN EXIT FOR
b$ = "": i% = i% + 1
WHILE MID$(source$, i%, 1) <> ";"
b$ = b$ + MID$(source$, i%, 1)
i% = i% + 1
IF i% = LEN(source$) THEN PRINT "Missing ending ;": SLEEP: EXIT SUB
WEND
m$(ix%) = b$
END IF
NEXT
source$ = MID$(source$, i% + 1)
'OK now letters, digits or symbols from strings wont interfere with program code
source$ = UCASE$(source$)
'let's clean the code up, check bracket balance
bktCnt% = 0: ifCnt% = 0: code$ = ""
FOR i = 1 TO LEN(source$)
char$ = MID$(source$, i, 1)
'check to see if this is a valid instruction character
IF INSTR(allChars$, char$) THEN
code$ = code$ + char$
'count brackets
IF char$ = "[" THEN bktCnt% = bktCnt% + 1
IF char$ = "]" THEN bktCnt% = bktCnt% - 1
IF char$ = "I" THEN ifCnt% = ifCnt% + 1
IF char$ = "N" THEN ifCnt% = ifCnt% - 1
END IF
NEXT
PRINT "Code check: "; code$
IF bktCnt% THEN 'mismatched brackets
PRINT "Uneven brackets": SLEEP: EXIT SUB
ELSEIF ifCnt% THEN
PRINT "Uneven I N counts": SLEEP: EXIT SUB
ELSE
PRINT code$ 'check
INPUT "OK, press enter... "; temp$
CLS
END IF
cmd$ = "": ds$ = "": err$ = ""
FOR i% = 1 TO LEN(code$) 'loop through the code
c$ = MID$(code$, i%, 1) 'get the instruction we're on
IF INSTR("-.1234567890", c$) THEN ds$ = ds$ + c$
IF INSTR(cmdChars$, c$) OR i% = LEN(code$) THEN 'hit next command or end
IF cmd$ <> "" THEN 'execute unfinished command
d# = VAL(ds$)
'exec last cmd
SELECT CASE cmd$
CASE "A": m$(1) = m$(d#)
CASE "B": m$(2) = m$(d#)
CASE "C": m$(3) = m$(d#)
CASE "D": m$(4) = m$(d#)
CASE "F"
SELECT CASE m$(1) 'the function name m$(2) 1st para...
CASE "NOT": IF VAL(m$(2)) = 0 THEN m$(d#) = "-1" ELSE m$(d#) = "0"
CASE "RND": m$(d#) = STR$(RND)
CASE "INT": m$(d#) = STR$(INT(VAL(m$(2))))
CASE "CTR": LOCATE CSRLIN, (80 - LEN(m$(2))) / 2: PRINT m$(2);
CASE "CLS": CLS
CASE "COLOR": COLOR VAL(m$(2)), VAL(m$(3))
CASE "LEN": m$(d#) = STR$(LEN(m$(2)))
CASE "MID1": m$(d#) = MID$(m$(2), VAL(m$(3)))
CASE "MID2": m$(d#) = MID$(m$(2), VAL(m$(3)), VAL(m$(4)))
CASE "INSTR1": m$(d#) = STR$(INSTR(m$(2), m$(3)))
CASE "INSTR2": m$(d#) = STR$(INSTR(VAL(m$(2)), m$(3), m$(4)))
CASE "LOCATE": LOCATE VAL(m$(2)), VAL(m$(3))
END SELECT
CASE "M": m$(d#) = m$(0)
CASE "W": PRINT m$(d#);
CASE "?": INPUT m$(d#)
END SELECT
cmd$ = "": ds$ = ""
END IF 'if cmd <> ""
'handle current cmd
IF INSTR("ABCDFMW?", c$) THEN
cmd$ = c$
ELSEIF c$ = "I" THEN
IF VAL(m$(0)) = 0 THEN i% = Findi(i%)
IF err$ <> "" THEN PRINT err$: SLEEP: EXIT SUB
ELSEIF c$ = "E" THEN
i% = Findi(i%)
IF err$ <> "" THEN PRINT err$: SLEEP: EXIT SUB
ELSEIF c$ = "P" THEN
PRINT
ELSEIF c$ = "X" THEN
bktCnt% = 1 'count the bracket we're on
i% = i% + 1 'move the code pointer to the next char
WHILE bktCnt% <> 0
'count nested loops till we find the matching one
IF MID$(code$, i%, 1) = "]" THEN bktCnt% = bktCnt% - 1
IF MID$(code$, i%, 1) = "[" THEN bktCnt% = bktCnt% + 1
i% = i% + 1 'search forward
WEND
i% = i% - 1%
ELSEIF c$ = "]" THEN ' end a loop if loop index is 0
bktCnt% = -1 'count the bracket we're on
i% = i% - 1 'move the code pointer back a char
WHILE bktCnt% <> 0
'count nested loops till we fine the matching one
IF MID$(code$, i%, 1) = "]" THEN bktCnt% = bktCnt% - 1
IF MID$(code$, i%, 1) = "[" THEN bktCnt% = bktCnt% + 1
i% = i% - 1 'search backwards
WEND
i% = i% + 1
ELSEIF c$ = "%" THEN: m$(0) = STR$(VAL(m$(1)) MOD VAL(m$(2)))
ELSEIF c$ = "^" THEN: m$(0) = STR$(VAL(m$(1)) ^ VAL(m$(2)))
ELSEIF c$ = "/" THEN: m$(0) = STR$(VAL(m$(1)) / VAL(m$(2)))
ELSEIF c$ = "*" THEN: m$(0) = STR$(VAL(m$(1)) * VAL(m$(2)))
ELSEIF c$ = "~" THEN: m$(0) = STR$(VAL(m$(1)) - VAL(m$(2)))
ELSEIF c$ = "+" THEN: m$(0) = STR$(VAL(m$(1)) + VAL(m$(2)))
ELSEIF c$ = "=" THEN: m$(0) = STR$(VAL(m$(1)) = VAL(m$(2)))
ELSEIF c$ = "<" THEN: m$(0) = STR$(VAL(m$(1)) < VAL(m$(2)))
ELSEIF c$ = ">" THEN: m$(0) = STR$(VAL(m$(1)) > VAL(m$(2)))
ELSEIF c$ = "(" THEN: m$(0) = STR$(VAL(m$(1)) <= VAL(m$(2)))
ELSEIF c$ = ")" THEN: m$(0) = STR$(VAL(m$(1)) >= VAL(m$(2)))
ELSEIF c$ = "!" THEN: m$(0) = STR$(VAL(m$(1)) <> VAL(m$(2)))
ELSEIF c$ = "&" THEN
IF VAL(m$(1)) <> 0 AND VAL(m$(2)) <> 0 THEN m$(0) = "-1" ELSE m$(0) = "0"
ELSEIF c$ = "|" THEN
IF VAL(m$(1)) <> 0 OR VAL(m$(2)) <> 0 THEN m$(0) = "-1" ELSE m$(0) = "0"
END IF ' ran into next command
END IF
NEXT
PRINT: INPUT "Run is done, enter to continue..."; temp$
END SUB
FUNCTION Findi% (i%)
cnt% = 1
FOR j% = i% + 1 TO LEN(code$)
c1$ = MID$(code$, j%, 1)
IF c1$ = "N" THEN
cnt% = cnt% - 1
IF cnt% = 0 THEN Findi% = j%: EXIT FUNCTION
ELSEIF c1$ = "I" THEN
cnt% = cnt% + 1
ELSEIF c1$ = "E" AND cnt% = 1 THEN
Findi% = j%: EXIT SUB
END IF
NEXT
err$ = "Could not find N"
END FUNCTION
' modified function from Help files
SUB loadDirList (spec$)
CONST TmpFile$ = "DIR$INF0.INF"
IF spec$ > "" THEN 'get file names when a spec is given
SHELL _HIDE "DIR " + spec$ + " /b > " + TmpFile$
Index% = 0: dirList$(Index%) = "": ff% = FREEFILE
OPEN TmpFile$ FOR APPEND AS #ff%
size& = LOF(ff%)
CLOSE #ff%
IF size& = 0 THEN KILL TmpFile$: EXIT SUB
OPEN TmpFile$ FOR INPUT AS #ff%
DO WHILE NOT EOF(ff%) AND Index% < ListMAX%
Index% = Index% + 1
LINE INPUT #ff%, dirList$(Index%)
LOOP
DIRCount% = Index% 'SHARED variable can return the file count
CLOSE #ff%
KILL TmpFile$
ELSE IF Index% > 0 THEN Index% = Index% - 1 'no spec sends next file name
END IF
END SUB
A Just Basic version might be fun with the GUI text editor control for editing and running in completely contained environment.