1 .. SPDX-License-Identifier: BSD-3-Clause
2 Copyright 2019 Olivier Matz <zer0@droids-corp.org>
7 Most of *libecoli* is written in C. It provides a C API to ease the
8 creation of interactive command line interfaces. It is split in several
11 - the core: it provides the main API to parse and complete strings.
12 - ecoli nodes: this is the modular part of *libecoli*. Each node
13 implements a specific parsing (integers, strings, regular expressions,
15 - yaml parser: load an ecoli tree described in yaml.
16 - editline: helpers to instantiate an *editline* and connect it to
18 - utilities: logging, string, strings vector, hash table, ...
23 The *ecoli nodes* are organized in a tree. An *ecoli grammar tree*
24 describes how the input is parsed and completed. Let's take a simple
27 .. figure:: simple-tree.svg
29 A simple *ecoli grammar tree*.
31 We can also represent it as text like this::
42 This tree matches the following strings:
47 But, for instance, it does **not** match the following strings:
56 When the *libecoli* parses an input, it browses the tree (depth first
57 search) and returns an *ecoli parse tree*. Let's decompose what is done
58 when ``ec_node_parse_strvec(root_node, input)`` is called, step by step:
60 1. The initial input is a string vector ``["foo bar"]``.
61 2. The *sh_lex* node splits the input as a shell would have done it, in
62 ``["foo", "bar"]``, and passes it to its child.
63 3. The *seq* node (sequence) passes the input to its first child.
64 4. The *str* node matches if the first element of the string vector is
65 ``foo``. This is the case, so it returns the number of eaten
66 strings (1) to its parent.
67 5. The *seq* node passes the remaining part ``["bar"]`` to its next
69 6. The option node passes the string vector to its child, which
70 matches. It returns 1 to its parent.
71 7. The *seq* node has no more child, it returns the number of eaten
72 strings in the vector (2).
73 8. Finally, *sh_lex* compares the returned value to the number of
74 strings in its initial vector, and return 1 (match) to its caller.
76 If a node does not match, it returns ``EC_PARSE_NOMATCH`` to its parent,
77 and it is propagated until it reaches a node that handle the case. For
78 instance, the *or* node is able to handle this error. If a child does
79 not match, the next one is tried until it finds one that matches.
84 Let's take another simple example.
86 .. figure:: simple-tree2.svg
88 Another simple *ecoli grammar tree*.
90 In that case, there is no lexer (the *sh_lex* node), so the input must
91 be a string vector that is already split. For instance, it matches:
97 But it does **not** match:
99 - ``["bar 1"]``, because there is no *sh_lex* node on the top of the tree
101 - ``[]`` (empty vector)
103 At the time the input is parsed, a *parse tree* is built. When it
104 matches, it describes which part of the *ecoli grammar tree* that
105 actually matched, and what input matched for each node.
107 Passing ``["bar", "1"]`` to the previous tree would result in the
108 following *parse tree*:
110 .. figure:: parse-tree.svg
112 The *ecoli parse tree*, result of parsing.
114 Each node of the *parse tree* references the node of the *grammar tree*
115 that matched. It also stores the string vector that matched.
117 .. figure:: parse-tree2.svg
119 The same *ecoli parse tree*, showing the references to the grammar
122 We can see that not all of the grammar nodes are referenced, since the
123 str("foo") node was not parsed. Similarly, one grammar node can be
124 referenced several times in the parse tree, as we can see it in the
127 .. figure:: simple-tree3.svg
129 A simple *ecoli grammar tree*, that matches ``[]``, ``[foo]``,
132 Here is the resulting *parse tree* when the input vector is ``[foo, foo,
135 .. figure:: parse-tree3.svg
137 The resulting *parse tree*.
151 - params are consumed