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

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

TokenReaderCommon.h


#pragma once

#include ".\TokenReader.h"

namespace SourceToHtml
{
using namespace System;
//*******************************************************************************************************
// トークンごとに 文字列と その種類を返す ( 共通 )
//*******************************************************************************************************
public __gc class TokenReaderCommon : public TokenReader
{
private:
// 予約語 コレクションを設定
void initKeyWord(String* langType);
// 演算子 コレクションを設定
void initOperator(String* langType);
// 状態を更新 (その他・区切り記号・不明)
void getNextStateOther();

protected:
//予約語 コレクション
System::Collections::Specialized::StringCollection* _keyWords;
//演算子 コレクション
String* _operators;

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

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

public:
// 初期化
TokenReaderCommon(Reader* reader, String* langType);
// 終了
~TokenReaderCommon();
};
}

TokenReaderCommon.cpp


#include "StdAfx.h"
#include ".\TokenReaderCommon.h"

namespace SourceToHtml
{
//*******************************************************************************************************
// トークンごとに 文字列と その種類を返す ( 共通 )
//*******************************************************************************************************
//-------------------------------------------------------------------------------------------------------
// 初期化
//-------------------------------------------------------------------------------------------------------
TokenReaderCommon::TokenReaderCommon(Reader* reader, String* langType):TokenReader(reader, langType)
{
//予約語 コレクションを設定
initKeyWord(langType);

//演算子 コレクションを設定
initOperator(langType);
}
//-------------------------------------------------------------------------------------------------------
// 終了
//-------------------------------------------------------------------------------------------------------
TokenReaderCommon::~TokenReaderCommon()
{
_keyWords = NULL;
}
//-------------------------------------------------------------------------------------------------------
// 予約語 コレクションを設定
//-------------------------------------------------------------------------------------------------------
void TokenReaderCommon::initKeyWord(String* langType)
{
//予約語 コレクションを設定 (".\cs7\key.txt")
_keyWords = new System::Collections::Specialized::StringCollection();

//予約語ファイルがなければ、予約語コレクションは空っぽ
if (System::IO::File::Exists(String::Concat(System::Windows::Forms::Application::StartupPath, S"\\", langType, S"\\key.txt")))
{
System::IO::StreamReader* keyReader = new System::IO::StreamReader(String::Concat(System::Windows::Forms::Application::StartupPath, S"\\", langType, S"\\key.txt"), System::Text::Encoding::GetEncoding(S"Shift_JIS"));
String* s;
while ((s = keyReader->ReadLine()) != NULL)
{
_keyWords->Add(s);
}
keyReader->Close();
keyReader = NULL;
}
}
//-------------------------------------------------------------------------------------------------------
// 演算子 コレクションを設定
//-------------------------------------------------------------------------------------------------------
void TokenReaderCommon::initOperator(String* langType)
{
_operators = S"";

//演算子ファイルがなければ、演算子コレクションは空っぽ
if (System::IO::File::Exists(String::Concat(System::Windows::Forms::Application::StartupPath, S"\\", langType, S"\\ope.txt")))
{
System::IO::StreamReader* opeReader = new System::IO::StreamReader(String::Concat(System::Windows::Forms::Application::StartupPath, S"\\", langType, S"\\ope.txt"), System::Text::Encoding::GetEncoding(S"Shift_JIS"));
String* s;
while ((s = opeReader->ReadLine()) != NULL)
{
_operators = String::Concat(_operators, s);
}
opeReader->Close();
opeReader = NULL;
}
}
//-------------------------------------------------------------------------------------------------------
// 状態を更新
//-------------------------------------------------------------------------------------------------------
void TokenReaderCommon::getNextToken()
{
TokenReader::getNextToken();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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