Created
July 22, 2012 13:47
-
-
Save lifthrasiir/3159760 to your computer and use it in GitHub Desktop.
UserScript: a forgotten programming language from the hell (2003)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Attribute VB_Name = "mdlUserScript" | |
'############################################################################### | |
'## @@ @@ @@@@ @@ +++ +++ ## | |
'## @@ @@ @@@@ @@@@ @@ @@ @@ @@@@ @@ @@ @@ @@@@ @@@@ ++ ++ ++ ++ ## | |
'## @@ @@ @@@ @@@@@@ @@@@ @@@ @@ @@@@ @@ @@ @@ @@ ++ ++ ++ ## | |
'## @@ @@ @@@ @@ @@ @@ @@ @@ @@ @@@@ @@ ++ ++ ++ ++ ## | |
'##__@@@@__@@@@___@@@@__@@____@@@@___@@@@_@@____@@_@@______@@___+++__++_+++++_## | |
'## UserScript, for Break the Box @@ version 0.2.3 ## | |
'##===========================================================================## | |
'## Created by Tokigun <[email protected]>, 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 = "[email protected]" | |
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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>% ^ * ( ) - + = [ ] < > , /</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 <> b, a >< b</dt> <dd>a와 b가 다르면 -1(참), 같으면 0(거짓)을 반환합니다.</dd> | |
<dt>a > b</dt> <dd>a가 b보다 크면 -1(참), 다르면 0(거짓)을 반환합니다.</dd> | |
<dt>a => b, a >= b</dt> <dd>a가 b보다 크거나 같다면 -1(참), 다르면 0(거짓)을 반환합니다.</dd> | |
<dt>a < b</dt> <dd>a가 b보다 작으면 -1(참), 다르면 0(거짓)을 반환합니다.</dd> | |
<dt>a <= b, a =< 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>>, >=, <, <=</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 /> | |
<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 /> | |
<i>if-block statement(s);</i><br /> | |
} else {<br /> | |
<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 /> | |
<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 /> | |
<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 /> | |
$RESULT++;<br /> | |
go_right(5);<br /> | |
}<br /> | |
$RESULT += 10000 * $_ROW + 100 * $_COLUMN;</code><br /> | |
<code class="result"> | |
returns 502 (error #0: Success)<br /> | |
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 /> | |
$RESULT++;<br /> | |
if($RESULT >= 50) {<br /> | |
exit();<br /> | |
}<br /> | |
}</code><br /> | |
<code class="result"> | |
returns 7164 (error #25: Timeout)<br /> | |
elasped time: 454 ms</code><br /><br /> | |
이 코드는 $RESULT가 50이 되거나 커지면 do 루프를 빠져 나오려 만든 것입니다. 하지만 exit()가 빠져 나오는 블록은 단지 if 블록 뿐이기 때문에 이 블록은 무한히 실행됩니다. 따라서 이 코드를 제대로 실행시키려면 다음과 같이 해야 합니다.<br /><br /> | |
<code>do {<br /> | |
$RESULT++;<br /> | |
if($RESULT >= 50) {<br /> | |
exit(2);<br /> | |
}<br /> | |
}</code><br /> | |
<code class="result"> | |
returns 50 (error #0: Success)<br /> | |
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 /> | |
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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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.