// xpr_xml.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

//#pragma warning (push)
#pragma warning (disable: 4100 4127 4244 4503 4512)
#include <boost/spirit/fusion/iterator/detail/iterator_base.hpp> // Xpr missing
#include <boost/xpressive/xpressive_static.hpp>
#include <boost/xpressive/detail/proto/proto.hpp>
//#pragma warning (pop)

#include <sstream>
#include <iostream>
#include <fstream>
#include <cassert>

namespace {

///////////////////////////////////////////////////////////////////////////////
// Char
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Char()
{
	namespace xpr = boost::xpressive;
	// return xpr::_w;
	return xpr::set[ xpr::range(_T('\x20'),_T('\xFF')) | _T('\x9') | _T('\xA') ];
}

///////////////////////////////////////////////////////////////////////////////
// Letter
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Letter()
{
	namespace xpr = boost::xpressive;
	// return xpr::_w;
	return xpr::set[
		xpr::range(_T('\x41'),_T('\x5A')) |
		xpr::range(_T('\x61'),_T('\x7A')) |
		xpr::range(_T('\xC0'),_T('\xD6')) |
		xpr::range(_T('\xD8'),_T('\xF6')) |
		xpr::range(_T('\xF8'),_T('\xFF')) ];
}

///////////////////////////////////////////////////////////////////////////////
// Digit
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Digit()
{
	namespace xpr = boost::xpressive;
	return xpr::_d;
	/*
	using boost::xpressive::range;
	return range(_T('0'),_T('9'));*/
}

///////////////////////////////////////////////////////////////////////////////
// Extender
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Extender()
{
	return boost::xpressive::as_xpr(_T('\xB7'));
}

///////////////////////////////////////////////////////////////////////////////
// xml_Sch
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Sch()
{
	namespace xpr = boost::xpressive;
	return xpr::set= _T('\x20'), _T('\x9'), _T('\xD'), _T('\xA');
}

///////////////////////////////////////////////////////////////////////////////
// xml_NameChar
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_NameChar()
{
	namespace xpr = boost::xpressive;

	return
		( xml_Letter<BidiIter>() >> xpr::epsilon )
		| xml_Digit<BidiIter>()
		| (xpr::set= _T('.'), _T('_'), _T(':'), _T('-'))
		| xml_Extender<BidiIter>()
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_S
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_S()
{
	namespace xpr = boost::xpressive;

	return
		+( xml_Sch<BidiIter>() >> xpr::epsilon )
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Name
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Name()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> ( xml_Letter<BidiIter>() | _T('_') | _T(':') )
		>> *(xml_NameChar<BidiIter>() >> xpr::epsilon)
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Eq
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Eq()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> !xml_S<BidiIter>()
		>> _T('=')
		>> !xml_S<BidiIter>()
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_EntityRef
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_EntityRef()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> _T('&') >> xml_Name<BidiIter>() >> _T(';');
}

///////////////////////////////////////////////////////////////////////////////
// xml_CharRef
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_CharRef()
{
	namespace xpr = boost::xpressive;

	return
		( _T("&#") >> +xpr::_d >> _T(';') )
		|
			( _T("&#x")
				>> +(xpr::set [ xpr::_d | xpr::range(_T('a'),_T('f')) | xpr::range(_T('A'),_T('F')) ])
				>> _T(';')
			)
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Reference
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Reference()
{
	namespace xpr = boost::xpressive;

	return
		( xml_EntityRef<BidiIter>() >> xpr::epsilon )
		| xml_CharRef<BidiIter>();
}

///////////////////////////////////////////////////////////////////////////////
// xml_AttValue
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_AttValue()
{
	namespace xpr = boost::xpressive;

	return
		(
			_T('"')
			>> *( ~(xpr::set= _T('<'),_T('&'),_T('"')) | xml_Reference<BidiIter>() )
			>> _T('"')
		)
		|
		(
			_T('\'')
			>> *( ~(xpr::set= _T('<'),_T('&'),_T('\'')) | xml_Reference<BidiIter>() )
			>> _T('\'')
		)
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Attribute
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Attribute()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> xml_Name<BidiIter>()
		>> xml_Eq<BidiIter>()
		>> xml_AttValue<BidiIter>()
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_STag
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_STag()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> _T('<')
		>> xml_Name<BidiIter>()
		>>
			*(xpr::epsilon
				>> xml_S<BidiIter>()
				>> xml_Attribute<BidiIter>()
			)
		>> !xml_S<BidiIter>()
		>> _T('>')
	;		
}

///////////////////////////////////////////////////////////////////////////////
// xml_ETag
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_ETag()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> _T("</")
		>> xml_Name<BidiIter>()
		>> !xml_S<BidiIter>()
		>> _T('>')
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_EmptyElemTag
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_EmptyElemTag()
{
	namespace xpr = boost::xpressive;

	return
		_T('<')
		>> xml_Name<BidiIter>()
		>> *(xpr::epsilon >> xml_S<BidiIter>() >> xml_Attribute<BidiIter>())
		>> !xml_S<BidiIter>()
		>> _T("/>")
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Comment
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Comment()
{
	namespace xpr = boost::xpressive;

	return
		_T("<!--")
		>> 
			-*(
				xml_Char<BidiIter>()
				| (_T('-') >> xml_Char<BidiIter>())
			)
		>> _T("-->")
	;
}

/* draft
///////////////////////////////////////////////////////////////////////////////
// xml_content
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter> xml_element();

template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_content()
{
	using boost::xpressive::epsilon;
	using boost::xpressive::by_ref;

	return
		*(
			(xml_element<BidiIter>() >> epsilon) // recursion
			| xml_Comment<BidiIter>()
		)
	;
}
*/
///////////////////////////////////////////////////////////////////////////////
// xml_element
//
/*
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_element()
{
	using boost::xpressive::epsilon;

	return
		xml_EmptyElemTag<BidiIter>()
		|
			(epsilon
				>> xml_STag<BidiIter>()
				>> xml_content<BidiIter>()
				>> xml_ETag<BidiIter>()
			)
	;
}*/

///////////////////////////////////////////////////////////////////////////////
// xml_CharData
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_CharData()
{
	namespace xpr = boost::xpressive;

	return
		*~(xpr::set= _T('&'), _T('<'))
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_element
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_element()
{
	namespace xpr = boost::xpressive;

	xpr::basic_regex<BidiIter> element;
	xpr::basic_regex<BidiIter> content;

	content =
		!xml_CharData<BidiIter>()
		>>
		*(
			(
				xpr::by_ref(element)									// the recursion
				| xml_Reference<BidiIter>()
				| xml_Comment<BidiIter>()
			)
			>> !xml_CharData<BidiIter>()
		)
	;

	element =
		xpr::keep( xml_EmptyElemTag<BidiIter>() )	// clean up stack, for the recursion
		| (xpr::epsilon
				>> xpr::keep( xml_STag<BidiIter>() )	//
				>> content
				>> xml_ETag<BidiIter>()
			)
	;

	return element;
}

///////////////////////////////////////////////////////////////////////////////
// xml_Misc
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_Misc()
{
	namespace xpr = boost::xpressive;

	return
		(xml_Comment<BidiIter>() >> xpr::epsilon)
		| xml_S<BidiIter>()
	;
}

///////////////////////////////////////////////////////////////////////////////
// xml_prolog
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_prolog()
{
	namespace xpr = boost::xpressive;

	return *(xml_Misc<BidiIter>() >> xpr::epsilon);
}

///////////////////////////////////////////////////////////////////////////////
// xml_document
//
template< class BidiIter > inline
boost::xpressive::basic_regex<BidiIter>
xml_document()
{
	namespace xpr = boost::xpressive;

	return xpr::epsilon
		>> xml_prolog<BidiIter>()
		>> xml_element<BidiIter>()
		>> *(xml_Misc<BidiIter>() >> xpr::epsilon)
	;
}

///////////////////////////////////////////////////////////////////////////////
// test_parse
//
inline void test_parse(char* filename)
{
	namespace xpr = boost::xpressive;

	// open input file
	std::wifstream fin(filename);
	assert(fin.good());

	std::wstring in;
	std::getline(fin, in, L'\0');

	xpr::wsmatch what;
	xpr::wsregex sre = (xpr::s1= xml_document<xpr::wsregex::iterator_type>());
	typedef std::wstring::iterator iter_t;
	if (xpr::regex_match(in, what, sre)) {
		std::wcout << what[1];
	}
}

} // namespace

#include <iostream>

int main(int argc, char* argv[])
{
	(argc); (argv);

	std::locale::global(std::locale("ja"));
  { // See: http://hw001.gate01.com/eggplant/tcf/cpp/wchar_t_trap.html
    std::wcin.imbue(std::locale("ja"));
    std::wcout.imbue(std::locale("ja"));
  }

	if (argc > 1) {
		for (int i = 1; i < argc; ++i) {
			std::cout << argv[i] << std::endl;
			test_parse(argv[i]);
		}
	} else {
		std::wcout << L"No filename given..." << std::endl;
	}
	std::wcin.ignore();
	return 0;
}

