スポンサーサイト

0

    一定期間更新がないため広告を表示しています

    • 2016.05.19 Thursday
    • -
    • -
    • -
    • -
    • -
    • by スポンサードリンク

    【D言語】PHPみたいにHTMLにコードを埋め込みたい。

    0
       スクリプト言語のRubyには、PHPのようにテキスト中にコードを埋め込めるeRubyというものがあります。これを使うと、HTML中にRubyスクリプトを埋め込めるため、動的なページを作成するときにすっきりとした構造にすることができます。

       一方、D言語はコンパイル言語ですが、rdmdというあたかもDコードをスクリプトのように実行できるツールがあります。私はサーバーサイドでの動的なページ生成をするつもりはありませんが、HTMLを全て直書きで管理しているというわけではありません。ローカルの環境で、ページのテンプレートからプログラムを使ってアップするHTMLを生成することを考えているわけです。PHPでもいいのですが、D言語の表現力で色々とやってみたいときもあるわけです。

       そこで、ページ中に埋め込んだコードを実行するツールを作ってみようと思い立ちました。まだ完成しているわけではありませんが、一応ソースを生成して実行できるところまではできました。

      import std.algorithm;
      import std.exception;
      import std.regex;
      import std.file;
      import std.path;
      import std.process;
      import std.stdio;
      import std.string;
      import core.stdc.time;

      void showUsage(){
      writeln("Embeded D Interpreter.");
      writeln("¥t Usage: emd options...");
      writeln("¥t Options:");
      writeln("¥t --input=FILE : input file.(require)");
      writeln("¥t -h/--help : show this message.");
      writeln("¥t -v/--version : show version.");
      writeln("¥t Note: This tool cannot handle other than UTF-8 input.");
      }

      string[string] parseOptions(string[] args){
      string[string] options;

      foreach(arg; args){
      auto eq = arg.indexOf('=');
      if(eq != -1){
      options[arg[0..eq]] = arg[eq+1..$];
      }else{
      options[arg] = "";
      }
      }

      return options;
      }

      int main(string[] args){
      auto options = parseOptions(args[1..$]);

      if("-h" in options || "--help" in options || !("--input" in options)){
      showUsage();
      return -1;
      }else if("-v" in options || "--version" in options){
      writeln("Embeded D Interpreter ver 1.0");
      return -1;
      }

      char[] input;
      try{
      input = replace(cast(char[])std.file.read(options["--input"]),"¥r¥n","¥n");
      }catch(FileException e){
      stderr.writeln(e);
      return -1;
      }

      auto maincode = `write(r"`
      ~ replaceAll!(caps => `");` ~ caps[1] ~ `write(r"`)(input,ctRegex!(r"<%dlang¥s([¥S¥s]+?)¥s%>"))
      ~ `");`;

      auto dsrcdir = buildPath(tempDir(),"EmbededD");
      auto dsrcname = buildPath(dsrcdir,format("%s%s.d",stripExtension(options["--input"]),time(null)));

      try{
      if(!exists(dsrcdir)){
      mkdir(dsrcdir);
      }
      File(dsrcname,"w").writeln("import std.stdio;¥n","void main(string[] args){¥n",maincode,"}");
      }catch(ErrnoException e){
      stderr.writeln(e);
      return -1;
      }catch(FileException e){
      stderr.writeln(e);
      return -1;
      }

      auto result = executeShell("rdmd " ~ dsrcname);
      write(result.output);

      return 0;
      }

      【D言語】式として評価可能なSwitchを書いてみた。

      0
         お遊びですが、Rubyなどで採用されている表現ですが、式として評価できるswitchを書いてみました。見た目も速度も実用的ではないでしょうけれども、D言語の表現力を応用するとこういうこともできるという一例です。


        auto switch_(R,T)(T value){
        return new class(value){
        T value_;
        bool delegate(T v,ref R r) switch_body;
        public this(T value){
        value_ = value;
        switch_body = (T v,ref R r){return false;};
        }
        public auto case_(RV)(T case_value,lazy RV result){
        auto switch_body_old = this.switch_body;
        static if(__traits(compiles,result()())){
        switch_body = (T v,ref R r){
        if(switch_body_old(v,r)){
        return true;
        }else if(v == case_value){
        r = result()();
        return true;
        }
        return false;
        };
        }else{
        switch_body = (T v,ref R r){
        if(switch_body_old(v,r)){
        return true;
        }else if(v == case_value){
        r = result();
        return true;
        }
        return false;
        };
        }
        return this;
        }
        public auto default_(RV)(lazy RV result){
        R r;
        if(switch_body(value_,r))return r;
        static if(__traits(compiles,result()())){
        return result()();
        }else{
        return result();
        }
        }
        public auto end(){
        return default_(function R(){throw new Exception("No Case Executed.");});
        }
        };
        }


         使い方はこうです。

        auto y = switch_!string(x)
        .case_(1,"one")
        .case_(2,"two")
        .case_(3,"three")
        .default_("unknown");

         ちなみに、関数リテラルなど、デリゲートあるいは関数ポインタを引数に取ることもできます。このとき、引数なしで呼び出したときの戻り値がこの式の値になります。したがって、デリゲートあるいは関数ポインタは引数なしであり、かつswitch_のテンプレート第1引数に変換可能な値である必要があります。
         default_の代わりにendで締めくくると、caseで引っかからなかった場合に例外が創出されるようになります。つまり、switch_の評価値が必ずcase_によって捕捉されるということを意味します。また、内部的にはifと==を用いているため、caseの式は定数でなくともいいということになります。

         繰り返しますが、実用性は期待できません。ただ、私はもしも機会があるなら使うかもしれません。

        【Windows API】コントロールのスーパークラス化

        0
           Windows APIにおいてコントロールを独自にカスタマイズしたい場合、サブクラス化と呼ばれる手法と、スーパークラス化(*1)と呼ばれる手法が存在します。今回は後者の方法について取り上げてみたいと思います。

           スーパークラス化というのは、コントロールのウィンドウクラスの情報を取得して、情報を書き換えて別名で登録することで、既存のコントロールを基にしたウィンドウクラスを作成・登録するという方法です。サブクラス化と異なるのは、サブクラス化は個々のインスタンスのプロシージャを書き換えますが、スーパークラス化は全く別のウィンドウクラスを作成してしまうという点にあります。一方で、サブクラス化と同じく自分でプロシージャを用意して、処理しきらなかったメッセージは元のプロシージャに流すということは共通します。

           処理の肝は、GetClassInfoEx APIでWNDCLASSEX構造体を初期化することです。第一引数はウィンドウクラスが登録されているインスタンスハンドルですが、Windowsが標準で用意しているウィンドウクラスをベースにする場合はNULLを指定します。

           後は、そのウィンドウクラスを登録して、登録したクラス名でCreateWindowを呼ぶだけです。デフォルトのプロシージャはサブクラス化同様CallWindowProcを通して呼び出します。


          // スーパークラス化した後のプロシージャ
          LRESULT FileOpenProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

          //後で元のプロシージャと入れ替えるので、スーパークラス化後のプロシージャで初期化しておく。
          WNDPROC lpDefStaticProc = &FileOpenProc;

          LRESULT FileOpenProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){
          switch(uMsg){
          case WM_LBUTTONDBLCLK:{
          //ここらのエラー処理は省略。本質ではないので。
          TCHAR pathText[MAX_PATH+10];
          GetWindowText(hWnd,pathText,ARRAYSIZE(pathText));
          ShellExecute(nullptr,_T("open"),pathText,nullptr,nullptr,SW_SHOWDEFAULT);
          break;
          }
          }
          return CallWindowProc(lpDefStaticProc,hWnd,uMsg,wParam,lParam);
          }

          /*
          * 以下、スーパークラス化のコード
          * この関数はRegiterClassExが成功したときに真を返す。
          */
          BOOL InitFileOpenStaticControl(){
          WNDCLASSEX fileOpenClass;

          //
          GetClassInfoEx(nullptr,_T("STATIC"),&fileOpenClass);

          //取得した情報を書き換える。
          fileOpenClass.style |= CS_DBLCLKS;

          //デフォルトのプロシージャを保存しておく(std::swapで書き換え後のプロシージャと入れ替える)
          std::swap(fileOpenClass.lpfnWndProc,lpDefStaticProc); //要C++、<utility>ヘッダ

          //新しいウィンドウクラス名をつける
          fileOpenClass.lpszClassName = _T("FileOpen");

          return RegisterClassEx(&fileOpenClass) ? TRUE : FALSE;
          }


          *1:「スーパークラス化」という用語法は、オブジェクト指向言語における継承元クラスのことを指す「スーパークラス」と混同しやすいのですが、両者は全く別物です。むしろオブジェクト指向でいうところの派生に近いと思うんですが…

          LLVM+ClangをVisual C++でビルドしてみた。

          0
             LLVM+Clang(version 3.7.1)をVisual C++でビルドしてみました。
             Clangは、Windows環境では、MinGWとVisual C++でビルドすることができますが、ビルドされたClangは、ビルドした環境にコンパチブルなコンパイラになります。Visual C++でビルドすると、Visual C++に依存する(具体的には、MS-COFF形式のオブジェクトファイルを吐きだし、バックグラウンドでVisual C++ Linkerを用いてEXE形式のファイルを生成する)ことになります。公式ビルドのClangはMinGWビルドで、clang-clはVC互換です。

            さて、ビルドには以下のツールを用意しました。
            CMake
             私の環境では3.3.0-rc4ですが、LLVMのCMakeLists.txtを読む限り、バージョン2.8.12.2よりも新しいものであれば大丈夫みたいですね。試してないので分かりませんが。
            Python
             これも必要です。どこかでPythonは3系列ではダメだということを見たことがあるので2.7を入れてます。python.exeのあるディレクトリにパスを通しておきます。
            ・ Visual Studio 2015 community, 2013 express edition
             今回はこの2つで試してみました。結果からいうと、いずれでも問題なくバイナリが生成されます。

            以下、私が実行した手順です(ディレクトリについては伏せてあります)。

            (1) まず、「Download LLVM 3.7.1」からLLVM source codeとClang source codeを落としてきます。解凍は7-zipで行いました。以下、llvm-3.7.1.src.tar.xzを解凍した場所(書き込みが出来ればどこでもいいです)を"D:¥Projects¥LLVMSource"として話を進めていきます。
            (2) D:¥Projects¥LLVMSource¥toolsにcfe-3.7.1.src.tar.xzを解凍したディレクトリを配置します。私はclangとリネームしましたが、別にしなくてもいいようです(CMakeがサブディレクトリも検索するので)。
            (3) CMake-guiを起動して、SourceディレクトリにD:/Projects/LLVMSourceを指定します。buildディレクトリは書き込みができればどこでもいいですが、ここではD:/Projects/LLVMBuildsを指定しておきます。
            (4) Configureを押すと、ビルド環境を設定するダイアログが出てきます。ここでビルドに使用するVisual Studioを選択するわけですが、ここでWin64と書いてあるのを選ぶと、生成されるバイナリが64bitコードになります。ただし、64bitバイナリになってもclangで32bit向けのバイナリを生成することは出来ます。ただ、Visual Studio 2013 expressの方では、64bitでコンパイルしようとすると、32bit/64bitいずれのClangもリンカを呼び出せずエラーになってしまいました。ただし、いったんobjファイルを生成してからlink.exeに渡すとうまくいきました。(*1)
            (5) 画面が真っ赤になります。これはCMakeが設定に関する変数を要求するからです。まず、次の変数を書き換えました。

            ・CMAKE_INSTALL_PREFIX : LLVMのインストール場所です。最終的にはここにLLVMが構築されます。各自の環境に合わせて設定します。

            他の変数については「Building LLVM with CMake」に詳細が書いてありますが、私は以下の変数を書き換えました。

            ・LLVM_DEFAULT_TARGET_TRIPLE : LLVMが生成するバイナリのデフォルトのターゲット環境です。Clangもこれに準じます。(4)でWin64を選んだ人はx86_64-pc-win32になっていると思います。32bitでコンパイルするのであればi686-pc-win32になります。
             これの何が問題かというと、Visual Studio 2015 Communityでは、デフォルトのままだとVCのコンパイラの内部バージョンと齟齬をきたしてしまい、このような問題が生じてしまいます。そこで、Visual Studio 2015 Communityのときは、"i686-pc-windows-msvc19"(64bitの場合は"x86_64-pc-windows-msvc19")と書き換えました。これでうまくいきます。(*2)
            (6) もう一度Configureを押すと、設定変数に異常がなければ画面が真っ白になります。赤い変数が残っている場合は変数に入れられない値が設定されているので修正します。全て白くなればGenerateを押します。するとD:/Projects/LLVMBuildsにVisual C++のソリューションが生成されます。
            (7) できたソリューションをVisual C++ IDEでビルドします。このとき、設定がDebugのままだとDebug用のバイナリが生成されますが、これだと速度もサイズもムダなので、Release(速度優先最適化)か、あるいはMinSizeRel(バイナリサイズ優先最適化)に変更します。ここでソリューションをビルドして、その後でINSTALLプロジェクトをビルドします。ただし、プロジェクト同士の依存関係上、INSTALLプロジェクトをビルドすればそれだけでも作業が完了します。
            (8) プロジェクトはかなり巨大なので、そこそこ時間がかかります。私のPCだと30分くらいでしたが、環境によるのでなんともいえないです。ビルド中はメモリもCPUも相当食います。

             これでVisual C++でLLVM+Clangでのビルドが完成するはずです。ここでビルドしたClangを使うときは、Visual Studioコンソールから使うのがいいだろうと思います。Clangのオプションはmingw向けのものと基本的に変わらないようですが、LIBCがデフォルトで/MT相当なようなので、必要であれば-MDとか、-MTdとかの指定が必要みたいです。あと、-m32/-m64オプションで、clangの吐き出すバイナリのメモリモデルを指定できます。
            【訂正】clangがVCコンパチブルで使用される場合のlibcについては、吐き出されたオブジェクトファイルはlibc中立です。したがって、clangで作成したオブジェクトファイルは、いずれのlibcともリンクすることができます。

            *1: 原因は、Clangが内部的にVCリンカを探すときに、Visual C++のクロスツールの存在を考慮しないので、VS2013 Expressのx64向けのC++ビルドツールを呼び出せないことにあります。VS2015 CommunityではX64向けのネイティブツールが存在するので、無事にコンパイルできます。
            *2: clangに-fms-compatibility-version=19.0.0を渡せばLLVM_DEFAULT_TARGET_TRIPLEを変更しなくても回避できます。

            MinGWのバイナリってどれがいいのかなぁ…

            0
              ここがMinGW本家版
              MSYS and mingwPORT Projects
              こちらがTDM版
              TDM-GCC

              これ以外にも、検索すれば大量に出てきます。

              GetMessageの戻り値 MSDNのミス?

              0
                Windows APIに「GetMessage」という関数があります。これはメッセージキューにメッセージが来るまで待ち続け、メッセージがプッシュされると処理を返し、MSG構造体に処理に必要な情報をセットする関数です。
                で、GetMessageの戻り値は、WM_QUITメッセージを取得すれば0、それ以外のメッセージを取得すると0以外の値を返すのですが、失敗時に-1を返します。そこで、次のようなメッセージループは書いてはいけないと「GetMessage関数 - MSDNライブラリ」に書いています。


                while(GetMessage(&msg,0,0,0)){ //失敗時-1を返す、つまりループは継続してしまう。
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                }


                ところが、
                http://msdn.microsoft.com/ja-jp/library/ff381405%28VS.85%29.aspx
                これやっちゃてるし… ドキュメント内で統一されていないというのはまずいのではないだろうか。

                相互リンク1件受け付けました。

                0
                  れいさんよりメールをいただきまして、先ほど、こちらからのリンクを貼らせていただきました。

                  プログラミング超初心者のPHP挑戦日記
                  プログラミング初心者の翻訳家がPHPに挑戦!

                  相互リンクは大歓迎ですので、希望される方はご一報ください。

                  Win32 Native の文字コード(3)

                  0
                    前に文字コードの話をしましたが、MSDNで面白い記事を見つけました。

                    文字列を使用する (Windows)

                    前の記事では、もはやTCHARによるAnsi/Unicode両対応ではなく、Unicodeにのみ対応しても全く問題ないだろうという意見を述べました。しかし、Microsoftは「も全く問題ないだろう」というよりも、「移行しなさい」という感じの記事を書いています。
                    Microsoftによれば、新しいAPIではAnsi版を提供しないそうです。新しいソフトウェアでは、TCHARは使われなくなったとか…

                    COM(OLE)ではOLECHARとかいう型が使われるらしいが、これはwchar_tと同等だそうだ…

                    Win32 Native の文字コード(2)

                    0
                      (1)に引き続いて、文字コードの話題を…

                      前回、NT系のWindowsは内部処理にUTF-16を用いると説明しました。APIの実装も、Ansi版は引数の文字列を変換してUnicode版の関数に処理を引継ぐようになっていると説明しました。

                      そこで、DLLを作成するときに、Ansi版インターフェイスなしで、Unicodeを受け取るインターフェイスだけを提供するという選択肢はどの程度「アリ」か?ということを考えてみたいと思います。
                      C/C++からの呼び出し → OK
                      .NETのDllImport経由 → OK
                      D言語からの呼び出し → OK
                      と、かなり恣意的な考え方ではありますが、そんなに問題なさそう…

                      最近の処理系はUnicodeを中心とするものも増えているので、ある程度「アリ」ではないでしょうかね…

                      テンプレートを変更しました。

                      0
                        シンプルイズベストということで、こちらに変更しました。
                        あと、MixC++にアカウントを開設しました。こちらもよろしく。
                        URL:http://dixq.net/forum/blog.php?u=673

                        | 1/4PAGES | >>

                        PR

                        calendar

                        S M T W T F S
                            123
                        45678910
                        11121314151617
                        18192021222324
                        252627282930 
                        << June 2017 >>

                        selected entries

                        categories

                        archives

                        recent comment

                        recommend

                        links

                        profile

                        search this site.

                        others

                        mobile

                        qrcode

                        powered

                        無料ブログ作成サービス JUGEM