diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2020-06-06 22:42:16 +0300 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2021-09-20 16:06:46 +0200 |
commit | 2181ec73117f2e18cc622ead6256c8104b631214 (patch) | |
tree | c9d1bb2a8d3140b6cc6dd162be8129f14e38a717 /cli/doc/cli-guide.xhtml | |
parent | a599248e9dfab9f5d57c06bed56f75941cb00047 (diff) |
Use ad hoc recipe for parsing code and documentation generating
The overall approach is to store pre-generated bootstrap options.?xx
and cli.{1,xhtml} and automatically update them in the development
build (config.cli.develop=true). See README.md in the root of the
repository for details.
Diffstat (limited to 'cli/doc/cli-guide.xhtml')
-rw-r--r-- | cli/doc/cli-guide.xhtml | 1336 |
1 files changed, 1336 insertions, 0 deletions
diff --git a/cli/doc/cli-guide.xhtml b/cli/doc/cli-guide.xhtml new file mode 100644 index 0000000..675db03 --- /dev/null +++ b/cli/doc/cli-guide.xhtml @@ -0,0 +1,1336 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> + +<head> + <title>CLI Language Getting Started Guide</title> + + <meta name="copyright" content="© 2009-2020 Code Synthesis Tools CC"/> + <meta name="keywords" content="cli,command,line,interface,language,c++"/> + <meta name="description" content="CLI Language Getting Started Guide"/> + + <link rel="stylesheet" type="text/css" href="../default.css" /> + +<style type="text/css"> + pre { + padding : 0 0 0 0em; + margin : 0em 0em 0em 0; + + font-size : 102% + } + + body { + min-width: 48em; + } + + h1 { + font-weight: bold; + font-size: 200%; + line-height: 1.2em; + } + + h2 { + font-weight : bold; + font-size : 150%; + + padding-top : 0.8em; + } + + h3 { + font-size : 140%; + padding-top : 0.8em; + } + + /* Adjust indentation for three levels. */ + #container { + max-width: 48em; + } + + #content { + padding: 0 0.1em 0 4em; + /*background-color: red;*/ + } + + #content h1 { + margin-left: -2.06em; + } + + #content h2 { + margin-left: -1.33em; + } + + /* Title page */ + + #titlepage { + padding: 2em 0 1em 0; + border-bottom: 1px solid black; + } + + #titlepage .title { + font-weight: bold; + font-size: 200%; + text-align: center; + } + + #titlepage #first-title { + padding: 1em 0 0.4em 0; + } + + #titlepage #second-title { + padding: 0.4em 0 2em 0; + } + + /* Lists */ + ul.list li, ol.list li { + padding-top : 0.3em; + padding-bottom : 0.3em; + } + + dl dt { + padding : 0.8em 0 0 0; + } + + /* TOC */ + table.toc { + border-style : none; + border-collapse : separate; + border-spacing : 0; + + margin : 0.2em 0 0.2em 0; + padding : 0 0 0 0; + } + + table.toc tr { + padding : 0 0 0 0; + margin : 0 0 0 0; + } + + table.toc * td, table.toc * th { + border-style : none; + margin : 0 0 0 0; + vertical-align : top; + } + + table.toc * th { + font-weight : normal; + padding : 0em 0.1em 0em 0; + text-align : left; + white-space : nowrap; + } + + table.toc * table.toc th { + padding-left : 1em; + } + + table.toc * td { + padding : 0em 0 0em 0.7em; + text-align : left; + } + + /* Sample options documentation. */ + .options dt { + padding-top : 0.4em; + } + + .options dd { + padding-top : 0.1em; + padding-bottom : 0.4em; + padding-left : 1.4em; + } +</style> + + +</head> + +<body> +<div id="container"> + <div id="content"> + + <div class="noprint"> + + <div id="titlepage"> + <div class="title" id="first-title">CLI Language</div> + <div class="title" id="second-title">Getting Started Guide</div> + + <p>Copyright © 2009-2020 Code Synthesis Tools CC.</p> + + <p>Permission is granted to copy, distribute, and/or modify this document + under the terms of the + <a href="http://www.codesynthesis.com/licenses/mit.txt">MIT License</a>. + </p> + + <p>This document is available in the following formats: + <a href="http://www.codesynthesis.com/projects/cli/doc/guide/index.xhtml">XHTML</a>, + <a href="http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.pdf">PDF</a>, and + <a href="http://www.codesynthesis.com/projects/cli/doc/guide/cli-guide.ps">PostScript</a>.</p> + + </div> + +<h1>Table of Contents</h1> + + <table class="toc"> + <tr> + <th>1</th><td><a href="#1">Introduction</a></td> + </tr> + + <tr> + <th>2</th><td><a href="#2">Hello World Example</a> + <table class="toc"> + <tr><th>2.1</th><td><a href="#2.1">Defining Command Line Interface</a></td></tr> + <tr><th>2.2</th><td><a href="#2.2">Translating CLI Definitions to C++</a></td></tr> + <tr><th>2.3</th><td><a href="#2.3">Implementing Application Logic</a></td></tr> + <tr><th>2.4</th><td><a href="#2.4">Compiling and Running</a></td></tr> + <tr><th>2.5</th><td><a href="#2.5">Adding Documentation</a></td></tr> + </table> + </td> + </tr> + + <tr> + <th>3</th><td><a href="#3">CLI Language</a> + <table class="toc"> + <tr><th>3.1</th><td><a href="#3.1">Options Class Definition</a></td></tr> + <tr><th>3.2</th><td><a href="#3.2">Option Definition</a></td></tr> + <tr><th>3.3</th><td><a href="#3.3">Option Documentation</a></td></tr> + <tr><th>3.4</th><td><a href="#3.4">Include Directive</a></td></tr> + <tr><th>3.5</th><td><a href="#3.5">Namespace Definition</a></td></tr> + </table> + </td> + </tr> + </table> + </div> + + <!-- Introduction --> + + <h1><a name="1">1 Introduction</a></h1> + + <p>Command Line Interface (CLI) definition language is a domain-specific + language (DSL) for defining command line interfaces of C++ programs. + CLI definitions are automatically translated to C++ classes using the + CLI compiler. These classes implement parsing of the command + line arguments and provide a convenient and type-safe interface + for accessing the extracted data.</p> + + <p>Beyond this guide, you may also find the following sources of + information useful:</p> + + <ul class="list"> + <li><a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI + Compiler Command Line Manual</a></li> + + <li>The <code>INSTALL</code> file in the CLI distribution provides build + instructions for various platforms.</li> + + <li>The <code>examples/</code> directory in the CLI distribution contains + a collection of examples and a README file with an overview of each + example.</li> + + <li>The <a href="http://www.codesynthesis.com/mailman/listinfo/cli-users">cli-users</a> + mailing list is the place to ask technical questions about the CLI language + and compiler. Furthermore, the + <a href="http://www.codesynthesis.com/pipermail/cli-users/">cli-users mailing + list archives</a> may already have answers to some of your questions.</li> + </ul> + + + <!-- Hello World Example --> + + + <h1><a name="2">2 Hello World Example</a></h1> + + <p>In this chapter we will examine how to define a very simple command + line interface in CLI, translate this interface to C++, and use the + result in an application. The code presented in this chapter is based + on the <code>hello</code> example which can be found in the + <code>examples/hello/</code> directory of the CLI distribution.</p> + + <h2><a name="2.1">2.1 Defining Command Line Interface</a></h2> + + <p>Our <code>hello</code> application is going to print a greeting + line for each name supplied on the command line. It will also + support two command line options, <code>--greeting</code> + and <code>--exclamations</code>, that can be used to + customize the greeting line. The <code>--greeting</code> + option allows us to specify the greeting phrase instead of the + default <code>"Hello"</code>. The <code>--exclamations</code> + option is used to specify how many exclamation marks should + be printed at the end of each greeting. We will also support + the <code>--help</code> option which triggers printing of the + usage information.</p> + + <p>We can now write a description of the above command line interface + in the CLI language and save it into <code>hello.cli</code>:</p> + + <pre class="cli"> +include <string>; + +class options +{ + bool --help; + std::string --greeting = "Hello"; + unsigned int --exclamations = 1; +}; + </pre> + + <p>While some details in the above code fragment might not be completely + clear (the CLI language is covered in greater detail in the next + chapter), it should be easy to connect declarations in + <code>hello.cli</code> to the command line interface described in + the preceding paragraphs. The next step is to translate this + interface specification to C++.</p> + + <h2><a name="2.2">2.2 Translating CLI Definitions to C++</a></h2> + + <p>Now we are ready to translate <code>hello.cli</code> to C++. + To do this we invoke the CLI compiler from a terminal (UNIX) or + a command prompt (Windows): + </p> + + <pre class="term"> +$ cli hello.cli + </pre> + + <p>This invocation of the CLI compiler produces three C++ files: + <code>hello.hxx</code> <code>hello.ixx</code>, and + <code>hello.cxx</code>. You can change the file name extensions + for these files with the compiler command line options. See the + <a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI + Compiler Command Line Manual</a> for more information.</p> + + <p>The following code fragment is taken from <code>hello.hxx</code>; it + should give you an idea about what gets generated:</p> + + <pre class="cxx"> +#include <string> + +class options +{ +public: + options (int argc, char** argv); + options (int argc, char** argv, int& end); + + // Option accessors. + // +public: + bool + help () const; + + const std::string& + greeting () const; + + unsigned int + exclamations () const; + +private: + .. +}; + </pre> + + <p>The <code>options</code> C++ class corresponds to the <code>options</code> + CLI class. For each option in this CLI class an accessor function is + generated inside the C++ class. The <code>options</code> C++ class also + defines a number of overloaded constructs that we can use to parse the + <code>argc/argv</code> array. Let's now see how we can use this generated + class to implement option parsing in our <code>hello</code> application.</p> + + <h2><a name="2.3">2.3 Implementing Application Logic</a></h2> + + <p>At this point we have everything we need to implement our + application:</p> + + <pre class="cxx"> +#include <iostream> +#include "hello.hxx" + +using namespace std; + +void +usage (ostream& os) +{ + os << "usage: driver [options] <names>" << endl + << "options:" << endl; + options::print_usage (os); +} + +int +main (int argc, char* argv[]) +{ + try + { + int end; // End of options. + options o (argc, argv, end); + + if (o.help ()) + { + usage (cout); + return 0; + } + + if (end == argc) + { + cerr << "no names provided" << endl; + usage (cerr); + return 1; + } + + // Print the greetings. + // + for (int i = end; i < argc; i++) + { + cout << o.greeting () << ", " << argv[i]; + + for (unsigned int j = 0; j < o.exclamations (); j++) + cout << '!'; + + cout << endl; + } + } + catch (const cli::exception& e) + { + cerr << e << endl; + usage (cerr); + return 1; + } +} +</pre> + + <p>At the beginning of our application we create the <code>options</code> + object which parses the command line. The <code>end</code> variable + contains the index of the first non-option argument. We then access + the option values as needed during the application execution. We also + catch and print <code>cli::exception</code> in case something goes + wrong, for example, an unknown option is specified or an option value + is invalid. + </p> + + <h2><a name="2.4">2.4 Compiling and Running</a></h2> + + <p>After saving our application from the previous section in + <code>driver.cxx</code>, we are ready to build and run our program. + On UNIX this can be done with the following commands:</p> + + <pre class="term"> +$ c++ -o driver driver.cxx hello.cxx + +$ ./driver world +Hello, world! + +$ ./driver --greeting Hi --exclamations 3 John Jane +Hi, John!!! +Hi, Jane!!! + </pre> + + <p>We can also test the error handling:</p> + + <pre class="term"> +$ ./driver -n 3 Jane +unknown option '-n' +usage: driver [options] <names> +options: +--help +--greeting <arg> +--exclamations <arg> + +$ ./driver --exclamations abc Jane +invalid value 'abc' for option '--exclamations' +usage: driver [options] <names> +options: +--help +--greeting <arg> +--exclamations <arg> + </pre> + + <h2><a name="2.5">2.5 Adding Documentation</a></h2> + + <p>As we have seen in the previous sections, the <code>options</code> + C++ class provides the <code>print_usage()</code> function which we + can use to display the application usage information. Right now this + information is very basic and does not include any description of + the purpose of each option:</p> + + <pre class="term"> +$ ./driver --help +usage: driver [options] <names> +options: +--help +--greeting <arg> +--exclamations <arg> + </pre> + + <p>To make the usage information more descriptive we can document each + option in the command line interface definition. This information can + also be used to automatically generate program documentation in various + formats, such as HTML and man page. For example:</p> + + <pre class="cli"> +include <string>; + +class options +{ + bool --help {"Print usage information and exit."}; + + std::string --greeting = "Hello" + { + "<text>", + "Use <text> as a greeting phrase instead of the default \"Hello\"." + }; + + unsigned int --exclamations = 1 + { + "<num>", + "Print <num> exclamation marks instead of 1 by default." + }; +}; + </pre> + + <p>If we now save this updated command line interface to + <code>hello.cli</code> and recompile our application, the usage + information printed by the program will look like this:</p> + + <pre class="term"> +usage: driver [options] <names> +options: +--help Print usage information and exit. +--greeting <text> Use <text> as a greeting phrase instead of the + default "Hello". +--exclamations <num> Print <num> exclamation marks instead of 1 by + default. + </pre> + + <p>We can also generate the program documentation in the HTML + (<code>--generate-html</code> CLI option) and man page + (<code>--generate-man</code> CLI option) formats. For example:</p> + + <pre class="term"> +$ cli --generate-html hello.cli + </pre> + + <p>The resulting <code>hello.html</code> file contains the following + documentation:</p> + +<dl class="options"> + <dt><code><b>--help</b></code></dt> + <dd>Print usage information and exit.</dd> + + <dt><code><b>--greeting</b></code> <i>text</i></dt> + <dd>Use <i>text</i> as a greeting phrase instead of the default "Hello".</dd> + + <dt><code><b>--exclamations</b></code> <i>num</i></dt> + <dd>Print <i>num</i> exclamation marks instead of 1 by default.</dd> + +</dl> + + <p>This HTML fragment can be combined with custom prologue and epilogue + to create a complete program documentation + (<code>--html-prologue/--html-epilogue</code> options for the HTML + output, <code>--man-prologue/--man-epilogue</code> options for the + man page output). For an example of such complete documentation see + the <a href="http://www.codesynthesis.com/projects/cli/doc/cli.xhtml">CLI + Compiler Command Line Manual</a> and the <code>cli(1)</code> man + page. For more information on the option documentation syntax, + see <a href="#3.3">Section 3.3, Option Documentation</a>.</p> + + <!-- CLI Language --> + + + <h1><a name="3">3 CLI Language</a></h1> + + <p>This chapter describes the CLI language and its mapping to C++. + A CLI file consists of zero or more <a href="#3.4">Include + Directives</a> followed by one or more <a href="#3.5">Namespace Definitions</a> + or <a href="#3.1">Option Class Definitions</a>. C and C++-style comments + can be used anywhere in the CLI file except in character and + string literals.</p> + + <h2><a name="3.1">3.1 Option Class Definition</a></h2> + +<p>The central part of the CLI language is <em>option class</em>. An + option class contains one or more <em>option</em> definitions, for + example:</p> + + <pre class="cli"> +class options +{ + bool --help; + int --compression; +}; + </pre> + + <p>If we translate the above CLI fragment to C++, we will get a C++ + class with the following interface:</p> + + <pre class="cli"> +class options +{ +public: + options (int& argc, + char** argv, + bool erase = false, + cli::unknown_mode opt_mode = cli::unknown_mode::fail, + cli::unknown_mode arg_mode = cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + bool erase = false, + cli::unknown_mode opt_mode = cli::unknown_mode::fail, + cli::unknown_mode arg_mode = cli::unknown_mode::stop); + + options (int& argc, + char** argv, + int& end, + bool erase = false, + cli::unknown_mode opt_mode = cli::unknown_mode::fail, + cli::unknown_mode arg_mode = cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + cli::unknown_mode opt_mode = cli::unknown_mode::fail, + cli::unknown_mode arg_mode = cli::unknown_mode::stop); + + options (cli::scanner&, + cli::unknown_mode opt_mode = cli::unknown_mode::fail, + cli::unknown_mode arg_mode = cli::unknown_mode::stop); + + options (const options&); + + options& + operator= (const options&); + +public: + static void + print_usage (std::ostream&); + +public: + bool + help () const; + + int + compression () const; +}; + </pre> + + + <p>An option class is mapped to a C++ class with the same name. The + C++ class defines a set of public overloaded constructors, a public + copy constructor and an assignment operator, as well as a set of public + accessor functions and, if the <code>--generate-modifier</code> CLI + compiler option is specified, modifier functions corresponding to option + definitions. It also defines a public static <code>print_usage()</code> + function that can be used to print the usage information for the options + defined by the class.</p> + + <p>The <code>argc/argv</code> arguments in the overloaded constructors + are used to pass the command line arguments array, normally as passed + to <code>main()</code>. The <code>start</code> argument is used to + specify the position in the arguments array from which the parsing + should start. The constructors that don't have this argument, start + from position 1, skipping the executable name in <code>argv[0]</code>. + The <code>end</code> argument is used to return the position in + the arguments array where the parsing of options stopped. This is the + position of the first program argument, if any. If the <code>erase</code> + argument is <code>true</code>, then the recognized options and their + values are removed from the <code>argv</code> array and the + <code>argc</code> count is updated accordingly.</p> + + <p>The <code>opt_mode</code> and <code>arg_mode</code> arguments + specify the parser behavior when it encounters an unknown option + and argument, respectively. The <code>unknown_mode</code> type + is part of the generated CLI runtime support code. It has the + following interface:</p> + + <pre class="cxx"> +namespace cli +{ + class unknown_mode + { + public: + enum value + { + skip, + stop, + fail + }; + + unknown_mode (value v); + operator value () const; + }; +} + </pre> + + <p>If the mode is <code>skip</code>, the parser skips an unknown + option or argument and continue parsing. If the mode is + <code>stop</code>, the parser stops the parsing process. The + position of the unknown entity is stored in the <code>end</code> + argument. If the mode is <code>fail</code>, the parser throws the + <code>cli::unknown_option</code> or <code>cli::unknown_argument</code> + exception (described blow) on encountering an unknown option or argument, + respectively.</p> + + <p>Instead of the <code>argc/argv</code> arguments, the last overloaded + constructor accepts the <code>cli::scanner</code> object. It is part + of the generated CLI runtime support code and has the following + abstract interface:</p> + + <pre class="cxx"> +namespace cli +{ + class scanner + { + public: + virtual bool + more () = 0; + + virtual const char* + peek () = 0; + + virtual const char* + next () = 0; + + virtual void + skip () = 0; + }; +} + </pre> + + <p>The CLI runtime also provides two implementations of this interface: + <code>cli::argv_scanner</code> and <code>cli::argv_file_scanner</code>. + The first implementation is a simple scanner for the <code>argv</code> + array (it is used internally by all the other constructors) and has the + following interface:</p> + + <pre class="cxx"> +namespace cli +{ + class argv_scanner + { + public: + argv_scanner (int& argc, char** argv, bool erase = false); + argv_scanner (int start, int& argc, char** argv, bool erase = false); + + int + end () const; + + ... + }; +} + </pre> + + <p>The <code>cli::argv_file_scanner</code> implementation provides + support for reading command line arguments from the <code>argv</code> + array as well as files specified with command line options. It is + generated only if explicitly requested with the + <code>--generate-file-scanner</code> CLI compiler option and has + the following interface:</p> + + <pre class="cxx"> +namespace cli +{ + class argv_file_scanner + { + public: + argv_file_scanner (int& argc, + char** argv, + const std::string& option, + bool erase = false); + + argv_file_scanner (int start, + int& argc, + char** argv, + const std::string& option, + bool erase = false); + + struct option_info + { + // If search_func is not NULL, it is called, with the arg + // value as the second argument, to locate the options file. + // If it returns an empty string, then the file is ignored. + // + const char* option; + std::string (*search_func) (const char*, void* arg); + void* arg; + }; + + argv_file_scanner (int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false); + + argv_file_scanner (int start, + int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false); + ... + }; +} + </pre> + + <p>The <code>option</code> argument in the first two constructors and + the <code>options</code> and <code>options_count</code> arguments + in the last two are used to pass the option name(s) that should be + recognized as specifying the file containing additional options. + Such a file contains a set of options, each appearing on a + separate line optionally followed by space and an option value. Empty lines + and lines starting with <code>#</code> are ignored. Option values can + be enclosed in double (<code>"</code>) or single (<code>'</code>) + quotes to preserve leading and trailing whitespaces as well as to + specify empty values. If the value itself contains trailing or leading + quotes, enclose it with an extra pair of quotes, for example + <code>'"x"'</code>. Non-leading and non-trailing quotes are interpreted + as being part of the option value.</p> + + <p>The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the + point where the options file is specified, except that the shell escaping + and quoting is not required. Multiple files can be specified by including + several file options on the command line or inside other files.</p> + + <p>The parsing constructor (those with the <code>argc/argv</code> or + <code>cli::scanner</code> arguments) can throw the following exceptions: <code>cli::unknown_option</code>, + <code>cli::unknown_argument</code>, <code>cli::missing_value</code>, and + <code>cli::invalid_value</code>. The first two exceptions are thrown + on encountering unknown options and arguments, respectively, as + described above. The <code>missing_value</code> exception is thrown when + an option value is missing. The <code>invalid_value</code> exception is + thrown when an option value is invalid, for example, a non-integer value + is specified for an option of type <code>int</code>.</p> + + <p>Furthermore, all scanners (and thus the parsing constructors that + call them) can throw the <code>cli::eos_reached</code> exception + which indicates that one of the <code>peek()</code>, <code>next()</code>, + or <code>skip()</code> functions were called while <code>more()</code> + returns <code>false</code>. Catching this exception normally indicates an + error in an option parser implementation. The <code>argv_file_scanner</code> + class can also throw the <code>cli::file_io_failure</code> exception + which indicates that a file could not be opened or there was a reading + error as well as the <code>cli::unmatched_quote</code> exception + which indicates that an unmatched leading or trailing quote was + found in an option value.</p> + + <p>All CLI exceptions are derived from the common <code>cli::exception</code> + class which implements the polymorphic <code>std::ostream</code> insertion. + For example, if you catch the <code>cli::unknown_option</code> + exception as <code>cli::exception</code> and print it to + <code>std::cerr</code>, you will get the error message corresponding + to the <code>unknown_option</code> exception.</p> + + <p>The exceptions described above are part of the generated CLI runtime + support code and have the following interfaces:</p> + + <pre class="cxx"> +#include <exception> + +namespace cli +{ + class exception: public std::exception + { + public: + virtual void + print (std::ostream&) const = 0; + }; + + inline std::ostream& + operator<< (std::ostream& os, const exception& e) + { + e.print (os); + return os; + } + + class unknown_option: public exception + { + public: + unknown_option (const std::string& option); + + const std::string& + option () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class unknown_argument: public exception + { + public: + unknown_argument (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class missing_value: public exception + { + public: + missing_value (const std::string& option); + + const std::string& + option () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class invalid_value: public exception + { + public: + invalid_value (const std::string& option, + const std::string& value); + + const std::string& + option () const; + + const std::string& + value () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class eos_reached: public exception + { + public: + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class file_io_failure: public exception + { + public: + file_io_failure (const std::string& file); + + const std::string& + file () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class unmatched_quote: public exception + { + public: + unmatched_quote (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + }; +} + </pre> + + + <h2><a name="3.2">3.2 Option Definition</a></h2> + +<p>An option definition consists of four components: <em>type</em>, + <em>name</em>, <em>default value</em>, and <em>documentation</em>. + An option type can be any C++ type as long as its string representation + can be parsed using the <code>std::istream</code> interface. If the option + type is user-defined then you will need to include its declaration using + the <a href="#3.4">Include Directive</a>.</p> + +<p>An option of a type other than <code>bool</code> is expected to + have a value. An option of type <code>bool</code> is treated as + a flag and does not have a value. That is, a mere presence of such + an option on the command line sets this option's value to + <code>true</code>.</p> + +<p>The name component specifies the option name as it will be entered + in the command line. A name can contain any number of aliases separated + by <code>|</code>. The C++ accessor and modifier function names are + derived from the first name by removing any leading special characters, + such as <code>-</code>, <code>/</code>, etc., and replacing special + characters in other places with underscores. For example, the following + option definition:</p> + + <pre class="cli"> +class options +{ + int --compression-level | --comp | -c; +}; + </pre> + + <p>Will result in the following accessor function:</p> + + <pre class="cli"> +class options +{ + int + compression_level () const; +}; + </pre> + + <p>While any option alias can be used on the command line to specify + this option's value.</p> + + <p>If the option name conflicts with one of the CLI language keywords, + it can be specified as a string literal:</p> + + <pre class="cli"> +class options +{ + bool "int"; +}; + </pre> + + <p>The following component of the option definition is the optional default + value. If the default value is not specified, then the option is + initialized with the default constructor. In particular, this means + that a <code>bool</code> option will be initialized to <code>false</code>, + an <code>int</code> option will be initialized to <code>0</code>, etc.</p> + + <p>Similar to C++ variable initialization, the default option value + can be specified using two syntactic forms: an assignment initialization + and constructor initialization. The two forms are equivalent except + that the constructor initialization can be used with multiple arguments, + for example:</p> + + <pre class="cli"> +include <string>; + +class options +{ + int -i1 = 5; + int -i2 (5); + + std::string -s1 = "John"; + std::string -s2 ("Mr John Doe", 8, 3); +}; + </pre> + + <p>The assignment initialization supports character, string, boolean, and + simple integer literals (including negative integers) as well + as identifiers. For more complex expressions use the constructor + initialization or wrap the expressions in parenthesis, for example:</p> + + <pre class="cli"> +include "constants.hxx"; // Defines default_value. + +class options +{ + int -a = default_value; + int -b (25 * 4); + int -c = (25 / default_value + 3); +}; + </pre> + + <p>By default, when an option is specified two or more times on the command + line, the last value overrides all the previous ones. However, a number + of standard C++ containers are handled differently to allow collecting + multiple option values or building key-value maps. These + containers are <code>std::vector</code>, <code>std::set</code>, and + <code>std::map</code>.</p> + + <p>When <code>std::vector</code> or <code>std::set</code> is specified + as an option type, all the values for this option are inserted into the + container in the order they are encountered. As a result, + <code>std::vector</code> will contain all the values, including + duplicates while <code>std::set</code> will contain all the unique + values. For example:</p> + + <pre class="cli"> +include <set>; +include <vector>; + +class options +{ + std::vector<int> --vector | -v; + std::set<int> --set | -s; +}; + </pre> + + <p>If we have a command line like this: + <code>-v 1 -v 2 -v 1 -s 1 -s 2 -s 1</code>, then the vector returned + by the <code>vector()</code> accessor function will contain three + elements: <code>1</code>, <code>2</code>, and <code>1</code> while + the set returned by the <code>set()</code> accessor will contain + two elements: <code>1</code> and <code>2</code>.</p> + + <p>When <code>std::map</code> is specified as an option type, the option + value is expected to have two parts: the key and the value, separated + by <code>=</code>. All the option values are then parsed into key/value + pairs and inserted into the map. For example:</p> + + <pre class="cli"> +include <map>; +include <string>; + +class options +{ + std::map<std::string, std::string> --map | -m; +}; + </pre> + + <p>The possible option values for this interface are: <code>-m a=A</code>, + <code>-m =B</code> (key is an empty string), <code>-m c=</code> (value + is an empty string), or <code>-m d</code> (same as <code>-m d=</code>).</p> + + <p>The last component in the option definition is optional documentation. + It is discussed in the next section.</p> + + <h2><a name="3.3">3.3 Option Documentation</a></h2> + + <p>Option documentation mimics C++ string array initialization: + it is enclosed in <code>{}</code> and consists of one or more + documentation strings separated by a comma, for example:</p> + + <pre class="cli"> +class options +{ + int --compression = 5 + { + "<level>", + "Set compression to <level> instead of 5 by default. + + With the higher compression levels the program may produce a + smaller output but may also take longer and use more memory." + }; +}; + </pre> + + <p>The option documentation consists of a maximum of three documentation + strings. The first string is the value documentation string. + It describes the option value and is only applicable to options + with types other than <code>bool</code> (options of type + <code>bool</code> are flags and don't have an explicit value). + The second string (or the first string for options of type + <code>bool</code>) is the short documentation string. It + provides a brief description of the option. The last entry + in the option documentation is the long documentation string. + It provides a detailed description of the option. The short + documentation string is optional. If only two strings are + present in the option documentation (one string for options + of type <code>bool</code>), then the second (first) string is + assumed to be the long documentation string.</p> + + <p>Option documentation is used to print the usage information + as well as to generate program documentation in the HTML and + man page formats. For usage information the short documentation + string is used if provided. If only the long string is available, + then, by default, only the first sentence from the long string + is used. You can override this behavior and include the complete + long string in the usage information by specifying the + <code>--long-usage</code> CLI compiler option. When generating + the program documentation, the long documentation strings are + always used.</p> + + <p>The value documentation string can contain text enclosed in + <code><></code> which is automatically recognized by the CLI + compiler and typeset according to the selected output in all three + documentation strings. For example, in usage the <code>level</code> + value for the <code>--compression</code> option presented above + will be displayed as <code><level></code> while in the HTML and + man page output it will be typeset in italic as + <code><i>level</i></code>. Here is another example using the + <code>std::map</code> type:</p> + + <pre class="cli"> +include <map>; +include <string>; + +class options +{ + std::map<std::string, std::string> --map + { + "<key>=<value>", + "Add the <key>, <value> pair to the map." + }; +}; + </pre> + + <p>The resulting HTML output for this option would look like this:</p> + +<dl class="options"> + <dt><code><b>--map</b></code> <i>key</i>=<i>value</i></dt> + <dd>Add the <i>key</i>, <i>value</i> pair to the map.</dd> +</dl> + + <p>As you might have noticed from the examples presented so far, the + documentation strings can span multiple lines which is not possible + in C++. Also, all three documentation strings support the following + basic formatting mechanisms. The start of a new paragraph is indicated + by a blank line. A fragment of text can be typeset in monospace font + (normally used for code fragments) by enclosing it in the + <code>\c{}</code> block. Similarly, text can be typeset in bold or + italic fonts using the <code>\b{}</code> and <code>\i{}</code> blocks, + respectively. You can also combine several font properties in a single + block, for example, <code>\cb{bold code}</code>. If you need to include + literal <code>}</code> in a formatting block, you can use the + <code>\}</code> escape sequence, for example, + <code>\c{int a[] = {1, 2\}}</code>. The following example shows how we + can use these mechanisms:</p> + + <pre class="cli"> +class options +{ + int --compression = 5 + { + "<level>", + "Set compression to <level> instead of 5 by default. + + With the higher compression levels the program \i{may} + produce a smaller output but may also \b{take longer} + and \b{use more memory}." + }; +}; + </pre> + + <p>The resulting HTML output for this option would look like this:</p> + +<dl class="options"> + <dt><code><b>--compression</b></code> <i>level</i></dt> + <dd>Set compression to <i>level</i> instead of 5 by default. + + <p>With the higher compression levels the program <i>may</i> produce a + smaller output but may also <b>take longer</b> and <b>use more memory</b>.</p></dd> +</dl> + + <h2><a name="3.4">3.4 Include Directive</a></h2> + + <p>If you are using user-defined types in your option definitions, + you will need to include their declarations with the include + directive. Include directives can use <code>< ></code> or + <code>" "</code>-enclosed paths. The CLI compiler does not + actually open or read these files. Instead, the include directives + are translated to C++ preprocessor <code>#include</code> directives + in the generated C++ header file. For example, the following CLI + definition:</p> + + <pre class="cli"> +include <string>; +include "types.hxx"; // Defines the name_type class. + +class options +{ + std::string --string; + name_type --name; +}; + </pre> + + <p>Will result in the following C++ header file:</p> + + <pre class="cli"> +#include <string> +#include "types.hxx" + +class options +{ + ... + + const std::string& + string () const; + + const name_type& + name () const; + + ... +}; + </pre> + + <p>Without the <code>#include</code> directives the <code>std::string</code> + and <code>name_type</code> types in the <code>options</code> class would + be undeclared and result in compilation errors.</p> + + <h2><a name="3.5">3.5 Namespace Definition</a></h2> + + <p>Option classes can be placed into namespaces which are translated + directly to C++ namespaces. For example:</p> + + <pre class="cli"> +namespace compiler +{ + namespace lexer + { + class options + { + int --warning-level = 0; + }; + } + + namespace parser + { + class options + { + int --warning-level = 0; + }; + } + + namespace generator + { + class options + { + int --target-width = 32; + }; + } +} + </pre> + + <p>The above CLI namespace structure would result in the equivalent C++ + namespaces structure:</p> + + <pre class="cxx"> +namespace compiler +{ + namespace lexer + { + class options + { + int + warning_level () const; + }; + } + + namespace parser + { + class options + { + int + warning_level () const; + }; + } + + namespace generator + { + class options + { + int + target_width () const; + }; + } +} + </pre> + + + </div> +</div> + + +</body> +</html> |