]> git.droids-corp.org - protos/libecoli.git/commitdiff
add first documentation draft and framework
authorOlivier Matz <zer0@droids-corp.org>
Wed, 9 Oct 2019 17:44:03 +0000 (19:44 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Wed, 9 Oct 2019 17:44:03 +0000 (19:44 +0200)
59 files changed:
doc/Doxyfile.in [new file with mode: 0644]
doc/_static/custom.css [new file with mode: 0644]
doc/_static/libecoli.svg [new file with mode: 0644]
doc/architecture.rst [new file with mode: 0644]
doc/conf.py [new file with mode: 0644]
doc/contributing.rst [new file with mode: 0644]
doc/index.rst [new file with mode: 0644]
doc/installation.rst [new file with mode: 0644]
doc/meson.build [new file with mode: 0644]
doc/overview.rst [new file with mode: 0644]
doc/parse-tree.svg [new file with mode: 0644]
doc/parse-tree2.svg [new file with mode: 0644]
doc/parse-tree3.svg [new file with mode: 0644]
doc/simple-tree.svg [new file with mode: 0644]
doc/simple-tree2.svg [new file with mode: 0644]
doc/simple-tree3.svg [new file with mode: 0644]
doc/user_guide.rst [new file with mode: 0644]
include/ecoli.h [new file with mode: 0644]
include/ecoli_assert.h
include/ecoli_complete.h
include/ecoli_config.h
include/ecoli_dict.h
include/ecoli_editline.h
include/ecoli_htable.h
include/ecoli_init.h
include/ecoli_log.h
include/ecoli_malloc.h
include/ecoli_murmurhash.h
include/ecoli_node.h
include/ecoli_node_any.h
include/ecoli_node_bypass.h
include/ecoli_node_cmd.h
include/ecoli_node_cond.h
include/ecoli_node_dynamic.h
include/ecoli_node_empty.h
include/ecoli_node_expr.h
include/ecoli_node_file.h
include/ecoli_node_int.h
include/ecoli_node_many.h
include/ecoli_node_none.h
include/ecoli_node_once.h
include/ecoli_node_option.h
include/ecoli_node_or.h
include/ecoli_node_re.h
include/ecoli_node_re_lex.h
include/ecoli_node_seq.h
include/ecoli_node_sh_lex.h
include/ecoli_node_space.h
include/ecoli_node_str.h
include/ecoli_node_subset.h
include/ecoli_parse.h
include/ecoli_string.h
include/ecoli_strvec.h
include/ecoli_test.h
include/ecoli_utils.h
include/ecoli_vec.h
include/ecoli_yaml.h
include/meson.build
meson.build

diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..274c476
--- /dev/null
@@ -0,0 +1,35 @@
+PROJECT_NAME           = "Libecoli"
+PROJECT_BRIEF          = "Extensible Command Line library"
+PROJECT_NUMBER         = @VERSION@
+INPUT                  = @TOPDIR@/include
+OUTPUT_DIRECTORY       = @OUTPUT@
+FILE_PATTERNS          = *.c *.h *.dox
+
+BRIEF_MEMBER_DESC = YES
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+INLINE_SIMPLE_STRUCTS = YES
+EXTRACT_ALL = YES
+SOURCE_BROWSER = YES
+REPEAT_BRIEF           = NO
+
+EXAMPLE_PATH           =
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+SOURCE_BROWSER          = YES
+
+GENERATE_XML           = YES
+XML_OUTPUT             = xml
+XML_PROGRAMLISTING     = YES
+
+GENERATE_LATEX         = NO
+HAVE_DOT               = NO
\ No newline at end of file
diff --git a/doc/_static/custom.css b/doc/_static/custom.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/_static/libecoli.svg b/doc/_static/libecoli.svg
new file mode 100644 (file)
index 0000000..605b9fd
--- /dev/null
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="50.595764mm"
+   height="9.8371639mm"
+   viewBox="0 0 50.595764 9.837164"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="libecoli.svg">
+  <defs
+     id="defs2" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.979899"
+     inkscape:cx="95.47757"
+     inkscape:cy="-26.215699"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-31.293259,-93.101089)">
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;line-height:6.61458302px;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="58.799297"
+       y="92.806084"
+       id="text836"><tspan
+         sodipodi:role="line"
+         id="tspan834"
+         x="58.799297"
+         y="98.424881"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold';stroke-width:0.26458332px" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.46666622px;line-height:6.61458302px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="56.504822"
+       y="100.59354"
+       id="text840"><tspan
+         sodipodi:role="line"
+         id="tspan838"
+         x="56.504822"
+         y="100.59354"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Nimbus Mono L';-inkscape-font-specification:'Nimbus Mono L Bold';stroke-width:0.26458332px">lib<tspan
+   style="fill:#0000ff"
+   id="tspan842">ecoli</tspan>&gt;</tspan></text>
+    <rect
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect865"
+       width="49.845764"
+       height="9.0871639"
+       x="31.668259"
+       y="93.476089" />
+  </g>
+</svg>
diff --git a/doc/architecture.rst b/doc/architecture.rst
new file mode 100644 (file)
index 0000000..64ecaa8
--- /dev/null
@@ -0,0 +1,153 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+Architecture
+============
+
+Most of *libecoli* is written in C. It provides a C API to ease the
+creation of interactive command line interfaces. It is split in several
+parts:
+
+- the core: it provides the main API to parse and complete strings.
+- ecoli nodes: this is the modular part of *libecoli*. Each node
+  implements a specific parsing (integers, strings, regular expressions,
+  sequence, ...)
+- yaml parser: load an ecoli tree described in yaml.
+- editline: helpers to instantiate an *editline* and connect it to
+  *libecoli*.
+- utilities: logging, string, strings vector, hash table, ...
+
+The grammar tree
+----------------
+
+The *ecoli nodes* are organized in a tree. An *ecoli grammar tree*
+describes how the input is parsed and completed. Let's take a simple
+example:
+
+.. figure:: simple-tree.svg
+
+   A simple *ecoli grammar tree*.
+
+We can also represent it as text like this::
+
+  sh_lex(
+    seq(
+      str(foo),
+      option(
+        str(bar)
+      )
+    )
+  )
+
+This tree matches the following strings:
+
+- ``foo``
+- ``foo bar``
+
+But, for instance, it does **not** match the following strings:
+
+- ``bar``
+- ``foobar``
+- (empty string)
+
+Parsing an input
+----------------
+
+When the *libecoli* parses an input, it browses the tree (depth first
+search) and returns an *ecoli parse tree*. Let's decompose what is done
+when ``ec_node_parse_strvec(root_node, input)`` is called, step by step:
+
+1. The initial input is a string vector ``["foo bar"]``.
+2. The *sh_lex* node splits the input as a shell would have done it, in
+   ``["foo", "bar"]``, and passes it to its child.
+3. The *seq* node (sequence) passes the input to its first child.
+4. The *str* node matches if the first element of the string vector is
+   ``foo``. This is the case, so it returns the number of eaten
+   strings (1) to its parent.
+5. The *seq* node passes the remaining part ``["bar"]`` to its next
+   child.
+6. The option node passes the string vector to its child, which
+   matches. It returns 1 to its parent.
+7. The *seq* node has no more child, it returns the number of eaten
+   strings in the vector (2).
+8. Finally, *sh_lex* compares the returned value to the number of
+   strings in its initial vector, and return 1 (match) to its caller.
+
+If a node does not match, it returns ``EC_PARSE_NOMATCH`` to its parent,
+and it is propagated until it reaches a node that handle the case. For
+instance, the *or* node is able to handle this error. If a child does
+not match, the next one is tried until it finds one that matches.
+
+The parse tree
+--------------
+
+Let's take another simple example.
+
+.. figure:: simple-tree2.svg
+
+   Another simple *ecoli grammar tree*.
+
+In that case, there is no lexer (the *sh_lex* node), so the input must
+be a string vector that is already split. For instance, it matches:
+
+- ``["foo"]``
+- ``["bar", "1"]``
+- ``["bar", "100"]``
+
+But it does **not** match:
+
+- ``["bar 1"]``, because there is no *sh_lex* node on the top of the tree
+- ``["bar"]``
+- ``[]`` (empty vector)
+
+At the time the input is parsed, a *parse tree* is built. When it
+matches, it describes which part of the *ecoli grammar tree* that
+actually matched, and what input matched for each node.
+
+Passing ``["bar", "1"]`` to the previous tree would result in the
+following *parse tree*:
+
+.. figure:: parse-tree.svg
+
+   The *ecoli parse tree*, result of parsing.
+
+Each node of the *parse tree* references the node of the *grammar tree*
+that matched. It also stores the string vector that matched.
+
+.. figure:: parse-tree2.svg
+
+   The same *ecoli parse tree*, showing the references to the grammar
+   tree.
+
+We can see that not all of the grammar nodes are referenced, since the
+str("foo") node was not parsed. Similarly, one grammar node can be
+referenced several times in the parse tree, as we can see it in the
+following example:
+
+.. figure:: simple-tree3.svg
+
+   A simple *ecoli grammar tree*, that matches ``[]``, ``[foo]``,
+   ``[foo, foo]``, ...
+
+Here is the resulting *parse tree* when the input vector is ``[foo, foo,
+foo]``:
+
+.. figure:: parse-tree3.svg
+
+   The resulting *parse tree*.
+
+Node identifier
+---------------
+
+XXX
+
+Todo
+----
+
+- completions
+- C example
+- ec_config
+- parse yaml
+- params are consumed
+- nodes
+- attributes
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644 (file)
index 0000000..657ac6f
--- /dev/null
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+# -*- coding: utf-8 -*-
+#
+# Libecoli Documentation documentation build configuration file, created by
+# sphinx-quickstart on Thu May 23 20:10:46 2019.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['breathe']
+import os
+cautodoc_root = os.path.abspath('my/sources/dir')
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Libecoli Documentation'
+copyright = u'2019, Olivier Matz'
+author = u'Olivier Matz'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'0.1'
+# The full version, including alpha/beta/rc tags.
+release = u'0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#
+html_theme_options = {
+    'sidebar_width': '350px',
+    'logo': 'libecoli.svg',
+    'fixed_sidebar': True,
+    'page_width': '1200px',
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# This is required for the alabaster theme
+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
+html_sidebars = {
+    '**': [
+        'about.html',
+        'navigation.html',
+        'relations.html',  # needs 'show_related': True theme option to display
+        'searchbox.html',
+        'donate.html',
+    ]
+}
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'LibecoliDocumentationdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    #
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    #
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    #
+    # 'preamble': '',
+
+    # Latex figure (float) alignment
+    #
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'LibecoliDocumentation.tex', u'Libecoli Documentation Documentation',
+     u'Olivier Matz', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'libecolidocumentation', u'Libecoli Documentation Documentation',
+     [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'LibecoliDocumentation', u'Libecoli Documentation Documentation',
+     author, 'LibecoliDocumentation', 'One line description of project.',
+     'Miscellaneous'),
+]
diff --git a/doc/contributing.rst b/doc/contributing.rst
new file mode 100644 (file)
index 0000000..ab62905
--- /dev/null
@@ -0,0 +1,7 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+Contributing
+============
+
+Todo.
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644 (file)
index 0000000..a5f8731
--- /dev/null
@@ -0,0 +1,45 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+Libecoli Documentation
+======================
+
+This is the documentation of *libecoli*. This library simplifies the
+creation of interactive command line interfaces (*Ecoli* stands for
+Extensible COmmand LIne).
+
+What can it be used for?
+
+- complex interactive cli interface in C (ex: a router cli)
+- interactive cli for shell scripts
+- application arguments parsing, natively supporting bash completion
+- parsers
+
+What are the main features?
+
+- dynamic completion
+- contextual help
+- integrated with libedit, but can use any readline-like library
+- modular: the cli behavior is defined through an assembly of basic
+  nodes
+- extensible: the user can write its own nodes to provide specific
+  features
+- C API
+- YAML API and Shell API: used from shell scripts
+
+Who use it?
+
+- 6WIND_ for its Turbo Router cli
+
+.. _6WIND: https://www.6wind.com
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
+
+   overview
+   installation
+   user_guide
+   architecture
+   api
+   contributing
diff --git a/doc/installation.rst b/doc/installation.rst
new file mode 100644 (file)
index 0000000..edf0f4d
--- /dev/null
@@ -0,0 +1,7 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+Installation
+============
+
+Todo.
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644 (file)
index 0000000..a6c7028
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2019, Olivier MATZ <zer0@droids-corp.org>
+
+doc_install_dir = join_paths('share', 'doc', 'libecoli')
+
+doxygen = find_program('doxygen', required : false)
+if not doxygen.found()
+  error('MESON_SKIP_TEST doxygen not found.')
+endif
+
+cdata = configuration_data()
+cdata.set('VERSION', meson.project_version())
+cdata.set('OUTPUT', join_paths(meson.build_root(), 'doc', 'api'))
+cdata.set('TOPDIR', meson.source_root())
+
+doxygen_conf = configure_file(
+  input: 'Doxyfile.in',
+  output: 'Doxyfile',
+  configuration: cdata,
+  install: false)
+
+doxygen_build = custom_target(
+  'doxygen',
+  input: doxygen_conf,
+  output: 'api',
+  command: [doxygen, '@INPUT@', '@OUTPUT@'],
+  build_by_default: true,
+  install_dir: doc_install_dir)
+
+sphinx_build = find_program(
+  'sphinx-build', required: get_option('build_doc'))
+if get_option('build_doc') and sphinx_build.found()
+       html_doc = custom_target('html_doc',
+               input: meson.current_source_dir(),
+               output: 'html_doc',
+               command: [sphinx_build, '@INPUT@', '@OUTPUT@'],
+               install: get_option('build_doc'),
+               install_dir: doc_install_dir)
+endif
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644 (file)
index 0000000..2ac3cbe
--- /dev/null
@@ -0,0 +1,7 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+Overview
+========
+
+Todo.
diff --git a/doc/parse-tree.svg b/doc/parse-tree.svg
new file mode 100644 (file)
index 0000000..9657a0a
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="97.485992mm"
+   height="109.30539mm"
+   viewBox="0 0 97.48599 109.30539"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.1 r15371"
+   sodipodi:docname="parse-tree.svg">
+  <defs
+     id="defs5400" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="198.39895"
+     inkscape:cy="154.19128"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-76.002527,-121.82488)">
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="124.74552"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6"
+       cx="124.74552"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2"
+       cx="124.74553"
+       cy="211.3884"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.64906"
+       y="142.50148"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="124.64906"
+         y="142.50148"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">or</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.62737"
+       y="213.08734"
+       id="text6021-3-0-6"><tspan
+         sodipodi:role="line"
+         x="124.62737"
+         y="213.08734"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-3">str</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.91586"
+       y="177.63344"
+       id="text6021-3-0-0"><tspan
+         sodipodi:role="line"
+         x="124.91586"
+         y="177.63344"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7">seq</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 124.88043,150.10613 0.25944,17.2179"
+       id="path6098"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-6" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 125.13987,185.21778 -0.25944,17.2179"
+       id="path6100"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2-6"
+       cx="152.82364"
+       cy="211.80174"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="152.67412"
+       y="213.67795"
+       id="text6021-3-5"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-24"
+         x="152.67412"
+         y="213.67795"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">int</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 130.85878,183.4729 16.21006,20.90667"
+       id="path6173"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2-6" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.74638"
+       y="146.47508"
+       id="text6021-3-0-68"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-5"
+         x="124.74638"
+         y="146.47508"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar, 1]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.83473"
+       y="181.62686"
+       id="text6021-3-0-4"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-9"
+         x="124.83473"
+         y="181.62686"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar, 1]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.7464"
+       y="216.92993"
+       id="text6021-3-0-46"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-8"
+         x="124.7464"
+         y="216.92993"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="152.82449"
+       y="217.45903"
+       id="text6021-3-0-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-2"
+         x="152.82449"
+         y="217.45903"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[1]</tspan></text>
+  </g>
+</svg>
diff --git a/doc/parse-tree2.svg b/doc/parse-tree2.svg
new file mode 100644 (file)
index 0000000..5d22d6a
--- /dev/null
@@ -0,0 +1,449 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="151.7977mm"
+   height="131.62782mm"
+   viewBox="0 0 151.7977 131.62782"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="parse-tree2.svg">
+  <defs
+     id="defs5400">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2644"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2642"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2616"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2614"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2594"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2592"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path2312"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="459.55526"
+     inkscape:cy="287.82874"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-21.690821,-99.502441)">
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="124.74552"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6"
+       cx="124.74552"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2"
+       cx="124.74553"
+       cy="211.3884"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.64906"
+       y="142.50148"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="124.64906"
+         y="142.50148"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">or</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.62737"
+       y="213.08734"
+       id="text6021-3-0-6"><tspan
+         sodipodi:role="line"
+         x="124.62737"
+         y="213.08734"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-3">str</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.91586"
+       y="177.63344"
+       id="text6021-3-0-0"><tspan
+         sodipodi:role="line"
+         x="124.91586"
+         y="177.63344"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7">seq</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 124.74552,150.10694 0,17.21044"
+       id="path6098"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-6" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 124.74552,185.22443 1e-5,17.21044"
+       id="path6100"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2-6"
+       cx="152.82364"
+       cy="211.80174"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="152.67412"
+       y="213.67795"
+       id="text6021-3-5"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-24"
+         x="152.67412"
+         y="213.67795"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">int</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 130.57567,183.64854 16.41782,20.77557"
+       id="path6173"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2-6" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.74638"
+       y="146.47508"
+       id="text6021-3-0-68"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-5"
+         x="124.74638"
+         y="146.47508"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar, 1]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.83473"
+       y="181.62686"
+       id="text6021-3-0-4"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-9"
+         x="124.83473"
+         y="181.62686"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar, 1]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.7464"
+       y="216.92993"
+       id="text6021-3-0-46"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-8"
+         x="124.7464"
+         y="216.92993"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[bar]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="152.82449"
+       y="217.45903"
+       id="text6021-3-0-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-2"
+         x="152.82449"
+         y="217.45903"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[1]</tspan></text>
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2-0"
+       cx="56.435303"
+       cy="118.83097"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-21"
+       cx="42.355698"
+       cy="153.94846"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-6"
+       cx="70.433815"
+       cy="153.94846"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2-5"
+       cx="70.433823"
+       cy="189.06595"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="-23.040615"
+       y="80.265793"
+       id="text6017-0"><tspan
+         sodipodi:role="line"
+         id="tspan6015-8"
+         x="-23.040615"
+         y="84.856041"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="56.338837"
+       y="120.17905"
+       id="text6021-3-1"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-22"
+         x="56.338837"
+         y="120.17905"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">or</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="42.31591"
+       y="152.32455"
+       id="text6021-3-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2"
+         x="42.31591"
+         y="152.32455"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="42.31591"
+         y="158.97026"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#de8787;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059">foo</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="70.29306"
+       y="187.44205"
+       id="text6021-3-0-6-6"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2-9"
+         x="70.29306"
+         y="187.44205"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="70.29306"
+         y="194.08775"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#de8787;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-3-9">bar</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="70.604156"
+       y="155.31099"
+       id="text6021-3-0-0-1"><tspan
+         sodipodi:role="line"
+         x="70.604156"
+         y="155.31099"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7-0">seq</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 53.045963,127.28469 -7.300927,18.21005"
+       id="path6096"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-0"
+       inkscape:connection-end="#path5951-21" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 59.807237,127.29 7.254641,18.19942"
+       id="path6098-4"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-0"
+       inkscape:connection-end="#path5951-6-6" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 70.433815,162.90199 4e-6,17.21043"
+       id="path6100-2"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-6"
+       inkscape:connection-end="#path5951-6-2-5" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2-6-7"
+       cx="98.511932"
+       cy="189.47929"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="98.362411"
+       y="191.3555"
+       id="text6021-3-5-4"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-24-0"
+         x="98.362411"
+         y="191.3555"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke:none;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">int</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 76.263963,161.32609 92.68178,182.10166"
+       id="path6173-3"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-6"
+       inkscape:connection-end="#path5951-6-2-6-7" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2644)"
+       d="M 115.11271,138.0056 66.068116,121.97879"
+       id="path2301"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-2-0" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="M 115.4414,172.44685 79.737934,157.77251"
+       id="path2303"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-6" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2616)"
+       d="M 115.44141,207.56435 79.737942,192.89"
+       id="path2305"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-2"
+       inkscape:connection-end="#path5951-6-2-5" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2594)"
+       d="M 143.51952,207.97769 107.81605,193.30334"
+       id="path2307"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-2-6"
+       inkscape:connection-end="#path5951-6-2-6-7" />
+  </g>
+</svg>
diff --git a/doc/parse-tree3.svg b/doc/parse-tree3.svg
new file mode 100644 (file)
index 0000000..d779721
--- /dev/null
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="107.22144mm"
+   height="99.133545mm"
+   viewBox="0 0 107.22143 99.133546"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="parse-tree3.svg">
+  <defs
+     id="defs5400">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2947"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2945"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2919"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2917"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2897"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2895"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path2312"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="18.041834"
+     inkscape:cy="115.74651"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-90.082132,-121.82488)">
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
+       d="M 141.55564,196.27523 118.99373,181.62558"
+       id="path2871"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-21" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2897)"
+       d="m 167.22825,198.00821 -47.0708,-18.11562"
+       id="path2873"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-4"
+       inkscape:connection-end="#path5951-21" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="110.74701"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-21"
+       cx="110.74701"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.65054"
+       y="142.50148"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="110.65054"
+         y="142.50148"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">many</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.70722"
+       y="174.647"
+       id="text6021-3-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2"
+         x="110.70722"
+         y="174.647"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#b3b3b3;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="110.70722"
+         y="181.29271"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#de8787;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059">foo</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#b3b3b3;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 111.14136,150.10029 -0.25945,17.2179"
+       id="path6096"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-21" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2-2"
+       cx="149.80237"
+       cy="166.51241"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="149.70592"
+       y="165.74384"
+       id="text6021-3-8"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0"
+         x="149.70592"
+         y="165.74384"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">many</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="149.6842"
+       y="202.99243"
+       id="text6021-3-0-0"><tspan
+         sodipodi:role="line"
+         x="149.6842"
+         y="202.99243"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7">str</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 149.80237,175.46593 v 17.21044"
+       id="path6098"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-2"
+       inkscape:connection-end="#path5951-6" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:3px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="149.80324"
+       y="169.71744"
+       id="text6021-3-0-68"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-5"
+         x="149.80324"
+         y="169.71744"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;line-height:3px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[foo, foo,</tspan><tspan
+         sodipodi:role="line"
+         x="149.80324"
+         y="173.05287"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;line-height:3px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan2812">foo]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="149.80322"
+       y="206.62503"
+       id="text6021-3-0-4"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-9"
+         x="149.80322"
+         y="206.62503"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[foo]</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="122.84789"
+       y="202.99243"
+       id="text6021-3-0-0-7"><tspan
+         sodipodi:role="line"
+         x="122.84789"
+         y="202.99243"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7-0">str</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="122.96692"
+       y="206.62503"
+       id="text6021-3-0-4-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-9-3"
+         x="122.96692"
+         y="206.62503"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[foo]</tspan></text>
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6"
+       cx="149.80237"
+       cy="201.6299"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-3"
+       cx="122.96606"
+       cy="201.6299"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-4"
+       cx="176.63869"
+       cy="201.6299"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="176.52052"
+       y="202.99243"
+       id="text6021-3-0-0-9"><tspan
+         sodipodi:role="line"
+         x="176.52052"
+         y="202.99243"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7-2">str</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="176.63954"
+       y="206.62503"
+       id="text6021-3-0-4-7"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-0-9-4"
+         x="176.63954"
+         y="206.62503"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:3.52777767px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#0000ff;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">[foo]</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 144.10487,173.96804 -15.44132,20.20622"
+       id="path2863"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-2"
+       inkscape:connection-end="#path5951-6-3" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 155.49986,173.96804 15.44133,20.20622"
+       id="path2865"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-2"
+       inkscape:connection-end="#path5951-6-4" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2919)"
+       d="M 141.55564,161.15773 118.99373,146.50808"
+       id="path2867"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2-2"
+       inkscape:connection-end="#path5951-2" />
+    <path
+       style="fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker2947)"
+       d="m 118.98747,193.37288 -4.26188,-8.84496"
+       id="path2869"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6-3"
+       inkscape:connection-end="#path5951-21" />
+  </g>
+</svg>
diff --git a/doc/simple-tree.svg b/doc/simple-tree.svg
new file mode 100644 (file)
index 0000000..ef3863e
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="69.488983mm"
+   height="144.00954mm"
+   viewBox="0 0 69.488983 144.00954"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.1 r15371"
+   sodipodi:docname="simple-tree.svg">
+  <defs
+     id="defs5400" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="74.113229"
+     inkscape:cy="285.35655"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-76.002527,-86.70739)">
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951"
+       cx="110.74702"
+       cy="106.03592"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="110.74702"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-21"
+       cx="96.667404"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6"
+       cx="124.82664"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2"
+       cx="124.82664"
+       cy="211.3884"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.65538"
+       y="107.32973"
+       id="text6021"><tspan
+         sodipodi:role="line"
+         id="tspan6019"
+         x="110.65538"
+         y="107.32973"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">sh_lex</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.82901"
+       y="142.02278"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="110.82901"
+         y="142.02278"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">seq</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="96.627617"
+       y="174.647"
+       id="text6021-3-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2"
+         x="96.627617"
+         y="174.647"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="96.627617"
+         y="181.29271"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059">foo</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.60477"
+       y="209.7645"
+       id="text6021-3-0-6"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2-9"
+         x="124.60477"
+         y="209.7645"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="124.60477"
+         y="216.4102"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-3">bar</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.91586"
+       y="177.63344"
+       id="text6021-3-0-0"><tspan
+         sodipodi:role="line"
+         x="124.91586"
+         y="177.63344"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7">option</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 110.74702,114.98945 v 17.21043"
+       id="path6094"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951"
+       inkscape:connection-end="#path5951-2" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 107.35768,149.60713 -7.30094,18.21006"
+       id="path6096"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-21" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 114.13636,149.60713 7.30094,18.21006"
+       id="path6098"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-6" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 124.82664,185.22443 v 17.21044"
+       id="path6100"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2" />
+  </g>
+</svg>
diff --git a/doc/simple-tree2.svg b/doc/simple-tree2.svg
new file mode 100644 (file)
index 0000000..2269c88
--- /dev/null
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="97.485992mm"
+   height="109.30539mm"
+   viewBox="0 0 97.48599 109.30539"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.1 r15371"
+   sodipodi:docname="simple-tree2.svg">
+  <defs
+     id="defs5400" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="198.39895"
+     inkscape:cy="154.19128"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-76.002527,-121.82488)">
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="110.74701"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-21"
+       cx="96.667404"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6"
+       cx="124.74552"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2"
+       cx="124.74553"
+       cy="211.3884"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.65054"
+       y="142.50148"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="110.65054"
+         y="142.50148"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">or</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="96.627617"
+       y="174.647"
+       id="text6021-3-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2"
+         x="96.627617"
+         y="174.647"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="96.627617"
+         y="181.29271"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059">foo</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.60477"
+       y="209.7645"
+       id="text6021-3-0-6"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2-9"
+         x="124.60477"
+         y="209.7645"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="124.60477"
+         y="216.4102"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-3">bar</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="124.91586"
+       y="177.63344"
+       id="text6021-3-0-0"><tspan
+         sodipodi:role="line"
+         x="124.91586"
+         y="177.63344"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059-7">seq</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 107.71677,149.70974 -7.54716,18.14234"
+       id="path6096"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-21" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 114.11895,149.61244 7.25464,18.19943"
+       id="path6098"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-6" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 124.74553,185.22443 v 17.21044"
+       id="path6100"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-6-2-6"
+       cx="152.82364"
+       cy="211.80174"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="152.67412"
+       y="213.67795"
+       id="text6021-3-5"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-24"
+         x="152.67412"
+         y="213.67795"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">int</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 130.57567,183.64854 16.41782,20.77557"
+       id="path6173"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-6"
+       inkscape:connection-end="#path5951-6-2-6" />
+  </g>
+</svg>
diff --git a/doc/simple-tree3.svg b/doc/simple-tree3.svg
new file mode 100644 (file)
index 0000000..f3a9f4b
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="41.329754mm"
+   height="73.774551mm"
+   viewBox="0 0 41.329753 73.774552"
+   version="1.1"
+   id="svg5406"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="simple-tree3.svg">
+  <defs
+     id="defs5400" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="18.041835"
+     inkscape:cy="19.90149"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     inkscape:window-width="1918"
+     inkscape:window-height="1058"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata5403">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-90.082132,-121.82488)">
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-2"
+       cx="110.74701"
+       cy="141.15341"
+       rx="10.289877"
+       ry="8.9535294" />
+    <ellipse
+       style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5951-21"
+       cx="110.74701"
+       cy="176.2709"
+       rx="10.289877"
+       ry="8.9535294" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458302px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="63.877975"
+       y="108.2009"
+       id="text6017"><tspan
+         sodipodi:role="line"
+         id="tspan6015"
+         x="63.877975"
+         y="112.79115"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.65054"
+       y="142.50148"
+       id="text6021-3"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6"
+         x="110.65054"
+         y="142.50148"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">many</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;line-height:6.61458349px;font-family:MrsEavesPetiteCaps;-inkscape-font-specification:'MrsEavesPetiteCaps Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       x="110.70722"
+       y="174.647"
+       id="text6021-3-0"><tspan
+         sodipodi:role="line"
+         id="tspan6019-6-2"
+         x="110.70722"
+         y="174.647"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none">str</tspan><tspan
+         sodipodi:role="line"
+         x="110.70722"
+         y="181.29271"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93888903px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;stroke-width:0.75;stroke-miterlimit:4;stroke-dasharray:none"
+         id="tspan6059">foo</tspan></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 110.61211,150.10613 -0.25945,17.2179"
+       id="path6096"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="0"
+       inkscape:connection-start="#path5951-2"
+       inkscape:connection-end="#path5951-21" />
+  </g>
+</svg>
diff --git a/doc/user_guide.rst b/doc/user_guide.rst
new file mode 100644 (file)
index 0000000..0d58c8e
--- /dev/null
@@ -0,0 +1,7 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2019 Olivier Matz <zer0@droids-corp.org>
+
+User Guide
+==========
+
+Todo.
diff --git a/include/ecoli.h b/include/ecoli.h
new file mode 100644 (file)
index 0000000..f5c42d2
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ */
+
+/**
+ * @anchor main_page
+ * @mainpage About Libecoli
+ *
+ * This is the C API documentation of libecoli. This library provides
+ * helpers to build interactive command line interfaces.
+ *
+ * To create a command line parser, one should create a @ref
+ * grammar_tree, which is composed of @ref nodes. Then an input can be
+ * parsed or completed, respectively using the @ref parse and @ref
+ * complete APIs.
+ *
+ * The library also provides helpers to create a an interactive command
+ * line based on @ref editline library, and a @ref yaml parser for
+ * grammar trees.
+ */
+
+#ifndef ECOLI_
+#define ECOLI_
+
+#include <ecoli_assert.h>
+#include <ecoli_complete.h>
+#include <ecoli_config.h>
+#include <ecoli_dict.h>
+#include <ecoli_editline.h>
+#include <ecoli_htable.h>
+#include <ecoli_init.h>
+#include <ecoli_log.h>
+#include <ecoli_malloc.h>
+#include <ecoli_murmurhash.h>
+#include <ecoli_node_any.h>
+#include <ecoli_node_bypass.h>
+#include <ecoli_node_cmd.h>
+#include <ecoli_node_cond.h>
+#include <ecoli_node_dynamic.h>
+#include <ecoli_node_empty.h>
+#include <ecoli_node_expr.h>
+#include <ecoli_node_file.h>
+#include <ecoli_node.h>
+#include <ecoli_node_helper.h>
+#include <ecoli_node_int.h>
+#include <ecoli_node_many.h>
+#include <ecoli_node_none.h>
+#include <ecoli_node_once.h>
+#include <ecoli_node_option.h>
+#include <ecoli_node_or.h>
+#include <ecoli_node_re.h>
+#include <ecoli_node_re_lex.h>
+#include <ecoli_node_seq.h>
+#include <ecoli_node_sh_lex.h>
+#include <ecoli_node_space.h>
+#include <ecoli_node_str.h>
+#include <ecoli_node_subset.h>
+#include <ecoli_parse.h>
+#include <ecoli_string.h>
+#include <ecoli_strvec.h>
+#include <ecoli_test.h>
+#include <ecoli_utils.h>
+#include <ecoli_vec.h>
+#include <ecoli_yaml.h>
+
+#endif
index fcd218628fc433b5cee60b6f59eb71487c0b9858..c44dc14542dd29c05e3fe45605abc1b5a71d4672 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Assert API
+ * @defgroup assert Assert
+ * @{
+ *
+ * @brief Assertion helpers
  *
  * Helpers to check at runtime if a condition is true, or otherwise
  * either abort (exit program) or return an error.
@@ -53,3 +56,5 @@ void __ec_assert_print(bool expr, const char *expr_str,
        } while(0)
 
 #endif
+
+/** @} */
index 4c71b5dbe1dc36b31b4bbe7f89fbd278d07f0181..b28aa4a873ef77525591398df382a63a0cd77898 100644 (file)
@@ -3,12 +3,17 @@
  */
 
 /**
- * API for generating completions item on a node.
+ * @defgroup complete Complete
+ * @{
+ *
+ * @brief Complete string input using a grammar tree
  *
  * This file provide helpers to list and manipulate the possible
  * completions for a given input.
  *
  * XXX comp vs item
+ *
+ * @}
  */
 
 #ifndef ECOLI_COMPLETE_
index b6d638e867fe83413d03b11f821a346022a4e2a3..ba933378af7c8ce9ff3dbac9e3cfc6c17be3a99b 100644 (file)
@@ -2,6 +2,13 @@
  * Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup config Node configuration
+ * @{
+ *
+ * @brief Configure nodes behavior through generic API.
+ */
+
 #ifndef ECOLI_CONFIG_
 #define ECOLI_CONFIG_
 
@@ -402,3 +409,5 @@ ec_config_dup(const struct ec_config *config);
 void ec_config_dump(FILE *out, const struct ec_config *config);
 
 #endif
+
+/** @} */
index 77558fb2aec4e3f63ba624467e4c616413e85317..b4bf7802dd0a3bc7820a5c78b6bff1c33e42e971 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Simple hash table API
+ * @defgroup dict Dictionary
+ * @{
+ *
+ * @brief Simple hash table API (string keys)
  *
  * This file provides functions to store objects in hash tables, using strings
  * as keys.
@@ -184,3 +187,5 @@ void *
 ec_dict_iter_get_val(const struct ec_dict_elt_ref *iter);
 
 #endif
+
+/** @} */
index 58824d275829ed8d433e26e832b6c7ccc70d7cdc..414d58b433ac507a21a482a00d42a6138020c51d 100644 (file)
@@ -3,6 +3,11 @@
  */
 
 /**
+ * @defgroup editline Editline
+ * @{
+ *
+ * @brief Helpers for editline
+ *
  * Helpers that can be used to associate an editline instance with
  * an ecoli node tree.
  *
index 0bed676892ec0f97d7326dd76bff69cbf639dda1..3e9eab9dd31aa45d87d249ffb6414665bb80f171 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Simple hash table API
+ * @defgroup htable Hash table
+ * @{
+ *
+ * @brief Simple hash table API (any key)
  *
  * This file provides functions to store objects in hash tables,
  * using arbitrary data as keys.
@@ -206,3 +209,5 @@ void *
 ec_htable_iter_get_val(const struct ec_htable_elt_ref *iter);
 
 #endif
+
+/** @} */
index 80a0c01c8732c993154e06731b10a4d211f66361..39938f787454d27480b44d252c1792ec8605c92f 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Register initialization routines.
+ * @defgroup nodes Nodes
+ * @{
+ *
+ * @brief Register initialization routines.
  */
 
 #ifndef ECOLI_INIT_
@@ -74,3 +77,5 @@ int ec_init(void);
 void ec_exit(void);
 
 #endif
+
+/** @} */
index bc18f96380689f1c428d2e2e8433b0696ac4b570..9363d233ab74eeb0a8825f2ddf83eb8c7974f2e2 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Logging API
+ * @defgroup log Log
+ * @{
+ *
+ * @brief Log API
  *
  * This file provide logging helpers:
  * - logging functions, supporting printf-like format
@@ -237,3 +240,5 @@ int ec_log_level_set(enum ec_log_level level);
 enum ec_log_level ec_log_level_get(void);
 
 #endif
+
+/** @} */
index 42cbf87a30e6a3a1f70adfaf54d8c6938c5b483c..0e5d2ba19fcad85613634e4f10ca49dccbd63873 100644 (file)
@@ -3,6 +3,11 @@
  */
 
 /**
+ * @defgroup alloc Allocation
+ * @{
+ *
+ * @brief Helpers to allocate and free memory
+ *
  * Interface to configure the allocator used by libecoli.
  * By default, the standard allocation functions from libc are used.
  */
@@ -253,3 +258,5 @@ char *__ec_strndup(const char *s, size_t n, const char *file,
 
 
 #endif
+
+/** @} */
index 6b76d34242b6b23f620614ca4fa5faf58514ee08..2cfd292b35027a93df6af22680032b086d56c7e3 100644 (file)
@@ -3,6 +3,11 @@
  */
 
 /**
+ * @defgroup murmurhash Murmurhash
+ * @{
+ *
+ * @brief Hash calculation using murmurhash algorithm
+ *
  * MurmurHash3 is a hash implementation that was written by Austin Appleby, and
  * is placed in the public domain. The author hereby disclaims copyright to this
  * source code.
@@ -64,3 +69,5 @@ static inline uint32_t ec_murmurhash3_fmix32(uint32_t h)
 uint32_t ec_murmurhash3(const void *key, int len, uint32_t seed);
 
 #endif /* ECOLI_MURMURHASH_H_ */
+
+/** @} */
index acd1daa455a2e29f8ee824934b8dcfd55227ea62..894e64f8fbe146cf64ae9d8142b0f7110e99f47d 100644 (file)
@@ -3,10 +3,13 @@
  */
 
 /**
- * Interface to manage the ecoli nodes.
+ * @defgroup grammar_tree Grammar Tree
+ * @{
  *
- * A node is a main structure of the ecoli library, used to define how
- * to match and complete the input tokens. A node is a generic object
+ * @brief Libecoli grammar nodes.
+ *
+ * The grammar node is a main structure of the ecoli library, used to define
+ * how to match and complete the input tokens. A node is a generic object
  * that implements:
  * - a parse(node, input) method: check if an input matches
  * - a complete(node, input) method: return possible completions for
@@ -46,6 +49,9 @@
 #include <sys/types.h>
 #include <stdio.h>
 
+/**
+ * Node has no identifier.
+ */
 #define EC_NO_ID "no-id"
 
 #define EC_NODE_ENDLIST ((void *)1)
@@ -204,3 +210,5 @@ int ec_node_check_type(const struct ec_node *node,
                const struct ec_node_type *type);
 
 #endif
+
+ /** @} */
index cb671e385ae259b773f5aae9ba68168be9531d32..3f21927a1279f3f15e0bc99082c38e3c644ad4f1 100644 (file)
@@ -3,6 +3,9 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * This node always matches 1 string in the vector.
  * An optional strvec attribute can be checked too. These
  * attributes are usually set by a lexer node.
@@ -25,3 +28,5 @@ struct ec_node *
 ec_node_any(const char *id, const char *attr);
 
 #endif
+
+/** @} */
index a5efb4612f4716aee4d62f02b7e3091773c36a66..024bcae5cb83d70cc22a995bbfc0a267d3f58b07 100644 (file)
@@ -3,6 +3,9 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * A node that does nothing else than calling the child node.
  * It can be helpful to build loops in a node graph.
  */
@@ -16,3 +19,5 @@ struct ec_node *ec_node_bypass(const char *id, struct ec_node *node);
 int ec_node_bypass_set_child(struct ec_node *gen_node, struct ec_node *child);
 
 #endif
+
+/** @} */
index 99afc0181666b9aeca1f29836c4489cd5b63ecbf..a60549265ee53eb64cbb18049a0fea4582b69bf4 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_CMD_
 #define ECOLI_NODE_CMD_
 
@@ -12,3 +17,5 @@
 struct ec_node *__ec_node_cmd(const char *id, const char *cmd_str, ...);
 
 #endif
+
+/** @} */
index 37da1a45b692552891ed748b8a67143ab854b384..83f7d4ec2aa986e827dc1c0e7a069114065901a0 100644 (file)
@@ -3,6 +3,9 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * The condition node checks that an expression is true before
  * parsing/completing the child node. If it is false, the node
  * doesn't match anything.
@@ -29,3 +32,5 @@ struct ec_node *ec_node_cond(const char *id, const char *cond_str,
        struct ec_node *child);
 
 #endif
+
+/** @} */
index 4f2535e28c0e9a9df201acf4dbf36fe16e81fdd0..65d3085b1d1519882bf32d6d5e3f002c8a1bc715 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2017, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_DYNAMIC_
 #define ECOLI_NODE_DYNAMIC_
 
@@ -17,3 +22,5 @@ struct ec_node *ec_node_dynamic(const char *id, ec_node_dynamic_build_t build,
                                void *opaque);
 
 #endif
+
+/** @} */
index ed5e32ef935e42f4d6bbfb85e5d93fe78ab0bcba..bfafc9bb1ab0f4265fa5995f5a71a36c99d96c08 100644 (file)
@@ -3,6 +3,9 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * This node always matches an empty string vector
  */
 
@@ -12,3 +15,5 @@
 struct ec_node *ec_node_empty(const char *id);
 
 #endif
+
+/** @} */
index 4f21d81128fab91563b6e1f91a44149137577489..15f81ae462b616b18bd5bc31ba3e3eebb57681a6 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_EXPR_
 #define ECOLI_NODE_EXPR_
 
@@ -91,3 +96,5 @@ int ec_node_expr_eval(void **result, const struct ec_node *node,
        void *userctx);
 
 #endif
+
+/** @} */
index 576090225e25686999f45b8f8551c8a2238493f9..cadad838d7b4c81de340cb35b85b8ff2b8478895 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_FILE_
 #define ECOLI_NODE_FILE_
 
@@ -13,3 +18,5 @@ struct ec_node *ec_node_file(const char *id, const char *file);
 int ec_node_file_set_str(struct ec_node *node, const char *file);
 
 #endif
+
+/** @} */
index b64c60c2e5b723dc417f0a01c81ede13a22089e9..6fac1c152e2d603b39b6d46b077d9dc552d34b31 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_INT_
 #define ECOLI_NODE_INT_
 
@@ -26,5 +31,6 @@ struct ec_node *ec_node_uint(const char *id, uint64_t min,
 int ec_node_uint_getval(const struct ec_node *node, const char *str,
                        uint64_t *result);
 
-
 #endif
+
+/** @} */
index 0a50fd704eb9c4de7b7dc8edc4645ff17779acae..bc31542be4e75e18168726c5ee1adb077488c79f 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_MANY_
 #define ECOLI_NODE_MANY_
 
@@ -16,3 +21,5 @@ ec_node_many_set_params(struct ec_node *gen_node, struct ec_node *child,
        unsigned int min, unsigned int max);
 
 #endif
+
+/** @} */
index 842f211cd63d90bbb32982a079996e72055c475f..b5e368e0e8731fe3ec3135f617332d3acb89dbbf 100644 (file)
@@ -3,10 +3,15 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * This node does not match anything
  */
 
-#ifndef ECOLI_NODE_ANY_
-#define ECOLI_NODE_ANY_
+#ifndef ECOLI_NODE_NONE_
+#define ECOLI_NODE_NONE_
 
 #endif
+
+/** @} */
index 690a10c9371b69b6e0837345c18f79ac2aacfbad..3e0552511754380fd25e85dc38235ec70601fd72 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_ONCE_
 #define ECOLI_NODE_ONCE_
 
@@ -27,3 +32,5 @@ struct ec_node *ec_node_once(const char *id, struct ec_node *child);
 int ec_node_once_set_child(struct ec_node *node, struct ec_node *child);
 
 #endif
+
+/** @} */
index 9f06d5f099cf936516e832ebb284280a02b0ded5..c88fb23c32eb4dd45b739b58ae784403f831eb89 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_OPTION_
 #define ECOLI_NODE_OPTION_
 
@@ -11,3 +16,5 @@ struct ec_node *ec_node_option(const char *id, struct ec_node *node);
 int ec_node_option_set_child(struct ec_node *gen_node, struct ec_node *child);
 
 #endif
+
+/** @} */
index db115b2a3f70ce75812a9c9ebfedfc941c2aed76..1738af1310b7da0311a4fb9eeafd1418d51bda36 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_OR_
 #define ECOLI_NODE_OR_
 
@@ -20,5 +25,6 @@ struct ec_node *ec_node_or(const char *id);
 /* child is consumed */
 int ec_node_or_add(struct ec_node *node, struct ec_node *child);
 
-
 #endif
+
+/** @} */
index bc3a317ea713cde7186e7e783a1e195146a02da0..66957c7b34a2e5b9e8b7cbc030f7d926fcfd11b9 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_RE_
 #define ECOLI_NODE_RE_
 
@@ -13,3 +18,5 @@ struct ec_node *ec_node_re(const char *id, const char *str);
 int ec_node_re_set_regexp(struct ec_node *node, const char *re);
 
 #endif
+
+/** @} */
index 94d426e0d2e186ebe0327c51a6653ccd3bb388ce..c6aea65d4ea63905f22b7703e8875a3197d945f5 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_RE_LEX_
 #define ECOLI_NODE_RE_LEX_
 
@@ -13,3 +18,5 @@ int ec_node_re_lex_add(struct ec_node *gen_node, const char *pattern, int keep,
        const char *attr_name);
 
 #endif
+
+/** @} */
index 21c96b1172b6a251506ab25215fb1ba13d8f6ef3..e1f389668a2e83e6cb9ddfae946777208c97f3bb 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_SEQ_
 #define ECOLI_NODE_SEQ_
 
@@ -21,3 +26,5 @@ struct ec_node *ec_node_seq(const char *id);
 int ec_node_seq_add(struct ec_node *node, struct ec_node *child);
 
 #endif
+
+/** @} */
index d45b998938f815546c4a05489ae141bcc32a7f5c..bbe250513799239ab0e9810eac4601f4d2ffc33e 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_SHLEX_
 #define ECOLI_NODE_SHLEX_
 
@@ -10,3 +15,5 @@
 struct ec_node *ec_node_sh_lex(const char *id, struct ec_node *child);
 
 #endif
+
+/** @} */
index 0dd62022c6cdcc9535478b9461ff876c78e8937c..bb4dac9ed764dc40bd2ab5c777b46eab324d514a 100644 (file)
@@ -3,6 +3,9 @@
  */
 
 /**
+ * @defgroup nodes Nodes
+ * @{
+ *
  * This node matches one string in the vector if it is only composed of
  * spaces, as interpreted by isspace().
  */
@@ -13,3 +16,5 @@
 /* no API for now, since there is no specific configuration for this node */
 
 #endif
+
+/** @} */
index 8a8634f017bb99acdcd9c450bfb728fa3bcaa06d..de2454fc13920c20f0a3dc6078336247d76ee95d 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_STR_
 #define ECOLI_NODE_STR_
 
@@ -13,3 +18,5 @@ struct ec_node *ec_node_str(const char *id, const char *str);
 int ec_node_str_set_str(struct ec_node *node, const char *str);
 
 #endif
+
+/** @} */
index 734b1aeab7128c128d7c2e458f2f69011fd5bd96..6ec33190ab8123f443bc4fefec12d8e6e7aa802f 100644 (file)
@@ -2,6 +2,11 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup nodes Nodes
+ * @{
+ */
+
 #ifndef ECOLI_NODE_SUBSET_
 #define ECOLI_NODE_SUBSET_
 
@@ -21,3 +26,5 @@ struct ec_node *ec_node_subset(const char *id);
 int ec_node_subset_add(struct ec_node *node, struct ec_node *child);
 
 #endif
+
+/** @} */
index c88fc18a611a9a1b302d2848193bf047da1b1383..a64c0ae43e8f76eb3860415f8f726b8e0b5af9dd 100644 (file)
@@ -3,11 +3,18 @@
  */
 
 /**
+ * @defgroup parse Parse
+ * @{
+ *
+ * @brief Create parse tree from string input and grammar tree
+ *
  * Node parse API.
  *
  * The parse operation is to check if an input (a string or vector of
  * strings) matches the node tree. On success, the result is stored in a
  * tree that describes which part of the input matches which node.
+ *
+ * @}
  */
 
 #ifndef ECOLI_PARSE_
index d611a13369e1c1fbe7334d46cb80eeacfa601a33..3ef022cb9e5864d59403b87c7a05e54ccfcb67dc 100644 (file)
@@ -2,6 +2,13 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup string String
+ * @{
+ *
+ * @brief Helpers for strings manipulation.
+ */
+
 #ifndef ECOLI_STRING_
 #define ECOLI_STRING_
 
index 727d4c8d785b5f168b6bc46bf501e1c2eefa6066..2464a2bb2ce658fa947c3d4a68bfaa6caa3076a6 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Vectors of strings.
+ * @defgroup strvec String vectors
+ * @{
+ *
+ * @brief Helpers for strings vectors manipulation.
  *
  * The ec_strvec API provide helpers to manipulate string vectors.
  * When duplicating vectors, the strings are not duplicated in memory,
@@ -222,3 +225,5 @@ void ec_strvec_sort(struct ec_strvec *strvec,
 void ec_strvec_dump(FILE *out, const struct ec_strvec *strvec);
 
 #endif
+
+/** } */
index 94cd0b9ba78a93ac4d716ef8f639d0af4e4418ca..e4b091b38e3c4f89b797f9644951de64b1726c7a 100644 (file)
@@ -2,6 +2,13 @@
  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup test Test
+ * @{
+ *
+ * @brief Helpers for unit tests
+ */
+
 #ifndef ECOLI_TEST_
 #define ECOLI_TEST_
 
@@ -95,3 +102,5 @@ int ec_test_check_complete(struct ec_node *node,
 })
 
 #endif
+
+/** @} */
index 5a141925e7fefebb0af5c6c0ebead9f5dee2d56a..98bfcc929dc0debe1a7d080818e47556a700e94c 100644 (file)
@@ -2,6 +2,14 @@
  * Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
  */
 
+/**
+ * @defgroup utils Utils
+ * @{
+ *
+ * @brief Misc utils
+ */
+
+
 #ifndef ECOLI_UTILS_
 #define ECOLI_UTILS_
 
@@ -14,3 +22,5 @@
        })
 
 #endif
+
+/** @} */
index 5fdaa9986c9e171bf054e4e32c0064c858a137fd..784d44048d4afeed6c6df33baa96357ac01309cf 100644 (file)
@@ -3,7 +3,10 @@
  */
 
 /**
- * Vectors of objects.
+ * @defgroup vec Vectors
+ * @{
+ *
+ * @brief Helpers for vectors manipulation.
  *
  * The ec_vec API provide helpers to manipulate vectors of objects
  * of any kind.
@@ -45,3 +48,5 @@ __attribute__((pure))
 size_t ec_vec_len(const struct ec_vec *vec);
 
 #endif
+
+/** @} */
index a63d837eca0d38c0d5087f0b1d033d38475238c6..6d26bbc6803ecd15e8551fe5b53dc8ec11c47d76 100644 (file)
@@ -3,6 +3,11 @@
  */
 
 /**
+ * @defgroup yaml Yaml
+ * @{
+ *
+ * @brief YAML import/export
+ *
  * Interface to import/export ecoli data structures in YAML.
  */
 
@@ -23,3 +28,5 @@ struct ec_node;
 struct ec_node *ec_yaml_import(const char *filename);
 
 #endif
+
+/** } */
index 1b979220821f5fe5023eebef48d163f10a7cb234..b7eeb60e4000fc21eed974b6a13d26565f7d341b 100644 (file)
@@ -2,6 +2,7 @@
 # Copyright 2018, Olivier MATZ <zer0@droids-corp.org>
 
 libecoli_headers = [
+       'ecoli.h',
        'ecoli_assert.h',
        'ecoli_complete.h',
        'ecoli_config.h',
index 0e7ebb015fdc1b1c59e7acde4efe8ebf442dd70d..ca9ddf16d309084f62a42b27740bc20e65e3b305 100644 (file)
@@ -19,6 +19,7 @@ priv_inc = include_directories('src')
 subdir('src')
 subdir('test')
 subdir('examples')
+subdir('doc')
 
 pkg_mod = import('pkgconfig')
 pkg_mod.generate(libraries : libecoli,