エラーメッセージに行番号を加える
これまでのエラーメッセージでは起きたエラーが何かということは判りましたが、それがどこで起きたのかということは判りませんでした
そこでエラーメッセージに行番号を加えてどこで発生したエラーなのかも判るようにしてみましょう
仕組み
解析器で改行を数えます
改行文字は必ず空白なので skipspace に手を加えます
ノードのメンバには行番号を追加しましょう
ノードの実装
class node { size_t m_lineno; . . . public: size_t get_lineno() const { return m_lineno; } . . . void clear(){ m_lineno = ( size_t )-1; m_operator.clear(); m_operands.clear(); m_value.clear(); } void assign( size_t lineno, const std::string& operator_new, const node& operand1 ){ clear(); m_lineno = lineno; m_operator = operator_new; m_operands.push_back( operand1 ); } void assign( size_t lineno, const std::string& operator_new, const node& operand1, const node& operand2 ){ clear(); m_lineno = lineno; m_operator = operator_new; m_operands.push_back( operand1 ); m_operands.push_back( operand2 ); } void assign( size_t lineno, const std::string& operator_new, const std::list<node>& operands ){ clear(); m_lineno = lineno; m_operator = operator_new; m_operands = operands; } void assign( size_t lineno, const std::string& name, const std::string& value ){ clear(); m_lineno = lineno; m_value.assign( name, value ); } node& operator=( const node& rhs ){ if( this != &rhs ){ m_lineno = rhs.m_lineno; m_operator = rhs.m_operator; m_operands = rhs.m_operands; m_value = rhs.m_value; } return *this; } node( size_t lineno = ( size_t )-1 ): m_lineno(lineno), m_operator(), m_operands(), m_value() { } node( const node& rhs ): m_lineno(rhs.m_lineno), m_operator(rhs.m_operator), m_operands(rhs.m_operands), m_value(rhs.m_value) { } node( size_t lineno, const std::string& operator_new, const node& operand1 ): m_lineno(( size_t )-1), m_operator(), m_operands(), m_value() { assign( lineno, operator_new, operand1 ); } node( size_t lineno, const std::string& operator_new, const node& operand1, const node& operand2 ): m_lineno(( size_t )-1), m_operator(), m_operands(), m_value() { assign( lineno, operator_new, operand1, operand2 ); } node( size_t lineno, const std::string& operator_new, std::list<node> operands ): m_lineno(( size_t )-1), m_operator(), m_operands(), m_value() { assign( lineno, operator_new, operands ); } node( size_t lineno, const std::string& name, const std::string& value ): m_lineno(( size_t )-1), m_operator(), m_operands(), m_value() { assign( lineno, name, value ); } };
解析器の実装
class parser : protected istringstream<char> { parser_callback* m_callback; std::vector<size_type> m_lines; size_type get_lineno( size_type offset ); ... }; parser::parser( parser_callback* callback ): istringstream<char>(), m_callback(callback), m_lines() { } parser::size_type parser::get_lineno( size_type offset ){ std::vector<size_type>::iterator p = std::lower_bound( m_lines.begin(), m_lines.end(), offset ); return size_type( std::distance( m_lines.begin(), p ) + 1 ); } bool parser::skipspace(){ char comment = 0; while( !eof()){ . . . if( c == '\n' ){ m_lines.push_back( m_offset ); } } return !eof(); }
エラー処理の実装
class string_calc : private parser_callback, private evaluator_callback { void error_illegal_character( size_t lineno, char c ); void error_unexpected_eof( size_t lineno ); void error_unbalanced_parenthesis( size_t lineno ); void runtime_error_devide_by_zero( size_t lineno ); ... }; void string_calc::runtime_error_devide_by_zero( size_t lineno ){ // 0 除算 OutputDebugString( stringprintf( " line#%d: ", lineno )); OutputDebugString( "runtime error: devide by zero.\n" ); } void string_calc::error_illegal_character( size_t lineno, char c ){ // 変な文字だからお終い OutputDebugString( stringprintf( " line#%d: ", lineno )); OutputDebugString( stringprintf( "error: illegal caracter '%c'.\n", c )); } void string_calc::error_unexpected_eof( size_t lineno ){ // 予期せぬ EOF OutputDebugString( stringprintf( " line#%d: ", lineno )); OutputDebugString( "error: unexpected EOF.\n" ); } void string_calc::error_unbalanced_parenthesis( size_t lineno ){ // 対応する () が見つからないから終わり OutputDebugString( stringprintf( " line#%d: ", lineno )); OutputDebugString( "error: unbalanced parenthesis.\n" ); }