/*============================================================================= Copyright (c) 2002 2004 2006 Joel de Guzman Copyright (c) 2004 Eric Niebler http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include "phrase.hpp" #include "grammars.hpp" #include "quickbook.hpp" #include "utils.hpp" #include "markups.hpp" #include "actions_class.hpp" #include "parse_utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include BOOST_FUSION_ADAPT_STRUCT( quickbook::anchor, (std::string, id) (char const*, dummy) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::link, (quickbook::markup, type) (std::string, destination) (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::simple_markup, (char, symbol) (std::string, raw_content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::break_, (quickbook::file_position, position) (char const*, dummy) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::image, (quickbook::file_position, position) (std::string, image_filename) (quickbook::image::attribute_map, attributes) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::cond_phrase, (std::string, macro_id) (std::string, content) ) BOOST_FUSION_ADAPT_STRUCT( quickbook::template_, (quickbook::file_position, position) (bool, escape) (quickbook::template_symbol, symbol) (std::vector, params) ) namespace quickbook { namespace qi = boost::spirit::qi; namespace ph = boost::phoenix; struct phrase_grammar::rules { rules(quickbook::actions& actions, bool& no_eols); quickbook::actions& actions; bool& no_eols; qi::rule space, blank, comment, phrase_markup, phrase_end, escape, common, hard_space, eol, replaceable, macro, dummy_block, brackets_1_4, template_inner_arg_1_5, brackets_1_5 ; qi::rule position; qi::rule template_; qi::rule template_arg_1_4, template_arg_1_5; qi::rule() > template_args; qi::rule phrase; qi::rule escape_punct, escape_markup; qi::rule break_, escape_break; qi::rule macro_identifier; qi::rule cond_phrase; qi::rule image, image_1_4, image_1_5; qi::rule image_filename, image_attribute_key, image_attribute_value; qi::rule image_attributes; qi::rule()> image_attribute; qi::rule inline_code, code_block; qi::rule > simple_format; qi::rule anchor; qi::symbols link_symbol; qi::rule link, url; qi::symbols format_symbol; qi::rule formatted, footnote; qi::symbols source_mode; }; phrase_grammar::phrase_grammar(quickbook::actions& actions, bool& no_eols) : phrase_grammar::base_type(start, "phrase") , rules_pimpl(new rules(actions, no_eols)) { start = rules_pimpl->common; } phrase_grammar::~phrase_grammar() {} phrase_grammar::rules::rules(quickbook::actions& actions, bool& no_eols) : actions(actions), no_eols(no_eols) { space = *(qi::space | comment) ; blank = *(qi::blank | comment) ; eol = blank >> qi::eol ; phrase_end = ']' | qi::eps(ph::ref(no_eols)) >> eol >> eol // Make sure that we don't go ; // past a single block, except // when preformatted. hard_space = !(qi::alnum | '_') >> space ; // must not be preceded by // alpha-numeric or underscore comment = "[/" >> *(dummy_block | (qi::char_ - ']')) >> ']' ; dummy_block = '[' >> *(dummy_block | (qi::char_ - ']')) >> ']' ; common = macro | phrase_markup | code_block [actions.process] | inline_code [actions.process] | simple_format [actions.process] | escape | comment ; macro = ( actions.macro // must not be followed by >> !(qi::alpha | '_') // alpha or underscore ) [actions.process] ; // Template call template_ = position >> ( '`' >> qi::attr(true) | qi::attr(false) ) >> ( // Lookup the template name (&qi::punct >> actions.templates.scope) | (actions.templates.scope >> hard_space) ) >> template_args >> &qi::lit(']') ; template_args = qi::eps(qbk_before(105u)) >> -(template_arg_1_4 % "..") | qi::eps(qbk_since(105u)) >> -(template_arg_1_5 % ".."); template_arg_1_4 = qi::raw[+(brackets_1_4 | (qi::char_ - (qi::lit("..") | ']')))] ; brackets_1_4 = '[' >> +template_arg_1_4 >> ']' ; template_arg_1_5 = qi::raw[+(brackets_1_5 | ('\\' >> qi::char_) | (qi::char_ - (qi::lit("..") | '[' | ']')))] ; template_inner_arg_1_5 = +(brackets_1_5 | ('\\' >> qi::char_) | (qi::char_ - (qi::lit('[') | ']'))) ; brackets_1_5 = '[' >> +template_inner_arg_1_5 >> ']' ; inline_code = '`' >> position >> qi::raw [ *( qi::char_ - ( '`' | (eol >> eol) // Make sure that we don't go ) // past a single block ) >> &qi::lit('`') ] >> '`' >> qi::attr(false) ; code_block = ( "```" >> position >> qi::raw[*(qi::char_ - "```")] >> "```" >> qi::attr(true) ) | ( "``" >> position >> qi::raw[*(qi::char_ - "``")] >> "``" >> qi::attr(true) ) ; simple_format %= qi::char_("*/_=") [qi::_a = qi::_1] >> qi::raw [ ( ( qi::graph // A single char. e.g. *c* >> &( qi::char_(qi::_a) >> (qi::space | qi::punct | qi::eoi) ) ) | ( qi::graph // qi::graph must follow qi::lit(qi::_r1) >> *( qi::char_ - ( (qi::graph >> qi::lit(qi::_a)) | phrase_end // Make sure that we don't go ) // past a single block ) >> qi::graph // qi::graph must precede qi::lit(qi::_r1) >> &( qi::char_(qi::_a) >> (qi::space | qi::punct | qi::eoi) ) ) ) ] >> qi::omit[qi::char_(qi::_a)] ; phrase = qi::eps [actions.phrase_push] >> *( common | comment | (qi::char_ - phrase_end) [actions.plain_char] ) >> qi::eps [actions.phrase_pop] ; phrase_markup = ( '[' >> ( cond_phrase | image | url | link | anchor | source_mode | formatted | footnote | template_ | break_ ) >> ']' ) [actions.process] ; break_ = position >> "br" >> qi::attr("dummy") ; escape = ( escape_break | "\\ " // ignore an escaped char | escape_punct | escape_markup ) [actions.process] ; escape_break = position >> "\\n" >> qi::attr("dummy") ; escape_punct = qi::attr(markup()) >> '\\' >> qi::repeat(1)[qi::punct] ; escape_markup = ("'''" >> -eol) >> qi::attr(markup(escape_pre_, escape_post_)) >> *(qi::char_ - "'''") >> "'''" ; macro_identifier = +(qi::char_ - (qi::space | ']')) ; cond_phrase = '?' >> blank >> macro_identifier >> -phrase ; image = (qi::eps(qbk_since(105u)) >> image_1_5) | (qi::eps(qbk_before(105u)) >> image_1_4); image_1_4 = position >> '$' >> blank >> *(qi::char_ - phrase_end) >> &qi::lit(']') ; image_1_5 = position >> '$' >> blank >> image_filename >> hard_space >> image_attributes >> &qi::lit(']') ; image_filename = qi::raw[ +(qi::char_ - (qi::space | phrase_end | '[')) >> *( +qi::space >> +(qi::char_ - (qi::space | phrase_end | '[')) )]; image_attributes = *(image_attribute >> space); image_attribute = '[' >> image_attribute_key >> space >> image_attribute_value >> ']' ; image_attribute_key = *(qi::alnum | '_'); image_attribute_value = *(qi::char_ - (phrase_end | '[')); anchor = '#' >> blank >> *(qi::char_ - phrase_end) >> qi::attr("dummy") ; link_symbol.add ("link", markup(link_pre_, link_post_)) ("funcref", markup(funcref_pre_, funcref_post_)) ("classref", markup(classref_pre_, classref_post_)) ("memberref", markup(memberref_pre_, memberref_post_)) ("enumref", markup(enumref_pre_, enumref_post_)) ("macroref", markup(macroref_pre_, macroref_post_)) ("headerref", markup(headerref_pre_, headerref_post_)) ("conceptref", markup(conceptref_pre_, conceptref_post_)) ("globalref", markup(globalref_pre_, globalref_post_)) ; link = link_symbol >> hard_space >> *(qi::char_ - (']' | qi::space)) >> ( &qi::lit(']') | (hard_space >> phrase) ) ; url = '@' >> qi::attr(markup(url_pre_, url_post_)) >> *(qi::char_ - (']' | qi::space)) >> ( &qi::lit(']') | (hard_space >> phrase) ) ; format_symbol.add ("*", markup(bold_pre_, bold_post_)) ("'", markup(italic_pre_, italic_post_)) ("_", markup(underline_pre_, underline_post_)) ("^", markup(teletype_pre_, teletype_post_)) ("-", markup(strikethrough_pre_, strikethrough_post_)) ("\"", markup(quote_pre_, quote_post_)) ("~", markup(replaceable_pre_, replaceable_post_)) ; formatted = format_symbol >> blank >> phrase; source_mode.add ("c++", quickbook::source_mode("c++")) ("python", quickbook::source_mode("python")) ("teletype", quickbook::source_mode("teletype")) ; footnote = "footnote" >> qi::attr(markup(footnote_pre_, footnote_post_)) >> blank >> phrase ; position = qi::raw[qi::eps] [get_position]; } struct simple_phrase_grammar::rules { rules(quickbook::actions& actions); quickbook::actions& actions; bool unused; phrase_grammar common; qi::rule phrase, comment, dummy_block; }; simple_phrase_grammar::simple_phrase_grammar(quickbook::actions& actions) : simple_phrase_grammar::base_type(start, "simple_phrase") , rules_pimpl(new rules(actions)) , start(rules_pimpl->phrase) {} simple_phrase_grammar::~simple_phrase_grammar() {} simple_phrase_grammar::rules::rules(quickbook::actions& actions) : actions(actions), unused(false), common(actions, unused) { phrase = *( common | comment | (qi::char_ - ']') [actions.plain_char] ) ; comment = "[/" >> *(dummy_block | (qi::char_ - ']')) >> ']' ; dummy_block = '[' >> *(dummy_block | (qi::char_ - ']')) >> ']' ; } }