調子に乗って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だったら四分の一くらいで収まりそうだな。