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

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

TokenReader.h


#pragma once

#include ".\reader.h"
#include ".\token.h"
#include ".\context.h"

namespace SourceToHtml
{
using namespace System;
//*******************************************************************************************************
// トークンごとに その種類と、内容を返す
//*******************************************************************************************************
public __gc class TokenReader
{
private:
const Char EOF; // '\0'
const Char NEWLINE; // '\n'
const Char TAB; // '\t'
const Char BLANK; // ' '

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

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

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

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

public:
// ファクトリー
static TokenReader* Create(Reader* reader, String* langType);
// 終了
~TokenReader();
// トークンごとに その種類と、内容を返す
Token* getToken();
};
}

TokenReader.cpp


#include "StdAfx.h"
#include ".\TokenReader.h"
#include ".\TokenReaderCSharp.h"
#include ".\TokenReaderVB.h"
#include ".\TokenReaderDelphi.h"
#include ".\TokenReaderPlsql.h"
#include ".\TokenReaderTsql.h"

namespace SourceToHtml
{
//*******************************************************************************************************
// トークンごとに その種類と、内容を返す
//*******************************************************************************************************
//-------------------------------------------------------------------------------------------------------
// ファクトリー
//-------------------------------------------------------------------------------------------------------
TokenReader* TokenReader::Create(Reader* reader, String* langType)
{
if (langType->Equals("cs7")) return new TokenReaderCSharp(reader, langType); // VC#.NET
else if (langType->Equals("vc6")) return new TokenReaderCase(reader, langType); // VC++
else if (langType->Equals("vc7")) return new TokenReaderCase(reader, langType); // VC++.NET
else if (langType->Equals("java")) return new TokenReaderCase(reader, langType); // VJ++, VJ#.NET, Java
else if (langType->Equals("js")) return new TokenReaderCase(reader, langType); // JavaScript
else if (langType->Equals("bcb")) return new TokenReaderCase(reader, langType); // C++Builder
else if (langType->Equals("vb6")) return new TokenReaderVB(reader, langType); // VB
else if (langType->Equals("vb7")) return new TokenReaderVB(reader, langType); // VB.NET
else if (langType->Equals("del")) return new TokenReaderDelphi(reader, langType); // Delphi
else if (langType->Equals("psq")) return new TokenReaderPlsql(reader, langType); // PL/SQL
else if (langType->Equals("tsq")) return new TokenReaderTsql(reader, langType); // T-SQL
else return new TokenReader(reader, langType); // other
}
//-------------------------------------------------------------------------------------------------------
// 初期化
//-------------------------------------------------------------------------------------------------------
TokenReader::TokenReader(Reader* reader, String* langType):EOF('\0'), NEWLINE('\n'), TAB('\t'), BLANK(' ')
{
//入力用クラス
_reader = reader;

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

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

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

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

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

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

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

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

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

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

//文字種が変わっても、取得した文字が空っぽなら 何もしない
if (_context->nextToken->tokenString->Length < 1) 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 == EOF) _context->currToken = NULL;
}
//-------------------------------------------------------------------------------------------------------
// 文字を取得・状態を更新
//-------------------------------------------------------------------------------------------------------
void TokenReader::getNextToken()
{
_context->nextToken->tokenKind = S"その他";
_context->nextToken->tokenString = Char::ToString(_context->currChar);
}
//-------------------------------------------------------------------------------------------------------
// 文字種が変わったら、変わる前の文字列情報を返す
//-------------------------------------------------------------------------------------------------------
Token* TokenReader::getPrevToken()
{
//確定済みでなければ 何もしない
if (!_context->prevToken->IsFixed) return NULL;

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

//1つ前のトークンを返す
return _context->prevToken;
}
//-------------------------------------------------------------------------------------------------------
// 現在位置が、TAB 位置かどうかを返す
//-------------------------------------------------------------------------------------------------------
bool TokenReader::TabPos(int col)
{
return ((col % 4) == 0);
}
//-------------------------------------------------------------------------------------------------------
// 取得した文字のByte数を返す
//-------------------------------------------------------------------------------------------------------
int TokenReader::getLength(Char c)
{
System::Text::Encoding* sjis = System::Text::Encoding::GetEncoding("shift-jis");
return sjis->GetByteCount(Char::ToString(c));
}
}