C#|Brainf*ckの処理系を書いてみた。

 唐突ですが、ちょっとやってみたくなったんです。

 まずはインタプリタ

using System;

using System.Collections.Generic;

using System.IO;

using System.Text;

class Program {

    static void Main(string[] args) {

        if(args.Length == 0) {

            Console.WriteLine("ソースファイルを指定して下さい。");

            return;

        }

        int memorySize = 256/**************************************************
                              *BrainFuckコードの実行に割り当てるメモリーサイズ。*
                              *実行するコードに対して充分な大きさが必要。       *
                              **************************************************/

        //ヘルプの表示

        if(args[0].ToLower().Contains("help") || args[0].ToLower().Contains("?")) {

            Console.WriteLine(

@"bfi [ドライブ:][パス]ファイル名[メモリサイズ]

メモリサイズ    プログラム実行の為に確保するメモリのサイズです。充分なサイズを指定して下さい。
                大き過ぎても落ちるかも…。規定値は256。");

            Console.ReadLine();

            return;

        }

        //ソースファイルの読み込み*/

        string src;

        string srcFile = Environment.CurrentDirectory + "\\" + args[0];

        if(File.Exists(args[0])) {

            srcFile = args[0];

        } else if(!File.Exists(srcFile)) {

            Console.WriteLine("ソースファイルがありません。");

            return;

        }

        using(System.IO.StreamReader sr = new System.IO.StreamReader(srcFile, Encoding.GetEncoding("Shift-Jis"))) {

            src = sr.ReadToEnd();

            sr.Close();

        }

        //コマンドラインオプションパーサ

        if(args.Length > 1) {

            if(!int.TryParse(args[1], out memorySize)) {

                Console.WriteLine("メモリサイズの指定が正しくありません。");

                return;

            }

        }

        brainFuck(src, memorySize);

#if DEBUG

        while(true) {

            Console.ReadLine();

        }

#endif

    }

    unsafe static void brainFuck(string src, int memorySize) {

        /*メモリーの確保と初期化*/

        byte* point = stackalloc byte[memorySize];

        byte* tmp = point;

        for(int i = 0; i < memorySize; i++) {

            *(tmp + i) = 0;

        }

        //実行

        for(int i = 0; i < src.Length; i++) {

            switch(src[i]) {

            case '>':

                point++;

                break;

            case '<':

                point--;

                break;

            case '+':

                (*point)++;

                break;

            case '-':

                (*point)--;

                break;

            case '.':

                Console.Write*1;

                break;

            case ',':

                *point = (byte)(Console.Read());

                break;

            case '[':

                if(*point == 0) {

                    i = kakko(src, i);

                }

                break;

            case ']':

                if(*point != 0) {

                    i = kakko(src, i);

                }

                break;

            }

        }

    }

    static int kakko(string src, int index) {

        int nest = 0;

        bool flag = src[index] == '[';

        for(int i = index; flag ? i < src.Length : i >= 0; i = i + (flag ? 1 : -1)) {

            if(src[i] == '[') nest++;

            else if(src[i] == ']') nest--;

            if(nest == 0return i;

        }

        return -1;

    }

}

 unsafeでポインタ使ってみました。C#だとわかるんですよね、何故か。なのにCでポインタ使って書くと動かないのは何故なんでしょう…。

 素直に配列使ってもそんなに速度変わらなかったりして、試して無いけど。List<byte>とか使えばメモリの指定が要らなくなってより安心して使えるかも知れないですね。

 次にコンパイラ

using System;

using System.CodeDom.Compiler;

using System.IO;

using System.Text;

using Microsoft.CSharp;

namespace Brainfuckコンパイラ {

    class Program {

        static void Main(string[] args) {

            if(args.Length == 0) {

                Console.WriteLine("ソースファイルを指定して下さい。");

                return;

            }

            int memorySize = 256/**************************************************
                                  *BrainFuckコードの実行に割り当てるメモリーサイズ。*
                                  *実行するコードに対して充分な大きさが必要。       *
                                  **************************************************/

            //ヘルプの表示

            if(args[0].ToLower().Contains("help") || args[0].ToLower().Contains("?")) {

                Console.WriteLine(

    @"bfi [ドライブ:][パス]ファイル名 [メモリサイズ]

メモリサイズ    プログラム実行の為に確保するメモリのサイズです。充分なサイズを指定して下さい。
                大き過ぎても落ちるかも…。規定値は256。");

                Console.ReadLine();

                return;

            }

            //ソースファイルの読み込み*/

            string src;

            string srcFile = Environment.CurrentDirectory + "\\" + args[0];

            if(File.Exists(args[0])) {

                srcFile = args[0];

            } else if(!File.Exists(srcFile)) {

                Console.WriteLine("ソースファイルがありません。");

                return;

            }

            using(System.IO.StreamReader sr = new System.IO.StreamReader(srcFile, Encoding.GetEncoding("Shift-Jis"))) {

                src = sr.ReadToEnd();

                sr.Close();

            }

            //コマンドラインオプションパーサ

            if(args.Length > 1) {

                if(!int.TryParse(args[1], out memorySize)) {

                    Console.WriteLine("メモリサイズの指定が正しくありません。");

                    return;

                }

            }

            brainFuck(src, memorySize,srcFile);

#if DEBUG

            while(true) {

                Console.ReadLine();

            }

#endif

        }

        static void brainFuck(string src, int memorySize,string srcFile) {

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("using System;");

            sb.AppendLine("class C{");

            sb.AppendLine(  "unsafe static void Main(){");

            sb.AppendLine(      "int memorySize = " + memorySize.ToString() + ";");

            sb.AppendLine(      "byte* point = stackalloc byte[memorySize];");

            sb.AppendLine(      "byte* tmp = point;");

            sb.AppendLine(      "for(int i = 0; i < memorySize; i++)*(tmp + i) = 0;");

            for(int i = 0; i < src.Length; i++) {

                switch(src[i]) {

                case '>':

                    sb.Append("point++;");

                    break;

                case '<':

                    sb.Append("point--;");

                    break;

                case '+':

                    sb.Append("(*point)++;");

                    break;

                case '-':

                    sb.Append("(*point)--;");

                    break;

                case '.':

                    sb.Append("Console.Write*2;");

                    break;

                case ',':

                    sb.Append("*point = (byte)(Console.Read());");

                    break;

                case '[':

                    sb.Append("while(*point != 0){");

                    break;

                case ']':

                    sb.Append("}");

                    break;

                }

            } 

            sb.Append("}}");

            CompilerParameters param = new CompilerParameters();

            param.OutputAssembly = Path.GetFileNameWithoutExtension(srcFile) + ".exe";

            param.GenerateExecutable = true;

            param.CompilerOptions += " /unsafe";

            CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, sb.ToString());

            foreach(string str in rs.Output) {

                Console.WriteLine(str);

            }

        }

    }

}

 コンパイラだなんて言ってカッコつけてますけど、中身はBrainf*ck→C#のトランスレータです。これをC#としてコンパイルさせてるだけです。

 やっぱインタプリタとは速度が段違いです。

 次はWhitespaceの処理系に挑戦してみようかと思っているのですが、僕にもわかるような言語仕様の説明が見付かりません。本家サイトは英語だし…。英語読めたらなぁ。努力はしませんけどね。

 うわぁ、読みにくいですね。

 ソースコードをHTMLに整形するツールを使ってみたのですが、ブログのスタイルシートが干渉して行間が…。

 やっぱ今まで通りソースファイルをそのままアップした方がよさそうですね。

*1char)(*point

*2:char)(*point

C#|ニコ動で晒されちゃいました。テヘッ

 最近、全くネタが無く更新をサボっていたあにすです。自転車になんて全く乗ってません。

 そんな久々の更新のネタはこれです。

 ニコ動で晒されてます。

 動画の一番最後、29分辺りからなのですが、僕がどう書く?orgに書いたコードを紹介して頂いてます。これ失敗作です。

 まぁ、素直に嬉しいです。

C#|2ちゃんねる専用ブラウザを作ってみた

 とりあえず動くってレベルで6時間かかりましたよ。

それでも思ったよりは楽でした、さすが.NET。

 C#でこんなことしてるサンプルってネット上探しても見付からないので、晒してみます。

実行ファイル

2ch.zip

ソースコード

2chsln.zip

 心配してた通信部分は.NETのライブラリのおかげで苦労はありませんでした。それよりも、板一覧のHTMLから板の情報を抽出する文字列処理が大変でした。しかも結構危ういんですよね。

 あとは.datの解析も仕様通りに処理すれば問題なく動きました。

 まぁ、僕のコメント一切無しのサンプル読むよりここ

http://www.monazilla.org/index.php?c=6-20

見た方が良いですよってことです。

どう書く?rg 2次元ランダムウォーク

久し振りの更新は久し振りのどう書く?投稿です。

http://ja.doukaku.org/comment/6862/

 最初はランダムウォークインターフェイスを定義して、次元数別に別のランダムウォーククラスを書きました。

 すると、次元数が変わっても共通の処理が多いことに気が付いたので、1次元のランダムウォーククラスを継承して、いくつかのメソッドをオーバーライドするだけで別の次元数のランダムウォークを書けるようにしました。

 実際に書いてみるとオーバーライドしたメソッドが一つだけだったので、引数で処理分けるだけでいいんじゃない?という結論に至りhttp://ja.doukaku.org/comment/6862/のコードになりました。

 なんとも無駄の多いコーディングでした。

C# | どう書く?org 出力の一時停止と再開

 久し振りに面白そうなトピックが出てきたので書いてみました。

http://ja.doukaku.org/comment/6359/

http://ja.doukaku.org/comment/6361/

 書いてから気付いたのですが、ネットで記事を読んだりして知ってはいたけど、実際にマルチスレッドでプログラミングするのは初めてでした。

 結構楽しいですね。

キーボードを新調しました。

 メーカー純正のキーボードのFキーとJキーが磨り減ってきたので、キーボードを新調しました。

Owltech キーボード KFK-109PS2

 タッチ音がとても静かです。友人を付き合わせて電気屋を数件回り、やっと見付けたお気に入りです。

 タッチ、キー配置、値段の最大公約数です。2000円位で買いました。展示している限りのキーボードを触りました。感触の良いキーボードは例外なく高いです。

 色々と弄っていると、どうやらメカニカルタイプのキーボードのタッチが好みのようです。しかし、高いです。

 手当たりしだいに弄っていると、どう見ても2000円しないだろうという地味な見た目のキーボードのタッチが最高なので、即決と思ったら、うわさのリアルフォースで、値段を聞いたら1万7千円くらいとのことでぶっ飛んだりしました。

 そんなこんなで、なんとか妥協出来るものを見付けて、そのキーボードでこの記事を書いています。

 悪くないです。普通のキーボードです。強いて特徴を挙げれば、タッチ音が静かなことです。パチンという高い音ではなく、カチョッっというような響かない音です。

 まぁ大事に使おうと思います。

2008年4月20日の走行記録

 今年ロード初乗りです。支笏湖まで行ってきました。千歳~支笏湖温泉辺りまで行って、のりさんととりさんと落ち合い、一緒に千歳まで引き返しました。

 やっぱ楽しいです。でも、翌日に筋肉痛が…。朝に走って、夕方に筋肉痛になって、夜には治ってた頃が懐かしいです。

 詳細は面倒なので書きません。

 サイコンデータ

走行距離 64.76km

平均速度 23.5km/h

最高速度 51.3km/h

走行時間 2h45m07s

キャリアタイプ診断

 転職ならDODA(デューダ) - 転職を成功に導く求人、転職情報が満載の転職サイトに登録している僕ですが、続けてキャリアタイプ診断なるものも試してみました。ちょっと長いですが、結果をコピペします。

 

 【総論】

 あなたは、物事の見方に関するバランスが優れており、自分の興味・関心に左右されたり、常識に縛られることなく、常に客観的な視点をもつことができるタイプと言えるでしょう。また、人の意見を聞くことと、自分自身で考えることのどちらにも偏ることなく、適切に判断できる傾向があります。

 さらに、自分の能力に対して自信があり、経験のない事柄にも物怖じせずにチャレンジできるバイタリティーを持っているため、常に可能性を信じ自らの考えや行動を貫いていける姿勢もあるようです。

 ただし、自分自身の考え方、やり方に対してこだわりを持っており、価値観が違う人の指示を受け入れなかったり、時には管理されることを拒否してしまう傾向があるようです。他者からの指示や指摘に納得いかない場面であっても、まずは相手の言わんとしていることに耳を傾けることが大切です。そうすることで、自分一人では決して気づけなかった、物事に対する新しい見方や考え方、物事を進めていく上での有効な方法などを獲得することができるでしょう。

 【性格・気質傾向】

あなたは、物事に対してとても積極的で、目の前の課題や問題に対して前向きに取り組んでいくようです。たとえ困難な状況であっても、悲観的になったりあきらめたりせずに何度でもチャレンジしようとする姿勢があります。また、自身の経験を活かしながら、物事の原因を正しく把握し、解決の糸口や手立てを見出していくなど、問題解決力にも優れています。自身の強みを理解し、それを活かしていくことによって、より大きな可能性が広がります。

 【能力傾向】

あなたは、物事に対してとても積極的で、目の前の課題や問題に対して前向きに取り組んでいくようです。たとえ困難な状況であっても、悲観的になったりあきらめたりせずに何度でもチャレンジしようとする姿勢があります。また、自身の経験を活かしながら、物事の原因を正しく把握し、解決の糸口や手立てを見出していくなど、問題解決力にも優れています。自身の強みを理解し、それを活かしていくことによって、より大きな可能性が広がります。

 【行動基準】

ここでは、あなたが普段何を基準にして行動しているか、その判断基準を見ています。あなたの場合、組織として定めた目標を達成していくことが基準となって行動するケースが多く、組織や集団の中で期待に応えていくことが重要と考えています。

 【おすすめの仕事スタイル】

あなたは、仕事を行う環境を整えたり、効率よく進めるための仕組みや流れを考え、提供していく仕事に向いているようです。また、ある特定の専門分野に関する深い知識や最新の技術を身につけながら、それを活かしていく仕事にも向いているようです。

 【おすすめの企業風土】

あなたは、自分の役割が明確で、慣例や一定のルールの中で、他の事に気を取られずにミッションに徹することができる企業風土に適しているようです。また、社歴や勤続年数などに応じて、組織や職務における役割が決定し、各職務への要求が明確な環境にも向いているようです。

 自分では大筋では当たってると思いますが、僕のことを知っている人はこの結果を見て妥当だと思うでしょうか?