Skip to content

Instantly share code, notes, and snippets.

@lifthrasiir
Created July 22, 2012 13:47
Show Gist options
  • Save lifthrasiir/3159760 to your computer and use it in GitHub Desktop.
Save lifthrasiir/3159760 to your computer and use it in GitHub Desktop.
UserScript: a forgotten programming language from the hell (2003)
BODY, P, LI, DD, DT { font:10pt Verdana; }
P { margin-left:40pt; margin-right:20pt; }
SMALL { font-style:italic; font-size:100%; }
A { color:blue; text-decoration:underline; }
A:visited { text-decoration:none ! important; }
A:hover { color:red; text-decoration:underline; }
H1 { margin-left:0pt; margin-right:0pt; padding-left:5pt; padding-right:5pt; border-bottom:#224466 solid 4pt; color:#336699; font-family:"Verdana"; letter-spacing:2px; }
H2 { margin-left:0pt; margin-right:0pt; padding-left:5pt; padding-right:5pt; border-bottom:#662244 solid 2pt; color:#993366; font-family:"Verdana"; letter-spacing:2px; }
H3 { margin-left:15pt; margin-right:5pt; padding-left:3pt; padding-right:3pt; border-bottom:#226644 solid 1.5pt; margin-bottom:0pt; color:#339966; font-family:"Verdana"; letter-spacing:1px; }
H4 { margin-left:25pt; margin-right:5pt; margin-bottom:0pt; color:#663399; font-family:"Verdana"; }
H1 SMALL { color:#99B3CC; }
H2 SMALL { color:#CC99B3; }
H3 SMALL { color:#99CCB3; }
H4 SMALL { color:#B399CC; }
UL { margin-left:50pt; margin-right:20pt; }
OL { margin-left:50pt; margin-right:20pt; }
LI { margin-top:5pt; }
DT { font-weight:bold; }
DL { margin-left:50pt; margin-right:20pt; }
DD { margin-left:30pt; }
CODE { font-family:"Lucida Console"; color:#000080; font-weight:bold; line-height:120%; }
CODE.result { font-family:"Lucida Console"; color:#008000; font-weight:bold; }
SPAN.warning { color:red; font-weight:bold; }
Attribute VB_Name = "mdlUserScript"
'###############################################################################
'## @@ @@ @@@@ @@ +++ +++ ##
'## @@ @@ @@@@ @@@@ @@ @@ @@ @@@@ @@ @@ @@ @@@@ @@@@ ++ ++ ++ ++ ##
'## @@ @@ @@@ @@@@@@ @@@@ @@@ @@ @@@@ @@ @@ @@ @@ ++ ++ ++ ##
'## @@ @@ @@@ @@ @@ @@ @@ @@ @@ @@@@ @@ ++ ++ ++ ++ ##
'##__@@@@__@@@@___@@@@__@@____@@@@___@@@@_@@____@@_@@______@@___+++__++_+++++_##
'## UserScript, for Break the Box @@ version 0.2.3 ##
'##===========================================================================##
'## Created by Tokigun <seitero@tokigun.net>, 2003/12/15 - 2003/12/22. ##
'## For more information, use usInformation() function please. :) ##
'###############################################################################
Option Explicit
'*******************************************************************************
'* Enumerations *
'*******************************************************************************
Private Enum usTokenEnum
T_UNDEFINED = 99 ' Undefined Tokens
T_NONE = 0 ' () Empty Parentheses
T_ENDLINE = -1 ' \r\n End of Statement
' Arithmetic Operators
T_PLUS = 1 ' + Addition
T_MINUS = 2 ' - Subtraction
T_TIMES = 3 ' * Multiplication
T_DIVIDE = 4 ' / Division
T_MODULOUS = 5 ' % Modulo
T_POWER = 6 ' ^ Involution
' Comparison Operators
T_EQUAL = 11 ' == Equality
T_INEQUAL = 12 ' != <> Inequality
T_GREATER = 13 ' > Greater than
T_GREATER_EQ = 14 ' >= => Equal to or Greater than
T_LESS = 15 ' < Less than
T_LESS_EQ = 16 ' <= =< Equal to or Less than
' Logical/Bitwise Operators
T_AND = 21 ' and Logical/Bitwise AND
T_OR = 22 ' or Logical/Bitwise OR
T_NOT = 23 ' not Logical/Bitwise NOT
' Unary Operators
T_POSITIVE = 24 ' + Unary Positive
T_NEGATIVE = 25 ' - Unary Negative (Complement)
T_PRE_INC = 26 ' ++ Pre-increment
T_POST_INC = 27 ' ++ Post-increment
T_PRE_DEC = 28 ' -- Pre-decrement
T_POST_DEC = 29 ' -- Post-decrement
' Comma/Assignment Operators
T_COMMA = 31 ' , Comma Operator for Function
T_ASSIGN = 32 ' = Assignment
T_PLUS_ASSIGN = 33 ' += Additive Assignment
T_MINUS_ASSIGN = 34 ' -= Subtractive Assignment
T_TIMES_ASSIGN = 35 ' *= Multiplicative Assignment
T_DIVIDE_ASSIGN = 36 ' /= Divisional Assignment
T_MODULOUS_ASSIGN = 37 ' %= Modulous Assignment
T_POWER_ASSIGN = 38 ' ^= Involutional Assignment
' Parentheses
T_LPARENT = 41 ' ( Left Parenthese
T_RPARENT = 42 ' ) Right Parenthese
T_LBRACKET = 43 ' [ Left Bracket
T_RBRACKET = 44 ' ] Right Bracket
T_LBRACE = 45 ' { Left Brace
T_RBRACE = 46 ' } Right Brace
' Special Tokens
T_FUNCTION = 51 ' abs() Function
T_NUMBER = 52 ' 123 Number
T_VARIABLE = 53 ' $TEMP Variable
T_COMMENT = 54 ' // Comment (never used)
' Statement Tokens
T_IF = 61 ' if() Conditional Statement (IF)
T_ELSE = 62 ' else Conditional Statement (ELSE)
T_DO = 63 ' do() Repetitive Statement (DO)
End Enum
Private Enum usActionEnum
VA_EXIST = 0 ' Check that this variable is.
VA_GET = 1 ' Get the value of this variable.
VA_LET = 2 ' Let the value of this variable given value.
End Enum
Public Enum usInformationEnum
usISignal = 0 ' Module S/N
usIProgramName = 1 ' Program Name
usIProgramVersion = 2 ' Program Version
usIProgramBuild = 3 ' Program Build Number
usIAuthor = 4 ' Author
usIAuthorMail = 5 ' Author's E-Mail
usIAuthorSite = 6 ' Author's Website
usICopyright = 7 ' Copyright
usIDateTime = 8 ' Last Update
usIWebSite = 9 ' Program's Website
usIRCSID = 10 ' RCS ID (undefined!)
End Enum
Public Enum usErrorEnum
usESuccess = 0 ' Successfully Done.
' Syntax Error
usEUnknownCharacter = 1 ' There is unknown character. (ex. #)
usENonNested = 2 ' Parentheses aren't well-nested.
usENoOperand = 3 ' There is no operand for more than one operators.
usEOpenedComment = 4 ' Long comment (/*...*/) isn't closed.
usEOpenedStatement = 5 ' There is no statement seperator (;).
usEInvalidSyntax = 6 ' There is invalid syntax.
usEUnknownBlock = 7 ' Block is not closed.
' Functions/Variables
usEUndefinedFunction = 11 ' This function is not.
usEWrongArgumentCount = 12 ' This function doesn't accept the number of arguments.
usEUndefinedVariable = 13 ' This variable is not.
usEReadOnlyVariable = 14 ' Can't write the variable in this variable.
usECantAssignToVariable = 15 ' This variable doesn't accept given value.
' Runtime Error
usEDivideByZero = 21 ' Script divided by zero.
usEZerothPowerOfZero = 22 ' Zeroth power of zero is undefined.
usEAssignToNonVariable = 23 ' Non-variable expression isn't assigned.
usEOverflow = 24 ' Number is too great.
usETimeout = 25 ' Script takes too long time.
' Special Error
usEEmpty = -1 ' This script contains no statement.
usEExitBlock = 100 ' Closest block is exited by this statement: exit()
usETerminateScript = 101 ' Script is terminated by this statement: end()
usEMatrixError = 102 ' Script can't accept this matrix: _error()
usEUndefined = 999 ' Undefined Error.
End Enum
'*******************************************************************************
'* UserScript-related Types *
'*******************************************************************************
Private Type usVariableType
Name As String
Value As Long
End Type
Private Type usBlockType
blockType As usTokenEnum
startPos As Integer
Counter As Long
limitCounter As Long
End Type
Private Type usTokenType
Token As usTokenEnum
Value As Variant
End Type
'*******************************************************************************
'* Constants *
'*******************************************************************************
Private Const spaceCharacters As String = " " & vbTab & vbCrLf
Private Const maximumLines As Long = 50000
'*******************************************************************************
'* Information Functions *
'*******************************************************************************
Public Function usInformation( _
ByVal WhatDoYouWant As usInformationEnum _
) As Variant
Const verMajor As Integer = 0
Const verMinor As Integer = 2
Const verAddition As Integer = 3
Const verBuild As Integer = 98
Const verTag As String = "-BTB"
Const lastUpdate As Date = 37977.4718634259
Select Case WhatDoYouWant
Case usISignal
usInformation = "TOK14000108-" & Format(verMajor * 10000 + verMinor * 100 + verAddition, "00000")
Case usIProgramName
usInformation = "UserScript"
Case usIProgramVersion
usInformation = "version " & verMajor & "." & verMinor & "." & verAddition & verTag
Case usIProgramBuild
usInformation = "Build " & verBuild
Case usIAuthor
usInformation = "Tokigun"
Case usIAuthorMail
usInformation = "seitero@tokigun.net"
Case usIAuthorSite
usInformation = "http://tokigun.net/"
Case usICopyright
usInformation = "Copyright (c) 2003, Tokigun. All rights reserved."
Case usIDateTime
usInformation = lastUpdate
Case usIWebSite
usInformation = "http://creation.tokigun.net/vb/userscript/"
Case usIRCSID
usInformation = _
"$Id: $" 'now undefined
Case Else
usInformation = Null
End Select
End Function
'*******************************************************************************
'* Utility Functions *
'*******************************************************************************
Private Function usIsSymbol( _
ByVal char As String, Optional ByVal isFirstChar As Boolean = False _
) As Boolean
If char = "" Then char = Chr(0)
usIsSymbol = ( _
((Asc(char) Or 32) > 96 And (Asc(char) Or 32) < 123) Or _
(Not isFirstChar And char >= "0" And char <= "9") Or _
char = "_" _
)
End Function
Private Function usIsNumeric( _
ByVal char As String _
) As Boolean
If char = "" Then char = Chr(0)
usIsNumeric = (char >= "0" And char <= "9")
End Function
Private Function usTrim( _
ByVal src As String _
) As String
Do While InStr(spaceCharacters, Left(src, 1)) > 0 And src <> ""
src = Mid(src, 2)
Loop
Do While InStr(spaceCharacters, Right(src, 1)) > 0 And src <> ""
src = Left(src, Len(src) - 1)
Loop
usTrim = src
End Function
Private Function usOperatorPrecedence( _
ByVal Token As usTokenEnum _
) As Integer
Select Case Token
Case T_PRE_INC, T_PRE_DEC, T_POST_INC, T_POST_DEC
usOperatorPrecedence = 1
Case T_POSITIVE, T_NEGATIVE, T_NOT
usOperatorPrecedence = 2
Case T_POWER
usOperatorPrecedence = 3
Case T_MODULOUS
usOperatorPrecedence = 4
Case T_TIMES, T_DIVIDE
usOperatorPrecedence = 5
Case T_PLUS, T_MINUS
usOperatorPrecedence = 6
Case T_GREATER, T_GREATER_EQ, T_LESS, T_LESS_EQ
usOperatorPrecedence = 7
Case T_EQUAL, T_INEQUAL
usOperatorPrecedence = 8
Case T_AND
usOperatorPrecedence = 9
Case T_OR
usOperatorPrecedence = 10
Case T_ASSIGN, T_PLUS_ASSIGN, T_MINUS_ASSIGN, T_TIMES_ASSIGN, T_DIVIDE_ASSIGN, _
T_MODULOUS_ASSIGN, T_POWER_ASSIGN
usOperatorPrecedence = 11
Case T_COMMA
usOperatorPrecedence = 12
Case T_LPARENT
usOperatorPrecedence = 100
Case T_FUNCTION
usOperatorPrecedence = 101
Case T_LBRACKET
usOperatorPrecedence = 0
Case Else
usOperatorPrecedence = -1
End Select
End Function
Private Function usIsEvaluatedToRight( _
ByVal Token As usTokenEnum _
) As Integer
Select Case Token
Case T_POSITIVE, T_NEGATIVE, T_NOT, T_ASSIGN, T_PLUS_ASSIGN, T_MINUS_ASSIGN, _
T_TIMES_ASSIGN, T_DIVIDE_ASSIGN, T_MODULOUS_ASSIGN, T_POWER_ASSIGN
usIsEvaluatedToRight = False
Case Else
usIsEvaluatedToRight = True
End Select
End Function
Private Function usIsUnaryOperator( _
ByVal Token As usTokenEnum _
) As Integer
Select Case Token
Case T_POSITIVE, T_NEGATIVE, T_NOT, T_FUNCTION, T_PRE_INC, T_PRE_DEC, _
T_POST_INC, T_POST_DEC
usIsUnaryOperator = True
Case Else
usIsUnaryOperator = False
End Select
End Function
Private Sub usPushNode( _
ByRef Node() As usTokenType, ByRef lNode As Integer, _
ByVal Token As usTokenEnum, ByVal Value As Variant _
)
ReDim Preserve Node(0 To lNode) As usTokenType
Node(lNode).Token = Token
Node(lNode).Value = Value
lNode = lNode + 1
End Sub
Private Function usPopNode( _
ByRef Node() As usTokenType, ByRef lNode As Integer, _
ByRef Token As usTokenEnum, ByRef Value As Variant _
) As Boolean
If lNode = 0 Then
usPopNode = False
Else
usPopNode = True
lNode = lNode - 1
Token = Node(lNode).Token
Value = Node(lNode).Value
If lNode > 0 Then
ReDim Preserve Node(0 To lNode) As usTokenType
End If
End If
End Function
Private Function usMatchingBlock( _
ByRef Tokens() As usTokenType, ByVal pos As Integer, _
Optional ByVal DestDepth As Integer = 0 _
) As Integer
Dim blockDepth As Integer, i As Integer
blockDepth = 0
If Tokens(pos).Token = T_LBRACE Then
For i = pos To UBound(Tokens)
If Tokens(i).Token = T_LBRACE Then
blockDepth = blockDepth + 1
ElseIf Tokens(i).Token = T_RBRACE Then
blockDepth = blockDepth - 1
End If
If blockDepth = DestDepth Then
usMatchingBlock = i
Exit Function
End If
Next
ElseIf Tokens(pos).Token = T_RBRACE Then
For i = pos To 0 Step -1
If Tokens(i).Token = T_RBRACE Then
blockDepth = blockDepth + 1
ElseIf Tokens(i).Token = T_LBRACE Then
blockDepth = blockDepth - 1
End If
If blockDepth = DestDepth Then
usMatchingBlock = i
Exit Function
End If
Next
End If
usMatchingBlock = -1
End Function
'*******************************************************************************
'* Tokenize Functions *
'*******************************************************************************
Private Function usTokenizeStatement( _
ByVal Expression As String, ByRef Result() As usTokenType _
) As usErrorEnum
Dim Stack() As usTokenType, lStack As Integer, lResult As Integer
Dim pos As Integer, prevOperator As Boolean, lastParenthese As Boolean
Dim tok As usTokenEnum, vtok As Variant, ptok As usTokenEnum, pvtok As Variant
Dim symbol As String, char As String
lStack = 0
lResult = 0
pos = 1
prevOperator = True
lastParenthese = False
Do While pos <= Len(Expression)
char = Mid(Expression, pos, 1)
If char = "(" Then
usPushNode Stack, lStack, T_LPARENT, 0
prevOperator = True
lastParenthese = True
pos = pos + 1
ElseIf char = ")" Or char = "]" Then
Do
If Not usPopNode(Stack, lStack, tok, vtok) Then
usTokenizeStatement = usENonNested
Exit Function
End If
If tok = T_LPARENT Or (char = ")" And tok = T_FUNCTION) Then Exit Do
usPushNode Result, lResult, tok, vtok
Loop
If lastParenthese Then
usPushNode Result, lResult, T_NONE, 0
End If
If tok = T_FUNCTION Then
usPushNode Result, lResult, tok, vtok
End If
prevOperator = False
lastParenthese = False
pos = pos + 1
ElseIf InStr("+-*/%^!<>=,", char) > 0 Then
tok = T_UNDEFINED
Select Case Mid(Expression, pos, 2)
Case "<=", "=<": tok = T_LESS_EQ
Case "=>", ">=": tok = T_GREATER_EQ
Case "==": tok = T_EQUAL
Case "!=", "<>", "><": tok = T_INEQUAL
Case "+=": tok = T_PLUS_ASSIGN
Case "-=": tok = T_MINUS_ASSIGN
Case "*=": tok = T_TIMES_ASSIGN
Case "/=": tok = T_DIVIDE_ASSIGN
Case "%=": tok = T_MODULOUS_ASSIGN
Case "^=": tok = T_POWER_ASSIGN
Case "++": tok = IIf(prevOperator, T_PRE_INC, T_POST_INC)
Case "--": tok = IIf(prevOperator, T_PRE_DEC, T_POST_DEC)
End Select
If tok = T_UNDEFINED Then
Select Case char
Case "+": tok = IIf(prevOperator, T_POSITIVE, T_PLUS)
Case "-": tok = IIf(prevOperator, T_NEGATIVE, T_MINUS)
Case "*": tok = T_TIMES
Case "/": tok = T_DIVIDE
Case "%": tok = T_MODULOUS
Case "^": tok = T_POWER
Case "<": tok = T_LESS
Case ">": tok = T_GREATER
Case "=": tok = T_ASSIGN
Case ",": tok = T_COMMA
Case Else
usTokenizeStatement = usEUnknownCharacter
Exit Function
End Select
pos = pos + 1
Else
pos = pos + 2
End If
Do
If Not usPopNode(Stack, lStack, ptok, pvtok) Then Exit Do
If _
usOperatorPrecedence(ptok) > usOperatorPrecedence(tok) Or _
(usOperatorPrecedence(ptok) = usOperatorPrecedence(tok) And _
Not usIsEvaluatedToRight(tok)) _
Then
usPushNode Stack, lStack, ptok, pvtok
Exit Do
End If
usPushNode Result, lResult, ptok, pvtok
Loop
usPushNode Stack, lStack, tok, 0
prevOperator = True
lastParenthese = False
ElseIf char = "$" Then
symbol = ""
Do
pos = pos + 1
char = Mid(Expression, pos, 1)
If Not usIsSymbol(char, symbol = "") Then Exit Do
symbol = symbol & char
Loop
Do While InStr(spaceCharacters, char) > 0 And char <> ""
pos = pos + 1
char = Mid(Expression, pos, 1)
Loop
If char = "[" Then
usPushNode Stack, lStack, T_LBRACKET, 0
usPushNode Stack, lStack, T_LPARENT, 0
usPushNode Result, lResult, T_VARIABLE, symbol
lastParenthese = True
pos = pos + 1
Else
usPushNode Result, lResult, T_VARIABLE, symbol
lastParenthese = False
End If
prevOperator = False
ElseIf usIsNumeric(char) Then
symbol = char
Do
pos = pos + 1
char = Mid(Expression, pos, 1)
If Not usIsNumeric(char) Then Exit Do
symbol = symbol & char
Loop
usPushNode Result, lResult, T_NUMBER, symbol
prevOperator = False
lastParenthese = False
ElseIf usIsSymbol(char, True) Then
symbol = char
Do
pos = pos + 1
char = Mid(Expression, pos, 1)
If Not usIsSymbol(char, False) Then Exit Do
symbol = symbol & char
Loop
tok = T_UNDEFINED
Select Case UCase(symbol)
Case "NOT": tok = T_NOT
Case "AND": tok = T_AND
Case "OR": tok = T_OR
Case "MOD": tok = T_MODULOUS
End Select
If tok = T_UNDEFINED Then
Do While InStr(spaceCharacters, char) > 0 And char <> ""
pos = pos + 1
char = Mid(Expression, pos, 1)
Loop
If char = "(" Then
usPushNode Stack, lStack, T_FUNCTION, symbol
lastParenthese = True
prevOperator = True
pos = pos + 1
Else
usPushNode Stack, lStack, T_UNDEFINED, symbol
lastParenthese = False
prevOperator = False
End If
Else
Do
If Not usPopNode(Stack, lStack, ptok, pvtok) Then Exit Do
If _
usOperatorPrecedence(ptok) > usOperatorPrecedence(tok) Or _
(usOperatorPrecedence(ptok) = usOperatorPrecedence(tok) And _
Not usIsEvaluatedToRight(tok)) _
Then
usPushNode Stack, lStack, ptok, pvtok
Exit Do
End If
usPushNode Result, lResult, ptok, pvtok
Loop
usPushNode Stack, lStack, tok, 0
lastParenthese = False
prevOperator = False
End If
ElseIf InStr(spaceCharacters, char) > 0 Then
pos = pos + 1
Else
usTokenizeStatement = usEUnknownCharacter
Exit Function
End If
Loop
Do While usPopNode(Stack, lStack, tok, vtok)
usPushNode Result, lResult, tok, vtok
Loop
If lResult = 0 Then
ReDim Preserve Result(0 To 0) As usTokenType
Result(0).Token = T_NONE: Result(0).Value = 0
usTokenizeStatement = usEEmpty
Else
usTokenizeStatement = usESuccess
End If
End Function
Private Function usTokenizeScript( _
ByVal Code As String, ByRef Result() As usTokenType _
) As usErrorEnum
Dim ScriptPos As Integer, ScriptLine() As String, ScriptLength As Integer, inComment As Integer
Dim CurrentLine As String, char As String, pchar As String, iError As usErrorEnum
Dim pResult() As usTokenType, lResult As Integer, lastToken As usTokenEnum, PrevSpecialToken As usTokenEnum
Dim vTemp As String, blockDepth As Integer, vIDepth As Integer, vIPos As Integer
Dim i As Integer, j As Integer
ScriptLength = 0
ScriptPos = 0
inComment = 0
CurrentLine = ""
char = ""
Do While ScriptPos <= Len(Code)
ScriptPos = ScriptPos + 1
pchar = char
char = Mid(Code, ScriptPos, 1)
If inComment = 1 Then
If char = vbCr Or char = vbLf Then inComment = 0
ElseIf inComment = 2 Then
If pchar & char = "*/" Then inComment = 0
ElseIf pchar & char = "//" Then
CurrentLine = Left(CurrentLine, Len(CurrentLine) - 1)
inComment = 1
ElseIf pchar & char = "/*" Then
CurrentLine = Left(CurrentLine, Len(CurrentLine) - 1)
inComment = 2
ElseIf char = ";" Then
ReDim Preserve ScriptLine(0 To ScriptLength) As String
ScriptLine(ScriptLength) = CurrentLine
ScriptLength = ScriptLength + 1
CurrentLine = ""
ElseIf char = "{" Or char = "}" Then
ReDim Preserve ScriptLine(0 To ScriptLength + 1) As String
ScriptLine(ScriptLength) = CurrentLine
ScriptLine(ScriptLength + 1) = char
ScriptLength = ScriptLength + 2
CurrentLine = ""
Else
CurrentLine = CurrentLine & char
End If
Loop
ReDim Preserve ScriptLine(0 To ScriptLength + 1) As String
ScriptLine(ScriptLength) = CurrentLine
ScriptLength = ScriptLength + 1
lResult = 0
blockDepth = 0
lastToken = T_UNDEFINED
For i = 0 To ScriptLength - 2
lastToken = T_UNDEFINED
ScriptLine(i) = usTrim(ScriptLine(i))
If ScriptLine(i) = "{" Or ScriptLine(i) = "}" Then
If ScriptLine(i) = "{" And PrevSpecialToken = T_UNDEFINED Then
usTokenizeScript = usEUnknownBlock
Exit Function
ElseIf ScriptLine(i) = "}" And blockDepth <= 0 Then
usTokenizeScript = usENonNested
Exit Function
End If
ReDim Preserve Result(0 To lResult + 1) As usTokenType
Result(lResult).Value = 0
Result(lResult).Token = IIf(ScriptLine(i) = "{", T_LBRACE, T_RBRACE)
Result(lResult + 1).Value = 0
Result(lResult + 1).Token = T_ENDLINE
lResult = lResult + 2
lastToken = T_UNDEFINED
blockDepth = blockDepth + IIf(ScriptLine(i) = "{", 1, -1)
ElseIf lastToken <> T_UNDEFINED Then
usTokenizeScript = usEInvalidSyntax
Exit Function
Else
vTemp = usTrim(Mid(ScriptLine(i), 3))
If Left(vTemp, 1) = "(" Then
Select Case UCase(Left(ScriptLine(i), 2))
Case "DO": lastToken = T_DO
Case "IF": lastToken = T_IF
End Select
If lastToken <> T_UNDEFINED Then ScriptLine(i) = vTemp
ElseIf UCase(ScriptLine(i)) = "DO" Then
lastToken = T_DO
ScriptLine(i) = ""
End If
vTemp = usTrim(Mid(ScriptLine(i), 5))
If vTemp = "" And UCase(ScriptLine(i)) = "ELSE" Then
lastToken = T_ELSE
ScriptLine(i) = ""
End If
If lastToken <> T_UNDEFINED And ScriptLine(i) <> "" Then
vIDepth = 0
For vIPos = 1 To Len(ScriptLine(i))
Select Case Mid(ScriptLine(i), vIPos, 1)
Case "(", "[": vIDepth = vIDepth + 1
Case ")", "]": vIDepth = vIDepth - 1
End Select
If vIDepth = 0 Then Exit For
Next
If vIPos <> Len(ScriptLine(i)) Or Mid(ScriptLine(i), vIPos, 1) <> ")" Then
usTokenizeScript = usENonNested
Exit Function
End If
End If
iError = usTokenizeStatement(ScriptLine(i), pResult)
If iError = usESuccess Then
vTemp = UBound(pResult) + IIf(lastToken = T_UNDEFINED, 1, 2)
ReDim Preserve Result(0 To lResult + vTemp) As usTokenType
For j = 0 To UBound(pResult)
Result(lResult + j) = pResult(j)
Next
If lastToken <> T_UNDEFINED Then
Result(lResult + vTemp - 1).Token = lastToken
Result(lResult + vTemp - 1).Value = 0
End If
Result(lResult + vTemp).Token = T_ENDLINE
Result(lResult + vTemp).Value = 0
lResult = lResult + vTemp + 1
ElseIf iError = usEEmpty Then
vTemp = IIf(lastToken = T_UNDEFINED, 0, IIf(lastToken = T_ELSE, 1, 2))
ReDim Preserve Result(0 To lResult + vTemp) As usTokenType
If vTemp = 2 Then
Result(lResult).Token = T_NONE
Result(lResult).Value = 0
End If
If vTemp > 0 Then
Result(lResult + vTemp - 1).Token = lastToken
Result(lResult + vTemp - 1).Value = 0
End If
Result(lResult + vTemp).Token = T_ENDLINE
Result(lResult + vTemp).Value = 0
lResult = lResult + vTemp + 1
Else
usTokenizeScript = iError
Exit Function
End If
PrevSpecialToken = lastToken
End If
Next
If lResult = 0 Then
usTokenizeScript = usEEmpty
ElseIf usTrim(ScriptLine(ScriptLength - 1)) = "" Then
usTokenizeScript = usESuccess
Else
usTokenizeScript = usEOpenedStatement
End If
End Function
'*******************************************************************************
'* Function/Variable Callback & Processing Functions *
'*******************************************************************************
Private Function usCallbackFunction( _
ByVal Name As String, ByRef param() As usTokenType, _
ByRef ReturnValue As Long, ByRef Matrix As Variant, ByRef Variables() As usVariableType _
) As usErrorEnum
Dim nArg As Integer, vTemp As Long, vTemp2 As Long, i As Integer
Name = UCase(Name)
nArg = UBound(param)
For i = 1 To nArg
If param(i).Token = T_VARIABLE Then
param(i).Token = T_NUMBER
usCallbackVariable param(i).Value, VA_GET, vTemp, Matrix, Variables
param(i).Value = vTemp
End If
Next
Select Case Name
Case "START"
Select Case nArg
Case 0
usCallbackVariable "_ROW", VA_LET, 0, Matrix, Variables
usCallbackVariable "_COLUMN", VA_LET, 0, Matrix, Variables
Case 2
If _
usCallbackVariable("_ROW", VA_LET, CLng(param(1).Value), Matrix, Variables) Or _
usCallbackVariable("_COLUMN", VA_LET, CLng(param(2).Value), Matrix, Variables) _
Then
usCallbackFunction = usECantAssignToVariable
Exit Function
End If
Case Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End Select
ReturnValue = 0
Case "GO_RIGHT", "GO_LEFT"
usCallbackVariable "_COLUMN", VA_GET, vTemp, Matrix, Variables
If nArg = 0 Or nArg = 1 Then
If nArg = 0 Then vTemp2 = 1 Else vTemp2 = param(1).Value
vTemp = vTemp + IIf(Name = "GO_LEFT", -1, 1) * vTemp2
If usCallbackVariable("_COLUMN", VA_LET, vTemp, Matrix, Variables) Then
usCallbackFunction = usEExitBlock
ReturnValue = 1
Exit Function
End If
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
ReturnValue = 0
Case "GO_UP", "GO_DOWN"
usCallbackVariable "_ROW", VA_GET, vTemp, Matrix, Variables
If nArg = 0 Or nArg = 1 Then
If nArg = 0 Then vTemp2 = 1 Else vTemp2 = param(1).Value
vTemp = vTemp + IIf(Name = "GO_UP", -1, 1) * vTemp2
If usCallbackVariable("_ROW", VA_LET, vTemp, Matrix, Variables) Then
usCallbackFunction = usEExitBlock
ReturnValue = 1
Exit Function
End If
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
ReturnValue = 0
Case "END"
usCallbackFunction = IIf(nArg = 0, usETerminateScript, usEWrongArgumentCount)
ReturnValue = 0
Exit Function
Case "EXIT"
usCallbackFunction = IIf(nArg = 0 Or nArg = 1, usEExitBlock, usEWrongArgumentCount)
If nArg = 0 Then ReturnValue = 1 Else ReturnValue = param(1).Value
Exit Function
Case "_ERROR"
usCallbackFunction = IIf(nArg = 0, usEMatrixError, usEWrongArgumentCount)
ReturnValue = 0
Exit Function
Case "ADD", "SUB", "MUL", "DIV", "MOD"
usCallbackVariable "RESULT", VA_GET, vTemp, Matrix, Variables
usCallbackVariable "CURRENT", VA_GET, vTemp2, Matrix, Variables
If nArg = 0 Then
Select Case Name
Case "ADD": vTemp = vTemp + vTemp2
Case "SUB": vTemp = vTemp - vTemp2
Case "MUL": vTemp = vTemp * vTemp2
Case "DIV", "MOD"
If vTemp2 = 0 Then
usCallbackFunction = usEDivideByZero
Exit Function
ElseIf Name = "DIV" Then
vTemp = vTemp \ vTemp2
Else
vTemp = vTemp Mod vTemp2
End If
End Select
If usCallbackVariable("RESULT", VA_LET, vTemp, Matrix, Variables) Then
usCallbackFunction = usECantAssignToVariable
Exit Function
End If
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
ReturnValue = 0
Case "_ADD", "_SUB", "_MUL", "_DIV", "_MOD"
usCallbackVariable "RESULT", VA_GET, vTemp, Matrix, Variables
If nArg = 1 Then
Select Case Name
Case "_ADD": vTemp = vTemp + param(1).Value
Case "_SUB": vTemp = vTemp - param(1).Value
Case "_MUL": vTemp = vTemp * param(1).Value
Case "_DIV", "_MOD"
If param(1).Value = 0 Then
usCallbackFunction = usEDivideByZero
Exit Function
ElseIf Name = "_DIV" Then
vTemp = vTemp \ param(1).Value
Else
vTemp = vTemp Mod param(1).Value
End If
End Select
If usCallbackVariable("RESULT", VA_LET, vTemp, Matrix, Variables) Then
usCallbackFunction = usECantAssignToVariable
Exit Function
End If
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
ReturnValue = 0
Case "ABS"
If nArg = 1 Then
ReturnValue = Abs(param(1).Value)
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
Case "SIGN"
If nArg = 1 Then
ReturnValue = Sgn(param(1).Value)
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
Case "_RANDOM"
If nArg = 0 Then
Randomize Timer
ElseIf nArg = 1 Then
Randomize param(1).Value
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
ReturnValue = 0
Case "RANDOM"
If nArg = 1 Then
ReturnValue = Int(Rnd * param(1).Value)
Else
usCallbackFunction = usEWrongArgumentCount
Exit Function
End If
Case Else
usCallbackFunction = usEUndefinedFunction
Exit Function
End Select
usCallbackFunction = usESuccess
End Function
Private Function usCallbackVariable( _
ByVal Name As String, ByVal Action As usActionEnum, _
ByRef Value As Long, ByRef Matrix As Variant, ByRef Variables() As usVariableType _
) As usErrorEnum
Dim i As Integer, vNum As Integer, vTemp As Long
Dim sRow As Long, sColumn As Long, sCurrent As Long, sPrevious As Long
Name = UCase(Name)
vNum = -1
For i = 0 To UBound(Variables)
If UCase(Variables(i).Name) = Name Then
vNum = i
Exit For
End If
Next
If vNum < 0 Then
usCallbackVariable = usEUndefinedVariable
Exit Function
ElseIf Action = VA_EXIST Then
Value = vNum
usCallbackVariable = usESuccess
Exit Function
ElseIf Action = VA_GET Then
Value = Variables(vNum).Value
usCallbackVariable = usESuccess
Exit Function
End If
Select Case Name
Case "CURRENT", "PREVIOUS", "_ROWS", "_COLUMNS", "TEMP"
usCallbackVariable = usEReadOnlyVariable
Exit Function
Case "_ROW"
usCallbackVariable "_ROWS", VA_GET, vTemp, Matrix, Variables
If Value < 0 Or Value >= vTemp Then
usCallbackVariable = usECantAssignToVariable
Exit Function
End If
Case "_COLUMN"
usCallbackVariable "_COLUMNS", VA_GET, vTemp, Matrix, Variables
If Value < 0 Or Value >= vTemp Then
usCallbackVariable = usECantAssignToVariable
Exit Function
End If
End Select
Variables(vNum).Value = Value
Select Case Name
Case "_ROW", "_COLUMN"
If Name = "_ROW" Then
sRow = vNum
usCallbackVariable "_COLUMN", VA_EXIST, sColumn, Matrix, Variables
Else
sColumn = vNum
usCallbackVariable "_ROW", VA_EXIST, sRow, Matrix, Variables
End If
usCallbackVariable "CURRENT", VA_EXIST, sCurrent, Matrix, Variables
usCallbackVariable "PREVIOUS", VA_EXIST, sPrevious, Matrix, Variables
Variables(sPrevious).Value = Variables(sCurrent).Value
Variables(sCurrent).Value = Matrix(Variables(sColumn).Value, Variables(sRow).Value)
End Select
usCallbackVariable = usESuccess
End Function
Private Sub usInitializeVariables( _
ByRef Variables() As usVariableType, _
ByRef Matrix As Variant _
)
ReDim Variables(0 To 17) As usVariableType
Dim i As Integer
With Variables(0): .Name = "RESULT": .Value = 0: End With
With Variables(1): .Name = "CURRENT": .Value = Matrix(0, 0): End With
With Variables(2): .Name = "PREVIOUS": .Value = 0: End With
With Variables(3): .Name = "_ROW": .Value = 0: End With
With Variables(4): .Name = "_COLUMN": .Value = 0: End With
With Variables(5): .Name = "_ROWS": .Value = UBound(Matrix, 2) + 1: End With
With Variables(6): .Name = "_COLUMNS": .Value = UBound(Matrix, 1) + 1: End With
With Variables(7): .Name = "TEMP": .Value = 0: End With 'no used!
For i = 0 To 9
With Variables(8 + i): .Name = "TEMP" & Chr(0) & i: .Value = 0: End With
Next
End Sub
Private Sub usInitializeFunctions( _
ByRef Variables() As usVariableType, _
ByRef Matrix As Variant _
)
Dim param(0 To 0) As usTokenType
Dim ReturnValue As Long
param(0).Token = T_FUNCTION
param(0).Value = "START"
usCallbackFunction "START", param, ReturnValue, Matrix, Variables
param(0).Value = "_RANDOM"
usCallbackFunction "_RANDOM", param, ReturnValue, Matrix, Variables
End Sub
'*******************************************************************************
'* Evaluate Function *
'*******************************************************************************
Private Function usEvaluateStatement( _
ByRef Tokens() As usTokenType, ByVal evStart As Integer, ByVal evDone As Integer, _
ByRef Value As Long, ByRef Matrix As Variant, ByRef Variables() As usVariableType _
) As usErrorEnum
On Error GoTo errorCatch
Dim Stack() As usTokenType, lStack As Integer, pStack As Long
Dim stok As usTokenEnum, svtok As Variant, vTemp As usErrorEnum, vTemp2 As Long
Dim tok As usTokenEnum, vtok As Variant, ptok As usTokenEnum, pvtok As Variant
Dim pValue As Long, pName As String, ppValue As Long, ppName As String
Dim i As Integer
If evStart > evDone Then
usEvaluateStatement = usEEmpty
Exit Function
End If
lStack = 0
For i = evStart To evDone
If _
Tokens(i).Token = T_NUMBER Or _
Tokens(i).Token = T_VARIABLE Or _
Tokens(i).Token = T_NONE _
Then
usPushNode Stack, lStack, Tokens(i).Token, Tokens(i).Value
Else
If Not usPopNode(Stack, lStack, tok, vtok) Then
usEvaluateStatement = usENoOperand
Exit Function
End If
If tok = T_NUMBER Or tok = T_VARIABLE Or tok = T_NONE Then
If tok = T_VARIABLE Then
vTemp = usCallbackVariable(CStr(vtok), VA_GET, pValue, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
Else
pName = vtok
End If
ElseIf tok = T_NONE Then
If Tokens(i).Token <> T_FUNCTION Then
usEvaluateStatement = usENoOperand
Exit Function
End If
Else
pValue = vtok
pName = ""
End If
Select Case Tokens(i).Token
Case T_NOT: pStack = Not pValue
Case T_POSITIVE: pStack = pValue
Case T_NEGATIVE: pStack = -pValue
Case T_FUNCTION
Dim param() As usTokenType, lParam As Integer
ReDim param(0 To 0) As usTokenType
param(0).Token = Tokens(i).Token
param(0).Value = Tokens(i).Value
lParam = 1
If tok <> T_NONE Then
usPushNode Stack, lStack, tok, vtok
Do
If Not usPopNode(Stack, lStack, stok, svtok) Then
usEvaluateStatement = usENoOperand
Exit Function
ElseIf stok <> T_COMMA Then
usPushNode param, lParam, stok, svtok
Exit Do
End If
If Not usPopNode(Stack, lStack, stok, svtok) Then
usEvaluateStatement = usENoOperand
Exit Function
End If
usPushNode param, lParam, stok, svtok
Loop
End If
vTemp = usCallbackFunction(param(0).Value, param, pStack, Matrix, Variables)
If vTemp = usEExitBlock Then
usEvaluateStatement = vTemp
Value = pStack
Exit Function
ElseIf vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
End If
Case T_PRE_INC, T_POST_INC, T_PRE_DEC, T_POST_DEC
If pName = "" Then
usEvaluateStatement = usEAssignToNonVariable
Exit Function
End If
vTemp = usCallbackVariable(pName, VA_GET, vTemp2, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
End If
tok = Tokens(i).Token
If tok = T_POST_INC Or tok = T_POST_DEC Then pStack = vTemp2
vTemp2 = vTemp2 + IIf(tok = T_PRE_INC Or tok = T_POST_INC, 1, -1)
If tok = T_PRE_INC Or tok = T_PRE_DEC Then pStack = vTemp2
vTemp = usCallbackVariable(pName, VA_LET, vTemp2, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
End If
End Select
If Not usIsUnaryOperator(Tokens(i).Token) Then
If Not usPopNode(Stack, lStack, ptok, pvtok) Then
usEvaluateStatement = usENoOperand
Exit Function
End If
If ptok = T_NUMBER Or ptok = T_VARIABLE Then
If ptok = T_VARIABLE Then
vTemp = usCallbackVariable(CStr(pvtok), VA_GET, ppValue, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
Else
ppName = pvtok
End If
Else
ppValue = pvtok
ppName = ""
End If
Select Case Tokens(i).Token
Case T_PLUS: pStack = ppValue + pValue
Case T_MINUS: pStack = ppValue - pValue
Case T_TIMES: pStack = ppValue * pValue
Case T_DIVIDE, T_MODULOUS
If pValue = 0 Then
usEvaluateStatement = usEDivideByZero
Exit Function
ElseIf Tokens(i).Token = T_DIVIDE Then
pStack = ppValue / pValue
Else
pStack = ppValue Mod pValue
End If
Case T_POWER
If ppValue = 0 And pValue = 0 Then
usEvaluateStatement = usEZerothPowerOfZero
Exit Function
Else
pStack = ppValue ^ pValue
End If
Case T_EQUAL: pStack = (ppValue = pValue)
Case T_INEQUAL: pStack = (ppValue <> pValue)
Case T_LESS: pStack = (ppValue < pValue)
Case T_LESS_EQ: pStack = (ppValue <= pValue)
Case T_GREATER: pStack = (ppValue > pValue)
Case T_GREATER_EQ: pStack = (ppValue >= pValue)
Case T_AND: pStack = (ppValue And pValue)
Case T_OR: pStack = (ppValue Or pValue)
Case T_COMMA 'in this case, we need special processing.
Case T_ASSIGN, T_PLUS_ASSIGN, T_MINUS_ASSIGN, T_TIMES_ASSIGN, _
T_DIVIDE_ASSIGN, T_POWER_ASSIGN, T_MODULOUS_ASSIGN
If ppName = "" Then
usEvaluateStatement = usEAssignToNonVariable
Exit Function
End If
Select Case Tokens(i).Token
Case T_ASSIGN: ppValue = pValue
Case T_PLUS_ASSIGN: ppValue = ppValue + pValue
Case T_MINUS_ASSIGN: ppValue = ppValue - pValue
Case T_TIMES_ASSIGN: ppValue = ppValue * pValue
Case T_DIVIDE_ASSIGN, T_MODULOUS_ASSIGN
If pValue = 0 Then
usEvaluateStatement = usEDivideByZero
Exit Function
ElseIf Tokens(i).Token = T_DIVIDE_ASSIGN Then
ppValue = ppValue / pValue
Else
ppValue = ppValue Mod pValue
End If
Case T_POWER
If pValue = 0 And ppValue = 0 Then
usEvaluateStatement = usEZerothPowerOfZero
Exit Function
Else
ppValue = ppValue ^ pValue
End If
End Select
vTemp = usCallbackVariable(ppName, VA_LET, ppValue, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
End If
pStack = ppValue
Case T_LBRACKET
If ppName = "" Then
usEvaluateStatement = usEAssignToNonVariable
Exit Function
End If
vtok = ppName & Chr(0) & pValue
End Select
Else
usEvaluateStatement = usENoOperand
Exit Function
End If
End If
If Tokens(i).Token = T_COMMA Then
usPushNode Stack, lStack, ptok, pvtok
usPushNode Stack, lStack, tok, vtok
usPushNode Stack, lStack, Tokens(i).Token, Tokens(i).Value
ElseIf Tokens(i).Token = T_LBRACKET Then
usPushNode Stack, lStack, T_VARIABLE, vtok
Else
usPushNode Stack, lStack, T_NUMBER, pStack
End If
Else
usEvaluateStatement = usENoOperand
Exit Function
End If
End If
Next
If lStack = 1 Then
If Stack(0).Token = T_VARIABLE Then
vTemp = usCallbackVariable(Stack(0).Value, VA_GET, Value, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateStatement = vTemp
Exit Function
End If
Else
Value = Stack(0).Value
End If
usEvaluateStatement = usESuccess
Else
usEvaluateStatement = usENoOperand
End If
Exit Function
errorCatch:
If Err.Number = 6 Then
usEvaluateStatement = usEOverflow
Else
usEvaluateStatement = usEUndefined
End If
End Function
'*******************************************************************************
'* Script Executing Functions *
'*******************************************************************************
Public Function usEvaluateScript( _
ByRef Tokens() As usTokenType, ByRef Result As Long, _
ByRef Matrix As Variant, ByRef Variables() As usVariableType _
) As usErrorEnum
Dim blockLine() As usBlockType, blockDepth As Integer
Dim vTemp As usErrorEnum, vResult As Long, vDepth As Integer
Dim pos As Integer, npos As Integer, tok As usTokenEnum
Dim numberLines As Long
blockDepth = 0
pos = 0
numberLines = 0
Do While pos <= UBound(Tokens)
For npos = pos To UBound(Tokens)
If Tokens(npos).Token = T_ENDLINE Then Exit For
Next
Select Case Tokens(npos - 1).Token
Case T_DO
ReDim Preserve blockLine(-1 To blockDepth) As usBlockType
With blockLine(blockDepth)
.blockType = T_DO
.startPos = npos + 1
.Counter = 0
If Tokens(npos - 2).Token = T_NONE Then
vResult = -1
Else
vTemp = usEvaluateStatement(Tokens, pos, npos - 2, vResult, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateScript = vTemp
Exit Function
End If
End If
.limitCounter = vResult
End With
npos = npos + 1
blockDepth = blockDepth + 1
Case T_IF
If Tokens(npos - 2).Token = T_NONE Then
usEvaluateScript = usEInvalidSyntax
Exit Function
Else
vTemp = usEvaluateStatement(Tokens, pos, npos - 2, vResult, Matrix, Variables)
If vTemp <> usESuccess Then
usEvaluateScript = vTemp
Exit Function
End If
End If
If vResult Then
ReDim Preserve blockLine(-1 To blockDepth) As usBlockType
With blockLine(blockDepth)
.blockType = T_IF
.Counter = 0
.limitCounter = 1
.startPos = npos + 1
End With
blockDepth = blockDepth + 1
npos = npos + 1
Else
vDepth = usMatchingBlock(Tokens, npos + 1)
If vDepth < 0 Then
usEvaluateScript = usEUnknownBlock
Exit Function
ElseIf vDepth + 1 < UBound(Tokens) Then
If Tokens(vDepth + 2).Token = T_ELSE Then
ReDim Preserve blockLine(-1 To blockDepth) As usBlockType
With blockLine(blockDepth)
.blockType = T_ELSE
.Counter = 0
.limitCounter = 1
.startPos = npos + 1
End With
blockDepth = blockDepth + 1
End If
End If
npos = vDepth + 2
End If
Case T_ELSE
If Tokens(npos + 1).Token = T_LBRACE Then
If blockLine(blockDepth - 1).blockType = T_ELSE Then
npos = npos + 1
ElseIf blockLine(blockDepth - 1).blockType = T_IF Then
ReDim Preserve blockLine(-1 To blockDepth - 2) As usBlockType
blockDepth = blockDepth - 1
vDepth = usMatchingBlock(Tokens, npos + 1)
If vDepth < 0 Then
usEvaluateScript = usEUnknownBlock
Exit Function
End If
npos = vDepth + 2
Else
usEvaluateScript = usEInvalidSyntax
Exit Function
End If
Else
usEvaluateScript = usEInvalidSyntax
Exit Function
End If
Case T_LBRACE
npos = npos + 1
Case T_RBRACE
If blockDepth = 0 Then
usEvaluateScript = usEUnknownBlock
Exit Function
End If
Select Case blockLine(blockDepth - 1).blockType
Case T_DO
blockLine(blockDepth - 1).Counter = blockLine(blockDepth - 1).Counter + 1
If _
blockLine(blockDepth - 1).limitCounter <> -1 And _
blockLine(blockDepth - 1).Counter >= blockLine(blockDepth - 1).limitCounter _
Then
ReDim Preserve blockLine(-1 To blockDepth - 2) As usBlockType
blockDepth = blockDepth - 1
npos = npos + 1
Else
npos = blockLine(blockDepth - 1).startPos + 2
End If
Case T_IF
If npos < UBound(Tokens) Then
If Tokens(npos + 1).Token <> T_ELSE Then
ReDim Preserve blockLine(-1 To blockDepth - 2) As usBlockType
blockDepth = blockDepth - 1
End If
End If
npos = npos + 1
Case T_ELSE
ReDim Preserve blockLine(-1 To blockDepth - 2) As usBlockType
blockDepth = blockDepth - 1
npos = npos + 1
End Select
Case Else
vTemp = usEvaluateStatement(Tokens, pos, npos - 1, vResult, Matrix, Variables)
If vTemp = usEExitBlock Then
If blockDepth = 0 Then
usEvaluateScript = usEUnknownBlock
Exit Function
Else
blockLine(blockDepth - 1).limitCounter = 0
npos = usMatchingBlock(Tokens, blockLine(blockDepth - 1).startPos, 1 - vResult)
If npos < 0 Then
usEvaluateScript = usEUnknownBlock
Exit Function
End If
ReDim Preserve blockLine(-1 To blockDepth - vResult) As usBlockType
blockDepth = blockDepth - vResult + 1
blockLine(blockDepth - 1).limitCounter = 0
End If
ElseIf vTemp = usESuccess Or vTemp = usEEmpty Then
npos = npos + 1
Else
usCallbackVariable "RESULT", VA_GET, Result, Matrix, Variables
usEvaluateScript = vTemp
Exit Function
End If
End Select
pos = npos
numberLines = numberLines + 1
If numberLines >= maximumLines Then
usCallbackVariable "RESULT", VA_GET, Result, Matrix, Variables
usEvaluateScript = usETimeout
Exit Function
End If
Loop
usCallbackVariable "RESULT", VA_GET, Result, Matrix, Variables
usEvaluateScript = usESuccess
End Function
Public Function usExecute( _
ByVal Code As String, ByRef Matrix As Variant, ByRef Result As Long _
) As usErrorEnum
Dim Variables() As usVariableType, Tokens() As usTokenType
Dim vTemp As usErrorEnum
vTemp = usTokenizeScript(Code, Tokens)
If vTemp <> usESuccess Then
usExecute = vTemp
Exit Function
End If
usInitializeVariables Variables, Matrix
usInitializeFunctions Variables, Matrix
usExecute = usEvaluateScript(Tokens, Result, Matrix, Variables)
End Function
<html>
<head>
<title>UserScript version 0.2.3</title>
<link rel="stylesheet" href="common.css" type="text/css" />
</head>
<body>
<h1>UserScript 레퍼런스 <small>UserScript Reference</small></h1>
<h2>0. 목차 <small>Contents</small></h2>
<h2>1. 소개 <small>Introduction</small></h2>
<h3>1.1 UserScript는? <small>What is UserScript?</small></h3>
<p>UserScript는 Break the Box 용으로 만들어진, Visual Basic 6에서 돌아 가는 스크립트 엔진 모듈입니다. 이 모듈은 <b>토끼군 강 성훈</b>이 개발하고 있으며, 현재 최신 버전은 0.2.3입니다.</p>
<h3>1.2 무엇을 하는가? <small>What does UserScript?</small></h3>
<p>UserScript는 정수로 구성된 행렬을 처리하여 하나의 값을 반환하는 역할을 합니다. (이것이 바로 Break the Box의 기본 원리기도 합니다)</p>
<h3>1.2 파일 구성 <small>File Structure</small></h3>
<ul>
<li><b>mdlUserScript.bas</b>: UserScript 모듈</li>
<li><b>ref/common.css</b>: 레퍼런스용 CSS (<a href="http://www.hypothetic.org/docs/msn/index.php">여기</a>서 많이 빌려 왔습니다.)</li>
<li><b>ref/index.html</b>: 이 문서 :)</li>
</ul>
<h2>2. 문법 레퍼런스 <small>Language Reference</small></h2>
<p>UserScript의 대부분의 문법은 C와 흡사합니다.</p>
<h3>2.1 개념 <small>Notions</small></h3>
<dl>
<dt>식 Expression</dt> <dd>UserScript에서 가장 작은 계산 단위로, 숫자, 혹은 하나 이상의 식의 결합으로 이루어집니다.</dd>
<dt>문장 Statement</dt> <dd>세미콜론(;)으로 끝나는, 하나의 실행 단위를 뜻합니다.</dd>
<dt>블록 Block</dt> <dd>{와 }로 묶여 있는, 문장들의 묶음입니다.</dd>
<dt>함수 Function</dt> <dd>하나 이상의 식을 받거나 아무 것도 받지 않고 기능을 수행하는 명령을 뜻합니다. UserScript의 함수는 항상 반환값이 있습니다.</dd>
<dt>반환값 Return Value</dt> <dd>함수가 계산된 후에 반환되는 값으로, 수식 중에 나타날 수 있으며 계산될 수 있습니다.</dd>
<dt>변수 Variable</dt> <dd>식의 계산 결과를 저장하기 위하여 사용되는 공간입니다.</dd>
<dt>주석 Comment</dt> <dd>실행에 아무 영향을 미치지 않는, 설명을 위해서 사용되는 부분입니다.</dd>
</dl>
<h3>2.2 사용하는 문자들 <small>Used Characters</small></h3>
<dl>
<dt>공백, 탭, 줄 바꿈</dt> <dd>UserScript에서 이 문자들은 모두 무시됩니다.</dd>
<dt>;</dt> <dd>문장 끝에 붙어서 문장과 문장을 구분합니다.</dd>
<dt>% ^ * ( ) - + = [ ] &lt; &gt; , /</dt> <dd>연산자들로, 식을 계산할 때 사용됩니다.</dd>
<dt>{ }</dt> <dd>블록을 구분하기 위해서 사용됩니다.</dd>
<dt>$</dt> <dd>변수를 나타낼 때 사용됩니다.</dd>
<dt>0~9</dt> <dd>숫자 상수를 나타낼 때 사용됩니다.</dd>
<dt>A~Z a~z _</dt> <dd>함수나 변수의 이름을 나타낼 때 사용됩니다. 대소문자를 구별하지 않습니다.</dd>
</dl>
<h3>2.3 형 <small>Types</small></h3>
<p>UserScript에서 지원하는 유일한 형은 정수형입니다. -2147483648부터 2147483647까지를 표현할 수 있습니다. 내부적으로 실수형을 전혀 사용하지 않으므로 소숫점을 사용할 수 없습니다.</p>
<p>UserScript에서 "참"은 "0이 아닌 모든 숫자"로, "거짓"은 "0"로 인식합니다. 비교 연산자와 같은 경우 "참"은 -1을, "거짓"은 0을 반환합니다.</p>
<h3>2.4 연산자 <small>Operators</small></h3>
<p>연산자는 식과 식을 연결해서 하나의 식(혹은 숫자)로 만드는 역할을 합니다.</p>
<h4>2.4.1 산술 연산자 <small>Arithmetic Operators</small></h4>
<dl>
<dt>a + b</dt> <dd>a와 b를 더합니다.</dd>
<dt>a - b</dt> <dd>a에서 b를 뺍니다.</dd>
<dt>a * b</dt> <dd>a와 b를 곱합니다.</dd>
<dt>a / b</dt> <dd>a를 b로 나눈 몫을 반환합니다. b가 0이면 에러가 발생합니다.</dd>
<dt>a % b, a mod b (대소문자를 구별하지 않습니다.)</dt> <dd>a를 b로 나눈 나머지를 반환합니다. 역시 b가 0이면 에러가 발생합니다.</dd>
<dt>a ^ b</dt> <dd>a의 b제곱을 반환합니다. a와 b가 모두 0이면 에러가 발생합니다.</dd>
</dl>
<h4>2.4.2 비교 연산자 <small>Comparison Operators</small></h4>
<dl>
<dt>a == b</dt> <dd>a와 b가 같으면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>a != b, a &lt;&gt; b, a &gt;&lt; b</dt> <dd>a와 b가 다르면 -1(참), 같으면 0(거짓)을 반환합니다.</dd>
<dt>a &gt; b</dt> <dd>a가 b보다 크면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>a =&gt; b, a &gt;= b</dt> <dd>a가 b보다 크거나 같다면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>a &lt; b</dt> <dd>a가 b보다 작으면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>a &lt;= b, a =&lt; b</dt> <dd>a가 b보다 작거나 같으면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
</dl>
<h4>2.4.3 논리/비트 연산자 <small>Logical/Bitwise Operators</small></h4>
<p>이 연산자들은 논리 연산자이자 비트 연산자입니다. 이는 베이직과 같습니다.</p>
<p>논리 연산자 앞 뒤에는 공백 문자가 하나 이상 있어야 합니다. 아래의 연산자들은 모두 대소문자를 구별하지 않습니다.</p>
<dl>
<dt>a and b</dt> <dd>a와 b가 모두 참이면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>a or b</dt> <dd>a와 b 중 하나 이상이 참이면 -1(참), 다르면 0(거짓)을 반환합니다.</dd>
<dt>not a</dt> <dd>a가 참이면 0(거짓), 거짓이면 1(참)을 반환합니다.</dd>
</dl>
<p>UserScript는 Lazy Evaluation (혹은 Shorthand Evaluation)을 지원하지 않습니다. 따라서 논리 연산자를 사용할 때는 항상 앞 뒤의 수식에서 에러가 발생할 수 있는 지 확인해 보아야 합니다.</p>
<h4>2.4.4 단항 부호 연산자 <small>Unary Sign Operators</small></h4>
<p>모든 단항 부호 연산자는 앞에 붙습니다.</p>
<dl>
<dt>+a</dt> <dd>a의 부호를 그대로 둡니다. 즉 a와 같습니다.</dd>
<dt>-a</dt> <dd>a의 부호를 바꿉니다. 즉 (-1) * a와 같습니다.</dd>
</dl>
<h4>2.4.5 변수 증감 연산자 <small>Variable Increase/Decrease Operators</small></h4>
<p>변수 증감 연산자는 앞에 오는 경우(전위)와 뒤에 오는 경우(후위)의 연산이 다릅니다.</p>
<dl>
<dt>++a</dt> <dd>a를 1 증가시킨 후 현재 값을 반환합니다.</dd>
<dt>a++</dt> <dd>a를 1 증가시킨 후 원래 값을 반환합니다. (++a보다 1 작습니다)</dd>
<dt>--a</dt> <dd>a를 1 감소시킨 후 현재 값을 반환합니다.</dd>
<dt>a--</dt> <dd>a를 1 감소시킨 후 원래 값을 반환합니다. (--a보다 1 큽니다)</dd>
</dl>
<p>변수 증감 연산자의 피연산자가 변수가 아니거나 읽기 전용 변수라면 에러가 발생합니다.</p>
<h4>2.4.6 쉼표 연산자 <small>Comma Operator</small></h4>
<dl>
<dt>,</dt> <dd>함수에 전달되는 값을 구분하기 위하여 사용됩니다.</dd>
</dl>
<p>C와는 다르게, 수식 중간에서 언제나 사용할 수는 없습니다. 쉼표 연산자는 함수 처리를 위한 특수한 연산자이기 때문입니다.</p>
<h4>2.4.7 대입 연산자 <small>Assignment Operators</small></h4>
<dl>
<dt>a = b</dt> <dd>a에 b를 넣습니다. (대입합니다.)</dd>
<dt>a += b</dt> <dd>a = a + b와 같은 표현입니다.</dd>
<dt>a -= b</dt> <dd>a = a - b와 같은 표현입니다.</dd>
<dt>a *= b</dt> <dd>a = a * b와 같은 표현입니다.</dd>
<dt>a /= b</dt> <dd>a = a / b와 같은 표현입니다.</dd>
<dt>a %= b</dt> <dd>a = a % b와 같은 표현입니다.</dd>
<dt>a ^= b</dt> <dd>a = a ^ b와 같은 표현입니다.</dd>
</dl>
<p>대입 연산자의 왼쪽 식은 항상 변수가 되어야 합니다.</dd>
<h4>2.4.8 괄호 연산자 <small>Parentheses Operators</small></h4>
<dl>
<dt>(...)</dt> <dd>괄호 안에 들어 있는 식을 먼저 계산합니다.</dd>
<dt>a[b]</dt> <dd>변수 배열 a의 b번째 변수를 뜻합니다. a는 항상 변수 배열이어야 합니다.</dd>
</dl>
<p>변수 배열에 대해서는 변수에 대해서 설명할 때 같이 설명합니다.</p>
<h4>2.4.9 연산자 우선순위 <small>Operator Precedence</small></h4>
<p>연산자들은 다음의 순서대로 계산됩니다. (단, 괄호로 인해서 순서가 바뀔 경우는 제외) 같은 순서에 있으면 연산자가 있는 순서로 계산됩니다.</p>
<ul>
<li><b>++, --</b></li>
<li><b>+, -</b>(부호 연산자)<b>, not</b></li>
<li><b>^</b></li>
<li><b>*, /</b></li>
<li><b>+, -</b>(산술 연산자)</li>
<li><b>&gt;, &gt;=, &lt;, &lt;=</b></li>
<li><b>==, !=</b></li>
<li><b>and</b></li>
<li><b>or</b></li>
<li><b>=, +=, -=, *=, /=, %=, ^=</b></li>
<li><b>,</b>(쉼표 연산자)<b>, []</b>(괄호 연산자)</li>
</ul>
<p>부호 연산자와 not 연산자, 그리고 대입 연산자를 뺀 모든 연산자는 오른쪽으로 계산됩니다.</p>
<h3>2.5 변수 <small>Variables</small></h3>
<p>변수는 값을 담아 두기 위해 사용되는 공간입니다. 모든 변수는 $로 시작하고, 변수 이름에는 알파벳과 _를 사용합니다. 변수는 대소문자 구분을 하지 않습니다.</p>
<p>UserScript는 상당히 제한적인 변수 처리를 합니다. 즉, 새로운 변수를 만들 수 없고 내부적으로 만든 변수들만 사용할 수 있습니다.</p>
<h4>2.5.1 변수 배열 <small>Variable Array</small></h4>
<p>한 이름의 변수가 여러 개의 값을 가질 수 있게 하기 위하여 사용되는 방법입니다. (C에서의 배열과 비슷합니다)</p>
<p>예를 들어서 $TEMP라는 변수가 있을 경우, 이 변수가 변수 배열로 사용될 경우 $TEMP[0]부터 $TEMP[9]까지 숫자를 붙여서 사용할 수 있습니다. 이 때 붙는 숫자를 인덱스(index)라 합니다. 변수 배열에 따라서 이 인덱스의 제한이 있습니다.</p>
<p>$TEMP[0]과 같이 변수 배열 안의 변수들은 일반 변수와 완전히 똑같이 취급됩니다. 따라서 $TEMP[11]과 같은 사용 불가능한 인덱스를 사용할 경우 변수가 없는 것으로 인식해서 에러를 발생시킵니다.</p>
<h4>2.5.2 행렬 변수들 <small>Matrix Variables</small></h4>
<p>아래에서 사용되는 "행 번호"나 "열 번호"는 모두 0부터 시작하는 숫자입니다. 즉 3 x 3 행렬에서 행 번호와 열 번호는 모두 0부터 2까지 사용할 수 있습니다.</p>
<dl>
<dt>$_ROW, $_COLUMN</dt> <dd>현재의 행 번호와 열 번호를 반환합니다. 이 변수에 값을 대입하면 현재 행과 열을 바꿀 수 있습니다.</dd>
<dt>$_ROWS, $_COLUMNS</dt> <dd>행렬의 행 갯수와 열 갯수를 반환합니다. 3 x 3 행렬의 경우 $_ROWS와 $_COLUMNS는 모두 3입니다. 이 변수는 값을 대입할 수 없는 읽기 전용 변수입니다.</dd>
<dt>$CURRENT</dd> <dd>현재의 행과 열이 가리키는 원소를 가리킵니다. 예를 들어서 $_ROW와 $_COLUMN이 1일 경우, $CURRENT는 두 번째 행 두 번째 열에 있는 원소의 값을 반환합니다. 이 변수는 읽기 전용 변수입니다.</dd>
<dt>$PREVIOUS</dd> <dd>현재의 행 번호나 열 번호가 바뀔 경우 이전에 가리키던 원소의 값을 가리킵니다. 이 변수는 읽기 전용 변수입니다. <span class="warning">$_ROW와 $_COLUMN에 직접 값을 대입할 경우, 한 번 대입할 때마다 $PREVIOUS가 갱신되며, 변수의 값이 바뀌지 않아도 $PREVIOUS의 값은 항상 갱신됩니다.</span></dd>
</dl>
<h4>2.5.2 일반 변수들 <small>General Variables</small></h4>
<dl>
<dt>$RESULT</dt> <dd>스크립트의 계산 결과를 저장하는 변수입니다. 처음에는 0으로 초기화됩니다.</dd>
<dt>$TEMP</dt> <dd>임시 변수 배열입니다. 0부터 9까지의 인덱스를 사용할 수 있으며 $TEMP 자체는 읽기 전용 변수입니다.</dd>
</dl>
<h3>2.6 조건/반복문 <small>Conditional/Repetitive Statements</small></h3>
<p>조건문은 조건에 따라서 다른 코드를 실행하는 문장(들)을 뜻하며, 반복문은 지정한 횟수나 조건에 따라서 반복하는 문장(들)을 뜻합니다.</p>
<p>UserScript의 모든 조건/반복문은 (한 문장이라도) 블록으로 묶여야 합니다. 블록은 이 문장들 이외에 단독으로 사용될 수 없습니다.</p>
<h4>2.6.1 IF...ELSE 문 <small>IF...ELSE Statement</small></h4>
<p>IF...ELSE 문은 두 가지 형태가 있습니다:</p>
<p><code><span style="color:black; text-decoration:underline;">Type I:</span><br />
if(<i>conditional_expression</i>) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<i>if-block statement(s);</i><br />
}</code></p>
<p><code><span style="color:black; text-decoration:underline;">Type II:</span><br />
if(<i>conditional_expression</i>) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<i>if-block statement(s);</i><br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<i>else-block statement(s);</i><br />
}</code></p>
<ul>
<li>Type I의 경우, <i>conditional_expression</i>이 참이면 그 다음에 나오는 블록을 실행하며, 거짓이면 그냥 넘어 갑니다.</li>
<li>Type II의 경우, <i>conditional_expression</i>이 참이면 그 다음에 나오는 블록을 실행하며, 거짓이면 else 뒤에 나오는 블록을 실행합니다.</li>
</ul>
<p>IF...ELSE 문도 하나의 블록이므로 exit() 함수를 사용할 경우 주의가 필요합니다.</p>
<h4>2.6.2 DO 문 <small>DO Statement</small></h4>
<p>DO 문도 두 가지 형태가 있습니다:</p>
<p><code><span style="color:black; text-decoration:underline;">Type I:</span><br />
do {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<i>do-block statement(s);</i><br />
}</code></p>
<p><code><span style="color:black; text-decoration:underline;">Type II:</span><br />
do(<i>repeating_number</i>) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<i>do-block statement(s);</i><br />
}</code></p>
<ul>
<li>Type I의 경우, do 블록 안의 문장은 exit()나 end()가 호출될 때까지 무한히 실행됩니다.</li>
<li>Type II의 경우, do 블록 안의 문장은 <i>repeating_number</i>번 반복해서 실행되고 블록을 빠져 나옵니다. (물론 이 안에서도 exit()나 end()를 쓸 수 있습니다)</li>
</ul>
<p>Type II의 경우 <i>repeating_number</i>가 -1이 되면 Type I와 같은 역할을 합니다. 또한, <i>repeating_number</i>는 do 루프가 시작할 때 바로 계산되므로 C의 while과 같은 조건을 달 수 없습니다. 조건을 달려면 Type I를 사용하여야 합니다.</p>
<h3>2.7 함수 <small>Function</small></h3>
<p>함수는 0개 이상의 식을 받아서 처리를 한 후 값을 반환하는 하나의 명령을 뜻합니다. 함수 이름 역시 변수와 마찬가지로 알파벳과 _를 사용하고, 대소문자를 구별하지 않습니다.</p>
<p>함수는 식 중간에서도 사용될 수 있고, 여러 개의 함수가 중첩되어 사용될 수도 있습니다.</p>
<h4>2.7.1 함수의 호출 <small>How to call function</small></h4>
<p>함수를 부를 때에는 abs()와 같이 함수 이름 뒤에 괄호로 묶인 인수(argument)들을 주면 됩니다. 이 때 인수가 없더라도 빈 괄호 -- () -- 를 사용해야 하며, 인수가 둘 이상이면 ,로 구분해 줘야 합니다. 함수에 들어간 인수들이 함수에 맞지 않는다면 에러가 발생합니다.</p>
<p>함수는 항상 값을 반환합니다. 즉 $RESULT = temp(); 와 같이 식 중간에서 사용될 수 있습니다.</p>
<h4>2.7.2 행렬 함수들 <small>Matrix Functions</small></h4>
<p><i>기울어진 인수들</i>은 생략될 수 있습니다.</p>
<dl>
<dt>start(<i>row, column</i>)</dt>
<dd>현재 행을 row, 열을 column으로 바꿉니다. row와 column이 생략되면 첫 행 첫 열로 바꿉니다.<br />이 함수는 항상 0을 반환합니다.</dd>
<dt>go_right(<i>num</i>), go_left(<i>num</i>), go_up(<i>num</i>), go_down(<i>num</i>)</dt>
<dd>num 만큼 오른쪽/왼쪽/윗쪽/아랫쪽으로 현재 칸을 이동합니다. num이 생략되었을 경우 한 칸 이동합니다.<br />
만약 이동할 수 없다면 (예를 들어서 행렬 맨 오른쪽 끝에서 go_right()를 호출할 경우) <b>현재 블록을 빠져 나옵니다.</b>
<span class="warning">이 때 이동할 수 없을 경우 현재 칸은 변하지 않습니다.</span><br /><br />
<code>// 1 x 8 행렬이 입력되었을 경우를 가정합시다:<br />
do {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$RESULT++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;go_right(5);<br />
}<br />
$RESULT += 10000 * $_ROW + 100 * $_COLUMN;</code><br />
<code class="result">
returns 502 (error #0: Success)<br />
&nbsp;&nbsp;elasped time: 0 ms</code><br /><br />
$RESULT가 2가 된 상태에서 go_right(5)가 호출되면 현재 위치가 여섯 번째 칸이므로 이동할 수 없습니다. 따라서 블록을 빠져 나오고 이동은 하지 않습니다.<br />
이 함수는 블록이 없는 경우 에러를 발생합니다. 이 함수는 항상 0을 반환합니다.</dd>
<dt>add(), sub(), mul(), div(), mod()</dt>
<dd>현재 칸의 내용을 $RESULT에 더하거나, 빼거나, 곱하거나, 나눈 몫이나 나머지를 구합니다.<br />
각각 $RESULT += $CURRENT, $RESULT -= $CURRENT, $RESULT *= $CURRENT, $RESULT /= $CURRENT, $RESULT %= $CURRENT와 같은 표기입니다.<br />
이 함수는 항상 0을 반환합니다.</dd>
</dl>
<h4>2.7.3 일반 함수들 <small>General Functions</small></h4>
<dl>
<dt>_add(num), _sub(num), _mul(num), _div(num), _mod(num)</dt>
<dd>num을 $RESULT에 더하거나, 빼거나, 곱하거나, 나눈 몫이나 나머지를 구합니다.<br />
각각 $RESULT += num, $RESULT -= num, $RESULT *= num, $RESULT /= num, $RESULT %= num와 같은 표기입니다.<br />
이 함수는 항상 0을 반환합니다.</dd>
<dt>abs(num)</dt>
<dd>num의 절대값을 반환합니다.</dd>
<dt>sign(num)</dt>
<dd>num이 양수이면 1, 음수이면 -1, 0이면 0을 반환합니다.</dd>
<dt>_random(<i>seed</i>)</dt>
<dd>난수 발생기를 초기화합니다. seed를 지정하면 자기가 원하는 숫자로 난수 발생기를 초기화할 수 있으며, 만약 seed가 같다면 생성되는 난수들은 똑같은 순서로 생성됩니다. 이 함수는 항상 0을 반환합니다.</dd>
<dt>random(num)</dt>
<dd>0부터 num-1까지의 정수 난수를 반환합니다.</dd>
</dl>
<h4>2.7.4 특수 함수들 <small>Special Functions</small></h4>
<dl>
<dt>exit(<i>num</i>)</dt>
<dd>현재 속해 있는 블록을 빠져 나옵니다. num을 지정하면 num 개 만큼의 블록을 빠져 나오며, 만약 블록이 num개보다 적다면 에러가 발생합니다.<br />
C의 break와 다른 점은 모든 {...}가 블록으로 인식된다는 점입니다. 즉, 다음과 같은 코드는 실패합니다.<br /><br />
<code>
do {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$RESULT++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if($RESULT &gt;= 50) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code><br />
<code class="result">
returns 7164 (error #25: Timeout)<br />
&nbsp;&nbsp;elasped time: 454 ms</code><br /><br />
이 코드는 $RESULT가 50이 되거나 커지면 do 루프를 빠져 나오려 만든 것입니다. 하지만 exit()가 빠져 나오는 블록은 단지 if 블록 뿐이기 때문에 이 블록은 무한히 실행됩니다. 따라서 이 코드를 제대로 실행시키려면 다음과 같이 해야 합니다.<br /><br />
<code>do {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$RESULT++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if($RESULT &gt;= 50) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code><br />
<code class="result">
returns 50 (error #0: Success)<br />
&nbsp;&nbsp;elasped time: 3 ms</code><br /><br />
이제 exit(2)는 if 블록과 do 블록 두 개를 모두 빠져 나오게 되어 정상적으로 작동합니다.<br />이 함수는 항상 0을 반환합니다.</dd>
<dt>end(), _error()</dt>
<dd>스크립트의 실행을 중지합니다. _error()는 특수 목적으로 사용되며 end()와 다른 에러 코드를 반환합니다.<br /><br />
<code>$RESULT = 30;<br />
end();<br />
$RESULT++;</code><br />
<code class="result">
returns 30 (error #101: Script terminated)<br />
&nbsp;&nbsp;elasped time: 0 ms</code><br /><br />
end()는 성공했다는 에러 코드를 반환하지 않습니다. UserScript 모듈을 사용할 때는 항상 이 점에 유의해야 합니다.</dd>
</dl>
<h2>3. 스크립트 엔진 레퍼런스 <small>Script Engine Reference</small></h2>
<h2>4. 변경 사항 <small>ChangeLog</small></h2>
<h3>UserScript 0.2.x</h3>
<h4>UserScript 0.2.4?</h4>
<ul>
<li><b>go_*()</b>를 제외한 모든 행렬 관련 함수들이 $PREVIOUS의 값을 두 번(!) 바꾸는 버그를 고쳤습니다.</li>
<li>단 한 문장으로만 이루어진 스크립트에서 ;가 빠졌을 경우 usEOpenedStatement가 아닌 usEEmpty 에러 코드가 발생하는 버그를 고쳤습니다.;;;</li>
<li>usEvaluateStatement에서만 나오던 usEOverflow 에러 코드를 usCallback* 함수도 나오게 고쳤습니다. -_-;; (까먹고 있었음)</li>
<li><b>add()~mod(), _add()~_mod()</b> 함수군이 0이 아닌 $RESULT를 반환하도록 고쳤습니다.</li>
<li>$TEMP 변수 배열의 크기를 스크립트 맨 처음에 <b>#pragma</b> 문법을 사용하여 고칠 수 있게 했습니다.</li>
</ul>
<h4>UserScript 0.2.3 <small>(2003/12/22)</small></h4>
<ul>
<li><b>random(), _random()</b> 함수가 추가되었습니다.</li>
<li><b>go_*()</b> 함수가 블록을 빠져 나오지 못 하는 문제를 수정하였습니다. (0.2.2에만 있던 문제)</li>
<li>usInitializeFunction 함수를 추가했습니다.</li>
</ul>
<h4>UserScript 0.2.2 <small>(2003/12/22)</small></h4>
<ul>
<li><b>exit()</b> 함수에 인수를 넣어서 빠져 나올 블록의 수를 정할 수 있습니다.</li>
<li>usExecuteScript 함수를 usEvaluateScript와 usExecute 함수로 분리했습니다.</li>
</ul>
<h4>UserScript 0.2.1 <small>(2003/12/21)</small></h4>
<ul>
<li><b>_error()</b> 함수가 추가되었습니다.</li>
<li>내부적으로 if()나 do() 문과 { 사이에 엉뚱한 문장이 끼어 있는 지 확인하는 방법을 바꿨습니다.</li>
<li>$TEMP[0]++과 같은 문장에서 후위 연산자 ++이 $TEMP[0]이 아닌 숫자 0에 달라 붙는 버그를 수정했습니다.</li>
<li>무한 루프를 돌 경우를 위해서 usETimeout 에러 코드가 추가되었습니다. 이 에러는 일정 횟수 이상 문장을 실행해서 자동으로 종료될 떄 발생합니다.</li>
<li>usEOverflow 에러 코드를 구현했습니다.</li>
<li>그 외에 온갖 버그들을 고쳤습니다. -_-;</li>
</ul>
<h4>UserScript 0.2.0 <small>(2003/12/21)</small></h4>
<ul>
<li><b>최초의 안정화 버전</b></li>
<li>usMatchingBlock 함수를 추가했습니다. -_-;</li>
<li>블록 처리를 완전하게 안정화시켰습니다.</li>
</ul>
<h3>UserScript 0.2.x-beta</h3>
<p>여기 있는 버전들은 개발 버전이므로 ChangeLog가 없습니다. -_-</p>
<h4>UserScript 0.2-beta17 <small>(2003/12/20)</small></h4>
<h4>UserScript 0.2-beta13 <small>(2003/12/19)</small></h4>
<h4>UserScript 0.2-beta9 <small>(2003/12/18)</small></h4>
<h4>UserScript 0.2-beta1 <small>(2003/12/17)</small></h4>
<h4>UserScript 0.2-alpha4 <small>(2003/12/16)</small></h4>
<h4>UserScript 0.2-alpha1 <small>(2003/12/15)</small></h4>
</body>
</html>
@Korb
Copy link

Korb commented Jun 27, 2021

What exactly does this script do?

@lifthrasiir
Copy link
Author

@Korb Back in 2003 when I was still in a high school, my friend commissioned me to make a programming language for a puzzle game to be presented in a school festival. Basically the goal was to find a pattern for given pairs of inputs and outputs and write a program to express that pattern. Incidentally I was making what became the first programming language implementation I would ever make, so I retrofitted and finished my code. In retrospect the game should never had a programming element, but we went forward anyway and this "programming language" is a remnant of that game.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment