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

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

TokenReader.vb


'*******************************************************************************************************
' トークンごとに その種類と、内容を返す
'*******************************************************************************************************
Public Class TokenReader
'入力用クラス
Private _reader As Reader

'文脈情報 クラス (前後のトークン、前後の文字を保持しておく)
Protected _context As Context = Nothing

Protected Const EOF As Char = ControlChars.NullChar
Protected Const NEWLINE As Char = ControlChars.Cr
Protected Const TAB As Char = ControlChars.Tab
Protected Const BLANK As Char = " "c
Private _col As Integer = 0 '現在位置を保持
'---------------------------------------------------------------------------------------------------
' ファクトリー
'---------------------------------------------------------------------------------------------------
Public Shared Function Create(ByVal aReader As Reader, ByVal langType As String) As TokenReader
Select Case langType
Case "cs7" : Return New TokenReaderCSharp(aReader, langType) ' VC#.NET
Case "vc6" : Return New TokenReaderCase(aReader, langType) ' VC++
Case "vc7" : Return New TokenReaderCase(aReader, langType) ' VC++.NET
Case "java" : Return New TokenReaderCase(aReader, langType) ' VJ++, VJ#.NET, Java
Case "js" : Return New TokenReaderCase(aReader, langType) ' JavaScript
Case "bcb" : Return New TokenReaderCase(aReader, langType) ' C++Builder
Case "vb6" : Return New TokenReaderVB(aReader, langType) ' VB
Case "vb7" : Return New TokenReaderVB(aReader, langType) ' VB.NET
Case "del" : Return New TokenReaderDelphi(aReader, langType) ' Delphi
Case "psq" : Return New TokenReaderPlsql(aReader, langType) ' PL/SQL
Case "tsq" : Return New TokenReaderTsql(aReader, langType) ' T-SQL
Case Else : Return New TokenReader(aReader, langType) ' other
End Select
End Function
'---------------------------------------------------------------------------------------------------
' 初期化
'---------------------------------------------------------------------------------------------------
Protected Sub New(ByVal aReader As Reader, ByVal langType As String)
'入力用クラス
_reader = aReader

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

'文字を取得 (1つ先読みする)
_context.nextChar = _reader.getChar()
End Sub
'---------------------------------------------------------------------------------------------------
' 終了
'---------------------------------------------------------------------------------------------------
Protected Overrides Sub Finalize()
_reader = Nothing
_context = Nothing
End Sub
'---------------------------------------------------------------------------------------------------
' トークンごとに その種類と、内容を返す
'---------------------------------------------------------------------------------------------------
Public Function getToken() As Token
'ファイルの終わりまで、1文字ずつ読む
Do
'文字を取得 (1つ先読みする)
_context.prevChar = _context.currChar '現在の文字を、前の文字に複写
_context.currChar = _context.nextChar '次の文字を、現在の文字に複写
_context.nextChar = _reader.getChar() '次の文字を先読み

If (_context.currChar = TAB) Then 'TAB文字なら
_context.currChar = BLANK '空白に置換
Do
addToken() 'TAB位置まで空白で埋める
_col += 1
Loop While (Not TabPos(_col)) 'TAB位置まで進んだら抜ける
Else
If (_context.currChar = BLANK) Then '空白なら
_col += 1 '現在位置を1つ進める

ElseIf (_context.currChar = NEWLINE) Then '改行コードなら
_col = 0 '現在位置をクリア

ElseIf (_context.currChar <> EOF) Then 'TABでも 改行コードでも 空白でも なければ
_col += getLength(_context.currChar) '現在位置を文字幅だけ進める
End If

addToken() '読み込み文字列に追加
End If
'文字種が変わったら、変わる前のトークンを返す
Dim myToken As Token = getPrevToken()
If Not (myToken Is Nothing) Then Return myToken
Loop While(_context.currChar <> EOF)

Return Nothing
End Function
'---------------------------------------------------------------------------------------------------
' 読み込んだ文字を トークンに追加
'---------------------------------------------------------------------------------------------------
Private Sub addToken()
'未確定トークン がクリアされていれば、ファイルの終わり
If (_context.currToken Is Nothing) Then Return

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

'文字種が変わってなかったら、未確定トークンに 取得した文字を 追加
If ((_context.nextToken.tokenKind = _context.currToken.tokenKind) AndAlso (_context.currChar <> EOF)) Then
_context.currToken.tokenString += _context.nextToken.tokenString
Return
End If

'文字種が変わっても、取得した文字が空っぽなら 何もしない
If (_context.nextToken.tokenString.Length < 1) Then 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) Then _context.currToken = Nothing
End Sub
'---------------------------------------------------------------------------------------------------
' 文字を取得・状態を更新
'---------------------------------------------------------------------------------------------------
Protected Overridable Sub getNextToken()
_context.nextToken.tokenKind = "その他"
_context.nextToken.tokenString = _context.currChar.ToString()
End Sub
'---------------------------------------------------------------------------------------------------
' 文字種が変わったら、変わる前の文字列情報を返す
'---------------------------------------------------------------------------------------------------
Private Function getPrevToken() As Token
'確定済みでなければ 何もしない
If (Not _context.prevToken.IsFixed) Then Return Nothing

'1つ前のトークンを未確定状態にして
_context.prevToken.IsFixed = False

'1つ前のトークンを返す
Return _context.prevToken
End Function
'---------------------------------------------------------------------------------------------------
' 現在位置が、TAB 位置かどうかを返す
'---------------------------------------------------------------------------------------------------
Private Function TabPos(ByVal col As Integer) As Boolean
Return ((col Mod 4) = 0)
End Function
'---------------------------------------------------------------------------------------------------
' 取得した文字のByte数を返す
'---------------------------------------------------------------------------------------------------
Private Function getLength(ByVal c As Char) As Integer
Dim sjis As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")
Return sjis.GetByteCount(c.ToString())
End Function
End Class