Microsoft Small Basic

Program Listing: VMW773
' Variable Simulator
' Version 0.1
' Copyright © 2016 Nonki Takahashi. The MIT License.
' Last update 2016-08-08

GraphicsWindow.Title = "Variable Simulator 0.1"
gw = 598
gh = 428
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.BackgroundColor = "LightGray"
CR = Text.GetCharacter(13)
LF = Text.GetCharacter(10)
WQ = Text.GetCharacter(34)
Not = "False=True;True=False;"
GraphicsWindow.BrushColor = "Black"
cmdbox = Controls.AddMultiLineTextBox(10, 10)
Controls.SetSize(cmdbox, 240, 38)
Controls.AddButton("RUN", gw / 2 - 42, 16)
histbox = Controls.AddMultiLineTextBox(10, 58)
Controls.SetSize(histbox, (gw - 30) / 2, gh - 68)
buttonClicked = "False"
Controls.ButtonClicked = OnButtonClicked

While "True"
If buttonClicked Then
cmd = Controls.GetTextBoxText(cmdbox)
CommandsToLine()
For j = 1 TO nLine
buf = line[j]
ParseCommand()
EndFor
history = history + cmd + CR + LF
Controls.SetTextBoxText(histbox, history)
buttonClicked = "False"
Else
Program.Delay(300)
EndIf
EndWhile

Sub CommandsToLine
p = 1
nLine = 0
eol = Text.GetIndexOf(Text.GetSubTextToEnd(cmd, p), CR)
While 0 < eol
nLine = nLine + 1
line[nLine] = Text.GetSubText(cmd, p, eol - 1)
If Text.GetSubTextToEnd(cmd, p + eol - 1) = LF Then
p = p + eol + 1
Else
p = p + eol
EndIf
eol = Text.GetIndexOf(Text.GetSubTextToEnd(cmd, p), LF)
EndWhile
If p < Text.GetLength(cmd) Then
nLine = nLine + 1
line[nLine] = Text.GetSubTextToEnd(cmd, p)
EndIf
EndSub

Sub OnButtonClicked
buttonClicked = "True"
EndSub

Sub DumpVar
n = Array.GetItemCount(var)
index = Array.GetAllIndices(var)
x = gw / 2 + 5
y = 10
For i = 1 To n
val = var[index[i]]
If val = "∅" Then
val = ""
EndIf
If name[i] = "" Then
name[i] = Shapes.AddText(index[i])
Shapes.Move(name[i], x, y + 3)
Else
Shapes.SetText(name[i], index[i])
EndIf
If vbox[i] = "" Then
vbox[i] = Controls.AddTextBox(x + 50, y)
Controls.SetSize(vbox[i], gw / 2 - 65, 20)
EndIf
Controls.SetTextBoxText(vbox[i], val)
y = y + 25
EndFor
While name[i] <> ""
Shapes.Remove(name[i])
Controls.Remove(vbox[i])
i = i + 1
EndWhile
EndSub

Sub LexCharacter
' param buf - buffer
' param p - pointer to the buffer
' return char
' return match
char = Text.GetSubText(buf, p, 1)
If char = WQ Then
match = "False"
Else
p = p + 1
match = "True"
EndIf
EndSub

Sub LexSkipSpace
' param buf - buffer
' param p - pointer to the buffer
While Text.GetSubText(buf, p, 1) = " "
p = p + 1
EndWhile
EndSub

Sub LexSymbol
' param symbol - symbol to get
' param buf - buffer
' param p - pointer to the buffer
' return match
If Text.GetSubText(buf, p, 1) = symbol Then
p = p + 1
match = "True"
Else
match = "False"
EndIf
EndSub

Sub ParseAddOperator
' add_operator = "+" | "-".
' return op - operator
' return match - "True" if match
op = Text.GetSubText(buf, p, 1)
If Text.IsSubText("+-", op) Then
match = "True"
p = p + 1
Else
match = "False"
EndIf
EndSub

Sub ParseAssignment
' assignment = designator ␣ "=" ␣ expression.
' return name - designator
' return value - value of the expression
pSave = p
ParseDesignator()
If match Then
LexSkipSpace()
symbol = "="
LexSymbol()
EndIf
If match Then
LexSkipSpace()
ParseExpression()
EndIf
If Not[match] Then
p = pSave
EndIf
EndSub

Sub ParseCommand
' command = ␣ assignment ␣ | ␣ expression ␣
' param buf - buffer
' return p - pointer to the buffer
' return len - length of the buffer
' return match - "True" if match
p = 1
len = Text.GetLength(buf)
LexSkipSpace()
ParseAssignment()
If match Then
If indices <> "" Then
arry = var[id]
arry[indices] = value
var[id] = arry
Else
If value = "" Then
var[id] = "∅"
Else
var[id] = value
EndIf
EndIf
DumpVar()
Else
ParseExpression()
If match Then
var["ans"] = value
DumpVar()
EndIf
EndIf
EndSub

Sub ParseDesignator
' designator = identifier { ␣ "[" ␣ expression ␣ "]" ␣ }.
' return id - identifier
' return indices - array indices
ParseIdentifier()
If match Then
valid = "True"
Else
valid = "False"
EndIf
indices = ""
While match
LexSkipSpace()
symbol = "["
LexSymbol()
If match Then
LexSkipSpace()
ParseExpression()
EndIf
If match Then
LexSkipSpace()
symbol = "]"
LexSymbol()
EndIf
If match Then
LexSkipSpace()
indices = indices + "[" + value + "]"
indices = value
EndIf
EndWhile
If valid Then
match = "True"
EndIf
EndSub

Sub ParseDigit
' digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
' return digit - digit
' return match - "True" if match
digit = Text.GetSubText(buf, p, 1)
If Text.IsSubText("0123456789", digit) Then
match = "True"
p = p + 1
Else
match = "False"
EndIf
EndSub

Sub ParseExpression
' expression = { ␣ "-" ␣ } term { ␣ add_operator ␣ term }.
' return value - the value of the expression
' return match - "True" if match
' retrun value - value of the term
' return match - "True" if match
PushLocal()
LexSkipSpace()
sign = 1
symbol = "-"
LexSymbol()
While match
LexSkipSpace()
sign = -sign
LexSymbol()
EndWhile
LexSkipSpace()
ParseTerm()
If match Then
If sign = -1 Then
v[1] = sign * value
Else
v[1] = value
EndIf
valid = "True"
Else
valid = "False"
EndIf
While match
LexSkipSpace()
ParseAddOperator()
If match Then
LexSkipSpace()
ParseTerm()
v[2] = value
If op = "+" Then
v[1] = v[1] + v[2]
ElseIf op = "-" Then
v[1] = v[1] - v[2]
EndIf
EndIf
EndWhile
If valid Then
value = v[1]
match = "True"
EndIf
PopLocal()
EndSub

Sub ParseFactor
' factor = number | text | designator | "(" ␣ expression ␣ ")".
' return value - value of the factor
' return match - "True" if match
PushLocal()
ParseNumber()
If match Then
value = num
EndIf
If Not[match] Then
ParseText()
If match Then
value = txt
EndIf
EndIf
If Not[match] Then
ParseDesignator()
If match Then
If indices <> "" Then
arry = var[id]
value = arry[indices]
Else
value = var[id]
If value = "∅" Then
value = ""
EndIf
EndIf
EndIf
EndIf
If Not[match] Then
pSave = p
symbol = "("
LexSymbol()
If match Then
LexSkipSpace()
ParseExpression()
EndIf
If match Then
LexSkipSpace()
symbol = ")"
LexSymbol()
EndIf
If Not[match] Then
p = pSave
Else
EndIf
EndIf
PopLocal()
EndSub

Sub ParseIdentifier
' identifier = letter { letter | digit }.
' return id - identifier
' return match - "True" if match
id = ""
ParseLetter()
If match Then
id = letter
EndIf
While match
ParseLetter()
If match Then
id = id + letter
Else
ParseDigit()
If match Then
id = id + digit
EndIf
EndIf
Endwhile
If id <> "" Then
match = "True"
EndIf
EndSub

Sub ParseLetter
' letter = "A" | .. | "Z" | "a" | .. | "z" | "_" .
' return letter - letter
' return match - "True" if match
letter = Text.GetSubText(buf, p, 1)
If Text.IsSubText("ABCDEFGHIJKLMNOPQRSTUVWXYZ_", Text.ConvertToUpperCase(letter)) Then
match = "True"
p = p + 1
Else
match = "False"
EndIf
EndSub

Sub ParseMultiplyOperator
' multiply_operator = "*" | "/".
' return op - operator
' return match - "True" if match
op = Text.GetSubText(buf, p, 1)
If Text.IsSubText("*/", op) Then
match = "True"
p = p + 1
Else
match = "False"
EndIf
EndSub

Sub ParseNumber
' number = digit { digit } [ "." { digit } ].
' return num - number
' return match - "True" if match
num = ""
ParseDigit()
If match Then
num = digit
EndIf
While match
ParseDigit()
If match Then
num = Text.Append(num, digit)
EndIf
Endwhile
symbol = "."
LexSymbol()
If match Then
num = Text.Append(num, ".")
EndIf
While match
ParseDigit()
If match Then
num = Text.Append(num, digit)
EndIf
EndWhile
If num <> "" Then
match = "True"
EndIf
EndSub

Sub ParseTerm
' term = factor { ␣ multiply_operator ␣ factor }.
' retrun value - value of the term
' return match - "True" if match
PushLocal()
ParseFactor()
If match Then
v[1] = value
valid = "True"
Else
valid = "False"
EndIf
While match
pSave = p
LexSkipSpace()
ParseMultiplyOperator()
If match Then
LexSkipSpace()
ParseFactor()
If match Then
v[2] = value
If op = "*" Then
v[1] = v[1] * v[2]
ElseIf op = "/" Then
v[1] = v[1] / v[2]
EndIf
Else
p = pSave
EndIf
EndIf
EndWhile
If valid Then
match = "True"
value = v[1]
EndIf
PopLocal()
EndSub

Sub ParseText
' text = '"' { character } '"'.
' return txt - text
' return match - "True" if match
pSave = p
symbol = WQ
LexSymbol()
If match Then
txt = ""
quot = "True"
Else
quot = "False"
EndIf
While match
LexCharacter()
If match Then
txt = Text.Append(txt, char)
EndIf
EndWhile
If quot Then
symbol = WQ
LexSymbol()
If Not[match] Then
txt = ""
p = pSave
EndIf
EndIF
EndSub

Sub PopLocal
sign = Stack.PopValue("local")
indices = Stack.PopValue("local")
id = Stack.PopValue("local")
v = Stack.PopValue("local")
op = Stack.PopValue("local")
EndSub

Sub PushLocal
Stack.PushValue("local", op)
Stack.PushValue("local", v)
Stack.PushValue("local", id)
Stack.PushValue("local", indices)
Stack.PushValue("local", sign)
EndSub