解析関数の記述方法
ここでは解析関数の記述方法を説明します。
はじめに、解析関数のシグニチャは以下のようになっています。
int 関数名(unsigned int it);
解析関数の引数であるunsigned int型は、構文解析を開始する位置(先頭から何トークン目か)を指し示すものです。
基本的には引数に格納されている値そのものを気にする必要はありません、必要なのはit, it+1, it+2, ... と順々に解析していくことです。
返り値であるint型には解析したトークン数を返します、たとえば「Sample
引数;」という命令であれば3(Sample+引数+;)と返すようにします。解析不能な場合には、-1を返すようにします。
(仮に上記の例において引数が「2+3*5」といった複数のトークンで構成されていても、コンパイラは自動的にそれらをまとめひとつのトークンとみなします)
解析関数の具体的な記述方法ですが、記述する時はコンパイラの関数を利用します。
コンパイラの関数を利用するといっても難しいことを行う必要はありません、必要なのは関数の形式を知ることです。
では、以下にコンパイラの関数の仕様を記します。
IsConst
__declspec(dllexport) bool IsConst(const Token& t);
説明
対象のトークンが定数であるかを判定し、定数であればtrueを、定数でなければfalseを返します。
使用例
IsConst(GetToken(it));
itが指し示しているトークンが定数であるかを判定しています。
IsLabel
__declspec(dllexport) bool IsLabel(const Token& t);
説明
対象のトークンがラベルであるかを判定し、ラベルであればtrueを、ラベルでなければfalseを返します。
使用例
IsLabel(GetToken(it));
itが指し示しているトークンがラベルであるかを判定しています。
IsString
__declspec(dllexport) bool IsString(const Token& t);
説明
対象のトークンが文字列であるかを判定し、文字列であればtrueを、文字列でなければfalseを返します。
使用例
IsString(GetToken(it));
itが指し示しているトークンが文字列であるかを判定しています。
IsOperator
__declspec(dllexport) int IsOperator(const Token& t);
説明
対象のトークンが演算子であるかを判定し、演算子であればtrueを、演算子でなければfalseを返します。
使用例
IsOperator(GetToken(it));
itが指し示しているトークンが演算子であるかを判定しています。
IsIdentifer
__declspec(dllexport) int IsIdentifer(const Token&
t);
説明
対象のトークンが識別子であるかを判定し、識別子であればtrueを、識別子でなければfalseを返します。
使用例
IsIdentifer(GetToken(it));
itが指し示しているトークンが識別子であるかを判定しています。
IsSeparator
__declspec(dllexport) int IsSeparator(const Token&
t);
説明
対象のトークンが区切り文字であるかを判定し、区切り文字であればtrueを、区切り文字でなければfalseを返します。
使用例
IsSeparator(GetToken(it));
itが指し示しているトークンが区切り文字であるかを判定しています。
IsParameter
__declspec(dllexport) bool IsParameter(const Token&
t);
説明
対象のトークンが(数式的な)引数であるかを判定し、引数であればtrueを、引数でなければfalseを返します。
使用例
IsParameter(GetToken(it));
itが指し示しているトークンが引数であるかを判定しています。
IsButtonVar
__declspec(dllexport) bool IsButtonVar(const Token&
t);
説明
対象のトークンがボタンであるかを判定し、ボタンであればtrueを、ボタンでなければfalseを返します。
使用例
IsButtonVar(GetToken(it));
itが指し示しているトークンがボタンであるかを判定しています。
IsSpriteVar
__declspec(dllexport) bool IsSpriteVar(const Token&
t);
説明
対象のトークンがスプライトであるかを判定し、スプライトであればtrueを、スプライトでなければfalseを返します。
使用例
IsSpriteVar(GetToken(it));
itが指し示しているトークンがスプライトであるかを判定しています。
IsValidSyntax
__declspec(dllexport) bool IsValidSyntax(unsigned int
FirstToken, unsigned int LastToken, ... );
説明
対象のトークン(複数可)が正しい構文を構成しているかを判定し、構成していればtrueを、構成していなければfalseを返します。
FirstToken:判定を開始する位置です。
LastToken:判定を終了する位置です。
...:正しい構文です、"ラベル"、"文字列"、"演算子"、"="、";"、","、"{"、"}"、"引数"、"変数"、"未定義変数"、"ボタン"、"スプライト"が使用可能です。
使用例
IsValidSyntax(it+1, it+4, "引数", ",", "引数", ";");
it+1からit+4までが「引数, 引数;」となっているかを判定しています。
GetTokenSize
__declspec(dllexport) unsigned int GetTokenSize();
説明
トークンの数を返します。
使用例
for(unsigned int i=it+1;i<GetTokenSize();i++){
it+1から終端までのforループです。
GetToken
__declspec(dllexport) const Token& GetToken(unsigned
int Num);
説明
数値からトークンを取得します。
使用例
GetToken(it);
itが指し示しているトークンを取得しています。
GetRef
__declspec(dllexport) INovelEngine* GetRef();
説明
コンパイラが現在参照しているINovelEngineクラスのポインタを取得します。
使用例
GetRef()->GetSymbolName()->Set(GetToken(it+1).Param.at(0).Text.c_str(), SY_BUTTON);
it+1が指し示しているトークンをボタンとしてシンボル名に登録しています。
AddCommand
__declspec(dllexport) void AddCommand(ICmd_Base*
NewCommand, const CmdParam& Parameter);
説明
命令クラスに引数を設定し、命令リストに追加します。
使用例
AddCommand(new Cmd_sample, Parameter);
newで生成したCmd_SampleにParameterをSetParamし、命令リストに追加しています。
次に、解析関数の具体例を示し説明を行います。
int Analysis_Sample(unsigned int it){ //正常時 if(IsValidSyntax(it+1, it+4, "引数", ",", "引数", ";")){ CmdParam Parameter; if(GetToken(it).Text=="quakex"){ Parameter.nArg[0] = EFFECTTYPE_QUAKE_X; Parameter.ExArg[1] = GetToken(it+3).Param; } else if(GetToken(it).Text=="quakey"){ Parameter.nArg[0] = EFFECTTYPE_QUAKE_Y; Parameter.ExArg[2] = GetToken(it+3).Param; } else{ goto Error; } Parameter.ExArg[0] = GetToken(it+1).Param; AddCommand(new Cmd_Sample, Parameter); return(5); } else if(IsValidSyntax(it+1, it+6, "引数", ",", "引数", ",", "引数", ";")){ CmdParam Parameter; if(GetToken(it).Text=="flash"){ Parameter.nArg[0] = EFFECTTYPE_FLASH; Parameter.ExArg[3] = GetToken(it+1).Param; Parameter.ExArg[4] = GetToken(it+3).Param; Parameter.ExArg[5] = GetToken(it+5).Param; } else if(GetToken(it).Text=="quakexy"){ Parameter.nArg[0] = EFFECTTYPE_QUAKE_XY; Parameter.ExArg[0] = GetToken(it+1).Param; Parameter.ExArg[1] = GetToken(it+3).Param; Parameter.ExArg[2] = GetToken(it+5).Param; } else{ goto Error; } AddCommand(new Cmd_Sample, Parameter); return(7); } else if(IsValidSyntax(it+1, it+8, "引数", ",", "引数", ",", "引数", ",", "引数", ";")){ CmdParam Parameter; if(GetToken(it).Text=="fadein"){ Parameter.nArg[0] = EFFECTTYPE_FADEIN; } else if(GetToken(it).Text=="fadeout"){ Parameter.nArg[0] = EFFECTTYPE_FADEOUT; } else{ goto Error; } Parameter.ExArg[0] = GetToken(it+1).Param; Parameter.ExArg[3] = GetToken(it+3).Param; Parameter.ExArg[4] = GetToken(it+5).Param; Parameter.ExArg[5] = GetToken(it+7).Param; AddCommand(new Cmd_Sample, Parameter); return(9); } //エラー else{ Error: GetRef()->DEBUGOUT("エラー(%3d行目):構文エラーです!\n", GetToken(it).Line); return(-1); } }
上記のソースコードは、PluginTemplateのCmd_Sample.cpp内にあります。
はじめに、IsValidSyntax関数で構文の解析を行っています。
Sample命令の構文は「Sample 引数, 引数;」か「Sample 引数, 引数, 引数;」か「Sample 引数, 引数, 引数, 引数;」です。
次に、命令の種類を確認します。
Sample命令の識別子は「quakex」か「quakey」か「flash」か「quakexy」か「fadein」か「fadeout」です。
(当然、RegisterPCommandName関数を使い上で挙げた全ての識別子を列挙型と関連付けています)
命令の種類が正しければCmdParam型にCmd_Sampleに与える引数を設定します、正しくなければErrorにgotoです。
最後に、AddCommand関数でnewしたCmd_Sampleクラスとそれに与える引数を命令リストに追加し、解析したトークン数を返します。
Errorでは解析不能な場合にエラーを表示し-1を返します。
解析関数の記述方法は以上です、具体例はBasicCommandsを参照してください。