Tuesday, June 14, 2005
CSI Hacks
My little interactive C# interpreter CSI has been coming on nicely. It originally started as a small experiment of about 160 lines; it's now closer to 1200 lines. This happens to all programs, eventually; they take on a life of their own, and suddenly other people want to use them.
The Code Project article gives an overview, but what I wanted to discuss here are some of the cool things that can be done with an extendable C# interpreter.
CSI's preprocessor is very useful in interactive work. For instance, these macro definitions in the .csi file will give you useful new commands:
#def cd(x) Directory.SetCurrentDirectory(#x)
#def pwd(x) Directory.GetCurrentDirectory()
#def ls(x) foreach(string s in Directory.GetFiles(".",#x)) Print(Path.GetFileName(s))
....
# /pwd
(String) 'D:\Downloads\csi'
# /ls *.cs
console.cs
csi.cs
csigui.cs
extension.cs
gui-defs.cs
interpreter.cs
loaded.cs
override.cs
prepro.cs
test.cs
testquotes.cs
# /cd ..
# /pwd
(String) 'D:\Downloads'
# /cd /stuff/boo/work
Now you can always execute these macros directly, e.g.
cd("..") but they're easier to type as slash-commands. Please notice that you need to use forward slashes (or double-up your backslashes), since the prepro stringizing operator is not smart enough to do that for you.Could we not make it more like the shell, and make the slash implicit? But then it's not clear how to distinguish commands from C# statements or expressions; there are too many opportunities for confusion. Why
#def, instead of #define? Apart from being easier to type, it reminds us that this is not a full C preprocessor - for instance, there is no #include available. In fact, there's no builtin command for loading code, but it's very easy to create such a command. The compilation context used for all statements in CSI derives from the Utils class, which supplies us useful things like Print and Include. (The last function calls the code responsible for loading the default csi script.) So here's a load command:
val.csi:
/cd /stuff/boo/work
/pwd
...
# #def L(file) Include(#file)
# /L val.csi
(String) 'D:\stuff\boo\work'
CSI makes certain events available to programmers, which makes adding custom functionality possible. For instance, there is no way to list all the currently defined macros. But there is an event which is fired by the MacroSubstitutor object whenever a macro is defined.
...
$_macros = new ArrayList()
void add_macro(string sym) { $_macros.Add(sym); }
$interpreter.macro.MacroDefined += new DefineEvent(add_macro)
void dump_macros() { foreach(string s in $_macros) Print(s); }
#def DM(x) dump_macros()
...
# /DM
DM
cd
pwd
ls
L
FOR
sin
cos
dir
M
MI
PR
ADD_CLOSE
ADD_VAR
OUT
D
CSI exposes much of its internal implementation. In particular, the
MacroSubsitutor object is publically available and any public method can be used:
# /dollar
# $mac = $interpreter.macro
# $mac.Lookup("pwd").Subst
(String) 'Directory.GetCurrentDirectory()'
# $mac.Substitute("cd(hello)")
(String) 'Directory.SetCurrentDirectory("hello")'
# $mac.AddMacro("ANSWER","42",null)
# ANSWER
(Int32) 42
There are four interpreter events which CSI scripts can monitor:
- Interpreter.Close
- Interpreter.VarAdding
- Interpreter.FunAdding
- Interpreter.PreprocessLine
For example, you may wish to always save your session at the end:
/var
#def ADD_CLOSE(x) interpreter.Closing += new InterpEvent(x)
void close() { interpreter.Save(null); }
ADD_CLOSE(close)
The other two events are passed the name and the first line of the definition. It can be used to keep track of function definitions:
var _funs = new Hashtable()
void add_fun(string v, string l) {
_funs[v] = l;
}
interpreter.FunAdding += new DeclareEvent(add_fun)
void dump(Hashtable table) { // used to implement the /D command
foreach(string s in table.Keys)
Print(s,table[s]);
}
#def D(x) dump(_##x)
...
# /D funs
dump void dump(Hashtable table) { // used to implement the /D command
# double sqr(double x) { // a suprisingly useful function
. return x*x;
. }
# /D funs
dump void dump(Hashtable table) { // used to implement the /D command
sqr double sqr(double x) { // a suprisingly useful function
Previously I noted that it would be cool if one could dispense with the forward slash when using macro-defined commands. The {{PreprocessLine}} event will pass you the string before it's processed, so you can do just about anything to it. CSI allows you to define classes, like this one
{{{
class CommandProcess {
MacroSubstitutor mac;
string firstWord(string s) {
int idx = s.IndexOf(" ");
if (idx == -1)
idx = s.Length;
return s.Substring(0,idx);
}
string prepro(string line) {
if (! Interpreter.Interactive)
return line;
if (mac.Lookup(firstWord(line)) != null)
line = "/" + line;
return line;
}
public CommandProcess(Interpreter interp) {
interp.PreprocessLine += new LineEvent(prepro);
mac = interp.macro;
}
}
var cp = new CommandProcess(interpreter)
Larger blocks of code like this can be compiled into their own assembly, as long as it references csi.exe (or csigui.exe). Assuming we are in the same directory as csi.exe, then the above class can compiled into an assembly (just remember to put a 'public' in front of the class):
D:\Downloads\csi> csc /t:library CommandProcess.cs /r:csi.exe
...
/r CommandProcess.dll
var cp = new CommandProcess(interpreter)
...
Although this is obviously going to be faster, the disadvantage of loading a class like this is that you can't reload the class, since assemblies can't be unloaded.
Comments:
<< Home
Get your High School Diploma, Or any Desired College Degree, In less then 2 weeks.
Call this number now 24 hours a day 7 days a week (413) 208-3069
Get these Degrees NOW!!!
High School Diploma "BA", "BSc", "MA", "MSc", "MBA", "PHD",
Get everything within 2 weeks.
100% verifiable, this is a real deal
Act now you owe it to your future.
(413) 208-3069 call now 24 hours a day, 7 days a week.
Call this number now 24 hours a day 7 days a week (413) 208-3069
Get these Degrees NOW!!!
High School Diploma "BA", "BSc", "MA", "MSc", "MBA", "PHD",
Get everything within 2 weeks.
100% verifiable, this is a real deal
Act now you owe it to your future.
(413) 208-3069 call now 24 hours a day, 7 days a week.
.net is very hard to learn.
before last week i started to learn
but becouse of some missed classes i am not able to learn now
i am getting prob.
facebook fan page
Post a Comment
before last week i started to learn
but becouse of some missed classes i am not able to learn now
i am getting prob.
facebook fan page
<< Home

