#196266 - 2009-10-06 10:03 PM
SteelKix 0.22
|
WvS
Fresh Scripter
Registered: 2009-05-30
Posts: 42
Loc: Netherlands
|
Yesterday I've released SteelKix 0.2.2!
Get it here: http://steelkix.codeplex.com/
- Added windows executable (does not show console)
- Added calculator example script (with a scanner, parser and evaluator)
- Fixed reporting of error messages related to user defined functions and the binary operation binder
- Fixed invocation of user defined function with null values
- Fixed issues with return value of user defined functions being null on exit
- Added "assert" setoption for showing assertion dialogs on exceptions
- SteelKixConsole now exits after script has finished.
Included is an example of a calculator that can parse and evaluate simple math expressions.
How to run this example:
imports $system = system
imports $io = system.io
global $tokens =
{
LeftPara=1,
RightPara=2,
Star=3,
Plus=4,
Min=5,
Number=6,
Div=7,
Var=8
}
;creates context for scanner
function scanner_create($expr)
if $system.string.isnullorempty($expr)
throw '$expr should not be null or empty'
endif
$scanner_create = {
PeekToken=nothing,
Reader = $io.StringReader($expr)
}
endfunction
;converts object to character
function ToChar($c)
$ToChar = $System.Convert.ToChar($c)
endfunction
;reads token from scanner state
function scanner_read($state)
dim $c = 0
dim $builder = $System.Text.StringBuilder()
dim $length = 0
if $state.PeekToken <> nothing
dim $ret = $state.PeekToken
$state.PeekToken = nothing
$scanner_read = $ret
exit 0
endif
$c = $state.Reader.Read
while $c > 0
dim $char = ToChar($c)
select
case $System.Char.IsWhitespace($char)
$c = $state.Reader.Read
continue
case $System.Char.IsNumber($char)
$length = $builder.Append($char)
$c = $state.Reader.Peek
while $c > 0
$char = ToChar($c)
if $System.Char.IsNumber($char) Or $char = "."
$length = $builder.Append($char)
$length = $state.Reader.Read
$c = $state.Reader.Peek
else
break
endif
loop
$scanner_read = {
Token = $tokens.Number,
Value = $builder.ToString
}
case $System.Char.IsLetter($char)
$scanner_read = {
Token = $tokens.Var,
Value = $char
}
case $char = "+"
$scanner_read = {
Token = $tokens.Plus,
Value = $char
}
case $char = "-"
$scanner_read = {
Token = $tokens.Min,
Value = $char
}
case $char = "*"
$scanner_read = {
Token = $tokens.Star,
Value = $char
}
case $char = "/"
$scanner_read = {
Token = $tokens.Div,
Value = $char
}
case $char = "("
$scanner_read = {
Token = $tokens.LeftPara,
Value = $char
}
case $char = ")"
$scanner_read = {
Token = $tokens.RightPara,
Value = $char
}
endselect
if $scanner_read = nothing
throw 'Unsupported token'
endif
break
loop
endfunction
;peeks token from scanner context
function scanner_peek($state)
if $state.PeekToken = nothing
$state.PeekToken = scanner_read($state)
endif
$scanner_peek = $state.PeekToken
endfunction
;parses expression
function parser_parseExpression($scanner)
$parser_parseExpression = parser_parseMinPlus($scanner)
endfunction
;parses final expression (atom/variable/parenthesis)
function parser_parseFinal($scanner)
dim $token = scanner_peek($scanner)
dim $swallow
select
case $token.token = $tokens.Number Or $token.token = $tokens.Var
$parser_parseFinal = {
Token = $token,
Left=nothing,
Right=nothing
}
$swallow = scanner_read($scanner)
case $token.token = $tokens.LeftPara
$swallow = scanner_read($scanner)
$parser_parseFinal = parser_parseExpression($scanner)
$swallow = scanner_read($scanner)
endselect
endfunction
;parses multiplication and division
function parser_parseMulDiv($scanner)
dim $left = parser_parseFinal($scanner)
dim $swallow
dim $token = scanner_peek($scanner)
while $token <> nothing and
( $token.token = $tokens.Star or $token.token = $tokens.Div )
$swallow = scanner_read($scanner)
dim $expr = {
Token = $token,
Left = $left,
Right = parser_parseFinal($scanner)
}
$left = $expr
$token = scanner_peek($scanner)
loop
$parser_parseMulDiv = $left
endfunction
;parses addition or subtraction
function parser_parseMinPlus($scanner)
dim $left = parser_parseMulDiv($scanner)
dim $swallow
dim $token = scanner_peek($scanner)
while $token <> nothing and
( $token.token = $tokens.Plus or $token.token = $tokens.Min )
$swallow = scanner_read($scanner)
dim $expr = {
Token = $token,
Left = $left,
Right = parser_parseMulDiv($scanner)
}
$left = $expr
$token = scanner_peek($scanner)
loop
$parser_parseMinPlus = $left
endfunction
;prints expression tree
function parser_print($expr, $ident)
for $i = 1 to $ident
" "
next
$expr.token.value ?
if $expr.left <> nothing
parser_print($expr.left, $ident+1)
endif
if $expr.right <> nothing
parser_print($expr.right, $ident+1)
endif
endfunction
;evaluate expression tree
function evaluator_eval($expr, optional $variables)
dim $left, $right
select
case $expr.token.token = $tokens.Plus
$left = evaluator_eval($expr.left, $variables)
$right = evaluator_eval($expr.right, $variables)
$evaluator_eval = $left + $right
case $expr.token.token = $tokens.Min
$left = evaluator_eval($expr.left, $variables)
$right = evaluator_eval($expr.right, $variables)
$evaluator_eval = $left - $right
case $expr.token.token = $tokens.Star
$left = evaluator_eval($expr.left, $variables)
$right = evaluator_eval($expr.right, $variables)
$evaluator_eval = $left * $right
case $expr.token.token = $tokens.Div
$left = evaluator_eval($expr.left, $variables)
$right = evaluator_eval($expr.right, $variables)
$evaluator_eval = $left / $right
case $expr.token.token = $tokens.number
$evaluator_eval = $System.Convert.ToDouble($expr.token.value, $System.Globalization.NumberFormatInfo() With { NumberDecimalSeparator = "." })
case $expr.token.token = $tokens.var
if not $variables
throw 'Variable referenced but not defined'
endif
$evaluator_eval = $System.Convert.ToDouble($variables[$expr.token.value])
endselect
endfunction
;"1+10 * (1+2)"
"Enter an expression. Only multiplication, addition, subtraction and division is supported. Parenthesis can be used." ?
"Example: 1+10 * (1+2)" ?
"Type exit to quit" ?
dim $input
gets $input
while $input <> "exit"
dim $scannerState = scanner_create($input)
dim $expr = parser_parseExpression($scannerState)
"Result: " evaluator_eval($expr, nothing) ?
"Tree: " ?
parser_print($expr, 0)
gets $input
loop
|
Top
|
|
|
|
#196267 - 2009-10-06 10:38 PM
Re: SteelKix 0.22
[Re: WvS]
|
BoForce
Fresh Scripter
Registered: 2005-10-22
Posts: 36
Loc: Leeuwarden, The Netherlands
|
Hi WvS,
Great!
I've just downloaded and tested the new release of SteelKix. Although I tested just a few items, I did found out that my macros do not work as expected.
Example: Macro @DATE
Macro DATE
Dim $dtn,$rc
Imports $dtn = System.DateTime.Now
Try
$rc = $dtn.ToString("yyy/MM/dd")
EndTry
Catch
$e
EndCatch
If $e
$DATE = $e.ToString()
Else
$DATE = $rc
EndIf
EndMacro
Result SteelKix 0.2
Result SteelKix 0.2.2
No typo here. The result with 0.2.2 is nothing.
|
Top
|
|
|
|
#196268 - 2009-10-06 11:30 PM
Re: SteelKix 0.22
[Re: BoForce]
|
Allen
KiX Supporter
Registered: 2003-04-19
Posts: 4549
Loc: USA
|
Jedi Bo (or is it Lord Force? ), for us less acclimated, would you mind explaining the use for Try and Catch, and specifically $e. This is not anything kix has and it would be great to understand it.
Thanks.
|
Top
|
|
|
|
#196271 - 2009-10-07 09:25 AM
Re: SteelKix 0.22
[Re: Allen]
|
BoForce
Fresh Scripter
Registered: 2005-10-22
Posts: 36
Loc: Leeuwarden, The Netherlands
|
Hi Allen,
Well it's just BoForce. Nothing special.
How to explain Try-EndTry Catch-EndCatch. I'm just starting to understand what this does. I could Try, but for you to Catch it you could read this http://msdn.microsoft.com/en-us/library/system.exception(VS.80).aspx
The info helped me to get started.
Please note that although this may look like @SERROR in Kix it isn't. In the example below I will use the function DelKey with a none existing key as the Exception is easy to trigger.
Kix >
DelKey('HKEY_CURRENT_USER\Test\New\some\Folder\Task')
?@SERROR
Result:
The system cannot find the file specified.
SteelKix:
? DelKey('HKEY_CURRENT_USER\Test\New\some\Folder\Task')
Result:
Cannot delete a subkey tree because the subkey does not exist.
SteelKix DelKey Function:
;SteelKix Function: DelKey()
;
;Author: Boforce
;
;Contributors: None
;
;Action: Deletes the specified subkey from the registry
;
;Syntax: DelKey("key")
;
;Version: 1.0
;
;Date: 2009-09-25
;
;Date Revised: 2009-09-25
;
;Parameters Key
; Required. A string that specifies the name of the subkey you want to delete
;
;Remarks: None
;
;Returns: Returns nothing if the key is deleted else an error message
;
;Dependencies:
; SteelKix version: 0.2
; Tested with Dot Net 3.5.30729.01
;
;Example(s): Delete some key:
; $DeleteKey = DelKey('HKEY_CURRENT_USER\Test\Some\New\Key')
; ? 'Deleted key : ' + $DeleteKey
;
;Comments : This has been successfully tested on Windows XP SP3 with DOT NET 3.5.30729.01.
;
;Source:
Function DelKey($Key)
Dim $Win32,$Hive,$Action
Imports $Win32 = Microsoft.Win32
$Hive = $Key.ToString.Split("\".ToCharArray())[0]
$Key = $Key.Remove($Hive+'\',$Hive.Length+1)
Select
Case $Hive = 'HKEY_CLASSES_ROOT' Or $Hive = 'HKCR'
$Hive = $Win32.Registry.ClassesRoot
Case $Hive = 'HKEY_CURRENT_USER' Or $Hive = 'HKCU'
$Hive = $Win32.Registry.CurrentUser
Case $Hive = 'HKEY_LOCAL_MACHINE' Or $Hive = 'HKLM'
$Hive = $Win32.Registry.LocalMachine
Case $Hive = 'HKEY_USERS' Or $Hive = 'HKU'
$Hive = $Win32.Registry.Users
Case 1
$atHive = 'Error'
EndSelect
If $atHive = 'Error'
$AddKey = 'Unknown hive'
Else
Try
$Action = $Hive.DeleteSubKey($Key,1)
EndTry
Catch
$e
EndCatch
If $e
$DelKey = $e.Message
Else
$DelKey = $Action
EndIf
EndIf
EndFunction
Note that in this case I use $e.Message because the $e.ToString() would result in:
System.ArgumentException: Cannot delete a subkey tree because the subkey does not exist.
at Microsoft.Scripting.Interpreter.ThrowInstruction.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
|
Top
|
|
|
|
#196275 - 2009-10-07 09:44 AM
Re: SteelKix 0.22
[Re: WvS]
|
BoForce
Fresh Scripter
Registered: 2005-10-22
Posts: 36
Loc: Leeuwarden, The Netherlands
|
Ok. Just a few more.
;SteelKix Macro: @TIME
;
;Author: Boforce
;
;Contributors: Richard von Mallesch (It took my meds)
;
;Action: Retrieve current Time
;
;Syntax: @TIME
;
;Version: 1.0
;
;Date: 2009-09-28
;
;Date Revised: 2009-09-28
;
;Parameters None
;
;Remarks: None
;
;Returns: Time (in the format HH:MM:SS)
;
;Dependencies:
; SteelKix version: 0.2
; Tested with Dot Net 3.5.30729.01
;
;Example(s): Get Current Time:
; ? @TIME
; Result > 10:23:15
;
;Comments : This has been successfully tested on Windows XP SP3 with DOT NET 3.5.30729.01.
;
;Source:
Macro TIME
Dim $dtn,$rc
Imports $dtn = System.DateTime.Now
Try
$rc = $dtn.ToString("HH:mm:ss")
EndTry
Catch
$e
EndCatch
If $e
$TIME = $e.Message
Else
$TIME = $rc
EndIf
EndMacro
;SteelKix Macro: @DAY
;
;Author: Boforce
;
;Contributors: Richard von Mallesch (It took my meds)
;
;Action: Retrieve day of the week
;
;Syntax: @DAY
;
;Version: 1.0
;
;Date: 2009-09-28
;
;Date Revised: 2009-09-28
;
;Parameters None
;
;Remarks: None
;
;Returns: Day (Monday, Tuesday, etc.)
;
;Dependencies:
; SteelKix version: 0.2
; Tested with Dot Net 3.5.30729.01
;
;Example(s): Get day of the week:
; ? @DAY
; Result > Monday
;
;Comments : This has been successfully tested on Windows XP SP3 with DOT NET 3.5.30729.01.
;
;Source:
Macro DAY
Dim $dtn,$rc
Imports $dtn = System.DateTime.Now
Try
$rc = $dtn.DayOfWeek
EndTry
Catch
$e
EndCatch
If $e
$DAY = $e.Message
Else
$DAY = $rc
EndIf
EndMacro
;SteelKix Macro: @MONTHNO
;
;Author: Boforce
;
;Contributors: Richard von Mallesch (It took my meds)
;
;Action: Retrieve the number of the current month of the year
;
;Syntax: @MONTHNO
;
;Version: 1.0
;
;Date: 2009-09-28
;
;Date Revised: 2009-09-28
;
;Parameters None
;
;Remarks: None
;
;Returns: Month number, beginning with January (1-12)
;
;Dependencies:
; SteelKix version: 0.2
; Tested with Dot Net 3.5.30729.01
;
;Example(s): Get month number of the year:
; ? @MONTHNO
; Result > 10 (if month is October)
;
;Comments : This has been successfully tested on Windows XP SP3 with DOT NET 3.5.30729.01.
;
;Source:
Macro MONTHNO
Dim $dtn,$rc
Imports $dtn = System.DateTime.Now
Try
$rc = $dtn.Month
EndTry
Catch
$e
EndCatch
If $e
$MONTHNO = $e.Message
Else
$MONTHNO = $rc
EndIf
EndMacro
;SteelKix Macro: @MONTH
;
;Author: Boforce
;
;Contributors: Richard von Mallesch (It took my meds)
;
;Action: Retrieve the name of the current month of the year
;
;Syntax: @MONTH
;
;Version: 1.0
;
;Date: 2009-09-28
;
;Date Revised: 2009-09-28
;
;Parameters None
;
;Remarks: None
;
;Returns: Name of the Month
;
;Dependencies:
; SteelKix version: 0.2
; Tested with Dot Net 3.5.30729.01
;
;Example(s): Get month of the year:
; ? @MONTH
; Result > OCTOBER (if month is October)
;
;Comments : This has been successfully tested on Windows XP SP3 with DOT NET 3.5.30729.01.
;
;Source:
Macro MONTH
Dim $dtn,$glob,$rc
Imports $dtn = System.DateTime.Now
Imports $glob = System.Globalization
Try
$rc = $dtn.Month
EndTry
Catch
$e
EndCatch
If $e
$MONTH = $e.Message
Else
$MONTH = $glob.DateTimeFormatInfo.CurrentInfo.GetMonthName($rc).ToUpper()
EndIf
EndMacro
|
Top
|
|
|
|
#196280 - 2009-10-07 11:29 AM
Re: SteelKix 0.22
[Re: Lonkero]
|
BoForce
Fresh Scripter
Registered: 2005-10-22
Posts: 36
Loc: Leeuwarden, The Netherlands
|
Yes, indeed the exception message from DotNet is better. But nothing is easier than just throwing an @ERROR or @SERROR after a line of Kix code to check the result. So I have to agree with you on the fact that Kix is very friendly to handle and since I've been playing arround with Steelkix, I started to appreciate Kix even more than I already did.
After working with Kix for about ten years now, Steelkix is a new challenge. Learning new stuff is always nice.
Uh proForce, Jedi Bo, Lord Force
Just BoForce
|
Top
|
|
|
|
#196293 - 2009-10-08 12:05 AM
Re: SteelKix 0.22
[Re: Lonkero]
|
Allen
KiX Supporter
Registered: 2003-04-19
Posts: 4549
Loc: USA
|
Thanks for the link above... For others wondering here is the meat of the article.
This class is the base class for all exceptions. When an error occurs, either the system or the currently executing application reports it by throwing an exception containing information about the error. Once thrown, an exception is handled by the application or by the default exception handler.
The common language runtime provides an exception handling model that is based on the representation of exceptions as objects, and the separation of program code and exception handling code into try blocks and catch blocks, respectively. There can be one or more catch blocks, each designed to handle a particular type of exception, or one block designed to catch a more specific exception than another block.
If an application handles exceptions that occur during the execution of a block of application code, the code must be placed within a try statement. Application code within a try statement is a try block. Application code that handles exceptions thrown by a try block is placed within a catch statement, and is called a catch block. Zero or more catch blocks are associated with a try block, and each catch block includes a type filter that determines the types of exceptions it handles.
When an exception occurs in a try block, the system searches the associated catch blocks in the order they appear in application code, until it locates a catch block that handles the exception. A catch block handles an exception of type T if the type filter of the catch block specifies T or any type that T derives from. The system stops searching after it finds the first catch block that handles the exception. For this reason, in application code, a catch block that handles a type must be specified before a catch block that handles its base types, as demonstrated in the example that follows this section. A catch block that handles System.Exception is specified last.
If none of the catch blocks associated with the current try block handle the exception, and the current try block is nested within other try blocks in the current call, the catch blocks associated with the next enclosing try block are searched. If no catch block for the exception is found, the system searches previous nesting levels in the current call. If no catch block for the exception is found in the current call, the exception is passed up the call stack, and the previous stack frame is searched for a catch block that handles the exception. The search of the call stack continues until the exception is handled or until no more frames exist on the call stack. If the top of the call stack is reached without finding a catch block that handles the exception, the default exception handler handles it and the application terminates.
What isn't so clear is the $e. Is that something that is just predefined in this syntax? What would happen if you dimmed $e and or had a var called $e, prior to doing a try/catch?
|
Top
|
|
|
|
Moderator: Glenn Barnas, NTDOC, Arend_, Jochen, Radimus, Allen, ShaneEP, Ruud van Velsen, Mart
|
0 registered
and 918 anonymous users online.
|
|
|