Conflicts: lark/common.py lark/exceptions.py lark/lexer.py lark/load_grammar.py lark/parser_frontends.pytags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.11.2
@@ -106,7 +106,7 @@ Lark is great at handling ambiguity. Here is the result of parsing the phrase "f | |||
- MyPy support using type stubs | |||
- And much more! | |||
See the full list of [features here](https://lark-parser.readthedocs.io/en/latest/features/) | |||
See the full list of [features here](https://lark-parser.readthedocs.io/en/latest/features.html) | |||
### Comparison to other libraries | |||
@@ -132,7 +132,7 @@ Check out the [JSON tutorial](/docs/json_tutorial.md#conclusion) for more detail | |||
|:--------|:----------|:----|:--------|:------------|:------------|:----------|:---------- | |||
| **Lark** | Earley/LALR(1) | EBNF | Yes! | Yes! | Yes! | Yes! | Yes! (LALR only) | | |||
| [PLY](http://www.dabeaz.com/ply/) | LALR(1) | BNF | No | No | No | No | No | | |||
| [PyParsing](http://pyparsing.wikispaces.com/) | PEG | Combinators | No | No | No\* | No | No | | |||
| [PyParsing](https://github.com/pyparsing/pyparsing) | PEG | Combinators | No | No | No\* | No | No | | |||
| [Parsley](https://pypi.python.org/pypi/Parsley) | PEG | EBNF | No | No | No\* | No | No | | |||
| [Parsimonious](https://github.com/erikrose/parsimonious) | PEG | EBNF | Yes | No | No\* | No | No | | |||
| [ANTLR](https://github.com/antlr/antlr4) | LL(*) | EBNF | Yes | No | Yes? | Yes | No | | |||
@@ -0,0 +1,212 @@ | |||
<!DOCTYPE html> | |||
<!-- saved from url=(0115)https://web.archive.org/web/20200128172318/http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/ --> | |||
<html lang="en-us"> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |||
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> | |||
<body> | |||
<div class="container"> | |||
<article class="article" itemscope itemtype="http://schema.org/Article"> | |||
<h1 itemprop="name">Shared Packed Parse Forest (SPPF)</h1> | |||
<div class="article-metadata" style="font-size: 80%"> | |||
<span class="article-date"> | |||
<time datetime="2014-06-27 12:00:00 +0000 UTC" itemprop="datePublished"> | |||
Fri, Jun 27, 2014 | |||
</time> | |||
</span> | |||
<span class="article-tags"> | |||
<i class="fa fa-tags"></i> | |||
<a class="article-tag-link" href="https://web.archive.org/web/20200128172318/http://www.bramvandersanden.com/tags/parsing">parsing</a>, | |||
<a class="article-tag-link" href="https://web.archive.org/web/20200128172318/http://www.bramvandersanden.com/tags/sppf">sppf</a> | |||
</span> | |||
</div> | |||
<div class="article-style" itemprop="articleBody"> | |||
<p></p> | |||
<p>In the last decade there has been a lot of interest in generalized parsing techniques. These techniques can be used to generate a working parser for any context-free grammar. This means that we no longer have to massage our grammar to fit into restricted classes such as <em>LL(k)</em> or <em>LR(k)</em>. Supporting all context-free grammars means that grammars can be written in a natural way, and grammars can be combined, since the class of context-free grammars is closed under composition.</p> | |||
<p>One of the consequences of supporting the whole class of context-free grammars is that also ambiguous grammars are supported. In an ambiguous grammar there are sentences in the language that can be derived in multiple ways. Each derivation results in a distinct parse tree. For each additional ambiguity in the input sentence, the number of derivations might grow exponentially. Therefore generalized parsers output a parse forest, rather than a set of the parse trees. In this parse forest, often sharing is used used to reduce the total space required to represent all derivation trees. Nodes which have the same subtree are shared, and nodes are combined which correspond to different derivations of the same substring. A parse forest where sharing is employed is called a shared packed parse forest (SPPF).</p> | |||
<p>This article will describe the SPPF data structure in more detail. More information about the generation of the SPPF using the GLL algorithm can be found in the paper <a href="https://web.archive.org/web/20200128172318/http://dx.doi.org/10.1016/j.scico.2012.03.005">GLL parse-tree generation</a> by E. Scott and A. Johnstone. Right Nulled GLR parsers can also be used to generate an SPPF, which is described in the paper <a href="https://web.archive.org/web/20200128172318/http://doi.acm.org/10.1145/1146809.1146810">Right Nulled GLR Parsers</a> by E. Scott and A. Johnstone.</p> | |||
<p>There are three types of nodes in an SPPF associated with a GLL parser: <em>symbol nodes</em>, <em>packed nodes</em>, and <em>intermediate nodes</em>. In the visualizations symbol nodes are shown as rectangles with rounded corners, packed nodes are shown as circles, or ovals when the label is visualized, and intermediate nodes are shown as rectangles.</p> | |||
<p>Symbol nodes have labels of the form $(x,j,i)$ where $x$ is a terminal, nonterminal, or $\varepsilon$ (i.e. $x \in T \cup N \cup \lbrace \varepsilon \rbrace$), and $0 \leq j \leq i \leq m$ with $m$ being the length of the input sentence. The tuple $(j,i)$ is called the <em>extent</em>, and denotes that the symbol $x$ has been matched on the substring from position $j$ up to position $i$. Here $j$ is called the <em>left extent</em>, and $i$ is called the <em>right extent</em>.</p> | |||
<p>Packed nodes have labels of the form $(t,k)$, where $0 \leq k \leq m$. Here $k$ is called the <em>pivot</em>, and $t$ is of the form $X ::= \alpha \cdot \beta$. The value of $k$ represents that the last symbol of $\alpha$ ends at position $k$ of the input string. Packed nodes are used to represent multiple derivation trees. When multiple derivations are possible with the same extent, starting from the same nonterminal symbol node, a separate packed node is added to the symbol node for each derivation.</p> | |||
<p>Intermediate nodes are used to binarize the SPPF. They are introduced from the left, and group the children of packed nodes in pairs from the left. The binarization ensures that the size of the SPPF is worst-case cubic in the size of the input sentence. The fact that the SPPF is binarized does not mean that each node in the SPPF has at most two children. A symbol node or intermediate node can still have as many packed node children as there are ambiguities starting from it. Intermediate nodes have labels of the form $(t,j,i)$ where $t$ is a grammar slot, and $(j,i)$ is the extent. There are no intermediate nodes of the shape $(A ::= \alpha \cdot, j,i)$, where the grammar pointer of the grammar slot is at the end of the alternate. These grammar slots are present in the form of symbol nodes.</p> | |||
<p>Consider the following grammar:</p> | |||
<p>$\quad S ::= ABCD \quad A ::= a \quad B ::= b \quad C ::= c \quad D ::= d. $</p> | |||
<p>Then given input sentence $abcd$, the the following SPPF will be the result:</p> | |||
<figure> | |||
<img src="sppf_abcd.svg"/> | |||
<figcaption> | |||
<h4>SPPF with intermediate nodes</h4> | |||
</figcaption> | |||
</figure> | |||
<p>Suppose that the intermediate nodes had not been added to the SPPF. Then the nonterminal symbol nodes for $A$, $B$, $C$, and $D$ would have been attached to the nonterminal symbol node $S$:</p> | |||
<figure> | |||
<img src="sppf_abcd_noint.svg"/> | |||
<figcaption> | |||
<h4>SPPF without intermediate nodes</h4> | |||
</figcaption> | |||
</figure> | |||
<p>This example shows how intermediate nodes ensure that the tree is binarized.</p> | |||
<h2 id="adding-cycles">Adding cycles</h2> | |||
<p>Grammars that contain cycles can generate sentences which have infinitely many derivation trees. A context-free grammar is cyclic if there exists a nonterminal $A \in N$ and a derivation $A \overset{+}\Rightarrow A$. Note that a cyclic context-free grammar implies that the context-free grammar is left-recursive, but the converse does not hold. The derivation trees for a cyclic grammar are represented in the finite SPPF by introducing cycles in the graph.</p> | |||
<p>Consider the following cyclic grammar: | |||
$S ::= SS \mid a \mid \varepsilon$.</p> | |||
<p>Given input sentence $a$, there are infinitely many derivations. All these derivations are present in the following SPPF:</p> | |||
<figure> | |||
<img src="sppf_cycle.svg"/> | |||
<figcaption> | |||
<h4>SPPF containing an infinite number of derivations</h4> | |||
</figcaption> | |||
</figure> | |||
<h2 id="ambiguities">Ambiguities</h2> | |||
<p>A parse forest is <em>ambiguous</em> if and only if it contains at least one ambiguity. An ambiguity arises when a symbol node or intermediate node has at least two packed nodes as its children. Such nodes are called <em>ambiguous</em>. Consider for instance the following grammar with input sentence $1+1+1$: | |||
$ E ::= E + E \mid 1 $.</p> | |||
<p>This gives the following SPPF:</p> | |||
<figure> | |||
<img src="sppf_111.svg"/> | |||
<figcaption> | |||
<h4>SPPF containing an ambiguous root node</h4> | |||
</figcaption> | |||
</figure> | |||
<p>In this SPPF, symbol node $(E,0,5)$ has two packed nodes as children. This means that there are at least two different parse trees starting at this node, the parse trees representing derivations $(E+(E+E))$ and $((E+E)+E)$ respectively.</p> | |||
<p>The set of all parse trees present in the SPPF is defined in the following way:</p> | |||
<p>Start at the root node of the SPPF, and walk the tree by choosing one packed node below each visited node, and choosing all the children of a visited packed node in a recursive manner.</p> | |||
<h2 id="structural-properties">Structural Properties</h2> | |||
<p>There are various structural properties that are useful when reasoning about SPPFs in general. At first note that each symbol node $(E,j,i)$ with $E \in T \cup N \cup \lbrace \varepsilon \rbrace$ is unique, so an SPPF does not contain two symbol nodes $(A,k,l)$ and $(B,m,n)$ with $A = B, k = m$, and $l=n$.</p> | |||
<p>Terminal symbol nodes have no children. These nodes represent the leaves of the parse forest. Nonterminal symbol nodes $(A,j,i)$ have packed node children of the form $(A ::= \gamma \cdot, k)$ with $j \leq k \leq i$, and the number of children is not limited to two.</p> | |||
<p>Intermediate nodes $(t,j,i)$ have packed node children with labels of the form $(t,k)$, where $j \leq k \leq i$.</p> | |||
<p>Packed nodes $(t,k)$ have one or two children. The right child is a symbol node $(x,k,i)$ and the left child (if it exists) is a symbol or intermediate node with label $(s,j,k)$, where $j \leq k \leq i$. Packed nodes have always exactly one parent which is a symbol node or intermediate node.</p> | |||
<p>It is useful to observe that the SPPF is a bipartite graph, with on the one hand the set of intermediate and symbol nodes and on the other hand the set of packed nodes. Therefore edges always go from a node of the first type to a node of the second type, or the other way round. As a consequence, cyles in the SPPF are always of even length.</p> | |||
<h2 id="transformation-to-an-abstract-syntax-tree">Transformation to an abstract syntax tree</h2> | |||
<p>In the end, we often want a single abstract syntax tree (AST) when parsing an input sentence. In order to arrive at this AST, we need disambiguation techniques to remove undesired parse trees from the SPPF or avoid the generation of undesired parse trees in the first place. {% cite sanden2014thesis %} describes several SPPF disambiguation filters that remove ambiguities arising in expression grammars. Furthermore a method is described to integrate parse-time filtering in GLL that tries to avoid embedding undesired parse trees in the SPPF.</p> | |||
<p>Of course, other transformation might be needed such as the removal of whitespace and comments from the parse forest.</p> | |||
</div> | |||
</article> | |||
<nav> | |||
<ul class="pager"> | |||
<li class="next"><a href="https://web.archive.org/web/20200128172318/http://www.bramvandersanden.com/post/2016/10/2016-10-31-fdl-presentation/">Compositional Specification of Functionality and Timing of Manufacturing Systems <span aria-hidden="true">→</span></a></li> | |||
</ul> | |||
</nav> | |||
<footer class="site-footer"> | |||
<div class="container"> | |||
<p class="powered-by"> | |||
© 2016 Bram van der Sanden · | |||
Powered by the <a href="https://web.archive.org/web/20200128172318/https://github.com/gcushen/hugo-academic" target="_blank">Academic | |||
theme</a> for <a href="https://web.archive.org/web/20200128172318/http://gohugo.io/" target="_blank">Hugo</a>. | |||
<span class="pull-right" aria-hidden="true"> | |||
<a href="#" id="back_to_top"> | |||
<span class="button_icon"> | |||
<i class="fa fa-chevron-up fa-2x"></i> | |||
</span> | |||
</a> | |||
</span> | |||
<p>Source: <a href="https://web.archive.org/web/20200128172318/http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/">Wayback Machine</a> | |||
copy of <code>http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/</code> used to be. | |||
</p> | |||
</p> | |||
</div> | |||
</footer> | |||
</body> |
@@ -0,0 +1,765 @@ | |||
<?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:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.1" | |||
width="538.75" | |||
height="490" | |||
id="svg2" | |||
xml:space="preserve"><metadata | |||
id="metadata8"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs6"><clipPath | |||
id="clipPath16"><path | |||
d="M 0,0 509,0 509,472 0,472 0,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path18" /></clipPath><clipPath | |||
id="clipPath20"><path | |||
d="m 36,436 438,0 0,-401 -438,0 0,401 z" | |||
inkscape:connector-curvature="0" | |||
id="path22" /></clipPath></defs><g | |||
transform="matrix(1.25,0,0,-1.25,0,490)" | |||
id="g10"><g | |||
transform="translate(-39,-40)" | |||
id="g12"><g | |||
id="g14" /><g | |||
id="g24"><g | |||
clip-path="url(#clipPath16)" | |||
id="g26"><g | |||
id="g28"><path | |||
d="m 36,436 438,0 0,-401 -438,0 0,401 z" | |||
inkscape:connector-curvature="0" | |||
id="path30" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g | |||
id="g32"><g | |||
clip-path="url(#clipPath20)" | |||
id="g34"><path | |||
d="m 36,436 438,0 0,-401 -438,0 0,401 z" | |||
inkscape:connector-curvature="0" | |||
id="path36" | |||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 278,431.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path38" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 238,431.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path40" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 231,424.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path42" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 231,417.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path44" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 238,410.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path46" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 278,410.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path48" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 285,417.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path50" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 285,424.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path52" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,239,418.5)" | |||
id="text54"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan56" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 0, 5)</tspan></text> | |||
<path | |||
d="m 210,384 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path58" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 243.523,410.496 c -9.019,-6.543 -20.316,-14.738 -27.937,-20.269" | |||
inkscape:connector-curvature="0" | |||
id="path60" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 216.891,388.148 -7.102,-2.125 4.227,6.094 2.875,-3.969 z" | |||
inkscape:connector-curvature="0" | |||
id="path62" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 312,384 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path64" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 272.477,410.496 c 9.019,-6.543 20.316,-14.738 27.937,-20.269" | |||
inkscape:connector-curvature="0" | |||
id="path66" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 301.984,392.117 4.227,-6.094 -7.102,2.125 2.875,3.969 z" | |||
inkscape:connector-curvature="0" | |||
id="path68" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 78,209.5 106,0 0,-21 -106,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path70" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,85.5,196.5)" | |||
id="text72"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 18.709543 26.959343 29.949268 35.939121 38.92905 47.16885 50.158775 56.148628 59.148556 65.138412 68.128334 71.118263 77.118118 80.108047 86.107903" | |||
y="0" | |||
id="tspan74" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E ::= E + • E ,0,2)</tspan></text> | |||
<path | |||
d="M 204.113,382.902 C 190.23,377.426 131,351.621 131,310 c 0,0 0,0 0,-37 0,-19.254 0,-41.328 0,-56.32" | |||
inkscape:connector-curvature="0" | |||
id="path76" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 133.449,216.539 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path78" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 227,357.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path80" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 187,357.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path82" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 180,350.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path84" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 180,343.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path86" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 187,336.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path88" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 227,336.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path90" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 234,343.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path92" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 234,350.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path94" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,188,344.5)" | |||
id="text96"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan98" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 2, 5)</tspan></text> | |||
<path | |||
d="m 207,380.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path100" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 209.449,364.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path102" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 462,283.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path104" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,283.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path106" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 415,276.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path108" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 415,269.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path110" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,262.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path112" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 462,262.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path114" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 469,269.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path116" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 469,276.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path118" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,423,270.5)" | |||
id="text120"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan122" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 4, 5)</tspan></text> | |||
<path | |||
d="m 312.211,383.301 c 9.875,-2.27 40.355,-10.172 60.789,-25.301 25.441,-18.84 46.984,-49.141 58.934,-68.02" | |||
inkscape:connector-curvature="0" | |||
id="path124" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 434.289,290.828 1.602,-7.242 -5.77,4.664 4.168,2.578 z" | |||
inkscape:connector-curvature="0" | |||
id="path126" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 256,357.5 106,0 0,-21 -106,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path128" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,263.5,344.5)" | |||
id="text130"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 18.709543 26.959343 29.949268 35.939121 38.92905 47.16885 50.158775 56.148628 59.148556 65.138412 68.128334 71.118263 77.118118 80.108047 86.107903" | |||
y="0" | |||
id="tspan132" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E ::= E + • E ,0,4)</tspan></text> | |||
<path | |||
d="m 309,380.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path134" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 311.449,364.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path136" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 134,162 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path138" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 131,188.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path140" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 133.449,172.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path142" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 343,310 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path144" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 234.383,339.02 c 3.57,-1.024 7.179,-2.051 10.617,-3.02 30.836,-8.684 67.418,-18.582 84.82,-23.266" | |||
inkscape:connector-curvature="0" | |||
id="path146" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 330.918,314.977 6.121,-4.184 -7.394,-0.551 1.273,4.735 z" | |||
inkscape:connector-curvature="0" | |||
id="path148" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path150" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path152" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path154" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path156" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path158" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path160" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path162" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path164" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,48,122.5)" | |||
id="text166"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan168" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 0, 1)</tspan></text> | |||
<path | |||
d="m 128.25,160.41 c -6.348,-3.672 -22.57,-13.047 -36.723,-21.23" | |||
inkscape:connector-curvature="0" | |||
id="path170" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 92.496,136.91 -7.285,-1.383 4.836,5.625 2.449,-4.242 z" | |||
inkscape:connector-curvature="0" | |||
id="path172" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 165,135.5 -42,0" | |||
inkscape:connector-curvature="0" | |||
id="path174" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path176" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path178" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path180" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,114.5 42,0" | |||
inkscape:connector-curvature="0" | |||
id="path182" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 165,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path184" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 172,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path186" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 172,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path188" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,124,122.5)" | |||
id="text190"><tspan | |||
x="0 3.7499084 11.989707 14.979634 17.969561 23.969416 26.959343 29.949268 35.949123" | |||
y="0" | |||
id="tspan192" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(+, 1, 2)</tspan></text> | |||
<path | |||
d="m 132.199,158.586 c 1.301,-3.703 3.481,-9.902 5.613,-15.973" | |||
inkscape:connector-curvature="0" | |||
id="path194" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 140.23,143.117 0.008,-7.414 -4.629,5.789 4.621,1.625 z" | |||
inkscape:connector-curvature="0" | |||
id="path196" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 70,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path198" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 67,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path200" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path202" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path204" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path206" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path208" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path210" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path212" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path214" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path216" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path218" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,48,48.5)" | |||
id="text220"><tspan | |||
x="0 3.7499084 9.7497625 12.739689 15.729616 21.729469 24.719397 27.709324 33.709179" | |||
y="0" | |||
id="tspan222" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(1, 0, 1)</tspan></text> | |||
<path | |||
d="m 67,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path224" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path226" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 287,283.5 106,0 0,-21 -106,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path228" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,294.5,270.5)" | |||
id="text230"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 18.709543 26.959343 29.949268 35.939121 38.92905 47.16885 50.158775 56.148628 59.148556 65.138412 68.128334 71.118263 77.118118 80.108047 86.107903" | |||
y="0" | |||
id="tspan232" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E ::= E + • E ,2,4)</tspan></text> | |||
<path | |||
d="m 340,306.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path234" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 342.449,290.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path236" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 342.941,308.934 c 9.497,-3.446 40.137,-14.559 64.852,-23.528" | |||
inkscape:connector-curvature="0" | |||
id="path238" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 408.84,287.633 5.746,-4.688 -7.414,0.082 1.668,4.606 z" | |||
inkscape:connector-curvature="0" | |||
id="path240" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 313,236 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path242" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 331.484,262.496 c -4.679,-5.769 -10.398,-12.82 -14.757,-18.199" | |||
inkscape:connector-curvature="0" | |||
id="path244" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 318.422,242.496 -6.313,-3.894 2.504,6.98 3.809,-3.086 z" | |||
inkscape:connector-curvature="0" | |||
id="path246" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 445,236 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path248" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 442,262.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path250" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 444.449,246.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path252" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,209.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path254" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 213,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path256" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 206,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path258" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 206,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path260" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 213,188.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path262" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path264" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path266" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path268" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,214,196.5)" | |||
id="text270"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan272" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 2, 3)</tspan></text> | |||
<path | |||
d="m 307.074,234.594 c -7.535,-3.621 -28.258,-13.578 -45.875,-22.043" | |||
inkscape:connector-curvature="0" | |||
id="path274" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 262.25,210.336 -7.371,-0.824 5.246,5.242 2.125,-4.418 z" | |||
inkscape:connector-curvature="0" | |||
id="path276" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 331,209.5 -42,0" | |||
inkscape:connector-curvature="0" | |||
id="path278" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 289,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path280" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 282,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path282" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 282,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path284" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 289,188.5 42,0" | |||
inkscape:connector-curvature="0" | |||
id="path286" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 331,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path288" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 338,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path290" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 338,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path292" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,290,196.5)" | |||
id="text294"><tspan | |||
x="0 3.7499084 11.989707 14.979634 17.969561 23.969416 26.959343 29.949268 35.949123" | |||
y="0" | |||
id="tspan296" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(+, 3, 4)</tspan></text> | |||
<path | |||
d="m 310,232.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path298" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 312.449,216.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path300" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 236,162 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path302" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 233,188.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path304" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 235.449,172.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path306" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path308" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 213,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path310" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 206,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path312" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 206,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path314" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 213,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path316" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path318" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path320" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path322" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,214,122.5)" | |||
id="text324"><tspan | |||
x="0 3.7499084 9.7497625 12.739689 15.729616 21.729469 24.719397 27.709324 33.709179" | |||
y="0" | |||
id="tspan326" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(1, 2, 3)</tspan></text> | |||
<path | |||
d="m 233,158.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path328" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 235.449,142.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path330" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 462,209.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path332" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path334" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 415,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path336" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 415,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path338" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,188.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path340" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 462,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path342" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 469,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path344" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 469,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path346" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,423,196.5)" | |||
id="text348"><tspan | |||
x="0 3.7499084 9.7497625 12.739689 15.729616 21.729469 24.719397 27.709324 33.709179" | |||
y="0" | |||
id="tspan350" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(1, 4, 5)</tspan></text> | |||
<path | |||
d="m 442,232.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path352" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 444.449,216.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path354" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 256,310 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path356" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 293.102,336.496 c -10.204,-6.742 -23.063,-15.238 -31.43,-20.766" | |||
inkscape:connector-curvature="0" | |||
id="path358" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 262.848,313.57 -7.188,-1.812 4.488,5.902 2.7,-4.09 z" | |||
inkscape:connector-curvature="0" | |||
id="path360" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 254.617,306.48 c 3.676,-7.976 13,-28.011 21.383,-44.48 7.992,-15.699 17.559,-33.328 24.504,-45.938" | |||
inkscape:connector-curvature="0" | |||
id="path362" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 302.824,216.93 1.242,-7.313 -5.531,4.942 4.289,2.371 z" | |||
inkscape:connector-curvature="0" | |||
id="path364" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 212,283.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path366" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 172,283.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path368" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 165,276.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path370" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 165,269.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path372" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 172,262.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path374" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 212,262.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path376" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 219,269.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path378" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 219,276.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path380" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,173,270.5)" | |||
id="text382"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan384" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(E, 0, 3)</tspan></text> | |||
<path | |||
d="m 250.059,308.215 c -6.219,-3.77 -21.207,-12.863 -34.395,-20.863" | |||
inkscape:connector-curvature="0" | |||
id="path386" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 216.633,285.078 -7.254,-1.539 4.715,5.727 2.539,-4.188 z" | |||
inkscape:connector-curvature="0" | |||
id="path388" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 195,236 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path390" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 192,262.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path392" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 194.449,246.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path394" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 189.059,234.215 c -6.219,-3.77 -21.207,-12.863 -34.395,-20.863" | |||
inkscape:connector-curvature="0" | |||
id="path396" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 155.633,211.078 -7.254,-1.539 4.715,5.727 2.539,-4.188 z" | |||
inkscape:connector-curvature="0" | |||
id="path398" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 194.691,233.574 c 4.286,-3.867 12.997,-11.73 21.032,-18.98" | |||
inkscape:connector-curvature="0" | |||
id="path400" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 217.559,216.234 3.554,-6.507 -6.84,2.871 3.286,3.636 z" | |||
inkscape:connector-curvature="0" | |||
id="path402" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /></g></g></g></g></g></g></svg> |
@@ -0,0 +1,584 @@ | |||
<?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:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.1" | |||
width="395" | |||
height="398.75" | |||
id="svg2" | |||
xml:space="preserve"><metadata | |||
id="metadata8"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs6"><clipPath | |||
id="clipPath16"><path | |||
d="M 0,0 394,0 394,398 0,398 0,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path18" /></clipPath><clipPath | |||
id="clipPath20"><path | |||
d="m 36,362 323,0 0,-327 -323,0 0,327 z" | |||
inkscape:connector-curvature="0" | |||
id="path22" /></clipPath></defs><g | |||
transform="matrix(1.25,0,0,-1.25,0,398.75)" | |||
id="g10"><g | |||
transform="translate(-39,-40)" | |||
id="g12"><g | |||
id="g14" /><g | |||
id="g24"><g | |||
clip-path="url(#clipPath16)" | |||
id="g26"><g | |||
id="g28"><path | |||
d="m 36,362 323,0 0,-327 -323,0 0,327 z" | |||
inkscape:connector-curvature="0" | |||
id="path30" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g | |||
id="g32"><g | |||
clip-path="url(#clipPath20)" | |||
id="g34"><path | |||
d="m 36,362 323,0 0,-327 -323,0 0,327 z" | |||
inkscape:connector-curvature="0" | |||
id="path36" | |||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 291,357.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path38" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 251,357.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path40" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 244,350.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path42" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 244,343.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path44" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 251,336.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path46" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 291,336.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path48" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298,343.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path50" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298,350.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path52" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,251.5,344.5)" | |||
id="text54"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 22.469452 25.459379 28.449306 34.449158" | |||
y="0" | |||
id="tspan56" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S, 0, 4)</tspan></text> | |||
<path | |||
d="m 274,310 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path58" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 271,336.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path60" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 273.449,320.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path62" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 158,283.5 118,0 0,-21 -118,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path64" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,166,270.5)" | |||
id="text66"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.449085 40.439014 47.18885 50.178776 56.928612 59.918537 65.908394 68.898315 76.398132 79.388062 82.377991 88.377846 91.367767 97.367622" | |||
y="0" | |||
id="tspan68" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= A B C • D ,0,3)</tspan></text> | |||
<path | |||
d="M 268.395,308.215 C 262.941,304.477 249.863,295.52 238.266,287.57" | |||
inkscape:connector-curvature="0" | |||
id="path70" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 239.543,285.477 -7.16,-1.938 4.39,5.981 2.77,-4.043 z" | |||
inkscape:connector-curvature="0" | |||
id="path72" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 347,283.5 -42,0" | |||
inkscape:connector-curvature="0" | |||
id="path74" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 305,283.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path76" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298,276.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path78" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298,269.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path80" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 305,262.5 42,0" | |||
inkscape:connector-curvature="0" | |||
id="path82" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 347,262.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path84" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 354,269.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path86" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 354,276.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path88" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,306,270.5)" | |||
id="text90"><tspan | |||
x="0 3.7499084 11.249725 14.239653 17.22958 23.229433 26.21936 29.209288 35.209141" | |||
y="0" | |||
id="tspan92" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(D, 3, 4)</tspan></text> | |||
<path | |||
d="m 273.652,308.215 c 5.555,-3.738 18.875,-12.695 30.688,-20.645" | |||
inkscape:connector-curvature="0" | |||
id="path94" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 305.891,289.48 4.441,-5.941 -7.176,1.875 2.735,4.066 z" | |||
inkscape:connector-curvature="0" | |||
id="path96" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 220,236 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path98" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 217,262.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path100" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 219.449,246.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path102" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 329,236 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path104" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 326,262.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path106" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 328.449,246.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path108" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 67,209.5 118,0 0,-21 -118,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path110" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,75,196.5)" | |||
id="text112"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.449085 40.439014 47.18885 50.178776 56.168629 59.158558 65.908394 68.898315 76.398132 79.388062 82.377991 88.377846 91.367767 97.367622" | |||
y="0" | |||
id="tspan114" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= A B • C D ,0,2)</tspan></text> | |||
<path | |||
d="m 213.973,234.77 c -8.571,-3.485 -33.758,-13.727 -54.996,-22.364" | |||
inkscape:connector-curvature="0" | |||
id="path116" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 159.652,210.039 -7.406,-0.367 5.559,4.906 1.847,-4.539 z" | |||
inkscape:connector-curvature="0" | |||
id="path118" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 254,209.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path120" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 214,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path122" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 207,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path124" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 207,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path126" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 214,188.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path128" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 254,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path130" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 261,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path132" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 261,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path134" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,214.5,196.5)" | |||
id="text136"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan138" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(C, 2, 3)</tspan></text> | |||
<path | |||
d="m 218.57,232.586 c 1.739,-3.785 4.672,-10.172 7.52,-16.367" | |||
inkscape:connector-curvature="0" | |||
id="path140" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 228.387,217.086 0.695,-7.383 -5.148,5.336 4.453,2.047 z" | |||
inkscape:connector-curvature="0" | |||
id="path142" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 129,162 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path144" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 126,188.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path146" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 128.449,172.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path148" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 237,162 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path150" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 234,188.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path152" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 236.449,172.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path154" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path156" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path158" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path160" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path162" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path164" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path166" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path168" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path170" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,47.5,122.5)" | |||
id="text172"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan174" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(A, 0, 1)</tspan></text> | |||
<path | |||
d="m 123.156,160.215 c -6.015,-3.77 -20.511,-12.863 -33.269,-20.863" | |||
inkscape:connector-curvature="0" | |||
id="path176" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 91.039,137.184 -7.23,-1.645 4.629,5.797 2.601,-4.152 z" | |||
inkscape:connector-curvature="0" | |||
id="path178" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path180" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path182" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path184" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path186" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path188" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path190" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path192" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path194" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,123.5,122.5)" | |||
id="text196"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan198" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(B, 1, 2)</tspan></text> | |||
<path | |||
d="m 127.57,158.586 c 1.739,-3.785 4.672,-10.172 7.52,-16.367" | |||
inkscape:connector-curvature="0" | |||
id="path200" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 137.387,143.086 0.695,-7.383 -5.148,5.336 4.453,2.047 z" | |||
inkscape:connector-curvature="0" | |||
id="path202" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 70,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path204" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 67,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path206" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path208" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 146,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path210" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 143,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path212" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 145.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path214" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path216" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path218" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path220" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path222" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path224" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path226" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path228" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path230" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,48,48.5)" | |||
id="text232"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan234" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(a, 0, 1)</tspan></text> | |||
<path | |||
d="m 67,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path236" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path238" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path240" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path242" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path244" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path246" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path248" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path250" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path252" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path254" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,124,48.5)" | |||
id="text256"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan258" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(b, 1, 2)</tspan></text> | |||
<path | |||
d="m 143,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path260" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 145.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path262" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,135.5 -38,0" | |||
inkscape:connector-curvature="0" | |||
id="path264" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 215,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path266" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 208,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path268" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 208,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path270" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 215,114.5 38,0" | |||
inkscape:connector-curvature="0" | |||
id="path272" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 253,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path274" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path276" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 260,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path278" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,215.5,122.5)" | |||
id="text280"><tspan | |||
x="0 3.7499084 8.9897804 11.979708 14.969635 20.969488 23.959415 26.949343 32.949196" | |||
y="0" | |||
id="tspan282" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(c, 2, 3)</tspan></text> | |||
<path | |||
d="m 234,158.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path284" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 236.449,142.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path286" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 346,209.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path288" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 306,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path290" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 299,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path292" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 299,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path294" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 306,188.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path296" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 346,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path298" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 353,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path300" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 353,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path302" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,307,196.5)" | |||
id="text304"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan306" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(d, 3, 4)</tspan></text> | |||
<path | |||
d="m 326,232.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path308" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 328.449,216.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path310" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /></g></g></g></g></g></g></svg> |
@@ -0,0 +1,522 @@ | |||
<?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:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.1" | |||
width="357.5" | |||
height="213.75" | |||
id="svg2" | |||
xml:space="preserve"><metadata | |||
id="metadata8"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs6"><clipPath | |||
id="clipPath16"><path | |||
d="M 0,0 364,0 364,250 0,250 0,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path18" /></clipPath><clipPath | |||
id="clipPath20"><path | |||
d="m 36,214 293,0 0,-179 -293,0 0,179 z" | |||
inkscape:connector-curvature="0" | |||
id="path22" /></clipPath></defs><g | |||
transform="matrix(1.25,0,0,-1.25,0,213.75)" | |||
id="g10"><g | |||
transform="translate(-39,-40)" | |||
id="g12"><g | |||
id="g14" /><g | |||
id="g24"><g | |||
clip-path="url(#clipPath16)" | |||
id="g26"><g | |||
id="g28"><path | |||
d="m 36,214 293,0 0,-179 -293,0 0,179 z" | |||
inkscape:connector-curvature="0" | |||
id="path30" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g | |||
id="g32"><g | |||
clip-path="url(#clipPath20)" | |||
id="g34"><path | |||
d="m 36,214 293,0 0,-179 -293,0 0,179 z" | |||
inkscape:connector-curvature="0" | |||
id="path36" | |||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 201,209.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path38" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 161,209.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path40" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 154,202.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path42" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 154,195.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path44" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 161,188.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path46" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 201,188.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path48" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 208,195.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path50" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 208,202.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path52" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,161.5,196.5)" | |||
id="text54"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 22.469452 25.459379 28.449306 34.449158" | |||
y="0" | |||
id="tspan56" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S, 0, 4)</tspan></text> | |||
<path | |||
d="m 184,162 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path58" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 181,188.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path60" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 183.449,172.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path62" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path64" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path66" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path68" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path70" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path72" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path74" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path76" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path78" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,47.5,122.5)" | |||
id="text80"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan82" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(A, 0, 1)</tspan></text> | |||
<path | |||
d="m 177.949,161.012 c -10.836,-3.52 -48.363,-15.7 -76.801,-24.93" | |||
inkscape:connector-curvature="0" | |||
id="path84" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 101.555,133.641 -7.418,0.168 5.902,4.492 1.516,-4.66 z" | |||
inkscape:connector-curvature="0" | |||
id="path86" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path88" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path90" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path92" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path94" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path96" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path98" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path100" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path102" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,123.5,122.5)" | |||
id="text104"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan106" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(B, 1, 2)</tspan></text> | |||
<path | |||
d="m 178.508,159.574 c -3.895,-3.793 -11.738,-11.429 -19.063,-18.562" | |||
inkscape:connector-curvature="0" | |||
id="path108" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 160.742,138.855 -6.726,-3.128 3.308,6.64 3.418,-3.512 z" | |||
inkscape:connector-curvature="0" | |||
id="path110" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 239,135.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path112" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 199,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path114" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 192,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path116" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 192,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path118" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 199,114.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path120" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 239,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path122" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 246,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path124" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 246,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path126" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,199.5,122.5)" | |||
id="text128"><tspan | |||
x="0 3.7499084 10.499743 13.489671 16.479597 22.479452 25.469379 28.459305 34.45916" | |||
y="0" | |||
id="tspan130" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(C, 2, 3)</tspan></text> | |||
<path | |||
d="m 183.492,159.574 c 3.895,-3.793 11.738,-11.429 19.063,-18.562" | |||
inkscape:connector-curvature="0" | |||
id="path132" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 204.676,142.367 3.308,-6.64 -6.726,3.128 3.418,3.512 z" | |||
inkscape:connector-curvature="0" | |||
id="path134" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 317,135.5 -42,0" | |||
inkscape:connector-curvature="0" | |||
id="path136" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 275,135.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path138" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 268,128.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path140" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 268,121.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path142" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 275,114.5 42,0" | |||
inkscape:connector-curvature="0" | |||
id="path144" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 317,114.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path146" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 324,121.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path148" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 324,128.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path150" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,276,122.5)" | |||
id="text152"><tspan | |||
x="0 3.7499084 11.249725 14.239653 17.22958 23.229433 26.21936 29.209288 35.209141" | |||
y="0" | |||
id="tspan154" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(D, 3, 4)</tspan></text> | |||
<path | |||
d="m 184.074,161.012 c 10.883,-3.5 48.426,-15.582 77.059,-24.793" | |||
inkscape:connector-curvature="0" | |||
id="path156" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 261.918,138.539 5.91,-4.477 -7.414,-0.187 1.504,4.664 z" | |||
inkscape:connector-curvature="0" | |||
id="path158" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 70,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path160" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 67,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path162" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path164" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 146,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path166" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 143,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path168" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 145.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path170" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 222,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path172" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 219,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path174" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 221.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path176" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 299,88 c 0,-4.668 -6,-4.668 -6,0 0,4.668 6,4.668 6,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path178" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 296,114.496 c 0,-4.926 0,-10.793 0,-15.75" | |||
inkscape:connector-curvature="0" | |||
id="path180" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298.449,98.586 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path182" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path184" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path186" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path188" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 40,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path190" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 47,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path192" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 87,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path194" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path196" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 94,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path198" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,48,48.5)" | |||
id="text200"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan202" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(a, 0, 1)</tspan></text> | |||
<path | |||
d="m 67,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path204" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 69.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path206" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path208" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path210" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path212" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 116,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path214" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 123,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path216" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 163,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path218" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path220" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 170,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path222" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,124,48.5)" | |||
id="text224"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan226" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(b, 1, 2)</tspan></text> | |||
<path | |||
d="m 143,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path228" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 145.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path230" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 238,61.5 -38,0" | |||
inkscape:connector-curvature="0" | |||
id="path232" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 200,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path234" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 193,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path236" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 193,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path238" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 200,40.5 38,0" | |||
inkscape:connector-curvature="0" | |||
id="path240" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 238,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path242" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 245,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path244" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 245,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path246" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,200.5,48.5)" | |||
id="text248"><tspan | |||
x="0 3.7499084 8.9897804 11.979708 14.969635 20.969488 23.959415 26.949343 32.949196" | |||
y="0" | |||
id="tspan250" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(c, 2, 3)</tspan></text> | |||
<path | |||
d="m 219,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path252" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 221.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path254" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 316,61.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path256" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 276,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path258" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 269,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path260" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 269,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path262" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 276,40.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path264" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 316,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path266" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 323,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path268" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 323,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path270" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,277,48.5)" | |||
id="text272"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan274" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(d, 3, 4)</tspan></text> | |||
<path | |||
d="m 296,84.316 c 0,-3.699 0,-9.687 0,-15.57" | |||
inkscape:connector-curvature="0" | |||
id="path276" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 298.449,68.527 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path278" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /></g></g></g></g></g></g></svg> |
@@ -0,0 +1,682 @@ | |||
<?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:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
version="1.1" | |||
width="1248.75" | |||
height="442.5" | |||
id="svg2" | |||
xml:space="preserve"><metadata | |||
id="metadata8"><rdf:RDF><cc:Work | |||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs | |||
id="defs6"><clipPath | |||
id="clipPath16"><path | |||
d="M 0,0 999,0 999,372 0,372 0,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path18" /></clipPath><clipPath | |||
id="clipPath20"><path | |||
d="m 0,0 1077,0 0,432 L 0,432 0,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path22" /></clipPath><clipPath | |||
id="clipPath24"><path | |||
d="m 36,396 1006,0 0,-361 -1006,0 0,361 z" | |||
inkscape:connector-curvature="0" | |||
id="path26" /></clipPath></defs><g | |||
transform="matrix(1.25,0,0,-1.25,0,442.5)" | |||
id="g10"><g | |||
transform="translate(0,-9)" | |||
id="g12"><g | |||
id="g14" /><g | |||
id="g28"><g | |||
clip-path="url(#clipPath16)" | |||
id="g30"><g | |||
transform="translate(-39,-30)" | |||
id="g32"><g | |||
id="g34" /><g | |||
id="g36"><g | |||
clip-path="url(#clipPath20)" | |||
id="g38"><g | |||
id="g40"><path | |||
d="m 36,396 1006,0 0,-361 -1006,0 0,361 z" | |||
inkscape:connector-curvature="0" | |||
id="path42" | |||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g | |||
id="g44"><g | |||
clip-path="url(#clipPath24)" | |||
id="g46"><path | |||
d="m 36,396 1006,0 0,-361 -1006,0 0,361 z" | |||
inkscape:connector-curvature="0" | |||
id="path48" | |||
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,391.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path50" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 382,391.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path52" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 375,384.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path54" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 375,377.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path56" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 382,370.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path58" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 422,370.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path60" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 429,377.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path62" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 429,384.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path64" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,382.5,378.5)" | |||
id="text66"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 22.469452 25.459379 28.449306 34.449158" | |||
y="0" | |||
id="tspan68" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S, 0, 1)</tspan></text> | |||
<path | |||
d="m 141.91,326 c 0,-8.199 -22.793,-14.848 -50.91,-14.848 -28.117,0 -50.91,6.649 -50.91,14.848 0,8.199 22.793,14.848 50.91,14.848 28.117,0 50.91,-6.649 50.91,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path70" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,63,323.5)" | |||
id="text72"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 36.689106 42.678959 45.668884 51.668739" | |||
y="0" | |||
id="tspan74" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= a•,0)</tspan></text> | |||
<path | |||
d="M 374.699,376.789 C 330.242,369.855 239.492,355.363 163,341 c -7.59,-1.426 -15.613,-3.016 -23.441,-4.609" | |||
inkscape:connector-curvature="0" | |||
id="path76" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 139.793,333.938 -7.348,0.988 6.364,3.812 0.984,-4.8 z" | |||
inkscape:connector-curvature="0" | |||
id="path78" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 301.188,326 c 0,-8.199 -26.051,-14.848 -58.188,-14.848 -32.137,0 -58.188,6.649 -58.188,14.848 0,8.199 26.051,14.848 58.188,14.848 32.137,0 58.188,-6.649 58.188,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path80" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,209.5,323.5)" | |||
id="text82"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 47.16885 53.168701 56.15863 62.148483" | |||
y="0" | |||
id="tspan84" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S S•,1)</tspan></text> | |||
<path | |||
d="m 374.668,371.547 c -24.824,-8.59 -61.801,-21.379 -90.254,-31.223" | |||
inkscape:connector-curvature="0" | |||
id="path86" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 285.164,337.992 -7.418,0.028 5.816,4.605 1.602,-4.633 z" | |||
inkscape:connector-curvature="0" | |||
id="path88" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 460.188,326 c 0,-8.199 -26.051,-14.848 -58.188,-14.848 -32.137,0 -58.188,6.649 -58.188,14.848 0,8.199 26.051,14.848 58.188,14.848 32.137,0 58.188,-6.649 58.188,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path90" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,368.5,323.5)" | |||
id="text92"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 47.16885 53.168701 56.15863 62.148483" | |||
y="0" | |||
id="tspan94" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S S•,0)</tspan></text> | |||
<path | |||
d="m 389.266,370.395 c -2.594,-6.274 -3.516,-14.465 -2.762,-22.098" | |||
inkscape:connector-curvature="0" | |||
id="path96" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 389,348.258 -1.188,-7.32 -3.636,6.464 4.824,0.856 z" | |||
inkscape:connector-curvature="0" | |||
id="path98" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 111,281.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path100" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 71,281.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path102" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 64,274.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path104" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 64,267.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path106" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 71,260.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path108" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 111,260.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path110" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 118,267.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path112" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 118,274.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path114" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,72,268.5)" | |||
id="text116"><tspan | |||
x="0 3.7499084 9.7397623 12.72969 15.719617 21.719471 24.709396 27.699324 33.699177" | |||
y="0" | |||
id="tspan118" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(a, 0, 1)</tspan></text> | |||
<path | |||
d="m 91,310.973 c 0,-6.821 0,-14.942 0,-22.075" | |||
inkscape:connector-curvature="0" | |||
id="path120" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 93.449,288.652 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path122" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 211,281.5 98,0 0,-21 -98,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path124" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,219,268.5)" | |||
id="text126"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336 71.128265 77.12812" | |||
y="0" | |||
id="tspan128" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,0,1)</tspan></text> | |||
<path | |||
d="m 247.645,310.973 c 2.152,-6.969 4.726,-15.285 6.964,-22.528" | |||
inkscape:connector-curvature="0" | |||
id="path130" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 256.98,289.066 -0.273,-7.414 -4.406,5.965 4.679,1.449 z" | |||
inkscape:connector-curvature="0" | |||
id="path132" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 637,281.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path134" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 597,281.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path136" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 590,274.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path138" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 590,267.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path140" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 597,260.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path142" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 637,260.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path144" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 644,267.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path146" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 644,274.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path148" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,597.5,268.5)" | |||
id="text150"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 22.469452 25.459379 28.449306 34.449158" | |||
y="0" | |||
id="tspan152" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S, 1, 1)</tspan></text> | |||
<path | |||
d="M 289.297,316.785 C 300.016,314.77 311.391,312.727 322,311 415.98,295.719 527.473,281.715 582.602,275.066" | |||
inkscape:connector-curvature="0" | |||
id="path154" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 583.02,277.484 6.66,-3.269 -7.242,-1.598 0.582,4.867 z" | |||
inkscape:connector-curvature="0" | |||
id="path156" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 416.746,340.523 c 2.055,7.036 2.305,15.547 0.75,22.942" | |||
inkscape:connector-curvature="0" | |||
id="path158" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 415.082,362.984 0.262,7.411 4.418,-5.957 -4.68,-1.454 z" | |||
inkscape:connector-curvature="0" | |||
id="path160" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 819,281.5 98,0 0,-21 -98,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path162" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,827,268.5)" | |||
id="text164"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336 71.128265 77.12812" | |||
y="0" | |||
id="tspan166" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,0,0)</tspan></text> | |||
<path | |||
d="m 455.004,319.746 c 88.605,-10.461 266.012,-31.398 356.742,-42.105" | |||
inkscape:connector-curvature="0" | |||
id="path168" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 812.258,280.047 6.664,-3.254 -7.238,-1.613 0.574,4.867 z" | |||
inkscape:connector-curvature="0" | |||
id="path170" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 339.934,216 c 0,-8.199 -28.176,-14.848 -62.934,-14.848 -34.758,0 -62.934,6.649 -62.934,14.848 0,8.199 28.176,14.848 62.934,14.848 34.758,0 62.934,-6.649 62.934,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path172" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,240.5,213.5)" | |||
id="text174"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336" | |||
y="0" | |||
id="tspan176" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,0)</tspan></text> | |||
<path | |||
d="m 263.277,260.395 c 1.95,-6.309 4.5,-14.555 6.871,-22.227" | |||
inkscape:connector-curvature="0" | |||
id="path178" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 272.527,238.77 -0.273,-7.415 -4.41,5.965 4.683,1.45 z" | |||
inkscape:connector-curvature="0" | |||
id="path180" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 516.203,216 c 0,-8.199 -22.476,-14.848 -50.203,-14.848 -27.727,0 -50.203,6.649 -50.203,14.848 0,8.199 22.476,14.848 50.203,14.848 27.727,0 50.203,-6.649 50.203,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path182" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,438.5,213.5)" | |||
id="text184"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324" | |||
y="0" | |||
id="tspan186" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= </tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,469.19925,213.5)" | |||
id="text188"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan190" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">ε</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,474.43912,213.5)" | |||
id="text192"><tspan | |||
x="0 5.9898539 8.9897804 14.979634" | |||
y="0" | |||
id="tspan194" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">•,1)</tspan></text> | |||
<path | |||
d="m 589.656,261.039 c -23.82,-8.676 -58.609,-21.348 -85.226,-31.043" | |||
inkscape:connector-curvature="0" | |||
id="path196" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 505.266,227.695 -7.414,-0.093 5.738,4.699 1.676,-4.606 z" | |||
inkscape:connector-curvature="0" | |||
id="path198" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 675.188,216 c 0,-8.199 -26.051,-14.848 -58.188,-14.848 -32.137,0 -58.188,6.649 -58.188,14.848 0,8.199 26.051,14.848 58.188,14.848 32.137,0 58.188,-6.649 58.188,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path200" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,583.5,213.5)" | |||
id="text202"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 47.16885 53.168701 56.15863 62.148483" | |||
y="0" | |||
id="tspan204" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S S•,1)</tspan></text> | |||
<path | |||
d="m 604.266,260.395 c -2.594,-6.274 -3.516,-14.465 -2.762,-22.098" | |||
inkscape:connector-curvature="0" | |||
id="path206" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 604,238.258 -1.188,-7.32 -3.636,6.464 4.824,0.856 z" | |||
inkscape:connector-curvature="0" | |||
id="path208" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 329.922,224.246 c 48.89,10.731 118.82,34.688 152.078,86.754 7.176,11.238 7.008,18.656 0,30 -10,16.18 -28.75,26.035 -45.582,31.914" | |||
inkscape:connector-curvature="0" | |||
id="path210" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 435.258,370.711 -5.906,4.484 7.414,0.18 -1.508,-4.664 z" | |||
inkscape:connector-curvature="0" | |||
id="path212" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 485,171.5 -38,0" | |||
inkscape:connector-curvature="0" | |||
id="path214" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 447,171.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path216" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 440,164.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path218" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 440,157.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path220" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 447,150.5 38,0" | |||
inkscape:connector-curvature="0" | |||
id="path222" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 485,150.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path224" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 492,157.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path226" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 492,164.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path228" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,447.5,158.5)" | |||
id="text230"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan232" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,451.24991,158.5)" | |||
id="text234"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan236" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">ε</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,456.48978,158.5)" | |||
id="text238"><tspan | |||
x="0 2.9899271 5.9898539 11.979708 14.979634 17.969561 23.959415" | |||
y="0" | |||
id="tspan240" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">, 1, 1)</tspan></text> | |||
<path | |||
d="m 466,200.973 c 0,-6.821 0,-14.942 0,-22.075" | |||
inkscape:connector-curvature="0" | |||
id="path242" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 468.449,178.652 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path244" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 631.746,230.523 c 2.055,7.036 2.305,15.547 0.75,22.942" | |||
inkscape:connector-curvature="0" | |||
id="path246" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 630.082,252.984 0.262,7.411 4.418,-5.957 -4.68,-1.454 z" | |||
inkscape:connector-curvature="0" | |||
id="path248" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 572,171.5 98,0 0,-21 -98,0 0,21 z" | |||
inkscape:connector-curvature="0" | |||
id="path250" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,580,158.5)" | |||
id="text252"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336 71.128265 77.12812" | |||
y="0" | |||
id="tspan254" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,1,1)</tspan></text> | |||
<path | |||
d="m 618.094,200.973 c 0.496,-6.821 1.086,-14.942 1.605,-22.075" | |||
inkscape:connector-curvature="0" | |||
id="path256" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 622.16,178.812 -1.933,-7.16 -2.954,6.805 4.887,0.355 z" | |||
inkscape:connector-curvature="0" | |||
id="path258" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 700.934,106 c 0,-8.199 -28.176,-14.848 -62.934,-14.848 -34.758,0 -62.934,6.649 -62.934,14.848 0,8.199 28.176,14.848 62.934,14.848 34.758,0 62.934,-6.649 62.934,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path260" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,601.5,103.5)" | |||
id="text262"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336" | |||
y="0" | |||
id="tspan264" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,1)</tspan></text> | |||
<path | |||
d="m 624.277,150.395 c 1.95,-6.309 4.5,-14.555 6.871,-22.227" | |||
inkscape:connector-curvature="0" | |||
id="path266" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 633.527,128.77 -0.273,-7.415 -4.41,5.965 4.683,1.45 z" | |||
inkscape:connector-curvature="0" | |||
id="path268" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 662.836,119.992 c 10.824,7.453 22.531,17.645 29.164,30.008 3.754,6.996 11.863,69.898 5,81 -10,16.18 -28.75,26.035 -45.582,31.914" | |||
inkscape:connector-curvature="0" | |||
id="path270" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 650.258,260.711 -5.906,4.484 7.414,0.18 -1.508,-4.664 z" | |||
inkscape:connector-curvature="0" | |||
id="path272" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 930.934,216 c 0,-8.199 -28.176,-14.848 -62.934,-14.848 -34.758,0 -62.934,6.649 -62.934,14.848 0,8.199 28.176,14.848 62.934,14.848 34.758,0 62.934,-6.649 62.934,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path274" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,831.5,213.5)" | |||
id="text276"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 46.418869 49.408794 56.15863 59.148556 62.138485 68.138336" | |||
y="0" | |||
id="tspan278" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S • S ,0)</tspan></text> | |||
<path | |||
d="m 868,260.395 c 0,-6.18 0,-14.219 0,-21.758" | |||
inkscape:connector-curvature="0" | |||
id="path280" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 870.449,238.355 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path282" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 906,171.5 -40,0" | |||
inkscape:connector-curvature="0" | |||
id="path284" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 866,171.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path286" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 859,164.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path288" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 859,157.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path290" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 866,150.5 40,0" | |||
inkscape:connector-curvature="0" | |||
id="path292" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 906,150.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path294" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 913,157.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path296" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 913,164.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path298" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,866.5,158.5)" | |||
id="text300"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 22.469452 25.459379 28.449306 34.449158" | |||
y="0" | |||
id="tspan302" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S, 0, 0)</tspan></text> | |||
<path | |||
d="m 872.918,200.973 c 2.281,-6.969 5.004,-15.285 7.371,-22.528" | |||
inkscape:connector-curvature="0" | |||
id="path304" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 882.664,179.066 -0.152,-7.414 -4.504,5.891 4.656,1.523 z" | |||
inkscape:connector-curvature="0" | |||
id="path306" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 878.203,106 c 0,-8.199 -22.476,-14.848 -50.203,-14.848 -27.727,0 -50.203,6.649 -50.203,14.848 0,8.199 22.476,14.848 50.203,14.848 27.727,0 50.203,-6.649 50.203,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path308" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,800.5,103.5)" | |||
id="text310"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324" | |||
y="0" | |||
id="tspan312" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= </tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,831.19925,103.5)" | |||
id="text314"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan316" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">ε</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,836.43912,103.5)" | |||
id="text318"><tspan | |||
x="0 5.9898539 8.9897804 14.979634" | |||
y="0" | |||
id="tspan320" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">•,0)</tspan></text> | |||
<path | |||
d="m 874.816,150.395 c -7.414,-7.032 -17.367,-16.469 -26.187,-24.833" | |||
inkscape:connector-curvature="0" | |||
id="path322" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 850.078,123.562 -6.762,-3.039 3.391,6.594 3.371,-3.555 z" | |||
inkscape:connector-curvature="0" | |||
id="path324" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 1037.188,106 c 0,-8.199 -26.051,-14.848 -58.188,-14.848 -32.137,0 -58.188,6.649 -58.188,14.848 0,8.199 26.051,14.848 58.188,14.848 32.137,0 58.188,-6.649 58.188,-14.848 z" | |||
inkscape:connector-curvature="0" | |||
id="path326" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,945.5,103.5)" | |||
id="text328"><tspan | |||
x="0 3.7499084 10.489744 13.479671 16.469599 19.459526 27.709324 30.699251 37.439087 40.429012 47.16885 53.168701 56.15863 62.148483" | |||
y="0" | |||
id="tspan330" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(S ::= S S•,0)</tspan></text> | |||
<path | |||
d="m 891.195,150.395 c 10.446,-8.172 29.223,-19.598 47.098,-28.809" | |||
inkscape:connector-curvature="0" | |||
id="path332" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 939.668,123.637 5.152,-5.336 -7.351,0.957 2.199,4.379 z" | |||
inkscape:connector-curvature="0" | |||
id="path334" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 847,61.5 -38,0" | |||
inkscape:connector-curvature="0" | |||
id="path336" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 809,61.5 c -3.5,0 -7,-3.5 -7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path338" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 802,54.5 0,-7" | |||
inkscape:connector-curvature="0" | |||
id="path340" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 802,47.5 c 0,-3.5 3.5,-7 7,-7" | |||
inkscape:connector-curvature="0" | |||
id="path342" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 809,40.5 38,0" | |||
inkscape:connector-curvature="0" | |||
id="path344" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 847,40.5 c 3.5,0 7,3.5 7,7" | |||
inkscape:connector-curvature="0" | |||
id="path346" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 854,47.5 0,7" | |||
inkscape:connector-curvature="0" | |||
id="path348" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 854,54.5 c 0,3.5 -3.5,7 -7,7" | |||
inkscape:connector-curvature="0" | |||
id="path350" | |||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><text | |||
transform="matrix(1,0,0,-1,809.5,48.5)" | |||
id="text352"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan354" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">(</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,813.24991,48.5)" | |||
id="text356"><tspan | |||
x="0" | |||
y="0" | |||
id="tspan358" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">ε</tspan></text> | |||
<text | |||
transform="matrix(1,0,0,-1,818.48978,48.5)" | |||
id="text360"><tspan | |||
x="0 2.9899271 5.9898539 11.979708 14.979634 17.969561 23.959415" | |||
y="0" | |||
id="tspan362" | |||
style="font-size:9.99975586px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">, 0, 0)</tspan></text> | |||
<path | |||
d="m 828,90.973 c 0,-6.821 0,-14.942 0,-22.075" | |||
inkscape:connector-curvature="0" | |||
id="path364" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 830.449,68.652 -2.449,-7 -2.449,7 4.898,0 z" | |||
inkscape:connector-curvature="0" | |||
id="path366" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="M 979.949,121.254 C 980.715,146.762 978.676,198.461 953,231 c -9.465,11.992 -23.383,20.566 -37.227,26.613" | |||
inkscape:connector-curvature="0" | |||
id="path368" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="M 914.551,255.465 909,260.383 916.406,260 914.551,255.465 z" | |||
inkscape:connector-curvature="0" | |||
id="path370" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 968.672,120.891 c -12.512,8.875 -31.633,19.984 -48.789,28.261" | |||
inkscape:connector-curvature="0" | |||
id="path372" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /><path | |||
d="m 918.48,147.102 -5.304,5.183 7.379,-0.742 -2.075,-4.441 z" | |||
inkscape:connector-curvature="0" | |||
id="path374" | |||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none" /></g></g></g></g></g></g></g></g></g></svg> |
@@ -23,7 +23,7 @@ | |||
## Extra features | |||
- Import rules and tokens from other Lark grammars, for code reuse and modularity. | |||
- Support for external regex module ([see here](classes.md#using-unicode-character-classes-with-regex)) | |||
- Support for external regex module ([see here](classes.html#using-unicode-character-classes-with-regex)) | |||
- Import grammars from Nearley.js ([read more](nearley.md)) | |||
- CYK parser | |||
- Visualize your parse trees as dot or png files ([see_example](https://github.com/lark-parser/lark/blob/master/examples/fruitflies.py)) | |||
@@ -112,9 +112,13 @@ You can use flags on regexps and strings. For example: | |||
```perl | |||
SELECT: "select"i //# Will ignore case, and match SELECT or Select, etc. | |||
MULTILINE_TEXT: /.+/s | |||
SIGNED_INTEGER: / | |||
[+-]? # the sign | |||
(0|[1-9][0-9]*) # the digits | |||
/x | |||
``` | |||
Supported flags are one of: `imslu`. See Python's regex documentation for more details on each one. | |||
Supported flags are one of: `imslux`. See Python's regex documentation for more details on each one. | |||
Regexps/strings of different flags can only be concatenated in Python 3.6+ | |||
@@ -251,7 +255,7 @@ COMMENT: "#" /[^\n]/* | |||
``` | |||
### %import | |||
Allows to import terminals and rules from lark grammars. | |||
Allows one to import terminals and rules from lark grammars. | |||
When importing rules, all their dependencies will be imported into a namespace, to avoid collisions. It's not possible to override their dependencies (e.g. like you would when inheriting a class). | |||
@@ -264,7 +268,7 @@ When importing rules, all their dependencies will be imported into a namespace, | |||
%import <module> (<TERM1>, <TERM2>, <rule1>, <rule2>) | |||
``` | |||
If the module path is absolute, Lark will attempt to load it from the built-in directory (currently, only `common.lark` is available). | |||
If the module path is absolute, Lark will attempt to load it from the built-in directory (which currently contains `common.lark`, `python.lark`, and `unicode.lark`). | |||
If the module path is relative, such as `.path.to.file`, Lark will attempt to load it from the current working directory. Grammars must have the `.lark` extension. | |||
@@ -25,9 +25,18 @@ Lark provides the following options to combat ambiguity: | |||
3) As an advanced feature, users may use specialized visitors to iterate the SPPF themselves. | |||
**dynamic_complete** | |||
**lexer="dynamic_complete"** | |||
Earley's "dynamic" lexer uses regular expressions in order to tokenize the text. It tries every possible combination of terminals, but it matches each terminal exactly once, returning the longest possible match. | |||
That means, for example, that when `lexer="dynamic"` (which is the default), the terminal `/a+/`, when given the text `"aa"`, will return one result, `aa`, even though `a` would also be correct. | |||
This behavior was chosen because it is much faster, and it is usually what you would expect. | |||
Setting `lexer="dynamic_complete"` instructs the lexer to consider every possible regexp match. This ensures that the parser will consider and resolve every ambiguity, even inside the terminals themselves. This lexer provides the same capabilities as scannerless Earley, but with different performance tradeoffs. | |||
Warning: This lexer can be much slower, especially for open-ended terminals such as `/.*/` | |||
**TODO: Add documentation on dynamic_complete** | |||
## LALR(1) | |||
@@ -37,7 +46,9 @@ Lark comes with an efficient implementation that outperforms every other parsing | |||
Lark extends the traditional YACC-based architecture with a *contextual lexer*, which automatically provides feedback from the parser to the lexer, making the LALR(1) algorithm stronger than ever. | |||
The contextual lexer communicates with the parser, and uses the parser's lookahead prediction to narrow its choice of tokens. So at each point, the lexer only matches the subgroup of terminals that are legal at that parser state, instead of all of the terminals. It’s surprisingly effective at resolving common terminal collisions, and allows one to parse languages that LALR(1) was previously incapable of parsing. | |||
The contextual lexer communicates with the parser, and uses the parser's lookahead prediction to narrow its choice of terminals. So at each point, the lexer only matches the subgroup of terminals that are legal at that parser state, instead of all of the terminals. It’s surprisingly effective at resolving common terminal collisions, and allows one to parse languages that LALR(1) was previously incapable of parsing. | |||
(If you're familiar with YACC, you can think of it as automatic lexer-states) | |||
This is an improvement to LALR(1) that is unique to Lark. | |||
@@ -16,7 +16,7 @@ Lark's mission is to make the process of writing them as simple and abstract as | |||
5. Performance is still very important | |||
6. Follow the Zen Of Python, whenever possible and applicable | |||
6. Follow the Zen of Python, whenever possible and applicable | |||
In accordance with these principles, I arrived at the following design choices: | |||
@@ -30,15 +30,17 @@ Example: | |||
:: | |||
class IncreaseAllNumbers(Visitor): | |||
def number(self, tree): | |||
assert tree.data == "number" | |||
tree.children[0] += 1 | |||
def number(self, tree): | |||
assert tree.data == "number" | |||
tree.children[0] += 1 | |||
IncreaseAllNumbers().visit(parse_tree) | |||
.. autoclass:: lark.visitors.Visitor | |||
:members: visit, visit_topdown, __default__ | |||
.. autoclass:: lark.visitors.Visitor_Recursive | |||
:members: visit, visit_topdown, __default__ | |||
Interpreter | |||
----------- | |||
@@ -63,7 +65,7 @@ Transformer | |||
----------- | |||
.. autoclass:: lark.visitors.Transformer | |||
:members: __default__, __default_token__ | |||
:members: transform, __default__, __default_token__, __mul__ | |||
Example: | |||
:: | |||
@@ -90,6 +92,11 @@ Example: | |||
T(visit_tokens=True).transform(tree) | |||
.. autoclass:: lark.visitors.Transformer_NonRecursive | |||
.. autoclass:: lark.visitors.Transformer_InPlace | |||
.. autoclass:: lark.visitors.Transformer_InPlaceRecursive | |||
v_args | |||
------ | |||
@@ -0,0 +1,79 @@ | |||
""" | |||
Example-Driven Error Reporting | |||
============================== | |||
A demonstration of example-driven error reporting with the Earley parser | |||
(See also: error_reporting_lalr.py) | |||
""" | |||
from lark import Lark, UnexpectedInput | |||
from _json_parser import json_grammar # Using the grammar from the json_parser example | |||
json_parser = Lark(json_grammar) | |||
class JsonSyntaxError(SyntaxError): | |||
def __str__(self): | |||
context, line, column = self.args | |||
return '%s at line %s, column %s.\n\n%s' % (self.label, line, column, context) | |||
class JsonMissingValue(JsonSyntaxError): | |||
label = 'Missing Value' | |||
class JsonMissingOpening(JsonSyntaxError): | |||
label = 'Missing Opening' | |||
class JsonMissingClosing(JsonSyntaxError): | |||
label = 'Missing Closing' | |||
class JsonMissingComma(JsonSyntaxError): | |||
label = 'Missing Comma' | |||
class JsonTrailingComma(JsonSyntaxError): | |||
label = 'Trailing Comma' | |||
def parse(json_text): | |||
try: | |||
j = json_parser.parse(json_text) | |||
except UnexpectedInput as u: | |||
exc_class = u.match_examples(json_parser.parse, { | |||
JsonMissingOpening: ['{"foo": ]}', | |||
'{"foor": }}', | |||
'{"foo": }'], | |||
JsonMissingClosing: ['{"foo": [}', | |||
'{', | |||
'{"a": 1', | |||
'[1'], | |||
JsonMissingComma: ['[1 2]', | |||
'[false 1]', | |||
'["b" 1]', | |||
'{"a":true 1:4}', | |||
'{"a":1 1:4}', | |||
'{"a":"b" 1:4}'], | |||
JsonTrailingComma: ['[,]', | |||
'[1,]', | |||
'[1,2,]', | |||
'{"foo":1,}', | |||
'{"foo":false,"bar":true,}'] | |||
}, use_accepts=True) | |||
if not exc_class: | |||
raise | |||
raise exc_class(u.get_context(json_text), u.line, u.column) | |||
def test(): | |||
try: | |||
parse('{"example1": "value"') | |||
except JsonMissingClosing as e: | |||
print(e) | |||
try: | |||
parse('{"example2": ] ') | |||
except JsonMissingOpening as e: | |||
print(e) | |||
if __name__ == '__main__': | |||
test() | |||
@@ -3,7 +3,7 @@ Example-Driven Error Reporting | |||
============================== | |||
A demonstration of example-driven error reporting with the LALR parser | |||
(See also: error_reporting_earley.py) | |||
""" | |||
from lark import Lark, UnexpectedInput | |||
@@ -23,7 +23,7 @@ decorated: decorators (classdef | funcdef | async_funcdef) | |||
async_funcdef: "async" funcdef | |||
funcdef: "def" NAME "(" parameters? ")" ["->" test] ":" suite | |||
parameters: paramvalue ("," paramvalue)* ["," [ starparams | kwparams]] | |||
parameters: paramvalue ("," paramvalue)* ["," "/"] ["," [starparams | kwparams]] | |||
| starparams | |||
| kwparams | |||
starparams: "*" typedparam? ("," paramvalue)* ["," kwparams] | |||
@@ -163,22 +163,14 @@ yield_arg: "from" test | testlist | |||
number: DEC_NUMBER | HEX_NUMBER | BIN_NUMBER | OCT_NUMBER | FLOAT_NUMBER | IMAG_NUMBER | |||
string: STRING | LONG_STRING | |||
// Tokens | |||
NAME: /[a-zA-Z_]\w*/ | |||
COMMENT: /#[^\n]*/ | |||
_NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ | |||
// Import terminals from standard library (grammars/python.lark) | |||
%import python (NAME, COMMENT, STRING, LONG_STRING) | |||
%import python (DEC_NUMBER, HEX_NUMBER, OCT_NUMBER, BIN_NUMBER, FLOAT_NUMBER, IMAG_NUMBER) | |||
STRING : /[ubf]?r?("(?!"").*?(?<!\\)(\\\\)*?"|'(?!'').*?(?<!\\)(\\\\)*?')/i | |||
LONG_STRING: /[ubf]?r?(""".*?(?<!\\)(\\\\)*?"""|'''.*?(?<!\\)(\\\\)*?''')/is | |||
// Other terminals | |||
DEC_NUMBER: /0|[1-9]\d*/i | |||
HEX_NUMBER.2: /0x[\da-f]*/i | |||
OCT_NUMBER.2: /0o[0-7]*/i | |||
BIN_NUMBER.2 : /0b[0-1]*/i | |||
FLOAT_NUMBER.2: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i | |||
IMAG_NUMBER.2: /\d+j/i | FLOAT_NUMBER "j"i | |||
_NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+ | |||
%ignore /[\t \f]+/ // WS | |||
%ignore /\\[\t \f]*\r?\n/ // LINE_CONT | |||
@@ -7,13 +7,13 @@ A reference implementation of the Lark grammar (using LALR(1)) | |||
import lark | |||
from pathlib import Path | |||
parser = lark.Lark.open('lark.lark', rel_to=__file__, parser="lalr") | |||
examples_path = Path(__file__).parent | |||
lark_path = Path(lark.__file__).parent | |||
parser = lark.Lark.open(lark_path / 'grammars/lark.lark', rel_to=__file__, parser="lalr") | |||
grammar_files = [ | |||
examples_path / 'lark.lark', | |||
examples_path / 'advanced/python2.lark', | |||
examples_path / 'advanced/python3.lark', | |||
examples_path / 'relative-imports/multiples.lark', | |||
@@ -21,7 +21,11 @@ grammar_files = [ | |||
examples_path / 'relative-imports/multiple3.lark', | |||
examples_path / 'tests/no_newline_at_end.lark', | |||
examples_path / 'tests/negative_priority.lark', | |||
examples_path / 'standalone/json.lark', | |||
lark_path / 'grammars/common.lark', | |||
lark_path / 'grammars/lark.lark', | |||
lark_path / 'grammars/unicode.lark', | |||
lark_path / 'grammars/python.lark', | |||
] | |||
def test(): | |||
@@ -9,6 +9,10 @@ class LarkError(Exception): | |||
pass | |||
class ConfigurationError(LarkError, ValueError): | |||
pass | |||
class GrammarError(LarkError): | |||
pass | |||
@@ -2,7 +2,7 @@ | |||
from typing import ( | |||
TypeVar, Type, List, Dict, IO, Iterator, Callable, Union, Optional, | |||
Literal, Protocol, Iterable, | |||
Literal, Protocol, Tuple, Iterable, | |||
) | |||
from .visitors import Transformer | |||
from .lexer import Token, Lexer, TerminalDef | |||
@@ -34,11 +34,25 @@ class LarkOptions: | |||
cache: Union[bool, str] | |||
g_regex_flags: int | |||
use_bytes: bool | |||
import_paths: List[Union[str, Callable[[Union[None, str, PackageResource], str], Tuple[str, str]]]] | |||
source_path: Optional[str] | |||
class PackageResource(object): | |||
pkg_name: str | |||
path: str | |||
def __init__(self, pkg_name: str, path: str): ... | |||
class FromPackageLoader: | |||
def __init__(self, pkg_name: str, search_paths: Tuple[str, ...] = ...): ... | |||
def __call__(self, base_path: Union[None, str, PackageResource], grammar_path: str) -> Tuple[PackageResource, str]: ... | |||
class Lark: | |||
source: str | |||
grammar_source: str | |||
source_path: str | |||
source_grammar: str | |||
options: LarkOptions | |||
lexer: Lexer | |||
terminals: List[TerminalDef] | |||
@@ -49,7 +63,7 @@ class Lark: | |||
*, | |||
start: Union[None, str, List[str]] = "start", | |||
parser: Literal["earley", "lalr", "cyk"] = "auto", | |||
lexer: Union[Literal["auto", "standard", "contextual", "dynamic", "dynamic_complete"], Lexer] = "auto", | |||
lexer: Union[Literal["auto", "standard", "contextual", "dynamic", "dynamic_complete"], Type[Lexer]] = "auto", | |||
transformer: Optional[Transformer] = None, | |||
postlex: Optional[PostLex] = None, | |||
ambiguity: Literal["explicit", "resolve"] = "resolve", | |||
@@ -62,6 +76,8 @@ class Lark: | |||
cache: Union[bool, str] = False, | |||
g_regex_flags: int = ..., | |||
use_bytes: bool = False, | |||
import_paths: List[Union[str, Callable[[Union[None, str, PackageResource], str], Tuple[str, str]]]] = ..., | |||
source_path: Optional[str]=None, | |||
): | |||
... | |||
@@ -71,6 +87,10 @@ class Lark: | |||
@classmethod | |||
def open(cls: Type[_T], grammar_filename: str, rel_to: Optional[str] = None, **options) -> _T: | |||
... | |||
@classmethod | |||
def open_from_package(cls: Type[_T], package: str, grammar_path: str, search_paths: Tuple[str, ...] = ..., **options) -> _T: | |||
... | |||
def lex(self, text: str) -> Iterator[Token]: | |||
... | |||
@@ -1,7 +1,7 @@ | |||
# -*- coding: utf-8 -*- | |||
from types import ModuleType | |||
from typing import ( | |||
TypeVar, Type, Tuple, List, Dict, Iterator, Collection, Callable, Optional, | |||
TypeVar, Type, Tuple, List, Dict, Iterator, Collection, Callable, Optional, FrozenSet, Any, | |||
Pattern as REPattern, | |||
) | |||
from abc import abstractmethod, ABC | |||
@@ -85,6 +85,9 @@ class Token(str): | |||
end_column: int | |||
end_pos: int | |||
def __init__(self, type_: str, value: Any, pos_in_stream: int = None, line: int = None, column: int = None, end_line: int = None, end_column: int = None, end_pos: int = None): | |||
... | |||
def update(self, type_: Optional[str] = None, value: Optional[str] = None) -> Token: | |||
... | |||
@@ -100,10 +103,22 @@ class Lexer(ABC): | |||
lex: Callable[..., Iterator[Token]] | |||
class LexerConf: | |||
tokens: Collection[TerminalDef] | |||
re_module: ModuleType | |||
ignore: Collection[str] = () | |||
postlex: Any =None | |||
callbacks: Optional[Dict[str, _Callback]] = None | |||
g_regex_flags: int = 0 | |||
skip_validation: bool = False | |||
use_bytes: bool = False | |||
class TraditionalLexer(Lexer): | |||
terminals: Collection[TerminalDef] | |||
ignore_types: List[str] | |||
newline_types: List[str] | |||
ignore_types: FrozenSet[str] | |||
newline_types: FrozenSet[str] | |||
user_callbacks: Dict[str, _Callback] | |||
callback: Dict[str, _Callback] | |||
mres: List[Tuple[REPattern, Dict[int, str]]] | |||
@@ -111,11 +126,7 @@ class TraditionalLexer(Lexer): | |||
def __init__( | |||
self, | |||
terminals: Collection[TerminalDef], | |||
re_: ModuleType, | |||
ignore: Collection[str] = ..., | |||
user_callbacks: Dict[str, _Callback] = ..., | |||
g_regex_flags: int = ... | |||
conf: LexerConf | |||
): | |||
... | |||
@@ -128,6 +139,8 @@ class TraditionalLexer(Lexer): | |||
def lex(self, stream: str) -> Iterator[Token]: | |||
... | |||
def next_token(self, lex_state: Any, parser_state: Any = None) -> Token: | |||
... | |||
class ContextualLexer(Lexer): | |||
lexers: Dict[str, TraditionalLexer] | |||
@@ -3,8 +3,8 @@ from .tree import Tree | |||
from .visitors import Transformer, Visitor, v_args, Discard, Transformer_NonRecursive | |||
from .visitors import InlineTransformer, inline_args # XXX Deprecated | |||
from .exceptions import (ParseError, LexError, GrammarError, UnexpectedToken, | |||
UnexpectedInput, UnexpectedCharacters, LarkError) | |||
UnexpectedInput, UnexpectedCharacters, UnexpectedEOF, LarkError) | |||
from .lexer import Token | |||
from .lark import Lark | |||
__version__ = "0.10.1" | |||
__version__ = "0.11.1" |
@@ -5,8 +5,9 @@ from .lexer import TerminalDef | |||
###{standalone | |||
class LexerConf(Serialize): | |||
__serialize_fields__ = 'terminals', 'ignore', 'g_regex_flags', 'use_bytes' | |||
__serialize_fields__ = 'terminals', 'ignore', 'g_regex_flags', 'use_bytes', 'lexer_type' | |||
__serialize_namespace__ = TerminalDef, | |||
def __init__(self, terminals, re_module, ignore=(), postlex=None, callbacks=None, g_regex_flags=0, skip_validation=False, use_bytes=False): | |||
@@ -18,19 +19,24 @@ class LexerConf(Serialize): | |||
self.re_module = re_module | |||
self.skip_validation = skip_validation | |||
self.use_bytes = use_bytes | |||
self.lexer_type = None | |||
@property | |||
def tokens(self): | |||
warn("LexerConf.tokens is deprecated. Use LexerConf.terminals instead", DeprecationWarning) | |||
return self.terminals | |||
###} | |||
class ParserConf: | |||
class ParserConf(Serialize): | |||
__serialize_fields__ = 'rules', 'start', 'parser_type' | |||
def __init__(self, rules, callbacks, start): | |||
assert isinstance(start, list) | |||
self.rules = rules | |||
self.callbacks = callbacks | |||
self.start = start | |||
self.parser_type = None | |||
###} |
@@ -6,22 +6,27 @@ from .utils import STRING_TYPE, logger | |||
class LarkError(Exception): | |||
pass | |||
class ConfigurationError(LarkError, ValueError): | |||
pass | |||
def assert_config(value, options, msg='Got %r, expected one of %s'): | |||
if value not in options: | |||
raise ConfigurationError(msg % (value, options)) | |||
class GrammarError(LarkError): | |||
pass | |||
class ParseError(LarkError): | |||
pass | |||
class LexError(LarkError): | |||
pass | |||
class UnexpectedEOF(ParseError): | |||
def __init__(self, expected): | |||
self.expected = expected | |||
message = ("Unexpected end-of-input. Expected one of: \n\t* %s\n" % '\n\t* '.join(x.name for x in self.expected)) | |||
super(UnexpectedEOF, self).__init__(message) | |||
class UnexpectedInput(LarkError): | |||
"""UnexpectedInput Error. | |||
@@ -44,6 +49,7 @@ class UnexpectedInput(LarkError): | |||
The parser doesn't hold a copy of the text it has to parse, | |||
so you have to provide it again | |||
""" | |||
assert self.pos_in_stream is not None, self | |||
pos = self.pos_in_stream | |||
start = max(pos - span, 0) | |||
end = pos + span | |||
@@ -88,7 +94,7 @@ class UnexpectedInput(LarkError): | |||
parse_fn(malformed) | |||
except UnexpectedInput as ut: | |||
if ut.state == self.state: | |||
if use_accepts and ut.accepts != self.accepts: | |||
if use_accepts and hasattr(self, 'accepts') and ut.accepts != self.accepts: | |||
logger.debug("Different accepts with same state[%d]: %s != %s at example [%s][%s]" % | |||
(self.state, self.accepts, ut.accepts, i, j)) | |||
continue | |||
@@ -105,7 +111,7 @@ class UnexpectedInput(LarkError): | |||
except AttributeError: | |||
pass | |||
if not candidate[0]: | |||
if candidate[0] is None: | |||
logger.debug("Same State match at example [%s][%s]" % (i, j)) | |||
candidate = label, False | |||
@@ -127,10 +133,24 @@ class UnexpectedInput(LarkError): | |||
ts = names | |||
return "Expected one of: \n\t* %s\n" % '\n\t* '.join(ts) | |||
class UnexpectedEOF(ParseError, UnexpectedInput): | |||
def __init__(self, expected, state=None): | |||
self.expected = expected | |||
self.state = state | |||
from .lexer import Token | |||
self.token = Token("<EOF>", "") #, line=-1, column=-1, pos_in_stream=-1) | |||
self.pos_in_stream = -1 | |||
self.line = -1 | |||
self.column = -1 | |||
message = ("Unexpected end-of-input. Expected one of: \n\t* %s\n" % '\n\t* '.join(x.name for x in self.expected)) | |||
super(UnexpectedEOF, self).__init__(message) | |||
class UnexpectedCharacters(LexError, UnexpectedInput): | |||
def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None, _all_terminals=None): | |||
# TODO considered_tokens and allowed can be figured out using state | |||
self.line = line | |||
self.column = column | |||
self.pos_in_stream = lex_pos | |||
@@ -168,7 +188,8 @@ class UnexpectedToken(ParseError, UnexpectedInput): | |||
see: :ref:`ParserPuppet`. | |||
""" | |||
def __init__(self, token, expected, considered_rules=None, state=None, puppet=None, all_terminals=None): | |||
def __init__(self, token, expected, considered_rules=None, state=None, puppet=None, all_terminals=None, token_history=None): | |||
# TODO considered_rules and expected can be figured out using state | |||
self.line = getattr(token, 'line', '?') | |||
self.column = getattr(token, 'column', '?') | |||
self.pos_in_stream = getattr(token, 'pos_in_stream', None) | |||
@@ -179,6 +200,7 @@ class UnexpectedToken(ParseError, UnexpectedInput): | |||
self.considered_rules = considered_rules | |||
self.puppet = puppet | |||
self._all_terminals = all_terminals | |||
self.token_history = token_history | |||
super(UnexpectedToken, self).__init__() | |||
@@ -191,6 +213,9 @@ class UnexpectedToken(ParseError, UnexpectedInput): | |||
# Be aware: Broken __str__ for Exceptions are terrible to debug. Make sure there is as little room as possible for errors | |||
message = ("Unexpected token %r at line %s, column %s.\n%s" | |||
% (self.token, self.line, self.column, self._format_terminals(self.accepts or self.expected))) | |||
if self.token_history: | |||
message += "Previous tokens: %r\n" % self.token_history | |||
return message | |||
@@ -207,4 +232,6 @@ class VisitError(LarkError): | |||
message = 'Error trying to process rule "%s":\n\n%s' % (rule, orig_exc) | |||
super(VisitError, self).__init__(message) | |||
###} |
@@ -40,14 +40,12 @@ class Terminal(Symbol): | |||
return '%s(%r, %r)' % (type(self).__name__, self.name, self.filter_out) | |||
class NonTerminal(Symbol): | |||
__serialize_fields__ = 'name', | |||
is_term = False | |||
class RuleOptions(Serialize): | |||
__serialize_fields__ = 'keep_all_tokens', 'expand1', 'priority', 'template_source', 'empty_indices' | |||
@@ -104,5 +102,4 @@ class Rule(Serialize): | |||
return self.origin == other.origin and self.expansion == other.expansion | |||
###} |
@@ -1,3 +1,6 @@ | |||
// Basic terminals for common use | |||
// | |||
// Numbers | |||
// | |||
@@ -21,7 +24,7 @@ SIGNED_NUMBER: ["+"|"-"] NUMBER | |||
// Strings | |||
// | |||
_STRING_INNER: /.*?/ | |||
_STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/ | |||
_STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/ | |||
ESCAPED_STRING : "\"" _STRING_ESC_INNER "\"" | |||
@@ -48,3 +51,9 @@ CR : /\r/ | |||
LF : /\n/ | |||
NEWLINE: (CR? LF)+ | |||
// Comments | |||
SH_COMMENT: /#[^\n]*/ | |||
CPP_COMMENT: /\/\/[^\n]*/ | |||
C_COMMENT: "/*" /.*?/s "*/" | |||
SQL_COMMENT: /--[^\n]*/ |
@@ -45,7 +45,7 @@ OP: /[+*]|[?](?![a-z])/ | |||
RULE: /!?[_?]?[a-z][_a-z0-9]*/ | |||
TOKEN: /_?[A-Z][_A-Z0-9]*/ | |||
STRING: _STRING "i"? | |||
REGEXP: /\/(?!\/)(\\\/|\\\\|[^\/\n])*?\/[imslux]*/ | |||
REGEXP: /\/(?!\/)(\\\/|\\\\|[^\/])*?\/[imslux]*/ | |||
_NL: /(\r?\n)+\s*/ | |||
%import common.ESCAPED_STRING -> _STRING |
@@ -0,0 +1,19 @@ | |||
// Python terminals | |||
NAME: /[a-zA-Z_]\w*/ | |||
COMMENT: /#[^\n]*/ | |||
STRING : /[ubf]?r?("(?!"").*?(?<!\\)(\\\\)*?"|'(?!'').*?(?<!\\)(\\\\)*?')/i | |||
LONG_STRING: /[ubf]?r?(""".*?(?<!\\)(\\\\)*?"""|'''.*?(?<!\\)(\\\\)*?''')/is | |||
DEC_NUMBER: /0|[1-9][\d_]*/i | |||
HEX_NUMBER.2: /0x[\da-f]*/i | |||
OCT_NUMBER.2: /0o[0-7]*/i | |||
BIN_NUMBER.2 : /0b[0-1]*/i | |||
FLOAT_NUMBER.2: /((\d+\.[\d_]*|\.[\d_]+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i | |||
IMAG_NUMBER.2: /\d+j/i | FLOAT_NUMBER "j"i | |||
// Comma-separated list (with an optional trailing comma) | |||
cs_list{item}: item ("," item)* ","? | |||
_cs_list{item}: item ("," item)* ","? |
@@ -0,0 +1,7 @@ | |||
// TODO: LETTER, WORD, etc. | |||
// | |||
// Whitespace | |||
// | |||
WS_INLINE: /[ \t\xa0]/+ | |||
WS: /[ \t\xa0\f\r\n]/+ |
@@ -1,12 +1,13 @@ | |||
from __future__ import absolute_import | |||
from lark.exceptions import UnexpectedCharacters, UnexpectedInput, UnexpectedToken | |||
from lark.exceptions import UnexpectedCharacters, UnexpectedInput, UnexpectedToken, ConfigurationError, assert_config | |||
import sys, os, pickle, hashlib | |||
from io import open | |||
import tempfile | |||
from warnings import warn | |||
from .utils import STRING_TYPE, Serialize, SerializeMemoizer, FS, isascii, logger | |||
from .load_grammar import load_grammar | |||
from .load_grammar import load_grammar, FromPackageLoader | |||
from .tree import Tree | |||
from .common import LexerConf, ParserConf | |||
@@ -23,6 +24,7 @@ except ImportError: | |||
###{standalone | |||
class LarkOptions(Serialize): | |||
"""Specifies the options for Lark | |||
@@ -33,9 +35,10 @@ class LarkOptions(Serialize): | |||
start | |||
The start symbol. Either a string, or a list of strings for multiple possible starts (Default: "start") | |||
debug | |||
Display debug information, such as warnings (default: False) | |||
Display debug information and extra warnings. Use only when debugging (default: False) | |||
When used with Earley, it generates a forest graph as "sppf.png", if 'dot' is installed. | |||
transformer | |||
Applies the transformer to every parse tree (equivlent to applying it after the parse, but faster) | |||
Applies the transformer to every parse tree (equivalent to applying it after the parse, but faster) | |||
propagate_positions | |||
Propagates (line, column, end_line, end_column) attributes into all tree branches. | |||
maybe_placeholders | |||
@@ -91,6 +94,10 @@ class LarkOptions(Serialize): | |||
Accept an input of type ``bytes`` instead of ``str`` (Python 3 only). | |||
edit_terminals | |||
A callback for editing the terminals before parse. | |||
import_paths | |||
A List of either paths or loader functions to specify from where grammars are imported | |||
source_path | |||
Override the source of from where the grammar was loaded. Useful for relative imports and unconventional grammar loading | |||
**=== End Options ===** | |||
""" | |||
@@ -125,6 +132,8 @@ class LarkOptions(Serialize): | |||
'edit_terminals': None, | |||
'g_regex_flags': 0, | |||
'use_bytes': False, | |||
'import_paths': [], | |||
'source_path': None, | |||
} | |||
def __init__(self, options_dict): | |||
@@ -146,14 +155,15 @@ class LarkOptions(Serialize): | |||
self.__dict__['options'] = options | |||
assert self.parser in ('earley', 'lalr', 'cyk', None) | |||
assert_config(self.parser, ('earley', 'lalr', 'cyk', None)) | |||
if self.parser == 'earley' and self.transformer: | |||
raise ValueError('Cannot specify an embedded transformer when using the Earley algorithm.' | |||
raise ConfigurationError('Cannot specify an embedded transformer when using the Earley algorithm.' | |||
'Please use your transformer on the resulting parse tree, or use a different algorithm (i.e. LALR)') | |||
if o: | |||
raise ValueError("Unknown options: %s" % o.keys()) | |||
raise ConfigurationError("Unknown options: %s" % o.keys()) | |||
def __getattr__(self, name): | |||
try: | |||
@@ -162,7 +172,7 @@ class LarkOptions(Serialize): | |||
raise AttributeError(e) | |||
def __setattr__(self, name, value): | |||
assert name in self.options | |||
assert_config(name, self.options.keys(), "%r isn't a valid option. Expected one of: %s") | |||
self.options[name] = value | |||
def serialize(self, memo): | |||
@@ -208,10 +218,13 @@ class Lark(Serialize): | |||
re_module = re | |||
# Some, but not all file-like objects have a 'name' attribute | |||
try: | |||
self.source = grammar.name | |||
except AttributeError: | |||
self.source = '<string>' | |||
if self.options.source_path is None: | |||
try: | |||
self.source_path = grammar.name | |||
except AttributeError: | |||
self.source_path = '<string>' | |||
else: | |||
self.source_path = self.options.source_path | |||
# Drain file-like objects to get their contents | |||
try: | |||
@@ -222,29 +235,29 @@ class Lark(Serialize): | |||
grammar = read() | |||
assert isinstance(grammar, STRING_TYPE) | |||
self.grammar_source = grammar | |||
self.source_grammar = grammar | |||
if self.options.use_bytes: | |||
if not isascii(grammar): | |||
raise ValueError("Grammar must be ascii only, when use_bytes=True") | |||
raise ConfigurationError("Grammar must be ascii only, when use_bytes=True") | |||
if sys.version_info[0] == 2 and self.options.use_bytes != 'force': | |||
raise NotImplementedError("`use_bytes=True` may have issues on python2." | |||
raise ConfigurationError("`use_bytes=True` may have issues on python2." | |||
"Use `use_bytes='force'` to use it at your own risk.") | |||
cache_fn = None | |||
if self.options.cache: | |||
if self.options.parser != 'lalr': | |||
raise NotImplementedError("cache only works with parser='lalr' for now") | |||
raise ConfigurationError("cache only works with parser='lalr' for now") | |||
if isinstance(self.options.cache, STRING_TYPE): | |||
cache_fn = self.options.cache | |||
else: | |||
if self.options.cache is not True: | |||
raise ValueError("cache argument must be bool or str") | |||
raise ConfigurationError("cache argument must be bool or str") | |||
unhashable = ('transformer', 'postlex', 'lexer_callbacks', 'edit_terminals') | |||
from . import __version__ | |||
options_str = ''.join(k+str(v) for k, v in options.items() if k not in unhashable) | |||
s = grammar + options_str + __version__ | |||
md5 = hashlib.md5(s.encode()).hexdigest() | |||
cache_fn = '.lark_cache_%s.tmp' % md5 | |||
cache_fn = tempfile.gettempdir() + '/.lark_cache_%s.tmp' % md5 | |||
if FS.exists(cache_fn): | |||
logger.debug('Loading grammar from cache: %s', cache_fn) | |||
@@ -265,27 +278,28 @@ class Lark(Serialize): | |||
else: | |||
assert False, self.options.parser | |||
lexer = self.options.lexer | |||
assert lexer in ('standard', 'contextual', 'dynamic', 'dynamic_complete') or issubclass(lexer, Lexer) | |||
if isinstance(lexer, type): | |||
assert issubclass(lexer, Lexer) # XXX Is this really important? Maybe just ensure interface compliance | |||
else: | |||
assert_config(lexer, ('standard', 'contextual', 'dynamic', 'dynamic_complete')) | |||
if self.options.ambiguity == 'auto': | |||
if self.options.parser == 'earley': | |||
self.options.ambiguity = 'resolve' | |||
else: | |||
disambig_parsers = ['earley', 'cyk'] | |||
assert self.options.parser in disambig_parsers, ( | |||
'Only %s supports disambiguation right now') % ', '.join(disambig_parsers) | |||
assert_config(self.options.parser, ('earley', 'cyk'), "%r doesn't support disambiguation. Use one of these parsers instead: %s") | |||
if self.options.priority == 'auto': | |||
self.options.priority = 'normal' | |||
if self.options.priority not in _VALID_PRIORITY_OPTIONS: | |||
raise ValueError("invalid priority option: %r. Must be one of %r" % (self.options.priority, _VALID_PRIORITY_OPTIONS)) | |||
raise ConfigurationError("invalid priority option: %r. Must be one of %r" % (self.options.priority, _VALID_PRIORITY_OPTIONS)) | |||
assert self.options.ambiguity not in ('resolve__antiscore_sum', ), 'resolve__antiscore_sum has been replaced with the option priority="invert"' | |||
if self.options.ambiguity not in _VALID_AMBIGUITY_OPTIONS: | |||
raise ValueError("invalid ambiguity option: %r. Must be one of %r" % (self.options.ambiguity, _VALID_AMBIGUITY_OPTIONS)) | |||
raise ConfigurationError("invalid ambiguity option: %r. Must be one of %r" % (self.options.ambiguity, _VALID_AMBIGUITY_OPTIONS)) | |||
# Parse the grammar file and compose the grammars (TODO) | |||
self.grammar = load_grammar(grammar, self.source, re_module, self.options.keep_all_tokens) | |||
# Parse the grammar file and compose the grammars | |||
self.grammar = load_grammar(grammar, self.source_path, self.options.import_paths, self.options.keep_all_tokens) | |||
if self.options.postlex is not None: | |||
terminals_to_keep = set(self.options.postlex.always_accept) | |||
@@ -310,7 +324,7 @@ class Lark(Serialize): | |||
# Else, if the user asked to disable priorities, strip them from the | |||
# rules. This allows the Earley parsers to skip an extra forest walk | |||
# for improved performance, if you don't need them (or didn't specify any). | |||
elif self.options.priority == None: | |||
elif self.options.priority is None: | |||
for rule in self.rules: | |||
if rule.options.priority is not None: | |||
rule.options.priority = None | |||
@@ -350,7 +364,7 @@ class Lark(Serialize): | |||
self.rules, | |||
self.options.tree_class or Tree, | |||
self.options.propagate_positions, | |||
self.options.parser!='lalr' and self.options.ambiguity=='explicit', | |||
self.options.parser != 'lalr' and self.options.ambiguity == 'explicit', | |||
self.options.maybe_placeholders | |||
) | |||
self._callbacks = self._parse_tree_builder.create_callback(self.options.transformer) | |||
@@ -389,18 +403,18 @@ class Lark(Serialize): | |||
memo = SerializeMemoizer.deserialize(memo, {'Rule': Rule, 'TerminalDef': TerminalDef}, {}) | |||
options = dict(data['options']) | |||
if (set(kwargs) - _LOAD_ALLOWED_OPTIONS) & set(LarkOptions._defaults): | |||
raise ValueError("Some options are not allowed when loading a Parser: {}" | |||
raise ConfigurationError("Some options are not allowed when loading a Parser: {}" | |||
.format(set(kwargs) - _LOAD_ALLOWED_OPTIONS)) | |||
options.update(kwargs) | |||
self.options = LarkOptions.deserialize(options, memo) | |||
self.rules = [Rule.deserialize(r, memo) for r in data['rules']] | |||
self.source = '<deserialized>' | |||
self.source_path = '<deserialized>' | |||
self._prepare_callbacks() | |||
self.parser = self.parser_class.deserialize( | |||
data['parser'], | |||
memo, | |||
self._callbacks, | |||
self.options, # Not all, but multiple attributes are used | |||
self.options, # Not all, but multiple attributes are used | |||
) | |||
self.terminals = self.parser.lexer_conf.terminals | |||
self._terminals_dict = {t.name: t for t in self.terminals} | |||
@@ -429,8 +443,26 @@ class Lark(Serialize): | |||
with open(grammar_filename, encoding='utf8') as f: | |||
return cls(f, **options) | |||
@classmethod | |||
def open_from_package(cls, package, grammar_path, search_paths=("",), **options): | |||
"""Create an instance of Lark with the grammar loaded from within the package `package`. | |||
This allows grammar loading from zipapps. | |||
Imports in the grammar will use the `package` and `search_paths` provided, through `FromPackageLoader` | |||
Example: | |||
Lark.open_from_package(__name__, "example.lark", ("grammars",), parser=...) | |||
""" | |||
package = FromPackageLoader(package, search_paths) | |||
full_path, text = package(None, grammar_path) | |||
options.setdefault('source_path', full_path) | |||
options.setdefault('import_paths', []) | |||
options['import_paths'].append(package) | |||
return cls(text, **options) | |||
def __repr__(self): | |||
return 'Lark(open(%r), parser=%r, lexer=%r, ...)' % (self.source, self.options.parser, self.options.lexer) | |||
return 'Lark(open(%r), parser=%r, lexer=%r, ...)' % (self.source_path, self.options.parser, self.options.lexer) | |||
def lex(self, text): | |||
@@ -490,5 +522,23 @@ class Lark(Serialize): | |||
except UnexpectedCharacters as e2: | |||
e = e2 | |||
@property | |||
def source(self): | |||
warn("Lark.source attribute has been renamed to Lark.source_path", DeprecationWarning) | |||
return self.source_path | |||
@source.setter | |||
def source(self, value): | |||
self.source_path = value | |||
@property | |||
def grammar_source(self): | |||
warn("Lark.grammar_source attribute has been renamed to Lark.source_grammar", DeprecationWarning) | |||
return self.source_grammar | |||
@grammar_source.setter | |||
def grammar_source(self, value): | |||
self.source_grammar = value | |||
###} |
@@ -1,4 +1,4 @@ | |||
## Lexer Implementation | |||
# Lexer Implementation | |||
import re | |||
@@ -8,6 +8,7 @@ from .exceptions import UnexpectedCharacters, LexError, UnexpectedToken | |||
###{standalone | |||
from copy import copy | |||
class Pattern(Serialize): | |||
def __init__(self, value, flags=(), raw=None): | |||
@@ -21,6 +22,7 @@ class Pattern(Serialize): | |||
# Pattern Hashing assumes all subclasses have a different priority! | |||
def __hash__(self): | |||
return hash((type(self), self.value, self.flags)) | |||
def __eq__(self, other): | |||
return type(self) == type(other) and self.value == other.value and self.flags == other.flags | |||
@@ -54,6 +56,7 @@ class PatternStr(Pattern): | |||
return len(self.value) | |||
max_width = min_width | |||
class PatternRE(Pattern): | |||
__serialize_fields__ = 'value', 'flags', '_width' | |||
@@ -71,6 +74,7 @@ class PatternRE(Pattern): | |||
@property | |||
def min_width(self): | |||
return self._get_width()[0] | |||
@property | |||
def max_width(self): | |||
return self._get_width()[1] | |||
@@ -141,7 +145,7 @@ class Token(Str): | |||
return cls(type_, value, borrow_t.pos_in_stream, borrow_t.line, borrow_t.column, borrow_t.end_line, borrow_t.end_column, borrow_t.end_pos) | |||
def __reduce__(self): | |||
return (self.__class__, (self.type, self.value, self.pos_in_stream, self.line, self.column, )) | |||
return (self.__class__, (self.type, self.value, self.pos_in_stream, self.line, self.column)) | |||
def __repr__(self): | |||
return 'Token(%r, %r)' % (self.type, self.value) | |||
@@ -195,6 +199,7 @@ class UnlessCallback: | |||
break | |||
return t | |||
class CallChain: | |||
def __init__(self, callback1, callback2, cond): | |||
self.callback1 = callback1 | |||
@@ -206,16 +211,13 @@ class CallChain: | |||
return self.callback2(t) if self.cond(t2) else t2 | |||
def _create_unless(terminals, g_regex_flags, re_, use_bytes): | |||
tokens_by_type = classify(terminals, lambda t: type(t.pattern)) | |||
assert len(tokens_by_type) <= 2, tokens_by_type.keys() | |||
embedded_strs = set() | |||
callback = {} | |||
for retok in tokens_by_type.get(PatternRE, []): | |||
unless = [] # {} | |||
unless = [] | |||
for strtok in tokens_by_type.get(PatternStr, []): | |||
if strtok.priority > retok.priority: | |||
continue | |||
@@ -247,13 +249,15 @@ def _build_mres(terminals, max_size, g_regex_flags, match_whole, re_, use_bytes) | |||
except AssertionError: # Yes, this is what Python provides us.. :/ | |||
return _build_mres(terminals, max_size//2, g_regex_flags, match_whole, re_, use_bytes) | |||
mres.append((mre, {i:n for n,i in mre.groupindex.items()} )) | |||
mres.append((mre, {i: n for n, i in mre.groupindex.items()})) | |||
terminals = terminals[max_size:] | |||
return mres | |||
def build_mres(terminals, g_regex_flags, re_, use_bytes, match_whole=False): | |||
return _build_mres(terminals, len(terminals), g_regex_flags, match_whole, re_, use_bytes) | |||
def _regexp_has_newline(r): | |||
r"""Expressions that may indicate newlines in a regexp: | |||
- newlines (\n) | |||
@@ -264,6 +268,7 @@ def _regexp_has_newline(r): | |||
""" | |||
return '\n' in r or '\\n' in r or '\\s' in r or '[^' in r or ('(?s' in r and '.' in r) | |||
class Lexer(object): | |||
"""Lexer interface | |||
@@ -302,7 +307,7 @@ class TraditionalLexer(Lexer): | |||
self.newline_types = frozenset(t.name for t in terminals if _regexp_has_newline(t.pattern.to_regexp())) | |||
self.ignore_types = frozenset(conf.ignore) | |||
terminals.sort(key=lambda x:(-x.priority, -x.pattern.max_width, -len(x.pattern.value), x.name)) | |||
terminals.sort(key=lambda x: (-x.priority, -x.pattern.max_width, -len(x.pattern.value), x.name)) | |||
self.terminals = terminals | |||
self.user_callbacks = conf.callbacks | |||
self.g_regex_flags = conf.g_regex_flags | |||
@@ -311,7 +316,7 @@ class TraditionalLexer(Lexer): | |||
self._mres = None | |||
def _build(self): | |||
terminals, self.callback = _create_unless(self.terminals, self.g_regex_flags, re_=self.re, use_bytes=self.use_bytes) | |||
terminals, self.callback = _create_unless(self.terminals, self.g_regex_flags, self.re, self.use_bytes) | |||
assert all(self.callback.values()) | |||
for type_, f in self.user_callbacks.items(): | |||
@@ -338,9 +343,9 @@ class TraditionalLexer(Lexer): | |||
def lex(self, state, parser_state): | |||
with suppress(EOFError): | |||
while True: | |||
yield self.next_token(state) | |||
yield self.next_token(state, parser_state) | |||
def next_token(self, lex_state): | |||
def next_token(self, lex_state, parser_state=None): | |||
line_ctr = lex_state.line_ctr | |||
while line_ctr.char_pos < len(lex_state.text): | |||
res = self.match(lex_state.text, line_ctr.char_pos) | |||
@@ -350,7 +355,7 @@ class TraditionalLexer(Lexer): | |||
allowed = {"<END-OF-FILE>"} | |||
raise UnexpectedCharacters(lex_state.text, line_ctr.char_pos, line_ctr.line, line_ctr.column, | |||
allowed=allowed, token_history=lex_state.last_token and [lex_state.last_token], | |||
_all_terminals=self.terminals) | |||
state=parser_state, _all_terminals=self.terminals) | |||
value, type_ = res | |||
@@ -363,7 +368,7 @@ class TraditionalLexer(Lexer): | |||
if t.type in self.callback: | |||
t = self.callback[t.type](t) | |||
if not isinstance(t, Token): | |||
raise ValueError("Callbacks must return a token (returned %r)" % t) | |||
raise LexError("Callbacks must return a token (returned %r)" % t) | |||
lex_state.last_token = t | |||
return t | |||
else: | |||
@@ -375,6 +380,7 @@ class TraditionalLexer(Lexer): | |||
# EOF | |||
raise EOFError(self) | |||
class LexerState: | |||
__slots__ = 'text', 'line_ctr', 'last_token' | |||
@@ -386,6 +392,7 @@ class LexerState: | |||
def __copy__(self): | |||
return type(self)(self.text, copy(self.line_ctr), self.last_token) | |||
class ContextualLexer(Lexer): | |||
def __init__(self, conf, states, always_accept=()): | |||
@@ -424,17 +431,17 @@ class ContextualLexer(Lexer): | |||
try: | |||
while True: | |||
lexer = self.lexers[parser_state.position] | |||
yield lexer.next_token(lexer_state) | |||
yield lexer.next_token(lexer_state, parser_state) | |||
except EOFError: | |||
pass | |||
except UnexpectedCharacters as e: | |||
# In the contextual lexer, UnexpectedCharacters can mean that the terminal is defined, but not in the current context. | |||
# This tests the input against the global context, to provide a nicer error. | |||
token = self.root_lexer.next_token(lexer_state) | |||
raise UnexpectedToken(token, e.allowed, state=parser_state.position, all_terminals=self.root_lexer.terminals) | |||
raise UnexpectedToken(token, e.allowed, state=parser_state.position, token_history=[lexer_state.last_token], all_terminals=self.root_lexer.terminals) | |||
class LexerThread: | |||
"A thread that ties a lexer instance and a lexer state, to be used by the parser" | |||
"""A thread that ties a lexer instance and a lexer state, to be used by the parser""" | |||
def __init__(self, lexer, text): | |||
self.lexer = lexer | |||
@@ -1,15 +1,17 @@ | |||
"Parses and creates Grammar objects" | |||
"""Parses and creates Grammar objects""" | |||
import os.path | |||
import sys | |||
from copy import copy, deepcopy | |||
from io import open | |||
import pkgutil | |||
from ast import literal_eval | |||
from .utils import bfs, eval_escaping, Py36, logger, classify_bool, isascii | |||
from .utils import bfs, Py36, logger, classify_bool | |||
from .lexer import Token, TerminalDef, PatternStr, PatternRE | |||
from .parse_tree_builder import ParseTreeBuilder | |||
from .parser_frontends import LALR_TraditionalLexer | |||
from .parser_frontends import ParsingFrontend | |||
from .common import LexerConf, ParserConf | |||
from .grammar import RuleOptions, Rule, Terminal, NonTerminal, Symbol | |||
from .utils import classify, suppress, dedup_list, Str | |||
@@ -20,7 +22,7 @@ from .visitors import Transformer, Visitor, v_args, Transformer_InPlace, Transfo | |||
inline_args = v_args(inline=True) | |||
__path__ = os.path.dirname(__file__) | |||
IMPORT_PATHS = [os.path.join(__path__, 'grammars')] | |||
IMPORT_PATHS = ['grammars'] | |||
EXT = '.lark' | |||
@@ -165,6 +167,7 @@ RULES = { | |||
'literal': ['REGEXP', 'STRING'], | |||
} | |||
@inline_args | |||
class EBNF_to_BNF(Transformer_InPlace): | |||
def __init__(self): | |||
@@ -258,9 +261,9 @@ class SimplifyRule_Visitor(Visitor): | |||
for i, child in enumerate(tree.children): | |||
if isinstance(child, Tree) and child.data == 'expansions': | |||
tree.data = 'expansions' | |||
tree.children = [self.visit(ST('expansion', [option if i==j else other | |||
for j, other in enumerate(tree.children)])) | |||
for option in dedup_list(child.children)] | |||
tree.children = [self.visit(ST('expansion', [option if i == j else other | |||
for j, other in enumerate(tree.children)])) | |||
for option in dedup_list(child.children)] | |||
self._flatten(tree) | |||
break | |||
@@ -283,8 +286,10 @@ class SimplifyRule_Visitor(Visitor): | |||
class RuleTreeToText(Transformer): | |||
def expansions(self, x): | |||
return x | |||
def expansion(self, symbols): | |||
return symbols, None | |||
def alias(self, x): | |||
(expansion, _alias), alias = x | |||
assert _alias is None, (alias, expansion, '-', _alias) # Double alias not allowed | |||
@@ -299,8 +304,9 @@ class CanonizeTree(Transformer_InPlace): | |||
tokenmods, value = args | |||
return tokenmods + [value] | |||
class PrepareAnonTerminals(Transformer_InPlace): | |||
"Create a unique list of anonymous terminals. Attempt to give meaningful names to them when we add them" | |||
"""Create a unique list of anonymous terminals. Attempt to give meaningful names to them when we add them""" | |||
def __init__(self, terminals): | |||
self.terminals = terminals | |||
@@ -309,7 +315,6 @@ class PrepareAnonTerminals(Transformer_InPlace): | |||
self.i = 0 | |||
self.rule_options = None | |||
@inline_args | |||
def pattern(self, p): | |||
value = p.value | |||
@@ -328,14 +333,16 @@ class PrepareAnonTerminals(Transformer_InPlace): | |||
try: | |||
term_name = _TERMINAL_NAMES[value] | |||
except KeyError: | |||
if value.isalnum() and value[0].isalpha() and value.upper() not in self.term_set and isascii(value): | |||
term_name = value.upper() | |||
if value.isalnum() and value[0].isalpha() and value.upper() not in self.term_set: | |||
with suppress(UnicodeEncodeError): | |||
value.upper().encode('ascii') # Make sure we don't have unicode in our terminal names | |||
term_name = value.upper() | |||
if term_name in self.term_set: | |||
term_name = None | |||
elif isinstance(p, PatternRE): | |||
if p in self.term_reverse: # Kind of a weird placement.name | |||
if p in self.term_reverse: # Kind of a weird placement.name | |||
term_name = self.term_reverse[p].name | |||
else: | |||
assert False, p | |||
@@ -357,7 +364,7 @@ class PrepareAnonTerminals(Transformer_InPlace): | |||
class _ReplaceSymbols(Transformer_InPlace): | |||
" Helper for ApplyTemplates " | |||
"""Helper for ApplyTemplates""" | |||
def __init__(self): | |||
self.names = {} | |||
@@ -372,8 +379,9 @@ class _ReplaceSymbols(Transformer_InPlace): | |||
return self.__default__('template_usage', [self.names[c[0]].name] + c[1:], None) | |||
return self.__default__('template_usage', c, None) | |||
class ApplyTemplates(Transformer_InPlace): | |||
" Apply the templates, creating new rules that represent the used templates " | |||
"""Apply the templates, creating new rules that represent the used templates""" | |||
def __init__(self, rule_defs): | |||
self.rule_defs = rule_defs | |||
@@ -399,6 +407,30 @@ def _rfind(s, choices): | |||
return max(s.rfind(c) for c in choices) | |||
def eval_escaping(s): | |||
w = '' | |||
i = iter(s) | |||
for n in i: | |||
w += n | |||
if n == '\\': | |||
try: | |||
n2 = next(i) | |||
except StopIteration: | |||
raise GrammarError("Literal ended unexpectedly (bad escaping): `%r`" % s) | |||
if n2 == '\\': | |||
w += '\\\\' | |||
elif n2 not in 'uxnftr': | |||
w += '\\' | |||
w += n2 | |||
w = w.replace('\\"', '"').replace("'", "\\'") | |||
to_eval = "u'''%s'''" % w | |||
try: | |||
s = literal_eval(to_eval) | |||
except SyntaxError as e: | |||
raise GrammarError(s, e) | |||
return s | |||
def _literal_to_pattern(literal): | |||
@@ -439,7 +471,7 @@ class PrepareLiterals(Transformer_InPlace): | |||
assert start.type == end.type == 'STRING' | |||
start = start.value[1:-1] | |||
end = end.value[1:-1] | |||
assert len(eval_escaping(start)) == len(eval_escaping(end)) == 1, (start, end, len(eval_escaping(start)), len(eval_escaping(end))) | |||
assert len(eval_escaping(start)) == len(eval_escaping(end)) == 1 | |||
regexp = '[%s-%s]' % (start, end) | |||
return ST('pattern', [PatternRE(regexp)]) | |||
@@ -458,6 +490,7 @@ def _make_joined_pattern(regexp, flags_set): | |||
return PatternRE(regexp, flags) | |||
class TerminalTreeToPattern(Transformer): | |||
def pattern(self, ps): | |||
p ,= ps | |||
@@ -501,6 +534,7 @@ class TerminalTreeToPattern(Transformer): | |||
def value(self, v): | |||
return v[0] | |||
class PrepareSymbols(Transformer_InPlace): | |||
def value(self, v): | |||
v ,= v | |||
@@ -512,13 +546,16 @@ class PrepareSymbols(Transformer_InPlace): | |||
return Terminal(Str(v.value), filter_out=v.startswith('_')) | |||
assert False | |||
def _choice_of_rules(rules): | |||
return ST('expansions', [ST('expansion', [Token('RULE', name)]) for name in rules]) | |||
def nr_deepcopy_tree(t): | |||
"Deepcopy tree `t` without recursion" | |||
"""Deepcopy tree `t` without recursion""" | |||
return Transformer_NonRecursive(False).transform(t) | |||
class Grammar: | |||
def __init__(self, rule_defs, term_defs, ignore): | |||
self.term_defs = term_defs | |||
@@ -545,7 +582,7 @@ class Grammar: | |||
raise GrammarError("Terminals cannot be empty (%s)" % name) | |||
transformer = PrepareLiterals() * TerminalTreeToPattern() | |||
terminals = [TerminalDef(name, transformer.transform( term_tree ), priority) | |||
terminals = [TerminalDef(name, transformer.transform(term_tree), priority) | |||
for name, (term_tree, priority) in term_defs if term_tree] | |||
# ================= | |||
@@ -564,10 +601,10 @@ class Grammar: | |||
ebnf_to_bnf = EBNF_to_BNF() | |||
rules = [] | |||
i = 0 | |||
while i < len(rule_defs): # We have to do it like this because rule_defs might grow due to templates | |||
while i < len(rule_defs): # We have to do it like this because rule_defs might grow due to templates | |||
name, params, rule_tree, options = rule_defs[i] | |||
i += 1 | |||
if len(params) != 0: # Dont transform templates | |||
if len(params) != 0: # Dont transform templates | |||
continue | |||
rule_options = RuleOptions(keep_all_tokens=True) if options and options.keep_all_tokens else None | |||
ebnf_to_bnf.rule_options = rule_options | |||
@@ -592,7 +629,7 @@ class Grammar: | |||
for i, (expansion, alias) in enumerate(expansions): | |||
if alias and name.startswith('_'): | |||
raise GrammarError("Rule %s is marked for expansion (it starts with an underscore) and isn't allowed to have aliases (alias=%s)" % (name, alias)) | |||
raise GrammarError("Rule %s is marked for expansion (it starts with an underscore) and isn't allowed to have aliases (alias=%s)"% (name, alias)) | |||
empty_indices = [x==_EMPTY for x in expansion] | |||
if any(empty_indices): | |||
@@ -621,14 +658,13 @@ class Grammar: | |||
# Remove duplicates | |||
compiled_rules = list(set(compiled_rules)) | |||
# Filter out unused rules | |||
while True: | |||
c = len(compiled_rules) | |||
used_rules = {s for r in compiled_rules | |||
for s in r.expansion | |||
if isinstance(s, NonTerminal) | |||
and s != r.origin} | |||
for s in r.expansion | |||
if isinstance(s, NonTerminal) | |||
and s != r.origin} | |||
used_rules |= {NonTerminal(s) for s in start} | |||
compiled_rules, unused = classify_bool(compiled_rules, lambda r: r.origin in used_rules) | |||
for r in unused: | |||
@@ -647,9 +683,63 @@ class Grammar: | |||
return terminals, compiled_rules, self.ignore | |||
class PackageResource(object): | |||
""" | |||
Represents a path inside a Package. Used by `FromPackageLoader` | |||
""" | |||
def __init__(self, pkg_name, path): | |||
self.pkg_name = pkg_name | |||
self.path = path | |||
def __str__(self): | |||
return "<%s: %s>" % (self.pkg_name, self.path) | |||
def __repr__(self): | |||
return "%s(%r, %r)" % (type(self).__name__, self.pkg_name, self.path) | |||
class FromPackageLoader(object): | |||
""" | |||
Provides a simple way of creating custom import loaders that load from packages via ``pkgutil.get_data`` instead of using `open`. | |||
This allows them to be compatible even from within zip files. | |||
Relative imports are handled, so you can just freely use them. | |||
pkg_name: The name of the package. You can probably provide `__name__` most of the time | |||
search_paths: All the path that will be search on absolute imports. | |||
""" | |||
def __init__(self, pkg_name, search_paths=("", )): | |||
self.pkg_name = pkg_name | |||
self.search_paths = search_paths | |||
def __repr__(self): | |||
return "%s(%r, %r)" % (type(self).__name__, self.pkg_name, self.search_paths) | |||
def __call__(self, base_path, grammar_path): | |||
if base_path is None: | |||
to_try = self.search_paths | |||
else: | |||
# Check whether or not the importing grammar was loaded by this module. | |||
if not isinstance(base_path, PackageResource) or base_path.pkg_name != self.pkg_name: | |||
# Technically false, but FileNotFound doesn't exist in python2.7, and this message should never reach the end user anyway | |||
raise IOError() | |||
to_try = [base_path.path] | |||
for path in to_try: | |||
full_path = os.path.join(path, grammar_path) | |||
try: | |||
text = pkgutil.get_data(self.pkg_name, full_path) | |||
except IOError: | |||
continue | |||
else: | |||
return PackageResource(self.pkg_name, full_path), text.decode() | |||
raise IOError() | |||
stdlib_loader = FromPackageLoader('lark', IMPORT_PATHS) | |||
_imported_grammars = {} | |||
def import_from_grammar_into_namespace(grammar, namespace, aliases): | |||
"""Returns all rules and terminals of grammar, prepended | |||
with a 'namespace' prefix, except for those which are aliased. | |||
@@ -670,8 +760,6 @@ def import_from_grammar_into_namespace(grammar, namespace, aliases): | |||
raise GrammarError("Missing symbol '%s' in grammar %s" % (symbol, namespace)) | |||
return _find_used_symbols(tree) - set(params) | |||
def get_namespace_name(name, params): | |||
if params is not None: | |||
try: | |||
@@ -692,19 +780,17 @@ def import_from_grammar_into_namespace(grammar, namespace, aliases): | |||
else: | |||
assert symbol.type == 'RULE' | |||
_, params, tree, options = imported_rules[symbol] | |||
params_map = {p: ('%s__%s' if p[0]!='_' else '_%s__%s' ) % (namespace, p) for p in params} | |||
params_map = {p: ('%s__%s' if p[0]!='_' else '_%s__%s') % (namespace, p) for p in params} | |||
for t in tree.iter_subtrees(): | |||
for i, c in enumerate(t.children): | |||
if isinstance(c, Token) and c.type in ('RULE', 'TERMINAL'): | |||
t.children[i] = Token(c.type, get_namespace_name(c, params_map)) | |||
params = [params_map[p] for p in params] # We can not rely on ordered dictionaries | |||
params = [params_map[p] for p in params] # We can not rely on ordered dictionaries | |||
rule_defs.append((get_namespace_name(symbol, params_map), params, tree, options)) | |||
return term_defs, rule_defs | |||
def resolve_term_references(term_defs): | |||
# TODO Solve with transitive closure (maybe) | |||
@@ -744,7 +830,7 @@ def options_from_rule(name, params, *x): | |||
else: | |||
expansions ,= x | |||
priority = None | |||
params = [t.value for t in params.children] if params is not None else [] # For the grammar parser | |||
params = [t.value for t in params.children] if params is not None else [] # For the grammar parser | |||
keep_all_tokens = name.startswith('!') | |||
name = name.lstrip('!') | |||
@@ -758,10 +844,12 @@ def options_from_rule(name, params, *x): | |||
def symbols_from_strcase(expansion): | |||
return [Terminal(x, filter_out=x.startswith('_')) if x.isupper() else NonTerminal(x) for x in expansion] | |||
@inline_args | |||
class PrepareGrammar(Transformer_InPlace): | |||
def terminal(self, name): | |||
return name | |||
def nonterminal(self, name): | |||
return name | |||
@@ -771,10 +859,11 @@ def _find_used_symbols(tree): | |||
return {t for x in tree.find_data('expansion') | |||
for t in x.scan_values(lambda t: t.type in ('RULE', 'TERMINAL'))} | |||
class GrammarLoader: | |||
ERRORS = [ | |||
('Unclosed parenthesis', ['a: (\n']), | |||
('Umatched closing parenthesis', ['a: )\n', 'a: [)\n', 'a: (]\n']), | |||
('Unmatched closing parenthesis', ['a: )\n', 'a: [)\n', 'a: (]\n']), | |||
('Expecting rule or terminal definition (missing colon)', ['a\n', 'A\n', 'a->\n', 'A->\n', 'a A\n']), | |||
('Illegal name for rules or terminals', ['Aa:\n']), | |||
('Alias expects lowercase name', ['a: -> "a"\n']), | |||
@@ -786,43 +875,53 @@ class GrammarLoader: | |||
('%ignore expects a value', ['%ignore %import\n']), | |||
] | |||
def __init__(self, re_module, global_keep_all_tokens): | |||
def __init__(self, global_keep_all_tokens): | |||
terminals = [TerminalDef(name, PatternRE(value)) for name, value in TERMINALS.items()] | |||
rules = [options_from_rule(name, None, x) for name, x in RULES.items()] | |||
rules = [Rule(NonTerminal(r), symbols_from_strcase(x.split()), i, None, o) for r, _p, xs, o in rules for i, x in enumerate(xs)] | |||
rules = [options_from_rule(name, None, x) for name, x in RULES.items()] | |||
rules = [Rule(NonTerminal(r), symbols_from_strcase(x.split()), i, None, o) | |||
for r, _p, xs, o in rules for i, x in enumerate(xs)] | |||
callback = ParseTreeBuilder(rules, ST).create_callback() | |||
lexer_conf = LexerConf(terminals, re_module, ['WS', 'COMMENT']) | |||
import re | |||
lexer_conf = LexerConf(terminals, re, ['WS', 'COMMENT']) | |||
parser_conf = ParserConf(rules, callback, ['start']) | |||
self.parser = LALR_TraditionalLexer(lexer_conf, parser_conf) | |||
lexer_conf.lexer_type = 'standard' | |||
parser_conf.parser_type = 'lalr' | |||
self.parser = ParsingFrontend(lexer_conf, parser_conf, {}) | |||
self.canonize_tree = CanonizeTree() | |||
self.re_module = re_module | |||
self.global_keep_all_tokens = global_keep_all_tokens | |||
def import_grammar(self, grammar_path, base_paths=[]): | |||
def import_grammar(self, grammar_path, base_path=None, import_paths=[]): | |||
if grammar_path not in _imported_grammars: | |||
import_paths = base_paths + IMPORT_PATHS | |||
for import_path in import_paths: | |||
with suppress(IOError): | |||
joined_path = os.path.join(import_path, grammar_path) | |||
with open(joined_path, encoding='utf8') as f: | |||
text = f.read() | |||
grammar = self.load_grammar(text, joined_path) | |||
# import_paths take priority over base_path since they should handle relative imports and ignore everything else. | |||
to_try = import_paths + ([base_path] if base_path is not None else []) + [stdlib_loader] | |||
for source in to_try: | |||
try: | |||
if callable(source): | |||
joined_path, text = source(base_path, grammar_path) | |||
else: | |||
joined_path = os.path.join(source, grammar_path) | |||
with open(joined_path, encoding='utf8') as f: | |||
text = f.read() | |||
except IOError: | |||
continue | |||
else: | |||
grammar = self.load_grammar(text, joined_path, import_paths) | |||
_imported_grammars[grammar_path] = grammar | |||
break | |||
else: | |||
open(grammar_path, encoding='utf8') # Force a file not found error | |||
# Search failed. Make Python throw a nice error. | |||
open(grammar_path, encoding='utf8') | |||
assert False | |||
return _imported_grammars[grammar_path] | |||
def load_grammar(self, grammar_text, grammar_name='<?>'): | |||
"Parse grammar_text, verify, and create Grammar object. Display nice messages on error." | |||
def load_grammar(self, grammar_text, grammar_name='<?>', import_paths=[]): | |||
"""Parse grammar_text, verify, and create Grammar object. Display nice messages on error.""" | |||
try: | |||
tree = self.canonize_tree.transform( self.parser.parse(grammar_text+'\n') ) | |||
tree = self.canonize_tree.transform(self.parser.parse(grammar_text+'\n')) | |||
except UnexpectedCharacters as e: | |||
context = e.get_context(grammar_text) | |||
raise GrammarError("Unexpected input at line %d column %d in %s: \n\n%s" % | |||
@@ -872,7 +971,7 @@ class GrammarLoader: | |||
aliases = {name: arg1 or name} # Aliases if exist | |||
if path_node.data == 'import_lib': # Import from library | |||
base_paths = [] | |||
base_path = None | |||
else: # Relative import | |||
if grammar_name == '<string>': # Import relative to script file path if grammar is coded in script | |||
try: | |||
@@ -882,16 +981,19 @@ class GrammarLoader: | |||
else: | |||
base_file = grammar_name # Import relative to grammar file path if external grammar file | |||
if base_file: | |||
base_paths = [os.path.split(base_file)[0]] | |||
if isinstance(base_file, PackageResource): | |||
base_path = PackageResource(base_file.pkg_name, os.path.split(base_file.path)[0]) | |||
else: | |||
base_path = os.path.split(base_file)[0] | |||
else: | |||
base_paths = [os.path.abspath(os.path.curdir)] | |||
base_path = os.path.abspath(os.path.curdir) | |||
try: | |||
import_base_paths, import_aliases = imports[dotted_path] | |||
assert base_paths == import_base_paths, 'Inconsistent base_paths for %s.' % '.'.join(dotted_path) | |||
import_base_path, import_aliases = imports[dotted_path] | |||
assert base_path == import_base_path, 'Inconsistent base_path for %s.' % '.'.join(dotted_path) | |||
import_aliases.update(aliases) | |||
except KeyError: | |||
imports[dotted_path] = base_paths, aliases | |||
imports[dotted_path] = base_path, aliases | |||
elif stmt.data == 'declare': | |||
for t in stmt.children: | |||
@@ -900,9 +1002,9 @@ class GrammarLoader: | |||
assert False, stmt | |||
# import grammars | |||
for dotted_path, (base_paths, aliases) in imports.items(): | |||
for dotted_path, (base_path, aliases) in imports.items(): | |||
grammar_path = os.path.join(*dotted_path) + EXT | |||
g = self.import_grammar(grammar_path, base_paths=base_paths) | |||
g = self.import_grammar(grammar_path, base_path=base_path, import_paths=import_paths) | |||
new_td, new_rd = import_from_grammar_into_namespace(g, '__'.join(dotted_path), aliases) | |||
term_defs += new_td | |||
@@ -972,7 +1074,7 @@ class GrammarLoader: | |||
raise GrammarError("Template '%s' used but not defined (in rule %s)" % (sym, name)) | |||
if len(args) != rule_names[sym]: | |||
raise GrammarError("Wrong number of template arguments used for %s " | |||
"(expected %s, got %s) (in rule %s)"%(sym, rule_names[sym], len(args), name)) | |||
"(expected %s, got %s) (in rule %s)" % (sym, rule_names[sym], len(args), name)) | |||
for sym in _find_used_symbols(expansions): | |||
if sym.type == 'TERMINAL': | |||
if sym not in terminal_names: | |||
@@ -981,10 +1083,8 @@ class GrammarLoader: | |||
if sym not in rule_names and sym not in params: | |||
raise GrammarError("Rule '%s' used but not defined (in rule %s)" % (sym, name)) | |||
return Grammar(rules, term_defs, ignore_names) | |||
def load_grammar(grammar, source, re_, global_keep_all_tokens): | |||
return GrammarLoader(re_, global_keep_all_tokens).load_grammar(grammar, source) | |||
def load_grammar(grammar, source, import_paths, global_keep_all_tokens): | |||
return GrammarLoader(global_keep_all_tokens).load_grammar(grammar, source, import_paths) |
@@ -1,7 +1,7 @@ | |||
from .exceptions import GrammarError | |||
from .lexer import Token | |||
from .tree import Tree | |||
from .visitors import InlineTransformer # XXX Deprecated | |||
from .visitors import InlineTransformer # XXX Deprecated | |||
from .visitors import Transformer_InPlace | |||
from .visitors import _vargs_meta, _vargs_meta_inline | |||
@@ -20,6 +20,7 @@ class ExpandSingleChild: | |||
else: | |||
return self.node_builder(children) | |||
class PropagatePositions: | |||
def __init__(self, node_builder): | |||
self.node_builder = node_builder | |||
@@ -87,8 +88,9 @@ class ChildFilter: | |||
return self.node_builder(filtered) | |||
class ChildFilterLALR(ChildFilter): | |||
"Optimized childfilter for LALR (assumes no duplication in parse tree, so it's safe to change it)" | |||
"""Optimized childfilter for LALR (assumes no duplication in parse tree, so it's safe to change it)""" | |||
def __call__(self, children): | |||
filtered = [] | |||
@@ -108,6 +110,7 @@ class ChildFilterLALR(ChildFilter): | |||
return self.node_builder(filtered) | |||
class ChildFilterLALR_NoPlaceholders(ChildFilter): | |||
"Optimized childfilter for LALR (assumes no duplication in parse tree, so it's safe to change it)" | |||
def __init__(self, to_include, node_builder): | |||
@@ -126,9 +129,11 @@ class ChildFilterLALR_NoPlaceholders(ChildFilter): | |||
filtered.append(children[i]) | |||
return self.node_builder(filtered) | |||
def _should_expand(sym): | |||
return not sym.is_term and sym.name.startswith('_') | |||
def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indices): | |||
# Prepare empty_indices as: How many Nones to insert at each index? | |||
if _empty_indices: | |||
@@ -156,21 +161,22 @@ def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indi | |||
# LALR without placeholders | |||
return partial(ChildFilterLALR_NoPlaceholders, [(i, x) for i,x,_ in to_include]) | |||
class AmbiguousExpander: | |||
"""Deal with the case where we're expanding children ('_rule') into a parent but the children | |||
are ambiguous. i.e. (parent->_ambig->_expand_this_rule). In this case, make the parent itself | |||
ambiguous with as many copies as their are ambiguous children, and then copy the ambiguous children | |||
into the right parents in the right places, essentially shifting the ambiguiuty up the tree.""" | |||
into the right parents in the right places, essentially shifting the ambiguity up the tree.""" | |||
def __init__(self, to_expand, tree_class, node_builder): | |||
self.node_builder = node_builder | |||
self.tree_class = tree_class | |||
self.to_expand = to_expand | |||
def __call__(self, children): | |||
def _is_ambig_tree(child): | |||
return hasattr(child, 'data') and child.data == '_ambig' | |||
def _is_ambig_tree(t): | |||
return hasattr(t, 'data') and t.data == '_ambig' | |||
#### When we're repeatedly expanding ambiguities we can end up with nested ambiguities. | |||
# -- When we're repeatedly expanding ambiguities we can end up with nested ambiguities. | |||
# All children of an _ambig node should be a derivation of that ambig node, hence | |||
# it is safe to assume that if we see an _ambig node nested within an ambig node | |||
# it is safe to simply expand it into the parent _ambig node as an alternative derivation. | |||
@@ -186,15 +192,17 @@ class AmbiguousExpander: | |||
if not ambiguous: | |||
return self.node_builder(children) | |||
expand = [ iter(child.children) if i in ambiguous else repeat(child) for i, child in enumerate(children) ] | |||
expand = [iter(child.children) if i in ambiguous else repeat(child) for i, child in enumerate(children)] | |||
return self.tree_class('_ambig', [self.node_builder(list(f[0])) for f in product(zip(*expand))]) | |||
def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): | |||
to_expand = [i for i, sym in enumerate(expansion) | |||
if keep_all_tokens or ((not (sym.is_term and sym.filter_out)) and _should_expand(sym))] | |||
if to_expand: | |||
return partial(AmbiguousExpander, to_expand, tree_class) | |||
class AmbiguousIntermediateExpander: | |||
""" | |||
Propagate ambiguous intermediate nodes and their derivations up to the | |||
@@ -275,12 +283,14 @@ class AmbiguousIntermediateExpander: | |||
return self.node_builder(children) | |||
def ptb_inline_args(func): | |||
@wraps(func) | |||
def f(children): | |||
return func(*children) | |||
return f | |||
def inplace_transformer(func): | |||
@wraps(func) | |||
def f(children): | |||
@@ -289,9 +299,11 @@ def inplace_transformer(func): | |||
return func(tree) | |||
return f | |||
def apply_visit_wrapper(func, name, wrapper): | |||
if wrapper is _vargs_meta or wrapper is _vargs_meta_inline: | |||
raise NotImplementedError("Meta args not supported for internal transformer") | |||
@wraps(func) | |||
def f(children): | |||
return wrapper(func, name, children, None) | |||
@@ -323,7 +335,6 @@ class ParseTreeBuilder: | |||
yield rule, wrapper_chain | |||
def create_callback(self, transformer=None): | |||
callbacks = {} | |||
@@ -1,12 +1,11 @@ | |||
from .exceptions import ConfigurationError, GrammarError, assert_config | |||
from .utils import get_regexp_width, Serialize | |||
from .parsers.grammar_analysis import GrammarAnalyzer | |||
from .lexer import LexerThread, TraditionalLexer, ContextualLexer, Lexer, Token, TerminalDef | |||
from .parsers import earley, xearley, cyk | |||
from .parsers.lalr_parser import LALR_Parser | |||
from .grammar import Rule | |||
from .tree import Tree | |||
from .common import LexerConf | |||
from .exceptions import UnexpectedInput | |||
from .common import LexerConf, ParserConf | |||
try: | |||
import regex | |||
except ImportError: | |||
@@ -15,63 +14,118 @@ import re | |||
###{standalone | |||
def get_frontend(parser, lexer): | |||
if parser=='lalr': | |||
if lexer is None: | |||
raise ValueError('The LALR parser requires use of a lexer') | |||
elif lexer == 'standard': | |||
return LALR_TraditionalLexer | |||
elif lexer == 'contextual': | |||
return LALR_ContextualLexer | |||
elif issubclass(lexer, Lexer): | |||
class CustomLexerWrapper(Lexer): | |||
def __init__(self, lexer_conf): | |||
self.lexer = lexer(lexer_conf) | |||
def lex(self, lexer_state, parser_state): | |||
return self.lexer.lex(lexer_state.text) | |||
class LALR_CustomLexerWrapper(LALR_CustomLexer): | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
super(LALR_CustomLexerWrapper, self).__init__( | |||
lexer, lexer_conf, parser_conf, options=options) | |||
def init_lexer(self): | |||
future_interface = getattr(lexer, '__future_interface__', False) | |||
if future_interface: | |||
self.lexer = lexer(self.lexer_conf) | |||
else: | |||
self.lexer = CustomLexerWrapper(self.lexer_conf) | |||
return LALR_CustomLexerWrapper | |||
else: | |||
raise ValueError('Unknown lexer: %s' % lexer) | |||
elif parser=='earley': | |||
if lexer=='standard': | |||
return Earley | |||
elif lexer=='dynamic': | |||
return XEarley | |||
elif lexer=='dynamic_complete': | |||
return XEarley_CompleteLex | |||
elif lexer=='contextual': | |||
raise ValueError('The Earley parser does not support the contextual parser') | |||
def _wrap_lexer(lexer_class): | |||
future_interface = getattr(lexer_class, '__future_interface__', False) | |||
if future_interface: | |||
return lexer_class | |||
else: | |||
class CustomLexerWrapper(Lexer): | |||
def __init__(self, lexer_conf): | |||
self.lexer = lexer_class(lexer_conf) | |||
def lex(self, lexer_state, parser_state): | |||
return self.lexer.lex(lexer_state.text) | |||
return CustomLexerWrapper | |||
class MakeParsingFrontend: | |||
def __init__(self, parser_type, lexer_type): | |||
self.parser_type = parser_type | |||
self.lexer_type = lexer_type | |||
def __call__(self, lexer_conf, parser_conf, options): | |||
assert isinstance(lexer_conf, LexerConf) | |||
assert isinstance(parser_conf, ParserConf) | |||
parser_conf.parser_type = self.parser_type | |||
lexer_conf.lexer_type = self.lexer_type | |||
return ParsingFrontend(lexer_conf, parser_conf, options) | |||
@classmethod | |||
def deserialize(cls, data, memo, callbacks, options): | |||
lexer_conf = LexerConf.deserialize(data['lexer_conf'], memo) | |||
parser_conf = ParserConf.deserialize(data['parser_conf'], memo) | |||
parser = LALR_Parser.deserialize(data['parser'], memo, callbacks, options.debug) | |||
parser_conf.callbacks = callbacks | |||
terminals = [item for item in memo.values() if isinstance(item, TerminalDef)] | |||
lexer_conf.callbacks = _get_lexer_callbacks(options.transformer, terminals) | |||
lexer_conf.re_module = regex if options.regex else re | |||
lexer_conf.use_bytes = options.use_bytes | |||
lexer_conf.g_regex_flags = options.g_regex_flags | |||
lexer_conf.skip_validation = True | |||
lexer_conf.postlex = options.postlex | |||
return ParsingFrontend(lexer_conf, parser_conf, options, parser=parser) | |||
class ParsingFrontend(Serialize): | |||
__serialize_fields__ = 'lexer_conf', 'parser_conf', 'parser', 'options' | |||
def __init__(self, lexer_conf, parser_conf, options, parser=None): | |||
self.parser_conf = parser_conf | |||
self.lexer_conf = lexer_conf | |||
self.options = options | |||
# Set-up parser | |||
if parser: # From cache | |||
self.parser = parser | |||
else: | |||
raise ValueError('Unknown lexer: %s' % lexer) | |||
elif parser == 'cyk': | |||
if lexer == 'standard': | |||
return CYK | |||
create_parser = { | |||
'lalr': create_lalr_parser, | |||
'earley': create_earley_parser, | |||
'cyk': CYK_FrontEnd, | |||
}[parser_conf.parser_type] | |||
self.parser = create_parser(lexer_conf, parser_conf, options) | |||
# Set-up lexer | |||
lexer_type = lexer_conf.lexer_type | |||
self.skip_lexer = False | |||
if lexer_type in ('dynamic', 'dynamic_complete'): | |||
self.skip_lexer = True | |||
return | |||
try: | |||
create_lexer = { | |||
'standard': create_traditional_lexer, | |||
'contextual': create_contextual_lexer, | |||
}[lexer_type] | |||
except KeyError: | |||
assert issubclass(lexer_type, Lexer), lexer_type | |||
self.lexer = _wrap_lexer(lexer_type)(lexer_conf) | |||
else: | |||
raise ValueError('CYK parser requires using standard parser.') | |||
else: | |||
raise ValueError('Unknown parser: %s' % parser) | |||
self.lexer = create_lexer(lexer_conf, self.parser, lexer_conf.postlex) | |||
if lexer_conf.postlex: | |||
self.lexer = PostLexConnector(self.lexer, lexer_conf.postlex) | |||
class _ParserFrontend(Serialize): | |||
def _parse(self, start, input, *args): | |||
def parse(self, text, start=None): | |||
if start is None: | |||
start = self.start | |||
start = self.parser_conf.start | |||
if len(start) > 1: | |||
raise ValueError("Lark initialized with more than 1 possible start rule. Must specify which start rule to parse", start) | |||
raise ConfigurationError("Lark initialized with more than 1 possible start rule. Must specify which start rule to parse", start) | |||
start ,= start | |||
return self.parser.parse(input, start, *args) | |||
if self.skip_lexer: | |||
return self.parser.parse(text, start) | |||
lexer_thread = LexerThread(self.lexer, text) | |||
return self.parser.parse(lexer_thread, start) | |||
def get_frontend(parser, lexer): | |||
assert_config(parser, ('lalr', 'earley', 'cyk')) | |||
if not isinstance(lexer, type): # not custom lexer? | |||
expected = { | |||
'lalr': ('standard', 'contextual'), | |||
'earley': ('standard', 'dynamic', 'dynamic_complete'), | |||
'cyk': ('standard', ), | |||
}[parser] | |||
assert_config(lexer, expected, 'Parser %r does not support lexer %%r, expected one of %%s' % parser) | |||
return MakeParsingFrontend(parser, lexer) | |||
def _get_lexer_callbacks(transformer, terminals): | |||
@@ -95,174 +149,86 @@ class PostLexConnector: | |||
return self.postlexer.process(i) | |||
class WithLexer(_ParserFrontend): | |||
lexer = None | |||
parser = None | |||
lexer_conf = None | |||
start = None | |||
__serialize_fields__ = 'parser', 'lexer_conf', 'start' | |||
__serialize_namespace__ = LexerConf, | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
self.lexer_conf = lexer_conf | |||
self.start = parser_conf.start | |||
self.postlex = lexer_conf.postlex | |||
@classmethod | |||
def deserialize(cls, data, memo, callbacks, options): | |||
inst = super(WithLexer, cls).deserialize(data, memo) | |||
inst.postlex = options.postlex | |||
inst.parser = LALR_Parser.deserialize(inst.parser, memo, callbacks, options.debug) | |||
terminals = [item for item in memo.values() if isinstance(item, TerminalDef)] | |||
inst.lexer_conf.callbacks = _get_lexer_callbacks(options.transformer, terminals) | |||
inst.lexer_conf.re_module = regex if options.regex else re | |||
inst.lexer_conf.use_bytes = options.use_bytes | |||
inst.lexer_conf.g_regex_flags = options.g_regex_flags | |||
inst.lexer_conf.skip_validation = True | |||
inst.init_lexer() | |||
return inst | |||
def _serialize(self, data, memo): | |||
data['parser'] = data['parser'].serialize(memo) | |||
def make_lexer(self, text): | |||
lexer = self.lexer | |||
if self.postlex: | |||
lexer = PostLexConnector(self.lexer, self.postlex) | |||
return LexerThread(lexer, text) | |||
def create_traditional_lexer(lexer_conf, parser, postlex): | |||
return TraditionalLexer(lexer_conf) | |||
def parse(self, text, start=None): | |||
try: | |||
return self._parse(start, self.make_lexer(text)) | |||
except UnexpectedInput as e: | |||
if e._all_terminals is None: | |||
e._all_terminals = self.lexer_conf.terminals | |||
raise e | |||
def init_traditional_lexer(self): | |||
self.lexer = TraditionalLexer(self.lexer_conf) | |||
class LALR_WithLexer(WithLexer): | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
debug = options.debug if options else False | |||
self.parser = LALR_Parser(parser_conf, debug=debug) | |||
WithLexer.__init__(self, lexer_conf, parser_conf, options) | |||
self.init_lexer() | |||
def create_contextual_lexer(lexer_conf, parser, postlex): | |||
states = {idx:list(t.keys()) for idx, t in parser._parse_table.states.items()} | |||
always_accept = postlex.always_accept if postlex else () | |||
return ContextualLexer(lexer_conf, states, always_accept=always_accept) | |||
def init_lexer(self, **kw): | |||
raise NotImplementedError() | |||
def create_lalr_parser(lexer_conf, parser_conf, options=None): | |||
debug = options.debug if options else False | |||
return LALR_Parser(parser_conf, debug=debug) | |||
class LALR_TraditionalLexer(LALR_WithLexer): | |||
def init_lexer(self): | |||
self.init_traditional_lexer() | |||
class LALR_ContextualLexer(LALR_WithLexer): | |||
def init_lexer(self): | |||
states = {idx:list(t.keys()) for idx, t in self.parser._parse_table.states.items()} | |||
always_accept = self.postlex.always_accept if self.postlex else () | |||
self.lexer = ContextualLexer(self.lexer_conf, states, always_accept=always_accept) | |||
create_earley_parser = NotImplemented | |||
CYK_FrontEnd = NotImplemented | |||
###} | |||
class LALR_CustomLexer(LALR_WithLexer): | |||
def __init__(self, lexer_cls, lexer_conf, parser_conf, options=None): | |||
self.lexer = lexer_cls(lexer_conf) | |||
debug = options.debug if options else False | |||
self.parser = LALR_Parser(parser_conf, debug=debug) | |||
WithLexer.__init__(self, lexer_conf, parser_conf, options) | |||
class Earley(WithLexer): | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
WithLexer.__init__(self, lexer_conf, parser_conf, options) | |||
self.init_traditional_lexer() | |||
resolve_ambiguity = options.ambiguity == 'resolve' | |||
debug = options.debug if options else False | |||
tree_class = options.tree_class or Tree if options.ambiguity != 'forest' else None | |||
self.parser = earley.Parser(parser_conf, self.match, resolve_ambiguity=resolve_ambiguity, debug=debug, tree_class=tree_class) | |||
def make_lexer(self, text): | |||
return WithLexer.make_lexer(self, text).lex(None) | |||
def match(self, term, token): | |||
return term.name == token.type | |||
class XEarley(_ParserFrontend): | |||
def __init__(self, lexer_conf, parser_conf, options=None, **kw): | |||
self.terminals_by_name = {t.name:t for t in lexer_conf.terminals} | |||
self.start = parser_conf.start | |||
self._prepare_match(lexer_conf) | |||
resolve_ambiguity = options.ambiguity == 'resolve' | |||
debug = options.debug if options else False | |||
tree_class = options.tree_class or Tree if options.ambiguity != 'forest' else None | |||
self.parser = xearley.Parser(parser_conf, | |||
self.match, | |||
ignore=lexer_conf.ignore, | |||
resolve_ambiguity=resolve_ambiguity, | |||
debug=debug, | |||
tree_class=tree_class, | |||
**kw | |||
) | |||
def match(self, term, text, index=0): | |||
return self.regexps[term.name].match(text, index) | |||
def _prepare_match(self, lexer_conf): | |||
class EarleyRegexpMatcher: | |||
def __init__(self, lexer_conf): | |||
self.regexps = {} | |||
for t in lexer_conf.terminals: | |||
if t.priority != 1: | |||
raise ValueError("Dynamic Earley doesn't support weights on terminals", t, t.priority) | |||
raise GrammarError("Dynamic Earley doesn't support weights on terminals", t, t.priority) | |||
regexp = t.pattern.to_regexp() | |||
try: | |||
width = get_regexp_width(regexp)[0] | |||
except ValueError: | |||
raise ValueError("Bad regexp in token %s: %s" % (t.name, regexp)) | |||
raise GrammarError("Bad regexp in token %s: %s" % (t.name, regexp)) | |||
else: | |||
if width == 0: | |||
raise ValueError("Dynamic Earley doesn't allow zero-width regexps", t) | |||
raise GrammarError("Dynamic Earley doesn't allow zero-width regexps", t) | |||
if lexer_conf.use_bytes: | |||
regexp = regexp.encode('utf-8') | |||
self.regexps[t.name] = lexer_conf.re_module.compile(regexp, lexer_conf.g_regex_flags) | |||
def parse(self, text, start): | |||
try: | |||
return self._parse(start, text) | |||
except UnexpectedInput as e: | |||
if e._all_terminals is None: | |||
e._all_terminals = self.terminals_by_name | |||
raise e | |||
def match(self, term, text, index=0): | |||
return self.regexps[term.name].match(text, index) | |||
class XEarley_CompleteLex(XEarley): | |||
def __init__(self, *args, **kw): | |||
XEarley.__init__(self, *args, complete_lex=True, **kw) | |||
def create_earley_parser__dynamic(lexer_conf, parser_conf, options=None, **kw): | |||
earley_matcher = EarleyRegexpMatcher(lexer_conf) | |||
return xearley.Parser(parser_conf, earley_matcher.match, ignore=lexer_conf.ignore, **kw) | |||
def _match_earley_basic(term, token): | |||
return term.name == token.type | |||
class CYK(WithLexer): | |||
def create_earley_parser__basic(lexer_conf, parser_conf, options, **kw): | |||
return earley.Parser(parser_conf, _match_earley_basic, **kw) | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
WithLexer.__init__(self, lexer_conf, parser_conf, options) | |||
self.init_traditional_lexer() | |||
def create_earley_parser(lexer_conf, parser_conf, options): | |||
resolve_ambiguity = options.ambiguity == 'resolve' | |||
debug = options.debug if options else False | |||
tree_class = options.tree_class or Tree if options.ambiguity != 'forest' else None | |||
extra = {} | |||
if lexer_conf.lexer_type == 'dynamic': | |||
f = create_earley_parser__dynamic | |||
elif lexer_conf.lexer_type == 'dynamic_complete': | |||
extra['complete_lex'] =True | |||
f = create_earley_parser__dynamic | |||
else: | |||
f = create_earley_parser__basic | |||
return f(lexer_conf, parser_conf, options, resolve_ambiguity=resolve_ambiguity, debug=debug, tree_class=tree_class, **extra) | |||
class CYK_FrontEnd: | |||
def __init__(self, lexer_conf, parser_conf, options=None): | |||
self._analysis = GrammarAnalyzer(parser_conf) | |||
self.parser = cyk.Parser(parser_conf.rules) | |||
self.callbacks = parser_conf.callbacks | |||
def parse(self, text, start): | |||
tokens = list(self.make_lexer(text).lex(None)) | |||
parse = self._parse(start, tokens) | |||
parse = self._transform(parse) | |||
return parse | |||
def parse(self, lexer_thread, start): | |||
tokens = list(lexer_thread.lex(None)) | |||
tree = self.parser.parse(tokens, start) | |||
return self._transform(tree) | |||
def _transform(self, tree): | |||
subtrees = list(tree.iter_subtrees()) | |||
@@ -1,4 +1,4 @@ | |||
"""This module implements an scanerless Earley parser. | |||
"""This module implements an Earley parser. | |||
The core Earley algorithm used here is based on Elizabeth Scott's implementation, here: | |||
https://www.sciencedirect.com/science/article/pii/S1571066108001497 | |||
@@ -6,8 +6,7 @@ The core Earley algorithm used here is based on Elizabeth Scott's implementation | |||
That is probably the best reference for understanding the algorithm here. | |||
The Earley parser outputs an SPPF-tree as per that document. The SPPF tree format | |||
is better documented here: | |||
http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/ | |||
is explained here: https://lark-parser.readthedocs.io/en/latest/_static/sppf/sppf.html | |||
""" | |||
from collections import deque | |||
@@ -147,7 +146,7 @@ class Parser: | |||
column.add(new_item) | |||
items.append(new_item) | |||
def _parse(self, stream, columns, to_scan, start_symbol=None): | |||
def _parse(self, lexer, columns, to_scan, start_symbol=None): | |||
def is_quasi_complete(item): | |||
if item.is_complete: | |||
return True | |||
@@ -246,7 +245,7 @@ class Parser: | |||
if not next_set and not next_to_scan: | |||
expect = {i.expect.name for i in to_scan} | |||
raise UnexpectedToken(token, expect, considered_rules = set(to_scan)) | |||
raise UnexpectedToken(token, expect, considered_rules=set(to_scan), state=frozenset(i.s for i in to_scan)) | |||
return next_to_scan | |||
@@ -262,20 +261,24 @@ class Parser: | |||
# Completions will be added to the SPPF tree, and predictions will be recursively | |||
# processed down to terminals/empty nodes to be added to the scanner for the next | |||
# step. | |||
expects = {i.expect for i in to_scan} | |||
i = 0 | |||
for token in stream: | |||
for token in lexer.lex(expects): | |||
self.predict_and_complete(i, to_scan, columns, transitives) | |||
to_scan = scan(i, token, to_scan) | |||
i += 1 | |||
expects.clear() | |||
expects |= {i.expect for i in to_scan} | |||
self.predict_and_complete(i, to_scan, columns, transitives) | |||
## Column is now the final column in the parse. | |||
assert i == len(columns)-1 | |||
return to_scan | |||
def parse(self, stream, start): | |||
def parse(self, lexer, start): | |||
assert start, start | |||
start_symbol = NonTerminal(start) | |||
@@ -292,12 +295,16 @@ class Parser: | |||
else: | |||
columns[0].add(item) | |||
to_scan = self._parse(stream, columns, to_scan, start_symbol) | |||
to_scan = self._parse(lexer, columns, to_scan, start_symbol) | |||
# If the parse was successful, the start | |||
# symbol should have been completed in the last step of the Earley cycle, and will be in | |||
# this column. Find the item for the start_symbol, which is the root of the SPPF tree. | |||
solutions = [n.node for n in columns[-1] if n.is_complete and n.node is not None and n.s == start_symbol and n.start == 0] | |||
if not solutions: | |||
expected_terminals = [t.expect for t in to_scan] | |||
raise UnexpectedEOF(expected_terminals, state=frozenset(i.s for i in to_scan)) | |||
if self.debug: | |||
from .earley_forest import ForestToPyDotVisitor | |||
try: | |||
@@ -308,10 +315,7 @@ class Parser: | |||
debug_walker.visit(solutions[0], "sppf.png") | |||
if not solutions: | |||
expected_tokens = [t.expect for t in to_scan] | |||
raise UnexpectedEOF(expected_tokens) | |||
elif len(solutions) > 1: | |||
if len(solutions) > 1: | |||
assert False, 'Earley should not generate multiple start symbol items!' | |||
if self.tree_class is not None: | |||
@@ -459,15 +459,20 @@ class PackedData(): | |||
that comes from the left child and the right child. | |||
""" | |||
class _NoData(): | |||
pass | |||
NO_DATA = _NoData() | |||
def __init__(self, node, data): | |||
self.left = None | |||
self.right = None | |||
self.left = self.NO_DATA | |||
self.right = self.NO_DATA | |||
if data: | |||
if node.left: | |||
if node.left is not None: | |||
self.left = data[0] | |||
if len(data) > 1 and node.right: | |||
if len(data) > 1: | |||
self.right = data[1] | |||
elif node.right: | |||
else: | |||
self.right = data[0] | |||
class ForestToParseTree(ForestTransformer): | |||
@@ -490,19 +495,22 @@ class ForestToParseTree(ForestTransformer): | |||
self.prioritizer = prioritizer | |||
self.resolve_ambiguity = resolve_ambiguity | |||
self._on_cycle_retreat = False | |||
self._cycle_node = None | |||
self._successful_visits = set() | |||
def on_cycle(self, node, path): | |||
logger.warning("Cycle encountered in the SPPF at node: %s. " | |||
logger.debug("Cycle encountered in the SPPF at node: %s. " | |||
"As infinite ambiguities cannot be represented in a tree, " | |||
"this family of derivations will be discarded.", node) | |||
if self.resolve_ambiguity: | |||
# TODO: choose a different path if cycle is encountered | |||
logger.warning("At this time, using ambiguity resolution for SPPFs " | |||
"with cycles may result in None being returned.") | |||
self._cycle_node = node | |||
self._on_cycle_retreat = True | |||
def _check_cycle(self, node): | |||
if self._on_cycle_retreat: | |||
if id(node) == id(self._cycle_node): | |||
self._cycle_node = None | |||
self._on_cycle_retreat = False | |||
return | |||
raise Discard() | |||
def _collapse_ambig(self, children): | |||
@@ -531,11 +539,17 @@ class ForestToParseTree(ForestTransformer): | |||
raise Discard() | |||
def transform_symbol_node(self, node, data): | |||
if id(node) not in self._successful_visits: | |||
raise Discard() | |||
self._successful_visits.remove(id(node)) | |||
self._check_cycle(node) | |||
data = self._collapse_ambig(data) | |||
return self._call_ambig_func(node, data) | |||
def transform_intermediate_node(self, node, data): | |||
if id(node) not in self._successful_visits: | |||
raise Discard() | |||
self._successful_visits.remove(id(node)) | |||
self._check_cycle(node) | |||
if len(data) > 1: | |||
children = [self.tree_class('_inter', c) for c in data] | |||
@@ -544,36 +558,40 @@ class ForestToParseTree(ForestTransformer): | |||
def transform_packed_node(self, node, data): | |||
self._check_cycle(node) | |||
if self.resolve_ambiguity and id(node.parent) in self._successful_visits: | |||
raise Discard() | |||
children = [] | |||
assert len(data) <= 2 | |||
data = PackedData(node, data) | |||
if data.left is not None: | |||
if data.left is not PackedData.NO_DATA: | |||
if node.left.is_intermediate and isinstance(data.left, list): | |||
children += data.left | |||
else: | |||
children.append(data.left) | |||
if data.right is not None: | |||
if data.right is not PackedData.NO_DATA: | |||
children.append(data.right) | |||
if node.parent.is_intermediate: | |||
return children | |||
return self._call_rule_func(node, children) | |||
def visit_symbol_node_in(self, node): | |||
self._on_cycle_retreat = False | |||
super(ForestToParseTree, self).visit_symbol_node_in(node) | |||
if self._on_cycle_retreat: | |||
return | |||
if self.prioritizer and node.is_ambiguous and isinf(node.priority): | |||
self.prioritizer.visit(node) | |||
if self.resolve_ambiguity: | |||
return node.children[0] | |||
return node.children | |||
def visit_packed_node_in(self, node): | |||
self._on_cycle_retreat = False | |||
return super(ForestToParseTree, self).visit_packed_node_in(node) | |||
to_visit = super(ForestToParseTree, self).visit_packed_node_in(node) | |||
if not self.resolve_ambiguity or id(node.parent) not in self._successful_visits: | |||
return to_visit | |||
def visit_token_node(self, node): | |||
self._on_cycle_retreat = False | |||
return super(ForestToParseTree, self).visit_token_node(node) | |||
def visit_packed_node_out(self, node): | |||
super(ForestToParseTree, self).visit_packed_node_out(node) | |||
if not self._on_cycle_retreat: | |||
self._successful_visits.add(id(node.parent)) | |||
def handles_ambiguity(func): | |||
"""Decorator for methods of subclasses of ``TreeForestTransformer``. | |||
@@ -679,7 +697,10 @@ class ForestToPyDotVisitor(ForestVisitor): | |||
def visit(self, root, filename): | |||
super(ForestToPyDotVisitor, self).visit(root) | |||
self.graph.write_png(filename) | |||
try: | |||
self.graph.write_png(filename) | |||
except FileNotFoundError as e: | |||
logger.error("Could not write png: ", e) | |||
def visit_token_node(self, node): | |||
graph_node_id = str(id(node)) | |||
@@ -3,15 +3,16 @@ | |||
# Author: Erez Shinan (2017) | |||
# Email : erezshin@gmail.com | |||
from copy import deepcopy, copy | |||
from ..exceptions import UnexpectedCharacters, UnexpectedInput, UnexpectedToken | |||
from ..exceptions import UnexpectedInput, UnexpectedToken | |||
from ..lexer import Token | |||
from ..utils import Serialize | |||
from .lalr_analysis import LALR_Analyzer, Shift, Reduce, IntParseTable | |||
from .lalr_puppet import ParserPuppet | |||
###{standalone | |||
class LALR_Parser(object): | |||
class LALR_Parser(Serialize): | |||
def __init__(self, parser_conf, debug=False): | |||
analysis = LALR_Analyzer(parser_conf, debug=debug) | |||
analysis.compute_lalr() | |||
@@ -62,6 +63,12 @@ class ParserState(object): | |||
def position(self): | |||
return self.state_stack[-1] | |||
# Necessary for match_examples() to work | |||
def __eq__(self, other): | |||
if not isinstance(other, ParserState): | |||
return False | |||
return self.position == other.position | |||
def __copy__(self): | |||
return type(self)( | |||
self.parse_conf, | |||
@@ -86,7 +93,7 @@ class ParserState(object): | |||
action, arg = states[state][token.type] | |||
except KeyError: | |||
expected = {s for s in states[state].keys() if s.isupper()} | |||
raise UnexpectedToken(token, expected, state=state, puppet=None) | |||
raise UnexpectedToken(token, expected, state=self, puppet=None) | |||
assert arg != end_state | |||
@@ -95,7 +102,7 @@ class ParserState(object): | |||
assert not is_end | |||
state_stack.append(arg) | |||
value_stack.append(token) | |||
return arg | |||
return | |||
else: | |||
# reduce+shift as many times as necessary | |||
rule = arg | |||
@@ -22,7 +22,7 @@ class ParserPuppet(object): | |||
Note that ``token`` has to be an instance of ``Token``. | |||
""" | |||
return self.parser_state.feed_token(token) | |||
return self.parser_state.feed_token(token, token.type == '$END') | |||
def __copy__(self): | |||
"""Create a new puppet with a separate state. | |||
@@ -35,15 +35,18 @@ class ParserPuppet(object): | |||
copy(self.lexer_state), | |||
) | |||
def copy(self): | |||
return copy(self) | |||
def __eq__(self, other): | |||
if not isinstance(other, ParserPuppet): | |||
return False | |||
return self.parser_state == other.parser_state and self.lexer_state == other.lexer_state | |||
# TODO Provide with an immutable puppet instance | |||
# def __hash__(self): | |||
# return hash((self.parser_state, self.lexer_state)) | |||
def as_immutable(self): | |||
p = copy(self) | |||
return ImmutableParserPuppet(p.parser, p.parser_state, p.lexer_state) | |||
def pretty(self): | |||
"""Print the output of ``choices()`` in a way that's easier to read.""" | |||
@@ -78,3 +81,16 @@ class ParserPuppet(object): | |||
def resume_parse(self): | |||
"""Resume parsing from the current puppet state.""" | |||
return self.parser.parse_from_state(self.parser_state) | |||
class ImmutableParserPuppet(ParserPuppet): | |||
result = None | |||
def __hash__(self): | |||
return hash((self.parser_state, self.lexer_state)) | |||
def feed_token(self, token): | |||
c = copy(self) | |||
c.result = ParserPuppet.feed_token(c, token) | |||
return c |
@@ -63,9 +63,10 @@ class Parser(BaseParser): | |||
t = Token(item.expect.name, m.group(0), i, text_line, text_column) | |||
delayed_matches[i+m.end()].append( (item, i, t) ) | |||
# Remove any items that successfully matched in this pass from the to_scan buffer. | |||
# This ensures we don't carry over tokens that already matched, if we're ignoring below. | |||
to_scan.remove(item) | |||
# XXX The following 3 lines were commented out for causing a bug. See issue #768 | |||
# # Remove any items that successfully matched in this pass from the to_scan buffer. | |||
# # This ensures we don't carry over tokens that already matched, if we're ignoring below. | |||
# to_scan.remove(item) | |||
# 3) Process any ignores. This is typically used for e.g. whitespace. | |||
# We carry over any unmatched items from the to_scan buffer to be matched again after | |||
@@ -113,7 +114,8 @@ class Parser(BaseParser): | |||
del delayed_matches[i+1] # No longer needed, so unburden memory | |||
if not next_set and not delayed_matches and not next_to_scan: | |||
raise UnexpectedCharacters(stream, i, text_line, text_column, {item.expect.name for item in to_scan}, set(to_scan)) | |||
raise UnexpectedCharacters(stream, i, text_line, text_column, {item.expect.name for item in to_scan}, | |||
set(to_scan), state=frozenset(i.s for i in to_scan)) | |||
return next_to_scan | |||
@@ -35,7 +35,9 @@ nearley_grammar = r""" | |||
COMMENT: /#[^\n]*/ | |||
REGEXP: /\[.*?\]/ | |||
%import common.ESCAPED_STRING -> STRING | |||
STRING: _STRING "i"? | |||
%import common.ESCAPED_STRING -> _STRING | |||
%import common.WS | |||
%ignore WS | |||
%ignore COMMENT | |||
@@ -183,7 +185,7 @@ def main(fn, start, nearley_lib, es6=False): | |||
return create_code_for_nearley_grammar(grammar, start, os.path.join(nearley_lib, 'builtin'), os.path.abspath(os.path.dirname(fn)), es6=es6) | |||
def get_arg_parser(): | |||
parser = argparse.ArgumentParser('Reads Nearley grammar (with js functions) outputs an equivalent lark parser.') | |||
parser = argparse.ArgumentParser(description='Reads a Nearley grammar (with js functions), and outputs an equivalent lark parser.') | |||
parser.add_argument('nearley_grammar', help='Path to the file containing the nearley grammar') | |||
parser.add_argument('start_rule', help='Rule within the nearley grammar to make the base rule') | |||
parser.add_argument('nearley_lib', help='Path to root directory of nearley codebase (used for including builtins)') | |||
@@ -46,14 +46,14 @@ class Tree(object): | |||
def _pretty(self, level, indent_str): | |||
if len(self.children) == 1 and not isinstance(self.children[0], Tree): | |||
return [ indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n'] | |||
return [indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n'] | |||
l = [ indent_str*level, self._pretty_label(), '\n' ] | |||
l = [indent_str*level, self._pretty_label(), '\n'] | |||
for n in self.children: | |||
if isinstance(n, Tree): | |||
l += n._pretty(level+1, indent_str) | |||
else: | |||
l += [ indent_str*(level+1), '%s' % (n,), '\n' ] | |||
l += [indent_str*(level+1), '%s' % (n,), '\n'] | |||
return l | |||
@@ -102,8 +102,8 @@ class Tree(object): | |||
###} | |||
def expand_kids_by_index(self, *indices): | |||
"Expand (inline) children at the given indices" | |||
for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices | |||
"""Expand (inline) children at the given indices""" | |||
for i in sorted(indices, reverse=True): # reverse so that changing tail won't affect indices | |||
kid = self.children[i] | |||
self.children[i:i+1] = kid.children | |||
@@ -144,12 +144,15 @@ class Tree(object): | |||
@property | |||
def line(self): | |||
return self.meta.line | |||
@property | |||
def column(self): | |||
return self.meta.column | |||
@property | |||
def end_line(self): | |||
return self.meta.end_line | |||
@property | |||
def end_column(self): | |||
return self.meta.end_column | |||
@@ -168,6 +171,7 @@ def pydot__tree_to_dot(tree, filename, rankdir="LR", **kwargs): | |||
graph = pydot__tree_to_graph(tree, rankdir, **kwargs) | |||
graph.write(filename) | |||
def pydot__tree_to_graph(tree, rankdir="LR", **kwargs): | |||
"""Creates a colorful image that represents the tree (data+children, without meta) | |||
@@ -196,7 +200,7 @@ def pydot__tree_to_graph(tree, rankdir="LR", **kwargs): | |||
subnodes = [_to_pydot(child) if isinstance(child, Tree) else new_leaf(child) | |||
for child in subtree.children] | |||
node = pydot.Node(i[0], style="filled", fillcolor="#%x"%color, label=subtree.data) | |||
node = pydot.Node(i[0], style="filled", fillcolor="#%x" % color, label=subtree.data) | |||
i[0] += 1 | |||
graph.add_node(node) | |||
@@ -69,6 +69,14 @@ def parse_rulename(s): | |||
return name, args | |||
class ChildrenLexer: | |||
def __init__(self, children): | |||
self.children = children | |||
def lex(self, parser_state): | |||
return self.children | |||
class TreeMatcher: | |||
"""Match the elements of a tree node, based on an ontology | |||
provided by a Lark grammar. | |||
@@ -173,6 +181,6 @@ class TreeMatcher: | |||
self._parser_cache[rulename] = parser | |||
# find a full derivation | |||
unreduced_tree = parser.parse(tree.children, rulename) | |||
unreduced_tree = parser.parse(ChildrenLexer(tree.children), rulename) | |||
assert unreduced_tree.data == rulename | |||
return unreduced_tree |
@@ -1,10 +1,9 @@ | |||
import sys | |||
import os | |||
from functools import reduce | |||
from ast import literal_eval | |||
from collections import deque | |||
###{standalone | |||
import sys, re | |||
import logging | |||
logger = logging.getLogger("lark") | |||
logger.addHandler(logging.StreamHandler()) | |||
@@ -12,6 +11,8 @@ logger.addHandler(logging.StreamHandler()) | |||
# By default, we should not output any log messages | |||
logger.setLevel(logging.CRITICAL) | |||
Py36 = (sys.version_info[:2] >= (3, 6)) | |||
def classify(seq, key=None, value=None): | |||
d = {} | |||
@@ -27,7 +28,7 @@ def classify(seq, key=None, value=None): | |||
def _deserialize(data, namespace, memo): | |||
if isinstance(data, dict): | |||
if '__type__' in data: # Object | |||
if '__type__' in data: # Object | |||
class_ = namespace[data['__type__']] | |||
return class_.deserialize(data, memo) | |||
elif '@' in data: | |||
@@ -105,7 +106,6 @@ class SerializeMemoizer(Serialize): | |||
return _deserialize(data, namespace, memo) | |||
try: | |||
STRING_TYPE = basestring | |||
except NameError: # Python 3 | |||
@@ -118,10 +118,11 @@ from contextlib import contextmanager | |||
Str = type(u'') | |||
try: | |||
classtype = types.ClassType # Python2 | |||
classtype = types.ClassType # Python2 | |||
except AttributeError: | |||
classtype = type # Python3 | |||
def smart_decorator(f, create_decorator): | |||
if isinstance(f, types.FunctionType): | |||
return wraps(f)(create_decorator(f, True)) | |||
@@ -139,17 +140,16 @@ def smart_decorator(f, create_decorator): | |||
else: | |||
return create_decorator(f.__func__.__call__, True) | |||
try: | |||
import regex | |||
except ImportError: | |||
regex = None | |||
import sys, re | |||
Py36 = (sys.version_info[:2] >= (3, 6)) | |||
import sre_parse | |||
import sre_constants | |||
categ_pattern = re.compile(r'\\p{[A-Za-z_]+}') | |||
def get_regexp_width(expr): | |||
if regex: | |||
# Since `sre_parse` cannot deal with Unicode categories of the form `\p{Mn}`, we replace these with | |||
@@ -173,9 +173,7 @@ def dedup_list(l): | |||
preserving the original order of the list. Assumes that | |||
the list entries are hashable.""" | |||
dedup = set() | |||
return [ x for x in l if not (x in dedup or dedup.add(x))] | |||
return [x for x in l if not (x in dedup or dedup.add(x))] | |||
try: | |||
@@ -197,8 +195,6 @@ except ImportError: | |||
pass | |||
try: | |||
compare = cmp | |||
except NameError: | |||
@@ -210,7 +206,6 @@ except NameError: | |||
return -1 | |||
class Enumerator(Serialize): | |||
def __init__(self): | |||
self.enums = {} | |||
@@ -229,31 +224,6 @@ class Enumerator(Serialize): | |||
return r | |||
def eval_escaping(s): | |||
w = '' | |||
i = iter(s) | |||
for n in i: | |||
w += n | |||
if n == '\\': | |||
try: | |||
n2 = next(i) | |||
except StopIteration: | |||
raise ValueError("Literal ended unexpectedly (bad escaping): `%r`" % s) | |||
if n2 == '\\': | |||
w += '\\\\' | |||
elif n2 not in 'uxnftr': | |||
w += '\\' | |||
w += n2 | |||
w = w.replace('\\"', '"').replace("'", "\\'") | |||
to_eval = "u'''%s'''" % w | |||
try: | |||
s = literal_eval(to_eval) | |||
except SyntaxError as e: | |||
raise ValueError(s, e) | |||
return s | |||
def combine_alternatives(lists): | |||
""" | |||
@@ -332,4 +302,5 @@ def _serialize(value, memo): | |||
return list(value) # TODO reversible? | |||
elif isinstance(value, dict): | |||
return {key:_serialize(elem, memo) for key, elem in value.items()} | |||
# assert value is None or isinstance(value, (int, float, str, tuple)), value | |||
return value |
@@ -8,6 +8,7 @@ from .lexer import Token | |||
###{standalone | |||
from inspect import getmembers, getmro | |||
class Discard(Exception): | |||
"""When raising the Discard exception in a transformer callback, | |||
that node is discarded and won't appear in the parent. | |||
@@ -16,6 +17,7 @@ class Discard(Exception): | |||
# Transformers | |||
class _Decoratable: | |||
"Provides support for decorating methods with @v_args" | |||
@@ -47,7 +49,7 @@ class _Decoratable: | |||
class Transformer(_Decoratable): | |||
"""Transformers visit each node of the tree, and run the appropriate method on it according to the node's data. | |||
Calls its methods (provided by user via inheritance) according to ``tree.data``. | |||
Calls its methods (provided by the user via inheritance) according to ``tree.data``. | |||
The returned value replaces the old one in the structure. | |||
They work bottom-up (or depth-first), starting with the leaves and ending at the root of the tree. | |||
@@ -64,12 +66,11 @@ class Transformer(_Decoratable): | |||
- ``Transformer_InPlaceRecursive`` - Recursive. Changes the tree in-place instead of returning new instances | |||
Parameters: | |||
visit_tokens: By default, transformers only visit rules. | |||
visit_tokens=True will tell ``Transformer`` to visit tokens | |||
as well. This is a slightly slower alternative to lexer_callbacks | |||
but it's easier to maintain and works for all algorithms | |||
(even when there isn't a lexer). | |||
visit_tokens (bool, optional): Should the transformer visit tokens in addition to rules. | |||
Setting this to ``False`` is slightly faster. Defaults to ``True``. | |||
(For processing ignored tokens, use the ``lexer_callbacks`` options) | |||
NOTE: A transformer without methods essentially performs a non-memoized deepcopy. | |||
""" | |||
__visit_tokens__ = True # For backwards compatibility | |||
@@ -108,7 +109,6 @@ class Transformer(_Decoratable): | |||
except Exception as e: | |||
raise VisitError(token.type, token, e) | |||
def _transform_children(self, children): | |||
for c in children: | |||
try: | |||
@@ -126,29 +126,29 @@ class Transformer(_Decoratable): | |||
return self._call_userfunc(tree, children) | |||
def transform(self, tree): | |||
"Transform the given tree, and return the final result" | |||
return self._transform_tree(tree) | |||
def __mul__(self, other): | |||
"""Chain two transformers together, returning a new transformer. | |||
""" | |||
return TransformerChain(self, other) | |||
def __default__(self, data, children, meta): | |||
"""Default operation on tree (for override) | |||
"""Default function that is called if there is no attribute matching ``data`` | |||
Function that is called on if a function with a corresponding name has not been found. | |||
Defaults to reconstruct the Tree. | |||
Can be overridden. Defaults to creating a new copy of the tree node (i.e. ``return Tree(data, children, meta)``) | |||
""" | |||
return Tree(data, children, meta) | |||
def __default_token__(self, token): | |||
"""Default operation on token (for override) | |||
"""Default function that is called if there is no attribute matching ``token.type`` | |||
Function that is called on if a function with a corresponding name has not been found. | |||
Defaults to just return the argument. | |||
Can be overridden. Defaults to returning the token as-is. | |||
""" | |||
return token | |||
class InlineTransformer(Transformer): # XXX Deprecated | |||
def _call_userfunc(self, tree, new_children=None): | |||
# Assumes tree is already transformed | |||
@@ -175,7 +175,10 @@ class TransformerChain(object): | |||
class Transformer_InPlace(Transformer): | |||
"Non-recursive. Changes the tree in-place instead of returning new instances" | |||
"""Same as Transformer, but non-recursive, and changes the tree in-place instead of returning new instances | |||
Useful for huge trees. Conservative in memory. | |||
""" | |||
def _transform_tree(self, tree): # Cancel recursion | |||
return self._call_userfunc(tree) | |||
@@ -187,7 +190,12 @@ class Transformer_InPlace(Transformer): | |||
class Transformer_NonRecursive(Transformer): | |||
"Non-recursive. Doesn't change the original tree." | |||
"""Same as Transformer but non-recursive. | |||
Like Transformer, it doesn't change the original tree. | |||
Useful for huge trees. | |||
""" | |||
def transform(self, tree): | |||
# Tree to postfix | |||
@@ -195,7 +203,7 @@ class Transformer_NonRecursive(Transformer): | |||
q = [tree] | |||
while q: | |||
t = q.pop() | |||
rev_postfix.append( t ) | |||
rev_postfix.append(t) | |||
if isinstance(t, Tree): | |||
q += t.children | |||
@@ -217,15 +225,13 @@ class Transformer_NonRecursive(Transformer): | |||
return t | |||
class Transformer_InPlaceRecursive(Transformer): | |||
"Recursive. Changes the tree in-place instead of returning new instances" | |||
"Same as Transformer, recursive, but changes the tree in-place instead of returning new instances" | |||
def _transform_tree(self, tree): | |||
tree.children = list(self._transform_children(tree.children)) | |||
return self._call_userfunc(tree) | |||
# Visitors | |||
class VisitorBase: | |||
@@ -233,7 +239,10 @@ class VisitorBase: | |||
return getattr(self, tree.data, self.__default__)(tree) | |||
def __default__(self, tree): | |||
"Default operation on tree (for override)" | |||
"""Default function that is called if there is no attribute matching ``tree.data`` | |||
Can be overridden. Defaults to doing nothing. | |||
""" | |||
return tree | |||
def __class_getitem__(cls, _): | |||
@@ -241,18 +250,19 @@ class VisitorBase: | |||
class Visitor(VisitorBase): | |||
"""Bottom-up visitor, non-recursive. | |||
"""Tree visitor, non-recursive (can handle huge trees). | |||
Visits the tree, starting with the leaves and finally the root (bottom-up) | |||
Calls its methods (provided by user via inheritance) according to ``tree.data`` | |||
Visiting a node calls its methods (provided by the user via inheritance) according to ``tree.data`` | |||
""" | |||
def visit(self, tree): | |||
"Visits the tree, starting with the leaves and finally the root (bottom-up)" | |||
for subtree in tree.iter_subtrees(): | |||
self._call_userfunc(subtree) | |||
return tree | |||
def visit_topdown(self,tree): | |||
"Visit the tree, starting at the root, and ending at the leaves (top-down)" | |||
for subtree in tree.iter_subtrees_topdown(): | |||
self._call_userfunc(subtree) | |||
return tree | |||
@@ -261,11 +271,13 @@ class Visitor(VisitorBase): | |||
class Visitor_Recursive(VisitorBase): | |||
"""Bottom-up visitor, recursive. | |||
Visits the tree, starting with the leaves and finally the root (bottom-up) | |||
Calls its methods (provided by user via inheritance) according to ``tree.data`` | |||
Visiting a node calls its methods (provided by the user via inheritance) according to ``tree.data`` | |||
Slightly faster than the non-recursive version. | |||
""" | |||
def visit(self, tree): | |||
"Visits the tree, starting with the leaves and finally the root (bottom-up)" | |||
for child in tree.children: | |||
if isinstance(child, Tree): | |||
self.visit(child) | |||
@@ -274,6 +286,7 @@ class Visitor_Recursive(VisitorBase): | |||
return tree | |||
def visit_topdown(self,tree): | |||
"Visit the tree, starting at the root, and ending at the leaves (top-down)" | |||
self._call_userfunc(tree) | |||
for child in tree.children: | |||
@@ -283,7 +296,6 @@ class Visitor_Recursive(VisitorBase): | |||
return tree | |||
def visit_children_decor(func): | |||
"See Interpreter" | |||
@wraps(func) | |||
@@ -324,8 +336,6 @@ class Interpreter(_Decoratable): | |||
return self.visit_children(tree) | |||
# Decorators | |||
def _apply_decorator(obj, decorator, **kwargs): | |||
@@ -337,7 +347,6 @@ def _apply_decorator(obj, decorator, **kwargs): | |||
return _apply(decorator, **kwargs) | |||
def _inline_args__func(func): | |||
@wraps(func) | |||
def create_decorator(_f, with_self): | |||
@@ -356,7 +365,6 @@ def inline_args(obj): # XXX Deprecated | |||
return _apply_decorator(obj, _inline_args__func) | |||
def _visitor_args_func_dec(func, visit_wrapper=None, static=False): | |||
def create_decorator(_f, with_self): | |||
if with_self: | |||
@@ -376,11 +384,11 @@ def _visitor_args_func_dec(func, visit_wrapper=None, static=False): | |||
return f | |||
def _vargs_inline(f, data, children, meta): | |||
def _vargs_inline(f, _data, children, _meta): | |||
return f(*children) | |||
def _vargs_meta_inline(f, data, children, meta): | |||
def _vargs_meta_inline(f, _data, children, meta): | |||
return f(meta, *children) | |||
def _vargs_meta(f, data, children, meta): | |||
def _vargs_meta(f, _data, children, meta): | |||
return f(children, meta) # TODO swap these for consistency? Backwards incompatible! | |||
def _vargs_tree(f, data, children, meta): | |||
return f(Tree(data, children, meta)) | |||
@@ -394,10 +402,14 @@ def v_args(inline=False, meta=False, tree=False, wrapper=None): | |||
``v_args`` can modify this behavior. When used on a transformer/visitor class definition, | |||
it applies to all the callback methods inside it. | |||
``v_args`` can be applied to a single method, or to an entire class. When applied to both, | |||
the options given to the method take precedence. | |||
Parameters: | |||
inline: Children are provided as ``*args`` instead of a list argument (not recommended for very long lists). | |||
meta: Provides two arguments: ``children`` and ``meta`` (instead of just the first) | |||
tree: Provides the entire tree as the argument, instead of the children. | |||
inline (bool, optional): Children are provided as ``*args`` instead of a list argument (not recommended for very long lists). | |||
meta (bool, optional): Provides two arguments: ``children`` and ``meta`` (instead of just the first) | |||
tree (bool, optional): Provides the entire tree as the argument, instead of the children. | |||
wrapper (function, optional): Provide a function to decorate all methods. | |||
Example: | |||
:: | |||
@@ -440,7 +452,7 @@ def v_args(inline=False, meta=False, tree=False, wrapper=None): | |||
###} | |||
#--- Visitor Utilities --- | |||
# --- Visitor Utilities --- | |||
class CollapseAmbiguities(Transformer): | |||
""" | |||
@@ -454,7 +466,9 @@ class CollapseAmbiguities(Transformer): | |||
""" | |||
def _ambig(self, options): | |||
return sum(options, []) | |||
def __default__(self, data, children_lists, meta): | |||
return [Tree(data, children, meta) for children in combine_alternatives(children_lists)] | |||
def __default_token__(self, t): | |||
return [t] |
@@ -29,8 +29,8 @@ setup( | |||
description = "a modern parsing library", | |||
license = "MIT", | |||
keywords = "Earley LALR parser parsing ast", | |||
url = "https://github.com/erezsh/lark", | |||
download_url = "https://github.com/erezsh/lark/tarball/master", | |||
url = "https://github.com/lark-parser/lark", | |||
download_url = "https://github.com/lark-parser/lark/tarball/master", | |||
long_description=''' | |||
Lark is a modern general-purpose parsing library for Python. | |||
@@ -9,6 +9,7 @@ from .test_tools import TestStandalone | |||
from .test_cache import TestCache | |||
from .test_grammar import TestGrammar | |||
from .test_reconstructor import TestReconstructor | |||
from .test_tree_forest_transformer import TestTreeForestTransformer | |||
try: | |||
from .test_nearley.test_nearley import TestNearley | |||
@@ -20,20 +21,7 @@ except ImportError: | |||
from .test_logger import Testlogger | |||
from .test_parser import ( | |||
TestLalrStandard, | |||
TestEarleyStandard, | |||
TestCykStandard, | |||
TestLalrContextual, | |||
TestEarleyDynamic, | |||
TestLalrCustom, | |||
# TestFullEarleyStandard, | |||
TestFullEarleyDynamic, | |||
TestFullEarleyDynamic_complete, | |||
TestParsers, | |||
) | |||
from .test_parser import * # We define __all__ to list which TestSuites to run | |||
logger.setLevel(logging.INFO) | |||
@@ -11,6 +11,7 @@ from copy import copy, deepcopy | |||
from lark.utils import Py36, isascii | |||
from lark import Token | |||
from lark.load_grammar import FromPackageLoader | |||
try: | |||
from cStringIO import StringIO as cStringIO | |||
@@ -29,6 +30,7 @@ try: | |||
except ImportError: | |||
regex = None | |||
import lark | |||
from lark import logger | |||
from lark.lark import Lark | |||
from lark.exceptions import GrammarError, ParseError, UnexpectedToken, UnexpectedInput, UnexpectedCharacters | |||
@@ -36,9 +38,9 @@ from lark.tree import Tree | |||
from lark.visitors import Transformer, Transformer_InPlace, v_args | |||
from lark.grammar import Rule | |||
from lark.lexer import TerminalDef, Lexer, TraditionalLexer | |||
from lark.indenter import Indenter | |||
logger.setLevel(logging.INFO) | |||
__all__ = ['TestParsers'] | |||
__path__ = os.path.dirname(__file__) | |||
def _read(n, *args): | |||
@@ -322,6 +324,22 @@ class TestParsers(unittest.TestCase): | |||
def test_alias(self): | |||
Lark("""start: ["a"] "b" ["c"] "e" ["f"] ["g"] ["h"] "x" -> d """) | |||
def test_backwards_custom_lexer(self): | |||
class OldCustomLexer(Lexer): | |||
def __init__(self, lexer_conf): | |||
pass | |||
def lex(self, text): | |||
yield Token('A', 'A') | |||
p = Lark(""" | |||
start: A | |||
%declare A | |||
""", parser='lalr', lexer=OldCustomLexer) | |||
r = p.parse('') | |||
self.assertEqual(r, Tree('start', [Token('A', 'A')])) | |||
def _make_full_earley_test(LEXER): | |||
@@ -745,6 +763,76 @@ def _make_full_earley_test(LEXER): | |||
tree = parser.parse(text) | |||
self.assertEqual(tree.children, ['foo', 'bar']) | |||
def test_cycle(self): | |||
grammar = """ | |||
start: start? | |||
""" | |||
l = Lark(grammar, ambiguity='resolve', lexer=LEXER) | |||
tree = l.parse('') | |||
self.assertEqual(tree, Tree('start', [])) | |||
l = Lark(grammar, ambiguity='explicit', lexer=LEXER) | |||
tree = l.parse('') | |||
self.assertEqual(tree, Tree('start', [])) | |||
def test_cycles(self): | |||
grammar = """ | |||
a: b | |||
b: c* | |||
c: a | |||
""" | |||
l = Lark(grammar, start='a', ambiguity='resolve', lexer=LEXER) | |||
tree = l.parse('') | |||
self.assertEqual(tree, Tree('a', [Tree('b', [])])) | |||
l = Lark(grammar, start='a', ambiguity='explicit', lexer=LEXER) | |||
tree = l.parse('') | |||
self.assertEqual(tree, Tree('a', [Tree('b', [])])) | |||
def test_many_cycles(self): | |||
grammar = """ | |||
start: a? | start start | |||
!a: "a" | |||
""" | |||
l = Lark(grammar, ambiguity='resolve', lexer=LEXER) | |||
tree = l.parse('a') | |||
self.assertEqual(tree, Tree('start', [Tree('a', ['a'])])) | |||
l = Lark(grammar, ambiguity='explicit', lexer=LEXER) | |||
tree = l.parse('a') | |||
self.assertEqual(tree, Tree('start', [Tree('a', ['a'])])) | |||
def test_cycles_with_child_filter(self): | |||
grammar = """ | |||
a: _x | |||
_x: _x? b | |||
b: | |||
""" | |||
grammar2 = """ | |||
a: x | |||
x: x? b | |||
b: | |||
""" | |||
l = Lark(grammar, start='a', ambiguity='resolve', lexer=LEXER) | |||
tree = l.parse('') | |||
self.assertEqual(tree, Tree('a', [Tree('b', [])])) | |||
l = Lark(grammar, start='a', ambiguity='explicit', lexer=LEXER) | |||
tree = l.parse(''); | |||
self.assertEqual(tree, Tree('a', [Tree('b', [])])) | |||
l = Lark(grammar2, start='a', ambiguity='resolve', lexer=LEXER) | |||
tree = l.parse(''); | |||
self.assertEqual(tree, Tree('a', [Tree('x', [Tree('b', [])])])) | |||
l = Lark(grammar2, start='a', ambiguity='explicit', lexer=LEXER) | |||
tree = l.parse(''); | |||
self.assertEqual(tree, Tree('a', [Tree('x', [Tree('b', [])])])) | |||
@@ -768,16 +856,32 @@ def _make_full_earley_test(LEXER): | |||
_NAME = "TestFullEarley" + LEXER.capitalize() | |||
_TestFullEarley.__name__ = _NAME | |||
globals()[_NAME] = _TestFullEarley | |||
__all__.append(_NAME) | |||
class CustomLexer(Lexer): | |||
class CustomLexerNew(Lexer): | |||
""" | |||
Purpose of this custom lexer is to test the integration, | |||
so it uses the traditionalparser as implementation without custom lexing behaviour. | |||
""" | |||
def __init__(self, lexer_conf): | |||
self.lexer = TraditionalLexer(copy(lexer_conf)) | |||
def lex(self, *args, **kwargs): | |||
return self.lexer.lex(*args, **kwargs) | |||
def lex(self, lexer_state, parser_state): | |||
return self.lexer.lex(lexer_state, parser_state) | |||
__future_interface__ = True | |||
class CustomLexerOld(Lexer): | |||
""" | |||
Purpose of this custom lexer is to test the integration, | |||
so it uses the traditionalparser as implementation without custom lexing behaviour. | |||
""" | |||
def __init__(self, lexer_conf): | |||
self.lexer = TraditionalLexer(copy(lexer_conf)) | |||
def lex(self, text): | |||
ls = self.lexer.make_lexer_state(text) | |||
return self.lexer.lex(ls, None) | |||
__future_interface__ = False | |||
def _tree_structure_check(a, b): | |||
""" | |||
@@ -851,12 +955,31 @@ class DualBytesLark: | |||
self.bytes_lark.load(f) | |||
def _make_parser_test(LEXER, PARSER): | |||
lexer_class_or_name = CustomLexer if LEXER == 'custom' else LEXER | |||
lexer_class_or_name = { | |||
'custom_new': CustomLexerNew, | |||
'custom_old': CustomLexerOld, | |||
}.get(LEXER, LEXER) | |||
def _Lark(grammar, **kwargs): | |||
return Lark(grammar, lexer=lexer_class_or_name, parser=PARSER, propagate_positions=True, **kwargs) | |||
def _Lark_open(gfilename, **kwargs): | |||
return Lark.open(gfilename, lexer=lexer_class_or_name, parser=PARSER, propagate_positions=True, **kwargs) | |||
if (LEXER, PARSER) == ('standard', 'earley'): | |||
# Check that the `lark.lark` grammar represents can parse every example used in these tests. | |||
# Standard-Earley was an arbitrary choice, to make sure it only ran once. | |||
lalr_parser = Lark.open(os.path.join(os.path.dirname(lark.__file__), 'grammars/lark.lark'), parser='lalr') | |||
def wrap_with_test_grammar(f): | |||
def _f(x, **kwargs): | |||
inst = f(x, **kwargs) | |||
lalr_parser.parse(inst.source_grammar) # Test after instance creation. When the grammar should fail, don't test it. | |||
return inst | |||
return _f | |||
_Lark = wrap_with_test_grammar(_Lark) | |||
_Lark_open = wrap_with_test_grammar(_Lark_open) | |||
class _TestParser(unittest.TestCase): | |||
def test_basic1(self): | |||
g = _Lark("""start: a+ b a* "b" a* | |||
@@ -1412,7 +1535,7 @@ def _make_parser_test(LEXER, PARSER): | |||
%s""" % (' '.join(tokens), '\n'.join("%s: %s"%x for x in tokens.items()))) | |||
def test_float_without_lexer(self): | |||
expected_error = UnexpectedCharacters if LEXER.startswith('dynamic') else UnexpectedToken | |||
expected_error = UnexpectedCharacters if 'dynamic' in LEXER else UnexpectedToken | |||
if PARSER == 'cyk': | |||
expected_error = ParseError | |||
@@ -1545,13 +1668,13 @@ def _make_parser_test(LEXER, PARSER): | |||
self.assertEqual(d.line, 2) | |||
self.assertEqual(d.column, 2) | |||
if LEXER != 'dynamic': | |||
self.assertEqual(a.end_line, 1) | |||
self.assertEqual(a.end_column, 2) | |||
self.assertEqual(bc.end_line, 2) | |||
self.assertEqual(bc.end_column, 2) | |||
self.assertEqual(d.end_line, 2) | |||
self.assertEqual(d.end_column, 3) | |||
# if LEXER != 'dynamic': | |||
self.assertEqual(a.end_line, 1) | |||
self.assertEqual(a.end_column, 2) | |||
self.assertEqual(bc.end_line, 2) | |||
self.assertEqual(bc.end_column, 2) | |||
self.assertEqual(d.end_line, 2) | |||
self.assertEqual(d.end_column, 3) | |||
@@ -1782,7 +1905,7 @@ def _make_parser_test(LEXER, PARSER): | |||
""" | |||
self.assertRaises(IOError, _Lark, grammar) | |||
@unittest.skipIf(LEXER=='dynamic', "%declare/postlex doesn't work with dynamic") | |||
@unittest.skipIf('dynamic' in LEXER, "%declare/postlex doesn't work with dynamic") | |||
def test_postlex_declare(self): # Note: this test does a lot. maybe split it up? | |||
class TestPostLexer: | |||
def process(self, stream): | |||
@@ -1805,6 +1928,59 @@ def _make_parser_test(LEXER, PARSER): | |||
tree = parser.parse(test_file) | |||
self.assertEqual(tree.children, [Token('B', 'A')]) | |||
@unittest.skipIf('dynamic' in LEXER, "%declare/postlex doesn't work with dynamic") | |||
def test_postlex_indenter(self): | |||
class CustomIndenter(Indenter): | |||
NL_type = 'NEWLINE' | |||
OPEN_PAREN_types = [] | |||
CLOSE_PAREN_types = [] | |||
INDENT_type = 'INDENT' | |||
DEDENT_type = 'DEDENT' | |||
tab_len = 8 | |||
grammar = r""" | |||
start: "a" NEWLINE INDENT "b" NEWLINE DEDENT | |||
NEWLINE: ( /\r?\n */ )+ | |||
%ignore " "+ | |||
%declare INDENT DEDENT | |||
""" | |||
parser = _Lark(grammar, postlex=CustomIndenter()) | |||
parser.parse("a\n b\n") | |||
def test_import_custom_sources(self): | |||
custom_loader = FromPackageLoader('tests', ('grammars', )) | |||
grammar = """ | |||
start: startab | |||
%import ab.startab | |||
""" | |||
p = _Lark(grammar, import_paths=[custom_loader]) | |||
self.assertEqual(p.parse('ab'), | |||
Tree('start', [Tree('startab', [Tree('ab__expr', [Token('ab__A', 'a'), Token('ab__B', 'b')])])])) | |||
grammar = """ | |||
start: rule_to_import | |||
%import test_relative_import_of_nested_grammar__grammar_to_import.rule_to_import | |||
""" | |||
p = _Lark(grammar, import_paths=[custom_loader]) | |||
x = p.parse('N') | |||
self.assertEqual(next(x.find_data('rule_to_import')).children, ['N']) | |||
custom_loader2 = FromPackageLoader('tests') | |||
grammar = """ | |||
%import .test_relative_import (start, WS) | |||
%ignore WS | |||
""" | |||
p = _Lark(grammar, import_paths=[custom_loader2], source_path=__file__) # import relative to current file | |||
x = p.parse('12 capybaras') | |||
self.assertEqual(x.children, ['12', 'capybaras']) | |||
@unittest.skipIf(PARSER == 'cyk', "Doesn't work for CYK") | |||
def test_prioritization(self): | |||
"Tests effect of priority on result" | |||
@@ -1849,7 +2025,7 @@ def _make_parser_test(LEXER, PARSER): | |||
@unittest.skipIf(PARSER != 'earley' or LEXER == 'standard', "Currently only Earley supports priority sum in rules") | |||
@unittest.skipIf(PARSER != 'earley' or 'dynamic' not in LEXER, "Currently only Earley supports priority sum in rules") | |||
def test_prioritization_sum(self): | |||
"Tests effect of priority on result" | |||
@@ -2060,9 +2236,9 @@ def _make_parser_test(LEXER, PARSER): | |||
self.assertEqual(tok, text) | |||
self.assertEqual(tok.line, 1) | |||
self.assertEqual(tok.column, 1) | |||
if _LEXER != 'dynamic': | |||
self.assertEqual(tok.end_line, 2) | |||
self.assertEqual(tok.end_column, 6) | |||
# if _LEXER != 'dynamic': | |||
self.assertEqual(tok.end_line, 2) | |||
self.assertEqual(tok.end_column, 6) | |||
@unittest.skipIf(PARSER=='cyk', "Empty rules") | |||
def test_empty_end(self): | |||
@@ -2153,7 +2329,7 @@ def _make_parser_test(LEXER, PARSER): | |||
parser = _Lark(grammar) | |||
@unittest.skipIf(PARSER!='lalr' or LEXER=='custom', "Serialize currently only works for LALR parsers without custom lexers (though it should be easy to extend)") | |||
@unittest.skipIf(PARSER!='lalr' or 'custom' in LEXER, "Serialize currently only works for LALR parsers without custom lexers (though it should be easy to extend)") | |||
def test_serialize(self): | |||
grammar = """ | |||
start: _ANY b "C" | |||
@@ -2199,6 +2375,31 @@ def _make_parser_test(LEXER, PARSER): | |||
self.assertEqual(a.line, 1) | |||
self.assertEqual(b.line, 2) | |||
@unittest.skipIf(PARSER=='cyk' or LEXER=='custom_old', "match_examples() not supported for CYK/old custom lexer") | |||
def test_match_examples(self): | |||
p = _Lark(r""" | |||
start: "a" "b" "c" | |||
""") | |||
def match_error(s): | |||
try: | |||
_ = p.parse(s) | |||
except UnexpectedInput as u: | |||
return u.match_examples(p.parse, { | |||
0: ['abe'], | |||
1: ['ab'], | |||
2: ['cbc', 'dbc'], | |||
}) | |||
assert False | |||
assert match_error("abe") == 0 | |||
assert match_error("ab") == 1 | |||
assert match_error("bbc") == 2 | |||
assert match_error("cbc") == 2 | |||
self.assertEqual( match_error("dbc"), 2 ) | |||
self.assertEqual( match_error("ebc"), 2 ) | |||
@unittest.skipIf(not regex or sys.version_info[0] == 2, 'Unicode and Python 2 do not place nicely together.') | |||
def test_unicode_class(self): | |||
"Tests that character classes from the `regex` module work correctly." | |||
@@ -2257,17 +2458,21 @@ def _make_parser_test(LEXER, PARSER): | |||
_TestParser.__name__ = _NAME | |||
_TestParser.__qualname__ = "tests.test_parser." + _NAME | |||
globals()[_NAME] = _TestParser | |||
__all__.append(_NAME) | |||
# Note: You still have to import them in __main__ for the tests to run | |||
_TO_TEST = [ | |||
('standard', 'earley'), | |||
('standard', 'cyk'), | |||
('standard', 'lalr'), | |||
('dynamic', 'earley'), | |||
('dynamic_complete', 'earley'), | |||
('standard', 'lalr'), | |||
('contextual', 'lalr'), | |||
('custom', 'lalr'), | |||
# (None, 'earley'), | |||
('custom_new', 'lalr'), | |||
('custom_new', 'cyk'), | |||
('custom_old', 'earley'), | |||
] | |||
for _LEXER, _PARSER in _TO_TEST: | |||