/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2008/X/X - 2015/11/11
/// 
/// @brief  字句解析関連
/// 
/// ****************************************************************************



#include "CPL_Core_LexicalAnalysis.h"
#include "../String/CPL_Core_String.h"


namespace CPL {
namespace Core {

// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @param[in] in_ptr_string
///   : 解析する文字列が格納されたバッファへのアドレスを指定します。
/// @param[in] in_size_buf
///   : 文字列バッファのサイズを指定します。\n
///   : null終端文字列の場合-1を指定することで、null終端までサーチします。
/// @param[in] in_char_code
///   : 扱う文字コードの識別フラグをCPL::Core::CharCode型で指定します。\n
///   : 現在対応しているのはUTF8およびSJISのみです。
/// @param[in] in_flag_error_throw
///   : このオブジェクトが、後にトークンの取得等に失敗した場合、戻り値を返すか
///     例外を投げるかどうかを設定します。\n
///   : 例外を投げる場合、CPL::Core::Exception<std::exception>が投げられます。\n
///   : この引数は省略可能で、省略するとfalseが指定されたものとみなします。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tokenizer::Tokenizer
( pin<char     > in_ptr_string
, _in<size_t   > in_size_buf
, _in<eCharCode> in_char_code
, _in<bool     > in_flag_error_throw
) : m_token_key       ( kStrMaxSize, 0 )
  //, m_str_original    { in_ptr_string }
  , m_char_code       { in_char_code }
  , m_flag_error_throw{ in_flag_error_throw }
{
  if( in_size_buf == -1 )
  {
    m_str_original = in_ptr_string;
  }
  else
  {
    m_str_original.resize( in_size_buf );
    memcpy( &m_str_original[0], in_ptr_string, in_size_buf );
  }

  m_addr_pos = &m_str_original[0];
  m_addr_end = &m_str_original[ m_str_original.length() ];

  static std::vector<TokenKey> key_def_utf8 ( kStrMaxSize );
  static std::vector<TokenKey> key_def_utf16( kStrMaxSize );
  static std::vector<TokenKey> key_def_sjis ( kStrMaxSize );

  CPL_BLOCK_ONCE
  {
    for( size_t i = 0; i < 128; ++i )
    {
      key_def_utf8 [ i ] = static_cast<U32>(i);
      key_def_utf16[ i ] = static_cast<U32>(i);
      key_def_sjis [ i ] = static_cast<U32>(i);
    }
    for( size_t i = 128; i < kStrMaxSize; ++i )
    {
      key_def_utf8 [ i ] = Token::eKey::NotAscii;
      key_def_utf16[ i ] = Token::eKey::NotAscii;
      key_def_sjis [ i ] = Token::eKey::NotAscii;
    }
  }

  switch( in_char_code )
  {
  case eCharCode::UTF8:  m_token_key = key_def_utf8;  break;
  case eCharCode::UTF16: m_token_key = key_def_utf16; break;
  case eCharCode::SJIS:  m_token_key = key_def_sjis;  break;
  }
}



// _____________________________________________________________________________
/// @brief トークンキーの設定。
/// 
/// @param[in] in_C : 設定する文字の先頭アドレスを指定します。
/// @param[in] in_token_key
///   : 設定するトークンキーを指定します。\n
///   : デフォルト値(-1)を指定すると、文字コードインデックスがキーとして設定されます。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::SetTokenKey( pin<char> in_C, int in_token_key )
{
  int idx = 0, size;
  switch( m_char_code )
  {
  case eCharCode::SJIS:
    idx = GetCharIndex_SJIS( (char_cptr)in_C, size );
    break;

  case eCharCode::UTF16:
    idx = GetCharIndex_UTF16( (wchar_t_cptr)in_C, size );
    break;

  case eCharCode::UTF8:
    idx = GetCharIndex_UTF8( (char_cptr)in_C, size );
    break;

  }

  if( in_token_key == -1 )
  {
    m_token_key[ idx ] = idx;
  }
  else
  {
    m_token_key[ idx ] = in_token_key;
  }
}


// _____________________________________________________________________________
/// @brief トークンキー列の設定。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::SetTokenKeyList( pin<char> c_tbl, int set )
{
  int    byte = 1 + (m_char_code == eCharCode::UTF16);
  size_t len = 0;
  auto*  p = c_tbl;
  
  if( m_char_code == eCharCode::UTF16 )
  {
    len = Core::StringW::str_len_( reinterpret_cast<wchar_t_cptr>(c_tbl) );
  }
  else
  {
    len = Core::StringA::str_len_( c_tbl );
  }

  for( decltype(len) i = 0; i < len; ++i )
  {
    SetTokenKey( p, set );
    p += byte;
  }
}


// _____________________________________________________________________________
/// @brief ブロックコメントの識別子の登録
/// 
/// @param[in] in_str_begin : 開始識別文字列を指定します。
/// @param[in] in_str_end   : 終了識別文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::SetCommentBlock( pin<char> in_str_begin, pin<char> in_str_end )
{
  m_comment_block.push_back( BlockPair{in_str_begin, in_str_end} );
}


// _____________________________________________________________________________
/// @brief 行コメントの識別子の登録
/// 
/// @param[in] in_str_comment : 行コメント識別文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::SetCommentLine( pin<char> in_str_comment )
{
  m_comment_block.push_back( BlockPair{in_str_comment, ""} );
}


// _____________________________________________________________________________
/// @brief 文字列として扱う識別子の登録
/// 
/// @param[in] in_str_begin : 開始識別文字列を指定します。
/// @param[in] in_str_end   : 終了識別文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::SetStringBlock( pin<char> in_str_begin, pin<char> in_str_end )
{
  m_string_block.push_back( BlockPair(in_str_begin,in_str_end ) );
}

// _____________________________________________________________________________
/// @brief トークン用キーのデフォルト初期化（C言語仕様）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::InitTokenKey_for_C()
{
	SetTokenKeyList
    ( " \a\b\f\t\v\r"
    , Token::eKey::Space // スペースおよび、これらエスケープシーケンスはスペースと同じ扱いとする。
    );
  SetTokenKey( '\n', Token::eKey::NewLine );
	//SetTokenKey( ';' );
	//SetTokenKey( ':' );
	//SetTokenKey( ',' );
	//SetTokenKey( '(' );
	//SetTokenKey( ')' );
	//SetTokenKey( '[' );
	//SetTokenKey( ']' );
	//SetTokenKey( '{' );
	//SetTokenKey( '}' );
	//SetTokenKey( '#' );
	//SetTokenKey( '!' );
	//SetTokenKey( '^' );
	//SetTokenKey( '~' );
	//SetTokenKey( '|' );
	//SetTokenKey( '%' );
	//SetTokenKey( '&' );
	//SetTokenKey( '<' );
	//SetTokenKey( '>' );
	//SetTokenKey( '?' );
	//SetTokenKey( '=' );
	//SetTokenKey( '+' );
	//SetTokenKey( '-' );
	//SetTokenKey( '*' );
	//SetTokenKey( '/' );
	//SetTokenKey( '.' );
	//SetTokenKey( '$' );
	//SetTokenKey( '"' );
	//SetTokenKey( '\'' );
	//SetTokenKey( '\\' );
	//SetTokenKey( '@' );
	// アルファベット
	SetTokenKeyList
    ( "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    , Token::eKey::Word
    );
	// 数値
	SetTokenKeyList( "0123456789", Token::eKey::Number );

	// コメントシグネチャを設定。
  ReleaseBlock_for_Comment();
  SetCommentBlock( "/*","*/" );
	SetCommentLine( "//" );

  // 文字列シグネチャを設定。
  ReleaseBlock_for_String();
  SetStringBlock( "\"", "\"" );

  //// マルチバイト文字用。
  //// 原則として、最上位ビットがONの場合はマルチバイトとして扱う。
  //for( int i = 0x80; i <= 0xFF; ++i )
  //{
  //  SetTokenKey( i, Token::eKey::MultiByte );
  //}
}

// _____________________________________________________________________________
/// @brief トークン用キーのデフォルト初期化（USI仕様）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Tokenizer::InitTokenKey_for_USI()
{
	SetTokenKeyList
    ( " \a\b\f\t\v\r"
    , Token::eKey::Space // スペースおよび、これらエスケープシーケンスはスペースと同じ扱いとする。
    );
  SetTokenKey( '\n', Token::eKey::NewLine );

  // アルファベット + 数値 + '+-*/'はまとめて、キー'a'とする。
  SetTokenKeyList
    ( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-*/"
    , Token::eKey::Word
    );

  //// マルチバイト文字用。
  //// 原則として、最上位ビットがONの場合はマルチバイトとして扱う。
  //for( int i = 0x80; i <= 0xFF; ++i )
  //{
  //  SetTokenKey( i, Token::eKey::MultiByte );
  //}
}

// _____________________________________________________________________________
/// @brief 次のトークンの取得。
/// 
/// @param[out] out_token
///   : トークンクラスを取得。\n
///   : トークンが取得できない（終端に達している等）場合は不定。
/// 
/// @retval false : トークンの取得に失敗。
/// @retval true  : トークンの取得に成功。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Tokenizer::GetNextToken( rout<Token> out_token ) const
{
  // 終端チェックとエラー対応。
  if( IsEOF() )
  {
    if( m_flag_error_throw )
    {
      CPL_THROW( "Next token was not found.\n" );
    }
    else
    {
      return false;
    }
  }
  
  if( m_char_code == eCharCode::UTF8 )
  {
    return zzz_getNextToken_UTF8( out_token );
  }
  else
  {
    return zzz_getNextToken_SJIS( out_token );
  }
}


// _____________________________________________________________________________
/// @brief ブロック(文字列などの囲み)チェック
/// 
/// @param[in] in_addr_begin
///   : チェックを開始する文字列の先頭アドレスを指定します。
/// @param[in] in_block_end
///   : ブロック識別子ペアを指定します。
/// @param[in] in_flag_newline_throw
///   : 改行をするーするかどうか。
/// @param[in] code_to_key_
///   : コードからキーを返す関数を指定。
/// 
/// @return
/// ブロックが存在したらその長さ(8bit単位)を返します。\n
/// このブロックの長さには両端の識別子も含まれます。\n
/// ブロックではない場合は０を返します。\n
/// in_flag_newline_throw==falseかつ、サーチ途中で改行に達した場合、
/// そこまでの長さ(8bit単位)の負数を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF
  Tokenizer::zzz_checkBlock_
    ( pin<char     > in_addr_begin
    , pin<char     > in_addr_end
    , _in<BlockPair> in_block
    , _in<bool     > in_flag_newline_throw
    , TokenKey(*code_to_key_)(pin<Tokenizer>,pin<char>,rout<int>)
    ) const
{
  auto& strS = in_block.first;
  auto& strE = in_block.second;
  SDEF  lenS = static_cast<SDEF>(strS.size());
  SDEF  lenE = static_cast<SDEF>(strE.size());
  // ブロックシグネチャ自体、残りの長さをオーバーしていたら、ブロックなしとして抜ける。
  if( lenS > (in_addr_end - in_addr_begin) )
  {
    return 0;
  }
  // 開始シグネチャチェック。
  if( Core::StringA::str_ncmp_( in_addr_begin, strS.c_str(), lenS ) == 0 )
  {
    auto p = in_addr_begin + lenS;
    int  res_size;
    // 改行を考慮する場合。
    if( !in_flag_newline_throw )
    {
      // 終了シグネチャが空の場合、改行を終了シグネチャとする（ラインコメント等）
      if( lenE == 0 )
      {
        // 改行または終端になるまでループ。
        while( p < in_addr_end )
        {
          auto key = (*code_to_key_)( this, p, res_size );
          if( key == Token::eKey::Null )
          {
            return in_addr_end - in_addr_begin;
          }
          if( key == Token::eKey::NewLine )
          {
            return p - in_addr_begin;
          }
          p += res_size;
        }
      }
      else
      {
        // 終了シグネチャが現れるまでループする。
        while( Core::StringA::str_ncmp_( p, strE.c_str(), lenE ) )
        {
          if( lenE > (in_addr_end - p) )
          {
            return in_addr_end - in_addr_begin;
          }
          auto key = (*code_to_key_)( this, p, res_size );
          if( key == Token::eKey::Null )
          {
            return p - in_addr_begin;
          }
          p += res_size;
          if( key == Token::eKey::NewLine )
          {
            return p - in_addr_begin;
          }
        }
      }
      p += lenS;
    }
    // 改行を考慮しない場合。
    else
    {
      while( Core::StringA::str_ncmp_( p, strE.c_str(), lenE ) )
      {
        if( lenE > (in_addr_end - p) )
        {
          return -(in_addr_end - in_addr_begin);
        }
        auto key = (*code_to_key_)( this, p, res_size );
        if( key == Token::eKey::Null )
        {
        }
        p += res_size;
      }
      p += lenS;
    }
    return p - in_addr_begin;
  }
  return 0;
}


// _____________________________________________________________________________
/// @brief トークンの取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Tokenizer::zzf_getNextToken_
    ( rout<Token> out_token
    , TokenKey(*code_to_key_)(pin<Tokenizer>,pin<char>,rout<int>)
    ) const
{
  auto* addr_top = m_addr_pos;
  int size_chr; // １文字サイズ
	out_token.key   = (*code_to_key_)( this, m_addr_pos, size_chr ); // 最初の文字のキーを取得。
  out_token.line  = m_line_count;
  out_token.index = m_index_count;

  if( out_token.key == Token::eKey::NewLine )
  {
    m_index_count = 0;
    ++m_line_count;
  }
  else
  {
    m_index_count += size_chr;
  }

  // 文字ブロックのチェック。
  for( auto& sb : m_string_block )
  {
    auto s0 = sb.first.size();
    auto s1 = sb.second.size();
    auto size = zzz_checkBlock_( addr_top, m_addr_end, sb, false, code_to_key_ );
    if( size > 0 ) // ブロックがあった場合。
    {
      m_addr_pos += size;
      size = size - s0 - s1;
      out_token.key = Token::eKey::String;
      out_token.str.resize( size );
      memcpy( &out_token.str[0], addr_top + s0, size );
      return true;
    }
    else
    if( size < 0 )
    {
      out_token.key = Token::eKey::StringError;
      m_addr_pos -= size;
      return true;
    }
  }
  // ブロックコメントのチェック
  for( auto& sb : m_comment_block )
  {
    auto size = zzz_checkBlock_( addr_top, m_addr_end, sb, true, code_to_key_ );
    if( size > 0 ) // ブロックがあった場合。
    {
      m_addr_pos += size;
      out_token.str.resize( size );
      memcpy( &out_token.str[0], addr_top, size );
      return true;
    }
    else
    if( size < 0 )
    {
      out_token.key = Token::eKey::CommentError;
      m_addr_pos -= -size;
      return true;
    }
  }

  m_addr_pos += size_chr;

  // 同じキーの間はループする。
  while( out_token.key == (*code_to_key_)( this, m_addr_pos, size_chr ) )
  {
    m_addr_pos += size_chr;
    if( out_token.key == Token::eKey::NewLine )
    {
      m_index_count = 0;
      ++m_line_count;
    }
    else
    {
      m_index_count += size_chr;
    }

    if( m_addr_pos >= m_addr_end )
    {
      break;
    }
  }

  // 
  auto size = m_addr_pos - addr_top;
  // out_token.strはstd::string(wstring)クラスなので、null文字は含めない。
  // null文字を含めると外部で意図しない動作になる可能性がある。
  out_token.str.resize( size );
  memcpy( &out_token.str[0], addr_top, size * sizeof(addr_top[0]) );
  // out_token.str[ size ] = 0; // ヌル文字禁止。

  return true;
}


// _____________________________________________________________________________
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tokenizer::TokenKey
  Tokenizer::zzz_codeToKey_UTF8
    ( pin<Tokenizer> in_this
    , pin<char     > in_chr
    , rout<int     > out_size
    ) 
{
  size_t idx = GetCharIndex_UTF8( in_chr, out_size );
  return in_this->m_token_key[ idx ];
}


// _____________________________________________________________________________
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tokenizer::TokenKey
  Tokenizer::zzz_codeToKey_SJIS
    ( pin<Tokenizer> in_this
    , pin<char     > in_chr
    , rout<int     > out_size
    )
{
  auto idx = GetCharIndex_SJIS( in_chr, out_size );
  return in_this->m_token_key[ idx ];
}


// _____________________________________________________________________________
bool Tokenizer::zzz_getNextToken_UTF8( rout<Token> out_token ) const
{
  return zzf_getNextToken_( out_token, this->zzz_codeToKey_UTF8 );
}

// _____________________________________________________________________________
bool Tokenizer::zzz_getNextToken_SJIS( rout<Token> out_token ) const
{
  return zzf_getNextToken_( out_token, this->zzz_codeToKey_SJIS );
}


// _____________________________________________________________________________
/// @brief 次のトークンへ進める。
/// 
/// @retval true  : トークンを進めることができた。
/// @retval false : トークンを進めることができなかった（終端など）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Tokenizer::SkipToken() const
{
  Token tkn;
  return GetNextToken( tkn );
}

// _____________________________________________________________________________
/// @brief 次のトークンが指定したキーと同じならばその次のトークンへ進める。
/// 
/// @retval true  : トークンを進めることができた。
/// @retval false : トークンを進めることができなかった（終端など）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Tokenizer::SkipToken( int in_key ) const
{
  // 現在位置を保存。
  auto p = this->m_addr_pos;
  Token tkn;
  if( GetNextToken( tkn ) )
  {
    if( tkn.key != in_key )
    {
      this->m_addr_pos = p;
    }
    return true;
  }
  return false;
}


//// _____________________________________________________________________________
///// @brief スペースのチェック。
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//bool Tokenizer::zzz_checkSpace_() const
//{
//  auto addr_top = m_addr_pos; // 初期位置を保存。
//
//	// スペース（またはスペース扱いの文字）のチェック。
//	while( *m_addr_pos  &&
//    (m_token_key[ (U8)*m_addr_pos ] == Token::eKey::Space/*  ||
//     m_token_key[ (U8)*m_addr_pos ] == Token::eKey::NewLine*/) )
//  {
//    if( m_token_key[ (U8)*m_addr_pos ] == Token::eKey::NewLine )
//    {
//      ++m_line_count;
//      m_index_count = 0;
//    }
//    else
//    {
//      ++m_index_count;
//    }
//		++m_addr_pos; // スペースが続く限り、アドレスを進める。
//	}
//
//  // スペースを処理したかどうかを返す。
//  // 初期の先頭アドレスと違う場合、スペースを処理したことになる。
//  return m_addr_pos != addr_top;
//}


//// _____________________________________________________________________________
///// @brief ブロックコメントのチェック。
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//bool Tokenizer::zzz_checkCommentBlock_() const
//{
//  auto addr_top = m_addr_pos; // 初期位置を保存。
//
//	auto num_cmt_block = m_comment_block.size();
//	for( decltype(num_cmt_block) i = 0; i < num_cmt_block; ++i )
//  {
//    auto str_cmt_begin  = m_comment_block[ i ].first;
//    auto str_cmt_end    = m_comment_block[ i ].second;
//		auto size_cmt_begin = str_cmt_begin.size();
//		auto size_cmt_end   = str_cmt_end.size();
//
//		// ブロックコメントの始端チェック。
//    auto res =
//      Core::StringA::str_ncmp_
//        ( m_addr_pos
//        , str_cmt_begin.c_str()
//        , size_cmt_begin
//        );
//		if( res != 0 )
//    {
//			continue; // 不一致の場合、次のコメントブロック判定へ。
//		}
//    // 次のアドレスへ。
//		m_addr_pos += size_cmt_begin;
//    m_index_count += static_cast<int>(size_cmt_begin);
//
//		// ブロックコメントの終端検索。
//		while( *m_addr_pos )
//    {
//			// 終端コメントシグネチャの先頭文字チェック。
//      if( *m_addr_pos != str_cmt_end[0] )
//      {
//				++m_addr_pos;    // 一致しない場合、次のアドレスへ。
//        ++m_index_count; // 
//        continue;
//      }
//
//			// コメントシグネチャの比較。
//			if( Core::StringA::str_ncmp_( m_addr_pos, str_cmt_end.c_str(), size_cmt_end ) == 0 )
//      {
//				m_addr_pos += size_cmt_end;
//        m_index_count += static_cast<int>(size_cmt_end);
//				break; // 完全一致したら抜ける。
//			}
//      if( m_token_key[ (U8)*m_addr_pos ] == Token::eKey::NewLine )
//      {
//        m_index_count = 0;
//        ++m_line_count;
//      }
//      else
//      {
//        ++m_index_count;
//      }
//      ++m_addr_pos;
//		}
//	}
//
//  // コメントを処理したかどうかを返す。
//  // 初期の先頭アドレスと違う場合、コメントを処理したことになる。
//  return m_addr_pos != addr_top;
//}


//// _____________________________________________________________________________
///// @brief ラインコメントのチェック。
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//bool Tokenizer::zzz_checkCommentLine_() const
//{
//  auto addr_top = m_addr_pos; // 初期位置を保存。
//
//  auto num_cmt_line = m_comment_line.size();
//  for( decltype(num_cmt_line) i = 0; i < num_cmt_line; ++i )
//  {
//    auto str_cmt  = m_comment_line[ i ];
//		auto size_cmt = Core::StringA::str_len_( str_cmt.c_str() );
//
//    // ラインコメントシグネチャのチェック。
//    if( Core::StringA::str_ncmp_( m_addr_pos, str_cmt.c_str(), size_cmt ) != 0 )
//    {
//      // 一致しない場合、次のコメントシグネチャのチェックへ。
//      continue;
//    }
//
//    // 改行または終端まで処理ポイントを進める。
//    while( *m_addr_pos  &&  *m_addr_pos != '\n' )
//    {
//      ++m_addr_pos;
//      ++m_index_count;
//    }
//  }
//
//  // コメントを処理したかどうかを返す。
//  // 初期の先頭アドレスと違う場合、コメントを処理したことになる。
//  return m_addr_pos != addr_top;
//}

// _____________________________________________________________________________
/// @brief 次の文字のアドレスを取得。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
char* Tokenizer::zzz_getNextChar_( char* c ) const
{
  if( m_char_code == eCharCode::UTF8 )
  {
    auto res = GetCharByte_UTF8( c );
    if( res < 0 )
    {
      return nullptr;
    }
    else
    {
      return c + res;
    }
  }
  else // Shift-JIS
  {
    return c + GetCharByte_SJIS( c );
  }
}



// _____________________________________________________________________________
/// @brief トークン配列　コンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TokenArray::TokenArray( _in<Tokenizer> in_tokenizer )
{
  try
  {
    Token token;
    while( in_tokenizer.GetNextToken( token ) )
    {
      m_token_list.push_back( token );
    }
  }
  catch(...)
  {
  }
}



// ------------------------------------------------------------------------------------------------
// 構文解析（デフォルトキーワード）
// ------------------------------------------------------------------------------------------------
//Parser::Parser( Tokenizer* pLA ){
//}



} // namespace Core
} // namespace CPL
