2007年7月18日水曜日

(X)HTMLコンバータ (1) 簡単なコンバータ

短期集中連載第1弾(?)、HSPスクリプトをXHTMLへコンバートするスクリプト。
HSP開発WikiのTABからスペース変換を参考にさせていただきました。kz3さんに感謝!

今回は動作イメージをつくるためのβ版です。命令や関数の色づけ、HSPスクリプトエディタ用外部ツール化などを目指します。
特にポイントと言える部分はありませんが、2バイト文字を判定するためにIsDBCSLeadByteEx()を利用していたり変わった方法で文字列を挿入していたり珍しいmemexpandを使っていたりとやや異色です。
// HSP to (X)HTML converter 2007.07.18
#uselib "kernel32.dll"
    #cfunc global IsDBCSLeadByteEx "IsDBCSLeadByteEx" sptr, sptr

#const CP_ACP           0
#const TAB_SIZE         4
#const EXPAND_SIZE      1024

*start
    dialog "hsp;*.as;*.hss;*.hsh"16
    fileName = refstr
    on stat goto *notSelected*openFile

// ファイルが選択されなかった → 終了
*notSelected
    end

// ファイルが選択された → ファイルを開く
*openFile
    notesel text
    noteload fileName

    gosub *replaceText

// 前後にタグを挿入(改善の余地あり?)
*addTags
    l = strlentext )
    s = ""
    memExpand text, l + 26
    poke text, l, ""
    poke textstrlen(s), text
    repeat strlen(s)
        poke textcntpeek( s, cnt )
    loop

*showResult
    mesbox textginfo_winxginfo_winy
    title "変換が終了しました。"
    stop

// テキストの置換
*replaceText
    rTextSize = strlen(text)
    sdim rText, rTextSize       // ReplacedText
    i = 0 : x = 0

    repeat
        c = peektextcnt )

        if ( rTextSize <= i + 6 * TAB_SIZE ) {
            rTextSize += EXPAND_SIZE
            memExpand rText, rTextSize
        }

        switch c
        case 0
            break
            swbreak
        case 13
            if ( peektextcnt + 1 ) == 10 ) {
                // 改行
                wpoke rText, i, 2573 : x = 0 : i += 2 // 2573 = ( 10 << 8 ) | 13
                continue cnt + 2
            }
            swbreak
        case '\t'
            repeat TAB_SIZE - ( x \ TAB_SIZE )
                poke rText, i, " " : i += 6 : x++
            loop
            swbreak
        case ' '
            poke rText, i, " " : i += 6 : x++
            swbreak
        case '&'
            poke rText, i, "&"  : i += 5 : x++
            swbreak
        case '<'
            poke rText, i, "<"   : i += 4 : x++
            swbreak
        case '>'
            poke rText, i, ">"   : i += 4 : x++
            swbreak
        default
            if IsDBCSLeadByteEx( CP_ACP, c ) {
                // 2バイト文字の場合
                wpoke rText, i, wpeektextcnt ) : i += 2 : x += 2
                continue cnt + 2
            } else {
                poke rText, i, c : i++ : x++
            }
        swend
; await 1
    loop

    text = rText
    sdim rText, 4
    return

3 件のコメント:

FUJI さんのコメント...

すいません、Googleのアカウントを入力したら、名前が本名になってしまいました。
もし直せるなら、名前を「FUJI」に直していただけますか?

eller さんのコメント...

> もし直せるなら、名前を「FUJI」に直していただけますか?

コメントの編集はできないようなので、こちらで削除&転記させていただきました。
FUJIさんのコメントは以下の通りです。

こんにちは、FUJIといいます。

スペースを に変換する処理をしていますが、これはpre要素で囲む方法の方がいいと思います。

そしてハイライトに関してですが、私は次のクラス名のspan要素でマークアップしています。
参考までに。

命令・関数 : func
文字列・文字 : string
コメント : comment
ラベル : abel
プリプロセッサ : preprocessor
拡張マクロ : macro

続きに期待しています。

eller さんのコメント...

FUJIさん、コメントありがとうございました。

> pre要素
タグの意味を考えると、本来はcode要素でマークアップすべきだと考えています(実際このブログ自身もそうしています)。
とはいえ最終的にはHTMLに詳しくない方にも使えるようにしたいと考えているため、この点はpreまたはcodeまたはタグなしから選択できるようにしたいと考えています。

> クラス名
他の言語などの衝突が怖いので、すべて"HSP3_xxxx"といった名前にしようかと考えています。
問題はどうやって命令や関数を判別するかなのですが、少々ややこしいことになりそうです。オートマトンの応用で何とかなれば良いのですが……。