SQLeleとHDLのデータベースを利用した、HSPスクリプトの(X)HTMLコンバータ……のモジュール。サンプルスクリプト付き。
ブログにアップするような量じゃない(約1000行!)のですが、折角できたので公開。そのうち正式にHPに置くと思います。ヘルプも作ってないので使いにくいと思いますが、使い道がありましたらどうぞご自由にお使いください。
このモジュールを利用したコンバータはHSPにHDLとSQLeleが標準でつくようになったら配布を開始したいと思います。
このスクリプト自身の変換で約3秒かかります。不必要な外部ファイルは解析しない処理を組み込んだこともあり、2秒近い高速化が行えているようです。// HSPスクリプトを(X)HTMLへ変換するモジュール(HTXmodule)
機能:
// 【動作条件】
// ・HDL用データベース(hdlbase.xdb)が作成されていること
// ・sqlele.hspがcommonフォルダにあること
// HDL用データベース内のCacheテーブルを使用します。
#ifndef HTX_MSG
#include "sqlele.hsp"
#module HSPtoXHTML
// 変換設定
#const global HTX_HTML 0x00000000 // HTML形式で変換
#const global HTX_XHTML 0x00000001 // XHTML形式で変換
#const global HTX_ADD_BR 0x00000002 // 改行時に<br>または<br />を追加
#const global HTX_TAB_TO_SPACE 0x00000004 // タブをスペースに変換
#const global HTX_SPACE_TO_NBSP 0x00000008 // スペースを に変換
#const global HTX_SEARCH_OTHER 0x00000010 // 外部のスクリプト(includeしたファイル)を検索
// マークアップ(MarkUp)する要素
#const global HTX_MU_CMD 0x00000100 // 命令
#const global HTX_MU_FUNC 0x00000200 // 関数
#const global HTX_MU_COMMENT 0x00000400 // コメント
#const global HTX_MU_PREPRO 0x00000800 // プリプロセッサ
#const global HTX_MU_SYSVAR 0x00001000 // システム変数
#const global HTX_MU_LABEL 0x00002000 // ラベル
#const global HTX_MU_BASIC 0x00003F00 // HSP3.1付属スクリプトエディタでマークアップされるすべての要素
#const global HTX_MU_STRING 0x00004000 // 文字列
#const global HTX_MU_MACRO 0x00008000 // マクロ
#const global HTX_MU_NUMBER 0x00010000 // 数値
#const global HTX_MU_SCODE 0x00020000 // 文字コード
#const global HTX_MU_ALL 0x00FFFF00 // すべての要素
// エラー
#enum global HTX_ERR_NOERROR = 0 // エラーなし・正常終了
#enum global HTX_ERR_NODB // データベースが見つからない
#enum global HTX_ERR_NOFILE // ファイルが見つからない
#enum global HTX_ERR_NODIR // ディレクトリが見つからない
#enum global HTX_ERR_CONSTRUCTION // 構文に誤りがある or 循環インクルード
// 定数
#const CP_ACP 0
#define DB_HEADER "_TABLE_FOR_HTX_" // ヘッダ
#const HTX_DEFAULT_TAB_WIDTH 4 // タブ幅 デフォルト値
#const HTX_EXPAND_SIZE 1024 // スクリプト保存用変数 メモリ確保量・拡張量
#const HTX_DEFAULT_NEST 5 // インクルードネスト
#const global HTX_MSG 0xB000
// 改行コード
#const CR 0x0D
#const LF 0x0A
#const CRLF 0x0A0D
// タグ
#define ctype tag_start(%1, %2="") _tag_start@HSPtoXHTML(%1, %2) + ">"
#defcfunc _tag_start@HSPtoXHTML str tag_name, str class_name
if class_name != "" {
return "<" + tag_name + " class=\"" + class_name + "\""
} else {
return "<" + tag_name
}
#define ctype tag_end(%1) "</" + (%1) + ">"
#define tag_alone(%1, %2="") _tag_alone@HSPtoXHTML(%1, %2="")
#deffunc _tag_alone@HSPtoXHTML str tag_name, str class_name
if mode_xhtml {
return _tag_start(tag_name, class_name) + " />"
} else {
return _tag_start(tag_name, class_name) + ">"
}
// 状態
#enum STATE_NORMAL = 1
#enum STATE_COMMENT
#enum STATE_MULTILINE_COMMENT
#enum STATE_STRINGS
#enum STATE_MULTILINE_STRINGS
// 状態(行)
#enum LSTATE_NORMAL = 1
#enum LSTATE_DEFFUNC
#enum LSTATE_DEFCFUNC
#enum LSTATE_UNDEF
#enum LSTATE_MACRO
#enum LSTATE_INCLUDE
#enum LSTATE_ADDITION
// データベース名
#define DB_HDL "hdlbase.xdb"
// デフォルトクラス名
#define DEFAULT_CLASS_CMD "cmd" // 命令
#define DEFAULT_CLASS_FUNC "func" // 関数
#define DEFAULT_CLASS_COMMENT "comment" // コメント
#define DEFAULT_CLASS_PREPRO "prepro" // プリプロセッサ
#define DEFAULT_CLASS_SYSVAR "sysvar" // システム変数
#define DEFAULT_CLASS_LABEL "label" // ラベル
#define DEFAULT_CLASS_STRING "str" // 文字列
#define DEFAULT_CLASS_MACRO "macro" // マクロ
#define DEFAULT_CLASS_NUMBER "num" // 数値
#define DEFAULT_CLASS_SCODE "scode" // 文字コード
#uselib "kernel32.dll"
#cfunc global IsDBCSLeadByteEx "IsDBCSLeadByteEx" sptr, sptr
// ***************************************************
// 内部で使用する命令
#deffunc insert_data@HSPtoXHTML int markup
num = stat
repeat num
sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(sql_v("Name")) + "'," + markup + ")"
sql_next
loop
return
#define ctype to_lower(%1) getpath(%1, 16)
// ***************************************************
// 変換で使用する命令
// 文字がスペースかどうか(キーワードとして利用できない文字かどうか)調べる
#defcfunc is_space@HSPtoXHTML int iTarget
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@HSPtoXHTML int iTarget
return ('0' <= iTarget) & (iTarget <= '9')
// 文字列の追加
#define add_string@HSPtoXHTML(%1,%2=0) _add_string@HSPtoXHTML %1, %2
#deffunc _add_string@HSPtoXHTML str str_to_add, int _width_to_add
if num_include == 0 {
len = strlen(str_to_add)
width_to_add = _width_to_add
if width_to_add == 0 : width_to_add = len
if code_after_size <= code_after_pos + len {
code_after_size += HTX_EXPAND_SIZE
memexpand code_after, code_after_size
}
poke code_after, code_after_pos, str_to_add
code_after_pos += len
code_after_x += width_to_add
}
return
// ***************************************************
// HTXmodule用データベースを作成(更新)する(Cacheテーブルを利用)
// htx_make_DB target_dir
// target_dir : データベースがあるディレクトリ
#deffunc htx_make_DB str target_dir
sql_open target_dir + "/" + DB_HDL
// Cacheテーブルを初期化
sql_q "DELETE FROM Cache"
sql_q "BEGIN"
// HTX用に初期化されていることを判別するためのデータを書きこむ
sql_q "INSERT INTO Cache (ID, Key) VALUES (1, '" + DB_HEADER + "')"
// 命令の登録
sql_q "SELECT Name FROM Help WHERE Prm NOT LIKE '(%' AND Group3 NOT LIKE '%マクロ%' AND Group3 NOT LIKE '%システム変数%' AND Group3 NOT LIKE '%プリプロセッサ%'"
insert_data@HSPtoXHTML HTX_MU_CMD
// 関数の登録
sql_q "SELECT Name FROM Help WHERE Prm LIKE '(%' AND Group3 NOT LIKE '%マクロ%' AND Group3 NOT LIKE '%システム変数%' AND Group3 NOT LIKE '%プリプロセッサ%'"
insert_data@HSPtoXHTML HTX_MU_FUNC
// システム変数の登録
sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%システム変数%'"
insert_data@HSPtoXHTML HTX_MU_SYSVAR
// マクロの登録
sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%マクロ%'"
insert_data@HSPtoXHTML HTX_MU_MACRO
// プリプロセッサの登録
sql_q "SELECT Name FROM Help WHERE Group3 LIKE '%プリプロセッサ%'"
insert_data@HSPtoXHTML HTX_MU_PREPRO
sql_q "COMMIT"
sql_close
return HTX_ERR_NOERROR
// データベースの存在確認・変数初期化
// 変換実行前に必ず1度実行すること
// path_DB : hdlbase.xdbがあるディレクトリ(デフォルトでdir_exe)
// stat == HTX_ERR_NOERROR : ロード成功
// stat == HTX_ERR_NODB : データベースが見つからない
// stat == HTX_ERR_NODIR : ディレクトリが見つからない
#define global htx_init(%1=dir_exe) _htx_init@HSPtoXHTML %1
#deffunc _htx_init@HSPtoXHTML str path_DB
// ディレクトリの存在を確認する
dirlist tmp, path_DB, 5
if stat == 0 {
// ディレクトリが見つからない
return HTX_ERR_NODIR
}
// データベースの存在を確認する
dir_current = dir_cur // 命令実行時のカレントディレクトリを記録
chdir path_DB : exist DB_HDL
if strsize == -1 {
// データベースファイルが見つからない
// 命令実行時のカレントディレクトリに戻る
gosub *back_to_first_dir_cur
return HTX_ERR_NODB
}
// CacheテーブルがHTXmodule用かどうか判別し、そうでなければ
// HDL用データベースからHTXmodule用データベースを作成
need_to_make = 0
sql_open DB_HDL
sql_q "SELECT Key FROM Cache WHERE ID = 1"
if stat == 0 {
// ID1のレコードが存在しない
need_to_make = 1
} else : if sql_v("Key") != DB_HEADER {
// ID1のレコードがHTXmodule用のヘッダと異なる
need_to_make = 1
}
sql_close
if need_to_make : htx_make_DB path_DB
// 各種変数の初期化
gosub *init_setting
// 命令実行時のカレントディレクトリに戻る
gosub *back_to_first_dir_cur
return HTX_ERR_NOERROR
// 各種変数の初期化
*init_setting
// タブ幅を設定
tab_width = HTX_DEFAULT_TAB_WIDTH
// データベース名をフルパスで記録
DB_name = path_DB +"/" + DB_HDL
// クラス名を設定
class_cmd = DEFAULT_CLASS_CMD
class_func = DEFAULT_CLASS_FUNC
class_comment = DEFAULT_CLASS_COMMENT
class_prepro = DEFAULT_CLASS_PREPRO
class_sysvar = DEFAULT_CLASS_SYSVAR
class_label = DEFAULT_CLASS_LABEL
class_string = DEFAULT_CLASS_STRING
class_macro = DEFAULT_CLASS_MACRO
class_number = DEFAULT_CLASS_NUMBER
class_scode = DEFAULT_CLASS_SCODE
return
// 命令実行時のカレントディレクトリに戻る
*back_to_first_dir_cur
chdir dir_current
return
// タブ幅を設定
// 幅が1未満の時は強制的にHTX_DEFAULT_TAB_WIDTHにする
#deffunc htx_set_tab_width int _new_width
new_width = _new_width
if new_width < 1 : new_width = HTX_DEFAULT_TAB_WIDTH
tab_width = new_width
return HTX_ERR_NOERROR
// htx_set_class new_class, mode
// クラス名を設定
// new_class : 新しいクラス名
// mode : 設定するクラスを指す数値(HTX_MU_???)
#deffunc htx_set_class str new_class, int mode
if mode & HTX_MU_CMD : class_cmd = new_class
if mode & HTX_MU_FUNC : class_func = new_class
if mode & HTX_MU_COMMENT : class_comment = new_class
if mode & HTX_MU_PREPRO : class_prepro = new_class
if mode & HTX_MU_SYSVAR : class_sysvar = new_class
if mode & HTX_MU_LABEL : class_label = new_class
if mode & HTX_MU_STRING : class_string = new_class
if mode & HTX_MU_MACRO : class_macro = new_class
if mode & HTX_MU_NUMBER : class_number = new_class
if mode & HTX_MU_SCODE : class_scode = new_class
return HTX_ERR_NOERROR
// htx_cnv code, mode, path_code, path_common
// 変換を実行(Shift-JIS限定)
// source : 変換するスクリプトが代入された変数
// mode : 変換モード(HTX_???およびHTX_MU_???の論理和)
// path_code : スクリプトのあるパス(デフォルトでdir_exe)
// path_common : コモンフォルダのパス(デフォルトでdir_exe + "/common")
// stat == HTX_ERR_NOERROR : 変換成功
// stat == HTX_ERR_NODB : データベースが作成されていない・htx_open未実行
// stat == HTX_ERR_NOFILE : インクルードするファイルが見つからない
// stat == HTX_ERR_CONSTRUCTION : 文法が間違っている
#define global htx_cnv(%1, %2, %3=dir_exe, %4="") _htx_cnv@HSPtoXHTML %1, %2, %3, %4
#deffunc _htx_cnv@HSPtoXHTML var source, int mode, str path_code, str _path_common
exist DB_name
if strsize == -1 {
// データベースファイルがない あるいは htx_open未実行
return HTX_ERR_NODB
}
path_common = _path_common
if path_common == "" : path_common = dir_exe + "\\common"
gosub *before_cnv // 変換の準備
gosub *convert // 変換の実行
gosub *after_cnv // 変換の後処理
return error
*before_cnv
sql_open DB_name
sql_q "BEGIN"
notesel code
code_before = source // 変換前のスクリプトを保存する変数
code = source // 解析対象のスクリプトを保存する変数
error = HTX_ERR_NOERROR
first_char_of_prm = 1 // ラベルの判定に使用
need_to_add = 0
need_to_del = 0
sdim code_name, 256, HTX_DEFAULT_NEST // ファイル名(フルパス)
dim code_size, HTX_DEFAULT_NEST // ファイルサイズ
dim code_pos, HTX_DEFAULT_NEST // 解析地点
dim code_state, HTX_DEFAULT_NEST // 状態
dim code_lstate, HTX_DEFAULT_NEST // 状態(行)
num_include = 0 // 外部ファイル ネスト数
code_name(0) = path_code + "\\"
code_size(0) = strlen(code_before)
code_pos(0) = 0
code_state(0) = STATE_NORMAL
code_lstate(0) = LSTATE_NORMAL
sdim code_after, EXPAND_SIZE // 変換結果を保存する変数
code_after_x = 0
code_after_pos = 0 // 変換結果 文字列挿入地点
code_after_size = EXPAND_SIZE
// 変換モードの抽出
mode_xhtml = (mode & HTX_XHTML) != 0
mode_add_br = (mode & HTX_ADD_BR) != 0
mode_tab_to_space = (mode & HTX_TAB_TO_SPACE) != 0
mode_space_to_nbsp = (mode & HTX_SPACE_TO_NBSP) != 0
mode_search_other = (mode & HTX_SEARCH_OTHER) != 0
// マークアップする要素の抽出
markup_cmd = (mode & HTX_MU_CMD) != 0
markup_func = (mode & HTX_MU_FUNC) != 0
markup_comment = (mode & HTX_MU_COMMENT) != 0
markup_prepro = (mode & HTX_MU_PREPRO) != 0
markup_sysvar = (mode & HTX_MU_SYSVAR) != 0
markup_label = (mode & HTX_MU_LABEL) != 0
markup_string = (mode & HTX_MU_STRING) != 0
markup_macro = (mode & HTX_MU_MACRO) != 0
markup_number = (mode & HTX_MU_NUMBER) != 0
markup_scode = (mode & HTX_MU_SCODE) != 0
return
// まだ書き換え終わっていない
*convert
repeat
if error != HTX_ERR_NOERROR : break
code_pos(num_include) = cnt
c = peek(code, code_pos(num_include))
switch c
case 0
// ファイル終了
break
swbreak
case CR
case LF
// 改行
gosub *start_new_line
// 自分自身にメッセージを送信する
sendmsg hwnd, HTX_MSG, 100 * code_pos(num_include) / code_size(num_include), num_include
if strmid(code, cnt, 2) == "\n" {
continue cnt + 2
}
swbreak
case '/'
if (strmid(code, cnt, 2) == "/*") & (code_state(num_include) == STATE_NORMAL) {
// 複数行コメント開始
gosub *start_multiline_comment
add_string "/*"
continue cnt + 2
}
if (strmid(code, cnt, 2) == "//") & (code_state(num_include) == STATE_NORMAL) {
// 単一行コメント開始
gosub *start_singleline_comment
add_string "//"
continue cnt + 2
}
add_string "/"
swbreak
case '*'
// ラベル
if (first_char_of_prm) & (code_state(num_include) == STATE_NORMAL) {
gosub *first_char_finished
gosub *add_label
continue code_pos(num_include)
}
// 複数行コメントの終了
if (strmid(code, cnt, 2) == "*/") & (code_state(num_include) == STATE_MULTILINE_COMMENT) {
add_string "*/"
gosub *end_multiline_comment
continue cnt + 2
}
add_string "*"
swbreak
case ';'
// 単一行コメント開始
if (code_state(num_include) == STATE_NORMAL) {
gosub *start_singleline_comment
}
add_string ";"
swbreak
case '{'
// 複数行文字列の開始
if (strmid(code, cnt, 2) == "{\"") & (code_state(num_include) == STATE_NORMAL) {
gosub *start_multiline_strings
add_string "{\""
continue cnt + 2
}
add_string "{"
swbreak
case '\"'
// 単一行文字列開始
if (code_state(num_include) == STATE_NORMAL) {
gosub *start_singleline_strings
add_string "\""
continue
}
// 単一行文字列終了
if (code_state(num_include) == STATE_STRINGS) {
add_string "\""
gosub *end_singleline_strings
continue cnt + 1
}
if (strmid(code, cnt, 2) == "\"}") & (code_state(num_include) == STATE_MULTILINE_STRINGS) {
add_string "\"}"
gosub *end_multiline_strings
continue cnt + 2
}
add_string "\""
swbreak
case '\t'
if mode_tab_to_space & (code_state(num_include) != STATE_STRINGS) & (code_state(num_include) != STATE_MULTILINE_STRINGS) {
// タブをスペースへ変換する
if mode_space_to_nbsp {
s = " "
} else {
s = " "
}
repeat tab_width - (code_after_x \ tab_width)
add_string s, 1
loop
} else {
add_string "\t", tab_width - (code_after_x \ tab_width)
}
swbreak
case ' '
if mode_space_to_nbsp {
// 半角スペースを変換(文字列中・コメント中でも実行)
add_string " ", 1
} else {
add_string " "
}
swbreak
case ':'
// 文の区切れ
add_string ":"
if code_state(num_include) == STATE_NORMAL : gosub *end_line
swbreak
case ',' : case '='
// パラメータの区切れ
add_string strf("%c", c)
if code_state(num_include) == STATE_NORMAL : gosub *end_area
swbreak
case '\\'
if (code_state(num_include) == STATE_STRINGS) | (code_state(num_include) == STATE_MULTILINE_STRINGS) {
if (strmid(code, cnt, 2) == "\\\\") | (strmid(code, cnt, 2) == "\\\"") {
add_string strmid(code, cnt, 2)
continue cnt + 2
}
}
add_string "\\"; : x++
swbreak
case '&' : add_string "&", 1 : swbreak
case '<' : add_string "<", 1 : swbreak
case '>' : add_string ">", 1 : swbreak
default
// 命令・関数などキーワードの可能性
if IsDBCSLeadByteEx(CP_ACP, c) {
// 2バイト文字の場合
// 現在のバージョンでは変数をマークアップしないので、
// このように扱ってもOK。
add_string strmid(code, cnt, 2); : x += 2
continue cnt + 2
}
// 1バイト文字の場合
if code_state(num_include) == STATE_NORMAL {
// 文字列中やコメント中でなければ、数値や命令・関数としてマークアップできるかどうか調べる
if is_number(c) | (c == '%') | (c == '$') | (c == '-') {
// 数値の挿入
gosub *add_number
continue code_pos(num_include)
}
if c == '\'' {
// 文字コード
gosub *add_stringing_code
continue code_pos(num_include)
}
if (is_space(c) == 0) | (c == '#') {
// 命令・プリプロセッサ・関数etc.の挿入
gosub *add_word
continue code_pos(num_include)
}
}
// 命令などを構成する文字列ではなかった場合(@,|,(,)など)
gosub *first_char_finished
add_string strf("%c", c); : x++
swbreak
swend
loop
gosub *start_new_line
return
// 変数の処理
*first_char_finished
// 空白でない文字を取り出した場合
first_char_of_prm = 0
return
*end_line
// (マルチステートメントを含む論理的な)行の終了に伴う変数の変化
*end_area
// パラメータの終了に伴う変数の変化
first_char_of_prm = 1
return
// *****************************************************************
// 単行コメントの開始
*start_singleline_comment
code_state(num_include) = STATE_COMMENT
if markup_comment {
add_string tag_start("span", class_comment)
}
return
// コメント行を終了
*end_singleline_comment
code_state(num_include) = STATE_NORMAL
if markup_comment {
add_string tag_end("span")
}
return
// 複数行コメントの開始
*start_multiline_comment
code_state(num_include) = STATE_MULTILINE_COMMENT
if markup_comment {
add_string tag_start("span", class_comment)
}
return
// 複数行コメントの終了
*end_multiline_comment
code_state(num_include) = STATE_NORMAL
if markup_comment {
add_string tag_end("span")
}
return
// 単行文字列の開始
*start_singleline_strings
code_state(num_include) = STATE_STRINGS
if markup_string {
add_string tag_start("span", class_string)
}
if mode_search_other & ((code_lstate(num_include) == LSTATE_INCLUDE) | (code_lstate(num_include) == LSTATE_ADDITION)) {
// インクルードするファイル名の開始
inc_filename_pos = code_pos(num_include) + 1
}
return
// 単行文字列の終了
*end_singleline_strings
code_state(num_include) = STATE_NORMAL
if markup_string {
add_string tag_end("span")
}
if mode_search_other & ((code_lstate(num_include) == LSTATE_INCLUDE) | (code_lstate(num_include) == LSTATE_ADDITION)) {
// インクルードするファイル名の終了
inc_filename = strmid(code, inc_filename_pos, code_pos(num_include) - inc_filename_pos)
// hsファイルがありそうなら検索しない(高速化)
sql_q "SELECT COUNT(*) FROM Help WHERE Mod LIKE '" + getpath(inc_filename, 9) + "'"
if sql_i("COUNT(*)") > 0 : return
exist getpath(code_name(num_include), 32) + inc_filename
if strsize < 0 {
// 今のスクリプトと同じフォルダに見つからない場合
exist path_common + "\\" + inc_filename
if strsize < 0 {
if code_lstate(num_include) == LSTATE_ADDITION {
// #additionの場合、ファイルが見つからないくても問題ない
return
}
if code_lstate(num_include) == LSTATE_INCLUDE {
// #includeの場合、ファイルが見つからないのは問題
error = HTX_ERR_NOFILE
return
}
} else {
// commonフォルダにありました
code_name(num_include + 1) = path_common + "\\" + inc_filename
}
} else {
// 今のスクリプトと同じフォルダにありました
code_name(num_include + 1) = getpath(code_name(num_include), 32) + inc_filename
}
// インクルードするファイル名が求まった!
// 多重インクルード防止
// 同じファイルをインクルードしている状態なら、エラーを発行(無限ループ防止)
repeat num_include + 1
if code_name(cnt) == code_name(num_include + 1) {
error = HTX_ERR_CONSTRUCTION
break
}
loop
if error != HTX_ERR_NOERROR : return
num_include++
exist code_name(num_include)
code_size(num_include) = strsize
code_pos(num_include) = 0
code_state(num_include) = STATE_NORMAL
code_lstate(num_include) = LSTATE_NORMAL
noteload code_name(num_include)
wait 1
gosub *convert
num_include--
if num_include {
exist inc_filename(num_include)
sdim code, strsize + 1
noteload inc_filename(num_include)
} else {
sdim code, code_size(0) + 1
code = code_before
}
wait 1
}
return
// 複数行文字列の開始
*start_multiline_strings
code_state(num_include) = STATE_MULTILINE_STRINGS
if markup_string {
add_string tag_start("span", class_string)
}
return
// 複数行文字列の終了
*end_multiline_strings
code_state(num_include) = STATE_NORMAL
if markup_string {
add_string tag_end("span")
}
return
// *****************************************************************
// code_pos(num_include)の位置以降をラベルとして挿入
*add_label
label_length = code_size(num_include) - code_pos(num_include)
repeat code_size(num_include) - code_pos(num_include) - 1, code_pos(num_include) + 1
if (code_size(num_include) <= cnt) {
label_length = code_size(num_include) - code_pos(num_include)
break
}
j = peek(code, cnt)
if IsDBCSLeadByteEx(CP_ACP, j) : continue cnt + 2
if (cnt == code_pos(num_include) + 1) & is_number(j) {
label_length = cnt - code_pos(num_include)
break
}
if is_space(j) {
label_length = cnt - code_pos(num_include)
break
}
loop
if markup_label & (1 < label_length) {
add_string tag_start("span", class_label)
}
add_string strmid(code, code_pos(num_include), label_length)
code_pos(num_include) += label_length
if (markup_label) & (1 < label_length) {
add_string tag_end("span")
}
return
// code_pos(num_include)の位置以降を数字として挿入
*add_number
if markup_number {
add_string tag_start("span", class_number)
}
number_length = 0
repeat -1, 1
j = peek(code, code_pos(num_include) + cnt)
if is_number(j) | (j == '.') {
continue
}
if (cnt == 1) : if (peek(code, code_pos(num_include)) == '0') & ((j == 'x') | (j == 'b')) {
continue
}
if (j == 'e') | (j == 'E') {
if code_pos(num_include) + cnt + 1 < code_size(num_include) {
n = peek(code, code_pos(num_include) + cnt + 1)
if (n == '+') | (n == '-') : continue cnt + 2
}
continue
}
if (('a' <= j) & (j <= 'f')) | (('A' <= j) & (j <= 'F')) {
if ((to_lower(strmid(code, code_pos(num_include), 2)) == "0x") | (peek(code, code_pos(num_include)) == '$')) {
// 16進数
continue
}
}
number_length = cnt
break
loop
add_string strmid(code, code_pos(num_include), number_length)
code_pos(num_include) += number_length
if markup_number {
add_string tag_end("span")
}
return
// 文字コード
*add_stringing_code
if markup_scode {
add_string tag_start("span", class_scode)
}
scode_length = 0
repeat -1, 1
j = peek(code, code_pos(num_include) + cnt)
if j == '\\' {
continue cnt + 2
}
if (j == '\'') | (j == 0) {
scode_length = cnt + 1
break
}
loop
add_string strmid(code, code_pos(num_include), scode_length)
code_pos(num_include) += scode_length
if markup_scode {
add_string tag_end("span")
}
return
// 命令・関数・システム変数など
*add_word
repeat -1, 1
if code_pos(num_include) + cnt >= code_size(num_include) {
keyword = strmid(code, code_pos(num_include), cnt)
break
}
if is_space(peek(code, code_pos(num_include) + cnt)) {
keyword = strmid(code, code_pos(num_include), cnt)
break
}
loop
lower_keyword = to_lower(keyword)
sql_q "SELECT * FROM Cache WHERE Key = '" + sqesc(keyword) + "' LIMIT 1"
if stat {
// データベースに載っている文字列は適切なタグで囲む
// doubleのみ別(データベースに載っているため)
if (tmp_stock == "#const") & (lower_keyword == "double") & (code_lstate(num_include) == LSTATE_MACRO) {
gosub *add_word_sub
return
}
need_to_add = 0 // hsファイルなどで先に定義されていた場合を考慮
switch sql_i("Data")
case HTX_MU_CMD
add_string tag_start("span", class_cmd)
swbreak
case HTX_MU_FUNC
if (code_lstate(num_include) == LSTATE_NORMAL) | ((lower_keyword!="int") & (lower_keyword!="str") & (lower_keyword!="double")) {
add_string tag_start("span", class_func)
}
swbreak
case HTX_MU_SYSVAR
add_string tag_start("span", class_sysvar)
swbreak
case HTX_MU_PREPRO
if markup_prepro : add_string tag_start("span", class_prepro)
if (lower_keyword == "#deffunc") | (lower_keyword == "#modfunc") | (lower_keyword == "#func") {
code_lstate(num_include) = LSTATE_DEFFUNC
tmp_stock = lower_keyword
if markup_cmd : need_to_add = 1
}
if (lower_keyword == "#modinit") {
code_lstate(num_include) = LSTATE_DEFFUNC
}
if (lower_keyword == "#defcfunc") | (lower_keyword == "#cfunc") {
code_lstate(num_include) = LSTATE_DEFCFUNC
if markup_func : need_to_add = 1
}
if (lower_keyword == "#enum") | (lower_keyword == "#const") | (lower_keyword == "#define") {
code_lstate(num_include) = LSTATE_MACRO
tmp_stock = lower_keyword
if markup_macro : need_to_add = 1
}
if lower_keyword == "#cmpopt" : tmp_stock = lower_keyword
if (lower_keyword == "#include") {
code_lstate(num_include) = LSTATE_INCLUDE
}
if (lower_keyword == "#addition") {
code_lstate(num_include) = LSTATE_ADDITION
}
if (lower_keyword == "#undef") {
code_lstate(num_include) = LSTATE_UNDEF
need_to_del = 1
}
swbreak
case HTX_MU_MACRO
add_string tag_start("span", class_macro)
swbreak
swend
add_string keyword
switch sql_i("Data")
case HTX_MU_CMD
case HTX_MU_SYSVAR
case HTX_MU_MACRO
add_string tag_end("span")
swbreak
case HTX_MU_PREPRO
if markup_prepro : add_string tag_end("span")
swbreak
case HTX_MU_FUNC
if (code_lstate(num_include) == LSTATE_NORMAL) | ((lower_keyword != "int") & (lower_keyword != "str") & (lower_keyword != "double")) {
add_string tag_end("span")
}
swbreak
swend
// データベースに載っていてundefする→データベースから一時的に削除
if need_to_del {
if code_lstate(num_include) == LSTATE_UNDEF {
sql_q "DELETE FROM Cache WHERE Key = '" + sqesc(keyword) + "'"
need_to_del = 0
}
}
} else {
// データベースに載っていないのにundefする→無効
if need_to_del {
if (code_lstate(num_include) == LSTATE_UNDEF) {
need_to_del = 0
}
}
// データベースに載っていない文字列はそのまま
if (tmp_stock == "#cmpopt") {
gosub *add_word_sub : tmp_stock = ""
return
}
if need_to_add {
if (code_lstate(num_include) == LSTATE_MACRO) & (lower_keyword == "global") {
gosub *add_word_sub
return
}
if ((code_lstate(num_include) == LSTATE_DEFFUNC) | (code_lstate(num_include) == LSTATE_DEFCFUNC)) & (lower_keyword == "local") {
gosub *add_word_sub
return
}
if ((code_lstate(num_include) == LSTATE_DEFFUNC) | (code_lstate(num_include) == LSTATE_DEFCFUNC)) & (lower_keyword == "global") & ((tmp_stock != "#deffunc") & (tmp_stock != "#defcfunc")) {
gosub *add_word_sub
return
}
if (tmp_stock == "#define") & (lower_keyword == "ctype") & (code_lstate(num_include) == LSTATE_MACRO) {
gosub *add_word_sub
return
}
switch code_lstate(num_include)
case LSTATE_DEFFUNC
sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_CMD + ")"
swbreak
case LSTATE_DEFCFUNC
sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_FUNC + ")"
swbreak
case LSTATE_MACRO
sql_q "INSERT INTO Cache (Key, Data) VALUES ('" + sqesc(keyword) + "'," + HTX_MU_MACRO + ")"
code_lstate(num_include) == LSTATE_NORMAL
swbreak
swend
need_to_add = 0
return
}
add_string keyword
}
gosub *first_char_finished
if (sql_i("Data") == HTX_MU_CMD) : gosub *end_area
code_pos(num_include) += strlen(keyword)
return
*add_word_sub
if markup_prepro {
add_string tag_start("span", class_prepro) + keyword + tag_end("span")
} else {
add_string keyword
}
code_pos(num_include) += strlen(keyword)
return
// 新しい行の開始(マルチステートメントを除く、物理的に新しい行)
*start_new_line
if code_state(num_include) == STATE_COMMENT {
gosub *end_singleline_comment
}
if (code_state(num_include) == STATE_STRINGS) {
error == HTX_ERR_CONSTRUCTION
return
}
code_lstate(num_include) = LSTATE_NORMAL
need_to_add = 0 : need_to_del = 0
if mode_add_br {
add_string tag_alone("br")
}
add_string "\n"
if num_include == 0 : code_after_x = 0
gosub *end_line
return
*after_cnv
sql_q "ROLLBACK"
sql_close
if error != HTX_ERR_NOERROR {
// 何らかのエラーが発生した
code_after = ""
}
source = code_after
sdim code, 4
sdim code_after, 4
sdim code_before, 4
return
#global
#endif
// テスト用
#if 1
#const STEP 5
#const BROGBAR_HEIGHT 22
#include "hsp3util.as"
oncmd gosub *jump, HTX_MSG
notesel code
// 対象となるスクリプトの選択
dialog "hsp",16
if stat == 0 : end
file_name = refstr
// GUIコンポーネントの配置
mesbox code, ginfo_winx / 2, ginfo_winy - BROGBAR_HEIGHT
id_mesbox = stat
progbar ginfo_winx, BROGBAR_HEIGHT
id_progbar = stat
progbar_set id_progbar, STEP
prog_step = 0
pos ginfo_winx / 2, 0
axobj ie, "Shell.Explorer.2", ginfo_winx / 2, ginfo_winy - BROGBAR_HEIGHT
if stat == -1 {
dialog "ActiveXコントロールの配置に失敗しました。", 1
}
id_ie = stat
// スクリプトのロード
noteload file_name
// 変換の準備
title "変換の準備をしています..."
htx_init
if stat == HTX_ERR_NODB {
dialog "データベースファイルが見つかりません。", 1
end
} else : if stat == HTX_ERR_NODIR {
dialog "ディレクトリが見つかりません。", 1
end
}
// 変換実行
title "変換中..."
htx_cnv code, HTX_MU_ALL | HTX_SEARCH_OTHER, getpath(file_name, 32) // すべての属性をマークアップする
if stat == HTX_ERR_NODB {
dialog "データベースファイルが見つかりません。", 1
end
} else : if stat == HTX_ERR_NOFILE {
dialog "インクルードするファイルが見つかりません。", 1
end
} else : if stat == HTX_ERR_CONSTRUCTION {
dialog "構文が異常です。解析できません。", 1
end
}
title "変換が終了しました。"
objprm id_mesbox, code
gosub *make_html
stop
// 変換の進行度合いによってプログレスバーを進める(100/5=20段階)
*jump
if lparam == 0 {
title strf("変換中(%d%%)...", wparam)
while(prog_step < wparam)
prog_step += STEP
progbar_step id_progbar
wend
}
return
// HTMLファイルの作成
*make_html
ie -> "Navigate" "about:blank"
doc = ie("Document")
header = {"<html><head><style TYPE='text/css'>
<!--
body {color : #ffffff;background-color : #000000;}
.comment {color : olive;}
.str {color : #5f9ea0;}
.cmd {color : #c71585;}
.sysvar {color : yellow;}
.macro {color : #cd853f;}
.prepro {color : orange;}
.func {color : #ff0000;}
.label {color : cyan;}
.num {color : #fff0e0;}
-->
</style></head><body><pre>"}
doc -> "write" header
doc -> "write" code
doc -> "write" "</pre></body></html>"
return
#endif
- HTML・XHTML両対応
- <,>,&への変換
- 命令やマクロなど要素のマークアップ(任意)
- マークアップ時のクラス名変更
- タブのスペースへの変換(任意)
- タブ幅の指定
- への変換(任意)
- 改行タグの追加(任意)
- 変換進行状況に応じた処理(ウィンドウメッセージの送信を利用)
2 件のコメント:
tag_alone の部分がおかしいです。
こうではありませんか。
#define ctype tag_alone(%1, %2="") _tag_alone(%1, %2)
#defcfunc _tag_alone str tag_name, str class_name
if mode_xhtml {
return _tag_start(tag_name, class_name) + " />"
} else {
return _tag_start(tag_name, class_name) + ">"
}
include したファイルを検索する設定だと user32.as や kernel32.as などを include していると変換に時間がかかってしまいますね。
スクリプトはじっくり読んでいませんが、よく include するファイルのパース結果のデータベースをキャッシュする仕組みがあれば速くなるのではないでしょうか。
その通りです。訂正させていただきます。m(_ _)m
> Win32API用ヘッダファイル
そうですね。キーワード名とそのタイプ(命令や関数などを識別する値)だけあれば充分なので、導入も簡単そうです。
ただ、データベースをどこに作るかで少し悩みます。HDL用データベース内のデータはhsファイルが更新されると消えてなくなってしまうので、別の場所を検討した方がいいかも知れません。
コメントを投稿