トークン読み込み用クラス (共通)

これまでC# で作成してきた「SourceToHTML」を、C++Builder に焼きなおしてみます。

TokenReaderCommon.h


//*******************************************************************************************************
// トークンごとに 文字列と その種類を返す ( 共通 )
//*******************************************************************************************************
#ifndef TokenReaderCommonH
#define TokenReaderCommonH
//---------------------------------------------------------------------------
#include "TokenReader.h"
//---------------------------------------------------------------------------
class TTokenReaderCommon : public TTokenReader
{
private:
// 予約語 コレクションを設定
void __fastcall initKeyWord(AnsiString langType);
// 演算子 コレクションを設定
void __fastcall initOperator(AnsiString langType);
// 状態を更新 (その他・区切り記号・不明)
void __fastcall getNextStateOther();

protected:
//予約語 コレクション
TStringList* _keyWords;
//演算子 コレクション
WideString _operators;

// 状態を更新
void __fastcall getNextToken();
// 単一行コメントか?
virtual bool __fastcall IsComSingle();
// 複数行コメントか?
virtual bool __fastcall IsComMulti();
// 文字列か?
virtual bool __fastcall IsString();
// 文字か?
virtual bool __fastcall IsChar();
// 逐語的文字列か?
virtual bool __fastcall IsLiteral();
// ディレクティブか?
virtual bool __fastcall IsDirective();
// 識別子か?
virtual bool __fastcall IsIdent();
// エスケープされた識別子か?
virtual bool __fastcall IsEscape();
// 数字か?
virtual bool __fastcall IsNumber();
// 演算子か?
virtual bool __fastcall IsOperator();
// 区切り記号か?
virtual bool __fastcall IsDelim();
// 日付か?
virtual bool __fastcall IsDate();

// 状態を更新 (単一行コメント)
virtual void __fastcall getNextStateComSin();
// 状態を更新 (複数行コメント)
virtual void __fastcall getNextStateComMul();
// 状態を更新 (文字列)
virtual void __fastcall getNextStateStr();
// 状態を更新 (文字列中のエスケープシーケンス)
virtual void __fastcall getNextStateStrEsc();
// 状態を更新 (逐語的文字列)
virtual void __fastcall getNextStateStrLit();
// 状態を更新 (文字)
virtual void __fastcall getNextStateCha();
// 状態を更新 (文字中のエスケープシーケンス)
virtual void __fastcall getNextStateChaEsc();
// 状態を更新 (識別子)
virtual void __fastcall getNextStateIdw();
// 予約語ではないか?
virtual WideString __fastcall getKeyWord();
// 状態を更新 (エスケープされた識別子)
virtual void __fastcall getNextStateIdwEsc();
// 状態を更新 (数字)
virtual void __fastcall getNextStateNum();
// 16進表記か?
virtual bool __fastcall IsNotHex();
// 状態を更新 (ディレクティブ)
virtual void __fastcall getNextStateDir();
// 状態を更新 (日付)
virtual void __fastcall getNextStateDtm();

public:
// 初期化
__fastcall TTokenReaderCommon(TTextReader* reader, AnsiString langType);
// 終了
__fastcall ~TTokenReaderCommon();
};
#endif

TokenReaderCommon.cpp


//*******************************************************************************************************
// トークンごとに 文字列と その種類を返す ( 共通 )
//*******************************************************************************************************
#pragma hdrstop
#include <vcl.h>
#include "TokenReaderCommon.h"
//-------------------------------------------------------------------------------------------------------
#pragma package(smart_init)
//-------------------------------------------------------------------------------------------------------
// 初期化
//-------------------------------------------------------------------------------------------------------
__fastcall TTokenReaderCommon::TTokenReaderCommon(TTextReader* reader, AnsiString langType):TTokenReader(reader, langType)
{
//予約語 コレクションを設定
initKeyWord(langType);

//演算子 コレクションを設定
initOperator(langType);
}
//-------------------------------------------------------------------------------------------------------
// 終了
//-------------------------------------------------------------------------------------------------------
__fastcall TTokenReaderCommon::~TTokenReaderCommon()
{
delete _keyWords;
}
//-------------------------------------------------------------------------------------------------------
// 予約語 コレクションを設定
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::initKeyWord(AnsiString langType)
{
//予約語 コレクションを設定 (".\cs7\key.txt")
_keyWords = new TStringList();

//予約語ファイルがなければ、予約語コレクションは空っぽ
AnsiString fileName = ExtractFilePath(Application->ExeName) + "\\" + langType + "\\key.txt";
if (FileExists(fileName))
_keyWords->LoadFromFile(fileName);

_keyWords->CaseSensitive = true;
}
//-------------------------------------------------------------------------------------------------------
// 演算子 コレクションを設定
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::initOperator(AnsiString langType)
{
_operators = "";

//演算子ファイルがなければ、演算子コレクションは空っぽ
AnsiString fileName = ExtractFilePath(Application->ExeName) + "\\" + langType + "\\ope.txt";
if (FileExists(fileName))
{
TStringList* reader = new TStringList();
reader->LoadFromFile(fileName);
_operators = reader->Strings[0];
delete reader;
}
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextToken()
{
TTokenReader::getNextToken();

do
{
if (WideSameStr(_context->State, "その他")) getNextStateOther();
else if (WideSameStr(_context->State, "演算子")) getNextStateOther();
else if (WideSameStr(_context->State, "区切り記号")) getNextStateOther();
else if (WideSameStr(_context->State, "不明")) getNextStateOther();
else if (WideSameStr(_context->State, "単一行コメント")) getNextStateComSin();
else if (WideSameStr(_context->State, "複数行コメント")) getNextStateComMul();
else if (WideSameStr(_context->State, "文字列")) getNextStateStr();
else if (WideSameStr(_context->State, "文字列中のエスケープシーケンス")) getNextStateStrEsc();
else if (WideSameStr(_context->State, "逐語的文字列")) getNextStateStrLit();
else if (WideSameStr(_context->State, "文字")) getNextStateCha();
else if (WideSameStr(_context->State, "文字中のエスケープシーケンス")) getNextStateChaEsc();
else if (WideSameStr(_context->State, "識別子")) getNextStateIdw();
else if (WideSameStr(_context->State, "エスケープされた識別子")) getNextStateIdwEsc();
else if (WideSameStr(_context->State, "数字")) getNextStateNum();
else if (WideSameStr(_context->State, "ディレクティブ")) getNextStateDir();
else if (WideSameStr(_context->State, "日付")) getNextStateDtm();

} while(WideSameStr(_context->State,"不明"));
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (その他・区切り記号・不明)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateOther()
{
_context->State = "その他";
_context->nextToken->tokenKind = "その他";

// 状態を更新
if (IsIdent()) _context->State = "識別子";
else if (IsEscape()) _context->State = "エスケープされた識別子";
else if (IsNumber()) _context->State = "数字";
else if (IsDirective()) _context->State = "ディレクティブ";
else if (IsComSingle()) _context->State = "単一行コメント";
else if (IsComMulti()) _context->State = "複数行コメント";
else if (IsString()) _context->State = "文字列";
else if (IsChar()) _context->State = "文字";
else if (IsLiteral()) _context->State = "逐語的文字列";
else if (IsDate()) _context->State = "日付";
else if (IsDelim()) _context->State = "区切り記号";
else if (IsOperator()) _context->State = "演算子";
else _context->State = "その他";

// トークンの種類を取得
if (WideSameStr(_context->State, "逐語的文字列")) _context->nextToken->tokenKind = "文字列";
else if (WideSameStr(_context->State, "エスケープされた識別子")) _context->nextToken->tokenKind = "識別子";
else if (WideSameStr(_context->State, "単一行コメント")) _context->nextToken->tokenKind = "コメント";
else if (WideSameStr(_context->State, "複数行コメント")) _context->nextToken->tokenKind = "コメント";
else if (WideSameStr(_context->State, "日付")) _context->nextToken->tokenKind = "文字列";
else _context->nextToken->tokenKind = _context->State;
}
//-------------------------------------------------------------------------------------------------------
// 単一行コメントか?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsComSingle()
{
return ((_context->currChar == '/') && (_context->nextChar == '/'));
}
//-------------------------------------------------------------------------------------------------------
// 複数行コメントか?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsComMulti()
{
return ((_context->currChar == '/') && (_context->nextChar == '*'));
}
//-------------------------------------------------------------------------------------------------------
// 文字列か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsString()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// 文字か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsChar()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// 逐語的文字列か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsLiteral()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// ディレクティブか?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsDirective()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// 識別子か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsIdent()
{
return (IsLetter(_context->currChar) || (_context->currChar == '_'));
}
//-------------------------------------------------------------------------------------------------------
// エスケープされた識別子か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsEscape()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// 数字か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsNumber()
{
return (IsDigit(_context->currChar));
}
//-------------------------------------------------------------------------------------------------------
// 演算子か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsOperator()
{
if (IsSymbol(_context->currChar))
{
if (_operators.Pos(WideString(_context->currChar)) > 0) return true;
}
return false;
}
//-------------------------------------------------------------------------------------------------------
// 区切り記号か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsDelim()
{
if (IsSymbol(_context->currChar))
{
if (_operators.Pos(WideString(_context->currChar)) <= 0) return true;
}
return false;
}
//-------------------------------------------------------------------------------------------------------
// 日付か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsDate()
{
return false;
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (単一行コメント)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateComSin()
{
_context->State = "単一行コメント";
_context->nextToken->tokenKind = "コメント";

if (_context->currChar == '\n')
{
_context->State = "その他";
_context->nextToken->tokenKind = "その他";
}
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (複数行コメント)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateComMul()
{
_context->State = "複数行コメント";
_context->nextToken->tokenKind = "コメント";

if ((_context->prevChar == '*') && (_context->currChar == '/'))
_context->State = "その他";
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (文字列)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateStr()
{
_context->State = "文字列";
_context->nextToken->tokenKind = "文字列";

// 各派生クラスで処理する
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (文字列中のエスケープシーケンス)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateStrEsc()
{
_context->State = "文字列";
_context->nextToken->tokenKind = "文字列";
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (逐語的文字列)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateStrLit()
{
_context->State = "逐語的文字列";
_context->nextToken->tokenKind = "文字列";

// 各派生クラスで処理する
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (文字)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateCha()
{
_context->State = "文字";
_context->nextToken->tokenKind = "文字";

// 各派生クラスで処理する
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (文字中のエスケープシーケンス)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateChaEsc()
{
_context->State = "文字";
_context->nextToken->tokenKind = "文字";
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (識別子)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateIdw()
{
_context->State = "識別子";
_context->nextToken->tokenKind = "識別子";

if (!IsLetter(_context->currChar) && !IsDigit(_context->currChar) && (_context->currChar != '_'))
{
_context->State = "不明";

//文字種が変わったら、識別子が 予約語ではないか 確認する
WideString keyWord = getKeyWord();
if ((keyWord != NULL) && (wcslen(keyWord) > 0))
{
_context->currToken->tokenKind = "予約語";
_context->currToken->tokenString = keyWord;
}
}
}
//-------------------------------------------------------------------------------------------------------
// 予約語ではないか?
//-------------------------------------------------------------------------------------------------------
WideString __fastcall TTokenReaderCommon::getKeyWord()
{
return "";
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (エスケープされた識別子)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateIdwEsc()
{
_context->State = "エスケープされた識別子";
_context->nextToken->tokenKind = "識別子";

// 各派生クラスで処理する
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (数字)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateNum()
{
_context->State = "数字";
_context->nextToken->tokenKind = "数字";

if ((_context->currChar == '.') && (_context->nextChar == '.'))
_context->State = "不明";

else if (!IsLetter(_context->currChar) && !IsDigit(_context->currChar) && (_context->currChar != '.'))
{
_context->State = "不明";

// "+" か "-" で
if ((_context->currChar == '+') || (_context->currChar == '-'))
{
//1つ前の文字が "e" か "E" で
if ((_context->prevChar == 'e') || (_context->prevChar == 'E'))
{
//16進表記でなければ、数字
if (IsNotHex())
_context->State = "数字";
}
}
}
}
//-------------------------------------------------------------------------------------------------------
// 16進表記か?
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReaderCommon::IsNotHex()
{
// 0x で始まっていたら、16進
if (wcslen(_context->currToken->tokenString) > 1)
if (_context->currToken->tokenString[1] == '0')
if ((_context->currToken->tokenString[2] == 'x') || (_context->currToken->tokenString[2] == 'X'))
return false;

return true;
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (ディレクティブ)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateDir()
{
_context->State = "ディレクティブ";
_context->nextToken->tokenKind = "ディレクティブ";

// 各派生クラスで処理する
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新 (日付)
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReaderCommon::getNextStateDtm()
{
_context->State = "日付";
_context->nextToken->tokenKind = "文字列";

// 各派生クラスで処理する (VBだけ)
}