diff options
Diffstat (limited to 'tools/quickbook/src/main_grammar.cpp')
-rw-r--r-- | tools/quickbook/src/main_grammar.cpp | 464 |
1 files changed, 286 insertions, 178 deletions
diff --git a/tools/quickbook/src/main_grammar.cpp b/tools/quickbook/src/main_grammar.cpp index 1ec2ff9ca8..74dbecea76 100644 --- a/tools/quickbook/src/main_grammar.cpp +++ b/tools/quickbook/src/main_grammar.cpp @@ -9,7 +9,8 @@ =============================================================================*/ #include "grammar_impl.hpp" -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" #include "utils.hpp" #include "template_tags.hpp" #include "block_tags.hpp" @@ -27,8 +28,6 @@ #include <boost/range/algorithm/find_first_of.hpp> #include <boost/range/as_literal.hpp> -#include <iostream> - namespace quickbook { namespace cl = boost::spirit::classic; @@ -91,44 +90,6 @@ namespace quickbook string_iterator last); void clear_stack(); - struct process_element_impl : scoped_action_base { - process_element_impl(main_grammar_local& l) - : l(l) {} - - bool start() - { - if (!(l.info.type & l.element.context()) || - qbk_version_n < l.info.qbk_version) - return false; - - info_ = l.info; - - if (info_.type != element_info::phrase && - info_.type != element_info::maybe_block) - l.actions_.paragraph(); - - l.actions_.values.builder.reset(); - - return true; - } - - template <typename ResultT, typename ScannerT> - bool result(ResultT result, ScannerT const& scan) - { - if (result || info_.type & element_info::in_phrase) - return result; - - l.actions_.error(scan.first, scan.first); - return true; - } - - void success(parse_iterator, parse_iterator) { l.element_type = info_.type; } - void failure() { l.element_type = element_info::nothing; } - - main_grammar_local& l; - element_info info_; - }; - struct in_list_impl { main_grammar_local& l; @@ -216,53 +177,167 @@ namespace quickbook element_info info; element_info::type_enum element_type; - // actions - quickbook::actions& actions_; - member_action<main_grammar_local> check_indentation; - member_action<main_grammar_local> check_code_block; - member_action<main_grammar_local> start_blocks; - member_action<main_grammar_local> end_blocks; - in_list_impl in_list; - scoped_parser<process_element_impl> process_element; - scoped_parser<set_no_eols_scoped> scoped_no_eols; + // state + quickbook::state& state_; //////////////////////////////////////////////////////////////////////// // Local constructor - main_grammar_local(quickbook::actions& actions) + main_grammar_local(quickbook::state& state) : list_stack() , list_indent(0) , no_eols(true) - , actions_(actions) - , check_indentation(*this, &main_grammar_local::check_indentation_impl) - , check_code_block(*this, &main_grammar_local::check_indentation_impl) - , start_blocks(*this, &main_grammar_local::start_blocks_impl) - , end_blocks(*this, &main_grammar_local::end_blocks_impl) - , in_list(*this) - , process_element(*this) - , scoped_no_eols(*this) + , state_(state) {} }; + struct process_element_impl : scoped_action_base { + process_element_impl(main_grammar_local& l) + : l(l) {} + + bool start() + { + if (!(l.info.type & l.element.context()) || + qbk_version_n < l.info.qbk_version) + return false; + + info_ = l.info; + + if (!l.list_stack.empty() && !l.list_stack.top().root && + info_.type == element_info::block) + { + // If in a list and the element is a block, end the list. + list_item_action list_item(l.state_); + list_item(); + l.clear_stack(); + } + else if (info_.type != element_info::phrase && + info_.type != element_info::maybe_block) + { + paragraph_action para(l.state_); + para(); + } + + assert(l.state_.values.builder.empty()); + + if (!l.state_.source_mode_next.empty() && + info_.type != element_info::maybe_block) + { + l.state_.source_mode.swap(saved_source_mode_); + l.state_.source_mode = l.state_.source_mode_next.get_quickbook(); + l.state_.source_mode_next = value(); + } + + return true; + } + + template <typename ResultT, typename ScannerT> + bool result(ResultT result, ScannerT const& scan) + { + if (result || info_.type & element_info::in_phrase) + return result; + + error_action error(l.state_); + error(scan.first, scan.first); + return true; + } + + void success(parse_iterator, parse_iterator) { l.element_type = info_.type; } + void failure() { l.element_type = element_info::nothing; } + + void cleanup() { + if (!saved_source_mode_.empty()) + l.state_.source_mode.swap(saved_source_mode_); + } + + main_grammar_local& l; + element_info info_; + std::string saved_source_mode_; + }; + + struct set_no_eols_scoped : scoped_action_base + { + set_no_eols_scoped(main_grammar_local& l) + : l(l) {} + + bool start() { + saved_no_eols = l.no_eols; + l.no_eols = false; + + return true; + } + + void cleanup() { + l.no_eols = saved_no_eols; + } + + main_grammar_local& l; + bool saved_no_eols; + }; + + struct in_list_impl { + main_grammar_local& l; + + in_list_impl(main_grammar_local& l) : + l(l) {} + + bool operator()() const { + return !l.list_stack.top().root; + } + }; + //////////////////////////////////////////////////////////////////////////// // Local grammar void quickbook_grammar::impl::init_main() { main_grammar_local& local = cleanup_.add( - new main_grammar_local(actions)); + new main_grammar_local(state)); + + // Global Actions + element_action element(state); + paragraph_action paragraph(state); + list_item_action list_item(state); + + phrase_end_action end_phrase(state); + raw_char_action raw_char(state.phrase); + plain_char_action plain_char(state.phrase, state); + escape_unicode_action escape_unicode(state.phrase, state); + + simple_phrase_action simple_markup(state.phrase, state); + + break_action break_(state.phrase, state); + do_macro_action do_macro(state.phrase, state); + + error_action error(state); + element_id_warning_action element_id_warning(state); + + scoped_parser<to_value_scoped_action> to_value(state); + + // Local Actions + scoped_parser<process_element_impl> process_element(local); + scoped_parser<set_no_eols_scoped> scoped_no_eols(local); + in_list_impl in_list(local); + member_action<main_grammar_local> check_indentation(local, + &main_grammar_local::check_indentation_impl); + member_action<main_grammar_local> check_code_block(local, + &main_grammar_local::check_code_block_impl); + member_action<main_grammar_local> start_blocks(local, + &main_grammar_local::start_blocks_impl); + member_action<main_grammar_local> end_blocks(local, + &main_grammar_local::end_blocks_impl); // phrase/phrase_start is used for an entirely self-contained // phrase. For example, any remaining anchors are written out // at the end instead of being saved for any following content. phrase_start = - inline_phrase [actions.phrase_end] + inline_phrase [end_phrase] ; // nested_phrase is used for a phrase nested inside square // brackets. nested_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(']') >> local.common(element_info::in_phrase) ) @@ -272,7 +347,7 @@ namespace quickbook // paragraph_phrase is like a nested_phrase but is also terminated // by a paragraph end. paragraph_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(phrase_end) >> local.common(element_info::in_phrase) ) @@ -282,7 +357,7 @@ namespace quickbook // extended_phrase is like a paragraph_phrase but allows some block // elements. extended_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(phrase_end) >> local.common(element_info::in_conditional) ) @@ -294,13 +369,13 @@ namespace quickbook // is expanding a template, which is parsed separately but // is part of the paragraph that contains it. inline_phrase = - actions.values.save() + state.values.save() [ *local.common(element_info::in_phrase) ] ; table_title_phrase = - actions.values.save() + state.values.save() [ *( ~cl::eps_p(space >> (']' | '[' >> space >> '[')) >> local.common(element_info::in_phrase) ) @@ -308,15 +383,15 @@ namespace quickbook ; inside_preformatted = - local.scoped_no_eols() + scoped_no_eols() [ paragraph_phrase ] ; // Top level blocks block_start = - (*eol) [local.start_blocks] - >> (*local.top_level) [local.end_blocks] + (*eol) [start_blocks] + >> (*local.top_level) [end_blocks] ; local.top_level = @@ -337,7 +412,7 @@ namespace quickbook ( *cl::blank_p >> !( (cl::ch_p('*') | '#') >> *cl::blank_p) - ) [local.check_indentation] + ) [check_indentation] ; local.paragraph = @@ -346,7 +421,7 @@ namespace quickbook >> *( cl::eps_p(local.paragraph.still_in_block) >> local.paragraph_item(element_info::only_block) ) - >> cl::eps_p [actions.paragraph] + >> cl::eps_p [paragraph] ; local.paragraph_item = @@ -361,9 +436,13 @@ namespace quickbook >> (cl::ch_p('*') | '#') >> (*cl::blank_p) [local.list.still_in_block = true] >> *( cl::eps_p(local.list.still_in_block) - >> local.list_item(element_info::only_block) + >> ( qbk_ver(106u) >> local.list_item(element_info::only_block) + | qbk_ver(0, 106u) >> local.list_item(element_info::only_list_block) + ) ) - >> cl::eps_p [actions.list_item] + // TODO: This is sometimes called in the wrong place. Currently + // harmless. + >> cl::eps_p [list_item] ; local.list_item = @@ -379,7 +458,7 @@ namespace quickbook ( *cl::blank_p >> ( cl::eol_p | cl::end_p - | cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#') + | cl::eps_p(in_list) >> (cl::ch_p('*') | '#') ) ) >> *eol @@ -387,25 +466,25 @@ namespace quickbook // Blocks contains within an element, e.g. a table cell or a footnote. inside_paragraph = - actions.values.save() - [ *( local.paragraph_separator [actions.paragraph] + state.values.save() + [ *( local.paragraph_separator [paragraph] >> *eol | ~cl::eps_p(']') >> local.common(element_info::in_nested_block) ) - ] [actions.paragraph] + ] [paragraph] ; local.hr = cl::str_p("----") - >> actions.values.list(block_tags::hr) - [ ( qbk_since(106u) + >> state.values.list(block_tags::hr) + [ ( qbk_ver(106u) >> *(line_comment | (cl::anychar_p - (cl::eol_p | '[' | ']'))) - | qbk_before(106u) + | qbk_ver(0, 106u) >> *(line_comment | (cl::anychar_p - (cl::eol_p | "[/"))) ) >> *eol - ] [actions.element] + ] [element] ; local.element @@ -415,27 +494,28 @@ namespace quickbook | elements [ph::var(local.info) = ph::arg1] >> (cl::eps_p - (cl::alnum_p | '_')) ) - >> local.process_element() - [ actions.values.list(ph::var(local.info.tag)) + >> process_element() + [ state.values.list(ph::var(local.info.tag)) [ cl::lazy_p(*ph::var(local.info.rule)) >> space >> ']' - ] [actions.element] + ] [element] ] ; local.code = - ( - local.code_line + state.values.list(code_tags::code_block) + [( local.code_line >> *(*local.blank_line >> local.code_line) - ) [actions.code] + ) [state.values.entry(ph::arg1, ph::arg2)] + ] [element] >> *eol ; local.code_line = ( *cl::blank_p >> ~cl::eps_p(cl::eol_p) - ) [local.check_code_block] + ) [check_code_block] >> cl::eps_p(ph::var(local.block_type) == block_types::code) >> *(cl::anychar_p - cl::eol_p) >> (cl::eol_p | cl::end_p) @@ -455,61 +535,61 @@ namespace quickbook | local.simple_markup | escape | comment - | qbk_since(106u) >> local.square_brackets - | cl::space_p [actions.raw_char] - | cl::anychar_p [actions.plain_char] + | qbk_ver(106u) >> local.square_brackets + | cl::space_p [raw_char] + | cl::anychar_p [plain_char] ; local.square_brackets = - ( cl::ch_p('[') [actions.plain_char] + ( cl::ch_p('[') [plain_char] >> paragraph_phrase - >> ( cl::ch_p(']') [actions.plain_char] - | cl::eps_p [actions.error("Missing close bracket")] + >> ( cl::ch_p(']') [plain_char] + | cl::eps_p [error("Missing close bracket")] ) - | cl::ch_p(']') [actions.plain_char] - >> cl::eps_p [actions.error("Mismatched close bracket")] + | cl::ch_p(']') [plain_char] + >> cl::eps_p [error("Mismatched close bracket")] ) ; local.macro = cl::eps_p - ( ( actions.macro + ( ( state.macro >> ~cl::eps_p(cl::alpha_p | '_') // must not be followed by alpha or underscore ) & macro_identifier // must be a valid macro for the current version ) - >> actions.macro [actions.do_macro] + >> state.macro [do_macro] ; local.template_ = ( '[' >> space - >> actions.values.list(template_tags::template_) - [ !cl::str_p("`") [actions.values.entry(ph::arg1, ph::arg2, template_tags::escape)] + >> state.values.list(template_tags::template_) + [ !cl::str_p("`") [state.values.entry(ph::arg1, ph::arg2, template_tags::escape)] >> ( cl::eps_p(cl::punct_p) - >> actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] - | actions.templates.scope [actions.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] + >> state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] + | state.templates.scope [state.values.entry(ph::arg1, ph::arg2, template_tags::identifier)] >> cl::eps_p(hard_space) ) >> space >> !local.template_args >> ']' ] - ) [actions.element] + ) [element] ; local.template_args = - qbk_since(105u) >> local.template_args_1_5 - | qbk_before(105u) >> local.template_args_1_4 + qbk_ver(105u) >> local.template_args_1_5 + | qbk_ver(0, 105u) >> local.template_args_1_4 ; local.template_args_1_4 = local.template_arg_1_4 >> *(".." >> local.template_arg_1_4); local.template_arg_1_4 = ( cl::eps_p(*cl::blank_p >> cl::eol_p) - >> local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)] - | local.template_inner_arg_1_4 [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] + >> local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::block)] + | local.template_inner_arg_1_4 [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] ) ; @@ -525,8 +605,8 @@ namespace quickbook local.template_arg_1_5 = ( cl::eps_p(*cl::blank_p >> cl::eol_p) - >> local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::block)] - | local.template_arg_1_5_content [actions.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] + >> local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::block)] + | local.template_arg_1_5_content [state.values.entry(ph::arg1, ph::arg2, template_tags::phrase)] ) ; @@ -548,48 +628,55 @@ namespace quickbook >> "br" >> space >> ']' - ) [actions.break_] + ) [break_] ; local.inline_code = - '`' >> - ( + '`' >> state.values.list(code_tags::inline_code) + [( *(cl::anychar_p - ( '`' | (cl::eol_p >> *cl::blank_p >> cl::eol_p) // Make sure that we don't go ) // past a single block ) >> cl::eps_p('`') - ) [actions.inline_code] + ) [state.values.entry(ph::arg1, ph::arg2)] >> '`' + ] [element] ; local.code_block = "```" >> ~cl::eps_p("`") - >> *(*cl::blank_p >> cl::eol_p) - >> ( *( "````" >> *cl::ch_p('`') - | ( cl::anychar_p - - (*cl::space_p >> "```" >> ~cl::eps_p("`")) - ) - ) - >> !(*cl::blank_p >> cl::eol_p) - ) [actions.code_block] - >> ( *cl::space_p >> "```" - | cl::eps_p [actions.error("Unfinished code block")] + >> ( state.values.list(code_tags::inline_code_block) + [ *(*cl::blank_p >> cl::eol_p) + >> ( *( "````" >> *cl::ch_p('`') + | ( cl::anychar_p + - (*cl::space_p >> "```" >> ~cl::eps_p("`")) + ) + ) + >> !(*cl::blank_p >> cl::eol_p) + ) [state.values.entry(ph::arg1, ph::arg2)] + >> (*cl::space_p >> "```") + ] [element] + | cl::eps_p [error("Unfinished code block")] + >> *cl::anychar_p ) | "``" >> ~cl::eps_p("`") - >> *(*cl::blank_p >> cl::eol_p) - >> ( *( "```" >> *cl::ch_p('`') - | ( cl::anychar_p - - (*cl::space_p >> "``" >> ~cl::eps_p("`")) - ) - ) - >> !(*cl::blank_p >> cl::eol_p) - ) [actions.code_block] - >> ( *cl::space_p >> "``" - | cl::eps_p [actions.error("Unfinished code block")] + >> ( state.values.list(code_tags::inline_code_block) + [ *(*cl::blank_p >> cl::eol_p) + >> ( *( "```" >> *cl::ch_p('`') + | ( cl::anychar_p + - (*cl::space_p >> "``" >> ~cl::eps_p("`")) + ) + ) + >> !(*cl::blank_p >> cl::eol_p) + ) [state.values.entry(ph::arg1, ph::arg2)] + >> (*cl::space_p >> "``") + ] [element] + | cl::eps_p [error("Unfinished code block")] + >> *cl::anychar_p ) ; @@ -606,22 +693,22 @@ namespace quickbook // by space or punctuation or the // mark character or a the start. ] - >> actions.values.save() + >> state.values.save() [ - actions.to_value() + to_value() [ - cl::eps_p((actions.macro & macro_identifier) >> local.simple_markup_end) - >> actions.macro [actions.do_macro] + cl::eps_p((state.macro & macro_identifier) >> local.simple_markup_end) + >> state.macro [do_macro] | ~cl::eps_p(cl::f_ch_p(local.simple_markup.mark)) >> +( ~cl::eps_p ( lookback [~cl::f_ch_p(local.simple_markup.mark)] >> local.simple_markup_end ) - >> cl::anychar_p [actions.plain_char] + >> cl::anychar_p [plain_char] ) ] >> cl::f_ch_p(local.simple_markup.mark) - [actions.simple_markup] + [simple_markup] ] ; @@ -643,37 +730,58 @@ namespace quickbook ; escape = - cl::str_p("\\n") [actions.break_] + cl::str_p("\\n") [break_] | cl::str_p("\\ ") // ignore an escaped space - | '\\' >> cl::punct_p [actions.plain_char] + | '\\' >> cl::punct_p [plain_char] | "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | ("'''" >> !eol) - >> actions.values.save() - [ (*(cl::anychar_p - "'''")) [actions.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)] + >> state.values.save() + [ (*(cl::anychar_p - "'''")) [state.values.entry(ph::arg1, ph::arg2, phrase_tags::escape)] >> ( cl::str_p("'''") - | cl::eps_p [actions.error("Unclosed boostbook escape.")] - ) [actions.element] + | cl::eps_p [error("Unclosed boostbook escape.")] + ) [element] ] ; raw_escape = - cl::str_p("\\n") [actions.error("Newlines invalid here.")] + cl::str_p("\\n") [error("Newlines invalid here.")] | cl::str_p("\\ ") // ignore an escaped space - | '\\' >> cl::punct_p [actions.raw_char] + | '\\' >> cl::punct_p [raw_char] | "\\u" >> cl::repeat_p(4) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] + [escape_unicode] | "\\U" >> cl::repeat_p(8) [cl::chset<>("0-9a-fA-F")] - [actions.escape_unicode] - | ('\\' >> cl::anychar_p) [actions.error("Invalid escape.")] - [actions.raw_char] - | ("'''" >> !eol) [actions.error("Boostbook escape invalid here.")] + [escape_unicode] + | ('\\' >> cl::anychar_p) [error("Invalid escape.")] + [raw_char] + | ("'''" >> !eol) [error("Boostbook escape invalid here.")] >> (*(cl::anychar_p - "'''")) >> ( cl::str_p("'''") - | cl::eps_p [actions.error("Unclosed boostbook escape.")] - ) [actions.element] + | cl::eps_p [error("Unclosed boostbook escape.")] + ) [element] + ; + + attribute_value_1_7 = + *( ~cl::eps_p(']' | cl::space_p | comment) + >> ( cl::eps_p + ( cl::ch_p('[') + >> space + >> ( cl::eps_p(cl::punct_p) + >> elements + | elements + >> (cl::eps_p - (cl::alnum_p | '_')) + ) + ) [error("Elements not allowed in attribute values.")] + >> local.square_brackets + | local.template_ + | cl::eps_p(cl::ch_p('[')) [error("Unmatched template in attribute value.")] + >> local.square_brackets + | raw_escape + | cl::anychar_p [raw_char] + ) + ) ; // @@ -681,22 +789,22 @@ namespace quickbook // command_line = - actions.values.list(block_tags::macro_definition) + state.values.list(block_tags::macro_definition) [ *cl::space_p >> local.command_line_macro_identifier - [actions.values.entry(ph::arg1, ph::arg2)] + [state.values.entry(ph::arg1, ph::arg2)] >> *cl::space_p >> !( '=' >> *cl::space_p - >> actions.to_value() [ inline_phrase ] + >> to_value() [ inline_phrase ] >> *cl::space_p ) >> cl::end_p - ] [actions.element] + ] [element] ; local.command_line_macro_identifier = - qbk_since(106u) + qbk_ver(106u) >> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']' | '=')) | +(cl::anychar_p - (cl::space_p | ']' | '=')) ; @@ -745,9 +853,9 @@ namespace quickbook ; macro_identifier = - qbk_since(106u) + qbk_ver(106u) >> +(cl::anychar_p - (cl::space_p | '[' | '\\' | ']')) - | qbk_before(106u) + | qbk_ver(0, 106u) >> +(cl::anychar_p - (cl::space_p | ']')) ; } @@ -819,8 +927,8 @@ namespace quickbook else { while (!list_stack.top().root && new_indent < list_stack.top().indent) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); list_indent = list_stack.top().indent; } @@ -853,8 +961,8 @@ namespace quickbook new_indent > list_stack.top().indent); if (new_indent <= list_stack.top().indent2) { - actions_.end_list_item(); - actions_.end_list(save.mark); + state_.end_list_item(); + state_.end_list(save.mark); list_indent = list_stack.top().indent; } else { @@ -889,44 +997,44 @@ namespace quickbook if (list_stack.top().root || new_indent > list_indent) { list_stack.push(list_stack_item(mark, new_indent, new_indent2)); - actions_.start_list(mark); + state_.start_list(mark); } else if (new_indent == list_indent) { - actions_.end_list_item(); + state_.end_list_item(); } else { // This should never reach root, since the first list // has indentation 0. while(!list_stack.top().root && new_indent < list_stack.top().indent) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); } - actions_.end_list_item(); + state_.end_list_item(); } list_indent = new_indent; if (mark != list_stack.top().mark) { - detail::outerr(actions_.current_file, first) + detail::outerr(state_.current_file, first) << "Illegal change of list style.\n"; - detail::outwarn(actions_.current_file, first) + detail::outwarn(state_.current_file, first) << "Ignoring change of list style." << std::endl; - ++actions_.error_count; + ++state_.error_count; } - actions_.start_list_item(); + state_.start_list_item(); block_type = block_types::list; } void main_grammar_local::clear_stack() { while (!list_stack.top().root) { - actions_.end_list_item(); - actions_.end_list(list_stack.top().mark); + state_.end_list_item(); + state_.end_list(list_stack.top().mark); list_stack.pop(); } } |