Recently in プログラミング Category

本日、内輪向け勉強会でLL構文解析機について発表しました。
その際に用意した資料を公開いたします。




基本的には、

  • - 構文解析表があれば構文解析ができる
  • - DIRECTOR集合があれば構文解析表を生成できる
  • - DIRECTOR集合を計算するには所定のアルゴリズムを実行すればよい

という流れで話しました。

前回のエントリでmultipartのバウンダリ文字列を抜き取る処理を記述したけれど、
multipartを分解したいだけなら、Mail/mimeDecode.php の基本処理で事足りたようである...

<?php 
require_once('Mail/mimeDecode.php');

$_params['include_bodies'] = true;
$_params['decode_bodies'] = true;
$_params['decode_headers'] = true;
$_params['input'] = file_get_contents('php://stdin');
$_structure = Mail_mimeDecode::decode($_params);

foreach ($_structure->parts as $_part) {
    //$_part->body;
}

?>

この例では、foreachの中の

$_part->body;
で分解された個々のbodyを取得できる。
本来、multipartかどうかの処理や、その他の細かい処理が必要になるが、そこら辺はPHPプロ!の記事を参照されたい。

!!!!!multipartを分解するだけの処理を知りたい場合は、こちらを参照されたい。!!!!!

multipartのバウンダリ文字列がヘッダで渡ることを知らなくて、少しだけはまった。

本エントリでは、qmailが動いているサーバでメールを受信し、
/tmp/mail_sample.txtにバウンダリ文字列を出力するまでの過程を記述する。

qmailでは、$HOME/.qmailでメール本文を受けたときに起動するスクリプトを記述できる。
私の環境では、.qmailは次のようになっている。

$ cat ~/.qmail
| /usr/bin/php /tmp/sample_script.php

この例では、メールを受信したタイミングで/tmp/sample_script.php が起動する。

さて、/tmp/sample_script.php は次のようになっている。
(PEAR のMail_Mimeがインストールされていることを前提としている)

<?php
require_once('Mail/mimeDecode.php');

$_in = fopen("php://stdin", "r");
$_mail_text = '';
while($_line = fgets($_in)) {
    $_mail_text .= $_line;
}

$_decoder = & new Mail_mimeDecode( $_mail_text );
$_parts =$_decoder->getSendArray();
list( $_recipients, $_headers, $_body ) = $_parts;

$_ret = preg_match("/boundary=\"([0-9a-zA-Z_\-\+\=\.\:]+)\"/", $_headers['Content-Type'], $_matches);
if($_ret) {
    $_fp = fopen("/tmp/mail_sample.txt", "w");
    fwrite($_fp, $_matches[1]);
    fclose($_fp);
}
?>

ただ単純に、ヘッダからContent-Typeの列を取り出して、正規表現で抜き出すだけ。
本来なら、multipart/mixed かどうかも見るべきかと思うけれど、
multipart/mixed でない限りは"boundary"という文字列は存在しないはずなので、これでよしとしている。

なお、multipart/mixed の場合は、次のような感じの文字列を受け取れる。

multipart/mixed; boundary="-----=_NextPart_46196_50244_54292"

この場合、上記のスクリプトでは、

-----=_NextPart_46196_50244_54292

を取得できる。

コンパイラ - 構文解析 -

| | Comments (0) | TrackBacks (0)

身内の勉強会で話す(話した)内容を公開します。

前提知識

- CFG

文脈自由文法(ぶんみゃくじゆうぶんぽう、Context-free Grammar、CFG)とは、言語学や情報工学において全生成規則が以下の形式である形式文法のひとつである。 V → w ここで V は非終端記号であり、w は終端文字と非終端記号から構成される文字列である。「文脈自由」という用語は前後関係に依存せずに非終端記号 V を w に置換できることを意味している。文脈自由文法によって生成される形式言語を文脈自由言語という。(Wikipediaより)

- 記号表

名前とそれに関する型、スコープ、値(名前が定数のとき)などの情報をまとめたものを記号表という。コンパイラの中では、名前は記号表のエントリ(へのポインタ)で代表させるのがふつうである。コンパイラの解析部では記号表に名前の情報を集め、合成部では記号表を利用して目的コードを生成する。(『プログラミング言語処理系』より)

slideshareで使用したソースコードのアーカイブ(.tgz)はこちら

なお、本スライドで使用しているflexとbisonのバージョンは次の通りである。

$ flex --version
flex version 2.5.4

$ bison --version
bison (GNU Bison) 2.1
Written by Robert Corbett and Richard Stallman.

Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[参考訳 -- 法的効力は英文が適用されます]
これはフリーソフトウェアです -- 複製についての条件はソースを見ましょう。
一切の保証はありません -- 商業性や目的適合性についての保証すらありません。

Yahoo! UI Library: YAHOO Global Object

| | Comments (0) | TrackBacks (0)

このエントリはhttp://developer.yahoo.com/yui/yahoo/を元に、日本語に翻訳したものです。



YAHOO Global Object には唯一のグローバル名前空間があり、そこに全てのYUIライブラリのコードが存在します。 YAHOO Global Object はYUIライブラリを使用する全てのページでインクルードされる必要があり、 またどのYUIコンポーネントよりも先に現れなければなりません。 YAHOO Global Object はライブラリ全体で使用可能な多くのメソッドが存在します。



はじめに

YAHOO Global Object は次のようにしてインクルードします。
<!-- YAHOO Global Object ソースファイル --> 
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.1/build/yahoo/yahoo-min.js"></script>
<!-- 追加のソースファイルはここに記述する -->



YAHOO.namespace

YAHOO Object は自動的にYAHOO.utilYAHOO.widgetYAHOO.exampleなどの名前空間を自動的に生成します。 これらの名前空間はYUIライブラリの内部スクリプトのために予約されています。 カスタムアプリケーション(=ユーザが作成するアプリケーション)のために追加の名前空間を作成できます。
// "myproduct1"のための名前空間を作成する
YAHOO.namespace ("myproduct1");
YAHOO.myproduct1.Class1 = function(info) {
    alert(info);
};

// "mysubproject1"のための名前空間"myproduct2"を作成する
YAHOO.namespace ("myproduct2.mysubproject1");
YAHOO.myproduct2.mysubproject1.Class1 = function(info) {
    alert(info);
};



YAHOO.lang

YAHOO.lang にはJavaScriptのユーティリティやYUIライブラリで使用するための拡張機能が含まれています。
// true、arrayリテラルは配列です
YAHOO.lang.isArray([1, 2]);

// false、objectリテラルは配列ではありません
YAHOO.lang.isArray({"one": "two"});

// しかし、 配列として宣言された場合にはtrue になります
function() {
    var a = new Array();
    a["one"] = "two";
    return YAHOO.lang.isArray(a);
}();

// false、エレメントの集合は配列のようですが、違います
YAHOO.lang.isArray(document.getElementsByTagName("body"));

// true、falseは論理型です
YAHOO.lang.isBoolean(false);

// false、1や"true"という文字列は論理型ではありません
YAHOO.lang.isBoolean(1);
YAHOO.lang.isBoolean("true");

// nullはnullですが、undefinedや""(空文字列)はnullではありません
YAHOO.lang.isNull(null); // true
YAHOO.lang.isNull(undefined); // false
YAHOO.lang.isNull(""); // false

// functionはfunctionですが、オブジェクトはfunctionではありません
YAHOO.lang.isFunction(function(){}); // true
YAHOO.lang.isFunction({foo: "bar"}); // false

// true、整数や少数は数です
YAHOO.lang.isNumber(0);
YAHOO.lang.isNumber(123.123);

// false, strings that can be cast to numbers aren't really numbers
// false、数にキャストできる文字列は、実際には文字列ではありません
YAHOO.lang.isNumber("123.123");

// false、未定義の値や無限大の値は数ではありません
YAHOO.lang.isNumber(1/0);

// true、オブジェクト、関数、配列はオブジェクトです
YAHOO.lang.isObject({});
YAHOO.lang.isObject(function(){});
YAHOO.lang.isObject([1,2]);

// false、プリミティブな値はオブジェクトではありません
YAHOO.lang.isObject(1);
YAHOO.lang.isObject(true);
YAHOO.lang.isObject("{}");

// 文字列
YAHOO.lang.isString("{}"); // true
YAHOO.lang.isString({foo: "bar"}); // false
YAHOO.lang.isString(123); // false
YAHOO.lang.isString(true); // false
 
// undefinedはundefinedですが、nullとfalseはundefinedではありません
YAHOO.lang.isUndefined(undefined); // true
YAHOO.lang.isUndefined(false); // false
YAHOO.lang.isUndefined(null); // false



YAHOO.lang.hasOwnProperty

YAHOO.lang.hasOwnPropertyはハッシュテーブルをイテレートする際に、オブジェクトのプロトタイプに追加されたプロパティを無視するために使用します。これは元々Aグレードのブラウザをサポートするものでしたが、つい最近までSafariはサポートされませんでした。(all internal usage of the hasOwnProperty test within YUI will use the version in YAHOO.lang for the forseeable future, and we recommend that you do the same in your own implementations.)。YAHOO.lang.hasOwnPropertyは可能な限りブラウザのネイティブな関数を使用します。 (訳者注:ブラウザをグレード分けし、優先的にサポートするブラウザとそれ以外を分けることがあります。詳しくはYahoo!のドキュメントを参照してください。)
// これが保護するものです
Object.prototype.myCustomFunction = function(x) {
    alert(x);
}

var o = {};
o["foo"] = "bar";
o["marco"] = "polo";

// これが保護する必要がある部分です
for (var i in o) {
    if (YAHOO.lang.hasOwnProperty(o, i)) {
        alert("good key: " + i);
    } else {
        alert("bad key: " + i);
    }
}



YAHOO.lang.extend

YAHOO.lang.extend は他のオブジェクトを継承したオブジェクトのプロトタイプ、コンストラクタ、スーパークラスのプロパティを設定する仕組みを提供します。また、継承先オブジェクトでコンストラクタが二度実行されるないようにします。YAHOO.lang.extend はバージョン2.3.1ではYAHOO.langパッケージに再配置されました。YAHOO.extendYAHOO.lang.extend のエイリアスですが推奨されていません。
YAHOO.namespace("test");

YAHOO.test.Class1 = function(info) {
    alert("Class1: " + info);
};

YAHOO.test.Class1.prototype.testMethod = function(info) {
    alert("Class1: " + info);
};

YAHOO.test.Class2 = function(info) {
    // コンストラクタを繋げる
    YAHOO.test.Class2.superclass.constructor.call(this, info);
    alert("Class2: " + info);
};

// Class2がClass1を継承する。これはClass2のコンストラクタの直後に実行される必要がある
YAHOO.lang.extend(YAHOO.test.Class2, YAHOO.test.Class1);

YAHOO.test.Class2.prototype.testMethod = function(info) {
    // 関数を繋げる
    YAHOO.test.Class2.superclass.testMethod.call(this, info);
    alert("Class2: " + info);
};

var class2Instance = new YAHOO.test.Class2("constructor executed");
class2Instance.testMethod("testMethod invoked");



YAHOO.lang.augment

YAHOO.lang.augment はプロトタイプのプロパティを複数のオブジェクトに適用することで、コードを再利用する手段を提供します。YAHOO.augmentYAHOO.lang.augment のエイリアスですが、推奨されません。
<!-- debugger output for environments without "console" -->
<!-- コンソールがない環境ではここにデバッガの出力が与えられます -->
<div id="consoleelement"> </div>

<script>
////////////////////////////////////////////////////////////////////////////
// ConsoleProvilderの例はコンソールがある場合はコンソールにログを出力します
// コンソールがない場合は"consoleelement"にログを出力します
////////////////////////////////////////////////////////////////////////////
YAHOO.example.ConsoleProvider = function() { };
YAHOO.example.ConsoleProvider.prototype = {
    log: function(msg) {
        // use the error console if available (FF+FireBug or Safari)
        if (typeof console != "undefined") {
            console.log(msg);
        // write the msg to a well-known div element
        } else {
            var el = document.getElementById("consoleelement");
            if (el) {
                el.innerHTML += "<p>" + msg + "</p>";
            }
        }
    }
};

////////////////////////////////////////////////////////////////////////////
// デバッグメッセージを出力するクラスを定義します
////////////////////////////////////////////////////////////////////////////
YAHOO.example.ClassWithLogging = function() { };
YAHOO.lang.augment(YAHOO.example.ClassWithLogging, YAHOO.example.ConsoleProvider);

////////////////////////////////////////////////////////////////////////////
// テスト
////////////////////////////////////////////////////////////////////////////
var c = new YAHOO.example.ClassWithLogging();
c.log("worked");

</script>



YAHOO.log

YAHOO.log はYAHOO Global Object に含まれており、(YUI Logger Controlがページ中に存在せずとも)YUIのコード中のどこでもログ出力を行うことが可能です。このため、デバッグ情報を除去する前にエラーが出現することを抑止できます。YAHOO.log はLogger Controlを使用できる環境ではYAHOO.widget.Logger.log を実行しますが、そうでない場合は何もしません。 使用方法についてはLogger Controlのドキュメントを参照してください。
YAHOO.namespace("test");

YAHOO.test.Class1 = function(info) {
    YAHOO.log("Class1: " + info, "error", "Class1");
};



YAHOO_config and YAHOO.env

YAHOO.env はブラウズ環境、特にページ表示のためにロードしたYUIコンポーネントの情報を保持します。 この情報はYAHOO.env.getVersion を介してどのコンポーネントからも取得可能で、特にライブラリがダイナミックにロードされる環境で有用です。 YAHOOやその他のYUIライブラリがロードされているか確認するために、ポーリングする代わりにYAHOO_configコールバック関数を定義することができます。
<html>
<head>
<script type="text/javascript">

// モジュールがロードされる度にコールバックされます
function mycallback(info) {
 
    alert(info.name + " loaded");

    // loggerがページでロードされると動作します
    if (info.name == "logger") {
        YAHOO.widget.Logger.enableBrowserConsole() 
        var l = new YAHOO.widget.LogWriter("(");

        YAHOO.example.EnvTest = function() {
            function log(msg,cat) {
                var c=c||"info";
                YAHOO.log(msg,c,"LangTest");
            }

            return { 
                init: function() {
                    new YAHOO.widget.LogReader("logoutput");
                    log("init");
                },
                
                showInfo: function(e, module){
                    // YAHOO.env.getVersion はYAHOO_config.listener が受け取るデータと同じデータを返します
                    var info = YAHOO.env.getVersion(module);

                    log("name: " + info.name);
                    log("version: " + info.version);
                    log("build: " + info.build);
                    log("versions: " + info.versions);
                    log("builds: " + info.builds);
                    log("mainClass version: " + info.mainClass.VERSION);
                }
            };
        } ();

        YAHOO.util.Event.addListener(window, "load", YAHOO.example.EnvTest.init);
        YAHOO.util.Event.addListener("showeventbutton", "click", YAHOO.example.EnvTest.showInfo, "event");
    }
}

YAHOO_config = {
    listener: mycallback
};

</script>
<script src = "../src/js/YAHOO.js" ></script>
<script src = "../../build/event/event.js" ></script>
<script src = "../../build/dom/dom.js" ></script>
<script src = "../../build/dragdrop/dragdrop.js" ></script>
<script src = "../../build/logger/logger.js" ></script>
<link rel="stylesheet" type="text/css" href="../../build/logger/assets/logger.css">
<style> #logoutput {float: right}</style>
</head>
<body>
<input type="button" id="showeventbutton" value="show event version" />
<div id="logoutput"></div>
</body>
</html>

YUI Module NamesYUI on Mobile: Using YAHOO Global Object with "A-Grade" Mobile Browsersは割愛します。

last.fm から自分の再生履歴を配列として取得するphpスクリプトのサンプルを以下に示す。


<?php

// --
// VERSION CHECK
// --
if( version_compare(phpversion(), '5.0', '<') ) {
    echo "本スクリプトはPHPのVersion5.0以降でのみ動作します\n";
    exit;
}

// --
// LOAD XML
// --
$_lastfmName = 'mahata';
$_targetUrl = "http://ws.audioscrobbler.com/1.0/user/{$_lastfmName}/recenttracks.xml";
$_xmlObj = simplexml_load_file($_targetUrl);

// --
// MAKE ARRAY
// --
$_playList = array();
foreach( $_xmlObj as $_xmlObj_ ) {
    $_tArray = array();
    $_tArray['artist']  = (string)$_xmlObj_->artist;
    $_tArray['name']    = (string)$_xmlObj_->name;
    $_tArray['album']   = (string)$_xmlObj_->album;
    $_tArray['date']    = date('Y/m/d H:i:s', (int)strtotime($_xmlObj_->date));

    $_playList[] = $_tArray;
}

// --
// DUMP ARRAY
// --
print_r( $_playList );

?>


ここで、$_lastfmNameに任意のIDを設定すればよい。
実行結果は次のようになる。


$ php playlist2array.php
Array
(
    [0] => Array
        (
            [artist] => Surface
            [name] => クセになりそうだ
            [album] => resurface
            [date] => 2007/10/03 14:42:00
        )

    [1] => Array
        (
            [artist] => Surface
            [name] => ハニカムハニ
            [album] => resurface
            [date] => 2007/10/03 14:37:00
        )

    [2] => Array
        (
            [artist] => Surface
            [name] => WAIT!
            [album] => resurface
            [date] => 2007/10/03 14:34:00
        )

    [3] => Array
        (
            [artist] => Surface
            [name] => Re:START
            [album] => Re:START
            [date] => 2007/10/03 14:30:00
        )

    [4] => Array
        (
            [artist] => Surface
            [name] => ちりつもたれつ
            [album] => resurface
            [date] => 2007/10/03 14:26:00
        )

    [5] => Array
        (
            [artist] => Surface
            [name] => ワクチン
            [album] =>
            [date] => 2007/10/03 14:20:00
        )

    [6] => Array
        (
            [artist] => Surface
            [name] => 夢の続きへ
            [album] =>
            [date] => 2007/10/03 14:15:00
        )

    [7] => Array
        (
            [artist] => LINDBERG
            [name] => Brand New Day
            [album] => XII
            [date] => 2007/10/03 14:09:00
        )

    [8] => Array
        (
            [artist] => LINDBERG
            [name] => アタシは磨けば光るダイアモンドなのに
            [album] => XII
            [date] => 2007/10/03 14:05:00
        )

    [9] => Array
        (
            [artist] => LINDBERG
            [name] => 自転車に初めて乗れた日
            [album] => XII
            [date] => 2007/10/03 13:59:00
        )

)
google-code-prettifyでソースコードをシンタックスハイライトする方法を示す。
本ブログではgoogle-code-prettifyを導入済みなので、HTMLソースを適宜参照されたい。


手順は大まかに次の通りである。


  1. google-code-prettifyをダウンロード
  2. google-code-prettifyをウェブサーバにアップロード
  3. google-code-prettify本体(jsおよびcss)をインクルード
  4. google-code-prettifyのprettyPrint()をbodyタグのonloadイベントでcall
  5. シンタックスハイライトしたい部分をpreタグでくくりprettyprintクラスを適用


1. google-code-prettifyはgoogleのサイトからダウンロードする。
2. アップロードはffftpwinscpなど、任意の方法でアップロードする。
3. headタグは次のようにする。


<head>
<title>this is a title.</title>
<link href="/js/google_code_prettify/prettify.css" rel="stylesheet" type="text/css"/>
<script src="/js/google_code_prettify/prettify.js" type="text/javascript"></script>
</head>


ただし、pretty.cssおよびpretty.jsの場所はアップロード先によって変更の必要がある。


4. bodyタグは次のようにする。


<body onload="prettyPrint()">


5. preタグの適用は次のようにする。


<pre class="prettyprint">ソースコード</pre>


Enjoy!! ともにソースコードを晒しましょう。

拡張子がphpのファイル(というか、phpコードが実行される環境)で、
かつphp.iniのshort_open_tagがOnになっていると、XHTMLのxml宣言でエラーが出る。
なぜかというと、インタプリタが<?xml から始まる文字列をphpコードとして解釈するからである。


通常、次のようなerror_logが出力される。


Parse error: parse error, unexpected T_STRING in *.php on line 1


php.ini のshort_open_tag をOffにするのが正しい解決方法だが、
php.ini を勝手に変更してはならないケースでは、次のような回避方法もある。


<?php echo '<?xml version="1.0" encoding="utf-8"?>'."\n" ?>


PHPの仕様に文句をこぼさずに生きていきたいものですね。

ソースコードをブログ(MT)に貼り付けられる形式に変換するツールを作成した。
ここ(mahata.net内)からツールに遷移できる。


ためしに、ツールそのもののコードを貼り付けて添付してみる。


(strip_tags.html)


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="description" content="mahata.net">
<meta name="keywords" content="mahata, mahata.net, programming, tool">
<meta name="author" content="Yasunori MAHATA">
<title>mahata.net - strip tags</title>


<body>


<p>
ブログにソースコードを貼り付けるツール。
</p>

<p>
<form action="strip_tags_proc.html" method="post">
<textarea name="code" cols="96" rows="32"></textarea><br />
<input type="submit" />
</form>
</p>

</body>

</html>


(strip_tags_proc.html)


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="description" content="mahata.net">
<meta name="keywords" content="mahata, mahata.net, programming, tool">
<meta name="author" content="Yasunori MAHATA">
<title>mahata.net - strip tags</title>


<body>


<p>
ブログに貼り付けられる形態に変換しました。
</p>


<p>
<textarea cols="96" rows="32"><?php echo str_replace('&', '&amp;', htmlspecialchars($_POST['code'])); ?></textarea><br />
</p>

<hr />

<p>
再度の変換を試したい場合は、次のテキストボックスを利用してください。
</p>

<p>
<form action="strip_tags_proc.html" method="post">
<textarea name="code"  cols="96" rows="32"><?php echo $_POST['code']; ?></textarea><br />
<input type="submit" />
</form>
</p>

</body>

</html>


何ていうことはしていなくて、ただ単にhtmlspecialcharsを通したものの&をさらに&amp(←本当は半角) に変換しただけ。

About this Archive

This page is a archive of recent entries in the プログラミング category.

ニュース is the previous category.

レーシック is the next category.

Find recent content on the main index or look in the archives to find all content.