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

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

TokenReaderCommon.pas


//*******************************************************************************************************
// トークンごとに 文字列と その種類を返す ( 共通 )
//*******************************************************************************************************
unit TokenReaderCommon;

interface
uses
SysUtils, Forms, Classes, TextReader, TokenReader;

type
TTokenReaderCommon = class(TTokenReader)
private
procedure initKeyWord(langType:string);
procedure initOperator(langType:string);
procedure getNextStateOther();

protected
//予約語 コレクション
_keyWords: TStringList;

//演算子 コレクション
_operators: string;

procedure getNextToken(); override;
function IsComSingle(): Boolean; virtual;
function IsComMulti(): Boolean; virtual;
function IsString(): Boolean; virtual;
function IsChar(): Boolean; virtual;
function IsLiteral(): Boolean; virtual;
function IsDirective(): Boolean; virtual;
function IsIdent(): Boolean; virtual;
function IsEscape(): Boolean; virtual;
function IsNumber(): Boolean; virtual;
function IsOperator(): Boolean; virtual;
function IsDelim(): Boolean; virtual;
function IsDate(): Boolean; virtual;
procedure getNextStateComSin(); virtual;
procedure getNextStateComMul(); virtual;
procedure getNextStateStr(); virtual;
procedure getNextStateStrEsc(); virtual;
procedure getNextStateStrLit(); virtual;
procedure getNextStateCha(); virtual;
procedure getNextStateChaEsc(); virtual;
procedure getNextStateIdw(); virtual;
function getKeyWord(): WideString; virtual;
procedure getNextStateIdwEsc(); virtual;
procedure getNextStateNum(); virtual;
function IsNotHex(): Boolean; virtual;
procedure getNextStateDir(); virtual;
procedure getNextStateDtm(); virtual;
public
constructor Create(reader:TTextReader; langType:string);override;
destructor Destroy; override;
end;

implementation
//---------------------------------------------------------------------------------------------------
// 初期化
//---------------------------------------------------------------------------------------------------
constructor TTokenReaderCommon.Create(reader:TTextReader; langType:string);
begin
inherited Create(reader, langType);

//予約語 コレクションを設定
initKeyWord(langType);

//演算子 コレクションを設定
initOperator(langType);
end;
//----------------------------------------------------------------------------------------------------
// 終了
//----------------------------------------------------------------------------------------------------
destructor TTokenReaderCommon.Destroy();
begin
_keyWords.Free;
_keyWords := nil;

inherited;
end;
//---------------------------------------------------------------------------------------------------
// 予約語 コレクションを設定
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.initKeyWord(langType:string);
var
fileName: string;
s: WideString;
begin
//予約語 コレクションを設定 ('.\cs7\key.txt')
_keyWords := TStringList.Create();

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

_keyWords.CaseSensitive := true;
end;
//---------------------------------------------------------------------------------------------------
// 演算子 コレクションを設定
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.initOperator(langType:string);
var
textReader: TStringList;
fileName: string;
s: WideString;
begin
_operators := '';
textReader := TStringList.Create();

//演算子ファイルがなければ、演算子コレクションは空っぽ
fileName := ExtractFilePath(Application.ExeName) + langType + '\ope.txt';
if SysUtils.FileExists(fileName) then
begin
textReader.LoadFromFile(fileName);
_operators := textReader[0];
textReader.Free;
end;
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextToken();
begin
inherited getNextToken();

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

until(_context.State <> '不明');
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (その他・区切り記号・不明)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateOther();
begin
_context.State := 'その他';
_context.nextToken.tokenKind := 'その他';

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

// トークンの種類を取得
if (_context.State = '逐語的文字列') then _context.nextToken.tokenKind := '文字列'
else if (_context.State = 'エスケープされた識別子') then _context.nextToken.tokenKind := '識別子'
else if (_context.State = '単一行コメント') then _context.nextToken.tokenKind := 'コメント'
else if (_context.State = '複数行コメント') then _context.nextToken.tokenKind := 'コメント'
else if (_context.State = '日付') then _context.nextToken.tokenKind := '文字列'
else _context.nextToken.tokenKind := _context.State;
end;
//---------------------------------------------------------------------------------------------------
// 単一行コメントか?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsComSingle():Boolean;
begin
result := ((_context.currChar = '/') and (_context.nextChar = '/'));
end;
//---------------------------------------------------------------------------------------------------
// 複数行コメントか?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsComMulti():Boolean;
begin
result := ((_context.currChar = '/') and (_context.nextChar = '*'));
end;
//---------------------------------------------------------------------------------------------------
// 文字列か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsString():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 文字か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsChar():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 逐語的文字列か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsLiteral():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// ディレクティブか?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsDirective():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 識別子か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsIdent():Boolean;
begin
result := (IsLetter(_context.currChar) or (_context.currChar = '_'));
end;
//---------------------------------------------------------------------------------------------------
// エスケープされた識別子か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsEscape():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 数字か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsNumber():Boolean;
begin
result := (IsDigit(_context.currChar));
end;
//---------------------------------------------------------------------------------------------------
// 演算子か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsOperator():Boolean;
begin
result := false;

if (IsSymbol(_context.currChar)) then
begin
if (pos(_operators, _context.currChar) >= 0) then result := true;
end;
end;
//---------------------------------------------------------------------------------------------------
// 区切り記号か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsDelim():Boolean;
begin
result := false;

if (IsSymbol(_context.currChar)) then
begin
if (pos(_operators, _context.currChar) < 0) then result := true;
end;
end;
//---------------------------------------------------------------------------------------------------
// 日付か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsDate():Boolean;
begin
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (単一行コメント)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateComSin();
begin
_context.State := '単一行コメント';
_context.nextToken.tokenKind := 'コメント';

if (_context.currChar = #13) then
begin
_context.State := 'その他';
_context.nextToken.tokenKind := 'その他';
end;
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (複数行コメント)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateComMul();
begin
_context.State := '複数行コメント';
_context.nextToken.tokenKind := 'コメント';

if ((_context.prevChar = '*')
and (_context.currChar = '/')) then
_context.State := 'その他';
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (文字列)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateStr();
begin
_context.State := '文字列';
_context.nextToken.tokenKind := '文字列';

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

// 各派生クラスで処理する
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (文字)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateCha();
begin
_context.State := '文字';
_context.nextToken.tokenKind := '文字';

// 各派生クラスで処理する
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (文字中のエスケープシーケンス)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateChaEsc();
begin
_context.State := '文字';
_context.nextToken.tokenKind := '文字';
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (識別子)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateIdw();
var
keyWord:WideString;
begin
_context.State := '識別子';
_context.nextToken.tokenKind := '識別子';

if (not IsLetter(_context.currChar) and not IsDigit(_context.currChar) and (_context.currChar <> '_')) then
begin
_context.State := '不明';

//文字種が変わったら、識別子が 予約語ではないか 確認する
keyWord := getKeyWord();
if (keyWord <> '') then
begin
_context.currToken.tokenKind := '予約語';
_context.currToken.tokenString := keyWord;
end;
end;
end;
//---------------------------------------------------------------------------------------------------
// 予約語ではないか?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.getKeyWord():WideString;
begin
result := '';
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (エスケープされた識別子)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateIdwEsc();
begin
_context.State := 'エスケープされた識別子';
_context.nextToken.tokenKind := '識別子';

// 各派生クラスで処理する
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (数字)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateNum();
begin
_context.State := '数字';
_context.nextToken.tokenKind := '数字';

if ((_context.currChar = '.') and (_context.nextChar = '.')) then
_context.State := '不明'

else if (not IsLetter(_context.currChar) and not IsDigit(_context.currChar) and (_context.currChar <> '.')) then
begin
_context.State := '不明';

// '+' か '-' で
if ((_context.currChar = '+') or (_context.currChar = '-')) then
begin
//1つ前の文字が 'e' か 'E' で
if ((_context.prevChar = 'e') or (_context.prevChar = 'E')) then
begin
//16進表記でなければ、数字
if (IsNotHex()) then
_context.State := '数字';
end;
end;
end;
end;
//---------------------------------------------------------------------------------------------------
// 16進表記か?
//---------------------------------------------------------------------------------------------------
function TTokenReaderCommon.IsNotHex():Boolean;
begin
result := true;

// 0x で始まっていたら、16進
if (Length(_context.currToken.tokenString) > 1) then
if (_context.currToken.tokenString[1] = '0') then
if ((_context.currToken.tokenString[2] = 'x') or (_context.currToken.tokenString[2] = 'X')) then
result := false;
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (ディレクティブ)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateDir();
begin
_context.State := 'ディレクティブ';
_context.nextToken.tokenKind := 'ディレクティブ';

// 各派生クラスで処理する
end;
//---------------------------------------------------------------------------------------------------
// 状態を更新 (日付)
//---------------------------------------------------------------------------------------------------
procedure TTokenReaderCommon.getNextStateDtm();
begin
_context.State := '日付';
_context.nextToken.tokenKind := '文字列';

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

end.