1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#!/usr/bin/python3
"""
Parsing sample
To parse we're giving a text to parse and an thing with a grammar. The default
setting includes skipping of whitespace, so we don't need to take care of that.
The comment parameter is set to C style /* comments */
>>> f = parse("int f(int a, long b) { do_this; do_that; }", Function, comment=comment_c)
Because function has a name() in its grammar, we can access this now as an
attribute. With Python 2.7 this gives Symbol(u'f'), with Python 3.2 it gives Symbol('f'):
>>> f.name
Symbol(...'f')
A Function has an Attribute "parms" in its grammar, which directs to class
Parameters.
>>> f.parms
Parameters([(Symbol(...'a'), <__main__.Parameter object at 0x...>), (Symbol(...'b'), <__main__.Parameter object at 0x...>), ])
Because Parameters is a Namespace, we can access its content by name.
>>> f.parms["a"]
<__main__.Parameter object at 0x...>
Its content are Parameter instances. Parameter has an Attribute "typing".
>>> f.parms["b"].typing
Type(...'long')
The Instructions of our small sample are just words. Because Function is a
List, we can access them one by one.
>>> f
Function([...'do_this', ...'do_that'], name=Symbol(...'f'))
>>> print("f is " + repr(f[0]))
f is ...'do_this'
The result can be composed to a text again.
>>> f.append(Instruction("do_something_else"))
>>> print(compose(f))
int f(int a, long b)
{
/* on level 1 */
do_this;
/* on level 1 */
do_that;
/* on level 1 */
do_something_else;
}
...
pyPEG contains an XML backend, too:
>>> del f[2]
>>> from pypeg2.xmlast import thing2xml
>>> xml = thing2xml(f, pretty=True)
>>> print(xml.decode())
<Function typing="int" name="f">
<Parameters>
<Parameter typing="int" name="a"/>
<Parameter typing="long" name="b"/>
</Parameters>
<Instruction>do_this</Instruction>
<Instruction>do_that</Instruction>
</Function>
...
The XML backend can read XML text and create things:
>>> from pypeg2.xmlast import xml2thing
>>> xml = b'<Function typing="long" name="g"><Parameters><Parameter name="x" typing="int"/></Parameters><Instruction>return</Instruction></Function>'
>>> g = xml2thing(xml, globals())
>>> g.name
Symbol(...'g')
>>> g.typing
Type(...'long')
>>> g.parms["x"].typing
Type(...'int')
>>> print("g[0] is " + repr(g[0]))
g[0] is ...'return'
"""
from __future__ import unicode_literals, print_function
from pypeg2 import *
# A Symbol can be an arbitrary word or one word of an Enum.
# In this easy example there is an Enum.
class Type(Keyword):
grammar = Enum( K("int"), K("long") )
# Parsing attributes adds them to the resulting thing.
# blank is a callback function. Callback functions are being executed by
# compose(). parse() ignores callback functions. blank inserts " ".
# name() generates a name attribute.
class Parameter(object):
grammar = attr("typing", Type), blank, name()
# A Namespace is a container for named things.
# csl() creates the grammar for a comma separated list.
class Parameters(Namespace):
grammar = optional(csl(Parameter))
# This is an example for a user defined callback function, heading().
# endl is a special callback function. It is never executed. Instead it
# triggers the indention system of compose() and will be replaced by "\n".
class Instruction(str):
def heading(self, parser):
return "/* on level " + str(parser.indention_level) + " */", endl
grammar = heading, word, ";", endl
# indent() is a function which marks things for being indented by compose().
# indent() raises the indention level by 1 for each thing which is inside.
block = "{", endl, maybe_some(indent(Instruction)), "}", endl
# If a thing is a List, then parsed things are being put into.
class Function(List):
grammar = attr("typing", Type), blank, name(), "(", attr("parms", Parameters), ")", endl, block
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=(doctest.ELLIPSIS | doctest.REPORT_ONLY_FIRST_FAILURE))
|