Esempio n. 1
0
        // while文
        private SExp evalWhile(SExp param)
        {
            SExp ret = SExpNull;
            while (true)
            {
                var condition = Elms2SExp2(param);

                if (breakLabel!=null || SExp2string(condition) != "#true")
                    return ret;

                ret = Elms2SExp2(param.next); // これこの時点で評価されるので1回実行されたことになる
            }
        }
Esempio n. 2
0
 // car
 // (car x)は (array x 0)と等価
 private SExp evalCar(SExp exp)
 {
     SExp array = Elms2SExp2(exp);
     return evalArrayOf(array, 0);
 }
Esempio n. 3
0
        // ファイル名を指定しての削除
        private SExp evalDeleteFile(SExp param)
        {
            string name = eval_getString(param);

            try
            {
                File.Delete(name);
            }
            catch { }

            return string2SExp(name);
        }
Esempio n. 4
0
        private SExp evalAddto(SExp exp)
        {
            var name = eval_getVariname(exp);

            SExp e = getVariable(name); // 追加開始する初期文字列として変数の元の値を入れておく
            if (e == SExpUndef)
                e = null;

            foreach_SExp(
                exp.next,
                o => e = concatSExp(e, SExp2cloneReplaceVariable(o))
                );

            setVar(name,e);

            return e;
        }
Esempio n. 5
0
        // 配列の要素にindex指定でアクセスする。
        // (array x 3) のようにしてアクセスする
        private SExp evalArray(SExp exp)
        {
            SExp array = Elms2SExp2(exp);
            var index = eval_getNum(exp.next);

            return evalArrayOf(array, index);
        }
Esempio n. 6
0
 // SExpに対して、その後続要素がnullであるかどうか。
 private static bool isNextNull(SExp exp)
 {
     return exp == null || exp.next == null || exp.next.elms == null;
 }
Esempio n. 7
0
        // expのElmsをSExpに変換その2
        // 変数名 → 中身のSExp
        // 文字列 → WrapしたSExp
        // SExp   → 評価してSExpとして返す
        // (eq param1 param2) のような形でパラメータをとる関数に使うと良い。
        private SExp Elms2SExp2(SExp exp)
        {
            if (exp == null)
                return SExpNull;
            var elms = exp.elms;
            if (exp == null)
                return SExpNull;

            if (elms is VarName)
            {
                return getVariable((elms as VarName).name);
            }
            if (elms is string)
            {
                return string2SExp(elms as string);
            }
            if (elms is SExp)
                return eval(elms as SExp);

            return SExpNull;
        }
Esempio n. 8
0
        // tolowerなど (tolower x 'AAA') のような形でパラメータをとるタイプの
        // 命令を簡単に実装できるようにするためのヘルパクラス
        private SExp eval_tolower_helper(SExp exp, Func<string, string> dg)
        {
            // 代入する変数
            if (!(exp.elms is VarName))
                return null;

            var name = (exp.elms as VarName).name;

            // そこ以降を文字列として連結する。
            var s = SExp2string(evalGet(exp.next));

            return setVar(name , string2SExp(dg(s)));
        }
Esempio n. 9
0
 private void foreach_num(SExp exp, Action<double> dg)
 {
     while (exp != null && exp.elms != null && breakLabel == null)
     {
         dg(eval_getNumDouble(exp));
         exp = exp.next;
     }
 }
Esempio n. 10
0
 // exp.elmsがS式ならそれを評価して文字列化して返す。文字列ならそのまま返す。変数名なら評価して返す。
 private string eval_getString(SExp exp)
 {
     return SExp2string(Elms2SExp2(exp));
 }
Esempio n. 11
0
        // exp.elmsに保持している変数名を取得する。ダブルコーテイションで囲まれた文字列はエラーになる。
        // SExpの場合、それを評価して文字列化する。
        private string eval_getVariname(SExp exp)
        {
            if (exp.elms is SExp)
            {
                return SExp2string( eval(exp.elms as SExp) );
            }

            // 変数名を意味する文字列のはずなので、これをそのまま返す
            // 文字列のはずだが、これがダブルコーテイションで囲われていたり、数値であったりしてはいけない。
            var ss = exp.elms as VarName;
            if (ss == null)
                throw new LispException("変数名が来ていない。");
            if (!LispUtil.isVariableName(ss.name))
                throw new LispException("変数名として"+ss+"はおかしい。");
            // 何故変数名が " "で囲われているのかは知らないが
            // 本来ありえないはず。

            return ss.name;
        }
Esempio n. 12
0
        // eval_getNumのdoubleで返す版
        private double eval_getNumDouble(SExp exp)
        {
            if (exp == null || exp.elms == null)
                return 0;

            double u;
            try
            {
                u = double.Parse(eval_getString(exp));
            }
            catch
            {
                u = 0;
            }
            return u;
        }
Esempio n. 13
0
        // exp.elmsがS式ならそれを評価して文字列化、文字列ならそのまま。
        // そして、それを数値にparseして返す
        private long eval_getNum(SExp exp)
        {
            if (exp == null || exp.elms == null)
                return 0;

            long u;
            try
            {
                u = long.Parse(eval_getString(exp));
            }
            catch
            {
                u = 0;
            }
            return u;
        }
Esempio n. 14
0
        private SExp evalWrite(SExp exp)
        {
            var sb = new StringBuilder();
            foreach_SExp(
                exp,
                o => sb.Append(evalOut_(o))
                );

            string ret = sb.ToString();

            // 出力ファイル名
            var filename = SExp2string(getVar("outfile"));
            if (filename != null && filename != "#undef")
            {
                // BOMで書き出すように変更(2009/11/6) これならBOMが追加される。
                using (var sw = new StreamWriter(filename, true , Encoding.UTF8))
                {
                    sw.WriteLine(ret);
                }
            }
            return string2SExp(ret);
        }
Esempio n. 15
0
        // ElmsをSExpに
        // x = ( exp1 exp2 exp3) のようなコレクションに対してforeachで回すときに使う。
        // exp = exp1 を指しているとき、これを参照透明と仮定して、SExpに包みたい
        // ときに使う
        private static SExp Elms2SExp(SExp exp)
        {
            var elms = exp.elms;
            SExp ret = null;
            if (elms is string)
                ret = string2SExp(elms as string);
            else if (elms is SExp)
                ret = elms as SExp;
            else if (elms is VarName)
                // ここに来て変数名かよ..
                ret = new SExp {elms = exp};

            return ret;
        }
Esempio n. 16
0
 // S式の内容を評価する。
 private void foreach_SExp(SExp exp, Action<SExp> dg)
 {
     while (exp != null && exp.elms != null && breakLabel == null)
     {
         dg(Elms2SExp2(exp));
         exp = exp.next;
     }
 }
Esempio n. 17
0
 // arrayのN番目の要素を返す、下請け関数
 private static SExp evalArrayOf(SExp exp, long index)
 {
     if (exp == null)
         return SExpNull;
     for (long i = 0; i < index; ++i)
     {
         exp = exp.next;
         if (exp == null)
             return SExpNull;
     }
     return Elms2SExp(exp); // 参照透明なのでcloneする必要がない。
 }
Esempio n. 18
0
        // 変数名を実体に置換しながら、Cloneしていく。
        private SExp SExp2cloneReplaceVariable(SExp exp)
        {
            incStack();

            var elms = exp.elms;
            if (elms is SExp)
            {
                var el = elms as SExp;
                var newexp = new SExp {elms = SExp2cloneReplaceVariable(el)};
                if (!isNextNull( exp.next ) )
                    newexp.next = SExp2cloneReplaceVariable(exp.next);
                return newexp;
            }
            if (elms is VarName)
            {
                // これを評価して返す必要がある。
                var el = getVariable((elms as VarName).name);
                var newexp = new SExp { elms = SExp2cloneReplaceVariable(el) };
                newexp = concatSExp(newexp,SExp2cloneReplaceVariable(exp.next));
                return newexp;
            }
            if (elms is string)
            {
                // stringは参照透明なので、cloneする必要はない。
                var newexp = new SExp { elms = elms };
                if (!isNextNull( exp ) )
                    newexp.next = SExp2cloneReplaceVariable(exp.next);
                return newexp;
            }
            // それ以外ってnullか?
            return null;
        }
Esempio n. 19
0
        private SExp doCommand(string command, SExp s)
        {
            var param = s.next;
            try
            {
                switch (command)
                {
                    // 文字列追加
                    case "addto":
                        return evalAddto(param);

                    // 加算
                    case "add":
                        return evalAdd(param);

                    // 減算
                    case "sub":
                        return evalSub(param);

                    // 掛け算
                    case "mul":
                        return evalMul(param);

                    // 割り算
                    case "div":
                        return evalDiv(param);

                    // 配列のgetter
                    case "array":
                        return evalArray(param);

                    // 配列のsetter
                    case "setarray":
                        return evalSetArray(param);

                    case "length":
                        return evalLength(param);

                    // 出力 console
                    case "out":
                        return evalOut(param);

                    // ファイルにwrite   'outfile'という変数がファイル名を示す。
                    case "write":
                        return evalWrite(param);

                    // 式を評価して、その値を返す
                    case "get":
                        return evalGet(param);

                    // ファイルの削除
                    case "del":
                        return evalDeleteFile(param);

                    // 後ろの値を評価せずに代入
                    case "let":
                        return evalLet(param);

                    // 後ろの値を評価してから代入
                    case "set":
                        return evalSet(param);

                    // 関数の定義用。
                    case "func":
                        return evalFunc(param);

                    case "break":
                        return evalBreak(param);

                    case "eval":
                        return evalEval(param);

            //					case "evalweak":
            //						return evalEvalWeak(param);

                    case "evalinclude":
                        return evalEvalInclude(param);

                    case "evalimport":
                        return evalEvalImport(param);

                    case "evalstr":
                        return evalEvalStr(param);

                    // 文字置換
                    case "replace":
                        return evalReplace(param);

                    // 正規表現置換
                    case "regex":
                        return evalRegex(param);

                    //  foreach
                    case "foreach":
                        return evalForeach(param);

                    // print
                    case "print":
                        return evalPrint(param);

                    // 回数指定繰り返し
                    case "loop":
                        return evalLoop(param);

                    // 小文字化
                    case "tolower":
                        return evalTolower(param);

                    // 大文字化
                    case "toupper":
                        return evalToupper(param);

                    // 条件分岐
                    case "if":
                        return evalIf(param);

                    // ==
                    case "eq":
                        return evalEq(param);

                    // !=
                    case "neq":
                        return evalNeq(param);

                    // and
                    case "and":
                        return evalAnd(param);

                    // or
                    case "or":
                        return evalOr(param);

                    // 制御構造

                    // while
                    case "while":
                        return evalWhile(param);

                    // for
                    case "for":
                        return evalFor(param);

                    // downfor ループカウンタが1ずつ減るfor
                    case "downfor":
                        return evalDownfor(param);

                    //  永久ループ
                    case "forever":
                        return evalForever(param);

                    case "switch":
                        return evalSwitch(param);

                    // 比較演算子

                    // less or equal
                    case "le":
                        return evalLe(param);

                    // less than
                    case "lt":
                        return evalLt(param);

                    // greater equal
                    case "ge":
                        return evalGe(param);

                    // greater than
                    case "gt":
                        return evalGt(param);

                    // 本家LISPの機能

                    case "car":
                        return evalCar(param);

                    case "cdr":
                        return evalCdr(param);

                    // ファイルを読み込み、それをS式とする。
                    // ただし、S式は //%で始まる行
                    case "import":
                        return evalImport(param);

                    // ファイルを読み込み、それをS式とする。
                    case "include":
                        return evalInclude(param);

                    // 以下、ユーティリティ
                    case "rand":
                        return evalRand(param);

                    // 以下、unroller(YaneC)
                    case "unroller":
                        return evalUnroller(param);
                }

                // ユーザー定義関数であれば、それをevalして返す
                if (functions.ContainsKey(command))
                {
                    // local変数が使えるようにする。
                    // 後続要素を評価して、それらを次のコンテキストのlocal変数に突っ込む
                    var local = new Dictionary<string, SExp>();

                    int i = 0;
                    while (param!=null && param.elms != null)
                    {
                        // @0,@1,@2,…というローカル変数に突っ込む
                        local["@" + i] = Elms2SExp2(param);
                        ++i;
                        param = param.next;
                    }

                    // ローカル変数コンテキストを切り替える。
                    localVariables.Push(local);

                    var ret = eval(functions[command]); // 評価

                    // ローカル変数コンテキストを戻す
                    localVariables.Pop();

                    return ret;
                }

            }
            catch (Exception ex)
            {
                string error = command + "で例外発生。 (" + ex.Message + ") 場所 "
                               + s.line + " 行 (" + s.sourcePos + ")";
                Console.WriteLine(error);
                return string2SExp(error);
            }

            // error("Eval不可能な式 :" + command ,s.elms);
            {
                string error = command + "は、evalできない。場所" + s.line + " 行 (" + s.sourcePos + ")";
                Console.WriteLine(error);
                return string2SExp(error);
                // エラーメッセージを文字列として返す。
            }
        }
Esempio n. 20
0
 // Lisp.evalの返し値(SExp)を読みやすい形式に変換して返す。
 // 返されたものがstring(文字列)なら、わかるように ' 'で囲って返す。
 public static string eval(SExp e)
 {
     var lisp = new Lisp();
         var ret = lisp.eval(e);
         return lisp.SExp2string(ret);
 }
Esempio n. 21
0
 // 加算
 private SExp evalAdd(SExp exp)
 {
     double sum = 0;
     foreach_num(
         exp,
         n => { sum += n; }
     );
     return string2SExp(sum.ToString());
 }
Esempio n. 22
0
        public SExp eval(SExp s)
        {
            evalCount++; // evalの深さを測定しておく。

            try
            {

                if (s == null || s.elms == null)
                    return null; // 評価不可能

                // 外側のラベルめがけてbreak中なのか?
                if (breakLabel != null)
                    return null;

                // 現在実行しているステートメントを例外発生時の表示のために保持しておく。
                evalNow = s;

                var exp = s.elms as SExp;
                if (exp != null)
                {
                    // ( (add 1 2) (sub 4 3) )のようにコマンドが並んでいるケース。
                    // この場合、後続するリストもすべて実行する必要がある..
                    if (s.next != null)
                    {
                        var o1 = eval(exp);
                        var o2 = eval(s.next); // 最後の要素が評価されてこのevalの値になるはずだが
                        return o2 ?? o1;
                    }
                    return eval(exp);
                }

                var command = s.elms as VarName;
                if (command != null)
                {
                    stackCount = 0; // stack overflowの防止用

                    var name = command.name; // コマンド名

                    // コマンド名に見えるものは実はラベルなのか?
                    var label = isLabel(name);
                    if (label != null)
                    {
                        labels.Push(label);
                        SExp ret = (s.next != null) ? eval(s.next) : null;
                        labels.Pop(); // このスコープから抜けるのだから、ラベルはもう不要になる…はず

                        // このlabelからbreakしている最中なら、そのbreak labelをリセット
                        if (label == breakLabel)
                            breakLabel = null;

                        return ret;
                    }
                    else
                    {
                        // 命令なので実行する。
                        return doCommand(name, s);
                    }
                }

                // stringなら無視しとけばいいか。
                // return string2SExp( command + "は、evalできない。場所 : " + s.line + " 行 (" + s.sourcePos + ")");

                if (!isNextNull(s))
                    return eval(s.next);

                return null; // 駄目ぽ

            }finally
            {
                evalCount--;
                if (evalCount == 0 && breakLabel!=null)
                    throw new LispException("breakラベル"+ breakLabel+"が見つからない。" );
            }
        }
Esempio n. 23
0
        // 論理and(&&)
        private SExp evalAnd(SExp param)
        {
            var elms1 = Elms2SExp2(param);
            var elms2 = Elms2SExp2(param.next);

            // 			return (elms1 == SExpTrue && elms2 == SExpTrue)
            //		↑これだと、user側が#true定数を作れなくて困る?(´ω`)

            return (SExp2string(elms1) == "#true" && SExp2string(elms2) == "#true")
                    ? SExpTrue : SExpFalse;
        }
Esempio n. 24
0
        // 変数名に値を設定する。
        public SExp setVar(string name, SExp exp)
        {
            // 変数名が@で始まるなら、それはlocal変数
            if (string.IsNullOrEmpty(name))
                return null;

            if (name[0] == '@')
            {
                if (localVariables.Count == 0)
                    throw new LispException("トップレベルでローカル変数は使えない。");

                return localVariables.Peek()[name] = exp;
            }

            return variables[name] = exp;
        }
Esempio n. 25
0
 // ラベルめがけてのbreak(JavaScript風)
 private SExp evalBreak(SExp exp)
 {
     var name = eval_getVariname(exp); // これがbreakラベル
     breakLabel = name;
     return null;
 }
Esempio n. 26
0
        // SExpの最初のエレメントの持っている文字列を取得する。
        public string SExp2string(SExp exp)
        {
            if (exp == null || exp.elms == null)
                return "";

            var elms = exp.elms;
            string s;
            if (elms is VarName)
                s = "#VarName:" + (elms as VarName).name;
            else if (elms is SExp)
                s = SExp2string(elms as SExp); // 再帰的に文字列化
            else if (elms is string)
                s= elms as string;
            else
                s = "#noname";

            return s + (!isNextNull(exp) ? SExp2string(exp.next) : "");
        }
Esempio n. 27
0
 // cdr
 private SExp evalCdr(SExp exp)
 {
     SExp array = Elms2SExp2(exp);
     if (isNextNull(array))
         return SExpNull;
     return array.next; // 後続要素
 }
Esempio n. 28
0
        // SExp同士を連結する
        private static SExp concatSExp(SExp e1, SExp e2)
        {
            var exp = e1;
            if (e1 == null)
                return e2;

            while (true)
            {
                if (isNextNull(exp) )
                {
                    exp.next = e2;
                    return e1;
                }
                exp = exp.next;
            }

            // expをe2に置換する。すなわち、一つ前のに置換してしまう。
        }
Esempio n. 29
0
 // 割り算
 private SExp evalDiv(SExp exp)
 {
     double sum = 1;
     bool isFirst = true;
     foreach_num(
         exp,
         n =>
             {
                 if (isFirst)
                 {
                     sum = n;
                     isFirst = false;
                 }
                 else
                     sum /= n;
             }
     );
     return string2SExp(sum.ToString());
 }
Esempio n. 30
0
 private SExp evalUnroller(SExp param)
 {
     var f = eval_getString(param);
     var u = new YaneUnroller.Unroller();
     var tree = u.ParseProgram(f);
     return string2SExp(tree.ToString());
 }