調子に乗ってS式評価機を
もはやantlrと何の関係もない……!
namespace SExpr {
public abstract class SExpr {
public override string ToString() {
StringBuilder sb = new StringBuilder();
ToString(sb);
return sb.ToString();
}
public abstract void ToString(StringBuilder sb);
public IEnumerator<SExpr> GetEnumerator() {
SExpr cur;
for(cur = this; cur is Cons; cur = ((Cons)cur).Cdr)
yield return ((Cons)cur).Car;
if(cur is Null)
yield break;
else
throw new Exception("not proper list.");
}
public SExpr this[int idx] {
get {
int i = idx;
foreach(SExpr se in this)
if(i-- == 0)
return se;
throw new Exception("idx rangeerr.");
}
}
}
public class Cons : SExpr {
public Cons(SExpr car, SExpr cdr) {
Car = car;
Cdr = cdr;
}
public SExpr Car;
public SExpr Cdr;
public override void ToString(StringBuilder sb) {
sb.Append('(');
SExpr cur;
for(cur = this; cur is Cons; cur = ((Cons)cur).Cdr) {
((Cons)cur).Car.ToString(sb);
sb.Append(' ');
}
if(cur is Null) {
;
} else {
sb.Append(". ");
cur.ToString(sb);
}
sb.Append(')');
}
}
public class Symbol : SExpr {
public Symbol(string name) {
Name = name;
}
public string Name;
public override void ToString(StringBuilder sb) {
sb.Append(Name);
}
}
public class Integer : SExpr {
public Integer(int v) {
Value = v;
}
public int Value;
public override void ToString(StringBuilder sb) {
sb.Append(Value);
}
}
public class Null : SExpr {
protected Null() { }
public override void ToString(StringBuilder sb) {
sb.Append("()");
}
public static Null Instance = new Null();
}
}
namespace SExpr {
public delegate SExpr ProcedureDelegate(SExpr args);
public class Procedure : SExpr {
public ProcedureDelegate Proc;
public Procedure(ProcedureDelegate proc) { Proc = proc; }
public override void ToString(StringBuilder sb) { sb.Append("<procedure>"); }
}
public class Closure : SExpr {
public Closure(Environment env, SExpr param, SExpr body) { Env = env; Params = param; Body = body; }
public override void ToString(StringBuilder sb) { sb.Append("<closure>"); }
public Environment Env;
public SExpr Params;
public SExpr Body;
}
public class Special : SExpr {
public Special(string name) { Name = name; }
public override void ToString(StringBuilder sb) { sb.Append(string.Format("<special:{0}>", Name)); }
public string Name;
}
public class Environment {
public Environment() : this(null) { }
public Environment(Environment parent) { Parent = parent; }
public Environment Parent;
Dictionary<string, SExpr> m_env = new Dictionary<string, SExpr>();
public SExpr this[SExpr symbol] {
get { return this[((Symbol)symbol).Name]; }
set { this[((Symbol)symbol).Name] = value; }
}
public SExpr this[string name] {
get { if(m_env.ContainsKey(name)) return m_env[name]; else return Parent[name]; }
set { m_env[name] = value; }
}
public void AddProc(string name, ProcedureDelegate proc) {
this[name] = new Procedure(proc);
}
}
public class Evaluator {
public Evaluator() { }
public Environment GlobalEnv = new Environment();
public SExpr Eval(SExpr src) {
return Eval(src, GlobalEnv);
}
private SExpr Eval(SExpr src, Environment env) {
if(src is Cons) {
return EvalList((Cons)src, env);
} else if(src is Symbol) {
return env[src];
} else {
return src;
}
}
private SExpr EvalList(Cons l, Environment env) {
SExpr head = Eval(l.Car, env);
if(head is Procedure) {
return ((Procedure)head).Proc(Map(l.Cdr, env));
} else if(head is Closure) {
Closure c = head as Closure;
return EvalClosure(c, Map(l.Cdr, env), env);
} else if(head is Special) {
return EvalSpecial((head as Special).Name, l.Cdr, env);
} else
throw new Exception("err");
}
private SExpr EvalClosure(Closure c, SExpr args, Environment env) {
Environment new_env = CreateEnv(env, c.Params, args);
SExpr result = Null.Instance;
foreach(SExpr se in c.Body)
result = Eval(se, new_env);
return result;
}
private SExpr Map(SExpr arr, Environment env) {
Stack<SExpr> stk = new Stack<SExpr>();
foreach(SExpr s in arr)
stk.Push(Eval(s, env));
SExpr r = Null.Instance;
while(stk.Count > 0) {
SExpr s = stk.Pop();
r = new Cons(s, r);
}
return r;
}
private SExpr EvalSpecial(string p, SExpr args, Environment env) {
switch(p) {
case "if":
if(Eval(args[0], env) is Null)
return Eval(args[2], env);
else
return Eval(args[1], env);
case "lambda":
return new Closure(env, args[0], (args as Cons).Cdr);
case "quote":
return args;
}
throw new Exception("unknown special form");
}
private Environment CreateEnv(Environment parent, SExpr param, SExpr args) {
Environment env = new Environment(parent);
IEnumerator<SExpr> cur = param.GetEnumerator();
IEnumerator<SExpr> argcur = args.GetEnumerator();
while(cur.MoveNext() && argcur.MoveNext()) {
env[(Symbol)cur.Current] = argcur.Current;
}
return env;
}
}
}
namespace SExpr {
class Program {
static void Main(string[] args) {
Evaluator eval = new Evaluator();
Environment e = eval.GlobalEnv;
e["'"] = new Special("quote");
e.AddProc("+", delegate(SExpr s) {
int result = 0;
foreach(Integer i in s)
result += i.Value;
return new Integer(result);
});
e.AddProc("-", delegate(SExpr s) {
int result = 0;
foreach(Integer i in s)
result -= i.Value;
result += ((Integer)s[0]).Value*2;
return new Integer(result);
});
e["if"] = new Special("if");
e["lambda"] = new Special("lambda");
while(true) {
SExpr s=null;
try {
SExprParser p = new SExprParser(new SExprLexer(Console.OpenStandardInput()));
s = p.sexpr();
if(s == null) {
Console.WriteLine("syntax err.");
} else {
Console.WriteLine(s);
Console.WriteLine(" ==> " + eval.Eval(s).ToString());
}
} catch {
Console.WriteLine("err");
}
}
}
}
}ふー、びっくりした。rubyだったら四分の一くらいで収まりそうだな。