トークン読み込み用クラス

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

TokenReader.h


//*******************************************************************************************************
// トークンごとに その種類と、内容を返す
//*******************************************************************************************************
#ifndef TokenReaderH
#define TokenReaderH
//---------------------------------------------------------------------------
#include "TextReader.h"
#include "Token.h"
#include "TokenContext.h"
//---------------------------------------------------------------------------
class TTokenReader
{
private:
const wchar_t C_EOF; // '\0'
const wchar_t C_NEWLINE; // '\n'
const wchar_t C_TAB; // '\t'
const wchar_t C_BLANK; // ' '

const WideString C_LETTERS; // 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const WideString C_DIGITS; // '0123456789';
const WideString C_SYMBOLS; // '!"#$%&''()*+,-./:;<=>?@[\]^`{|}~';

//現在位置を保持
int _col;

//入力用クラス
TTextReader* _reader;

// 読み込んだ文字を トークンに追加
void __fastcall addToken();
// 文字種が変わったら、変わる前の文字列情報を返す
TToken* __fastcall getPrevToken();
// 現在位置が、TAB 位置かどうかを返す
bool __fastcall TabPos(int col);
// 取得した文字のByte数を返す
int __fastcall getLength(wchar_t c);

protected:
//文脈情報 クラス (前後のトークン、前後の文字を保持しておく)
TTokenContext* _context;
// 初期化
__fastcall TTokenReader(TTextReader* reader, AnsiString langType);
// 文字を取得・状態を更新
virtual void __fastcall getNextToken();

bool __fastcall IsLetter(wchar_t c);
bool __fastcall IsDigit(wchar_t c);
bool __fastcall IsSymbol(wchar_t c);

public:
// ファクトリー
static TTokenReader* __fastcall Create(TTextReader* reader, AnsiString langType);
// 終了
__fastcall ~TTokenReader();
// トークンごとに その種類と、内容を返す
TToken* __fastcall getToken();
};
#endif

TokenReader.cpp


//*******************************************************************************************************
// トークンごとに その種類と、内容を返す
//*******************************************************************************************************
#pragma hdrstop
#include "TokenReader.h"
#include "TokenReaderCase.h"
#include "TokenReaderCSharp.h"
#include "TokenReaderVB.h"
#include "TokenReaderDelphi.h"
#include "TokenReaderPlsql.h"
#include "TokenReaderTsql.h"
//-------------------------------------------------------------------------------------------------------
#pragma package(smart_init)
//-------------------------------------------------------------------------------------------------------
// ファクトリー
//-------------------------------------------------------------------------------------------------------
TTokenReader* __fastcall TTokenReader::Create(TTextReader* reader, AnsiString langType)
{
if (langType == "cs7") return new TTokenReaderCSharp(reader, langType); // VC#.NET
else if (langType == "vc6") return new TTokenReaderCase(reader, langType); // VC++
else if (langType == "vc7") return new TTokenReaderCase(reader, langType); // VC++.NET
else if (langType == "java") return new TTokenReaderCase(reader, langType); // VJ++, VJ#.NET, Java
else if (langType == "js") return new TTokenReaderCase(reader, langType); // JavaScript
else if (langType == "bcb") return new TTokenReaderCase(reader, langType); // C++Builder
else if (langType == "vb6") return new TTokenReaderVB(reader, langType); // VB
else if (langType == "vb7") return new TTokenReaderVB(reader, langType); // VB.NET
else if (langType == "del") return new TTokenReaderDelphi(reader, langType); // Delphi
else if (langType == "psq") return new TTokenReaderPlsql(reader, langType); // PL/SQL
else if (langType == "tsq") return new TTokenReaderTsql(reader, langType); // T-SQL
else return new TTokenReader(reader, langType); // other
}
//-------------------------------------------------------------------------------------------------------
// 初期化
//-------------------------------------------------------------------------------------------------------
__fastcall TTokenReader::TTokenReader(TTextReader* reader, AnsiString langType):
C_EOF(L'\0'),
C_NEWLINE(L'\n'),
C_TAB(L'\t'),
C_BLANK(L' '),
C_LETTERS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
C_DIGITS("0123456789"),
C_SYMBOLS("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~")
{
//入力用クラス
_reader = reader;

//文脈情報 クラス (前後のトークン、前後の文字を保持しておく)
_context = new TTokenContext();

//文字を取得 (1つ先読みする)
_context->nextChar = _reader->getChar();

//現在位置を保持
_col = 0;
}
//-------------------------------------------------------------------------------------------------------
// 終了
//-------------------------------------------------------------------------------------------------------
__fastcall TTokenReader::~TTokenReader()
{
delete _context;

_reader = NULL;
_context = NULL;
}
//-------------------------------------------------------------------------------------------------------
// トークンごとに その種類と、内容を返す
//-------------------------------------------------------------------------------------------------------
TToken* __fastcall TTokenReader::getToken()
{
//ファイルの終わりまで、1文字ずつ読む
do
{
//文字を取得 (1つ先読みする)
_context->prevChar = _context->currChar; //現在の文字を、前の文字に複写
_context->currChar = _context->nextChar; //次の文字を、現在の文字に複写
_context->nextChar = _reader->getChar(); //次の文字を先読み

if (_context->currChar == C_TAB) //TAB文字なら
{
_context->currChar = C_BLANK; //空白に置換
do
{
addToken(); //TAB位置まで空白で埋める
}
while (!TabPos(++_col)); //TAB位置まで進んだら抜ける
}
else
{
if (_context->currChar == C_BLANK) //空白なら
_col++; //現在位置を1つ進める

else if (_context->currChar == C_NEWLINE) //改行コードなら
_col = 0; //現在位置をクリア

else if (_context->currChar != C_EOF) //TABでも 改行コードでも 空白でも なければ
_col += getLength(_context->currChar); //現在位置を文字幅だけ進める

addToken(); //読み込み文字列に追加
}
//文字種が変わったら、変わる前のトークンを返す
TToken* token;
if ((token = getPrevToken()) != NULL) return token;
}
while(_context->currChar != C_EOF);

return NULL;
}
//-------------------------------------------------------------------------------------------------------
// 読み込んだ文字を トークンに追加
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReader::addToken()
{
//未確定トークン がクリアされていれば、ファイルの終わり
if (_context->currToken == NULL) return;

//読み込んだ文字の種類を取得、状態を更新 (nextToken にセットする)
getNextToken();

//文字種が変わってなかったら、未確定トークンに 取得した文字を 追加
if ((_context->nextToken->tokenKind == _context->currToken->tokenKind) && (_context->currChar != C_EOF))
{
_context->currToken->tokenString += _context->nextToken->tokenString;
return;
}

//文字種が変わっても、取得した文字が空っぽなら 何もしない
if ((wcslen(_context->nextToken->tokenString) < 1) && (_context->currChar != C_EOF))return;

//文字種が変わったら、確定済みトークン に、未確定トークン を Copy
_context->prevToken->tokenKind = _context->currToken->tokenKind;
_context->prevToken->tokenString = _context->currToken->tokenString;
_context->prevToken->IsFixed = true;

//未確定トークン に、新しいトークン を Copy
_context->currToken->tokenKind = _context->nextToken->tokenKind;
_context->currToken->tokenString = _context->nextToken->tokenString;

//ファイルの終わりに達したら、未確定トークン をクリア
if (_context->currChar == C_EOF) _context->currToken = NULL;
}
//-------------------------------------------------------------------------------------------------------
// 文字を取得・状態を更新
//-------------------------------------------------------------------------------------------------------
void __fastcall TTokenReader::getNextToken()
{
_context->nextToken->tokenKind = "その他";
_context->nextToken->tokenString = WideString(_context->currChar);
}
//-------------------------------------------------------------------------------------------------------
// 文字種が変わったら、変わる前の文字列情報を返す
//-------------------------------------------------------------------------------------------------------
TToken* __fastcall TTokenReader::getPrevToken()
{
//確定済みでなければ 何もしない
if (!_context->prevToken->IsFixed) return NULL;

//1つ前のトークンを未確定状態にして
_context->prevToken->IsFixed = false;

//1つ前のトークンを返す
return _context->prevToken;
}
//-------------------------------------------------------------------------------------------------------
// 現在位置が、TAB 位置かどうかを返す
//-------------------------------------------------------------------------------------------------------
bool __fastcall TTokenReader::TabPos(int col)
{
return ((col % 4) == 0);
}
//-------------------------------------------------------------------------------------------------------
// 取得した文字のByte数を返す
//-------------------------------------------------------------------------------------------------------
int __fastcall TTokenReader::getLength(wchar_t c)
{
AnsiString s = WideString(c);
return s.Length();
}
//---------------------------------------------------------------------------------------------------
// 英字か?
//---------------------------------------------------------------------------------------------------
bool __fastcall TTokenReader::IsLetter(wchar_t c)
{
return (C_LETTERS.Pos(WideString(c)) > 0);
}
//---------------------------------------------------------------------------------------------------
// 数字か?
//---------------------------------------------------------------------------------------------------
bool __fastcall TTokenReader::IsDigit(wchar_t c)
{
return (C_DIGITS.Pos(WideString(c)) > 0);
}
//---------------------------------------------------------------------------------------------------
// 記号か?
//---------------------------------------------------------------------------------------------------
bool __fastcall TTokenReader::IsSymbol(wchar_t c)
{
return (C_SYMBOLS.Pos(WideString(c)) > 0);
}