/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2008/X/X - 2015/11/11
/// 
/// @brief  字句解析関連
///
/// 2015/01/15 リリース版に仮実装
/// 
/// ****************************************************************************


#ifndef CPL_LEXICAL_ANALYSIS_H
#define CPL_LEXICAL_ANALYSIS_H


//#include "../CPL_Core.h"
//#include "../Base/CPL_Core_Basic.h"
#include "../String/CPL_Core_String.h"


namespace CPL {
namespace Core {

// _____________________________________________________________________________
/// @brief トークン型
///
// *****************************************************************************
struct Token
{
  using TypeKey = U32;
  struct eKey
  { enum : TypeKey
    { Null  = 0
    , Space = (U32)kStrMaxSize
    , Comment
    , NewLine
    , Number
    , Word
    , NotAscii
    , String
    , StringError
    , CommentError
    , Error // その他エラー

    , UserCode
    };
  };

  std::string str;
  TypeKey     key   = 0;
  int         line  = -1;
  int         index = -1;
  //U16         length = 0; // スペースやコメントの場合、その長さが設定される。
  //bool        is_prev_space   = false; // 前方にスペースがあったかどうか。
  //bool        is_prev_comment = false; // 前方にコメントがあったかどうか。

  Token() = default;
  Token( std::string&& str_, TypeKey key_, int line_, int index_ )
    : str( str_ )
    , key( key_ )
    , line( line_ )
    , index( index_ )
  {}
  Token( cref<Token> in_token )
    : str( in_token.str )
    , key( in_token.key )
    , line( in_token.line )
    , index( in_token.index )
    //, length( in_token.length )
    //, is_prev_space( in_token.is_prev_space )
    //, is_prev_comment( in_token.is_prev_comment )
  {}

  Token& operator = ( cref<Token> in_token )
  {
    if( &in_token != this )
    {
      str   = in_token.str;
      key   = in_token.key;
      line  = in_token.line;
      index = in_token.index;
      //length = in_token.length;
      //is_prev_space = 
    }
    return *this;
  }
};




// _____________________________________________________________________________
/// @brief 字句解析クラス
///
/// @note
/// ・スペースおよびスペースとして扱われるエスケープシーケンスは、
///   １文字のスペースのトークンとして扱う。\n
/// ・コメントは、0文字のトークンとして扱う。
///   これは、コメントを区切りとして扱うかは構文解析によるため。
/// ・
// *****************************************************************************
class Tokenizer
{
  friend class Tokenizer;
public:
	Tokenizer
  ( pin<char     > in_ptr_string
  , _in<size_t   > in_size_buf
  , _in<eCharCode> in_char_code
  , _in<bool     > in_flag_error_throw = false
  );
  //Tokenizer
  //( _in<std::string> in_string
  //, _in<eCharCode  > in_char_code
  //, _in<bool       > in_flag_error_throw = false
  //) : Tokenizer( in_string.c_str(), in_string.size(), in_char_code, in_flag_error_throw )
  //{}

  void SetFlag_ErrorThrow( _in<bool> in_flag_error_throw )
        {
          m_flag_error_throw = in_flag_error_throw;
        }
	void SetTokenKey( pin<char> in_C, int set = -1 );
	void SetTokenKey( _in<int> in_C, int set = -1 )
  {
    SetTokenKey( (char_cptr)&in_C, set );
  }
	void SetTokenKeyList( pin<char> c_tbl, int in_token_key );
  void SetCommentBlock( pin<char> in_str_begin, pin<char> in_str_end );
  void SetCommentLine( pin<char> in_str_comment );
  void SetStringBlock( pin<char> in_str_begin, pin<char> in_str_end );

  void ReleaseBlock_for_Comment(){ m_comment_block.clear(); }
  void ReleaseBlock_for_String(){ m_string_block.clear(); }

	bool GetNextToken( rout<Token> out_token ) const;
  bool SkipToken() const;
  bool SkipToken( int in_key ) const;
  bool IsEOF() const { return m_addr_pos >= m_addr_end; }

	void InitTokenKey_for_C();
  void InitTokenKey_for_USI();

private:
	using BlockPair = std::pair<std::string,std::string>;
  using TokenKey  = Token::TypeKey; // 文字に対応するインデックスとする。

  std::vector<TokenKey>    m_token_key;    // 
  std::string              m_str_original; // オリジナルバッファ。
  mutable char_cptr        m_addr_pos;     // 現在解析中のアドレス。
  char_cptr                m_addr_end;     // 終端アドレス（主に高速化のため。なお、最後＋１のアドレス）
  eCharCode                m_char_code;
  std::vector<BlockPair>   m_string_block;
  std::vector<BlockPair>   m_comment_block;
  mutable int              m_line_count  = 0;
  mutable int              m_index_count = 0;
  bool                     m_flag_error_throw = false;

  SDEF  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;
  char* zzz_getNextChar_( char* c ) const;
  bool  zzf_getNextToken_
          ( rout<Token> out_token
          , TokenKey(*code_to_key_)(pin<Tokenizer>,pin<char>,rout<int>)
          ) const;
	bool  zzz_getNextToken_UTF8( rout<Token> out_token ) const;
	bool  zzz_getNextToken_SJIS( rout<Token> out_token ) const;

  static TokenKey zzz_codeToKey_UTF8( pin<Tokenizer> in_this, pin<char> in_chr, rout<int> out_size );
  static TokenKey zzz_codeToKey_SJIS( pin<Tokenizer> in_this, pin<char> in_chr, rout<int> out_size );
};


// _____________________________________________________________________________
/// @brief トークン配列クラス
///
// *****************************************************************************
class TokenArray
{
  using TokenArray_ = std::vector<Token>;

  TokenArray_ m_token_list;

public:
  TokenArray( _in<Tokenizer> in_tokenizer );

  cref<TokenArray_> GetTokenList() const
  {
    return m_token_list;
  }

  size_t GetTokenNum() const
  {
    return m_token_list.size();
  }

  cref<Token> GetToken( size_t in_idx ) const
  {
    return m_token_list[ in_idx ];
  }
  //int GetKey( size_t in_idx ) const
  //{
  //  return m_token_list[ in_idx ].key;
  //}
};


// ================================================================================================
// 構文解析クラス
// ================================================================================================
//class Parser {
//private:
//public:
//	Parser( Tokenizer* pLA );
//};



} // namespace Core
} // namespace CPL



#endif
