/*

cls_2: Curl Like Syntax
Yauheni A. Akhotnikau (C) 2001-2003
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/
#if !defined( _CLS_2__PARSER_HPP_ )
#define _CLS_2__PARSER_HPP_

#include <cls_2/h/cls.hpp>

namespace cls_2 {

//
// file_scope_tag_t
//

class	file_scope_tag_t :
	public tag_t {
	public :
		file_scope_tag_t();
		virtual ~file_scope_tag_t();

		// Returns c_syntax_error
		// (expected tag or EOF)
		virtual int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value );

		// Returns c_syntax_error
		// (expected tag or EOF)
		virtual int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value );
};

//
// _parser_t
//
struct	syn_state_t;
struct	syn_state_trans_t;

/*
	Real parser class
*/
class	_parser_t {
	public :
		_parser_t();
		~_parser_t();

		int
		parse( parser_context_t & context );

		void
		tag_add( tag_t & tag );

		void
		tag_remove( tag_t & tag );

		// Root tag is not included
		size_t
		tag_stack_size() const;

		// Tag at top of stack has greater index than
		// tag at bottom of stack.
		// Root tag is not included
		const tag_t *
		tag_stack_at( size_t index ) const;

	protected :
		file_scope_tag_t	m_root_tag;

		typedef tag_t * tag_ptr_t;
		auto_ptr_3::vect_ptr_t< tag_ptr_t >	m_tag_stack;
		size_t	m_tag_stack_size;

		// Current content (tag name, tag space token,
		// tag nonspace token, tag string token, etc)
		auto_ptr_3::vect_ptr_t< char >	m_cnt;
		size_t	m_cnt_size;

		void
		cleanup();

		void
		cnt_reset();

		void
		cnt_append( char ch );

		void
		push_tag( tag_t * tag );

		void
		pop_tag();

		tag_t *
		top_tag();

		int
		process_token(
			parser_context_t & context,
			syn_state_t * & cur_state,
			int token,
			char ch,
			bool & is_get_next_token );

		int
		process_trans(
			parser_context_t & context,
			const syn_state_trans_t * trans,
			syn_state_t * & cur_state,
			char ch,
			bool & is_get_next_token );

		int
		start_new_tag(
			parser_context_t & context,
			tag_t * tag );

	public :

		// Default token proc. Simply add ch to content
		void
		on_token_default(
			parser_context_t & context,
			char ch );

		//
		// Syntax state procedures
		//

		int
		on_enter_finish(
			parser_context_t & context );
		int
		on_enter_wait_tag_name(
			parser_context_t & context );
		int
		on_exit_fill_tag_name(
			parser_context_t & context );
		int
		on_enter_tag_complete(
			parser_context_t & context );
		int
		on_exit_tag_complete(
			parser_context_t & context );
		int
		on_enter_tag_cnt_space(
			parser_context_t & context );
		int
		on_exit_tag_cnt_space(
			parser_context_t & context );
		int
		on_enter_tag_cnt_nonspace(
			parser_context_t & context );
		int
		on_exit_tag_cnt_nonspace(
			parser_context_t & context );
		int
		on_enter_tag_cnt_string(
			parser_context_t & context );
		int
		on_exit_tag_cnt_string(
			parser_context_t & context );

	private :
		_parser_t( const _parser_t & );
		_parser_t &
		operator=( const _parser_t & );
};

typedef int (_parser_t:: *pfn_state_proc_t)
	( parser_context_t & context );
typedef void (_parser_t:: *pfn_token_proc_t)
	( parser_context_t & context, char ch );

} /* namespace cls_2 */

#endif
