From 8ea2b63ef3af238191571c4cc41d7d88f7ac934b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Mon, 5 Sep 2005 01:50:41 +0000 Subject: [PATCH] initial import of regression testing mechanism for quickbook. (Note: has known annoyances and limitations) [SVN r30806] --- test/Jamfile.v2 | 15 + test/quickbook-testing.jam | 35 + test/test1.gold | 2260 ++++++++++++++++++++++++++++++++++++ test/test1.qbk | 1771 ++++++++++++++++++++++++++++ test/text_diff.cpp | 84 ++ 5 files changed, 4165 insertions(+) create mode 100644 test/Jamfile.v2 create mode 100644 test/quickbook-testing.jam create mode 100644 test/test1.gold create mode 100644 test/test1.qbk create mode 100644 test/text_diff.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 0000000..12b1fb3 --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,15 @@ +# +# Copyright (c) 2005 João Abecasis +# +# Distributed under 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) +# + +project test ; + +import quickbook-testing : quickbook-test ; + +test-suite quickbook.test : + [ quickbook-test test1 ] + ; diff --git a/test/quickbook-testing.jam b/test/quickbook-testing.jam new file mode 100644 index 0000000..ab9fde4 --- /dev/null +++ b/test/quickbook-testing.jam @@ -0,0 +1,35 @@ +# +# Copyright (c) 2005 João Abecasis +# +# Distributed under 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) +# + +import testing ; +import project ; + +# +# quickbook-test - generates a test for quickbook itself. A quickbook-test is +# actually made up of two tests: +# $(target-name) : generate boostbook from $(source) or $(target-name).qbk +# $(target-name).diff : compare generated boostbook to $(target-name).gold +# +# Known Issues: +# * FIXME: quickbook gets generated for each test +# * FIXME: text_diff gets generated for each test +# * FIXME: text_diff will fail on dates, and other variable output +# +rule quickbook-test ( target-name : source ? : requirements * ) +{ + local project = [ project.current ] ; + source ?= $(target-name).qbk ; + + return + [ testing.make-test boostbook : $(source) : $(requirements) + : $(target-name) ] + + [ run text_diff.cpp : : $(target-name) $(target-name).gold + : $(requirements) : $(target-name).diff : $(default-build) ] + ; +} diff --git a/test/test1.gold b/test/test1.gold new file mode 100644 index 0000000..0cd0076 --- /dev/null +++ b/test/test1.gold @@ -0,0 +1,2260 @@ + + + + + + Joelde Guzman + + + EricNiebler + + + 20022004Joel de Guzman, Eric Niebler + + + + Distributed under 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 ) + + + + WikiWiki style documentation tool + + quickbook 1.1 +
+ Introduction +
+ + "Why program by hand in five days what + you can spend five years of your life automating?" + -- Terrence Parr, author ANTLR/PCCTS + +
+ + Well, QuickBook started as a weekend hack. It was originally intended to be + a sample application using Spirit + . What is it? What you are viewing now, this documentation, is autogenerated + by QuickBook. These files were generated from one master: + +
+ + quickbook.qbk + +
+ + Originally named QuickDoc, this funky tool that never dies evolved into a funkier + tool thanks to Eric Niebler who resurrected the project making it generate + BoostBook + instead of HTML. The + BoostBookdocumentation format is an extension of + DocBook, an SGML or XML based format for describing documentation. + + + QuickBook is a WikiWiki style documentation tool geared towards C++ documentation + using simple rules and markup for simple formatting tasks. QuickBook extends + the WikiWiki concept. Like the WikiWiki, QuickBook documents are simple text + files. A single QuickBook document can generate a fully linked set of nice + HTML and PostScript/PDF documents complete with images and syntax- colorized + source code. + + + Features include: + + + + generate BoostBook + xml, to generate HTML, PostScript and PDF + + + simple markup to link to Doxygen-generated entities + + + macro system for simple text substitution + + + simple markup for italics, bold, preformatted, blurbs, code samples, tables, + URLs, anchors, images, etc. + + + automatic syntax coloring of code samples + + + CSS support + + +
+
+ Syntax Summary + + A QuickBook document is composed of one or more blocks. An example of a block + is the paragraph or a C++ code snippet. Some blocks have special mark-ups. + Blocks, except code snippets which have their own grammar (C++ or Python), + are composed of one or more phrases. A phrase can be a simple contiguous run + of characters. Phrases can have special mark-ups. Marked up phrases can recursively + contain other phrases, but cannot contain blocks. A terminal is a self contained + block-level or phrase-level element that does not nest anything. + + + Blocks, in general, are delimited by two end-of-lines (the block terminator). + Phrases in each block cannot contain a block terminator. This way, syntax errors + such as un-matched closing brackets do not go haywire and corrupt anything + past a single block. + Comments + + Can be placed anywhere. + +[/ comment (no output generated) ] + + Phrase + Level Elements + Font Styles +['italic], [*bold], [_underline], [^teletype], [-strikethrough] + + + will generate: + + + italic, bold, underline, teletype, strikethrough + + + Like all non-terminal phrase level elements, this can of course be nested: + +[*['bold-italic]] + + + will generate: + + + bold-italic + + Simple formatting + + Simple markup for formatting text, common in many applications, is now supported: + +/italic/, *bold*, _underline_, =teletype=, -strikethrough- + + + will generate: + + + italic, bold, underline, teletype, strikethrough + + + Unlike QuickBook's standard formatting scheme, the rules for simpler alternatives + are much stricter. + + + + Simple markups cannot nest. You can combine a simple markup with a nestable + markup. + + + A non-space character must follow the leading markup + + + A non-space character must precede the trailing markup + + + A space or a punctuation must follow the trailing markup + + + If the matching markup cannot be found within a line, the formatting will + not be applied. This is to ensure that un-matched formatting markups, which + can be a common mistake, does not corrupt anything past a single line. We + do not want the rest of the document to be rendered bold just because we + forgot a trailing '*'. + + + A line starting with the star will be interpreted as an unordered list. See + Unordered lists. + + + + More Formatting Samples + + + + + MarkupResult + + + + + *Bold* + Bold + + + *Is bold* + Is bold + + + * Not bold* *Not bold * * Not bold * + * Not bold* *Not bold * * Not bold * + + + This*Isn't*Bold (no bold)This*Isn't*Bold + (no bold) + + + (*Bold Inside*) (parenthesis not bold) + (Bold Inside) (parenthesis not + bold) + + + *(Bold Outside)* (parenthesis bold) + (Bold Outside)(parenthesis bold) + + + + 3*4*5 = 60 (no bold)3*4*5 = + 60 (no bold) + + + 3 * 4 * 5 = 60 (no bold)3 * + 4 * 5 = 60 (no bold) + + + 3 *4* 5 = 60 (4 is bold)3 45 = 60 (4 is bold) + + + *This is bold* this is not *but this is* + This is boldthis is not but this is + + + *This is bold*. + This is bold. + + + *B*. (bold B) + B. (bold B) + + + ['*Bold-Italic*]Bold-Italic + + + + + + + + + + + Thanks to David Barrett, + author of + Qwiki, for sharing these samples and teaching me these obscure + formatting rules. I wasn't sure at all if + Spirit, being more or less a formal EBNF parser, can handle the + context sensitivity and ambiguity. + + + + + Inline code + + Inlining code in paragraphs is quite common when writing C++ documentation. + We provide a very simple markup for this. For example, this: + +This text has inlined code `int main() { return 0; }` in it. + + + will generate: + + + This text has inlined code + + intmain + (){return0 + ;} + in it. The code will be syntax highlighted. + + + + + + + + Note that we simply enclose + the code with the tick: "`", not the single quote: + + "'" + . Note too that `some code`is prefered over + [^some code]. + + + + + Source Mode + + If a document contains more than one type of source code then the source mode + may be changed dynamically as the document is processed. All QuickBook documents + are initially in C++ mode by default, though an alternative initial value may + be set in the Document Infosection. + + + To change the source mode, use the [source-mode]markup, + where source-modeis one of the supported modes. For example, + this: + +Python's [python] `import` is rather like C++'s [c++] `#include`. A +C++ comment `// looks like this` whereas a Python comment [python] +`# looks like this`. + + + will generate: + + + Python's + + import + is rather like C++'s + + #include + . A C++ comment + + // looks like this + whereas a Python comment + + #looks like this + . + + + Supported Source Modes + + + + + ModeSource Mode Markup + + + + + C++[c++] + + + Python[python] + + + + + + + + + + + The source mode strings + are lowercase. + + + + + line-break +[br] + + + + + + + + Note that + + \n + is now preferred over + + [br + ] + . + + + + Anchors + +[#named_anchor] + + + A named anchor is a hook that can be referenced by a link elsewhere in the + document. You can then reference an anchor with [link named_anchor + Some link text]. More on anchors + here, hereand + here. + Links +[@http://www.boost.org this is [*boost's] website....] + + + will generate: + + + this is boost's + website.... + + + URL links where the link text is the link itself is common. Example: + +see http://spirit.sourceforge.net/ + + + so, when the text is absent in a link markup, the URL is assumed. Example: + +see [@http://spirit.sourceforge.net/] + + + will generate: + + + see http://spirit.sourceforge.net/ + + Anchor + links + + You can link within a document using: + +[link section_id.normalized_header_text The link text] + + + See sections Sectionand + Headingsfor more info. + refentry + links + + In addition, you can link internally to an XML refentry like: + +[link xml.refentry The link text] + + + This gets converted into <link linkend="xml.refentry" + >The link text</link>. + + + Like URLs, the link text is optional. If this is not present, the link text + will automatically be the refentry. Example: + +[link xml.refentry] + + + This gets converted into <link linkend="xml.refentry" + >xml.refentry</link>. + function, class, member, enum or header links + + If you want to link to a function, class, member, enum or header in the reference + section, you can use: + +[funcref fully::qualified::function_name The link text] +[classref fully::qualified::class_name The link text] +[memberref fully::qualified::member_name The link text] +[enumref fully::qualified::enum_name The link text] +[headerref path/to/header.hpp The link text] + + + Again, the link text is optional. If this is not present, the link text will + automatically be the function, class, member or enum. Example: + +[classref boost::bar::baz] + + + would have "boost::bar::baz" as the link text. + Escape + + The escape mark-up is used when we don't want to do any processing. + +''' +escape (no processing/formatting) +''' + + + Escaping allows us to pass XML markup to + BoostBookor DocBook. For + example: + +''' +<emphasis role="bold">This is direct XML markup</emphasis> +''' + + + This is direct XML markup + + + + + + + + Be careful when using the + escape. The text must conform to + BoostBook/DocBook + syntax. + + + + + Single char escape + + The backslash may be used to escape a single punctuation character. The punctuation + immediately after the backslash is passed without any processing. This is useful + when we need to escape QuickBook punctuations such as + + [ + and + + ] + . For example, how do you escape the triple quote? Simple: + \'\'\' + + + + \n + has a special meaning. It is used to generate line breaks. Note that + + \n + is now preferred over + + [br] + . + + Images (terminal) +[$image.jpg] + + Block + Level Elements + Document + + Every document must begin with a Document Info section, which should look like + this: + +[document-type The Document Title + [version 1.0] + [id the_document_name] + [dirname the_document_dir] + [copyright 2000 2002 2003 Joe Blow, Jane Doe] + [purpose The document's reason for being] + [category The document's category] + [authors [Blow, Joe], [Doe, Jane]] + [license The document's license] + [last-revision $Date: 2005/09/05 01:50:41 $] + [source-mode source-type] +] + + + Where document-type is one of: + + + + book + + + library + + + part + + + article + + + chapter + + + + and version, id, dirname + , copyright, purpose, category + , authors, license, + last-revisionand source-modeare optional information. + + + Here source-typeis a lowercase string setting the initial + source mode. If the source-mode + field is omitted, a default value of c++will be + used. + Section + + Starting a new section is accomplished with: + +[section:id The Section Title] + + + where idis optional. id will be the filename of the generated + section. If it is not present, "The Section Title" will be normalized + and become the id. Valid characters are a-Z, A-Z + , 0-9and _. All non-valid characters + are converted to underscore and all upper-case are converted to lower case. + Thus: "The Section Title" will be normalized to "the_section_title + ". + + + End a section with: + +[endsect] + + + Sections can nest, and that results in a hierarchy in the table of contents. + xinclude + + You can include another XML file with: + +[xinclude file.xml] + + + This is useful when file.xml has been generated by Doxygen and contains your + reference section. + Paragraphs + + + Paragraphs start left-flushed and are terminated by two or more newlines. No + markup is needed for paragraphs. QuickBook automatically detects paragraphs + from the context. + Ordered + lists +# One +# Two +# Three + + + will generate: + + + + One + + + Two + + + Three + + + List Hierarchies + + List hierarchies are supported. Example: + +# One +# Two +# Three + # Three.a + # Three.b + # Three.c +# Four + # Four.a + # Four.a.i + # Four.a.ii +# Five + + + will generate: + + + + One + + + Two + + + Three + + + Three.a + + + Three.b + + + Three.c + + + + + Fourth + + + Four.a + + + Four.a.i + + + Four.a.ii + + + + + + + Five + + + Long List Lines + + Long lines will be wrapped appropriately. Example: + +# A short item. +# A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. +# A short item. + + + + A short item. + + + A very long item. A very long item. A very long item. A very long item. A + very long item. A very long item. A very long item. A very long item. A very + long item. A very long item. A very long item. A very long item. A very long + item. A very long item. A very long item. + + + A short item. + + + Unordered lists +* First +* Second +* Third + + + will generate: + + + + First + + + Second + + + Third + + + Mixed lists + + Mixed lists (ordered and unordered) are supported. Example: + +# One +# Two +# Three + * Three.a + * Three.b + * Three.c +# Four + + + will generate: + + + + One + + + Two + + + Three + + + Three.a + + + Three.b + + + Three.c + + + + + Four + + + + And... + +# 1 + * 1.a + # 1.a.1 + # 1.a.2 + * 1.b +# 2 + * 2.a + * 2.b + # 2.b.1 + # 2.b.2 + * 2.b.2.a + * 2.b.2.b + + + will generate: + + + + 1 + + + 1.a + + + 1.a.1 + + + 1.a.2 + + + + + 1.b + + + + + 2 + + + 2.a + + + 2.b + + + 2.b.1 + + + 2.b.2 + + + 2.b.2.a + + + 2.b.2.b + + + + + + + + Code + + Preformatted code starts with a space or a tab. The code will be syntax highlighted + according to the current source mode + : + + + + + + +#include <iostream> + +int main() +{ + // Sample code + std::cout << "Hello, World\n"; + return 0; +} + + + + + + + +import cgi + +def cookForHtml(text): + '''"Cooks" the input text for HTML.''' + + return cgi.escape(text) + + + Macros that are already defined are expanded in source code. Example: + +[def __syntax_highlight__ [@quickbook/highlight.html syntax_highlight]] +[def __quickbook__ [@index.html quickbook]] + + using __quickbook__::__syntax_highlight__; + + + Generates: + + + +using quickbook::syntax_highlight; + + Preformatted + + + Sometimes, you don't want some preformatted text to be parsed as C++. In such + cases, use the [pre ... ]markup block. + +[pre + + Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + +] + + + Spaces, tabs and newlines are rendered as-is. Unlike all quickbook block level + markup, pre (and Code) are the only ones that allow multiple newlines. The + markup above will generate: + +Some preformatted text Some preformatted text + + Some preformatted text Some preformatted text + + Some preformatted text Some preformatted text + + + + Notice that unlike Code, phrase markup such as font style is still permitted + inside preblocks. + Blockquote + +[:sometext...] + +
+ + Indents the paragraph. This applies to one paragraph only. + +
Headings + +[h1 Heading 1] +[h2 Heading 2] +[h3 Heading 3] +[h4 Heading 4] +[h5 Heading 5] +[h6 Heading 6] + + Heading 1 + Heading 2 + Heading 3 + Heading 4 + Heading 5 + Heading 6 + + Headings 1-3 [h1 h2 and h3] will automatically have anchors with normalized + names with name="section_id.normalized_header_text" + (i.e. valid characters are a-z, A-Z, + 0-9and _. All non-valid characters are + converted to underscore and all upper-case are converted to lower-case. For + example: Heading 1 in section Section 2 will be normalized to section_2.heading_1 + ). You can use: + +[link section_id.normalized_header_text The link text] + + + to link to them. See Anchor links + and Sectionfor more info. + Macros +[def macro_identifier some text] + + + When a macro is defined, the identifier replaces the text anywhere in the file, + in paragraphs, in markups, etc. macro_identifier is a string of non-white space + characters except ']' while the replacement text can be any phrase (even marked + up). Example: + +[def sf_logo [$http://sourceforge.net/sflogo.php?group_id=28447&type=1]] +sf_logo + + + Now everywhere the sf_logo is placed, the picture will be inlined. + + + + + + + + + + + + It's a good idea to use + macro identifiers that are distinguishable. For instance, in this document, + macro identifiers have two leading and trailing underscores (e.g. + __spirit__). The reason is to avoid unwanted macro replacement. + + + + + + + Links (URLS) and images are good candidates for macros. + 1) They tend to change a lot. It is a good idea to place all links + and images in one place near the top to make it easy to make changes. 2) The syntax is not pretty. It's easier to read and + write, e.g. __spirit__than [@http://spirit.sourceforge.net + Spirit]. + + + Some more examples: + +[def :-) [$theme/smiley.png]] +[def __spirit__ [@http://spirit.sourceforge.net Spirit]] + + + (See Imagesand + Links) + + + Invoking these macros: + +Hi __spirit__ :-) + + + will generate this: + + + Hi Spirit + + + + Predefined Macros + + Quickbook has some predefined macros that you can already use. + + + Predefined Macros + + + + + MacroMeaningExample + + + + + __DATE__Today's date2005-Sep-05 + + + + __TIME__The current time02:25:18 + AM + + + __FILENAME__Quickbook source filename + /home/joao/sandbox/boost/tools/quickbook/test/test1.qbk + + + + Blurbs + +[blurb :-) [*An eye catching advertisement or note...]\n\n + __spirit__ is an object-oriented recursive-descent parser generator framework + implemented using template meta-programming techniques. Expression templates + allow us to approximate the syntax of Extended Backus-Normal Form (EBNF) + completely in C++. +] + + + will generate this: + + + + + + + + + An eye catching advertisement or note...Spiritis an object-oriented + recursive-descent parser generator framework implemented using template + meta-programming techniques. Expression templates allow us to approximate + the syntax of Extended Backus-Normal Form (EBNF) completely in C++. + + + + + Tables + +[table A Simple Table + [[Heading 1] [Heading 2] [Heading 3]] + [[R0-C0] [R0-C1] [R0-C2]] + [[R1-C0] [R1-C1] [R1-C2]] + [[R2-C0] [R2-C1] [R2-C2]] +] + + + will generate: + + + A Simple Table + + + + + Heading 1Heading 2Heading 3 + + + + + R0-C0R0-C1R0-C2 + + + R2-C0R2-C1R2-C2 + + + R3-C0R3-C1R3-C2 + + + + + + The first row of the table is automatically treated as the table header; that + is, it is wrapped in <thead>...</thead>XML tags. + Note that unlike the original QuickDoc, the columns are nested in [ cells... + ]. The syntax is free-format and allows big cells to be formatted nicely. Example: + +[table Table with fat cells + [[Heading 1] [Heading 2]] + [ + [Row 0, Col 0: a small cell] + [ + Row 0, Col 1: + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + ] + ] + [ + [Row 1, Col 0: a small cell] + [Row 1, Col 1: a small cell] + ] +] + + + and thus: + + + Table with fat cells + + + + + Heading 1Heading 2 + + + + + Row 0, Col 0: a small cellRow 0, Col 1: A very + big cell...A very big cell...A very big cell... A very big cell...A very + big cell...A very big cell... A very big cell...A very big cell...A very + big cell... + + + Row 1, Col 0: a small cellRow 1, Col 1: a small + cell + + + + + Variable Lists +[variablelist A Variable List + [[term 1] [The definition of term 1]] + [[term 2] [The definition of term 2]] + [[term 3] [The definition of term 3]] +] + + + will generate: + + + A Variable Listterm 1 + + The definition of term 1 + term 2 + + The definition of term 2 + term 3 + + The definition of term 3 + + + + The rules for variable lists are the same as for tables, except that only 2 + "columns" are allowed. The first column contains the terms, and the + second column contains the definitions. Those familiar with HTML will recognize + this as a "definition list". + Include + + You can include one QuickBook file from another. The syntax is simply: + +[include someother.qbk] + + + The included file will be processed as if it had be cut and pasted into the + current document, with the following exceptions: + + + + The __FILENAME__ predefined macro will reflect the name of the file currently + being processed. + + + Any macros defined in the included file are scoped to that file. + + + + As the number of included QuickBook files grows, so too does the likelihood + of two sections having the same name. Since QuickBook generates an anchor for + each section based on the section name, it is possible to end up with two identically + named anchors, leading to link ambiguities. To resolve these ambiguities, the + [include]directive lets you specify a document id to use + for the included file. You can use it like this: + +[include:someid someother.qbk] + + + When using this form, all auto-generated anchors will use "someid" + as a unique prefix. So for instance, if there is a section in someother.qbk + named "Intro", the named anchor for that section will be "someid.intro + ", and you can link to it with [link someid.intro The Intro] + . + +
+
+ Quick Reference + + Syntax Compendium + + + + + To do this...Use this... + + + + + comment[/ some comment] + + + italics['italics] + or /italics/ + + + bold + [*bold] or *bold* + + + underline + [_underline] or _underline_ + + + teletype[^teletype] + or =teletype= + + + strikethrough + [-strikethrough] or -strikethrough- + + + source mode[c++]or + [python] + + + inline code`int main();` + + + line break[br] or \n + + + anchor[#anchor] + + + link[@http://www.boost.org Boost] + + + + anchor link[link section.anchor Link text] + + + + refentry link[link xml.refentry Link text] + + + + function link[funcref fully::qualified::function_name + Link text] + + + class link[classref fully::qualified::class_name + Link text] + + + member link[memberref fully::qualified::member_name + Link text] + + + enum link[enumref fully::qualified::enum_name + Link text] + + + header link[headerref path/to/header.hpp + Link text] + + + escape'''escaped text (no processing/formatting)''' + + + + single char escape\c + + + images[$image.jpg] + + + begin section[section The Section Title] + + + + end section[endsect] + + + paragraphNo markup. Paragraphs start left-flushed + and are terminated by two or more newlines. + + + ordered list# one# two# three + + + + unordered list* one* two* + three + + + codeNo markup. Preformatted code starts with a + space or a tab. + + + preformatted[pre preformatted] + + + + block quote[:sometext...] + + + heading 1[h1 Heading 1] + + + heading 2[h2 Heading 2] + + + heading 3[h3 Heading 3] + + + heading 4[h4 Heading 4] + + + heading 5[h5 Heading 5] + + + heading 6[h6 Heading 6] + + + macro[def macro_identifier some text] + + + + blurb[blurb advertisement or note...] + + + + table[table Title[[a][b][c]] + [[a][b][c]]] + + + variablelist[variablelist Title + [[a][b]][[a][b]]] + + + include[include someother.qbk] + + + + + +
+
+ Library Document Grammar + + + + + +doc_info = + space + >> '[' + >> ( str_p("book") + | "article" + | "library" + | "chapter" + | "part" + ) + >> hard_space + >> ( *(anychar_p - + (ch_p('[') | ']' | eol_p) + ) + ) + >> *( doc_version + | doc_id + | doc_dirname + | doc_copyright + | doc_purpose + | doc_category + | doc_authors + | doc_license + | doc_last_revision + ) + >> ']' >> +eol_p + ; + +doc_version = + space + >> "[version" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_id = + space + >> "[id" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_dirname = + space + >> "[dirname" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_copyright = + space + >> "[copyright" >> hard_space + >> +( repeat_p(4)[digit_p] + >> space + ) + >> space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_purpose = + space + >> "[purpose" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_category = + space + >> "[category" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_author = + space + >> '[' >> space + >> (*(anychar_p - ',')) + >> ',' >> space + >> (*(anychar_p - ']')) + >> ']' + ; + +doc_authors = + space + >> "[authors" >> hard_space + >> doc_author + >> *( ',' + >> doc_author + ) + >> ']' >> +eol_p + ; + +doc_license = + space + >> "[license" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_last_revision = + space + >> "[last-revision" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + +doc_source_mode = + space + >> "[source-mode" >> hard_space + >> ( + str_p("c++") + | "python" + ) + >> space >> ']' >> +eol_p + ; + +comment = + "[/" >> *(anychar_p - ']') >> ']' + ; + +space = + *(space_p | comment) + ; + +hard_space = + (eps_p - (alnum_p | '_')) >> space // must not be followed by + ; // alpha-numeric or underscore + + + +
+
+ QuickBook Grammar + + +library = + *(space_p | comment) >> blocks >> blank + ; + +blocks = + +( block_markup + | code + | list + | hr + | comment >> *eol + | paragraph + | eol + ) + ; + +space = + *(space_p | comment) + ; + +blank = + *(blank_p | comment) + ; + +eol = blank >> eol_p + ; + +close_bracket = + ']' | + if_p(var(is_not_preformatted)) + [ + eol_p >> eol_p // Make sure that we don't go + ] // past a single block, except + ; // when preformatted. + +hard_space = + (eps_p - (alnum_p | '_')) >> space // must not be followed by + ; // alpha-numeric or underscore + +comment = + "[/" >> *(anychar_p - ']') >> ']' + ; + +hr = + str_p("----") + >> *(anychar_p - eol) + >> +eol + ; + +block_markup = + '[' + >> ( begin_section + | end_section + | headings + | blurb + | blockquote + | preformatted + | def_macro + | table + | variablelist + | xinclude + | include + ) + >> ( (']' >> +eol) + | eps_p + ) + ; + +begin_section = + "section" + >> hard_space + >> (':' >> (*(alnum_p | '_')) + | eps_p + ) + >> (*(anychar_p - + close_bracket)) + ; + +end_section = + str_p("endsect") + ; + +headings = + h1 | h2 | h3 | h4 | h5 | h6 + ; + +h1 = "h1" >> hard_space >> phrase +h2 = "h2" >> hard_space >> phrase +h3 = "h3" >> hard_space >> phrase +h4 = "h4" >> hard_space >> phrase +h5 = "h5" >> hard_space >> phrase +h6 = "h6" >> hard_space >> phrase + +blurb = + "blurb" >> hard_space + >> phrase + ; + +blockquote = + ':' >> blank >> + phrase + ; + +preformatted = + "pre" >> hard_space + >> !eol >> phrase + >> eps_p + ; + +def_macro = + "def" >> hard_space + >> identifier + >> blank >> phrase + ; + +table = + "table" >> hard_space + >> (*(anychar_p - eol)) + >> +eol + >> *table_row + >> eps_p + ; + +table_row = + space + >> ch_p('[') + >> + ( + ( + *table_cell + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + +table_cell = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + +variablelist = + "variablelist" >> hard_space + >> (*(anychar_p - eol)) + >> +eol + >> *varlistentry + >> eps_p + ; + +varlistentry = + space + >> ch_p('[') + >> + ( + ( + varlistterm + >> +varlistitem + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + +varlistterm = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + +varlistitem = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + +xinclude = + "xinclude" + >> hard_space + >> (*(anychar_p - + close_bracket)) + ; + +include = + "include" + >> hard_space + >> + !( + ':' + >> (*((alnum_p | '_') - space_p)) + >> space + ) + >> (*(anychar_p - + close_bracket)) + ; + +identifier = + *(anychar_p - (space_p | ']')) + ; + +source_mode = + ( + str_p("c++") + | "python" + ) + ; + +code = + ( + code_line + >> *(*eol >> code_line) + ) + >> +eol + ; + +code_line = + ((ch_p(' ') | '\t')) + >> *(anychar_p - eol) >> eol + ; + +list = + eps_p(ch_p('*') | '#') >> + +( + (*blank_p + >> (ch_p('*') | '#')) + >> *blank_p + >> list_item + ) + ; + +list_item = + *( common + | (anychar_p - + ( eol_p >> *blank_p >> eps_p(ch_p('*') | '#') + | (eol >> eol) + ) + ) + ) + >> +eol + ; + +common = + self.actions.macro + | phrase_markup + | inline_code + | simple_format + | escape + | comment + ; + +inline_code = + '`' >> + ( + *(anychar_p - + ( '`' + | (eol >> eol) // Make sure that we don't go + ) // past a single block + ) >> eps_p('`') + ) + >> '`' + ; + +simple_format = + simple_bold + | simple_italic + | simple_underline + | simple_teletype + | simple_strikethrough + ; + +simple_bold = + '*' >> + ( + ( graph_p >> // graph_p must follow '*' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '*') // past a single line + ) + ) >> graph_p // graph_p must precede '*' + >> eps_p('*' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '*' + | ( + graph_p // A single char. e.g. *c* + >> eps_p('*' + >> (space_p | punct_p)) + ) + ) + >> '*' + ; + +simple_italic = + '/' >> + ( + ( graph_p >> // graph_p must follow '/' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '/') // past a single line + ) + ) >> graph_p // graph_p must precede '/' + >> eps_p('/' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '/' + | ( + graph_p // A single char. e.g. /c/ + >> eps_p('/' + >> (space_p | punct_p)) + ) + ) + >> '/' + ; + +simple_underline = + '_' >> + ( + ( graph_p >> // graph_p must follow '_' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '_') // past a single line + ) + ) >> graph_p // graph_p must precede '_' + >> eps_p('_' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '_' + | ( + graph_p // A single char. e.g. _c_ + >> eps_p('_' + >> (space_p | punct_p)) + ) + ) + >> '_' + ; + +simple_teletype = + '=' >> + ( + ( graph_p >> // graph_p must follow '=' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '=') // past a single line + ) + ) >> graph_p // graph_p must precede '=' + >> eps_p('=' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '=' + | ( + graph_p // A single char. e.g. =c= + >> eps_p('=' + >> (space_p | punct_p)) + ) + ) + >> '=' + ; + +simple_strikethrough = + '-' >> + ( + ( graph_p >> // graph_p must follow '-' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '-') // past a single line + ) + ) >> graph_p // graph_p must precede '-' + >> eps_p('-' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '-' + | ( + graph_p // A single char. e.g. =c= + >> eps_p('-' + >> (space_p | punct_p)) + ) + ) + >> '-' + ; + +paragraph = + *( common + | (anychar_p - // Make sure we don't go past + (eol >> eol) // a single block. + ) + ) + >> +eol + ; + +phrase = + *( common + | comment + | (anychar_p - + close_bracket) + ) + ; + +phrase_markup = + '[' + >> ( image + | url + | link + | anchor + | source_mode + | funcref + | classref + | memberref + | enumref + | headerref + | bold + | italic + | underline + | teletype + | strikethrough + | str_p("br") + ) + >> ']' + ; + +escape = + str_p("\\n") + | '\\' >> punct_p + | ( + "'''" >> !eol + >> *(anychar_p - "'''") + >> "'''" + ) + ; + +image = + '$' >> blank + >> (*(anychar_p - + close_bracket)) + ; + +url = + '@' + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +link = + "link" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +anchor = + '#' + >> blank + >> ( *(anychar_p - + close_bracket) + ) + ; + +funcref = + "funcref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +classref = + "classref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +memberref = + "memberref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +enumref = + "enumref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +headerref = + "headerref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + +bold = + ch_p('*') + >> blank >> phrase + ; + +italic = + ch_p('\'') + >> blank >> phrase + ; + +underline = + ch_p('_') + >> blank >> phrase + ; + +teletype = + ch_p('^') + >> blank >> phrase + ; + +strikethrough = + ch_p('-') + >> blank >> phrase + ; + + + +
+
+ C++ Syntax Highlighting Grammar + + +program + = + *( macro + | preprocessor + | comment + | keyword + | identifier + | special + | string_ + | char_ + | number + | space_p + | anychar_p + ) + ; + +macro + = *space_p >> self.macro + ; + +preprocessor + = *space_p >> '#' >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + +comment + = +(*space_p >> (comment_p("//") | comment_p("/*", "*/"))) + ; + +keyword + = *space_p >> keyword_ >> (eps_p - (alnum_p | '_')) + ; // make sure we recognize whole words only + +keyword_ + = "and_eq", "and", "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", "char", "class", + "compl", "const_cast", "const", "continue", "default", + "delete", "do", "double", "dynamic_cast", "else", + "enum", "explicit", "export", "extern", "false", + "float", "for", "friend", "goto", "if", "inline", + "int", "long", "mutable", "namespace", "new", "not_eq", + "not", "operator", "or_eq", "or", "private", + "protected", "public", "register", "reinterpret_cast", + "return", "short", "signed", "sizeof", "static", + "static_cast", "struct", "switch", "template", "this", + "throw", "true", "try", "typedef", "typeid", + "typename", "union", "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", "while", "xor_eq", "xor" + ; + +special + = *space_p >> +chset_p("~!%^&*()+={[}]:;,<.>?/|\\-") + ; + +string_ + = *space_p >> !as_lower_d['l'] >> confix_p('"', *c_escape_ch_p, '"') + ; + +char_ + = *space_p >> !as_lower_d['l'] >> confix_p('\'', *c_escape_ch_p, '\'') + ; + +number + = *space_p >> + ( as_lower_d["0x"] >> hex_p + | '0' >> oct_p + | real_p + ) + >> *as_lower_d[chset_p("ldfu")] + ; + +identifier + = *space_p >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + + + +
+
+ Python Syntax Highlighting Grammar + + + + + +program + = + *( macro + | comment + | keyword + | identifier + | special + | string_ + | number + | space_p + | anychar_p + ) + ; + +acro + = *space_p >> self.macro + ; + +comment + = +(*space_p >> comment_p("#")) + ; + +keyword + = *space_p >> keyword_ >> (eps_p - (alnum_p | '_')) + ; // make sure we recognize whole words only + +keyword_ + = + "and", "del", "for", "is", "raise", + "assert", "elif", "from", "lambda", "return", + "break", "else", "global", "not", "try", + "class", "except", "if", "or", "while", + "continue", "exec", "import", "pass", "yield", + "def", "finally", "in", "print", + + // Technically "as" and "None" are not yet keywords (at Python + // 2.4). They are destined to become keywords, and we treat them + // as such for syntax highlighting purposes. + + "as", "None" + ; + +special + = *space_p >> +chset_p("~!%^&*()+={[}]:;,<.>/|\\-") + ; + +string_prefix + = as_lower_d[str_p("u") >> ! str_p("r")] + ; + +string_ + = *space_p >> ! string_prefix >> (long_string | short_string) + ; + +short_string + = confix_p('"', * c_escape_ch_p, '"') | + confix_p('\'', * c_escape_ch_p, '\'') + ; + +long_string + = confix_p("'''", * lex_escape_ch_p, "'''") | + confix_p("\"\"\"", * lex_escape_ch_p, "\"\"\"") + ; + +number + = *space_p >> + ( + as_lower_d["0x"] >> hex_p + | '0' >> oct_p + | real_p + ) + >> *as_lower_d[chset_p("lj")] + ; + +identifier + = *space_p >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + + + +
+
\ No newline at end of file diff --git a/test/test1.qbk b/test/test1.qbk new file mode 100644 index 0000000..9f5722c --- /dev/null +++ b/test/test1.qbk @@ -0,0 +1,1771 @@ +[part quickbook + [version 1.1] + [authors [de Guzman, Joel], [Niebler, Eric]] + [copyright 2002 2004 Joel de Guzman, Eric Niebler] + [purpose WikiWiki style documentation tool] + [license + Distributed under 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 + ) + ] + [last-revision $Date$] +] + +[/ QuickBook Document version 1.1 ] +[/ Sept 24, 2002 ] +[/ Sept 2, 2004 ] +[/ Feb 14, 2005 ] + +[/ Some links] + +[def __note__ [$images/note.png]] +[def __alert__ [$images/alert.png]] +[def __tip__ [$images/tip.png]] +[def :-) [$images/smiley.png]] +[def __spirit__ [@http://spirit.sourceforge.net Spirit]] +[def __boostbook__ [@http://www.boost.org/doc/html/boostbook.html BoostBook]] +[def __docbook__ [@http://www.docbook.org/ DocBook]] + +[section:intro Introduction] + +[:[*['"Why program by hand in five days what you can spend five years of your +life automating?"]]\n\n-- Terrence Parr, author ANTLR/PCCTS] + +Well, QuickBook started as a weekend hack. It was originally intended to be a +sample application using __spirit__. What is it? What you are viewing now, this +documentation, is autogenerated by QuickBook. These files were generated from +one master: + +[:[@../quickbook.qbk quickbook.qbk]] + +Originally named QuickDoc, this funky tool that never dies evolved into a +funkier tool thanks to Eric Niebler who resurrected the project making it +generate __boostbook__ instead of HTML. The __boostbook__ documentation format +is an extension of __docbook__, an SGML or XML based format for describing +documentation. + +QuickBook is a WikiWiki style documentation tool geared towards C++ +documentation using simple rules and markup for simple formatting tasks. +QuickBook extends the WikiWiki concept. Like the WikiWiki, QuickBook documents are +simple text files. A single QuickBook document can generate a fully linked set +of nice HTML and PostScript/PDF documents complete with images and syntax- +colorized source code. + +Features include: + +* generate __boostbook__ xml, to generate HTML, PostScript and PDF +* simple markup to link to Doxygen-generated entities +* macro system for simple text substitution +* simple markup for italics, bold, preformatted, blurbs, code samples, + tables, URLs, anchors, images, etc. +* automatic syntax coloring of code samples +* CSS support + +[endsect] +[section:syntax Syntax Summary] + +A QuickBook document is composed of one or more blocks. An example of +a block is the paragraph or a C++ code snippet. Some blocks have +special mark-ups. Blocks, except code snippets which have their own +grammar (C++ or Python), are composed of one or more phrases. A phrase +can be a simple contiguous run of characters. Phrases can have special +mark-ups. Marked up phrases can recursively contain other phrases, but +cannot contain blocks. A terminal is a self contained block-level or +phrase-level element that does not nest anything. + +Blocks, in general, are delimited by two end-of-lines (the block terminator). +Phrases in each block cannot contain a block terminator. This way, syntax errors +such as un-matched closing brackets do not go haywire and corrupt anything past +a single block. + +[h2 Comments] + +Can be placed anywhere. + +[pre +'''[/ comment (no output generated) ]''' +] + +[h2 Phrase Level Elements] + +[h3 Font Styles] + +[pre''' +['italic], [*bold], [_underline], [^teletype], [-strikethrough] +'''] + +will generate: + +['italic], [*bold], [_underline], [^teletype], [-strikethrough] + +Like all non-terminal phrase level elements, this can of course be nested: + +[pre''' +[*['bold-italic]] +'''] + +will generate: + +[*['bold-italic]] + +[h3 Simple formatting] + +Simple markup for formatting text, common in many applications, is now supported: + +[pre''' +/italic/, *bold*, _underline_, =teletype=, -strikethrough- +'''] + +will generate: + +/italic/, *bold*, _underline_, =teletype=, -strikethrough- + +Unlike QuickBook's standard formatting scheme, the rules for simpler alternatives +are much stricter. + +* Simple markups cannot nest. You can combine a simple markup with a nestable markup. +* A non-space character must follow the leading markup +* A non-space character must precede the trailing markup +* A space or a punctuation must follow the trailing markup +* If the matching markup cannot be found within a line, the formatting + will not be applied. This is to ensure that un-matched formatting markups, + which can be a common mistake, does not corrupt anything past a single line. + We do not want the rest of the document to be rendered bold just because we + forgot a trailing '*'. +* A line starting with the star will be interpreted as an unordered list. + See [link syntax.unordered_lists Unordered lists]. + +[table More Formatting Samples + [[Markup] [Result]] + [[[^'''*Bold*''']] [*Bold*]] + [[[^'''*Is bold*''']] [*Is bold*]] + [[[^'''* Not bold* *Not bold * * Not bold *''']] [* Not bold* *Not bold * * Not bold *]] + [[[^'''This*Isn't*Bold (no bold)''']] [This*Isn't*Bold (no bold)]] + [[[^'''(*Bold Inside*) (parenthesis not bold)''']] [(*Bold Inside*) (parenthesis not bold)]] + [[[^'''*(Bold Outside)* (parenthesis bold)''']] [*(Bold Outside)* (parenthesis bold)]] + [[[^'''3*4*5 = 60 (no bold)''']] [3*4*5 = 60 (no bold)]] + [[[^'''3 * 4 * 5 = 60 (no bold)''']] [3 * 4 * 5 = 60 (no bold)]] + [[[^'''3 *4* 5 = 60 (4 is bold)''']] [3 *4* 5 = 60 (4 is bold)]] + [[[^'''*This is bold* this is not *but this is*''']][*This is bold* this is not *but this is*]] + [[[^'''*This is bold*.''']] [*This is bold*.]] + [[[^'''*B*. (bold B)''']] [*B*. (bold B)]] + [[[^'''['*Bold-Italic*]''']] [['*Bold-Italic*]]] +] + +[blurb __note__ Thanks to David Barrett, author of +[@http://quinthar.com/qwikiwiki/index.php?page=Home Qwiki], for sharing these samples +and teaching me these obscure formatting rules. I wasn't sure at all if __spirit__, +being more or less a formal EBNF parser, can handle the context sensitivity and ambiguity.] + +[h3 Inline code] + +Inlining code in paragraphs is quite common when writing C++ documentation. We +provide a very simple markup for this. For example, this: + +[pre''' +This text has inlined code `int main() { return 0; }` in it. +'''] + +will generate: + +This text has inlined code `int main() { return 0; }` in it. The code will be +syntax highlighted. + +[blurb __note__ +Note that we simply enclose the code with the tick: [^'''"`"'''], not the +single quote: `"'"`. Note too that [^'''`some code`'''] is prefered over +[^'''[^some code]''']. +] + +[h3 Source Mode] + +If a document contains more than one type of source code then the source mode +may be changed dynamically as the document is processed. All QuickBook +documents are initially in C++ mode by default, though an alternative initial value +may be set in the [link syntax.document Document Info] section. + +To change the source mode, use the [^\[source-mode\]] markup, where +=source-mode= is one of the supported modes. For example, this: + +[pre''' +Python's [python] `import` is rather like C++'s [c++] `#include`. A +C++ comment `// looks like this` whereas a Python comment [python] +`# looks like this`. +'''] + +will generate: + +Python's [python] `import` is rather like C++'s [c++] `#include`. A +C++ comment `// looks like this` whereas a Python comment [python] +`#looks like this`. + +[table Supported Source Modes + [[Mode] [Source Mode Markup]] + [[C++] [[^\[c++\]]]] + [[Python] [[^\[python\]]]] +] + +[blurb __note__ The source mode strings are lowercase.] + +[h3 line-break] + +[pre''' +[br] +'''] + +[blurb __note__ Note that `\n` is now preferred over `[br]`.] + +[h3 Anchors] + +[pre''' +[#named_anchor] +'''] + +A named anchor is a hook that can be referenced by a link elsewhere in the +document. You can then reference an anchor with [^'''[link named_anchor Some link text]''']. +More on anchors [link syntax.anchor_links here], [link syntax.section here] and +[link syntax.headings here]. + +[h3 Links] + +[pre''' +[@http://www.boost.org this is [*boost's] website....] +'''] + +will generate: + +[@http://www.boost.org this is [*boost's] website....] + +URL links where the link text is the link itself is common. Example: + +[pre''' +see http://spirit.sourceforge.net/ +'''] + +so, when the text is absent in a link markup, the URL is assumed. Example: + +[pre +see '''[@http://spirit.sourceforge.net/]''' +] + +will generate: + +see [@http://spirit.sourceforge.net/] + +[h3 Anchor links] + +You can link within a document using: + +[pre''' +[link section_id.normalized_header_text The link text] +'''] + +See sections [link syntax.section Section] and [link syntax.headings Headings] +for more info. + +[h3 refentry links] + +In addition, you can link internally to an XML refentry like: + +[pre''' +[link xml.refentry The link text] +'''] + +This gets converted into [^The link text]. + +Like URLs, the link text is optional. If this is not present, the link text will +automatically be the refentry. Example: + +[pre''' +[link xml.refentry] +'''] + +This gets converted into [^xml.refentry]. + +[h3 function, class, member, enum or header links] + +If you want to link to a function, class, member, enum or header in the reference +section, you can use: + +[pre''' +[funcref fully::qualified::function_name The link text] +[classref fully::qualified::class_name The link text] +[memberref fully::qualified::member_name The link text] +[enumref fully::qualified::enum_name The link text] +[headerref path/to/header.hpp The link text] +'''] + +Again, the link text is optional. If this is not present, the link text will +automatically be the function, class, member or enum. Example: + +[pre''' +[classref boost::bar::baz] +'''] + +would have "boost::bar::baz" as the link text. + +[h3 Escape] + +The escape mark-up is used when we don't want to do any processing. + +[pre +\'\'\' +escape (no processing/formatting) +\'\'\' +] + +Escaping allows us to pass XML markup to __boostbook__ or __docbook__. For example: + +[pre +\'\'\' +This is direct XML markup +\'\'\' +] + +''' +This is direct XML markup +''' + +[blurb __alert__ Be careful when using the escape. The text must conform to +__boostbook__/__docbook__ syntax.] + +[h3 Single char escape] + +The backslash may be used to escape a single punctuation character. The +punctuation immediately after the backslash is passed without any processing. +This is useful when we need to escape QuickBook punctuations such as `[` and `]`. +For example, how do you escape the triple quote? Simple: [^\\'\\'\\'] + +`\n` has a special meaning. It is used to generate line breaks. Note that `\n` +is now preferred over `[br]`. + +[h3 Images (terminal)] + +[pre''' +[$image.jpg] +'''] + +[h2 Block Level Elements] + +[h3 Document] + +Every document must begin with a Document Info section, which should look +like this: + +[pre''' +[document-type The Document Title + [version 1.0] + [id the_document_name] + [dirname the_document_dir] + [copyright 2000 2002 2003 Joe Blow, Jane Doe] + [purpose The document's reason for being] + [category The document's category] + [authors [Blow, Joe], [Doe, Jane]] + [license The document's license] + [last-revision $Date$] + [source-mode source-type] +] +'''] + +Where document-type is one of: + +* book +* library +* part +* article +* chapter + +and =version=, =id=, =dirname=, =copyright=, =purpose=, =category=, =authors=, +=license=, =last-revision= and =source-mode= are optional information. + +Here =source-type= is a lowercase string setting the initial +[link syntax.source_mode source mode]. If the =source-mode= field is omitted, a +default value of =c++= will be used. + +[h3 Section] + +Starting a new section is accomplished with: + +[pre''' +[section:id The Section Title] +'''] + +where /id/ is optional. id will be the filename of the generated section. +If it is not present, "The Section Title" will be normalized and become the id. +Valid characters are =a-Z=, =A-Z=, =0-9= and =_=. All non-valid characters are +converted to underscore and all upper-case are converted to lower case. +Thus: "The Section Title" will be normalized to "the_section_title". + +End a section with: + +[pre''' +[endsect] +'''] + +Sections can nest, and that results in a hierarchy in the table of contents. + +[h3 xinclude] + +You can include another XML file with: + +[pre''' +[xinclude file.xml] +'''] + +This is useful when file.xml has been generated by Doxygen and contains your +reference section. + +[h3 Paragraphs] + +Paragraphs start left-flushed and are terminated by two or more newlines. No +markup is needed for paragraphs. QuickBook automatically detects paragraphs from +the context. + +[h3 Ordered lists] + +[pre +# One +# Two +# Three +] + +will generate: + +# One +# Two +# Three + +[h3 List Hierarchies] + +List hierarchies are supported. Example: + +[pre +# One +# Two +# Three + # Three.a + # Three.b + # Three.c +# Four + # Four.a + # Four.a.i + # Four.a.ii +# Five +] + +will generate: + +# One +# Two +# Three + # Three.a + # Three.b + # Three.c +# Fourth + # Four.a + # Four.a.i + # Four.a.ii +# Five + +[h3 Long List Lines] + +Long lines will be wrapped appropriately. Example: + +[pre +# A short item. +# A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. +# A short item. +] + +# A short item. +# A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. + A very long item. A very long item. A very long item. +# A short item. + +[h3 Unordered lists] + +[pre''' +* First +* Second +* Third +'''] + +will generate: + +* First +* Second +* Third + +[h3 Mixed lists] + +Mixed lists (ordered and unordered) are supported. Example: + +[pre''' +# One +# Two +# Three + * Three.a + * Three.b + * Three.c +# Four +'''] + +will generate: + +# One +# Two +# Three + * Three.a + * Three.b + * Three.c +# Four + +And... + +[pre''' +# 1 + * 1.a + # 1.a.1 + # 1.a.2 + * 1.b +# 2 + * 2.a + * 2.b + # 2.b.1 + # 2.b.2 + * 2.b.2.a + * 2.b.2.b +'''] + +will generate: + +# 1 + * 1.a + # 1.a.1 + # 1.a.2 + * 1.b +# 2 + * 2.a + * 2.b + # 2.b.1 + # 2.b.2 + * 2.b.2.a + * 2.b.2.b + +[h3 Code] + +Preformatted code starts with a space or a tab. The code will be +syntax highlighted according to the current [link syntax.source_mode source mode]: + +[c++] + + #include + + int main() + { + // Sample code + std::cout << "Hello, World\n"; + return 0; + } + +[python] + + import cgi + + def cookForHtml(text): + '''"Cooks" the input text for HTML.''' + + return cgi.escape(text) + +Macros that are already defined are expanded in source code. Example: + +[pre''' +[def __syntax_highlight__ [@quickbook/highlight.html syntax_highlight]] +[def __quickbook__ [@index.html quickbook]] + + using __quickbook__::__syntax_highlight__; +'''] + +Generates: + +[def __syntax_highlight__ [@quickbook/highlight.html syntax_highlight]] +[def __quickbook__ [@index.html quickbook]] + + using __quickbook__::__syntax_highlight__; + +[h3 Preformatted] + +Sometimes, you don't want some preformatted text to be parsed as C++. In such +cases, use the [^[pre ... \]] markup block. + +[pre''' +[pre + + Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + +] +'''] + +Spaces, tabs and newlines are rendered as-is. Unlike all quickbook block level +markup, pre (and Code) are the only ones that allow multiple newlines. The +markup above will generate: + +[pre + +Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + + Some *preformatted* text Some *preformatted* text + +] + +Notice that unlike Code, phrase markup such as font style is still permitted +inside =pre= blocks. + +[h3 Blockquote] + +[pre +'''[:sometext...]''' +] + +[:Indents the paragraph. This applies to one paragraph only.] + +[h3 Headings] + +[pre''' +[h1 Heading 1] +[h2 Heading 2] +[h3 Heading 3] +[h4 Heading 4] +[h5 Heading 5] +[h6 Heading 6] +'''] + +[h1 Heading 1] +[h2 Heading 2] +[h3 Heading 3] +[h4 Heading 4] +[h5 Heading 5] +[h6 Heading 6] + +Headings 1-3 [h1 h2 and h3] will automatically have anchors with normalized +names with [^name="section_id.normalized_header_text"] (i.e. valid characters are +=a-z=, =A-Z=, =0-9= and =_=. All non-valid characters are converted to underscore +and all upper-case are converted to lower-case. For example: Heading +1 in section Section 2 will be normalized to [^section_2.heading_1]). You can use: + +[pre''' +[link section_id.normalized_header_text The link text] +'''] + +to link to them. See [link syntax.anchor_links Anchor links] and +[link syntax.section Section] for more info. + +[h3 Macros] + +[pre''' +[def macro_identifier some text] +'''] + +When a macro is defined, the identifier replaces the text anywhere in the file, +in paragraphs, in markups, etc. macro_identifier is a string of non-white space +characters except '\]' while the replacement text can be any phrase (even +marked up). Example: + +[pre''' +[def sf_logo [$http://sourceforge.net/sflogo.php?group_id=28447&type=1]] +sf_logo +'''] + +Now everywhere the sf_logo is placed, the picture will be inlined. + +[def sf_logo [$http://sourceforge.net/sflogo.php?group_id=28447&type=1]] +sf_logo + +[blurb __tip__ It's a good idea to use macro identifiers that are distinguishable. +For instance, in this document, macro identifiers have two leading and trailing +underscores (e.g. [^'''__spirit__''']). The reason is to avoid unwanted macro replacement.] + +Links (URLS) and images are good candidates for macros. *1*) They tend to +change a lot. It is a good idea to place all links and images in one place near the top +to make it easy to make changes. *2*) The syntax is not pretty. It's easier to read and +write, e.g. [^'''__spirit__'''] than [^'''[@http://spirit.sourceforge.net Spirit]''']. + +Some more examples: + +[pre''' +[def :-) [$theme/smiley.png]] +[def __spirit__ [@http://spirit.sourceforge.net Spirit]] +'''] + +(See [link syntax.images__terminal_ Images] +and [link syntax.links Links]) + +Invoking these macros: + +[pre''' +Hi __spirit__ :-) +'''] + +will generate this: + +Hi __spirit__ :-) + +[h3 Predefined Macros] + +Quickbook has some predefined macros that you can already use. + +[table Predefined Macros + [[Macro] [Meaning] [Example]] + [['''__DATE__'''] [Today's date] [__DATE__]] + [['''__TIME__'''] [The current time] [__TIME__]] + [['''__FILENAME__'''] [Quickbook source filename] [__FILENAME__]] +] + +[h3 Blurbs] + +[pre''' +[blurb :-) [*An eye catching advertisement or note...]\n\n + __spirit__ is an object-oriented recursive-descent parser generator framework + implemented using template meta-programming techniques. Expression templates + allow us to approximate the syntax of Extended Backus-Normal Form (EBNF) + completely in C++. +] +'''] + +will generate this: + +[blurb :-) [*An eye catching advertisement or note...]\n\n + __spirit__ is an object-oriented recursive-descent parser generator + framework implemented using template meta-programming techniques. Expression + templates allow us to approximate the syntax of Extended Backus-Normal Form + (EBNF) completely in C++. +] + +[h3 Tables] + +[pre''' +[table A Simple Table + [[Heading 1] [Heading 2] [Heading 3]] + [[R0-C0] [R0-C1] [R0-C2]] + [[R1-C0] [R1-C1] [R1-C2]] + [[R2-C0] [R2-C1] [R2-C2]] +] +'''] + +will generate: + +[table A Simple Table + [[Heading 1] [Heading 2] [Heading 3]] + [[R0-C0] [R0-C1] [R0-C2]] + [[R2-C0] [R2-C1] [R2-C2]] + [[R3-C0] [R3-C1] [R3-C2]] +] + +The first row of the table is automatically treated as the table header; that is, +it is wrapped in [^...] XML tags. Note that unlike the original QuickDoc, +the columns are nested in [ cells... ]. The syntax is free-format and allows big +cells to be formatted nicely. Example: + +[pre''' +[table Table with fat cells + [[Heading 1] [Heading 2]] + [ + [Row 0, Col 0: a small cell] + [ + Row 0, Col 1: + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + ] + ] + [ + [Row 1, Col 0: a small cell] + [Row 1, Col 1: a small cell] + ] +] +'''] + +and thus: + +[table Table with fat cells + [[Heading 1] [Heading 2]] + [ + [Row 0, Col 0: a small cell] + [ + Row 0, Col 1: + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + A very big cell...A very big cell...A very big cell... + ] + ] + [ + [Row 1, Col 0: a small cell] + [Row 1, Col 1: a small cell] + ] +] + +[h3 Variable Lists] + +[pre''' +[variablelist A Variable List + [[term 1] [The definition of term 1]] + [[term 2] [The definition of term 2]] + [[term 3] [The definition of term 3]] +] +'''] + +will generate: + +[variablelist A Variable List + [[term 1] [The definition of term 1]] + [[term 2] [The definition of term 2]] + [[term 3] [The definition of term 3]] +] + +The rules for variable lists are the same as for tables, except that +only 2 "columns" are allowed. The first column contains the terms, and +the second column contains the definitions. Those familiar with HTML +will recognize this as a "definition list". + +[h3 Include] + +You can include one QuickBook file from another. The syntax is simply: + +[pre''' +[include someother.qbk] +'''] + +The included file will be processed as if it had be cut and pasted +into the current document, with the following exceptions: + +* The '''__FILENAME__''' predefined macro will reflect the name of the + file currently being processed. +* Any macros defined in the included file are scoped to that file. + +As the number of included QuickBook files grows, so too does the +likelihood of two sections having the same name. Since QuickBook generates +an anchor for each section based on the section name, it is possible to +end up with two identically named anchors, leading to link ambiguities. +To resolve these ambiguities, the [^\[include\]] directive lets you +specify a document id to use for the included file. You can use it like +this: + +[pre''' +[include:someid someother.qbk] +'''] + +When using this form, all auto-generated anchors will use "someid" as +a unique prefix. So for instance, if there is a section in someother.qbk +named "Intro", the named anchor for that section will be "someid.intro", +and you can link to it with [^\[link someid.intro The Intro\]]. + +[endsect] +[section:ref Quick Reference] + +[table Syntax Compendium + [[To do this...] [Use this...]] + [[comment] [[^'''[/ some comment]''']]] + [[['italics]] [[^'''['italics] or /italics/''']]] + [[[*bold]] [[^'''[*bold] or *bold*''']]] + [[[_underline]] [[^'''[_underline] or _underline_''']]] + [[[^teletype]] [[^'''[^teletype] or =teletype=''']]] + [[[-strikethrough]] [[^'''[-strikethrough] or -strikethrough-''']]] + [[source mode] [[^\[c++\]] or [^\[python\]]]] + [[inline code] [[^'''`int main();`''']]] + [[line break] [[^'''[br] or \n''']]] + [[anchor] [[^'''[#anchor]''']]] + [[link] [[^'''[@http://www.boost.org Boost]''']]] + [[anchor link] [[^'''[link section.anchor Link text]''']]] + [[refentry link] [[^'''[link xml.refentry Link text]''']]] + [[function link] [[^'''[funcref fully::qualified::function_name Link text]''']]] + [[class link] [[^'''[classref fully::qualified::class_name Link text]''']]] + [[member link] [[^'''[memberref fully::qualified::member_name Link text]''']]] + [[enum link] [[^'''[enumref fully::qualified::enum_name Link text]''']]] + [[header link] [[^'''[headerref path/to/header.hpp Link text]''']]] + [[escape] [[^\'\'\'escaped text (no processing/formatting)\'\'\']]] + [[single char escape] [[^\\c]]] + [[images] [[^'''[$image.jpg]''']]] + [[begin section] [[^'''[section The Section Title]''']]] + [[end section] [[^'''[endsect]''']]] + [[paragraph] [No markup. Paragraphs start left-flushed and are terminated by two or more newlines.]] + [[ordered list] [[^# one\n# two\n# three\n]]] + [[unordered list] [[^\* one\n\* two\n\* three\n]]] + [[code] [No markup. Preformatted code starts with a space or a tab.]] + [[preformatted] [[^'''[pre preformatted]''']]] + [[block quote] [[^'''[:sometext...]''']]] + [[heading 1] [[^'''[h1 Heading 1]''']]] + [[heading 2] [[^'''[h2 Heading 2]''']]] + [[heading 3] [[^'''[h3 Heading 3]''']]] + [[heading 4] [[^'''[h4 Heading 4]''']]] + [[heading 5] [[^'''[h5 Heading 5]''']]] + [[heading 6] [[^'''[h6 Heading 6]''']]] + [[macro] [[^'''[def macro_identifier some text]''']]] + [[blurb] [[^'''[blurb advertisement or note...]''']]] + [[table] [[^[table Title\n \[\[a\]\[b\]\[c\]\]\n \[\[a\]\[b\]\[c\]\]\n\]]]] + [[variablelist] [[^[variablelist Title\n \[\[a\]\[b\]\]\n \[\[a\]\[b\]\]\n\]]]] + [[include] [[^'''[include someother.qbk]''']]] +] + +[endsect] +[section:docinfo Library Document Grammar] + +[c++] + + doc_info = + space + >> '[' + >> ( str_p("book") + | "article" + | "library" + | "chapter" + | "part" + ) + >> hard_space + >> ( *(anychar_p - + (ch_p('[') | ']' | eol_p) + ) + ) + >> *( doc_version + | doc_id + | doc_dirname + | doc_copyright + | doc_purpose + | doc_category + | doc_authors + | doc_license + | doc_last_revision + ) + >> ']' >> +eol_p + ; + + doc_version = + space + >> "[version" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_id = + space + >> "[id" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_dirname = + space + >> "[dirname" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_copyright = + space + >> "[copyright" >> hard_space + >> +( repeat_p(4)[digit_p] + >> space + ) + >> space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_purpose = + space + >> "[purpose" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_category = + space + >> "[category" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_author = + space + >> '[' >> space + >> (*(anychar_p - ',')) + >> ',' >> space + >> (*(anychar_p - ']')) + >> ']' + ; + + doc_authors = + space + >> "[authors" >> hard_space + >> doc_author + >> *( ',' + >> doc_author + ) + >> ']' >> +eol_p + ; + + doc_license = + space + >> "[license" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_last_revision = + space + >> "[last-revision" >> hard_space + >> (*(anychar_p - ']')) + >> ']' >> +eol_p + ; + + doc_source_mode = + space + >> "[source-mode" >> hard_space + >> ( + str_p("c++") + | "python" + ) + >> space >> ']' >> +eol_p + ; + + comment = + "[/" >> *(anychar_p - ']') >> ']' + ; + + space = + *(space_p | comment) + ; + + hard_space = + (eps_p - (alnum_p | '_')) >> space // must not be followed by + ; // alpha-numeric or underscore + +[endsect] +[section:quickbook QuickBook Grammar] + + library = + *(space_p | comment) >> blocks >> blank + ; + + blocks = + +( block_markup + | code + | list + | hr + | comment >> *eol + | paragraph + | eol + ) + ; + + space = + *(space_p | comment) + ; + + blank = + *(blank_p | comment) + ; + + eol = blank >> eol_p + ; + + close_bracket = + ']' | + if_p(var(is_not_preformatted)) + [ + eol_p >> eol_p // Make sure that we don't go + ] // past a single block, except + ; // when preformatted. + + hard_space = + (eps_p - (alnum_p | '_')) >> space // must not be followed by + ; // alpha-numeric or underscore + + comment = + "[/" >> *(anychar_p - ']') >> ']' + ; + + hr = + str_p("----") + >> *(anychar_p - eol) + >> +eol + ; + + block_markup = + '[' + >> ( begin_section + | end_section + | headings + | blurb + | blockquote + | preformatted + | def_macro + | table + | variablelist + | xinclude + | include + ) + >> ( (']' >> +eol) + | eps_p + ) + ; + + begin_section = + "section" + >> hard_space + >> (':' >> (*(alnum_p | '_')) + | eps_p + ) + >> (*(anychar_p - + close_bracket)) + ; + + end_section = + str_p("endsect") + ; + + headings = + h1 | h2 | h3 | h4 | h5 | h6 + ; + + h1 = "h1" >> hard_space >> phrase + h2 = "h2" >> hard_space >> phrase + h3 = "h3" >> hard_space >> phrase + h4 = "h4" >> hard_space >> phrase + h5 = "h5" >> hard_space >> phrase + h6 = "h6" >> hard_space >> phrase + + blurb = + "blurb" >> hard_space + >> phrase + ; + + blockquote = + ':' >> blank >> + phrase + ; + + preformatted = + "pre" >> hard_space + >> !eol >> phrase + >> eps_p + ; + + def_macro = + "def" >> hard_space + >> identifier + >> blank >> phrase + ; + + table = + "table" >> hard_space + >> (*(anychar_p - eol)) + >> +eol + >> *table_row + >> eps_p + ; + + table_row = + space + >> ch_p('[') + >> + ( + ( + *table_cell + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + + table_cell = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + + variablelist = + "variablelist" >> hard_space + >> (*(anychar_p - eol)) + >> +eol + >> *varlistentry + >> eps_p + ; + + varlistentry = + space + >> ch_p('[') + >> + ( + ( + varlistterm + >> +varlistitem + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + + varlistterm = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + + varlistitem = + space + >> ch_p('[') + >> + ( + ( + phrase + >> ch_p(']') + >> space + ) + | eps_p + ) + ; + + xinclude = + "xinclude" + >> hard_space + >> (*(anychar_p - + close_bracket)) + ; + + include = + "include" + >> hard_space + >> + !( + ':' + >> (*((alnum_p | '_') - space_p)) + >> space + ) + >> (*(anychar_p - + close_bracket)) + ; + + identifier = + *(anychar_p - (space_p | ']')) + ; + + source_mode = + ( + str_p("c++") + | "python" + ) + ; + + code = + ( + code_line + >> *(*eol >> code_line) + ) + >> +eol + ; + + code_line = + ((ch_p(' ') | '\t')) + >> *(anychar_p - eol) >> eol + ; + + list = + eps_p(ch_p('*') | '#') >> + +( + (*blank_p + >> (ch_p('*') | '#')) + >> *blank_p + >> list_item + ) + ; + + list_item = + *( common + | (anychar_p - + ( eol_p >> *blank_p >> eps_p(ch_p('*') | '#') + | (eol >> eol) + ) + ) + ) + >> +eol + ; + + common = + self.actions.macro + | phrase_markup + | inline_code + | simple_format + | escape + | comment + ; + + inline_code = + '`' >> + ( + *(anychar_p - + ( '`' + | (eol >> eol) // Make sure that we don't go + ) // past a single block + ) >> eps_p('`') + ) + >> '`' + ; + + simple_format = + simple_bold + | simple_italic + | simple_underline + | simple_teletype + | simple_strikethrough + ; + + simple_bold = + '*' >> + ( + ( graph_p >> // graph_p must follow '*' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '*') // past a single line + ) + ) >> graph_p // graph_p must precede '*' + >> eps_p('*' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '*' + | ( + graph_p // A single char. e.g. *c* + >> eps_p('*' + >> (space_p | punct_p)) + ) + ) + >> '*' + ; + + simple_italic = + '/' >> + ( + ( graph_p >> // graph_p must follow '/' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '/') // past a single line + ) + ) >> graph_p // graph_p must precede '/' + >> eps_p('/' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '/' + | ( + graph_p // A single char. e.g. /c/ + >> eps_p('/' + >> (space_p | punct_p)) + ) + ) + >> '/' + ; + + simple_underline = + '_' >> + ( + ( graph_p >> // graph_p must follow '_' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '_') // past a single line + ) + ) >> graph_p // graph_p must precede '_' + >> eps_p('_' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '_' + | ( + graph_p // A single char. e.g. _c_ + >> eps_p('_' + >> (space_p | punct_p)) + ) + ) + >> '_' + ; + + simple_teletype = + '=' >> + ( + ( graph_p >> // graph_p must follow '=' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '=') // past a single line + ) + ) >> graph_p // graph_p must precede '=' + >> eps_p('=' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '=' + | ( + graph_p // A single char. e.g. =c= + >> eps_p('=' + >> (space_p | punct_p)) + ) + ) + >> '=' + ; + + simple_strikethrough = + '-' >> + ( + ( graph_p >> // graph_p must follow '-' + *(anychar_p - + ( eol // Make sure that we don't go + | (graph_p >> '-') // past a single line + ) + ) >> graph_p // graph_p must precede '-' + >> eps_p('-' + >> (space_p | punct_p)) // space_p or punct_p must + ) // follow '-' + | ( + graph_p // A single char. e.g. =c= + >> eps_p('-' + >> (space_p | punct_p)) + ) + ) + >> '-' + ; + + paragraph = + *( common + | (anychar_p - // Make sure we don't go past + (eol >> eol) // a single block. + ) + ) + >> +eol + ; + + phrase = + *( common + | comment + | (anychar_p - + close_bracket) + ) + ; + + phrase_markup = + '[' + >> ( image + | url + | link + | anchor + | source_mode + | funcref + | classref + | memberref + | enumref + | headerref + | bold + | italic + | underline + | teletype + | strikethrough + | str_p("br") + ) + >> ']' + ; + + escape = + str_p("\\n") + | '\\' >> punct_p + | ( + "'''" >> !eol + >> *(anychar_p - "'''") + >> "'''" + ) + ; + + image = + '$' >> blank + >> (*(anychar_p - + close_bracket)) + ; + + url = + '@' + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + link = + "link" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + anchor = + '#' + >> blank + >> ( *(anychar_p - + close_bracket) + ) + ; + + funcref = + "funcref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + classref = + "classref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + memberref = + "memberref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + enumref = + "enumref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + headerref = + "headerref" >> hard_space + >> (*(anychar_p - + (']' | hard_space))) + >> ( eps_p(']') + | (hard_space >> phrase) + ) + ; + + bold = + ch_p('*') + >> blank >> phrase + ; + + italic = + ch_p('\'') + >> blank >> phrase + ; + + underline = + ch_p('_') + >> blank >> phrase + ; + + teletype = + ch_p('^') + >> blank >> phrase + ; + + strikethrough = + ch_p('-') + >> blank >> phrase + ; + +[endsect] +[section:highlight C++ Syntax Highlighting Grammar] + + program + = + *( macro + | preprocessor + | comment + | keyword + | identifier + | special + | string_ + | char_ + | number + | space_p + | anychar_p + ) + ; + + macro + = *space_p >> self.macro + ; + + preprocessor + = *space_p >> '#' >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + + comment + = +(*space_p >> (comment_p("//") | comment_p("/*", "*/"))) + ; + + keyword + = *space_p >> keyword_ >> (eps_p - (alnum_p | '_')) + ; // make sure we recognize whole words only + + keyword_ + = "and_eq", "and", "asm", "auto", "bitand", "bitor", + "bool", "break", "case", "catch", "char", "class", + "compl", "const_cast", "const", "continue", "default", + "delete", "do", "double", "dynamic_cast", "else", + "enum", "explicit", "export", "extern", "false", + "float", "for", "friend", "goto", "if", "inline", + "int", "long", "mutable", "namespace", "new", "not_eq", + "not", "operator", "or_eq", "or", "private", + "protected", "public", "register", "reinterpret_cast", + "return", "short", "signed", "sizeof", "static", + "static_cast", "struct", "switch", "template", "this", + "throw", "true", "try", "typedef", "typeid", + "typename", "union", "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", "while", "xor_eq", "xor" + ; + + special + = *space_p >> +chset_p("~!%^&*()+={[}]:;,<.>?/|\\-") + ; + + string_ + = *space_p >> !as_lower_d['l'] >> confix_p('"', *c_escape_ch_p, '"') + ; + + char_ + = *space_p >> !as_lower_d['l'] >> confix_p('\'', *c_escape_ch_p, '\'') + ; + + number + = *space_p >> + ( as_lower_d["0x"] >> hex_p + | '0' >> oct_p + | real_p + ) + >> *as_lower_d[chset_p("ldfu")] + ; + + identifier + = *space_p >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + +[endsect] +[section:pyhighlight Python Syntax Highlighting Grammar] + +[c++] + + program + = + *( macro + | comment + | keyword + | identifier + | special + | string_ + | number + | space_p + | anychar_p + ) + ; + + macro + = *space_p >> self.macro + ; + + comment + = +(*space_p >> comment_p("#")) + ; + + keyword + = *space_p >> keyword_ >> (eps_p - (alnum_p | '_')) + ; // make sure we recognize whole words only + + keyword_ + = + "and", "del", "for", "is", "raise", + "assert", "elif", "from", "lambda", "return", + "break", "else", "global", "not", "try", + "class", "except", "if", "or", "while", + "continue", "exec", "import", "pass", "yield", + "def", "finally", "in", "print", + + // Technically "as" and "None" are not yet keywords (at Python + // 2.4). They are destined to become keywords, and we treat them + // as such for syntax highlighting purposes. + + "as", "None" + ; + + special + = *space_p >> +chset_p("~!%^&*()+={[}]:;,<.>/|\\-") + ; + + string_prefix + = as_lower_d[str_p("u") >> ! str_p("r")] + ; + + string_ + = *space_p >> ! string_prefix >> (long_string | short_string) + ; + + short_string + = confix_p('"', * c_escape_ch_p, '"') | + confix_p('\'', * c_escape_ch_p, '\'') + ; + + long_string + = confix_p("'''", * lex_escape_ch_p, "'''") | + confix_p("\"\"\"", * lex_escape_ch_p, "\"\"\"") + ; + + number + = *space_p >> + ( + as_lower_d["0x"] >> hex_p + | '0' >> oct_p + | real_p + ) + >> *as_lower_d[chset_p("lj")] + ; + + identifier + = *space_p >> ((alpha_p | '_') >> *(alnum_p | '_')) + ; + +[endsect] diff --git a/test/text_diff.cpp b/test/text_diff.cpp new file mode 100644 index 0000000..9409dc5 --- /dev/null +++ b/test/text_diff.cpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 2005 João Abecasis +// +// Distributed under 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 +#include +#include + +#include +#include + +namespace spirit = boost::spirit; + +typedef std::istream_iterator iterator; +typedef spirit::scanner scanner; + +int main(int argc, char * argv[]) +{ + if (argc != 3) + { + std::cerr << "ERROR: Wrong number of arguments." << std::endl; + std::cout << "Usage:\n\t" << argv[0] << " file1 file2" << std::endl; + + return 1; + } + + std::ifstream + file1(argv[1], std::ios_base::binary | std::ios_base::in), + file2(argv[2], std::ios_base::binary | std::ios_base::in); + + if (!file1 || !file2) + { + std::cerr << "ERROR: Unable to open one or both files." << std::endl; + return 2; + } + + file1.unsetf(std::ios_base::skipws); + file2.unsetf(std::ios_base::skipws); + + iterator + iter_file1(file1), + iter_file2(file2); + + scanner + scan1(iter_file1, iterator()), + scan2(iter_file2, iterator()); + + std::size_t line = 1, column = 1; + + while (!scan1.at_end() && !scan2.at_end()) + { + if (spirit::eol_p.parse(scan1)) + { + if (!spirit::eol_p.parse(scan2)) + { + std::cout << "Files differ at line " << line << ", column " << + column << '.' << std::endl; + return 3; + } + + ++line, column = 1; + continue; + } + + if (*scan1 != *scan2) + { + std::cout << "Files differ at line " << line << ", column " << + column << '.' << std::endl; + return 4; + } + + ++scan1, ++scan2, ++column; + } + + if (scan1.at_end() != scan2.at_end()) + { + std::cout << "Files differ in length." << std::endl; + return 5; + } +}