2007年7月30日月曜日

弾むリング

モジュール変数によるキャラクタの管理。
#module ring x, z, r, v_x, v_z, a_z, ang, a_ang, life, r_inner
#const DIV_NUM 14      // リングの分割数
#const LIFE_MAX 500    // 寿命の初期値

// 初期化
#modinit int _x, int _z, double _r, int _v_x, double _v_z, double _a_ang
    x = _x : z = _z : r = _r : r_inner = 0.8 * r
    v_x = _v_x : v_z = _v_z : a_z = -2.0
    ang = 0.0 : a_ang = _a_ang
    life = LIFE_MAX
    return

// リングを動かす
#modfunc move
    v_z += a_z
    x += v_x : z += v_z
    if ( z < r ) {
        z = r * 2 - z
        v_z = -v_z * 0.9
    }
    life -= 5
    ang += a_ang
    return

// リングを描く
#modfunc draw
    gmode GMODE_ALPHA, , , limit(life , 0200)
    repeat DIV_NUM
        hsvcolor cnt * 191 / DIV_NUM255255
        c = 3.14 * 2 * cnt / DIV_NUM + ang
        gs_x = x + r * cos( c ), x + r * cos( c + g ), x + r_inner * cos( c + g ), x + r_inner * cos( c )
        gs_y = ginfo_winy - z - r * sin( c ), ginfo_winy - z - r * sin( c + g ), ginfo_winy - z - r_inner * sin( c + g ), ginfo_winy - z - r_inner * sin( c )
        gsquare -1, gs_x, gs_y
    loop
    return life <= 0
#global
    g@ring = ( 3.14 * 2.0 ) / ( DIV_NUM@ring + 3 )

    dimtype mod_ring, 520
    onclick gosub *make_ring
    title "click to create rings"

*main
    redraw 0
    color : boxf
    foreach mod_ring
        move mod_ring( cnt )          // リングを移動させる
        draw mod_ring( cnt )          // リングを描く
        if stat : delmod mod_ring( cnt )   // リングが寿命を迎えていたら削除
    loop
    redraw 1
    wait 3
    goto *main

*make_ring
    switch iparam
    case 0
        newmod mod_ring, ring, 0,          rnd100 ) + 15060 + rnd50 ), rnd5 ) + 30.0, -0.1
        swbreak
    default
        newmod mod_ring, ring, ginfo_winxrnd100 ) + 15060 + rnd50 ), rnd5 ) - 70.0,  0.1
        swbreak
    swend
    return

2007年7月29日日曜日

累乗根を求める

ニュートン・ラフソン法を用いて累乗根を求めるモジュール。
もちろん打ち切り誤差が発生します。// ニュートン・ラフソン法でxのn乗根を求める
#include "hspmath.as"
#module
#defcfunc radical_root double x, double n, local x_old, local x_new
    x_new = x
    repeat
        x_old = x_new
        x_new = ( n - 1.0 + x * pow@( x_old, -n ) ) * x_old / n
        if ( absf( x_old - x_new ) < 0.00000000001 ) {
            // ある程度の精度で演算を打ち切る
            break
        }
    loop
    return x_new
#global

    repeat 3
        pos cnt * 2200
        up_cnt = cnt + 2
        repeat 152
            mes strfstrcnt ) + "の" + str( up_cnt ) + "乗根は%1.10f", radical_root( cnt, up_cnt ) )
        loop
    loop
    stop


本家のBBSにあった「xの(1/n)乗がxのn乗根」という考え方を使えば、何と1行で記述できます。#define ctype radical_root( %1%2 ) expflogf%1 ) / ( %2 ) )

2007年7月28日土曜日

(X)HTMLコンバータ β版公開

(X)HTMLコンバータのβ版ができました。よろしければお試しください。

β1 ダウンロード(133KB)
β2 ダウンロード(136KB)
β3 ダウンロード(99KB)
なおスクリプトの公開は正式版からとする予定です。

v1.0を公開しました。
変換スクリプトをこちらで公開しています。他のスクリプトはただいま整理中です。

β3からはHSPと同じフォルダに入れる必要があります。

(X)HTMLコンバータ (7) スクリプトの変換

HSP3のスクリプトを解析して(X)HTMLへ変換するスクリプト。これでバージョン1.0とします。
このスクリプト内で説明されていない変数などもありますが、変換の流れ程度はわかっていただけるかもしれません。

命令やラベルや数値などスペースを含まないものはstrmidで一気に解析してしまい、コメントや文字列などスペースを含むことができるものはpeekで1バイトずつ(オートマトンのように)変換しています。#uselib "kernel32.dll"
    #cfunc global IsDBCSLeadByteEx "IsDBCSLeadByteEx" sptr, sptr

#const global CP_ACP      0
#const global EXPAND_SIZE 1024

#const global CR   0x0D
#const global LF   0x0A
#const global CRLF 0x0A0D

#enum STATE_NORMAL = 1
#enum STATE_COMMENT
#enum STATE_MULTILINE_COMMENT
#enum STATE_STRINGS
#enum STATE_MULTILINE_STRINGS

#module
#deffunc setConvertMode int i
    convertMode = i
    return

#deffunc addString str s, local l
    l = strlen( s )
    if ( rTextSize@ <= rTextPos@ + l ) {
        // バッファをオーバーしてしまうので、拡張する
        rTextSize@ += EXPAND_SIZE
        memExpand rText@, rTextSize@
    }
    poke rText@, rTextPos@, s
    rTextPos@ += l
    return

// 単独タグ
#defcfunc _aloneTag str tagName, str className
    if ( convertMode == REPLACEMODE_XHTML ) {
        if ( className == "" ) {
            return "<" + tagName + " />"
        } else {
            return "<" + tagName + " class=\"" + className + "\" />"
        }
    } else {
        if ( className == "" ) {
            return "<" + tagName + ">"
        } else {
            return "<" + tagName + " class=\"" + className + "\">"
        }
    }

// 終了タグ
#defcfunc endTag str tagName
    return "</" + tagName + ">"

// 開始タグ
#defcfunc _startTag str tagName, str className, str idName, local s
    if ( idName == "" ) {
        s = ""
    } else {
        s = " id=\"" + idName + "\""
    }
    if ( className == "" ) {
        return "<" + tagName + s + ">"
    } else {
        return "<" + tagName + " class=\"" + className + "\"" + s + ">"
    }

// 文字がスペースかどうか(キーワードとして利用できない文字かどうか)調べる
#defcfunc is_space int iTarget, local iResult
    if IsDBCSLeadByteEx( CP_ACP, iTarget )     : return 0
    if ( '0' <= iTarget ) & ( iTarget <= '9' ) : return 0
    if ( 'a' <= iTarget ) & ( iTarget <= 'z' ) : return 0
    if ( 'A' <= iTarget ) & ( iTarget <= 'Z' ) : return 0
    if ( iTarget == '_' ) : return 0
    return 1

// 文字が数字かどうか調べる
#defcfunc is_number int iTarget
    return ( '0' <= iTarget ) & ( iTarget <= '9' )

#global
#define ctype aloneTag( %1, %2 = "" ) _aloneTag( %1, %2 )
#define ctype startTag( %1, %2 = "", %3 = "" ) _startTag( %1, %2, %3 )

*convertText
    setConvertMode replaceMode
    gosub *loadDictionary       // 変換用データベースの準備
    gosub *beforeConvert        // 変換の準備
    gosub *convert              // 変換の実行
    gosub *afterConvert         // 変換の後処理
    gosub *deleteDictionary     // データベースの削除
    return

// 変換の準備
*beforeConvert
    textSize = strlentext )
    rTextSize = textSize
    sdim rText, rTextSize       // ReplacedText

    if ( sandwichMode == 1 ) & ( sandwichTag != "" ) {
        if ( addIdMode ) {
            // コマンドライン(ファイル名が格納されているはず)から
            // ファイル名を取り出してidとする
            rText = startTag( sandwichTag, sandwichClass, getpathdir_cmdline, 8 ) )
        } else {
            rText = startTag( sandwichTag, sandwichClass )
        }
    }
    rTextPos = strlen( rText )

    x = 0
    firstCharOfArea = 1    // ラベルの判定に使用
    state = STATE_NORMAL

    return

// 変換の実行
*convert
    repeat
        textPos = cnt
        c = peektext, textPos )
        switch c
        case 0
            break
            swbreak
        case CR : case LF
            // 改行
            gosub *startNewLine
            if ( strmidtext, textPos, 2 ) == "\n" ) {
                continue textPos + 2
            }
            swbreak
        case '/'
            if ( strmidtext, textPos, 2 ) == "/*" ) & ( state == STATE_NORMAL ) {
                // 複数行コメント開始
                gosub *startMultiLineComment
                addString "/*" : x += 2
                continue textPos + 2
            }
            if ( strmidtext, textPos, 2 ) == "//" ) & ( state == STATE_NORMAL ) {
                // 単一行コメント開始
                gosub *startSingleLineComment
                addString "//" : x += 2
                continue textPos + 2
            }
            addString "/" : x++
            swbreak
        case '*'
            if ( firstCharOfArea ) & ( state == STATE_NORMAL ) {
                gosub *firstCharFinished
                gosub *addLabel
                continue textPos
            }
            if ( strmidtext, textPos, 2 ) == "*/" ) & ( state == STATE_MULTILINE_COMMENT ) {
                // 複数行コメントの終了
                addString "*/" : x += 2
                gosub *endMultiLineComment
                continue textPos + 2
            }
            addString "*" : x++
            swbreak
        case ';'
            if ( state == STATE_NORMAL ) {
                // 単一行コメント開始
                gosub *startSingleLineComment
            }
            addString ";" : x++
            swbreak
        case '{'
            if ( strmidtext, textPos, 2 ) == "{\"" ) & ( state == STATE_NORMAL ) {
                // 複数行文字列の開始
                gosub *startMultiLineStrings
                addString "{\"" : x += 2
                continue textPos + 2
            }
            addString "{" : x++
            swbreak
        case '"'
if ( state == STATE_NORMAL ) {
// 単一行文字列開始
gosub *startSingleLineStrings
addString "
\"" : x++
                continue
            }
            if ( state == STATE_STRINGS ) {
                // 単一行文字列終了
                addString "\"" : x++
                gosub *endSingleLineStrings
                continue
            }
            if ( strmidtext, textPos, 2 ) == "\"}" ) & ( state == STATE_MULTILINE_STRINGS ) {
                addString "\"}"
                gosub *endMultiLineStrings
                continue textPos + 2
            }
            addString "\"" : x++
            swbreak
        case '\t'
            if ( replaceTabs ) & ( state != STATE_STRINGS ) & ( state != STATE_MULTILINE_STRINGS ) {
                // タブをスペースへ変換する
                if replaceSpaces {
                    s = "&nbsp;"
                } else {
                    s = " "
                }
                repeat tabWidth - ( x \ tabWidth )
                    addString s : x++
                loop
            } else {
                addString "\t" : x += tabWidth - ( x \ tabWidth )
            }
            swbreak
        case ' '
            if replaceSpaces {
                // 半角スペースを変換(文字列中・コメント中でも実行)
                addString "&nbsp;"
            } else {
                addString " "
            }
            x++
            swbreak
        case ':'
            // 文の区切れ
            addString ":" : x++
            if ( state == STATE_NORMAL ) : gosub *endLine
            swbreak
        case ',' : case '='
            // パラメータの区切れ
            addString strf"%c", c ) : x++
            if ( state == STATE_NORMAL ) : gosub *endArea
            swbreak
        case '\\'
            if ( state == STATE_STRINGS ) | ( state == STATE_MULTILINE_STRINGS ) {
                if ( strmidtext, textPos, 2 ) == "\\\\" ) | ( strmidtext, textPos, 2 ) == "\\\"" ) {
                    addString strmidtext, textPos, 2 ) : x += 2
                    continue textPos + 2
                }
            }
            addString "\\" : x++
            swbreak
        case '&' : addString "&amp;"  : x++ : swbreak
        case '<' : addString "&lt;"   : x++ : swbreak
        case '>' : addString "&gt;"   : x++ : swbreak
        default
            // 命令・関数などキーワードの可能性
            if IsDBCSLeadByteEx( CP_ACP, c ) {
                // 2バイト文字の場合

                // 現在のバージョンでは変数をマークアップしないので、
                // このように扱ってもOK。
                addString strmidtext, textPos, 2 ) : x += 2
                continue textPos + 2
            }
            // 1バイト文字の場合
            if ( state == STATE_NORMAL ) {
                // 文字列中やコメント中でなければ、数値や命令・関数としてマークアップできるかどうか調べる
                if ( is_number( c ) ) | ( c == '%' ) | ( c == '$' ) {
                    // 数値の挿入
                    gosub *addNumber
                    continue textPos
                }
                if ( is_space( c ) == 0 ) | ( c == '#' ) {
                    // 命令・プリプロセッサ・関数etc.の挿入
                    gosub *addWord
                    continue textPos
                }
            }
            // 命令などを構成する文字列ではなかった場合(@,|,(,)など)
            gosub *firstCharFinished
            addString strf"%c", c ) : x++
            swbreak
        swend
    loop
    return

// *****************************************************************

// 変換終了後処理
*afterConvert
    if ( sandwichMode == 1 ) & ( sandwichTag != "" ) {
        addString endTag( sandwichTag )
    }
    addString "\n"

    text = rText
    sdim rText, 4

    return

// 変数の処理
*firstCharFinished
    // 空白でない文字を取り出した場合
    firstCharOfArea = 0
    return

*endLine
    // (マルチステートメントを含む論理的な)行の終了に伴う変数の変化
*endArea
    // パラメータの終了に伴う変数の変化
    firstCharOfArea = 1
    return

// *****************************************************************

// 単行コメントの開始
*startSingleLineComment
    state = STATE_COMMENT
    if markupComments {
        addString startTag( "span", CLASSNAME_COMMENT )
    }
    return

// コメント行を終了
*endSingleLineComment
    state = STATE_NORMAL
    if ( markupComments ) {
        addString endTag( "span" )
    }
    return

// 複数行コメントの開始
*startMultiLineComment
    state = STATE_MULTILINE_COMMENT
    if ( markupComments ) {
        addString startTag( "span", CLASSNAME_COMMENT )
    }
    return

// 複数行コメントの終了
*endMultiLineComment
    state = STATE_NORMAL
    if ( markupComments ) {
        addString endTag( "span" )
    }
    return

// 単行文字列の開始
*startSingleLineStrings
    state = STATE_STRINGS
    if ( markupStrings ) {
        addString startTag( "span", CLASSNAME_STRING )
    }
    return

// 単行文字列の終了
*endSingleLineStrings
    state = STATE_NORMAL
    if ( markupStrings ) {
        addString endTag( "span" )
    }
    return

// 複数行文字列の開始
*startMultiLineStrings
    state = STATE_MULTILINE_STRINGS
    if ( markupStrings ) {
        addString startTag( "span", CLASSNAME_STRING )
    }
    return

// 複数行文字列の終了
*endMultiLineStrings
    state = STATE_NORMAL
    if ( markupStrings ) {
        addString endTag( "span" )
    }
    return

// *****************************************************************

// textPosの位置以降をラベルとして挿入
*addLabel
    lLabel = textSize - textPos
    repeat textSize - textPos - 1, textPos + 1
        if ( textSize <= cnt ) {
            lLabel = textSize - textPos
            break
        }
        j = peektextcnt )
        if ( IsDBCSLeadByteEx( CP_ACP, j ) ) : continue cnt + 2
        if ( cnt == textPos + 1 ) & ( is_number( j ) ) {
            lLabel = cnt - textPos
            break
        }
        if is_space( j ) {
            lLabel = cnt - textPos
            break
        }
    loop
    if ( markupLabels ) & ( 1 < lLabel ) {
        addString startTag( "span", CLASSNAME_LABEL )
    }
    addString strmidtext, textPos, lLabel )
    textPos += lLabel : x += lLabel
    if ( markupLabels ) & ( 1 < lLabel ) {
        addString endTag( "span" )
    }
    return

// textPosの位置以降を数字として挿入
*addNumber
    if ( markupNumbers ) {
        addString startTag( "span", CLASSNAME_NUMBER )
    }
    repeat -1, 1
        j = peektext, textPos + cnt )
        if is_number( j ) | ( j == '.' ) {
            continue
        }
        if ( cnt == 1 ) : if ( peektext, textPos ) == '0' ) & (( j == 'x' ) | ( j == 'b' )) {
            continue
        }
        if ( j == 'e' ) | ( j == 'E' ) {
            if ( textPos + cnt + 1 < textSize ) {
                n = peektext, textPos + cnt + 1 )
                if ( n == '+' ) | ( n == '-' ) : continue cnt + 2
            }
            continue
        }
        lNumber = cnt
        break
    loop
    addString strmidtext, textPos, lNumber )
    textPos += lNumber : x += lNumber
    if ( markupNumbers ) {
        addString endTag( "span" )
    }
    return

// 命令・関数・システム変数など
*addWord
    repeat -1, 1
        if textPos + cnt >= textSize {
            dcKey = strmidtext, textPos, cnt )
            break
        }
        if is_space( peektext, textPos + cnt ) ) {
            dcKey = strmidtext, textPos, cnt )
            break
        }
    loop

    dc -> "Exists" dcKey
    if ( vret != 0 ) {
        // 辞書に載っている文字列は適切なタグで囲む
        dcVal = dc( "Item", dcKey )
        if ( dcVal == DCVAL_COMMAND ) & ( markupCommands == 1 ) {
            addString startTag( "span", CLASSNAME_COMMAND )
        }
        if ( dcVal == DCVAL_FUNCTION ) & ( markupFunctions == 1 ) {
            addString startTag( "span", CLASSNAME_FUNCTION )
        }
        if ( dcVal == DCVAL_SYSVAL ) & ( markupSysvals == 1 ) {
            addString startTag( "span", CLASSNAME_SYSVAL )
        }
        if ( dcVal == DCVAL_PREPROCESSOR ) & ( markupPreprocessors == 1 ) {
            addString startTag( "span", CLASSNAME_PREPROCESSOR )
        }
        if ( dcVal == DCVAL_MACRO ) & ( markupMacros == 1 ) {
            addString startTag( "span", CLASSNAME_MACRO )
        }
        addString dcKey
        if (( dcVal == DCVAL_COMMAND ) & ( markupCommands == 1 )) | (( dcVal == DCVAL_FUNCTION ) & ( markupFunctions == 1 )) {
            addString endTag( "span" )
        }
        if (( dcVal == DCVAL_SYSVAL ) & ( markupSysvals == 1 )) | (( dcVal == DCVAL_PREPROCESSOR ) & ( markupPreprocessors == 1 )) {
            addString endTag( "span" )
        }
        if (( dcVal == DCVAL_MACRO ) & ( markupMacros == 1 )) {
            addString endTag( "span" )
        }
    } else {
        // 辞書に載っていない文字列はそのまま
        addString dcKey
    }
    x += strlen( dcKey )
    gosub *firstCharFinished
    if ( dcVal == DCVAL_COMMAND ) : gosub *endArea
    textPos += strlen( dcKey )
    return

// *****************************************************************

// 新しい行の開始(マルチステートメントを除く、物理的に新しい行)
*startNewLine
    if ( state == STATE_COMMENT ) : gosub *endSingleLineComment
;   if ( state == STATE_STRINGS ) : state == STATE_NORMAL // 本来は必要ないはず

    if addBrTags {
        addString aloneTag( "br" )
    }
    addString "\n" : x = 0
    gosub *endLine
    return

// *****************************************************************

// 辞書の読み込み
*loadDictionary
    newcom dc, "Scripting.Dictionary"
    comres vret
    dc( "compareMode" ) = 1   // 大文字小文字を区別しない
    dcKey = 0

    dcList = DCFILE_FUNCTIONS, DCFILE_SYSVALS, DCFILE_COMMANDS, DCFILE_PREPROCESSORS, DCFILE_MACROS
    dcVal  = DCVAL_FUNCTION,   DCVAL_SYSVAL,   DCVAL_COMMAND,   DCVAL_PREPROCESSOR,   DCVAL_MACRO

    chdir dir_source + "/" + SAVE_FOLDER
    notesel note
    repeat length( dcList )
        exist dcList( cnt )
        if ( strsize < 0 ) : continue
        noteload dcList( cnt )
        _cnt = cnt
        repeat notemax
            noteget s, cnt
            if ( s != "" ) {
                dc -> "Add" s, dcVal( _cnt )
            }
        loop
    loop
    sdim note, 4
    return

// 辞書の削除
*deleteDictionary
    delcom dc
    return


ラベルや変数をローワーキャメルケースで書いてきたのですが、やはりHSPユーザはアンダースコア区切りが多いようなのでそちらに変えようかな、と思っています。

2007年7月27日金曜日

円柱のHSV色空間


最近文字列ばかりだったので、一息入れる意味で3D。

奥行きの計算は厳密なものではなく近似したものです。

#include "d3m.hsp"
#include "hspda.as"

#const H_MAX      12
#const S_MAX      4
#const V_MAX      7
#const PANEL_MAX  H_MAX * S_MAX * V_MAX
#const PANEL_SIZE 150                   // パネル一辺の長さ
#const PANEL_DIST 200                   // 同じ角度上のパネル同士の距離(左下の座標の間)
#const OBSERVER_R 2000                  // 観測者の中心からの距離

#const double PI        3.1415
#const double ANG_SPEED 0.04            // 観測者の角速度

    ct = 0.0
    d3setcam OBSERVER_R, 0, V_MAX * 100,  00, V_MAX * 100

*init
    dim  panel_h,   PANEL_MAX : dim  panel_s,   PANEL_MAX : dim  panel_v,   PANEL_MAX  // 色(HSV指定)
    dim  panel_r,   PANEL_MAX : ddim panel_t,   PANEL_MAX : dim  panel_z,   PANEL_MAX  // パネルの位置 円柱座標系(パネルの左下の座標)
    ddim panel_far, PANEL_MAX   // 奥行き

    repeat H_MAX : cnt1 = cnt
        h = 191 * cnt / H_MAX                       // HSV の H
        t = PI * 2.0 * cnt / H_MAX                  // 角度
        repeat S_MAX : cnt2 = cnt
            s = 256 * cnt / S_MAX                   // HSV の S
            r = cnt * PANEL_DIST + PANEL_DIST / 2   // 中心からの距離
            repeat V_MAX
                v = 256 * cnt / V_MAX               // HSV の V

                i = cnt1 * S_MAX * V_MAX + cnt2 * V_MAX + cnt
                panel_h( i ) = h : panel_s( i ) = s : panel_v( i ) = v
                panel_r( i ) = r : panel_t( i ) = t : panel_z( i ) = cnt * PANEL_DIST
            loop
        loop
    loop
    observer_t = 0.0

*main
    gosub *calc
    gosub *draw
    wait 2
    goto *main

*calc
    // 観測者の回転
    observer_t += ANG_SPEED
    if ( PI * 2.0 < observer_t ) : observer_t -= PI * 2.0
    d3setlocal 0,0,0cos( observer_t ),sin( observer_t ),0, -sin( observer_t ),cos( observer_t ),00,0,1

    // 奥行きを計算。遠くにあるものほどpanel_farは小さくなる
    repeat PANEL_MAX
        panel_far( cnt ) = cos( panel_t( cnt ) - observer_t ) * panel_r( cnt )
    loop
    // 小さい順(昇順)に並べ替え
    sortval panel_far, 0
    return

*draw
    redraw 0
    hsvcolor 00, ( sin( observer_t )  + 1.0 ) * 128 : boxf
    repeat PANEL_MAX
        sortget i, cnt // 奥から数えてcnt番目のパネルのインデックス
        x = cos( panel_t( i ) ) * panel_r( i ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * panel_r( i )
        y = sin( panel_t( i ) ) * panel_r( i ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * panel_r( i )
        z = panel_z( i ) + PANEL_SIZE, panel_z( i ) + PANEL_SIZE, panel_z( i ), panel_z( i )
        hsvcolor panel_h( i ), panel_s( i ), panel_v( i )
        d3square x, y, z
    loop
    redraw 1
    return

2007年7月25日水曜日

(X)HTMLコンバータ (6) hsファイルから命令や関数等の一覧を作成

hsファイルから関数一覧を作成」と同じ考え方ですが、HHX付属のモジュールを利用することで格段に効率UPしました。

#include "../hsphelp/src/hhx_db.hsp"
#define HELP_DIR "hsphelp"

// ヘルプディレクトリの存在を確認
    chdir dir_exe
    dirlist s, HELP_DIR, 5
    if stat == 0 : dialog "ヘルプディレクトリが見つかりません", 1 : end
    chdir HELP_DIR

// データベースのロード
    mes "loading..."
    HHX_init_load_db
    if HHX_currentset_sum() ! HHX_diskset_sum() {
        mes "rebuilding db..."
        HHX_init_rebuild_db DBR_WRITEDB
    } else {
        HHX_init_extract_db
    }

// コンバータ用デーベースの作成
    mes "making DB for (X)HTML-converter..."
    db_num = HHX_select_all()
    repeat db_num
        c = HHX_get_next()
        db_name  = hhxdata( c, C_NAME )
        db_group = hhxdata( c, C_GROUP )
        db_prm   = hhxdata( c, C_PRM )
        if instr( db_group, 0, "プリプロセッサ命令" ) >= 0 {
            ; プリプロセッサ
            notesel list_prepro
        } else : if instr( db_group, 0, "システム変数" ) >= 0 {
            ; システム変数
            notesel list_sysval
        } else : if instr( db_group, 0, "マクロ" ) >= 0 {
            ; マクロ
            notesel list_macro
        } else : if db_prm = "" {
            ; 引数なし(命令)
            notesel list_command
        } else : if peek( db_prm ) = '(' {
            ; 関数型
            notesel list_func
        } else {
            ; 命令型
            notesel list_command
        }
        noteadd db_name
    loop
    mes "finish."

2007年7月23日月曜日

(X)HTMLコンバータ (5) 複数行文字列を取得

{"で始まり"}で終わる複数行文字列を切りだして表示するスクリプト。
変換はだいたいこんな感じで行っています。
このスクリプトの場合コメント内文字列にも律儀に反応してしまいますが、コンバータではそうはなりません。

instr後にちゃっちゃと切りだしてしてしまえば良さそうなものですが、そうしていない理由は次のようなスクリプトに対応するためです。mes {"
この行で終わってはいけない\"}
この行で終わるべき\\"}


mes {"2バイト目が'\\'の2バイト文字には
反応しない→ソ"}

これに対して、複数行コメントの場合はこうした心配は必要ありません。

// 複数行文字列を切りだすスクリプト

    dialog "hsp;*.as;*.hss;*.hsh", 16
    if stat == 0 : end
    notesel buf
    noteload refstr
    bufSize = notesize

    repeat bufSize
        bufPos = cnt
        c = peek( buf, bufPos )
        if ( c == '{' ) & ( bufPos + 1 < bufSize ) {
            if ( peek( buf, bufPos + 1 ) == '"' ) {
                k = 0
                repeat
                    ins = instr( buf, bufPos + k, "\"}" )
                    if ( ins < 0 ) {
                        k = bufSize - bufPos
                        break
                    }
                    repeat
                        j = peek( buf, bufPos + k + ins - cnt - 1 )
                        if j == '\\' : continue
                        if (( 129 <= j ) & ( j <= 159 )) | (( 224 <= j ) & ( j <= 252 )) {
                            j = cnt - 1
                            if ( j < 0 ) : j = 0
                            break
                        }
                        j = cnt
                        break
                    loop
                    k += ins + 2 // 2 = strlen( "\"}" )
                    if ( j \ 2 ) {
                        // まだ続く
                        continue
                    }
                    break
                loop
                s = strmid( buf, bufPos, k )
                mes s
                continue bufPos + k
            }
        }
    loop
    stop