<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Fuji Diablog</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/" />
<link rel="self" type="application/atom+xml" href="http://www.fujidig.com/feeds/atom.xml" />
<id>http://www.fujidig.com/</id>
<author>
<name>fujidig</name>
<uri>http://www.fujidig.com/</uri>
</author>
<updated>2008-05-14T14:29:26+09:00</updated>
<subtitle>fujidig による日記サイトです。 HSP や秀丸など興味のあることについてマイペースで綴ってます。</subtitle>
<generator version="0.1.3">Jidilog</generator>
<entry>
<title>OpenHSP ver 3.2 の可変長引数対応 strf を HSP 3.1 でも使えるようにするプラグインを作ったよ</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/05/strf-ex.html" />
<id>http://www.fujidig.com/2008/05/strf-ex.html</id>
<published>2008-05-13T15:19:00+09:00</published>
<updated>2008-05-14T14:29:26+09:00</updated>
<summary>strf_ex OpenHSP ver 3.2 の strf...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/05/strf-ex.html">
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.fujidig.com/archives/#strf_ex&quot;&gt;strf_ex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenHSP ver 3.2 の strf は可変長引数対応になって便利なので、HSP 3.1 でも動かせるようにプラグインにしてみました。みんなぜひ使うといいと思うよ！&lt;/p&gt;
&lt;h2&gt;サンプル&lt;/h2&gt;
&lt;p&gt;付属しているサンプルとまったく同じものをここに掲載しておきます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// サンプル
//     strf_ex : OpenHSP ver 3.2 の可変長引数対応 strf を HSP 3.1 でも使えるようにするプラグイン

// ファイル strf_ex.dll と次の 2 文で strf_ex が使えるようになります
#regcmd &quot;hsp3cmdinit&quot;, &quot;strf_ex.dll&quot;
#cmd strf_ex 0

//標準の strf を置き換えることもできます
;#undef strf
;#define global strf strf_ex

mes strf_ex(&quot;&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%f&amp;gt;&quot;, &quot;hoge&quot;,123, 3.14) //=&amp;gt; &amp;lt;hoge&amp;gt;&amp;lt;123&amp;gt;&amp;lt;3.140000&amp;gt;

// 型が合わなければ自動的に変換されます
mes strf_ex( &quot;&amp;lt;%s&amp;gt;&amp;lt;%d&amp;gt;&amp;lt;%f&amp;gt;&quot;, 123, 3.14, &quot;hoge&quot; ) //=&amp;gt; &amp;lt;123&amp;gt;&amp;lt;3&amp;gt;&amp;lt;0.000000&amp;gt;

mes strf_ex( &quot;%%&quot; ) //=&amp;gt; %

a = 0x80000000
mes strf_ex( &quot;&amp;lt;%d&amp;gt;&amp;lt;%u&amp;gt;&amp;lt;%o&amp;gt;&amp;lt;%x&amp;gt;&quot;, a, a, a, a ) //=&amp;gt; &amp;lt;-2147483648&amp;gt;&amp;lt;2147483648&amp;gt;&amp;lt;20000000000&amp;gt;&amp;lt;80000000&amp;gt;

mes strf_ex( &quot;%.3s&quot;, &quot;hello&quot; ) //=&amp;gt; hel
mes strf_ex( &quot;&amp;lt;%06d&amp;gt;&quot;, 123 ) //=&amp;gt; &amp;lt;000123&amp;gt;

// `*' で幅や精度を引数から得る機能はありません！
;mes strf_ex( &quot;&amp;lt;%.*s&amp;gt;&quot;, 3, &quot;hello&quot; ) //エラー
;mes strf_ex( &quot;&amp;lt;%0*d&amp;gt;&quot;, 6, 123 ) //エラー

// 数が合わない場合もエラー
;mes strf_ex( &quot;%d&quot; ) //エラー
;mes strf_ex( &quot;&quot;, 123 ) //エラー

// HSP 3.1 の strf では %s で文字列ポインタから文字列を取り出せました（仕様外）が、
// そうはできなくなりました。

a = &quot;hoge&quot;
mes strf( &quot;&amp;lt;%s&amp;gt;&quot;, varptr(a) + 1 ) //=&amp;gt; &amp;lt;oge&amp;gt;
mes strf_ex( &quot;&amp;lt;%s&amp;gt;&quot;, varptr(a) + 1 ) //=&amp;gt; &amp;lt;10683521&amp;gt;

// HSP 3.2 からは必ず dupptr をかましてやってください
a = &quot;hoge&quot;
dupptr b, varptr(a) + 1, 1, 2
mes strf_ex( &quot;&amp;lt;%s&amp;gt;&quot;, b) //=&amp;gt; &amp;lt;oge&amp;gt;

// なんと3.1では第二引数が文字列だとそれ単体で返ってきてしまいます
// 3.2 ではそんなことはありません
mes strf( &quot;&amp;lt;%s&amp;gt;&quot;, &quot;abc&quot;) //=&amp;gt; abc
mes strf_ex( &quot;&amp;lt;%s&amp;gt;&quot;, &quot;abc&quot;) //=&amp;gt; &amp;lt;abc&amp;gt;

// 3.1 の strf は結果が長いと場合によっては異常終了したり、なぞのエラーが出たり、システムエラーが発生したりします
;mes strlen(strf(&quot;%05000d&quot;,0))
;mes strlen(strf(&quot;%06000d&quot;,0))
;mes strlen(strf(&quot;%07000d&quot;,0))
;mes strlen(strf(&quot;%08000d&quot;,0))

// 3.2 ではそんなことはありません
mes strlen(strf_ex(&quot;%05000d&quot;,0)) //=&amp;gt; 5000
mes strlen(strf_ex(&quot;%06000d&quot;,0)) //=&amp;gt; 6000
mes strlen(strf_ex(&quot;%07000d&quot;,0)) //=&amp;gt; 7000
mes strlen(strf_ex(&quot;%08000d&quot;,0)) //=&amp;gt; 8000
mes strlen(strf_ex(&quot;%0100000d&quot;,0)) //=&amp;gt; 100000

// こんなところかな。&lt;/code&gt;&lt;/pre&gt;
</content>
</entry>
<entry>
<title>HSP の rnd を再現</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/03/hsp-rnd.html" />
<id>http://www.fujidig.com/2008/03/hsp-rnd.html</id>
<published>2008-03-28T13:30:59+09:00</published>
<updated>2008-03-28T13:32:17+09:00</updated>
<summary>HSP の rnd 関数の実装は以下のようになっています。（...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/03/hsp-rnd.html">
&lt;p&gt;
HSP の rnd 関数の実装は以下のようになっています。（ &lt;a href=&quot;http://dev.onionsoft.net/trac/browser/trunk/hsp3/hsp3int.cpp#L493&quot;&gt;OpenHSP trunc/hsp3/hsp3int.cpp#L493&lt;/a&gt; ）
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ival = code_geti();
if ( ival == 0 ) throw HSPERR_DIVIDED_BY_ZERO;
reffunc_intfunc_ivalue = rand()%ival;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
C の標準ライブラリの rand の値を引数の値で剰余しているだけですね。
&lt;/p&gt;
&lt;p&gt;
HSP は VC++ でビルドされています。 VC++ の rand の実装は &lt;a href=&quot;http://www001.upp.so-net.ne.jp/isaku/rand.html&quot;&gt;良い乱数・悪い乱数&lt;/a&gt; に掲載されています。
&lt;/p&gt;
&lt;p&gt;
ということで、HSP の rnd を再現してみると以下のような感じ。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#module
#defcfunc rnd2 int a
    x = x * 214013 + 2531011
    return ((x&gt;&gt;16)&amp;32767)\a
#deffunc randomize2 int a
    x = a
    return
#global

randomize 12345
randomize2 12345

repeat 10
    mes &quot;&quot;+rnd(1000)+&quot;, &quot;+rnd2(1000)
loop&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
結果も同じですね。
&lt;/p&gt;
&lt;pre&gt;&lt;samp&gt;584, 584
164, 164
795, 795
125, 125
828, 828
405, 405
477, 477
413, 413
72, 72
404, 404&lt;/samp&gt;&lt;/pre&gt;
</content>
</entry>
<entry>
<title>HSP 対応版 kmyacc を公開しました</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/03/kmyacc-hsp.html" />
<id>http://www.fujidig.com/2008/03/kmyacc-hsp.html</id>
<published>2008-03-24T19:28:09+09:00</published>
<updated>2008-03-26T20:34:00+09:00</updated>
<summary>HSP 対応版 kmyacc ダウンロード Windows ...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/03/kmyacc-hsp.html">
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.fujidig.com/archives/#kmyacc-hsp&quot;&gt;HSP 対応版 kmyacc ダウンロード&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Windows 用バイナリアーカイブ とソースアーカイブの二つを用意しました。
&lt;/p&gt;
&lt;p&gt;
他の言語のプロトタイプを参考にやったら出来ました！ kmyacc 本体をイジる必要があったのは改行周りだけでした。（ HSP では改行が文の終わりだから。 Python 版でも同じように改行周りで特別に処理していた。）
&lt;/p&gt;
&lt;p&gt;
-tオプション（デバッグモード）、-aオプション（reduce時のactionを一つ一つサブルーチンに分けてラベル型配列変数を使って実行）に対応しています。
&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;http://d.hatena.ne.jp/yukoba/20080220/p1&quot;&gt; ActionScriptのyaccを作ったよ - yukobaの日記&lt;/a&gt;の画像を見ると ActionScript 版のデバッグモードでは accept 後にツリーを表示しているようですね。 HSP 版でも次期バージョンで対応するかもしれません。&lt;ins&gt;→対応しました&lt;/ins&gt;
&lt;/p&gt;
&lt;p&gt;
kmyacc の作者、各言語のプロトタイプの作者に感謝します。
&lt;/p&gt;
&lt;ins datetime=&quot;2008-03-26T20:19:06+09:00&quot;&gt;
&lt;p&gt;
Ver 1.10 として更新しました。デバッグモード時に下図のようなパーサーツリーのダンプが出来るようになりました。
&lt;/p&gt;
&lt;p&gt;
&lt;img src=&quot;/2008/03/images/kmyacc-tree-dump.png&quot; alt=&quot;&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
方法は、まず kmyacc 実行時に-tオプションをつけます。すると、デバッグのためのトレース表示を行うようになります。これだけではツリーのダンプはされません。さらにツリーのダンプを行うには、 &lt;code&gt;yyparse&lt;/code&gt; を呼ぶ直前あたりに &lt;code&gt;yyDumpParseTree = 1&lt;/code&gt; というコードを差し込みます。
&lt;/p&gt;
&lt;/ins&gt;
&lt;h2&gt;構文木を使ったサンプル&lt;/h2&gt;
&lt;p&gt;
付属のサンプル（ calc.hspy ）では物足りないと思うので、構文木を使ったサンプルも置いておきます。参考にしてみてください。変数の代入とか、if文とか使えます。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%token kNUMBER kIDENT kEOL kIF kELSE kEND

%right '='
%left '+' '-'
%left '*' '/'

%%

program
    : stmt_list { syntaxtree = $1 }

stmt_list
    : { new_list_node $$ }
    | stmt_list stmt kEOL { yylrec++ : append_list_node $$, $2 }
    | stmt_list kEOL

stmt
    : expr
    | if_stmt

if_stmt
    : kIF expr kEOL stmt_list else_stmt kEND
        {
            new_if_node $$, $2, $4, $5
        }

else_stmt
    : kELSE kEOL stmt_list { $$ = $3 }
    | { new_list_node $$ }

expr
    : expr '+' expr { new_operator_node $$, '+', $1, $3 }
    | expr '-' expr { new_operator_node $$, '-', $1, $3 }
    | expr '*' expr { new_operator_node $$, '*', $1, $3 }
    | expr '/' expr { new_operator_node $$, '/', $1, $3 }
    | '(' expr ')' { $$ = $2 }
    | kNUMBER { new_literal_node $$, $1 }
    | kIDENT { new_varref_node $$, $1 }
    | kIDENT '=' expr { new_assign_node $$, $1, $3 }

%%

#runtime &quot;hsp3cl&quot;

if 0 {
#defcfunc varref str varname
    if vars( &quot;Exists&quot;, varname ) {
        return vars( &quot;Item&quot;, varname )
    }
    mes &quot;undefined variable `&quot;+varname+&quot;'&quot;
    return 0
#deffunc setvar str varname, int val
    if vars( &quot;Exists&quot;, varname ) : vars -&amp;gt; &quot;Remove&quot; varname
    vars -&amp;gt; &quot;Add&quot; varname, val
    return
}

#module m_node type, children, val
#enum TYPE_LITERAL = 1
#enum TYPE_VARREF
#enum TYPE_ASSIGN
#enum TYPE_OPERATOR
#enum TYPE_LIST
#enum TYPE_IF

#define last_node (nodes(length(nodes)-1))

#modfunc init_literal_node int _val
    type = TYPE_LITERAL
    val = _val
    return
#deffunc new_literal_node var ret, int _val
    newmod nodes, m_node
    init_literal_node last_node, _val
    ret = last_node
    return

#modfunc init_varref_node str varname
    type = TYPE_VARREF
    val = varname
    return
#deffunc new_varref_node var ret, str varname
    newmod nodes, m_node
    init_varref_node last_node, varname
    ret = last_node
    return

#modfunc init_assign_node str varname, var expr
    type = TYPE_ASSIGN
    val = varname
    children = expr
    return
#deffunc new_assign_node var ret, str varname, var expr
    newmod nodes, m_node
    init_assign_node last_node, varname, expr
    ret = last_node
    return

#modfunc init_operator_node int operator, var lhs, var rhs
    type = TYPE_OPERATOR
    val = operator
    children = lhs, rhs
    return
#deffunc new_operator_node var ret, int operator, var lhs, var rhs
    newmod nodes, m_node
    init_operator_node last_node, operator, lhs, rhs
    ret = last_node
    return

#modfunc init_list_node
    type = TYPE_LIST
    dimtype children, 5
    val = 0 // appended flag
    return
#deffunc new_list_node var ret
    newmod nodes, m_node
    init_list_node last_node
    ret = last_node
    return
#modfunc append_list_node var append_node
    if val {
        children( length( children ) ) = append_node
    } else {
        children = append_node
    }
    val = 1
    return

#modfunc init_if_node var cond, var tstmt, var fstmt
    type = TYPE_IF
    children = cond, tstmt, fstmt
    return
#deffunc new_if_node var ret, var cond, var tstmt, var fstmt
    newmod nodes, m_node
    init_if_node last_node, cond, tstmt, fstmt
    ret = last_node
    return

#defcfunc eval_node modvar m_node@
    if type == TYPE_LITERAL {
        return val
    }
    if type == TYPE_VARREF {
        return varref( val )
    }
    if type == TYPE_ASSIGN {
        v = eval_node( children )
        setvar val, v
        return v
    }
    if type == TYPE_OPERATOR {
        l = eval_node( children.0 )
        r = eval_node( children.1 )
        if val == '+' {
            return l + r
        }
        if val == '-' {
            return l - r
        }
        if val == '*' {
            return l * r
        }
        if val == '/' {
            return l / r
        }
    }
    if type == TYPE_LIST {
        result = 0
        foreach children
            result = eval_node( children.cnt )
        loop
        return result
    }
    if type == TYPE_IF {
        if eval_node( children.0 ) {
            return eval_node( children.1 )
        }
        return eval_node( children.2 )
    }
    mes &quot;must not happen&quot; : stop
#global

    newcom vars, &quot;Scripting.Dictionary&quot;
    vars(&quot;compareMode&quot;) = 0
    
    newcom reserved, &quot;Scripting.Dictionary&quot;
    reserved -&amp;gt; &quot;Add&quot; &quot;if&quot;, kIF
    reserved -&amp;gt; &quot;Add&quot; &quot;else&quot;, kELSE
    reserved -&amp;gt; &quot;Add&quot; &quot;end&quot;, kEND
    
    yyparse
    if vartype( syntaxtree ) == 5 : mes eval_node( syntaxtree )
    ;end stat
    stop

*yylex
    if start == 0 {
        input expr,, 1
        if peek( expr ) == 0 : return 0
        expr_ptr = 0
        start = 1
    }
    char = peek( expr, expr_ptr )
    if char == 10 || char == 13 {
        start = 0
        return kEOL
    }
    if char == ' ' || char == '\t' {
        expr_ptr ++
        goto *yylex
    }
    if char &amp;gt;= '0' &amp;amp;&amp;amp; char &amp;lt;= '9' {
        yylval = char - '0'
        expr_ptr ++
        repeat
            char = peek( expr, expr_ptr )
            if char &amp;gt;= '0' &amp;amp;&amp;amp; char &amp;lt;= '9' : else : break
            yylval = yylval * 10 + char - '0'
            expr_ptr ++
        loop
        return kNUMBER
    }
    if ( char &amp;gt;= 'a' &amp;amp;&amp;amp; char &amp;lt;= 'z' ) || ( char &amp;gt;= 'A' &amp;amp;&amp;amp; char &amp;lt;= 'Z' ) || char == '_' {
        yylval = expr_ptr
        repeat
            char = peek( expr, expr_ptr )
            cond   = char &amp;gt;= 'a' &amp;amp;&amp;amp; char &amp;lt;= 'z'
            cond ||= char &amp;gt;= 'A' &amp;amp;&amp;amp; char &amp;lt;= 'Z'
            cond ||= char == '_'
            cond ||= char &amp;gt;= '0' &amp;amp;&amp;amp; char &amp;lt;= '9'
            if cond : else : break
            expr_ptr ++
        loop
        yylval = strmid( expr, yylval, expr_ptr - yylval )
        if reserved( &quot;Exists&quot;, yylval ) {
            return reserved( &quot;Item&quot;, yylval )
        }
        return kIDENT
    }
    expr_ptr ++
    return char

*yyerror
    mes yyerrmsg
    return&lt;/code&gt;&lt;/pre&gt;
</content>
</entry>
<entry>
<title>mrefを使わずにstatに値を格納</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/03/set-into-stat.html" />
<id>http://www.fujidig.com/2008/03/set-into-stat.html</id>
<published>2008-03-21T06:25:18+09:00</published>
<updated>2008-03-21T06:31:16+09:00</updated>
<summary>ちょっとした HSP の小技。 gosub *@f : if...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/03/set-into-stat.html">
&lt;p&gt;
ちょっとした HSP の小技。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gosub *@f : if 0 : *@ : return 123
mes stat ;=&gt; 123&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
もちろん、ほとんどの場合では素直に mref を使った方がいいでしょう。
&lt;/p&gt;
</content>
</entry>
<entry>
<title>文字列の式を計算</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/02/calc.html" />
<id>http://www.fujidig.com/2008/02/calc.html</id>
<published>2008-02-12T08:00:49+09:00</published>
<updated>2008-02-13T07:12:40+09:00</updated>
<summary>カッコも演算子の優先度、単行演算子もあります。 Ruby で...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/02/calc.html">
&lt;p&gt;
カッコも演算子の優先度、単行演算子もあります。 &lt;a href=&quot;http://d.hatena.ne.jp/chaperatta/20080211/1202685889&quot;&gt;Ruby で書いた&lt;/a&gt;のを移植しました。文字列の式をトークンの配列に分解→逆ポーランド記法に変換→計算という段階を踏んでいます。
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#module calc_token type, val
#modinit int _type, var _val
    type = _type
    val = _val
    return
#defcfunc calc_token_type modvar calc_token@
    return type
#defcfunc calc_token_val modvar calc_token@
    return val
#global

#module calc

#enum TOKEN_TYPE_NONE = 0
#enum TOKEN_TYPE_BINARY_OPERATOR
#enum TOKEN_TYPE_UNARY_OPERATOR
#enum TOKEN_TYPE_NUM
#enum TOKEN_TYPE_LEFT_BRACKETS
#enum TOKEN_TYPE_RIGHT_BRACKETS

#deffunc init_calc
    binary_operators           = &quot;*&quot;, &quot;/&quot;, &quot;+&quot;, &quot;-&quot;
    binary_operators_priority  =   2,   2,   1,   1
    unary_operators            = &quot;+&quot;, &quot;-&quot;
    unary_operators_priority   =   5,   3
    return

#defcfunc calc_operate_binary int operator, double a, double b
    switch operator
    case 0
        return a * b
    case 1
        return a / b
    case 2
        return a + b
    case 3
        return a - b
    swend

#defcfunc calc_operate_unary int operator, double a
    switch operator
    case 0
        return a
    case 1
        return -a
    swend

#deffunc calc_scan_num
    c = char
    if c == '-' : c = peek( expr, i + 1 )
    if c &amp;lt; '0' || c &amp;gt; '9' : return
    type = TOKEN_TYPE_NUM
    size = 1
    find = 1
    repeat
        if i + size &amp;gt;= len : break
        c = peek( expr, i + size )
        if c &amp;lt; '0' || c &amp;gt; '9' : break
        size ++
    loop
    c = peek( expr, i + size )
    if c == '.' {
        c = peek( expr, i + size + 1 )
        if c &amp;gt;= '0' &amp;amp;&amp;amp; c &amp;lt;= '9' {
            size ++
            repeat
                if i + size &amp;gt;= len : break
                c = peek( expr, i + size )
                if c &amp;lt; '0' || c &amp;gt; '9' : break
                size ++
            loop
        }
    }
    val = double( strmid( expr, i, size ) )
    return

#deffunc calc_scan_operator array operators
    foreach operators
        dup operator, operators.cnt
        if strmid( expr, i, strlen( operator ) ) == operator {
            size = strlen( operator )
            val = cnt
            find = 1
            break
        }
    loop
    return

#deffunc calc_lex str _expr
    expr = _expr
    dimtype tokens, 5
    prev_type = TOKEN_TYPE_NONE
    i = 0
    len = strlen( expr )
    find = 1
    repeat
        if i &amp;gt;= len : break
        char = peek( expr, i )
        switch char
        case ' ' : case 0x09 : case 0x0a
        case 0x0d : case 0x0c
            i ++
            continue
        swend
        find = 0 : size = 0 : type = TOKEN_TYPE_NONE : val = 0
        switch prev_type
        case TOKEN_TYPE_NONE : case TOKEN_TYPE_LEFT_BRACKETS
        case TOKEN_TYPE_BINARY_OPERATOR : case TOKEN_TYPE_UNARY_OPERATOR
            calc_scan_num
            if find : swbreak
            calc_scan_operator unary_operators
            if find : type = TOKEN_TYPE_UNARY_OPERATOR : swbreak
            if char == '(' {
                type = TOKEN_TYPE_LEFT_BRACKETS
                size = 1
                find = 1
                swbreak
            }
            swbreak
        case TOKEN_TYPE_NUM : case TOKEN_TYPE_RIGHT_BRACKETS
            calc_scan_operator binary_operators
            if find : type = TOKEN_TYPE_BINARY_OPERATOR : swbreak
            if char == ')' {
                type = TOKEN_TYPE_RIGHT_BRACKETS
                size = 1
                find = 1
                swbreak
            }
        swend
        if find == 0 : break
        newmod tokens, calc_token, type, val
        prev_type = type
        i += size
    loop
    if find == 0 {
        error = &quot;構文エラーです&quot;
        return 1
    }
    return 0

#deffunc calc_insert_rpn_tokens
    i = rpn_tokens_size
    repeat
        if i &amp;lt;= rpn_tokens_ptr : break
        rpn_tokens( i ) = rpn_tokens( i - 1 )
        i --
    loop
    rpn_tokens( rpn_tokens_ptr ) = token
    rpn_tokens_size ++
    return

#defcfunc calc_is_token_operator var t
    if calc_token_type( t ) == TOKEN_TYPE_BINARY_OPERATOR : return 1
    if calc_token_type( t ) == TOKEN_TYPE_UNARY_OPERATOR  : return 1
    return 0

#defcfunc calc_operator_token_prioririty var t
    if calc_token_type( t ) == TOKEN_TYPE_BINARY_OPERATOR {
        return binary_operators_priority( calc_token_val( t ) )
    }
    return unary_operators_priority( calc_token_val( t ) )

#defcfunc calc_rop_is_end
    if rs_stack_ptr &amp;lt;= 0 : return 0
    if rs_stack( rs_stack_ptr - 1 ) != brackets_level : return 0

    if rpn_tokens_ptr &amp;gt;= rpn_tokens_size : return 1
    token1 = rpn_tokens( rpn_tokens_ptr )
    if tokens_i + 1 &amp;gt;= length( tokens ) : return 1
    token2 = tokens( tokens_i + 1 )

    if calc_is_token_operator( token1 ) == 0 : return 1
    if calc_is_token_operator( token2 ) == 0 : return 1

    token1p = calc_operator_token_prioririty( token1 )
    token2p = calc_operator_token_prioririty( token2 )

    return token2p &amp;lt;= token1p

#deffunc calc_rop_exit
    while calc_rop_is_end()
        rs_stack_ptr --
        rpn_tokens_ptr ++
    wend
    return

#deffunc calc_convert_to_rpn
    ret = 0
    dimtype rpn_tokens, 5
    rpn_tokens_size = 0
    rpn_tokens_ptr = 0
    prev_type = TOKEN_TYPE_NONE
    dim rs_stack
    rs_stack_ptr = 0
    brackets_level = 0

    foreach tokens
        tokens_i = cnt
        dup token, tokens.cnt
        type = calc_token_type( token )
        switch type
        case TOKEN_TYPE_NUM
            calc_insert_rpn_tokens
            rpn_tokens_ptr ++
            if prev_type == TOKEN_TYPE_BINARY_OPERATOR || prev_type == TOKEN_TYPE_UNARY_OPERATOR {
                calc_rop_exit
            }
            swbreak
        case TOKEN_TYPE_BINARY_OPERATOR
        case TOKEN_TYPE_UNARY_OPERATOR
            calc_insert_rpn_tokens
            rs_stack.rs_stack_ptr = brackets_level
            rs_stack_ptr ++
            swbreak
        case TOKEN_TYPE_LEFT_BRACKETS
            brackets_level ++
            swbreak
        case TOKEN_TYPE_RIGHT_BRACKETS
            if brackets_level &amp;lt;= 0 {
                error = &quot;不正な閉じカッコです&quot;
                ret = 1
                break
            }
            brackets_level --
            calc_rop_exit
            swbreak
        default
            error = &quot;不明なトークンです&quot;
            ret = 1
            break
        swend
        prev_type = type
    loop
/*  デバッグ表示
    repeat rpn_tokens_size
        if calc_token_type( rpn_tokens.cnt ) == TOKEN_TYPE_BINARY_OPERATOR {
            mes binary_operators( calc_token_val( rpn_tokens.cnt ) )
        } else : if calc_token_type( rpn_tokens.cnt ) == TOKEN_TYPE_UNARY_OPERATOR {
            mes unary_operators( calc_token_val( rpn_tokens.cnt ) )
        } else {
            mes calc_token_val( rpn_tokens.cnt )
        }
    loop */
    if ret : return ret
    if rpn_tokens_ptr != rpn_tokens_size {
        error = &quot;式が途中で終了しています&quot;
        return 1
    }
    if brackets_level != 0 {
        error = &quot;カッコが閉じられていません&quot;
        return 1
    }
    return 0

#deffunc calculate_rpn var result
    ddim stack, 1
    stack_ptr = 0
    ret = 0
    foreach rpn_tokens
        dup token, rpn_tokens.cnt
        type = calc_token_type( token )
        switch type
        case TOKEN_TYPE_NUM
            stack.stack_ptr = calc_token_val( token )
            stack_ptr ++
            swbreak
        case TOKEN_TYPE_BINARY_OPERATOR
            if stack_ptr &amp;lt; 2 {
                error = &quot;オペランドが足りません&quot;
                ret = 1
                break
            }
            stack_ptr --
            _b = stack.stack_ptr
            stack_ptr --
            _a = stack.stack_ptr
            stack.stack_ptr = calc_operate_binary( calc_token_val( token ), _a, _b )
            stack_ptr ++
            swbreak
        case TOKEN_TYPE_UNARY_OPERATOR
            if stack_ptr &amp;lt; 1 {
                error = &quot;オペランドが足りません&quot;
                ret = 1
                break
            }
            stack( stack_ptr-1 ) = calc_operate_unary( calc_token_val( token ), stack( stack_ptr-1 ) )
            swbreak
        default
            error = &quot;不明なトークンです&quot;
            ret = 1
            break
        swend
    loop
    if ret : return ret
    if stack_ptr != 1 {
        error = &quot;オペランドが足りないか、余っています&quot;
        return 1
    }
    result = stack.0
    return 0

#deffunc calculate str _expr, var result
    calc_lex _expr
    if stat : return stat
    calc_convert_to_rpn
    if stat : return stat
    calculate_rpn result
    return stat

#global
init_calc

exprs = &quot;1+2*(3+4)&quot;, &quot;1+--1&quot;, &quot; ( 1 + ( 2 + ( 3 ) ) )&quot;, &quot;2.5/-1.2&quot;, &quot;1+&quot;, &quot;((&quot;, &quot;()&quot;, &quot;&quot;
foreach exprs
    expr = exprs.cnt
    mes expr
    calculate expr, result
    if stat {
        mes &quot;Error: &quot;+error@calc
    } else {
        mes &quot; = &quot; + result
    }
loop&lt;/code&gt;&lt;/pre&gt;
&lt;ins datetime=&quot;2008-02-13T07:10:54+09:00&quot;&gt;
&lt;p&gt;
二項演算子のオペランドの &lt;code&gt;_a&lt;/code&gt; と &lt;code&gt;_b&lt;/code&gt; が逆だったので修正。
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>d3module Z ソート</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/02/d3module-z-sort.html" />
<id>http://www.fujidig.com/2008/02/d3module-z-sort.html</id>
<published>2008-02-07T06:28:58+09:00</published>
<updated>2008-02-07T07:45:52+09:00</updated>
<summary>#include &quot;d3m.hsp&quot; #module cub...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/02/d3module-z-sort.html">
&lt;p&gt;
&lt;img src=&quot;/2008/02/images/d3module-z-sort.png&quot; alt=&quot;&quot;&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;d3m.hsp&quot;

#module cube

#deffunc init_cube
    // 面の座標（4点）のパターン（4つ）
    dim pattern, 4, 4
    pattern.0.0 = 0, 0, 0, 0
    pattern.0.1 = 0, 1, 1, 0
    pattern.0.2 = 1, 1, 0, 0
    pattern.0.3 = 1, 1, 1, 1

    dim association, 3, 6
    // それぞれの面(6)のX,Y,Z(3)について、patternのインデックスを設定する
    // よい変数名がうかばない
    association.0.0 = 0, 1, 2
    association.0.1 = 3, 1, 2
    association.0.2 = 1, 0, 2
    association.0.3 = 1, 3, 2
    association.0.4 = 1, 2, 0
    association.0.5 = 1, 2, 3
    return

#deffunc cube_coordinate int face
    dup xs, pattern( 0, association( 0, face ) )
    dup ys, pattern( 0, association( 1, face ) )
    dup zs, pattern( 0, association( 2, face ) )
    return

#deffunc draw_cube int face
    cube_coordinate face
    d3square xs, ys, zs
    return

#defcfunc face_dist int face
    cube_coordinate face
    dx = 0.25 * ( xs.0 + xs.1 + xs.2 + xs.3 )
    dy = 0.25 * ( ys.0 + ys.1 + ys.2 + ys.3 )
    dz = 0.25 * ( zs.0 + zs.1 + zs.2 + zs.3 )

    // ダサい＞＜
    dx += local_coordinate@.0 - camera@.0
    dy += local_coordinate@.1 - camera@.1
    dz += local_coordinate@.2 - camera@.2

    return d3dist( dx, dy, dz )

#deffunc cube_sorted_faces array faces
    dim faces, 6 // 面番号の配列
    ddim face_dists, 6 // 面のカメラとの距離
    repeat 6
        faces.cnt = cnt
        face_dists.cnt = face_dist( cnt )
    loop

    // バブルソート
    repeat 6
        i = cnt
        repeat 6 - i - 1
            j = cnt
            dup n, faces.j
            dup v, face_dists.j
            if( v &amp;lt; v.1 ) {
                tmp_n = n
                tmp_v = v
                n = n.1
                v = v.1
                n.1 = tmp_n
                v.1 = tmp_v
            }
        loop
    loop
    return

#global
init_cube

    gmode 3,,, 200
    repeat
        redraw 0
        camera = sin(0.01*cnt)*1.5, cos(0.01*cnt)*1.5, 1.0
        d3setcam camera.0, camera.1, camera.2
        local_coordinate = -0.5, -0.5, -0.5
        d3setlocal local_coordinate.0, local_coordinate.1, local_coordinate.2
        color : boxf
        cube_sorted_faces faces
        repeat 6
            i = faces.cnt
            hsvcolor i * 192 / 6, 255, 255
            draw_cube i
        loop
        redraw 1
        await 40
    loop&lt;/code&gt;&lt;/pre&gt;
</content>
</entry>
<entry>
<title>d3module でマウス座標と重なっているセルを調べる</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/02/d3module-mouse-hover-cell.html" />
<id>http://www.fujidig.com/2008/02/d3module-mouse-hover-cell.html</id>
<published>2008-02-05T08:04:47+09:00</published>
<updated>2008-02-07T06:42:43+09:00</updated>
<summary>といっても、二次元座標から三次元座標に変換をするわけではあり...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/02/d3module-mouse-hover-cell.html">
&lt;p&gt;
&lt;img src=&quot;/2008/02/images/d3module-mouse-hover-cell.png&quot; alt=&quot;&quot;&gt;
&lt;/p&gt;
&lt;p&gt;
といっても、二次元座標から三次元座標に変換をするわけではありません。書き込んだバッファから pget してどのセルと重なっているか調べるだけです。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;d3m.hsp&quot;

#const WINDOW_ID_MAIN 0
#const WINDOW_ID_WORK 1

#const PANEL_SIZE_X 1.0
#const PANEL_SIZE_Y 1.0

#const PANEL_DISTANCE_X PANEL_SIZE_X * 1.1
#const PANEL_DISTANCE_Y PANEL_SIZE_Y * 1.1

#const PANELS_NUM_X 10
#const PANELS_NUM_Y 10

#const PANELS_ALL_SIZE_X PANEL_DISTANCE_X * ( PANELS_NUM_X - 1 ) + PANEL_SIZE_X
#const PANELS_ALL_SIZE_Y PANEL_DISTANCE_Y * ( PANELS_NUM_Y - 1 ) + PANEL_SIZE_Y

#const PANELS_START_X 0.0 - PANELS_ALL_SIZE_X / 2
#const PANELS_START_Y 0.0 - PANELS_ALL_SIZE_Y / 2

    buffer WINDOW_ID_WORK
    screen WINDOW_ID_MAIN

    repeat
        d3setcam sin(0.01*cnt)*10, cos(0.01*cnt)*10, 10
        mx = mousex : my = mousey
        gsel WINDOW_ID_WORK
        cls
        gosub *draw
        pget mx, my
        select_x = ginfo_r : select_y = ginfo_g
        gsel WINDOW_ID_MAIN
        redraw 0
        color 255, 255, 255 : boxf
        gosub *draw
        redraw
        await 40
    loop
    stop


*draw
    repeat PANELS_NUM_Y
        y = cnt
        py = PANEL_DISTANCE_Y * y + PANELS_START_Y
        repeat PANELS_NUM_X
            x = cnt
            px = PANEL_DISTANCE_X * x + PANELS_START_X
            pxs = px, px + PANEL_SIZE_X, px + PANEL_SIZE_X, px
            pys = py, py, py + PANEL_SIZE_Y, py + PANEL_SIZE_Y
            pzs = 0, 0, 0, 0
            if ginfo_sel == WINDOW_ID_WORK {
                color x, y
            } else {
                color
                if select_x == x &amp;amp;&amp;amp; select_y == y {
                    color 255
                }
            }
            d3square pxs, pys, pzs
        loop
    loop
    return&lt;/code&gt;&lt;/pre&gt;
</content>
</entry>
<entry>
<title>簡単にスペースの連続した文字列を得る</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/02/get-spaces-string.html" />
<id>http://www.fujidig.com/2008/02/get-spaces-string.html</id>
<published>2008-02-02T19:30:57+09:00</published>
<updated>2008-02-02T19:30:57+09:00</updated>
<summary>mes &quot;[&quot;+strf(&quot;%10.0d&quot;, 0 )+&quot;]&quot;...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/02/get-spaces-string.html">
&lt;pre&gt;&lt;code&gt;mes &quot;[&quot;+strf(&quot;%10.0d&quot;, 0 )+&quot;]&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
10 のところを変更すれば任意のサイズにできるよ。
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;memset&lt;/code&gt; を使うのに比べて変数が不要な分、簡単。
&lt;/p&gt;
</content>
</entry>
<entry>
<title>HSP の文字列リテラルを表す正規表現</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/02/string-regexp.html" />
<id>http://www.fujidig.com/2008/02/string-regexp.html</id>
<published>2008-02-01T06:11:09+09:00</published>
<updated>2008-02-01T07:59:48+09:00</updated>
<summary>文字列リテラル /&quot;[^\\&quot;]*(\\.[^\\&quot;]*)*...</summary>
<category term="未分類" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/02/string-regexp.html">
&lt;dl&gt;
&lt;dt&gt;文字列リテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/&quot;[^\\&quot;]*(\\.[^\\&quot;]*)*(&quot;|$)/&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;複数行文字列リテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/\{&quot;[^\\&quot;]*((&quot;(?!\})|\\.)[^\\&quot;]*)*&quot;\}/m&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;文字コードリテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/'[^\\']*(\\.[^\\']*)*('|$)/&lt;/code&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;
少し前は文字列リテラルを表す正規表現ってどう書けばいいのかぜんぜん分からなかったんだけれど、今だとぜんぜん普通に書けた。
&lt;/p&gt;
&lt;p&gt;
ところで、文字列リテラル中にダブルクォートが3つ以上入る場合、複数行文字列リテラルを使った方がスクリプトの文字数が短くなる。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mes &quot;\&quot;&quot;
mes {&quot;&quot;&quot;}

mes &quot;\&quot;\&quot;&quot;
mes {&quot;&quot;&quot;&quot;}

mes &quot;\&quot;\&quot;\&quot;&quot;
mes {&quot;&quot;&quot;&quot;&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
というわけで、たとえ 1 行でもダブルクォートのたくさん入った文字列を使う場合は複数行文字列リテラルを使おう。
&lt;/p&gt;
&lt;ins datetime=&quot;2008-02-01T06:08:49+09:00&quot;&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.google.com/search?q=%E6%96%87%E5%AD%97%E5%88%97%E3%83%AA%E3%83%86%E3%83%A9%E3%83%AB+%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE&quot;&gt;文字列リテラル 正規表現でググって&lt;/a&gt;みました。
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://refluxflow.blogspot.com/2007/09/blog-post.html&quot;&gt;refluxflow::memo: 文字列リテラルにマッチする正規表現&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
そっか。もう少し短くかけたね。
&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;文字列リテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/&quot;([^\\&quot;]|\\.)*(&quot;|$)/&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;複数行文字列リテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/\{&quot;([^\\&quot;]|\\.|&quot;(?!\}))*&quot;\}/m&lt;/code&gt;&lt;/dd&gt;
&lt;dt&gt;文字コードリテラル&lt;/dt&gt;
&lt;dd&gt;&lt;code&gt;/'([^\\']|\\.)*('|$)/&lt;/code&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;
複数行文字列リテラルは &lt;code&gt;/\{&quot;([^\\&quot;]|\\.|&quot;)*?&quot;\}/m&lt;/code&gt; でもいいか。
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>巨大な実数を str に渡したり、 mes で表示しようとすると落ちる。</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/passel-crash.html" />
<id>http://www.fujidig.com/2008/01/passel-crash.html</id>
<published>2008-01-31T22:37:03+09:00</published>
<updated>2008-02-02T19:19:19+09:00</updated>
<summary>mes 1e100 // 落ちる これで HSP が落ちる。...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/passel-crash.html">
&lt;pre&gt;&lt;code&gt;mes 1e100 // 落ちる&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
これで HSP が落ちる。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a = str(1e100) // 落ちる&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;code&gt;str&lt;/code&gt; に渡しても落ちる。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#runtime &quot;hsp3cl&quot;
mes 1e100 // 落ちない
a = str(1e100) // 落ちない&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
両方ともランタイムが hsp3cl なら落ちない。
&lt;/p&gt;
&lt;p&gt;
環境は Windows XP Home SP2 / HSP3.1
&lt;/p&gt;
&lt;ins datetime=&quot;2008-02-02T19:19:08+09:00&quot;&gt;
&lt;p&gt;
OpenHSP のソースコードを追っかけてみた。
&lt;/p&gt;
&lt;p&gt;
hspvar_str.cpp
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static char conv[64];&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
という固定長の配列に書き込んでいたので、これを超えるとバッファオーバーフローが発生するというわけですねー。
&lt;/p&gt;
&lt;p&gt;
同じような原因で、&lt;code&gt;a=strf(&quot;%5000d&quot;, 0 )&lt;/code&gt;で終了時に「問題が発生したため、hsp3.exe を終了します。 ご不便をおかけして申し訳ありません。」というエラーが出たり。
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>数値表記のアンダースコア</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/numeric-underscore.html" />
<id>http://www.fujidig.com/2008/01/numeric-underscore.html</id>
<published>2008-01-31T21:25:37+09:00</published>
<updated>2008-02-01T06:09:35+09:00</updated>
<summary>OpenHSP - HSPメモ帳（全然更新しないブログ） /...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/numeric-underscore.html">
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.goo.ne.jp/hiro239415/e/b855bcdd9c1d7d119413e507c41992d5&quot;&gt;OpenHSP - HSPメモ帳（全然更新しないブログ）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dev.onionsoft.net/trac/browser/trunk/hspcmp/codegen.cpp#L500&quot;&gt;/trunk/hspcmp/codegen.cpp(500) - OpenHSP - Trac&lt;/a&gt;
&lt;/ul&gt;
&lt;p&gt;
へええ、 16 進表記や 2 進表記では Perl や Ruby みたいにアンダースコアをつけることができるんですね。
&lt;/p&gt;
&lt;p&gt;
だから、以下のような Perl みたいなスクリプトが HSP でもコンパイルできます。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/perl
print( $_ );&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;small&gt;&lt;code&gt;#!/usr/bin/perl&lt;/code&gt; は不明なプリプロセッサ命令として無視されているんだと思います。&lt;/small&gt;
&lt;/p&gt;
&lt;p&gt;
そして、 &lt;code&gt;$&lt;/code&gt; や &lt;code&gt;%&lt;/code&gt; の後ろには何もついていなくても OK なんですね。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mes 0x //=&gt; 0&lt;/code&gt;&lt;/pre&gt;
&lt;ins datetime=&quot;2008-01-31T22:06:09+09:00&quot;&gt;
&lt;pre&gt;&lt;code&gt;mes 0e //=&gt; 0
mes 0e+&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
指数表記の &lt;code&gt;e&lt;/code&gt; の後ろも省略できるんだあ。
&lt;/p&gt;
&lt;/ins&gt;
&lt;ins datetime=&quot;2008-02-01T06:08:49+09:00&quot;&gt;
&lt;p&gt;
さらに少し遊んでみる。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mes %^(%*`!%--$&amp;gt;@&amp;amp;(_&amp;lt;&amp;lt;$))+%|@&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
宇宙人からの暗号か何か？顔文字みたいなのも作れるかな。（全角文字使えばそんなの簡単に作れるとか言わない！）
&lt;/p&gt;
&lt;p&gt;
他に、あらかじめ
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#define my(%1)if$&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
しておいて、
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;my $cafe = &quot;hello&quot;;
print( $cafe );&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
とか。
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>HDL で使われている文字列連結</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/hdl-concat.html" />
<id>http://www.fujidig.com/2008/01/hdl-concat.html</id>
<published>2008-01-26T14:31:30+09:00</published>
<updated>2008-01-26T15:36:14+09:00</updated>
<summary>HSP Document Library のソースを読んでみ...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/hdl-concat.html">
&lt;p&gt;
&lt;a href=&quot;http://sprocket.babyblue.jp/html/dlpage.htm&quot;&gt;HSP Document Library&lt;/a&gt; のソースを読んでみました。
&lt;/p&gt;
&lt;p&gt;
hdl.hsp（バージョン 1.0 ） 1234 行目、 1305 行目と 1446 行目あたりで以下のように文字列の連結を行っていました。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tmp = &quot;&quot; ; accelerator ▽
repeat count
    ( 略 )
    tmp += ( 略 )
    if 1000000\(cnt+1)=0 : buf += tmp:tmp=&quot;&quot; ; accelerator
    sql_next
loop
buf += tmp ; accelerator △&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
これって &lt;code&gt;tmp&lt;/code&gt; という変数を使わずに直接 &lt;code&gt; buf&lt;/code&gt; に連結しても多分大丈夫だと思うんですが、こうした方が高速なのでしょう。文字列を連結するときには先頭から文字列の終端を探すことになるので、長い文字列だと時間がかかります。連結する文字列をまとめてから連結することで、長い文字列に連結する回数が減って高速になる、ということです。
&lt;/p&gt;
&lt;h2&gt;実験１&lt;/h2&gt;
&lt;p&gt;
本当に速くなるのか試しに実験。
&lt;/p&gt;
&lt;h3&gt;コード&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#uselib &quot;winmm.dll&quot;
#cfunc timeGetTime &quot;timeGetTime&quot;

#const trial_times 2000

    proc = *a, *b
    repeat 5, 1
        trial_strlen = cnt * cnt * cnt * 1000
        mes strf(&quot;文字列長（%dbytes）の場合：&quot;, trial_strlen)
        foreach proc
            sdim buf, trial_strlen + 1
            memset buf, 'a', trial_strlen
            time = timeGetTime()
            gosub proc.cnt
            time = timeGetTime() - time
            mes strf(&quot; %c : &quot;, 'a'+cnt) + strf( &quot;%d[msec]&quot;, time )
            await
        loop
        mes
    loop
    stop

*a
    repeat trial_times
        buf += &quot;sample string&quot;
    loop
    return

*b
    tmp = &quot;&quot;
    repeat trial_times
        tmp += &quot;sample string&quot;
        if 1000000\(cnt+1)=0 : buf += tmp:tmp=&quot;&quot;
    loop
    buf += tmp
    return&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;結果&lt;/h3&gt;
&lt;pre&gt;&lt;samp&gt;文字列長（1000bytes）の場合：
 a : 35[msec]
 b : 6[msec]

文字列長（8000bytes）の場合：
 a : 62[msec]
 b : 6[msec]

文字列長（27000bytes）の場合：
 a : 125[msec]
 b : 9[msec]

文字列長（64000bytes）の場合：
 a : 215[msec]
 b : 10[msec]

文字列長（125000bytes）の場合：
 a : 329[msec]
 b : 14[msec]&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
なかなか速くなっているようで驚き。
&lt;/p&gt;
&lt;h2&gt;実験２&lt;/h2&gt;
&lt;p&gt;
&lt;a href=&quot;http://rpen.blogspot.com/2007/12/blog-post_16.html&quot;&gt;HSP3のスクリプトを垂れ流すブログ: 高速な文字列の結合（連結）&lt;/a&gt; のスクリプトに以下を追加して試してみました。
&lt;/p&gt;
&lt;h3&gt;コード&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;    mes &quot;\ntmp使用版計測開始……&quot;
    string = &quot;&quot;
    tmp = &quot;&quot;
    time_start = timeGetTime()
    repeat TRIAL_TIME
        tmp += &quot;sample string\n&quot;
        if 1000000\(cnt+1)=0 : string += tmp:tmp=&quot;&quot;
    loop
    string += tmp
    time(3) = timeGetTime() - time_start
    mes strf(&quot;tmpを使用：%d[ms]&quot;, time(3))
    mes &quot;tmp使用版計測終了。&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;結果&lt;/h3&gt;
&lt;pre&gt;&lt;samp&gt;独自命令版計測中……
独自命令を使用：88[ms]
独自命令版計測終了。

+=使用版計測開始……
標準の+=を使用：1020[ms]
+=使用版計測終了。

noteadd使用版計測開始……
noteaddを使用：3306[ms]
noteadd使用版計測終了。

tmp使用版計測開始……
tmpを使用：123[ms]
tmp使用版計測終了。&lt;/samp&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;code&gt;poke&lt;/code&gt; を使うのよりやや遅いくらいです。 &lt;code&gt;+=&lt;/code&gt; を使うのでも工夫すれば速くなるのですね。
&lt;/p&gt;
&lt;p&gt;
計測した環境は Windows XP Home SP2 / Pentium 4 CPU 2.40GHz / 512 MB RAM です。
&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://rpen.blogspot.com/2007/12/blog-post_16.html&quot;&gt;HSP3のスクリプトを垂れ流すブログ: 高速な文字列の結合（連結）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rpen.blogspot.com/2008/01/lstrlenastrlen.html&quot;&gt;HSP3のスクリプトを垂れ流すブログ: lstrlenAとstrlenの速度比較&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
</entry>
<entry>
<title>Atom が Invalid だったのを修正</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/atom-to-valid.html" />
<id>http://www.fujidig.com/2008/01/atom-to-valid.html</id>
<published>2008-01-19T22:31:41+09:00</published>
<updated>2008-01-20T14:44:40+09:00</updated>
<summary>jidilog に移行してから Atom の更新が Feed...</summary>
<category term="未分類" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/atom-to-valid.html">
&lt;p&gt;
jidilog に移行してから Atom の更新が Feed リーダー（ LDR ）に反映されないなー、なんでだろー。って思って &lt;a href=&quot;http://validator.w3.org/feed/&quot;&gt;W3C Feed Validator&lt;/a&gt; にかけてみると &lt;code&gt;link&lt;/code&gt; 要素が間違っていたみたい。
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link rel=&quot;alternate&quot; type=&quot;text/html&quot; href=&quot;http://www.fujidig.com/2008/01/black-and-pink-style.html&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
こんな風にしないといけないところを、
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link&amp;gt;http://www.fujidig.com/2008/01/black-and-pink-style.html&amp;lt;/link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
こんな感じになっていた。（多分 RSS を吐くコードをコピペした後に修正し忘れ）
&lt;/p&gt;
&lt;p&gt;
すぐに修正して Valid にしました。これで直るはずだと思うけど...&lt;ins datetime=&quot;2008-01-20T14:44:22+09:00&quot;&gt;直りました&lt;/ins&gt;
&lt;/p&gt;
&lt;ins datetime=&quot;2008-01-19T23:01:36+09:00&quot;&gt;
&lt;p&gt;
ついでに RSS ・ Atom でカテゴリの出力もうまくいっていないことを発見したのでそれも修正。（カテゴリ ID を使ってカテゴリを探さないといけないのに、エントリ ID で探していたのが原因）
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>黒とピンクのスタイル</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/black-and-pink-style.html" />
<id>http://www.fujidig.com/2008/01/black-and-pink-style.html</id>
<published>2008-01-15T22:15:31+09:00</published>
<updated>2008-01-18T23:13:13+09:00</updated>
<summary>前回の白背景に青緑のスタイルから主に配色をいじって、 CSS...</summary>
<category term="未分類" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/black-and-pink-style.html">
&lt;p&gt;
前回の白背景に青緑のスタイルから主に配色をいじって、 CSS を作りました。今まで自分があまりやったことのない配色ということで黒背景とピンク。
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;body&lt;/code&gt; に左マージンをとって、見出しをネガティブマージンではみだしたりとかもしてみました。
&lt;/p&gt;
&lt;p&gt;
前回のスタイルは代替スタイルシートにしています。
&lt;/p&gt;
&lt;ins datetime=&quot;2007-01-18T21:45:00+09:00&quot;&gt;
&lt;p&gt;
あまりピンクって感じではなかったので明るいピンクを背景色にしたのも作りました。見出しのはみ出している部分に左ボーダーを使って透けているように見せかけたり。今回のこの二つのスタイルでは、文書の最後のナビゲーションとインフォメーションが本文じゃないんだよってことが分かるようにできたと思います。
&lt;/p&gt;
&lt;/ins&gt;
</content>
</entry>
<entry>
<title>HSP のオープンソースプロジェクトが始まってるー</title>
<link rel="alternate" type="text/html" href="http://www.fujidig.com/2008/01/openhsp-project.html" />
<id>http://www.fujidig.com/2008/01/openhsp-project.html</id>
<published>2008-01-15T17:35:18+09:00</published>
<updated>2008-01-15T17:35:18+09:00</updated>
<summary>OpenHSP - Trac わー、すごい。わくわくしちゃう...</summary>
<category term="HSP" />
<content type="html" xml:lang="ja" xml:base="http://www.fujidig.com/2008/01/openhsp-project.html">
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://dev.onionsoft.net/trac/&quot;&gt;OpenHSP - Trac&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
わー、すごい。わくわくしちゃう。私も参加してみたくなりました＞＜
&lt;/p&gt;
</content>
</entry>
</feed>
