http://hsp.tv/play/pforum.php?mode=all&num=60555での
NO.60568の発言が「言いだしっぺの法則」などと言われたくないので作った。
内容としては、
「エラー発生時に『分かりやすく』表示して終了する」ための命令と、
「エラー発生時にそのエラー番号を『指定した変数』に渡し、
『指定したラベル』に向かってジャンプする」ための命令。
前者はNO.60568への回答だが、後者はモロ例外処理を意識した感じ。
あまりテストはしていないので不具合があったら先に謝っておく、ごめん。
【モジュール本体(仮にerror.asとする)】
/* エラー出力用モジュール for HSP3 製作者 : YSR 概要 : エラーを分かりやすく表示する命令と、エラーをトラップして種類を取得する命令。 前者を使えば初心者にも分かりやすいエラー表示ができ、 後者を使えばワザとエラー(例外)を出させてから捉えることができる。 命令一覧 : ・ErrorTrapBegin、ErrorTrapEnd →ErrorTrapBeginからErrorTrapEndまでの区間でエラーが発生した場合、 分かりやすいエラー表示を行ってから終了する ・ErrorCatchBegin ErrorNum Label、ErrorCatchEnd →ErrorCatchBeginからErrorCatchEndまでの区間でエラーが発生した場合、 エラー番号をErrorNum(変数名)に返し、Label(ラベル名)までジャンプする。 注意 : グローバル空間における予約語として、 定数→ErrorKinds SizeofInt 変数→ErrorMessageString OutputString ErrorNum モジュール名→ExceptionModule がある。また、ErrorCatchBeginの引数ErrorNumのポインタ位置が変わるような 操作を決して行わないこと。 既知の不具合 : ErrorCatchBeginを使うとアプリケーション終了時にMSVC++のRuntime Libraryでエラーが出る。 要するに「変な終了の仕方だったから情報をサポートまで送ってね」ということ。無視するべし。 */ #const ErrorKinds 41 ;全エラー数 #const SizeofInt 4 ;整数型のバイト数 sdim ErrorMessageString, 64, ErrorKinds ErrorMessageString( 0) = "システムエラーが発生しました" ErrorMessageString( 1) = "文法が間違っています" ErrorMessageString( 2) = "パラメータの値が異常です" ErrorMessageString( 3) = "計算式でエラーが発生しました" ErrorMessageString( 4) = "パラメータの省略はできません" ErrorMessageString( 5) = "パラメータの型が違います" ErrorMessageString( 6) = "配列の要素が無効です" ErrorMessageString( 7) = "有効なラベルが指定されていません" ErrorMessageString( 8) = "サブルーチンやループのネストが深すぎます" ErrorMessageString( 9) = "サブルーチン外のreturnは無効です" ErrorMessageString(10) = "repeat外でのloopは無効です" ErrorMessageString(11) = "ファイルが見つからないか無効な名前です" ErrorMessageString(12) = "画像ファイルがありません" ErrorMessageString(13) = "外部ファイル呼び出し中のエラーです" ErrorMessageString(14) = "計算式でカッコの記述が違います" ErrorMessageString(15) = "パラメータの数が多すぎます" ErrorMessageString(16) = "文字列式で扱える文字数を越えました" ErrorMessageString(17) = "代入できない変数名を指定しています" ErrorMessageString(18) = "0で除算しました" ErrorMessageString(19) = "バッファオーバーフローが発生しました" ErrorMessageString(20) = "サポートされない機能を選択しました" ErrorMessageString(21) = "計算式のカッコが深すぎます" ErrorMessageString(22) = "変数名が指定されていません" ErrorMessageString(23) = "整数以外が指定されています" ErrorMessageString(24) = "配列の要素書式が間違っています" ErrorMessageString(25) = "メモリの確保ができませんでした" ErrorMessageString(26) = "タイプの初期化に失敗しました" ErrorMessageString(27) = "関数に引数が設定されていません" ErrorMessageString(28) = "スタック領域のオーバーフローです" ErrorMessageString(29) = "無効な名前がパラメーターに指定されています" ErrorMessageString(30) = "異なる型を持つ配列変数に代入しました" ErrorMessageString(31) = "関数のパラメーター記述が不正です" ErrorMessageString(32) = "オブジェクト数が多すぎます" ErrorMessageString(33) = "配列・関数として使用できない型です" ErrorMessageString(34) = "モジュール変数が指定されていません" ErrorMessageString(35) = "モジュール変数の指定が無効です" ErrorMessageString(36) = "変数型の変換に失敗しました" ErrorMessageString(37) = "外部DLLの呼び出しに失敗しました" ErrorMessageString(38) = "外部オブジェクトの呼び出しに失敗しました" ErrorMessageString(39) = "関数の戻り値が設定されていません。" ErrorMessageString(40) = "関数を命令として記述しています。" #module ExceptionModule #deffunc ErrorTrapBegin onerror goto *ErrorTrapLabel@ return #deffunc ErrorTrapEnd onerror 0 return #deffunc _ErrorCatchBegin var ErrorNum, var Label ErrorNumPtr = varptr(ErrorNum) ErrorCatchEndLabel = Label onerror gosub *ErrorCatchLabel@ return #define global ErrorCatchBegin(%1, %2) LabelName@ExceptionModule = %2 :_ErrorCatchBegin %1, LabelName@ExceptionModule #deffunc ErrorCatchEnd onerror 0 return #global goto *ErrorLabelx *ErrorTrapLabel sdim OutputString, 1024 OutputString = "エラー番号 : " + wparam + "\n" if(lparam != -1){ OutputString += "エラー発生行番号 : " + lparam + "\n" }else{ OutputString += "エラー発生行番号 : 不明\n" } OutputString += "内容 : " if(limit(wparam, 1, ErrorKinds) == wparam){ OutputString += ErrorMessageString(wparam - 1) }else{ OutputString += "不明" } dialog OutputString, 1, "Error!" end *ErrorCatchLabel dupptr ErrorNum, ErrorNumPtr@ExceptionModule, SizeofInt, vartype("int") ErrorNum = wparam goto ErrorCatchEndLabel@ExceptionModule *ErrorLabelx
【サンプルコード】
#include "error.as" #define TestCodeFlg 0 ;0ならErrorTrapBegin、1ならErrorCatchBeginのテストができる #if TestCodeFlg ErrorTrapBegin ;エラー(例外)捕捉開始 ;具体的なコードを記述する(エラーが出ても構わない) mes 1 / 0 ErrorTrapEnd ;エラー捕捉終了 #else ErrorCatchBegin ErrorCode, *ErrorCatchEndLabel ;エラー(例外)捕捉開始 ;具体的なコードを記述する(エラーが出ても構わない) mes 1 / 0 *ErrorCatchEndLabel ;エラー発生時に飛ぶ箇所 ErrorCatchEnd ;エラー捕捉終了 mes "エラー番号 : " + ErrorCode #endif stop