IronHSP UTF-16 ワイド文字列型 (wstr) - 設計書
最終更新: 2026-04-11
1. 概要
HSP の変数型に UTF-16 LE ワイド文字列型 wstr (HSPVAR_FLAG_WSTR = 10) を追加する。
既存の文字列関数は第1引数の変数型を見て str/wstr を自動判定し、戻り値も同じ型で返す。
使用例
wsdim ws, 256
ws = L"Unicode文字列" ; L"..." リテラルで UTF-16 直接代入
ws = "Shift-JIS文字列" ; str → wstr 自動変換
n = strlen(ws) ; wstr なので wcslen 動作 → 文字数
s = strmid(ws, 0, 4) ; wstr → wstr 部分文字列
mes ws ; wstr → str 自動変換して表示
#func MessageBoxW "MessageBoxW" int, wstr, wstr, int
MessageBoxW 0, L"本文", L"題名", 0
2. 変数型の定義
| ID | 定数名 | 内部格納 | basesize |
| 2 | HSPVAR_FLAG_STR | char* (SJIS or UTF-8) | sizeof(char*) |
| 10 | HSPVAR_FLAG_WSTR | wchar_t* (UTF-16 LE) | sizeof(wchar_t*) |
自動変換ルール
| 変換 | 方法 |
| str → wstr | MultiByteToWideChar(CP_ACP or CP_UTF8) |
| wstr → str | WideCharToMultiByte(CP_ACP or CP_UTF8) |
| wstr → int | wcstol() |
| wstr → double | wcstod() |
| int → wstr | swprintf(L"%d") |
| double → wstr | swprintf(L"%f") |
L"..." リテラル
コンパイラのトークナイザで L" を検出し、ソース文字列を UTF-16 に変換してデータセグメント (DS) に格納。
バイトコードでは新しい即値型 TYPE_WSTR として扱う。
ws = L"Hello" ; DS に 48 00 65 00 6C 00 6C 00 6F 00 00 00 (UTF-16 LE) を格納
ws = "Hello" ; DS に "Hello\0" (SJIS/UTF-8) を格納 → ランタイムで wstr に自動変換
3. 命令・関数の対応一覧
以下の全ての命令・関数を wstr 対応にする。第1引数(対象文字列変数)の型が wstr の場合、内部的に wchar_t ベースの処理に切り替える。
3.1 文字列関数 (戻り値あり)
| 関数 | 対応 | str 時の動作 | wstr 時の動作 | 戻り値の型 |
strlen(s) |
型判定 |
strlen() バイト数 |
wcslen() 文字数 |
int |
strmid(s, p, n) |
型判定 |
char ベース部分文字列 |
wchar_t ベース部分文字列 |
str / wstr (入力と同じ) |
instr(s, p, target) |
型判定 |
strstr() |
wcsstr() |
int |
strtrim(s, n, target) |
型判定 |
char ベーストリミング |
wchar_t ベーストリミング |
str / wstr (入力と同じ) |
strf(format, ...) |
型判定 |
sprintf() |
swprintf() |
str / wstr (format引数と同じ) |
getpath(s, type) |
型判定 |
char ベースパス処理 |
wchar_t ベースパス処理 |
str / wstr (入力と同じ) |
notefind(target, mode) |
型判定 |
char ベース行検索 |
wchar_t ベース行検索 |
int |
noteinfo(type) |
自動 |
notesel で選択中のバッファ型に応じて自動切替 |
int / str / wstr |
3.2 文字列命令 (戻り値なし)
| 命令 | 対応 | str 時の動作 | wstr 時の動作 |
strrep s, old, new |
型判定 |
char ベース置換 |
wchar_t ベース置換 |
split s, delim, v1, v2... |
型判定 |
char ベース分割 |
wchar_t ベース分割 → 各変数も wstr |
getstr buf, src, offset, delim |
型判定 |
char バッファ読み出し |
wchar_t バッファ読み出し |
strexchange file, mode |
対象外 |
スクリプト置換(ランタイム時は不要) |
3.3 ノートパッド命令
notesel で選択した変数が wstr の場合、以降の note 系命令は全て wchar_t ベースで動作する。
改行コードは L"\r\n" (0x000D 0x000A) を使用。
| 命令 | 対応 | 備考 |
notesel s |
型判定 |
s が wstr なら以降 wchar モード。内部フラグで記録 |
noteunsel |
自動 |
フラグをリセット |
noteget s, n |
型判定 |
notesel のバッファ型に応じて動作。出力先が str なら自動変換 |
noteadd s, n, mode |
型判定 |
wstr バッファに wchar_t 行を追加/置換 |
notedel n |
自動 |
改行文字 (0x000A) で行を判定 |
noteload file |
型判定 |
wstr バッファの場合: UTF-16 LE ファイルとして読み込み (BOM 自動判定) |
notesave file |
型判定 |
wstr バッファの場合: UTF-16 LE + BOM で保存 |
3.4 変換命令
| 命令/関数 | 対応 | 備考 |
cnvstow |
拡張 |
出力先が wstr 変数なら直接代入。従来の byte バッファ方式も互換維持 |
cnvwtos |
拡張 |
入力が wstr 変数なら直接読み取り。従来の byte バッファ方式も互換維持 |
cnvstoa |
自動 |
wstr 入力時: UTF-16 → ANSI 変換 |
cnvatos |
自動 |
wstr 出力時: ANSI → UTF-16 変換 |
3.5 新規命令・関数
| 命令/関数 | 説明 |
wsdim var, len |
wstr 変数を宣言。len は文字数(バイト数ではない)。内部的に len * 2 + 2 バイト確保 |
L"..." |
UTF-16 文字列リテラル。コンパイル時に UTF-16 LE に変換して DS に格納 |
4. 内部実装
4.1 hspvar_wstr.cpp
既存の hspvar_str.cpp と同様の FlexBuffer 方式。ただし char の代わりに wchar_t を使用。
// 主要関数
HspVarWstr_Cnv() // str/int/double → wstr 変換
HspVarWstr_CnvCustom() // wstr → str/int/double 変換
HspVarWstr_Set() // wchar_t* のコピー
HspVarWstr_AddI() // 文字列結合 (wcscat)
HspVarWstr_GetSize() // wcslen() * sizeof(wchar_t)
// FlexBuffer: wchar_t* の配列
// pval->pt → wchar_t* (offset 0)
// pval->master → wchar_t*[] (配列要素)
4.2 型判定パターン(既存関数の拡張)
// hsp3int.cpp - strlen の例
case 0x002: // strlen
{
int chk = code_get();
if (chk <= PARAM_END) throw HSPERR_INVALID_FUNCPARAM;
if (mpval->flag == HSPVAR_FLAG_WSTR) {
// wstr: 文字数を返す
wchar_t *ws = (wchar_t *)HspVarCoreCnvPtr(mpval, HSPVAR_FLAG_WSTR);
reffunc_intfunc_ivalue = (int)wcslen(ws);
} else {
// str: バイト数を返す(従来通り)
char *ss = (char *)HspVarCoreCnvPtr(mpval, HSPVAR_FLAG_STR);
reffunc_intfunc_ivalue = (int)strlen(ss);
}
ptr = &reffunc_intfunc_ivalue;
break;
}
4.3 L"..." リテラルのコンパイル
// codegen.cpp - トークナイザ
if ((a1 == 'L' || a1 == 'l') && wp[1] == 0x22) { // L"
wp += 2;
Pickstr(); // s3 に SJIS/UTF-8 文字列を取得
// UTF-16 に変換
int wlen = MultiByteToWideChar(codepage, 0, (char*)s3, -1, NULL, 0);
wchar_t *wbuf = new wchar_t[wlen];
MultiByteToWideChar(codepage, 0, (char*)s3, -1, wbuf, wlen);
// DS に UTF-16 バイト列を格納
int dsofs = PutDSBufW(wbuf, wlen * sizeof(wchar_t));
delete[] wbuf;
val = dsofs;
return TK_WSTRING; // 新トークン型
}
// PutCS で TYPE_WSTR として出力
// ランタイムが DS からワイド文字列ポインタを取得
5. 実装フェーズ
| Phase | 内容 | 対象ファイル | 状態 |
| 1 |
wstr 変数型 + wsdim + CnvCustom (自動変換) |
hspvar_wstr.cpp (新規), hspvar_core.h/cpp, hsp3code.cpp |
完了 |
| 2 |
L"..." リテラル (PP + CG + RT) |
token.cpp, token.h, codegen.cpp, hsp3code.cpp |
完了 |
| 3 |
文字列関数の型判定分岐 (strlen/strmid/instr/strtrim/getpath) |
hsp3int.cpp |
完了 |
| 4 |
文字列命令の型判定分岐 (strrep/split/getstr) |
hsp3int.cpp |
完了 |
| 5 |
note 系命令の wstr 対応 (notesel/noteget/noteadd/notedel/noteload/notesave/noteinfo/notefind) |
hsp3int.cpp |
完了 |
| 6 |
変換命令 (cnvstow/cnvwtos) — 自動変換で代替可能、既存実装維持 |
hsp3ext_win.cpp (既存) |
完了 |
strf は現状フォーマット文字列が char ベースのため wstr 非対応。wstr 引数は CnvCustom で自動的に str に変換される。
6. 互換性
- 既存の str コードは一切変更なしで動作する
mes ws や s = "" + ws では CnvCustom で wstr → str に自動変換される
- DLL の
wstr パラメータ型は既存の MPTYPE_LOCALWSTR を活用
cnvstow / cnvwtos は従来の byte バッファ方式も引き続き動作する
L"..." リテラルを含む .ax は従来のランタイムでは実行できない