summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/0README.html309
-rw-r--r--examples/AcManForm.dfm885
-rw-r--r--examples/LAparser.py417
-rw-r--r--examples/Setup.ini73
-rw-r--r--examples/SimpleCalc.py118
-rw-r--r--examples/SingleForm.dfm751
-rw-r--r--examples/TAP.py217
-rw-r--r--examples/__init__.py0
-rw-r--r--examples/adventureEngine.py648
-rw-r--r--examples/antlr_grammar.py219
-rw-r--r--examples/antlr_grammar_tests.py87
-rw-r--r--examples/apicheck.py58
-rw-r--r--examples/btpyparse.py129
-rw-r--r--examples/builtin_parse_action_demo.py29
-rw-r--r--examples/cLibHeader.py25
-rw-r--r--examples/chemicalFormulas.py67
-rw-r--r--examples/commasep.py26
-rw-r--r--examples/configParse.py72
-rw-r--r--examples/cpp_enum_parser.py52
-rw-r--r--examples/datetimeParseActions.py68
-rw-r--r--examples/deltaTime.py208
-rw-r--r--examples/dfmparse.py179
-rw-r--r--examples/dhcpd_leases_parser.py87
-rw-r--r--examples/dictExample.py41
-rw-r--r--examples/dictExample2.py59
-rw-r--r--examples/ebnf.py151
-rw-r--r--examples/ebnftest.py72
-rw-r--r--examples/eval_arith.py227
-rw-r--r--examples/excelExpr.py69
-rw-r--r--examples/fourFn.py192
-rw-r--r--examples/gen_ctypes.py174
-rw-r--r--examples/getNTPservers.py30
-rw-r--r--examples/getNTPserversNew.py35
-rw-r--r--examples/greeting.py17
-rw-r--r--examples/greetingInGreek.py20
-rw-r--r--examples/greetingInKorean.py22
-rw-r--r--examples/groupUsingListAllMatches.py17
-rw-r--r--examples/holaMundo.py38
-rw-r--r--examples/htmlStripper.py32
-rw-r--r--examples/httpServerLogParser.py73
-rw-r--r--examples/idlParse.py173
-rw-r--r--examples/indentedGrammarExample.py54
-rw-r--r--examples/invRegex.py257
-rw-r--r--examples/javascript_grammar.g894
-rw-r--r--examples/jsonParser.py107
-rw-r--r--examples/linenoExample.py49
-rw-r--r--examples/list1.py56
-rw-r--r--examples/listAllMatches.py52
-rw-r--r--examples/lucene_grammar.py319
-rw-r--r--examples/macroExpander.py60
-rw-r--r--examples/makeHTMLTagExample.py21
-rw-r--r--examples/matchPreviousDemo.py33
-rw-r--r--examples/mozilla.ics50
-rw-r--r--examples/mozillaCalendarParser.py81
-rw-r--r--examples/nested.py30
-rw-r--r--examples/numerics.py62
-rw-r--r--examples/oc.py188
-rw-r--r--examples/parseListString.py82
-rw-r--r--examples/parsePythonValue.py70
-rw-r--r--examples/parseResultsSumExample.py26
-rw-r--r--examples/parseTabularData.py50
-rw-r--r--examples/partial_gene_match.py88
-rw-r--r--examples/pgn.py94
-rw-r--r--examples/position.py55
-rw-r--r--examples/protobuf_parser.py100
-rw-r--r--examples/pymicko.py1387
-rw-r--r--examples/pythonGrammarParser.py220
-rw-r--r--examples/rangeCheck.py62
-rw-r--r--examples/readJson.py1917
-rw-r--r--examples/removeLineBreaks.py45
-rw-r--r--examples/romanNumerals.py74
-rw-r--r--examples/scanExamples.py75
-rw-r--r--examples/scanYahoo.py14
-rw-r--r--examples/searchParserAppDemo.py34
-rw-r--r--examples/searchparser.py292
-rw-r--r--examples/select_parser.py126
-rw-r--r--examples/sexpParser.py167
-rw-r--r--examples/shapes.py64
-rw-r--r--examples/simpleArith.py67
-rw-r--r--examples/simpleBool.py102
-rw-r--r--examples/simpleSQL.py88
-rw-r--r--examples/simpleWiki.py32
-rw-r--r--examples/snmp_api.h795
-rw-r--r--examples/sparser.py365
-rw-r--r--examples/sql2dot.py96
-rw-r--r--examples/stackish.py81
-rw-r--r--examples/stateMachine2.py258
-rw-r--r--examples/test_bibparse.py195
-rw-r--r--examples/urlExtractor.py33
-rw-r--r--examples/urlExtractorNew.py35
-rw-r--r--examples/verilogParse.py720
-rw-r--r--examples/withAttribute.py24
-rw-r--r--examples/wordsToNum.py106
93 files changed, 16518 insertions, 0 deletions
diff --git a/examples/0README.html b/examples/0README.html
new file mode 100644
index 0000000..303d44d
--- /dev/null
+++ b/examples/0README.html
@@ -0,0 +1,309 @@
+<HTML>
+<title>pyparsing Examples</title>
+<body>
+<h1>pyparsing Examples</h1>
+<p>
+This directory contains a number of Python scripts that can get you started in learning to use pyparsing.
+
+<ul>
+<li><a href="greeting.py">greeting.py</a><br>
+Parse "Hello, World!".
+</li>
+<p>
+
+<li><a href="greetingInKorean.py">greetingInKorean.py</a> <i>~ submission by June Kim</i><br>
+Unicode example to parse "Hello, World!" in Korean.
+</li>
+<p>
+
+<li><a href="greetingInGreek.py">greetingInGreek.py</a> <i>~ submission by ???</i><br>
+Unicode example to parse "Hello, World!" in Greek.
+</li>
+<p>
+
+<li><a href="holaMundo.py">holaMundo.py</a> <i>~ submission by Marco Alfonso</i><br>
+"Hello, World!" example translated to Spanish, from Marco Alfonso's blog.
+</li>
+<p>
+
+<li><a href="chemicalFormulas.py">chemicalFormulas.py</a><br>
+Simple example to demonstrate the use of ParseResults returned from parseString().
+Parses a chemical formula (such as "H2O" or "C6H5OH"), and walks the returned list of tokens to calculate the molecular weight.
+</li>
+<p>
+
+<li><a href="wordsToNum.py">wordsToNum.py</a><br>
+A sample program that reads a number in words (such as "fifteen hundred and sixty four"), and returns the actual number (1564).
+Also demonstrates some processing of ParseExceptions, including marking where the parse failure was found.
+</li>
+<p>
+
+<li><a href="pythonGrammarparser.py">pythonGrammarparser.py</a> <i>~ suggested by JH Stovall</i><br>
+A sample program that parses the EBNF used in the Python source code to define the Python grammar. From this parser,
+one can generate Python grammar documentation tools, such as railroad track diagrams. Also demonstrates use of
+Dict class.
+</li>
+<p>
+
+<li><a href="commasep.py">commasep.py</a><br>
+Demonstration of the use of the commaSeparatedList helper. Shows examples of
+proper handling of commas within quotes, trimming of whitespace around delimited entries, and handling of consecutive commas (null arguments). Includes comparison with simple string.split(',').
+</li>
+<p>
+
+<li><a href="dictExample.py">dictExample.py</a><br>
+A demonstration of using the Dict class, to parse a table of ASCII tabulated data.
+</li>
+<p>
+
+<li><a href="dictExample2.py">dictExample2.py</a> <i>~ submission by Mike Kelly</i><br>
+An extended version of dictExample.py, in which Mike Kelly also parses the column headers, and generates a transposed version of the original table!
+</li>
+<p>
+
+<li><a href="scanExamples.py">scanExamples.py</a><br>
+Some examples of using scanString and transformString, as alternative parsing methods to parseString, to do macro substitution, and selection and/or removal of matching strings within a source file.
+</li>
+<p>
+
+<li><a href="urlExtractor.py">urlExtractor.py</a><br>
+Another example using scanString, this time to extract all HREF references found on Yahoo!'s home page, and return them as a dictionary.
+</li>
+<p>
+
+<li><a href="makeHTMLTagExample.py">makeHTMLTagExample.py</a><br>
+A sample program showing sample definitions and applications of HTML tag expressions
+created using makeHTMLTags helper function. Very useful for scraping data from HTML pages.
+</li>
+<p>
+
+<li><a href="urlExtractorNew.py">urlExtractorNew.py</a><br>
+Another updated version of urlExtractor.py, using the new makeHTMLTags() method.
+</li>
+<p>
+
+<li><a href="fourFn.py">fourFn.py</a><br>
+A simple algebraic expression parser, that performs +,-,*,/, and ^ arithmetic operations. (With suggestions and bug-fixes graciously offered by Andrea Griffini.)
+</li>
+<p>
+
+<li><a href="SimpleCalc.py">SimpleCalc.py</a> <i>~ submission by Steven Siew</i><br>
+An interactive version of fourFn.py, with support for variables.
+</li>
+<p>
+
+<li><a href="LAParser.py">LAParser.py</a> <i>~ submission by Mike Ellis</i><br>
+An interactive Linear Algebra Parser, an extension of SimpleCalc.py. Supports linear algebra (LA) notation for vectors, matrices, and scalars,
+including matrix operations such as inversion and determinants. Converts LA expressions to C code - uses a separate C library for runtime
+evaluation of results.
+</li>
+<p>
+
+<li><a href="configParse.py">configParse.py</a><br>
+A simple alternative to Python's ConfigParse module, demonstrating the use of the Dict class to return nested dictionary access to configuration values.
+</li>
+<p>
+
+<li><a href="getNTPservers.py">getNTPservers.py</a><br>
+Yet another scanString example, to read/extract the list of NTP servers from NIST's web site.
+</li>
+<p>
+
+<li><a href="getNTPserversNew.py">getNTPserversNew.py</a><br>
+An updated version of getNTPservers.py, using the new makeHTMLTags() method.
+</li>
+<p>
+
+<li><a href="httpServerLogParser.py">httpServerLogParser.py</a><br>
+Parser for Apache server log files.
+</li>
+<p>
+
+<li><a href="idlParse.py">idlParse.py</a><br>
+Parser for CORBA IDL files.
+</li>
+<p>
+
+<li><a href="mozillaCalendarParser.py">mozillaCalendarParser.py</a>
+<i>~ submission by Petri Savolainen</i><br>
+Parser for Mozilla calendar (*.ics) files.
+</li>
+<p>
+
+<li><a href="pgn.py">pgn.py</a> <i>~ submission by Alberto Santini</i><br>
+Parser for PGN (Portable Game Notation) files, the standard form for documenting the moves in chess games.
+</li>
+<p>
+
+<li><a href="simpleSQL.py">simpleSQL.py</a><br>
+A simple parser that will extract table and column names from SQL SELECT statements..
+</li>
+<p>
+
+<li><a href="dfmparse.py">dfmparse.py</a> <i>~ submission by Dan Griffith</i><br>
+Parser for Delphi forms.
+</li>
+<p>
+
+<li><a href="ebnf.py">ebnf.py / ebnftest.py</a> <i>~ submission by Seo Sanghyeon</i><br>
+An EBNF-compiler that reads EBNF and generates a pyparsing grammar! Including a test that compiles... EBNF itself!
+</li>
+<p>
+
+<li><a href="searchparser.py">searchparser.py</a> <i>~ submission by Steven Mooij and Rudolph Froger</i><br>
+An expression parser that parses search strings, with special keyword and expression operations using (), not, and, or, and quoted strings.
+</li>
+<p>
+
+<li><a href="sparser.py">sparser.py</a> <i>~ submission by Tim Cera</i><br>
+A configurable parser module that can be configured with a list of tuples, giving a high-level definition for parsing common sets
+of water table data files. Tim had to contend with several different styles of data file formats, each with slight variations of its own.
+Tim created a configurable parser (or "SPECIFIED parser" - hence the name "sparser"), that simply works from a config variable listing
+the field names and data types, and implicitly, their order in the source data file.
+<p>
+See <a href="mayport_florida_8720220_data_def.txt">mayport_florida_8720220_data_def.txt</a> for an
+example configuration file.
+</li>
+<p>
+
+<li><a href="romanNumerals.py">romanNumerals.py</a><br>
+A Roman numeral generator and parser example, showing the power of parse actions
+to compile Roman numerals into their integer values.
+</li>
+<p>
+
+<li><a href="removeLineBreaks.py">removeLineBreaks.py</a><br>
+A string transformer that converts text files with hard line-breaks into one with line breaks
+only between paragraphs. Useful when converting downloads from
+<a href="http://www.gutenberg.org">Project Gutenberg</a> to import to word processing apps
+that can reformat paragraphs once hard line-breaks are removed, or for loading into your Palm Pilot for portable perusal.
+<p>
+See <a href="Successful Methods of Public Speaking.txt">Successful Methods of Public Speaking.txt</a> and
+<a href="Successful Methods of Public Speaking(2).txt">Successful Methods of Public Speaking(2).txt</a> for a sample
+before and after (text file courtesy of Project Gutenberg).
+</li>
+<p>
+
+<li><a href="listAllMatches.py">listAllMatches.py</a><br>
+An example program showing the utility of the listAllMatches option when specifying results naming.
+</li>
+<p>
+
+<li><a href="linenoExample.py">linenoExample.py</a><br>
+An example program showing how to use the string location to extract line and column numbers, or the
+source line of text.
+</li>
+<p>
+
+<li><a href="parseListString.py">parseListString.py</a><br>
+An example program showing a progression of steps, how to parse a string representation of a Python
+list back into a true list.
+</li>
+<p>
+
+<li><a href="parsePythonValue.py">parsePythonValue.py</a><br>
+An extension of parseListString.py to parse tuples and dicts, including nested values,
+returning a Python value of the original type.
+</li>
+<p>
+
+<li><a href="indentedGrammarExample.py">indentedGrammarExample.py</a><br>
+An example program showing how to parse a grammar using indentation for grouping,
+such as is done in Python.
+</li>
+<p>
+
+<li><a href="simpleArith.py">simpleArith.py</a><br>
+An example program showing how to use the new operatorPrecedence helper method to define a 6-function
+(+, -, *, /, ^, and !) arithmetic expression parser, with unary plus and minus signs.
+</li>
+<p>
+
+<li><a href="simpleBool.py">simpleBool.py</a><br>
+An example program showing how to use the new operatorPrecedence helper method to define a
+boolean expression parser, with parse actions associated with each operator to "compile" the expression
+into a data structure that will evaluate the expression's boolean value.
+</li>
+<p>
+
+<li><a href="simpleWiki.py">simpleWiki.py</a><br>
+An example program showing how to use transformString to implement a simple Wiki markup parser.
+</li>
+<p>
+
+<li><a href="sql2dot.py">sql2dot.py</a><i>~ submission by EnErGy [CSDX]</i><br>
+A nice graphing program that generates schema diagrams from SQL table definition statements.
+</li>
+<p>
+
+<li><a href="htmlStripper.py">htmlStripper.py</a><br>
+An example implementation of a common application, removing HTML markup tags from an HTML page,
+leaving just the text content.
+</li>
+<p>
+
+<li><a href="macroExpansion.py">macroExpansion.py</a><br>
+An example implementation of a simple preprocessor, that will read embedded macro definitions
+and replace macro references with the defined substitution string.
+</li>
+<p>
+
+<li><a href="sexpParser.py">sexpParser.py</a><br>
+A parser that uses a recursive grammar to parse S-expressions.
+</li>
+<p>
+
+<li><a href="nested.py">nested.py</a><br>
+An example using nestedExpr, a helper method to simplify definitions of expressions of nested lists.
+</li>
+<p>
+
+<li><a href="withAttribute.py">withAttribute.py</a><br>
+An example using withAttribute, a helper method to define parse actions to validate matched HTML tags
+using additional attributes. Especially helpful for matching common tags such as &lt;DIV&gt; and &lt;TD&gt;.
+</li>
+<p>
+
+<li><a href="stackish.py">stackish.py</a><br>
+A parser for the data representation format, Stackish.
+</li>
+<p>
+
+<li><a href="builtin_parse_action_demo.py">builtin_parse_action_demo.py</a><br>
+<b>New in version 1.5.7</b><br>
+Demonstration of using builtins (min, max, sum, len, etc.) as parse actions.
+</li>
+<p>
+
+<li><a href="antlr_grammar.py">antlr_grammar.py</a><i>~ submission by Luca DellOlio</i><br>
+<b>New in version 1.5.7</b><br>
+Pyparsing example parsing ANTLR .a files and generating a working pyparsing parser.
+</li>
+<p>
+
+<li><a href="shapes.py">shapes.py</a><br>
+<b>New in version 1.5.7</b><br>
+Parse actions example simple shape definition syntax, and returning the matched tokens as
+domain objects instead of just strings.
+</li>
+<p>
+
+<li><a href="datetimeParseActions.py">datetimeParseActions.py</a><br>
+<b>New in version 1.5.7</b><br>
+Parse actions example showing a parse action returning a datetime object instead of
+string tokens, and doing validation of the tokens, raising a ParseException if the
+given YYYY/MM/DD string does not represent a valid date.
+</li>
+<p>
+
+<li><a href="position.py">position.py</a><br>
+<b>New in version 1.5.7</b><br>
+Demonstration of a couple of different ways to capture the location a particular
+expression was found within the overall input string.
+</li>
+<p>
+
+
+</ul>
+
+</body></html>
diff --git a/examples/AcManForm.dfm b/examples/AcManForm.dfm
new file mode 100644
index 0000000..db80f6a
--- /dev/null
+++ b/examples/AcManForm.dfm
@@ -0,0 +1,885 @@
+object Form1: TForm1
+ Left = 193
+ Top = 105
+ Width = 696
+ Height = 480
+ Caption = 'AcManTest'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object RichEdit1: TRichEdit
+ Left = 0
+ Top = 107
+ Width = 688
+ Height = 346
+ Align = alClient
+ Lines.Strings = (
+ 'RichEdit1')
+ TabOrder = 0
+ end
+ object ActionToolBar1: TActionToolBar
+ Left = 0
+ Top = 25
+ Width = 688
+ Height = 28
+ ActionManager = ActionManager1
+ Caption = 'ActionToolBar1'
+ ColorMap.HighlightColor = 14410210
+ ColorMap.BtnSelectedColor = clBtnFace
+ ColorMap.UnusedColor = 14410210
+ EdgeBorders = [ebTop, ebBottom]
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ Spacing = 0
+ end
+ object ActionMainMenuBar1: TActionMainMenuBar
+ Left = 0
+ Top = 0
+ Width = 688
+ Height = 25
+ UseSystemFont = False
+ ActionManager = ActionManager1
+ AnimationStyle = asSlide
+ Caption = 'ActionMainMenuBar1'
+ ColorMap.HighlightColor = 14410210
+ ColorMap.BtnSelectedColor = clBtnFace
+ ColorMap.UnusedColor = 14410210
+ EdgeBorders = [ebTop, ebBottom]
+ EdgeOuter = esNone
+ Font.Charset = ANSI_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentShowHint = False
+ ShowHint = True
+ Spacing = 0
+ end
+ object ActionToolBar2: TActionToolBar
+ Left = 0
+ Top = 53
+ Width = 688
+ Height = 28
+ ActionManager = ActionManager1
+ Caption = 'ActionToolBar2'
+ ColorMap.HighlightColor = 14410210
+ ColorMap.BtnSelectedColor = clBtnFace
+ ColorMap.UnusedColor = 14410210
+ EdgeBorders = [ebTop, ebBottom]
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ ParentFont = False
+ ParentShowHint = False
+ ShowHint = True
+ Spacing = 0
+ end
+ object ActionToolBar3: TActionToolBar
+ Left = 0
+ Top = 81
+ Width = 688
+ Height = 26
+ ActionManager = ActionManager1
+ Caption = 'ActionToolBar3'
+ ColorMap.HighlightColor = 14410210
+ ColorMap.BtnSelectedColor = clBtnFace
+ ColorMap.UnusedColor = 14410210
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ ParentFont = False
+ Spacing = 0
+ end
+ object ActionManager1: TActionManager
+ FileName = 'settings'
+ ActionBars.SessionCount = 4
+ ActionBars = <
+ item
+ Items = <
+ item
+ Action = EditUndo1
+ ImageIndex = 3
+ ShortCut = 16474
+ end
+ item
+ Action = EditCut1
+ ImageIndex = 0
+ ShortCut = 16472
+ end
+ item
+ Action = EditCopy1
+ ImageIndex = 1
+ ShortCut = 16451
+ end
+ item
+ Action = EditPaste1
+ ImageIndex = 2
+ ShortCut = 16470
+ end
+ item
+ Action = SearchFind1
+ ImageIndex = 15
+ ShortCut = 16454
+ end
+ item
+ Action = SearchReplace1
+ ImageIndex = 17
+ end>
+ ActionBar = ActionToolBar1
+ AutoSize = False
+ end
+ item
+ Items = <
+ item
+ Items = <
+ item
+ Action = FileOpen1
+ ImageIndex = 12
+ ShortCut = 16463
+ end
+ item
+ Action = FileSaveAs1
+ ImageIndex = 13
+ end
+ item
+ Action = FilePrintSetup1
+ end
+ item
+ Action = FileRun1
+ end
+ item
+ Action = FileExit1
+ ImageIndex = 14
+ LastSession = -1
+ UsageCount = -1
+ end>
+ Caption = '&File'
+ end
+ item
+ Items = <
+ item
+ Action = EditCut1
+ ImageIndex = 0
+ ShortCut = 16472
+ end
+ item
+ Action = EditCopy1
+ ImageIndex = 1
+ ShortCut = 16451
+ end
+ item
+ Action = EditPaste1
+ ImageIndex = 2
+ ShortCut = 16470
+ end
+ item
+ Action = EditSelectAll1
+ ShortCut = 16449
+ end
+ item
+ Action = EditUndo1
+ ImageIndex = 3
+ ShortCut = 16474
+ end
+ item
+ Action = EditDelete1
+ ImageIndex = 4
+ ShortCut = 46
+ end>
+ Caption = '&Edit'
+ end
+ item
+ Items = <
+ item
+ Action = RichEditBold1
+ ImageIndex = 5
+ ShortCut = 16450
+ end
+ item
+ Action = RichEditItalic1
+ ImageIndex = 6
+ ShortCut = 16457
+ end
+ item
+ Action = RichEditUnderline1
+ ImageIndex = 7
+ ShortCut = 16469
+ end
+ item
+ Action = RichEditStrikeOut1
+ end
+ item
+ Action = RichEditBullets1
+ ImageIndex = 8
+ end
+ item
+ Action = RichEditAlignLeft1
+ ImageIndex = 9
+ end
+ item
+ Action = RichEditAlignRight1
+ ImageIndex = 10
+ end
+ item
+ Action = RichEditAlignCenter1
+ ImageIndex = 11
+ end>
+ Caption = 'F&ormat'
+ end
+ item
+ Items = <
+ item
+ Action = SearchFind1
+ ImageIndex = 15
+ ShortCut = 16454
+ end
+ item
+ Action = SearchFindNext1
+ ImageIndex = 16
+ ShortCut = 114
+ end
+ item
+ Action = SearchReplace1
+ ImageIndex = 17
+ end
+ item
+ Action = SearchFindFirst1
+ end>
+ Caption = '&Search'
+ end
+ item
+ Items = <
+ item
+ Action = CustomizeActionBars1
+ end>
+ Caption = '&Tools'
+ end
+ item
+ Items = <
+ item
+ Action = HelpContents1
+ ImageIndex = 18
+ end>
+ Caption = '&Help'
+ end>
+ ActionBar = ActionMainMenuBar1
+ AutoSize = False
+ end
+ item
+ Items = <
+ item
+ Action = RichEditBold1
+ ImageIndex = 5
+ ShortCut = 16450
+ end
+ item
+ Action = RichEditItalic1
+ ImageIndex = 6
+ ShortCut = 16457
+ end
+ item
+ Action = RichEditUnderline1
+ ImageIndex = 7
+ ShortCut = 16469
+ end
+ item
+ Action = RichEditBullets1
+ Caption = 'Bull&ets'
+ ImageIndex = 8
+ end
+ item
+ Action = RichEditAlignLeft1
+ ImageIndex = 9
+ end
+ item
+ Action = RichEditAlignRight1
+ ImageIndex = 10
+ end
+ item
+ Action = RichEditAlignCenter1
+ ImageIndex = 11
+ end>
+ ActionBar = ActionToolBar2
+ AutoSize = False
+ end
+ item
+ AutoSize = False
+ end
+ item
+ AutoSize = False
+ end
+ item
+ Items = <
+ item
+ Action = FileSaveAs1
+ ImageIndex = 13
+ LastSession = 2
+ end
+ item
+ Action = CustomizeActionBars1
+ end
+ item
+ Action = FileExit1
+ ImageIndex = 14
+ end
+ item
+ Action = HelpContents1
+ Caption = 'C&ontents'
+ ImageIndex = 18
+ end
+ item
+ Action = ActionShowStatus
+ Caption = '&ShowStatus'
+ end>
+ ActionBar = ActionToolBar3
+ AutoSize = False
+ end>
+ Images = ImageList1
+ Left = 88
+ Top = 136
+ StyleName = 'XP Style'
+ object EditCut1: TEditCut
+ Category = 'Edit'
+ Caption = 'Cu&t'
+ Hint = 'Cut|Cuts the selection and puts it on the Clipboard'
+ ImageIndex = 0
+ ShortCut = 16472
+ end
+ object EditCopy1: TEditCopy
+ Category = 'Edit'
+ Caption = '&Copy'
+ Hint = 'Copy|Copies the selection and puts it on the Clipboard'
+ ImageIndex = 1
+ ShortCut = 16451
+ end
+ object EditPaste1: TEditPaste
+ Category = 'Edit'
+ Caption = '&Paste'
+ Hint = 'Paste|Inserts Clipboard contents'
+ ImageIndex = 2
+ ShortCut = 16470
+ end
+ object EditSelectAll1: TEditSelectAll
+ Category = 'Edit'
+ Caption = 'Select &All'
+ Hint = 'Select All|Selects the entire document'
+ ShortCut = 16449
+ end
+ object EditUndo1: TEditUndo
+ Category = 'Edit'
+ Caption = '&Undo'
+ Hint = 'Undo|Reverts the last action'
+ ImageIndex = 3
+ ShortCut = 16474
+ end
+ object EditDelete1: TEditDelete
+ Category = 'Edit'
+ Caption = '&Delete'
+ Hint = 'Delete|Erases the selection'
+ ImageIndex = 4
+ ShortCut = 46
+ end
+ object RichEditBold1: TRichEditBold
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Bold'
+ Hint = 'Bold'
+ ImageIndex = 5
+ ShortCut = 16450
+ end
+ object RichEditItalic1: TRichEditItalic
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Italic'
+ Hint = 'Italic'
+ ImageIndex = 6
+ ShortCut = 16457
+ end
+ object RichEditUnderline1: TRichEditUnderline
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Underline'
+ Hint = 'Underline'
+ ImageIndex = 7
+ ShortCut = 16469
+ end
+ object RichEditStrikeOut1: TRichEditStrikeOut
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Strikeout'
+ Hint = 'Strikeout'
+ end
+ object RichEditBullets1: TRichEditBullets
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Bullets'
+ Hint = 'Bullets|Inserts a bullet on the current line'
+ ImageIndex = 8
+ end
+ object RichEditAlignLeft1: TRichEditAlignLeft
+ Category = 'Format'
+ AutoCheck = True
+ Caption = 'Align &Left'
+ Hint = 'Align Left|Aligns text at the left indent'
+ ImageIndex = 9
+ end
+ object RichEditAlignRight1: TRichEditAlignRight
+ Category = 'Format'
+ AutoCheck = True
+ Caption = 'Align &Right'
+ Hint = 'Align Right|Aligns text at the right indent'
+ ImageIndex = 10
+ end
+ object RichEditAlignCenter1: TRichEditAlignCenter
+ Category = 'Format'
+ AutoCheck = True
+ Caption = '&Center'
+ Hint = 'Center|Centers text between margins'
+ ImageIndex = 11
+ end
+ object FileOpen1: TFileOpen
+ Category = 'File'
+ Caption = '&Open...'
+ Hint = 'Open|Opens an existing file'
+ ImageIndex = 12
+ ShortCut = 16463
+ end
+ object FileSaveAs1: TFileSaveAs
+ Category = 'File'
+ Caption = 'Save &As...'
+ Hint = 'Save As|Saves the active file with a new name'
+ ImageIndex = 13
+ end
+ object FilePrintSetup1: TFilePrintSetup
+ Category = 'File'
+ Caption = 'Print Set&up...'
+ Hint = 'Print Setup'
+ end
+ object FileRun1: TFileRun
+ Category = 'File'
+ Browse = False
+ BrowseDlg.Title = 'Run'
+ Caption = '&Run...'
+ Hint = 'Run|Runs an application'
+ Operation = 'open'
+ ShowCmd = scShowNormal
+ end
+ object FileExit1: TFileExit
+ Category = 'File'
+ Caption = 'E&xit'
+ Hint = 'Exit|Quits the application'
+ ImageIndex = 14
+ end
+ object SearchFind1: TSearchFind
+ Category = 'Search'
+ Caption = '&Find...'
+ Hint = 'Find|Finds the specified text'
+ ImageIndex = 15
+ ShortCut = 16454
+ end
+ object SearchFindNext1: TSearchFindNext
+ Category = 'Search'
+ Caption = 'Find &Next'
+ Enabled = False
+ Hint = 'Find Next|Repeats the last find'
+ ImageIndex = 16
+ ShortCut = 114
+ end
+ object SearchReplace1: TSearchReplace
+ Category = 'Search'
+ Caption = '&Replace'
+ Hint = 'Replace|Replaces specific text with different text'
+ ImageIndex = 17
+ end
+ object SearchFindFirst1: TSearchFindFirst
+ Category = 'Search'
+ Caption = 'F&ind First'
+ Hint = 'Find First|Finds the first occurance of specified text'
+ end
+ object CustomizeActionBars1: TCustomizeActionBars
+ Category = 'Tools'
+ Caption = '&Customize'
+ CustomizeDlg.StayOnTop = False
+ end
+ object HelpContents1: THelpContents
+ Category = 'Help'
+ Caption = '&Contents'
+ Enabled = False
+ Hint = 'Help Contents'
+ ImageIndex = 18
+ end
+ object ActionShowStatus: TAction
+ Category = 'Tools'
+ Caption = 'ShowStatus'
+ OnExecute = ActionShowStatusExecute
+ end
+ end
+ object ImageList1: TImageList
+ Left = 168
+ Top = 136
+ Bitmap = {
+ 494C010113001400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+ 0000000000003600000028000000400000005000000001001000000000000028
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 1040104010420000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000010401040
+ FF7FFF7F18631042000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000010401040FF7FFF7F
+ 0000000018631863104200000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000104210401040FF7FFF7F00000000
+ 1040104000001863186310420000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000001863000000000000
+ 0000000000000000186300000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000010421040FF7F0000000010401040
+ 1040104010400000186318631042000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000010420000
+ 0000000010420000000000000000000000000000000000001863000000000000
+ 0000000000000000186300000000000000001042000000001040104010400042
+ E07F104010401040000018631863104200000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000010420000
+ 0000000010420000000000000000000000001042104010401040104010401040
+ 0042104010401040104000001863000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000001863000000000000
+ 0000186300000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000001040FF7F1040104010401040
+ 1040E07FE07F1040104010400000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000001863000000000000
+ 0000186300000000000000000000000000000000000000001863000000000000
+ 000018630000000000000000000000000000000000001040FF7F104010401040
+ 104010400042E07FE07F10401040000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000001863000000000000
+ 0000186300000000000000000000000000000000000000001040FF7F10401040
+ 104000421040E07FE07F10401040104000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 1042000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000001040FF7F1040
+ 1040E07FE07FE07F104010401040000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 104200000000000000000000000000000000000000000000000000001040FF7F
+ 1040104010401040104000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000001040
+ FF7F104010400000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 1040104000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000001042104210421042104210421042
+ 104210421042FF7F186310421863FF7F18630000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000001042104210421042104210421042
+ 1042104210421042FF7F1042FF7F104210420000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420042000000000000
+ 0000000000000000000000000042000000000000000000000000000000000000
+ 0000000000000000000000000000000000001000100010001000000000001042
+ 10421042FF7FFF7FFF7F10001000100010000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420042000000000000
+ 0000000000000000000000000042000000000000000000000000004200420000
+ 00000000000018630000004200000000000000000000000010001F0010000000
+ 00001042FF7FFF7FFF7F10000000000000000000FF7F00000000000000000000
+ 0000000000000000FF7F00000000000000000000000000420042000000000000
+ 0000000000000000000000000042000000000000000000000000004200420000
+ 000000000000186300000042000000000000000000000000100010001F001000
+ 0000FF7FFF7FFF7FFF7F10000000000000000000FF7F00000000000000000000
+ 0000000000000000FF7F00000000000000000000000000420042000000000000
+ 0000000000000000000000000042000000000000000000000000004200420000
+ 00000000000000000000004200000000000000000000000010001F0010001F00
+ 0000FF7FFF7FFF7FFF7F10000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420042004200420042
+ 0042004200420042004200420042000000000000000000000000004200420042
+ 004200420042004200420042000000000000000000000000100010001F001000
+ 0000FF7FFF03FF7FFF03100000000000000000000000FF7F0000000000000000
+ 00000000FF7F0000000000000000000000000000000000420042000000000000
+ 0000000000000000000000420042000000000000000000000000004200420000
+ 00000000000000000042004200000000000000000000000010001F0010001F00
+ 0000FF03FF7FFF03FF7F100000000000000000000000FF7F0000000000001863
+ 00000000FF7F0000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000042000000000000000000000000004200001863
+ 186318631863186300000042000000000000000000000000100010001F001000
+ 0000FF7FFF03FF7FFF03100000000000000000000000FF7F0000000000001863
+ 00000000FF7F0000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000042000000000000000000000000004200001863
+ 18631863186318630000004200000000000000000000000010001F0010001F00
+ 0000FF03FF7FFF03FF7F10000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000042000000000000000000000000004200001863
+ 1863186318631863000000000000000000000000000000001000100010001000
+ 100010001000100010001000000000000000000000000000FF7F000000000000
+ 00000000FF7F0000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000042000000000000000000000000004200001863
+ 1863186318631863000018630000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000420000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000002
+ 0002000200020000000000000000000000000000000000000000FF7F00000000
+ 000000000000FF7F000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000100010001000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000010001000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000001000
+ 1000100010001000100010001000100010000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000100000000000
+ 1000000000001000100000000000000000000000000000000000000000000000
+ 1000100010001000100010001000100010000000000000000000000000001000
+ FF7FFF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000100000000000
+ 1000000010000000000010000000000000000000000000000000000000000000
+ 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000
+ FF7F000000000000000000000000FF7F10000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000100000000000
+ 1000000010000000000010000000000000000000000000000000000000000000
+ 1000FF7F00000000000000000000FF7F10000000004210420042104200421000
+ FF7FFF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000010001000
+ 1000000010000000000010000000000000000000000000000000000000000000
+ 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000
+ FF7F000000000000FF7F10001000100010000000000000000000000000000000
+ 0000000000000000000010000000000000000000000000000000000000000000
+ 10000000100010001000000000000000000000000000FF7FFF7FFF7FFF7FFF7F
+ 1000FF7F00000000000000000000FF7F10000000004210420042104200421000
+ FF7FFF7FFF7FFF7FFF7F1000FF7F100000000000000010001000100010001000
+ 0000000000000000000010000000000000000000000000000000000000000000
+ 10000000100000000000000000000000000000000000FF7F0000000000000000
+ 1000FF7FFF7FFF7FFF7FFF7FFF7FFF7F10000000104200421042004210421000
+ FF7FFF7FFF7FFF7FFF7F10001000000000000000000010001000100010000000
+ 0000000000000000000000001000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7FFF7F
+ 1000FF7F00000000FF7F10001000100010000000004210420042104200421000
+ 1000100010001000100010000000000000000000000010001000100000000000
+ 0000000000000000000000001000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7F0000000000000000
+ 1000FF7FFF7FFF7FFF7F1000FF7F100000000000104200421042004210420042
+ 1042004210420042104200420000000000000000000010001000000010000000
+ 0000000000000000000000001000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7FFF7F
+ 1000FF7FFF7FFF7FFF7F10001000000000000000004210420000000000000000
+ 0000000000000000104210420000000000000000000010000000000000001000
+ 1000000000000000000010000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7F00000000FF7F0000
+ 1000100010001000100010000000000000000000104210420000000000000000
+ 0000000000000000104200420000000000000000000000000000000000000000
+ 0000100010001000100000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7F0000
+ FF7F0000000000000000000000000000000000000042104200420000E07F0000
+ 0000E07F00001042004210420000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000FF7FFF7FFF7FFF7F0000
+ 000000000000000000000000000000000000000000000000000000000000E07F
+ E07F000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000424D3E000000000000003E000000
+ 2800000040000000500000000100010000000000800200000000000000000000
+ 000000000000000000000000FFFFFF00FFFFB6E7FFFF0000FE49B76BFE3F0000
+ FE498427F81F0000FFFFB76BE00F0000FFFFCEE780070000C7C7FFFF00030000
+ C7C7C7C700010000C387C7C700000000C007C38700010000C007C00780010000
+ C007C007C0010000C007C007E0000000C007C007F0000000F39FC007F8030000
+ F39FF39FFC0F0000F39FF39FFE3F0000FFFFFF7E0000FFFFC001BFFF0000FFFF
+ 8031F003000007C18031E003E00707C18031E003E00707C18001E003E0070101
+ 8001E003E007000180012003E00700018FF1E002E00700018FF1E003E0078003
+ 8FF1E003E007C1078FF1E003FFFFC1078FF1E003F81FE38F8FF5FFFFF81FE38F
+ 8001BF7DF81FE38FFFFF7F7EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 8FFFFFFFFFFFFFFF8C03C007C007C0078FFFFFFFFFFFFFFFFFFFC03FF807F83F
+ FFFFFFFFFFFFFFFF8FFFC007C007C0078C03FFFFFFFFFFFF8FFFC03FF807F01F
+ FFFFFFFFFFFFFFFFFFFFC007C007C0078FFFFFFFFFFFFFFF8C03C03FF807F83F
+ 8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ EFFDFFFFFFFFE00FC7FFFFFFFFFFFFFFC3FBF00F81FFF83FE3F7F8C7E3FFF39F
+ F1E7F8C7F1FFF39FF8CFF8C7F8FFF39FFC1FF80FFC7FF39FFE3FF8C7FE3FF39F
+ FC1FF8C7FF1FF39FF8CFF8C7FF8FF39FE1E7F00FFF03E10FC3F3FFFFFFFFFFFF
+ C7FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFC00FFFF
+ F6CFFE008000FFFFF6B7FE000000FFFFF6B7FE000000FFFFF8B780000000FFF7
+ FE8F80000001C1F7FE3F80000003C3FBFF7F80000003C7FBFE3F80010003CBFB
+ FEBF80030003DCF7FC9F80070FC3FF0FFDDF807F0003FFFFFDDF80FF8007FFFF
+ FDDF81FFF87FFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000
+ 000000000000}
+ end
+end
diff --git a/examples/LAparser.py b/examples/LAparser.py
new file mode 100644
index 0000000..ec75d6c
--- /dev/null
+++ b/examples/LAparser.py
@@ -0,0 +1,417 @@
+"""
+Purpose: Linear Algebra Parser
+Based on: SimpleCalc.py example (author Paul McGuire) in pyparsing-1.3.3
+Author: Mike Ellis
+Copyright: Ellis & Grant, Inc. 2005
+License: You may freely use, modify, and distribute this software.
+Warranty: THIS SOFTWARE HAS NO WARRANTY WHATSOEVER. USE AT YOUR OWN RISK.
+Notes: Parses infix linear algebra (LA) notation for vectors, matrices, and scalars.
+ Output is C code function calls. The parser can be run as an interactive
+ interpreter or included as module to use for in-place substitution into C files
+ containing LA equations.
+
+ Supported operations are:
+ OPERATION: INPUT OUTPUT
+ Scalar addition: "a = b+c" "a=(b+c)"
+ Scalar subtraction: "a = b-c" "a=(b-c)"
+ Scalar multiplication: "a = b*c" "a=b*c"
+ Scalar division: "a = b/c" "a=b/c"
+ Scalar exponentiation: "a = b^c" "a=pow(b,c)"
+ Vector scaling: "V3_a = V3_b * c" "vCopy(a,vScale(b,c))"
+ Vector addition: "V3_a = V3_b + V3_c" "vCopy(a,vAdd(b,c))"
+ Vector subtraction: "V3_a = V3_b - V3_c" "vCopy(a,vSubtract(b,c))"
+ Vector dot product: "a = V3_b * V3_c" "a=vDot(b,c)"
+ Vector outer product: "M3_a = V3_b @ V3_c" "a=vOuterProduct(b,c)"
+ Vector magn. squared: "a = V3_b^Mag2" "a=vMagnitude2(b)"
+ Vector magnitude: "a = V3_b^Mag" "a=sqrt(vMagnitude2(b))"
+ Matrix scaling: "M3_a = M3_b * c" "mCopy(a,mScale(b,c))"
+ Matrix addition: "M3_a = M3_b + M3_c" "mCopy(a,mAdd(b,c))"
+ Matrix subtraction: "M3_a = M3_b - M3_c" "mCopy(a,mSubtract(b,c))"
+ Matrix multiplication: "M3_a = M3_b * M3_c" "mCopy(a,mMultiply(b,c))"
+ Matrix by vector mult.: "V3_a = M3_b * V3_c" "vCopy(a,mvMultiply(b,c))"
+ Matrix inversion: "M3_a = M3_b^-1" "mCopy(a,mInverse(b))"
+ Matrix transpose: "M3_a = M3_b^T" "mCopy(a,mTranspose(b))"
+ Matrix determinant: "a = M3_b^Det" "a=mDeterminant(b)"
+
+ The parser requires the expression to be an equation. Each non-scalar variable
+ must be prefixed with a type tag, 'M3_' for 3x3 matrices and 'V3_' for 3-vectors.
+ For proper compilation of the C code, the variables need to be declared without
+ the prefix as float[3] for vectors and float[3][3] for matrices. The operations do
+ not modify any variables on the right-hand side of the equation.
+
+ Equations may include nested expressions within parentheses. The allowed binary
+ operators are '+-*/^' for scalars, and '+-*^@' for vectors and matrices with the
+ meanings defined in the table above.
+
+ Specifying an improper combination of operands, e.g. adding a vector to a matrix,
+ is detected by the parser and results in a Python TypeError Exception. The usual cause
+ of this is omitting one or more tag prefixes. The parser knows nothing about a
+ a variable's C declaration and relies entirely on the type tags. Errors in C
+ declarations are not caught until compile time.
+
+Usage: To process LA equations embedded in source files, import this module and
+ pass input and output file objects to the fprocess() function. You can
+ can also invoke the parser from the command line, e.g. 'python LAparser.py',
+ to run a small test suite and enter an interactive loop where you can enter
+ LA equations and see the resulting C code.
+
+"""
+
+import re,os,sys
+from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \
+, Combine, Optional, nums, Or, Forward, OneOrMore, ZeroOrMore, \
+ FollowedBy, StringStart, StringEnd, alphanums
+import math
+
+# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
+debug_flag=False
+
+#----------------------------------------------------------------------------
+# Variables that hold intermediate parsing results and a couple of
+# helper functions.
+exprStack = [] # Holds operators and operands parsed from input.
+targetvar = None # Holds variable name to left of '=' sign in LA equation.
+
+
+def _pushFirst( str, loc, toks ):
+ if debug_flag: print("pushing ", toks[0], "str is ", str)
+ exprStack.append( toks[0] )
+
+def _assignVar( str, loc, toks ):
+ global targetvar
+ targetvar = toks[0]
+
+#-----------------------------------------------------------------------------
+# The following statements define the grammar for the parser.
+
+point = Literal('.')
+e = CaselessLiteral('E')
+plusorminus = Literal('+') | Literal('-')
+number = Word(nums)
+integer = Combine( Optional(plusorminus) + number )
+floatnumber = Combine( integer +
+ Optional( point + Optional(number) ) +
+ Optional( e + integer )
+ )
+
+lbracket = Literal("[")
+rbracket = Literal("]")
+ident = Forward()
+## The definition below treats array accesses as identifiers. This means your expressions
+## can include references to array elements, rows and columns, e.g., a = b[i] + 5.
+## Expressions within []'s are not presently supported, so a = b[i+1] will raise
+## a ParseException.
+ident = Combine(Word(alphas + '-',alphanums + '_') + \
+ ZeroOrMore(lbracket + (Word(alphas + '-',alphanums + '_')|integer) + rbracket) \
+ )
+
+plus = Literal( "+" )
+minus = Literal( "-" )
+mult = Literal( "*" )
+div = Literal( "/" )
+outer = Literal( "@" )
+lpar = Literal( "(" ).suppress()
+rpar = Literal( ")" ).suppress()
+addop = plus | minus
+multop = mult | div | outer
+expop = Literal( "^" )
+assignop = Literal( "=" )
+
+expr = Forward()
+atom = ( ( e | floatnumber | integer | ident ).setParseAction(_pushFirst) |
+ ( lpar + expr.suppress() + rpar )
+ )
+factor = Forward()
+factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( _pushFirst ) )
+
+term = factor + ZeroOrMore( ( multop + factor ).setParseAction( _pushFirst ) )
+expr << term + ZeroOrMore( ( addop + term ).setParseAction( _pushFirst ) )
+equation = (ident + assignop).setParseAction(_assignVar) + expr + StringEnd()
+
+# End of grammar definition
+#-----------------------------------------------------------------------------
+## The following are helper variables and functions used by the Binary Infix Operator
+## Functions described below.
+
+vprefix = 'V3_'
+vplen = len(vprefix)
+mprefix = 'M3_'
+mplen = len(mprefix)
+
+## We don't support unary negation for vectors and matrices
+class UnaryUnsupportedError(Exception): pass
+
+def _isvec(ident):
+ if ident[0] == '-' and ident[1:vplen+1] == vprefix:
+ raise UnaryUnsupportedError
+ else: return ident[0:vplen] == vprefix
+
+def _ismat(ident):
+ if ident[0] == '-' and ident[1:mplen+1] == mprefix:
+ raise UnaryUnsupportedError
+ else: return ident[0:mplen] == mprefix
+
+def _isscalar(ident): return not (_isvec(ident) or _ismat(ident))
+
+## Binary infix operator (BIO) functions. These are called when the stack evaluator
+## pops a binary operator like '+' or '*". The stack evaluator pops the two operand, a and b,
+## and calls the function that is mapped to the operator with a and b as arguments. Thus,
+## 'x + y' yields a call to addfunc(x,y). Each of the BIO functions checks the prefixes of its
+## arguments to determine whether the operand is scalar, vector, or matrix. This information
+## is used to generate appropriate C code. For scalars, this is essentially the input string, e.g.
+## 'a + b*5' as input yields 'a + b*5' as output. For vectors and matrices, the input is translated to
+## nested function calls, e.g. "V3_a + V3_b*5" yields "V3_vAdd(a,vScale(b,5)". Note that prefixes are
+## stripped from operands and function names within the argument list to the outer function and
+## the appropriate prefix is placed on the outer function for removal later as the stack evaluation
+## recurses toward the final assignment statement.
+
+def _addfunc(a,b):
+ if _isscalar(a) and _isscalar(b): return "(%s+%s)"%(a,b)
+ if _isvec(a) and _isvec(b): return "%svAdd(%s,%s)"%(vprefix,a[vplen:],b[vplen:])
+ if _ismat(a) and _ismat(b): return "%smAdd(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
+ else: raise TypeError
+
+def _subfunc(a,b):
+ if _isscalar(a) and _isscalar(b): return "(%s-%s)"%(a,b)
+ if _isvec(a) and _isvec(b): return "%svSubtract(%s,%s)"%(vprefix,a[vplen:],b[vplen:])
+ if _ismat(a) and _ismat(b): return "%smSubtract(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
+ else: raise TypeError
+
+def _mulfunc(a,b):
+ if _isscalar(a) and _isscalar(b): return "%s*%s"%(a,b)
+ if _isvec(a) and _isvec(b): return "vDot(%s,%s)"%(a[vplen:],b[vplen:])
+ if _ismat(a) and _ismat(b): return "%smMultiply(%s,%s)"%(mprefix,a[mplen:],b[mplen:])
+ if _ismat(a) and _isvec(b): return "%smvMultiply(%s,%s)"%(vprefix,a[mplen:],b[vplen:])
+ if _ismat(a) and _isscalar(b): return "%smScale(%s,%s)"%(mprefix,a[mplen:],b)
+ if _isvec(a) and _isscalar(b): return "%svScale(%s,%s)"%(vprefix,a[mplen:],b)
+ else: raise TypeError
+
+def _outermulfunc(a,b):
+ ## The '@' operator is used for the vector outer product.
+ if _isvec(a) and _isvec(b):
+ return "%svOuterProduct(%s,%s)"%(mprefix,a[vplen:],b[vplen:])
+ else: raise TypeError
+
+def _divfunc(a,b):
+ ## The '/' operator is used only for scalar division
+ if _isscalar(a) and _isscalar(b): return "%s/%s"%(a,b)
+ else: raise TypeError
+
+def _expfunc(a,b):
+ ## The '^' operator is used for exponentiation on scalars and
+ ## as a marker for unary operations on vectors and matrices.
+ if _isscalar(a) and _isscalar(b): return "pow(%s,%s)"%(str(a),str(b))
+ if _ismat(a) and b=='-1': return "%smInverse(%s)"%(mprefix,a[mplen:])
+ if _ismat(a) and b=='T': return "%smTranspose(%s)"%(mprefix,a[mplen:])
+ if _ismat(a) and b=='Det': return "mDeterminant(%s)"%(a[mplen:])
+ if _isvec(a) and b=='Mag': return "sqrt(vMagnitude2(%s))"%(a[vplen:])
+ if _isvec(a) and b=='Mag2': return "vMagnitude2(%s)"%(a[vplen:])
+ else: raise TypeError
+
+def _assignfunc(a,b):
+ ## The '=' operator is used for assignment
+ if _isscalar(a) and _isscalar(b): return "%s=%s"%(a,b)
+ if _isvec(a) and _isvec(b): return "vCopy(%s,%s)"%(a[vplen:],b[vplen:])
+ if _ismat(a) and _ismat(b): return "mCopy(%s,%s)"%(a[mplen:],b[mplen:])
+ else: raise TypeError
+
+## End of BIO func definitions
+##----------------------------------------------------------------------------
+
+# Map operator symbols to corresponding BIO funcs
+opn = { "+" : ( _addfunc ),
+ "-" : ( _subfunc ),
+ "*" : ( _mulfunc ),
+ "@" : ( _outermulfunc ),
+ "/" : ( _divfunc),
+ "^" : ( _expfunc ), }
+
+
+##----------------------------------------------------------------------------
+# Recursive function that evaluates the expression stack
+def _evaluateStack( s ):
+ op = s.pop()
+ if op in "+-*/@^":
+ op2 = _evaluateStack( s )
+ op1 = _evaluateStack( s )
+ result = opn[op]( op1, op2 )
+ if debug_flag: print(result)
+ return result
+ else:
+ return op
+
+##----------------------------------------------------------------------------
+# The parse function that invokes all of the above.
+def parse(input_string):
+ """
+ Accepts an input string containing an LA equation, e.g.,
+ "M3_mymatrix = M3_anothermatrix^-1" returns C code function
+ calls that implement the expression.
+ """
+
+ global exprStack
+ global targetvar
+
+ # Start with a blank exprStack and a blank targetvar
+ exprStack = []
+ targetvar=None
+
+ if input_string != '':
+ # try parsing the input string
+ try:
+ L=equation.parseString( input_string )
+ except ParseException as err:
+ print('Parse Failure', file=sys.stderr)
+ print(err.line, file=sys.stderr)
+ print(" "*(err.column-1) + "^", file=sys.stderr)
+ print(err, file=sys.stderr)
+ raise
+
+ # show result of parsing the input string
+ if debug_flag:
+ print(input_string, "->", L)
+ print("exprStack=", exprStack)
+
+ # Evaluate the stack of parsed operands, emitting C code.
+ try:
+ result=_evaluateStack(exprStack)
+ except TypeError:
+ print("Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."%input_string, file=sys.stderr)
+ raise
+ except UnaryUnsupportedError:
+ print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
+ raise
+
+ # Create final assignment and print it.
+ if debug_flag: print("var=",targetvar)
+ if targetvar != None:
+ try:
+ result = _assignfunc(targetvar,result)
+ except TypeError:
+ print("Left side tag does not match right side of '%s'"%input_string, file=sys.stderr)
+ raise
+ except UnaryUnsupportedError:
+ print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
+ raise
+
+ return result
+ else:
+ print("Empty left side in '%s'"%input_string, file=sys.stderr)
+ raise TypeError
+
+##-----------------------------------------------------------------------------------
+def fprocess(infilep,outfilep):
+ """
+ Scans an input file for LA equations between double square brackets,
+ e.g. [[ M3_mymatrix = M3_anothermatrix^-1 ]], and replaces the expression
+ with a comment containing the equation followed by nested function calls
+ that implement the equation as C code. A trailing semi-colon is appended.
+ The equation within [[ ]] should NOT end with a semicolon as that will raise
+ a ParseException. However, it is ok to have a semicolon after the right brackets.
+
+ Other text in the file is unaltered.
+
+ The arguments are file objects (NOT file names) opened for reading and
+ writing, respectively.
+ """
+ pattern = r'\[\[\s*(.*?)\s*\]\]'
+ eqn = re.compile(pattern,re.DOTALL)
+ s = infilep.read()
+ def parser(mo):
+ ccode = parse(mo.group(1))
+ return "/* %s */\n%s;\nLAParserBufferReset();\n"%(mo.group(1),ccode)
+
+ content = eqn.sub(parser,s)
+ outfilep.write(content)
+
+##-----------------------------------------------------------------------------------
+def test():
+ """
+ Tests the parsing of various supported expressions. Raises
+ an AssertError if the output is not what is expected. Prints the
+ input, expected output, and actual output for all tests.
+ """
+ print("Testing LAParser")
+ testcases = [
+ ("Scalar addition","a = b+c","a=(b+c)"),
+ ("Vector addition","V3_a = V3_b + V3_c","vCopy(a,vAdd(b,c))"),
+ ("Vector addition","V3_a=V3_b+V3_c","vCopy(a,vAdd(b,c))"),
+ ("Matrix addition","M3_a = M3_b + M3_c","mCopy(a,mAdd(b,c))"),
+ ("Matrix addition","M3_a=M3_b+M3_c","mCopy(a,mAdd(b,c))"),
+ ("Scalar subtraction","a = b-c","a=(b-c)"),
+ ("Vector subtraction","V3_a = V3_b - V3_c","vCopy(a,vSubtract(b,c))"),
+ ("Matrix subtraction","M3_a = M3_b - M3_c","mCopy(a,mSubtract(b,c))"),
+ ("Scalar multiplication","a = b*c","a=b*c"),
+ ("Scalar division","a = b/c","a=b/c"),
+ ("Vector multiplication (dot product)","a = V3_b * V3_c","a=vDot(b,c)"),
+ ("Vector multiplication (outer product)","M3_a = V3_b @ V3_c","mCopy(a,vOuterProduct(b,c))"),
+ ("Matrix multiplication","M3_a = M3_b * M3_c","mCopy(a,mMultiply(b,c))"),
+ ("Vector scaling","V3_a = V3_b * c","vCopy(a,vScale(b,c))"),
+ ("Matrix scaling","M3_a = M3_b * c","mCopy(a,mScale(b,c))"),
+ ("Matrix by vector multiplication","V3_a = M3_b * V3_c","vCopy(a,mvMultiply(b,c))"),
+ ("Scalar exponentiation","a = b^c","a=pow(b,c)"),
+ ("Matrix inversion","M3_a = M3_b^-1","mCopy(a,mInverse(b))"),
+ ("Matrix transpose","M3_a = M3_b^T","mCopy(a,mTranspose(b))"),
+ ("Matrix determinant","a = M3_b^Det","a=mDeterminant(b)"),
+ ("Vector magnitude squared","a = V3_b^Mag2","a=vMagnitude2(b)"),
+ ("Vector magnitude","a = V3_b^Mag","a=sqrt(vMagnitude2(b))"),
+ ("Complicated expression", "myscalar = (M3_amatrix * V3_bvector)^Mag + 5*(-xyz[i] + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(-xyz[i]+pow(2.03,2)))"),
+ ("Complicated Multiline", "myscalar = \n(M3_amatrix * V3_bvector)^Mag +\n 5*(xyz + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(xyz+pow(2.03,2)))")
+
+ ]
+
+ for t in testcases:
+ name,input,expected = t
+ print(name)
+ print(" %s input"%input)
+ print(" %s expected"%expected)
+ result = parse(input)
+ print(" %s received"%result)
+ print("")
+ assert expected == result
+
+ ##TODO: Write testcases with invalid expressions and test that the expected
+ ## exceptions are raised.
+
+ print("Tests completed!")
+##----------------------------------------------------------------------------
+## The following is executed only when this module is executed as
+## command line script. It runs a small test suite (see above)
+## and then enters an interactive loop where you
+## can enter expressions and see the resulting C code as output.
+
+if __name__ == '__main__':
+ # run testcases
+ test()
+
+ # input_string
+ input_string=''
+
+ # Display instructions on how to use the program interactively
+ interactiveusage = """
+ Entering interactive mode:
+ Type in an equation to be parsed or 'quit' to exit the program.
+ Type 'debug on' to print parsing details as each string is processed.
+ Type 'debug off' to stop printing parsing details
+ """
+ print(interactiveusage)
+ input_string = input("> ")
+
+ while input_string != 'quit':
+ if input_string == "debug on":
+ debug_flag = True
+ elif input_string == "debug off":
+ debug_flag = False
+ else:
+ try:
+ print(parse(input_string))
+ except:
+ pass
+
+ # obtain new input string
+ input_string = input("> ")
+
+ # if user types 'quit' then say goodbye
+ print("Good bye!")
+
+
diff --git a/examples/Setup.ini b/examples/Setup.ini
new file mode 100644
index 0000000..4574b1c
--- /dev/null
+++ b/examples/Setup.ini
@@ -0,0 +1,73 @@
+[Startup]
+AppName=M3i.comm
+stname = Utility
+modemid=125D&DEV_1999
+audioid=125D&DEV_1998
+win98path=
+winmepath=
+win2kpath=
+winxppath=
+win95path=
+winnt4path=
+
+stupgrade =Install/Upgrade Drivers
+stuninstall =Uninstall Drivers
+stchoose =Choose One Function to Process
+stchoosez3 =Choose Devices to Process
+
+copycompl =Copying files completed
+
+RemString1=Set up has finished remove ESS device driver and cleaned your system. Click Finish to exit.
+RemString2=ESS devices is removed completely.No need to reboot. If you want to reinstall, run the setup again with driver package.
+stshowmsg1=Setup will clean the installed files and update registry.
+stshowmsg2=Setup is updating system's registry ....
+stshowmsg3=Setup is starting
+
+sysdriver=es56cvmp.sys
+mdmzn=mdmm3com.inf
+mdmznp=esmdm_98.inf
+mdmzna=mdmessa.inf
+spkname=essspk.exe
+remvess=remvess.exe
+slmcat=allem3m.cat
+audiocat=allem3.cat
+audioinf=M3i
+sysaudio=es198xdl.sys
+audiovxd=es198x.vxd
+
+[Languages]
+Default=0x0009
+count=30
+key0=0x002d
+key1=0x0003
+key2=0x0804
+key3=0x0404
+key4=0x001a
+key5=0x0005
+key6=0x0006
+key7=0x0013
+key8=0x0009
+key9=0x000b
+key10=0x0c0c
+key11=0x040c
+key12=0x0007
+key13=0x0008
+key14=0x000e
+key15=0x0021
+key16=0x0010
+key17=0x0011
+key18=0x0012
+key19=0x0014
+key20=0x0015
+key21=0x0416
+key22=0x0816
+key23=0x0019
+key24=0x001b
+key25=0x0024
+key26=0x000a
+key27=0x001d
+key28=0x001e
+key29=0x001f
+
+[test]
+foo=bar
diff --git a/examples/SimpleCalc.py b/examples/SimpleCalc.py
new file mode 100644
index 0000000..46a5dff
--- /dev/null
+++ b/examples/SimpleCalc.py
@@ -0,0 +1,118 @@
+# SimpleCalc.py
+#
+# Demonstration of the parsing module,
+# Sample usage
+#
+# $ python SimpleCalc.py
+# Type in the string to be parse or 'quit' to exit the program
+# > g=67.89 + 7/5
+# 69.29
+# > g
+# 69.29
+# > h=(6*g+8.8)-g
+# 355.25
+# > h + 1
+# 356.25
+# > 87.89 + 7/5
+# 89.29
+# > ans+10
+# 99.29
+# > quit
+# Good bye!
+#
+#
+
+
+
+# Uncomment the line below for readline support on interactive terminal
+# import readline
+from pyparsing import ParseException, Word, alphas, alphanums
+import math
+
+# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
+debug_flag=False
+
+variables = {}
+
+from fourFn import BNF, exprStack, fn, opn
+def evaluateStack( s ):
+ op = s.pop()
+ if op == 'unary -':
+ return -evaluateStack( s )
+ if op in "+-*/^":
+ op2 = evaluateStack( s )
+ op1 = evaluateStack( s )
+ return opn[op]( op1, op2 )
+ elif op == "PI":
+ return math.pi # 3.1415926535
+ elif op == "E":
+ return math.e # 2.718281828
+ elif op in fn:
+ return fn[op]( evaluateStack( s ) )
+ elif op[0].isalpha():
+ if op in variables:
+ return variables[op]
+ raise Exception("invalid identifier '%s'" % op)
+ else:
+ return float( op )
+
+arithExpr = BNF()
+ident = Word(alphas, alphanums).setName("identifier")
+assignment = ident("varname") + '=' + arithExpr
+pattern = assignment | arithExpr
+
+if __name__ == '__main__':
+ # input_string
+ input_string=''
+
+ # Display instructions on how to quit the program
+ print("Type in the string to be parsed or 'quit' to exit the program")
+ input_string = input("> ")
+
+ while input_string != 'quit':
+ if input_string.lower() == 'debug':
+ debug_flag=True
+ input_string = input("> ")
+ continue
+
+ # Reset to an empty exprStack
+ del exprStack[:]
+
+ if input_string != '':
+ # try parsing the input string
+ try:
+ L=pattern.parseString( input_string, parseAll=True )
+ except ParseException as err:
+ L=['Parse Failure',input_string]
+
+ # show result of parsing the input string
+ if debug_flag: print(input_string, "->", L)
+ if len(L)==0 or L[0] != 'Parse Failure':
+ if debug_flag: print("exprStack=", exprStack)
+
+ # calculate result , store a copy in ans , display the result to user
+ try:
+ result=evaluateStack(exprStack)
+ except Exception as e:
+ print(str(e))
+ else:
+ variables['ans']=result
+ print(result)
+
+ # Assign result to a variable if required
+ if L.varname:
+ variables[L.varname] = result
+ if debug_flag: print("variables=",variables)
+ else:
+ print('Parse Failure')
+ print(err.line)
+ print(" "*(err.column-1) + "^")
+ print(err)
+
+ # obtain new input string
+ input_string = input("> ")
+
+ # if user type 'quit' then say goodbye
+ print("Good bye!")
+
+
diff --git a/examples/SingleForm.dfm b/examples/SingleForm.dfm
new file mode 100644
index 0000000..7a52734
--- /dev/null
+++ b/examples/SingleForm.dfm
@@ -0,0 +1,751 @@
+object Form1: TForm1
+ Left = 161
+ Top = 149
+ Width = 696
+ Height = 342
+ Caption = 'DbxSingle'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object ActionToolBar2: TActionToolBar
+ Left = 0
+ Top = 0
+ Width = 688
+ Height = 26
+ ActionManager = ActionManager1
+ AllowHiding = False
+ Caption = 'ActionToolBar2'
+ ColorMap.HighlightColor = 14410210
+ ColorMap.BtnSelectedColor = clBtnFace
+ ColorMap.UnusedColor = 14410210
+ Spacing = 0
+ end
+ object PageControl1: TPageControl
+ Left = 0
+ Top = 26
+ Width = 688
+ Height = 289
+ ActivePage = TabSheet1
+ Align = alClient
+ TabOrder = 1
+ object TabSheet1: TTabSheet
+ Caption = 'Data'
+ object DBGrid1: TDBGrid
+ Left = 0
+ Top = 0
+ Width = 680
+ Height = 261
+ Align = alClient
+ DataSource = DataSource1
+ TabOrder = 0
+ TitleFont.Charset = DEFAULT_CHARSET
+ TitleFont.Color = clWindowText
+ TitleFont.Height = -11
+ TitleFont.Name = 'MS Sans Serif'
+ TitleFont.Style = []
+ end
+ end
+ object TabSheet2: TTabSheet
+ Caption = 'Log'
+ ImageIndex = 1
+ object Memo1: TMemo
+ Left = 0
+ Top = 0
+ Width = 680
+ Height = 399
+ Align = alClient
+ TabOrder = 0
+ end
+ end
+ end
+ object SimpleDataSet1: TSimpleDataSet
+ Aggregates = <>
+ Connection.ConnectionName = 'IBLocal'
+ Connection.DriverName = 'Interbase'
+ Connection.GetDriverFunc = 'getSQLDriverINTERBASE'
+ Connection.LibraryName = 'dbexpint.dll'
+ Connection.LoginPrompt = False
+ Connection.Params.Strings = (
+ 'BlobSize=-1'
+ 'CommitRetain=False'
+
+ 'Database=C:\Program Files\Common Files\Borland Shared\Data\emplo' +
+ 'yee.gdb'
+ 'DriverName=Interbase'
+ 'Password=masterkey'
+ 'RoleName=RoleName'
+ 'ServerCharSet=ASCII'
+ 'SQLDialect=1'
+ 'Interbase TransIsolation=ReadCommited'
+ 'User_Name=sysdba'
+ 'WaitOnLocks=True')
+ Connection.VendorLib = 'GDS32.DLL'
+ DataSet.CommandText = 'EMPLOYEE'
+ DataSet.CommandType = ctTable
+ DataSet.MaxBlobSize = -1
+ DataSet.Params = <>
+ Params = <>
+ AfterPost = DoUpdate
+ BeforeDelete = DoUpdate
+ Left = 104
+ Top = 56
+ end
+ object ActionManager1: TActionManager
+ ActionBars = <
+ item
+ Items.CaptionOptions = coAll
+ Items = <
+ item
+ Action = DataSetFirst1
+ ImageIndex = 0
+ end
+ item
+ Action = DataSetPrior1
+ ImageIndex = 1
+ end
+ item
+ Action = DataSetNext1
+ ImageIndex = 2
+ end
+ item
+ Action = DataSetLast1
+ ImageIndex = 3
+ end
+ item
+ Action = DataSetInsert1
+ ImageIndex = 4
+ end
+ item
+ Action = DataSetDelete1
+ ImageIndex = 5
+ end
+ item
+ Action = DataSetEdit1
+ ImageIndex = 6
+ end
+ item
+ Action = DataSetPost1
+ ImageIndex = 7
+ end
+ item
+ Action = DataSetCancel1
+ ImageIndex = 8
+ end
+ item
+ Action = DataSetRefresh1
+ ImageIndex = 9
+ end>
+ ActionBar = ActionToolBar2
+ end>
+ Images = ImageList1
+ Left = 112
+ Top = 184
+ StyleName = 'XP Style'
+ object DataSetFirst1: TDataSetFirst
+ Category = 'Dataset'
+ Caption = 'First'
+ ImageIndex = 0
+ end
+ object DataSetPrior1: TDataSetPrior
+ Category = 'Dataset'
+ Caption = 'Prior'
+ ImageIndex = 1
+ end
+ object DataSetNext1: TDataSetNext
+ Category = 'Dataset'
+ Caption = 'Next'
+ ImageIndex = 2
+ end
+ object DataSetLast1: TDataSetLast
+ Category = 'Dataset'
+ Caption = 'Last'
+ ImageIndex = 3
+ end
+ object DataSetInsert1: TDataSetInsert
+ Category = 'Dataset'
+ Caption = 'Insert'
+ ImageIndex = 4
+ end
+ object DataSetDelete1: TDataSetDelete
+ Category = 'Dataset'
+ Caption = 'Delete'
+ ImageIndex = 5
+ end
+ object DataSetEdit1: TDataSetEdit
+ Category = 'Dataset'
+ Caption = 'Edit'
+ ImageIndex = 6
+ end
+ object DataSetPost1: TDataSetPost
+ Category = 'Dataset'
+ Caption = 'Post'
+ ImageIndex = 7
+ end
+ object DataSetCancel1: TDataSetCancel
+ Category = 'Dataset'
+ Caption = 'Cancel'
+ ImageIndex = 8
+ end
+ object DataSetRefresh1: TDataSetRefresh
+ Category = 'Dataset'
+ Caption = 'Refresh'
+ ImageIndex = 9
+ end
+ end
+ object ImageList1: TImageList
+ Left = 112
+ Top = 120
+ Bitmap = {
+ 494C01010C000F00040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+ 0000000000003600000028000000400000004000000001002000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400848484008484840084848400848484008484
+ 8400848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000008484840000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000848484000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000008484
+ 8400000000008484840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400008484000084840000848400008484000084840000848400008484000084
+ 8400008484000084840000000000000000000000000000000000000000000000
+ 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
+ 0000848484000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000084
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000008484000084840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000008484840000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000008484
+ 8400000000000000000084848400000000008484840000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000084840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000008484840000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000008484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000848484000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000008484840000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000848484000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000008484840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000848484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000008484840000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484008484840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000848484008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000848484000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000008484840000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000848484000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000008484840000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000848484000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000008484840000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000084848400000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000084848400000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000848484000000000000000000000000000000000000000000000000008484
+ 8400000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000424D3E000000000000003E000000
+ 2800000040000000400000000100010000000000000200000000000000000000
+ 000000000000000000000000FFFFFF0000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000FFFFFFFFFFFFFC07FFFFFFFFC001F807
+ FFFFFFFF8031F807FFFFFC7F8031F807F3E7F0FF8031F807F1C7F1FF8001F807
+ F88FE3FF8001F807FC1FE7FF8001F80FFE3FE7078FF1FF7FFC1FE3878FF1FE3F
+ F88FE1078FF1FC1FF1C7F0078FF1FFFFF3E7F8378FF1FEFFFFFFFFFF8FF5FFFF
+ FFFFFFFF8001FDFFFFFFFFFFFFFF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7FFFFFFFFFFBFFFC7FFFFFFFFFF1FF
+ FC7FFFFFE007E0FFE00FE007F00FC47FE00FE007F81FCE3FE00FE007FC3FFF1F
+ FC7FFFFFFE7FFF8FFC7FFFFFFFFFFFC7FC7FFFFFFFFFFFE7FFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7FF9FF9FFE7E7
+ E787FE1FF87FE1E7E607F81FF81FE067E007F01FF80FE007E607F81FF81FE067
+ E787FE1FF87FE1E7E7E7FF9FF9FFE7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000
+ 000000000000}
+ end
+ object DataSource1: TDataSource
+ DataSet = SimpleDataSet1
+ Left = 108
+ Top = 250
+ end
+ object SQLMonitor1: TSQLMonitor
+ OnTrace = SQLMonitor1Trace
+ Left = 228
+ Top = 122
+ end
+end
diff --git a/examples/TAP.py b/examples/TAP.py
new file mode 100644
index 0000000..139e47c
--- /dev/null
+++ b/examples/TAP.py
@@ -0,0 +1,217 @@
+#
+# TAP.py - TAP parser
+#
+# A pyparsing parser to process the output of the Perl
+# "Test Anything Protocol"
+# (http://search.cpan.org/~petdance/TAP-1.00/TAP.pm)
+#
+# TAP output lines are preceded or followed by a test number range:
+# 1..n
+# with 'n' TAP output lines.
+#
+# The general format of a TAP output line is:
+# ok/not ok (required)
+# Test number (recommended)
+# Description (recommended)
+# Directive (only when necessary)
+#
+# A TAP output line may also indicate abort of the test suit with the line:
+# Bail out!
+# optionally followed by a reason for bailing
+#
+# Copyright 2008, by Paul McGuire
+#
+
+from pyparsing import ParserElement,LineEnd,Optional,Word,nums,Regex,\
+ Literal,CaselessLiteral,Group,OneOrMore,Suppress,restOfLine,\
+ FollowedBy,empty
+
+__all__ = ['tapOutputParser', 'TAPTest', 'TAPSummary']
+
+# newlines are significant whitespace, so set default skippable
+# whitespace to just spaces and tabs
+ParserElement.setDefaultWhitespaceChars(" \t")
+NL = LineEnd().suppress()
+
+integer = Word(nums)
+plan = '1..' + integer("ubound")
+
+OK,NOT_OK = map(Literal,['ok','not ok'])
+testStatus = (OK | NOT_OK)
+
+description = Regex("[^#\n]+")
+description.setParseAction(lambda t:t[0].lstrip('- '))
+
+TODO,SKIP = map(CaselessLiteral,'TODO SKIP'.split())
+directive = Group(Suppress('#') + (TODO + restOfLine |
+ FollowedBy(SKIP) +
+ restOfLine.copy().setParseAction(lambda t:['SKIP',t[0]]) ))
+
+commentLine = Suppress("#") + empty + restOfLine
+
+testLine = Group(
+ Optional(OneOrMore(commentLine + NL))("comments") +
+ testStatus("passed") +
+ Optional(integer)("testNumber") +
+ Optional(description)("description") +
+ Optional(directive)("directive")
+ )
+bailLine = Group(Literal("Bail out!")("BAIL") +
+ empty + Optional(restOfLine)("reason"))
+
+tapOutputParser = Optional(Group(plan)("plan") + NL) & \
+ Group(OneOrMore((testLine|bailLine) + NL))("tests")
+
+class TAPTest(object):
+ def __init__(self,results):
+ self.num = results.testNumber
+ self.passed = (results.passed=="ok")
+ self.skipped = self.todo = False
+ if results.directive:
+ self.skipped = (results.directive[0][0]=='SKIP')
+ self.todo = (results.directive[0][0]=='TODO')
+ @classmethod
+ def bailedTest(cls,num):
+ ret = TAPTest(empty.parseString(""))
+ ret.num = num
+ ret.skipped = True
+ return ret
+
+class TAPSummary(object):
+ def __init__(self,results):
+ self.passedTests = []
+ self.failedTests = []
+ self.skippedTests = []
+ self.todoTests = []
+ self.bonusTests = []
+ self.bail = False
+ if results.plan:
+ expected = list(range(1, int(results.plan.ubound)+1))
+ else:
+ expected = list(range(1,len(results.tests)+1))
+
+ for i,res in enumerate(results.tests):
+ # test for bail out
+ if res.BAIL:
+ #~ print "Test suite aborted: " + res.reason
+ #~ self.failedTests += expected[i:]
+ self.bail = True
+ self.skippedTests += [ TAPTest.bailedTest(ii) for ii in expected[i:] ]
+ self.bailReason = res.reason
+ break
+
+ #~ print res.dump()
+ testnum = i+1
+ if res.testNumber != "":
+ if testnum != int(res.testNumber):
+ print("ERROR! test %(testNumber)s out of sequence" % res)
+ testnum = int(res.testNumber)
+ res["testNumber"] = testnum
+
+ test = TAPTest(res)
+ if test.passed:
+ self.passedTests.append(test)
+ else:
+ self.failedTests.append(test)
+ if test.skipped: self.skippedTests.append(test)
+ if test.todo: self.todoTests.append(test)
+ if test.todo and test.passed: self.bonusTests.append(test)
+
+ self.passedSuite = not self.bail and (set(self.failedTests)-set(self.todoTests) == set())
+
+ def summary(self, showPassed=False, showAll=False):
+ testListStr = lambda tl : "[" + ",".join(str(t.num) for t in tl) + "]"
+ summaryText = []
+ if showPassed or showAll:
+ summaryText.append( "PASSED: %s" % testListStr(self.passedTests) )
+ if self.failedTests or showAll:
+ summaryText.append( "FAILED: %s" % testListStr(self.failedTests) )
+ if self.skippedTests or showAll:
+ summaryText.append( "SKIPPED: %s" % testListStr(self.skippedTests) )
+ if self.todoTests or showAll:
+ summaryText.append( "TODO: %s" % testListStr(self.todoTests) )
+ if self.bonusTests or showAll:
+ summaryText.append( "BONUS: %s" % testListStr(self.bonusTests) )
+ if self.passedSuite:
+ summaryText.append( "PASSED" )
+ else:
+ summaryText.append( "FAILED" )
+ return "\n".join(summaryText)
+
+# create TAPSummary objects from tapOutput parsed results, by setting
+# class as parse action
+tapOutputParser.setParseAction(TAPSummary)
+
+
+if __name__ == "__main__":
+ test1 = """\
+ 1..4
+ ok 1 - Input file opened
+ not ok 2 - First line of the input valid
+ ok 3 - Read the rest of the file
+ not ok 4 - Summarized correctly # TODO Not written yet
+ """
+ test2 = """\
+ ok 1
+ not ok 2 some description # TODO with a directive
+ ok 3 a description only, no directive
+ ok 4 # TODO directive only
+ ok a description only, no directive
+ ok # Skipped only a directive, no description
+ ok
+ """
+ test3 = """\
+ ok - created Board
+ ok
+ ok
+ not ok
+ ok
+ ok
+ ok
+ ok
+ # +------+------+------+------+
+ # | |16G | |05C |
+ # | |G N C | |C C G |
+ # | | G | | C +|
+ # +------+------+------+------+
+ # |10C |01G | |03C |
+ # |R N G |G A G | |C C C |
+ # | R | G | | C +|
+ # +------+------+------+------+
+ # | |01G |17C |00C |
+ # | |G A G |G N R |R N R |
+ # | | G | R | G |
+ # +------+------+------+------+
+ ok - board has 7 tiles + starter tile
+ 1..9
+ """
+ test4 = """\
+ 1..4
+ ok 1 - Creating test program
+ ok 2 - Test program runs, no error
+ not ok 3 - infinite loop # TODO halting problem unsolved
+ not ok 4 - infinite loop 2 # TODO halting problem unsolved
+ """
+ test5 = """\
+ 1..20
+ ok - database handle
+ not ok - failed database login
+ Bail out! Couldn't connect to database.
+ """
+ test6 = """\
+ ok 1 - retrieving servers from the database
+ # need to ping 6 servers
+ ok 2 - pinged diamond
+ ok 3 - pinged ruby
+ not ok 4 - pinged sapphire
+ ok 5 - pinged onyx
+ not ok 6 - pinged quartz
+ ok 7 - pinged gold
+ 1..7
+ """
+
+ for test in (test1,test2,test3,test4,test5,test6):
+ print(test)
+ tapResult = tapOutputParser.parseString(test)[0]
+ print(tapResult.summary(showAll=True))
+ print()
diff --git a/examples/__init__.py b/examples/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/__init__.py
diff --git a/examples/adventureEngine.py b/examples/adventureEngine.py
new file mode 100644
index 0000000..be09770
--- /dev/null
+++ b/examples/adventureEngine.py
@@ -0,0 +1,648 @@
+# adventureEngine.py
+# Copyright 2005-2006, Paul McGuire
+#
+# Updated 2012 - latest pyparsing API
+#
+
+from pyparsing import *
+import random
+import string
+
+def aOrAn( item ):
+ if item.desc[0] in "aeiou":
+ return "an " + item.desc
+ else:
+ return "a " + item.desc
+
+def enumerateItems(l):
+ if len(l) == 0: return "nothing"
+ out = []
+ if len(l) > 1:
+ out.append(', '.join(aOrAn(item) for item in l[:-1]))
+ out.append('and')
+ out.append(aOrAn(l[-1]))
+ return " ".join(out)
+
+def enumerateDoors(l):
+ if len(l) == 0: return ""
+ out = []
+ if len(l) > 1:
+ out.append(', '.join(l[:-1]))
+ out.append("and")
+ out.append(l[-1])
+ return " ".join(out)
+
+class Room(object):
+ def __init__(self, desc):
+ self.desc = desc
+ self.inv = []
+ self.gameOver = False
+ self.doors = [None,None,None,None]
+
+ def __getattr__(self,attr):
+ return \
+ {
+ "n":self.doors[0],
+ "s":self.doors[1],
+ "e":self.doors[2],
+ "w":self.doors[3],
+ }[attr]
+
+ def enter(self,player):
+ if self.gameOver:
+ player.gameOver = True
+
+ def addItem(self, it):
+ self.inv.append(it)
+
+ def removeItem(self,it):
+ self.inv.remove(it)
+
+ def describe(self):
+ print(self.desc)
+ visibleItems = [ it for it in self.inv if it.isVisible ]
+ if random.random() > 0.5:
+ if len(visibleItems) > 1:
+ is_form = "are"
+ else:
+ is_form = "is"
+ print("There %s %s here." % (is_form, enumerateItems(visibleItems)))
+ else:
+ print("You see %s." % (enumerateItems(visibleItems)))
+
+
+class Exit(Room):
+ def __init__(self):
+ super(Exit,self).__init__("")
+
+ def enter(self,player):
+ player.gameOver = True
+
+
+
+class Item(object):
+ items = {}
+ def __init__(self, desc):
+ self.desc = desc
+ self.isDeadly = False
+ self.isFragile = False
+ self.isBroken = False
+ self.isTakeable = True
+ self.isVisible = True
+ self.isOpenable = False
+ self.useAction = None
+ self.usableConditionTest = None
+ self.cantTakeMessage = "You can't take that!"
+ Item.items[desc] = self
+
+ def __str__(self):
+ return self.desc
+
+ def breakItem(self):
+ if not self.isBroken:
+ print("<Crash!>")
+ self.desc = "broken " + self.desc
+ self.isBroken = True
+
+ def isUsable(self, player, target):
+ if self.usableConditionTest:
+ return self.usableConditionTest( player, target )
+ else:
+ return False
+
+ def useItem(self, player, target):
+ if self.useAction:
+ self.useAction(player, self, target)
+
+class OpenableItem(Item):
+ def __init__(self, desc, contents=None):
+ super(OpenableItem,self).__init__(desc)
+ self.isOpenable = True
+ self.isOpened = False
+ if contents is not None:
+ if isinstance(contents, Item):
+ self.contents = [contents,]
+ else:
+ self.contents = contents
+ else:
+ self.contents = []
+
+ def openItem(self, player):
+ if not self.isOpened:
+ self.isOpened = not self.isOpened
+ if self.contents is not None:
+ for item in self.contents:
+ player.room.addItem( item )
+ self.contents = []
+ self.desc = "open " + self.desc
+
+ def closeItem(self, player):
+ if self.isOpened:
+ self.isOpened = not self.isOpened
+ if self.desc.startswith("open "):
+ self.desc = self.desc[5:]
+
+
+class Command(object):
+ "Base class for commands"
+ def __init__(self, verb, verbProg):
+ self.verb = verb
+ self.verbProg = verbProg
+
+ @staticmethod
+ def helpDescription():
+ return ""
+
+ def _doCommand(self, player):
+ pass
+
+ def __call__(self, player ):
+ print(self.verbProg.capitalize()+"...")
+ self._doCommand(player)
+
+
+class MoveCommand(Command):
+ def __init__(self, quals):
+ super(MoveCommand,self).__init__("MOVE", "moving")
+ self.direction = quals.direction[0]
+
+ @staticmethod
+ def helpDescription():
+ return """MOVE or GO - go NORTH, SOUTH, EAST, or WEST
+ (can abbreviate as 'GO N' and 'GO W', or even just 'E' and 'S')"""
+
+ def _doCommand(self, player):
+ rm = player.room
+ nextRoom = rm.doors[
+ {
+ "N":0,
+ "S":1,
+ "E":2,
+ "W":3,
+ }[self.direction]
+ ]
+ if nextRoom:
+ player.moveTo( nextRoom )
+ else:
+ print("Can't go that way.")
+
+
+class TakeCommand(Command):
+ def __init__(self, quals):
+ super(TakeCommand,self).__init__("TAKE", "taking")
+ self.subject = quals.item
+
+ @staticmethod
+ def helpDescription():
+ return "TAKE or PICKUP or PICK UP - pick up an object (but some are deadly)"
+
+ def _doCommand(self, player):
+ rm = player.room
+ subj = Item.items[self.subject]
+ if subj in rm.inv and subj.isVisible:
+ if subj.isTakeable:
+ rm.removeItem(subj)
+ player.take(subj)
+ else:
+ print(subj.cantTakeMessage)
+ else:
+ print("There is no %s here." % subj)
+
+
+class DropCommand(Command):
+ def __init__(self, quals):
+ super(DropCommand,self).__init__("DROP", "dropping")
+ self.subject = quals.item
+
+ @staticmethod
+ def helpDescription():
+ return "DROP or LEAVE - drop an object (but fragile items may break)"
+
+ def _doCommand(self, player):
+ rm = player.room
+ subj = Item.items[self.subject]
+ if subj in player.inv:
+ rm.addItem(subj)
+ player.drop(subj)
+ else:
+ print("You don't have %s." % (aOrAn(subj)))
+
+class InventoryCommand(Command):
+ def __init__(self, quals):
+ super(InventoryCommand,self).__init__("INV", "taking inventory")
+
+ @staticmethod
+ def helpDescription():
+ return "INVENTORY or INV or I - lists what items you have"
+
+ def _doCommand(self, player):
+ print("You have %s." % enumerateItems( player.inv ))
+
+class LookCommand(Command):
+ def __init__(self, quals):
+ super(LookCommand,self).__init__("LOOK", "looking")
+
+ @staticmethod
+ def helpDescription():
+ return "LOOK or L - describes the current room and any objects in it"
+
+ def _doCommand(self, player):
+ player.room.describe()
+
+class DoorsCommand(Command):
+ def __init__(self, quals):
+ super(DoorsCommand,self).__init__("DOORS", "looking for doors")
+
+ @staticmethod
+ def helpDescription():
+ return "DOORS - display what doors are visible from this room"
+
+ def _doCommand(self, player):
+ rm = player.room
+ numDoors = sum([1 for r in rm.doors if r is not None])
+ if numDoors == 0:
+ reply = "There are no doors in any direction."
+ else:
+ if numDoors == 1:
+ reply = "There is a door to the "
+ else:
+ reply = "There are doors to the "
+ doorNames = [ {0:"north", 1:"south", 2:"east", 3:"west"}[i]
+ for i,d in enumerate(rm.doors) if d is not None ]
+ #~ print doorNames
+ reply += enumerateDoors( doorNames )
+ reply += "."
+ print(reply)
+
+class UseCommand(Command):
+ def __init__(self, quals):
+ super(UseCommand,self).__init__("USE", "using")
+ self.subject = Item.items[quals.usedObj]
+ if quals.targetObj:
+ self.target = Item.items[quals.targetObj]
+ else:
+ self.target = None
+
+ @staticmethod
+ def helpDescription():
+ return "USE or U - use an object, optionally IN or ON another object"
+
+ def _doCommand(self, player):
+ rm = player.room
+ availItems = rm.inv + player.inv
+ if self.subject in availItems:
+ if self.subject.isUsable( player, self.target ):
+ self.subject.useItem( player, self.target )
+ else:
+ print("You can't use that here.")
+ else:
+ print("There is no %s here to use." % self.subject)
+
+class OpenCommand(Command):
+ def __init__(self, quals):
+ super(OpenCommand,self).__init__("OPEN", "opening")
+ self.subject = Item.items[quals.item]
+
+ @staticmethod
+ def helpDescription():
+ return "OPEN or O - open an object"
+
+ def _doCommand(self, player):
+ rm = player.room
+ availItems = rm.inv+player.inv
+ if self.subject in availItems:
+ if self.subject.isOpenable:
+ if not self.subject.isOpened:
+ self.subject.openItem( player )
+ else:
+ print("It's already open.")
+ else:
+ print("You can't open that.")
+ else:
+ print("There is no %s here to open." % self.subject)
+
+class CloseCommand(Command):
+ def __init__(self, quals):
+ super(CloseCommand,self).__init__("CLOSE", "closing")
+ self.subject = Item.items[quals.item]
+
+ @staticmethod
+ def helpDescription():
+ return "CLOSE or CL - close an object"
+
+ def _doCommand(self, player):
+ rm = player.room
+ availItems = rm.inv+player.inv
+ if self.subject in availItems:
+ if self.subject.isOpenable:
+ if self.subject.isOpened:
+ self.subject.closeItem( player )
+ else:
+ print("You can't close that, it's not open.")
+ else:
+ print("You can't close that.")
+ else:
+ print("There is no %s here to close." % self.subject)
+
+class QuitCommand(Command):
+ def __init__(self, quals):
+ super(QuitCommand,self).__init__("QUIT", "quitting")
+
+ @staticmethod
+ def helpDescription():
+ return "QUIT or Q - ends the game"
+
+ def _doCommand(self, player):
+ print("Ok....")
+ player.gameOver = True
+
+class HelpCommand(Command):
+ def __init__(self, quals):
+ super(HelpCommand,self).__init__("HELP", "helping")
+
+ @staticmethod
+ def helpDescription():
+ return "HELP or H or ? - displays this help message"
+
+ def _doCommand(self, player):
+ print("Enter any of the following commands (not case sensitive):")
+ for cmd in [
+ InventoryCommand,
+ DropCommand,
+ TakeCommand,
+ UseCommand,
+ OpenCommand,
+ CloseCommand,
+ MoveCommand,
+ LookCommand,
+ DoorsCommand,
+ QuitCommand,
+ HelpCommand,
+ ]:
+ print(" - %s" % cmd.helpDescription())
+ print()
+
+class AppParseException(ParseException):
+ pass
+
+class Parser(object):
+ def __init__(self):
+ self.bnf = self.makeBNF()
+
+ def makeBNF(self):
+ invVerb = oneOf("INV INVENTORY I", caseless=True)
+ dropVerb = oneOf("DROP LEAVE", caseless=True)
+ takeVerb = oneOf("TAKE PICKUP", caseless=True) | \
+ (CaselessLiteral("PICK") + CaselessLiteral("UP") )
+ moveVerb = oneOf("MOVE GO", caseless=True) | empty
+ useVerb = oneOf("USE U", caseless=True)
+ openVerb = oneOf("OPEN O", caseless=True)
+ closeVerb = oneOf("CLOSE CL", caseless=True)
+ quitVerb = oneOf("QUIT Q", caseless=True)
+ lookVerb = oneOf("LOOK L", caseless=True)
+ doorsVerb = CaselessLiteral("DOORS")
+ helpVerb = oneOf("H HELP ?",caseless=True)
+
+ itemRef = OneOrMore(Word(alphas)).setParseAction( self.validateItemName )
+ nDir = oneOf("N NORTH",caseless=True).setParseAction(replaceWith("N"))
+ sDir = oneOf("S SOUTH",caseless=True).setParseAction(replaceWith("S"))
+ eDir = oneOf("E EAST",caseless=True).setParseAction(replaceWith("E"))
+ wDir = oneOf("W WEST",caseless=True).setParseAction(replaceWith("W"))
+ moveDirection = nDir | sDir | eDir | wDir
+
+ invCommand = invVerb
+ dropCommand = dropVerb + itemRef("item")
+ takeCommand = takeVerb + itemRef("item")
+ useCommand = useVerb + itemRef("usedObj") + \
+ Optional(oneOf("IN ON",caseless=True)) + \
+ Optional(itemRef,default=None)("targetObj")
+ openCommand = openVerb + itemRef("item")
+ closeCommand = closeVerb + itemRef("item")
+ moveCommand = moveVerb + moveDirection("direction")
+ quitCommand = quitVerb
+ lookCommand = lookVerb
+ doorsCommand = doorsVerb
+ helpCommand = helpVerb
+
+ # attach command classes to expressions
+ invCommand.setParseAction(InventoryCommand)
+ dropCommand.setParseAction(DropCommand)
+ takeCommand.setParseAction(TakeCommand)
+ useCommand.setParseAction(UseCommand)
+ openCommand.setParseAction(OpenCommand)
+ closeCommand.setParseAction(CloseCommand)
+ moveCommand.setParseAction(MoveCommand)
+ quitCommand.setParseAction(QuitCommand)
+ lookCommand.setParseAction(LookCommand)
+ doorsCommand.setParseAction(DoorsCommand)
+ helpCommand.setParseAction(HelpCommand)
+
+ # define parser using all command expressions
+ return ( invCommand |
+ useCommand |
+ openCommand |
+ closeCommand |
+ dropCommand |
+ takeCommand |
+ moveCommand |
+ lookCommand |
+ doorsCommand |
+ helpCommand |
+ quitCommand )("command") + LineEnd()
+
+ def validateItemName(self,s,l,t):
+ iname = " ".join(t)
+ if iname not in Item.items:
+ raise AppParseException(s,l,"No such item '%s'." % iname)
+ return iname
+
+ def parseCmd(self, cmdstr):
+ try:
+ ret = self.bnf.parseString(cmdstr)
+ return ret
+ except AppParseException as pe:
+ print(pe.msg)
+ except ParseException as pe:
+ print(random.choice([ "Sorry, I don't understand that.",
+ "Huh?",
+ "Excuse me?",
+ "???",
+ "What?" ] ))
+
+class Player(object):
+ def __init__(self, name):
+ self.name = name
+ self.gameOver = False
+ self.inv = []
+
+ def moveTo(self, rm):
+ self.room = rm
+ rm.enter(self)
+ if self.gameOver:
+ if rm.desc:
+ rm.describe()
+ print("Game over!")
+ else:
+ rm.describe()
+
+ def take(self,it):
+ if it.isDeadly:
+ print("Aaaagh!...., the %s killed me!" % it)
+ self.gameOver = True
+ else:
+ self.inv.append(it)
+
+ def drop(self,it):
+ self.inv.remove(it)
+ if it.isFragile:
+ it.breakItem()
+
+
+def createRooms( rm ):
+ """
+ create rooms, using multiline string showing map layout
+ string contains symbols for the following:
+ A-Z, a-z indicate rooms, and rooms will be stored in a dictionary by
+ reference letter
+ -, | symbols indicate connection between rooms
+ <, >, ^, . symbols indicate one-way connection between rooms
+ """
+ # start with empty dictionary of rooms
+ ret = {}
+
+ # look for room symbols, and initialize dictionary
+ # - exit room is always marked 'Z'
+ for c in rm:
+ if c in string.ascii_letters:
+ if c != "Z":
+ ret[c] = Room(c)
+ else:
+ ret[c] = Exit()
+
+ # scan through input string looking for connections between rooms
+ rows = rm.split("\n")
+ for row,line in enumerate(rows):
+ for col,c in enumerate(line):
+ if c in string.ascii_letters:
+ room = ret[c]
+ n = None
+ s = None
+ e = None
+ w = None
+
+ # look in neighboring cells for connection symbols (must take
+ # care to guard that neighboring cells exist before testing
+ # contents)
+ if col > 0 and line[col-1] in "<-":
+ other = line[col-2]
+ w = ret[other]
+ if col < len(line)-1 and line[col+1] in "->":
+ other = line[col+2]
+ e = ret[other]
+ if row > 1 and col < len(rows[row-1]) and rows[row-1][col] in '|^':
+ other = rows[row-2][col]
+ n = ret[other]
+ if row < len(rows)-1 and col < len(rows[row+1]) and rows[row+1][col] in '|.':
+ other = rows[row+2][col]
+ s = ret[other]
+
+ # set connections to neighboring rooms
+ room.doors=[n,s,e,w]
+
+ return ret
+
+# put items in rooms
+def putItemInRoom(i,r):
+ if isinstance(r,str):
+ r = rooms[r]
+ r.addItem( Item.items[i] )
+
+def playGame(p,startRoom):
+ # create parser
+ parser = Parser()
+ p.moveTo( startRoom )
+ while not p.gameOver:
+ cmdstr = input(">> ")
+ cmd = parser.parseCmd(cmdstr)
+ if cmd is not None:
+ cmd.command( p )
+ print()
+ print("You ended the game with:")
+ for i in p.inv:
+ print(" -", aOrAn(i))
+
+
+#====================
+# start game definition
+roomMap = """
+ d-Z
+ |
+ f-c-e
+ . |
+ q<b
+ |
+ A
+"""
+rooms = createRooms( roomMap )
+rooms["A"].desc = "You are standing on the front porch of a wooden shack."
+rooms["b"].desc = "You are in a garden."
+rooms["c"].desc = "You are in a kitchen."
+rooms["d"].desc = "You are on the back porch."
+rooms["e"].desc = "You are in a library."
+rooms["f"].desc = "You are on the patio."
+rooms["q"].desc = "You are sinking in quicksand. You're dead..."
+rooms["q"].gameOver = True
+
+# define global variables for referencing rooms
+frontPorch = rooms["A"]
+garden = rooms["b"]
+kitchen = rooms["c"]
+backPorch = rooms["d"]
+library = rooms["e"]
+patio = rooms["f"]
+
+# create items
+itemNames = """sword.diamond.apple.flower.coin.shovel.book.mirror.telescope.gold bar""".split(".")
+for itemName in itemNames:
+ Item( itemName )
+Item.items["apple"].isDeadly = True
+Item.items["mirror"].isFragile = True
+Item.items["coin"].isVisible = False
+Item.items["shovel"].usableConditionTest = ( lambda p,t: p.room is garden )
+def useShovel(p,subj,target):
+ coin = Item.items["coin"]
+ if not coin.isVisible and coin in p.room.inv:
+ coin.isVisible = True
+Item.items["shovel"].useAction = useShovel
+
+Item.items["telescope"].isTakeable = False
+def useTelescope(p,subj,target):
+ print("You don't see anything.")
+Item.items["telescope"].useAction = useTelescope
+
+OpenableItem("treasure chest", Item.items["gold bar"])
+Item.items["chest"] = Item.items["treasure chest"]
+Item.items["chest"].isTakeable = False
+Item.items["chest"].cantTakeMessage = "It's too heavy!"
+
+OpenableItem("mailbox")
+Item.items["mailbox"].isTakeable = False
+Item.items["mailbox"].cantTakeMessage = "It's nailed to the wall!"
+
+putItemInRoom("mailbox", frontPorch)
+putItemInRoom("shovel", frontPorch)
+putItemInRoom("coin", garden)
+putItemInRoom("flower", garden)
+putItemInRoom("apple", library)
+putItemInRoom("mirror", library)
+putItemInRoom("telescope", library)
+putItemInRoom("book", kitchen)
+putItemInRoom("diamond", backPorch)
+putItemInRoom("treasure chest", patio)
+
+# create player
+plyr = Player("Bob")
+plyr.take( Item.items["sword"] )
+
+# start game
+playGame( plyr, frontPorch )
diff --git a/examples/antlr_grammar.py b/examples/antlr_grammar.py
new file mode 100644
index 0000000..76c681c
--- /dev/null
+++ b/examples/antlr_grammar.py
@@ -0,0 +1,219 @@
+'''
+antlr_grammar.py
+
+Created on 4 sept. 2010
+
+@author: luca
+
+Submitted by Luca DallOlio, September, 2010
+(Minor updates by Paul McGuire, June, 2012)
+'''
+from pyparsing import Word, ZeroOrMore, printables, Suppress, OneOrMore, Group, \
+ LineEnd, Optional, White, originalTextFor, hexnums, nums, Combine, Literal, Keyword, \
+ cStyleComment, Regex, Forward, MatchFirst, And, srange, oneOf, alphas, alphanums, \
+ delimitedList
+
+# http://www.antlr.org/grammar/ANTLR/ANTLRv3.g
+
+# Tokens
+EOL = Suppress(LineEnd()) # $
+singleTextString = originalTextFor(ZeroOrMore(~EOL + (White(" \t") | Word(printables)))).leaveWhitespace()
+XDIGIT = hexnums
+INT = Word(nums)
+ESC = Literal('\\') + (oneOf(list(r'nrtbf\">'+"'")) | ('u' + Word(hexnums, exact=4)) | Word(printables, exact=1))
+LITERAL_CHAR = ESC | ~(Literal("'") | Literal('\\')) + Word(printables, exact=1)
+CHAR_LITERAL = Suppress("'") + LITERAL_CHAR + Suppress("'")
+STRING_LITERAL = Suppress("'") + Combine(OneOrMore(LITERAL_CHAR)) + Suppress("'")
+DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"'
+DOUBLE_ANGLE_STRING_LITERAL = '<<' + ZeroOrMore(Word(printables, exact=1)) + '>>'
+TOKEN_REF = Word(alphas.upper(), alphanums+'_')
+RULE_REF = Word(alphas.lower(), alphanums+'_')
+ACTION_ESC = (Suppress("\\") + Suppress("'")) | Suppress('\\"') | Suppress('\\') + (~(Literal("'") | Literal('"')) + Word(printables, exact=1))
+ACTION_CHAR_LITERAL = Suppress("'") + (ACTION_ESC | ~(Literal('\\') | Literal("'")) + Word(printables, exact=1)) + Suppress("'")
+ACTION_STRING_LITERAL = Suppress('"') + ZeroOrMore(ACTION_ESC | ~(Literal('\\') | Literal('"')) + Word(printables, exact=1)) + Suppress('"')
+SRC = Suppress('src') + ACTION_STRING_LITERAL("file") + INT("line")
+id = TOKEN_REF | RULE_REF
+SL_COMMENT = Suppress('//') + Suppress('$ANTLR') + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL
+ML_COMMENT = cStyleComment
+WS = OneOrMore(Suppress(' ') | Suppress('\t') | (Optional(Suppress('\r')) + Literal('\n')))
+WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT)
+NESTED_ARG_ACTION = Forward()
+NESTED_ARG_ACTION << Suppress('[') + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress(']')
+ARG_ACTION = NESTED_ARG_ACTION
+NESTED_ACTION = Forward()
+NESTED_ACTION << Suppress('{') + ZeroOrMore(NESTED_ACTION | SL_COMMENT | ML_COMMENT | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress('}')
+ACTION = NESTED_ACTION + Optional('?')
+SCOPE = Suppress('scope')
+OPTIONS = Suppress('options') + Suppress('{') # + WS_LOOP + Suppress('{')
+TOKENS = Suppress('tokens') + Suppress('{') # + WS_LOOP + Suppress('{')
+FRAGMENT = 'fragment';
+TREE_BEGIN = Suppress('^(')
+ROOT = Suppress('^')
+BANG = Suppress('!')
+RANGE = Suppress('..')
+REWRITE = Suppress('->')
+
+# General Parser Definitions
+
+# Grammar heading
+optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal('*').setName("s")
+
+option = Group(id("id") + Suppress('=') + optionValue("value"))("option")
+optionsSpec = OPTIONS + Group(OneOrMore(option + Suppress(';')))("options") + Suppress('}')
+tokenSpec = Group(TOKEN_REF("token_ref") + (Suppress('=') + (STRING_LITERAL | CHAR_LITERAL)("lit")))("token") + Suppress(';')
+tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + Suppress('}')
+attrScope = Suppress('scope') + id + ACTION
+grammarType = Keyword('lexer') + Keyword('parser') + Keyword('tree')
+actionScopeName = id | Keyword('lexer')("l") | Keyword('parser')("p")
+action = Suppress('@') + Optional(actionScopeName + Suppress('::')) + id + ACTION
+
+grammarHeading = Optional(ML_COMMENT("ML_COMMENT")) + Optional(grammarType) + Suppress('grammar') + id("grammarName") + Suppress(';') + Optional(optionsSpec) + Optional(tokensSpec) + ZeroOrMore(attrScope) + ZeroOrMore(action)
+
+modifier = Keyword('protected') | Keyword('public') | Keyword('private') | Keyword('fragment')
+ruleAction = Suppress('@') + id + ACTION
+throwsSpec = Suppress('throws') + delimitedList(id)
+ruleScopeSpec = (Suppress('scope') + ACTION) | (Suppress('scope') + delimitedList(id) + Suppress(';')) | (Suppress('scope') + ACTION + Suppress('scope') + delimitedList(id) + Suppress(';'))
+unary_op = oneOf("^ !")
+notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL
+terminal = (CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | '.') + Optional(unary_op)
+block = Forward()
+notSet = Suppress('~') + (notTerminal | block)
+rangeNotPython = CHAR_LITERAL("c1") + RANGE + CHAR_LITERAL("c2")
+atom = Group(rangeNotPython + Optional(unary_op)("op")) | terminal | (notSet + Optional(unary_op)("op")) | (RULE_REF + Optional(ARG_ACTION("arg")) + Optional(unary_op)("op"))
+element = Forward()
+treeSpec = Suppress('^(') + element*(2,) + Suppress(')')
+ebnfSuffix = oneOf("? * +")
+ebnf = block + Optional(ebnfSuffix("op") | '=>')
+elementNoOptionSpec = (id("result_name") + oneOf('= +=')("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + oneOf('= +=')("labelOp") + block + Optional(ebnfSuffix)) | atom("atom") + Optional(ebnfSuffix) | ebnf | ACTION | (treeSpec + Optional(ebnfSuffix)) # | SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED )
+element << Group(elementNoOptionSpec)("element")
+alternative = Group(Group(OneOrMore(element))("elements")) # Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure?
+rewrite = Optional(Literal('TODO REWRITE RULES TODO'))
+block << Suppress('(') + Optional(Optional(optionsSpec("opts")) + Suppress(':')) + Group(alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives"))("block") + Suppress(')')
+altList = alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives")
+exceptionHandler = Suppress('catch') + ARG_ACTION + ACTION
+finallyClause = Suppress('finally') + ACTION
+exceptionGroup = (OneOrMore(exceptionHandler) + Optional(finallyClause)) | finallyClause
+
+ruleHeading = Optional(ML_COMMENT)("ruleComment") + Optional(modifier)("modifier") + id("ruleName") + Optional("!") + Optional(ARG_ACTION("arg")) + Optional(Suppress('returns') + ARG_ACTION("rt")) + Optional(throwsSpec) + Optional(optionsSpec) + Optional(ruleScopeSpec) + ZeroOrMore(ruleAction)
+rule = Group(ruleHeading + Suppress(':') + altList + Suppress(';') + Optional(exceptionGroup))("rule")
+
+grammarDef = grammarHeading + Group(OneOrMore(rule))("rules")
+
+def grammar():
+ return grammarDef
+
+def __antlrAlternativesConverter(pyparsingRules, antlrBlock):
+ rule = None
+ if hasattr(antlrBlock, 'alternatives') and antlrBlock.alternatives != '' and len(antlrBlock.alternatives) > 0:
+ alternatives = []
+ alternatives.append(__antlrAlternativeConverter(pyparsingRules, antlrBlock.a1))
+ for alternative in antlrBlock.alternatives:
+ alternatives.append(__antlrAlternativeConverter(pyparsingRules, alternative))
+ rule = MatchFirst(alternatives)("anonymous_or")
+ elif hasattr(antlrBlock, 'a1') and antlrBlock.a1 != '':
+ rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)
+ else:
+ raise Exception('Not yet implemented')
+ assert rule != None
+ return rule
+
+def __antlrAlternativeConverter(pyparsingRules, antlrAlternative):
+ elementList = []
+ for element in antlrAlternative.elements:
+ rule = None
+ if hasattr(element.atom, 'c1') and element.atom.c1 != '':
+ regex = r'['+str(element.atom.c1[0])+'-'+str(element.atom.c2[0]+']')
+ rule = Regex(regex)("anonymous_regex")
+ elif hasattr(element, 'block') and element.block != '':
+ rule = __antlrAlternativesConverter(pyparsingRules, element.block)
+ else:
+ ruleRef = element.atom
+ assert ruleRef in pyparsingRules
+ rule = pyparsingRules[element.atom](element.atom)
+ if hasattr(element, 'op') and element.op != '':
+ if element.op == '+':
+ rule = Group(OneOrMore(rule))("anonymous_one_or_more")
+ elif element.op == '*':
+ rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more")
+ elif element.op == '?':
+ rule = Optional(rule)
+ else:
+ raise Exception('rule operator not yet implemented : ' + element.op)
+ rule = rule
+ elementList.append(rule)
+ if len(elementList) > 1:
+ rule = Group(And(elementList))("anonymous_and")
+ else:
+ rule = elementList[0]
+ assert rule != None
+ return rule
+
+def __antlrRuleConverter(pyparsingRules, antlrRule):
+ rule = None
+ rule = __antlrAlternativesConverter(pyparsingRules, antlrRule)
+ assert rule != None
+ rule(antlrRule.ruleName)
+ return rule
+
+def antlrConverter(antlrGrammarTree):
+ pyparsingRules = {}
+ antlrTokens = {}
+ for antlrToken in antlrGrammarTree.tokens:
+ antlrTokens[antlrToken.token_ref] = antlrToken.lit
+ for antlrTokenName, antlrToken in list(antlrTokens.items()):
+ pyparsingRules[antlrTokenName] = Literal(antlrToken)
+ antlrRules = {}
+ for antlrRule in antlrGrammarTree.rules:
+ antlrRules[antlrRule.ruleName] = antlrRule
+ pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar
+ for antlrRuleName, antlrRule in list(antlrRules.items()):
+ pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule)
+ assert pyparsingRule != None
+ pyparsingRules[antlrRuleName] << pyparsingRule
+ return pyparsingRules
+
+if __name__ == "__main__":
+
+ text = """grammar SimpleCalc;
+
+options {
+ language = Python;
+}
+
+tokens {
+ PLUS = '+' ;
+ MINUS = '-' ;
+ MULT = '*' ;
+ DIV = '/' ;
+}
+
+/*------------------------------------------------------------------
+ * PARSER RULES
+ *------------------------------------------------------------------*/
+
+expr : term ( ( PLUS | MINUS ) term )* ;
+
+term : factor ( ( MULT | DIV ) factor )* ;
+
+factor : NUMBER ;
+
+
+/*------------------------------------------------------------------
+ * LEXER RULES
+ *------------------------------------------------------------------*/
+
+NUMBER : (DIGIT)+ ;
+
+/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */
+
+fragment DIGIT : '0'..'9' ;
+
+"""
+
+ grammar().validate()
+ antlrGrammarTree = grammar().parseString(text)
+ print(antlrGrammarTree.asXML("antlrGrammarTree"))
+ pyparsingRules = antlrConverter(antlrGrammarTree)
+ pyparsingRule = pyparsingRules["expr"]
+ pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25")
+ print(pyparsingTree.asXML("pyparsingTree"))
diff --git a/examples/antlr_grammar_tests.py b/examples/antlr_grammar_tests.py
new file mode 100644
index 0000000..c2c3d8d
--- /dev/null
+++ b/examples/antlr_grammar_tests.py
@@ -0,0 +1,87 @@
+'''
+Created on 4 sept. 2010
+
+@author: luca
+
+Submitted by Luca DallOlio, September, 2010
+'''
+import unittest
+import antlr_grammar
+
+class Test(unittest.TestCase):
+
+
+ def testOptionsSpec(self):
+ text = """options {
+ language = Python;
+ }"""
+ antlr_grammar.optionsSpec.parseString(text) #@UndefinedVariable
+
+ def testTokensSpec(self):
+ text = """tokens {
+ PLUS = '+' ;
+ MINUS = '-' ;
+ MULT = '*' ;
+ DIV = '/' ;
+ }"""
+ antlr_grammar.tokensSpec.parseString(text) #@UndefinedVariable
+
+ def testBlock(self):
+ text = """( PLUS | MINUS )"""
+ antlr_grammar.block.parseString(text) #@UndefinedVariable
+
+ def testRule(self):
+ text = """expr : term ( ( PLUS | MINUS ) term )* ;"""
+ antlr_grammar.rule.parseString(text) #@UndefinedVariable
+
+ def testLexerRule(self):
+ text = """fragment DIGIT : '0'..'9' ;"""
+ antlr_grammar.rule.parseString(text) #@UndefinedVariable
+
+ def testLexerRule2(self):
+ text = """WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;"""
+ #antlr_grammar.rule.parseString(text) #@UndefinedVariable
+
+ def testGrammar(self):
+ text = """grammar SimpleCalc;
+
+options {
+ language = Python;
+}
+
+tokens {
+ PLUS = '+' ;
+ MINUS = '-' ;
+ MULT = '*' ;
+ DIV = '/' ;
+}
+
+/*------------------------------------------------------------------
+ * PARSER RULES
+ *------------------------------------------------------------------*/
+
+expr : term ( ( PLUS | MINUS ) term )* ;
+
+term : factor ( ( MULT | DIV ) factor )* ;
+
+factor : NUMBER ;
+
+
+/*------------------------------------------------------------------
+ * LEXER RULES
+ *------------------------------------------------------------------*/
+
+NUMBER : (DIGIT)+ ;
+
+/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */
+
+fragment DIGIT : '0'..'9' ;"""
+ antlrGrammarTree = antlr_grammar.grammarDef.parseString(text) #@UndefinedVariable
+ pyparsingRules = antlr_grammar.antlrConverter(antlrGrammarTree)
+ pyparsingRule = pyparsingRules["expr"]
+ pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25")
+ self.assertNotEqual(None, pyparsingTree)
+
+if __name__ == "__main__":
+ #import sys;sys.argv = ['', 'Test.testOptionsSpec']
+ unittest.main() \ No newline at end of file
diff --git a/examples/apicheck.py b/examples/apicheck.py
new file mode 100644
index 0000000..7bca41a
--- /dev/null
+++ b/examples/apicheck.py
@@ -0,0 +1,58 @@
+# apicheck.py
+# A simple source code scanner for finding patterns of the form
+# [ procname1 $arg1 $arg2 ]
+# and verifying the number of arguments
+#
+# Copyright (c) 2004-2016, Paul McGuire
+#
+
+from pyparsing import *
+
+# define punctuation and simple tokens for locating API calls
+LBRACK,RBRACK,LBRACE,RBRACE = map(Suppress,"[]{}")
+ident = Word(alphas,alphanums+"_") | QuotedString("{",endQuoteChar="}")
+arg = "$" + ident
+
+# define an API call with a specific number of arguments - using '-'
+# will ensure that after matching procname, an incorrect number of args will
+# raise a ParseSyntaxException, which will interrupt the scanString
+def apiProc(name, numargs):
+ return LBRACK + Keyword(name)("procname") - arg*numargs + RBRACK
+
+# create an apiReference, listing all API functions to be scanned for, and
+# their respective number of arguments. Beginning the overall expression
+# with FollowedBy allows us to quickly rule out non-api calls while scanning,
+# since all of the api calls begin with a "["
+apiRef = FollowedBy("[") + MatchFirst([
+ apiProc("procname1", 2),
+ apiProc("procname2", 1),
+ apiProc("procname3", 2),
+ ])
+
+test = """[ procname1 $par1 $par2 ]
+ other code here
+ [ procname1 $par1 $par2 $par3 ]
+ more code here
+ [ procname1 $par1 ]
+ [ procname3 ${arg with spaces} $par2 ]"""
+
+
+# now explicitly iterate through the scanner using next(), so that
+# we can trap ParseSyntaxException's that would be raised due to
+# an incorrect number of arguments. If an exception does occur,
+# then see how we reset the input text and scanner to advance to the
+# next line of source code
+api_scanner = apiRef.scanString(test)
+while 1:
+ try:
+ t,s,e = next(api_scanner)
+ print("found %s on line %d" % (t.procname, lineno(s,test)))
+ except ParseSyntaxException as pe:
+ print("invalid arg count on line", pe.lineno)
+ print(pe.lineno,':',pe.line)
+ # reset api scanner to start after this exception location
+ test = "\n"*(pe.lineno-1)+test[pe.loc+1:]
+ api_scanner = apiRef.scanString(test)
+ except StopIteration:
+ break
+
diff --git a/examples/btpyparse.py b/examples/btpyparse.py
new file mode 100644
index 0000000..4fbbac8
--- /dev/null
+++ b/examples/btpyparse.py
@@ -0,0 +1,129 @@
+""" Pyparsing parser for BibTeX files
+
+A standalone parser using pyparsing.
+
+pyparsing has a simple and expressive syntax so the grammar is easy to read and
+write.
+
+Submitted by Matthew Brett, 2010
+
+Simplified BSD license
+"""
+
+from pyparsing import (Regex, Suppress, ZeroOrMore, Group, Optional, Forward,
+ SkipTo, CaselessLiteral, Dict)
+
+
+class Macro(object):
+ """ Class to encapsulate undefined macro references """
+ def __init__(self, name):
+ self.name = name
+ def __repr__(self):
+ return 'Macro("%s")' % self.name
+ def __eq__(self, other):
+ return self.name == other.name
+ def __ne__(self, other):
+ return self.name != other.name
+
+
+# Character literals
+LCURLY,RCURLY,LPAREN,RPAREN,QUOTE,COMMA,AT,EQUALS,HASH = map(Suppress,'{}()",@=#')
+
+
+def bracketed(expr):
+ """ Return matcher for `expr` between curly brackets or parentheses """
+ return (LPAREN + expr + RPAREN) | (LCURLY + expr + RCURLY)
+
+
+# Define parser components for strings (the hard bit)
+chars_no_curly = Regex(r"[^{}]+")
+chars_no_curly.leaveWhitespace()
+chars_no_quotecurly = Regex(r'[^"{}]+')
+chars_no_quotecurly.leaveWhitespace()
+# Curly string is some stuff without curlies, or nested curly sequences
+curly_string = Forward()
+curly_item = Group(curly_string) | chars_no_curly
+curly_string << LCURLY + ZeroOrMore(curly_item) + RCURLY
+# quoted string is either just stuff within quotes, or stuff within quotes, within
+# which there is nested curliness
+quoted_item = Group(curly_string) | chars_no_quotecurly
+quoted_string = QUOTE + ZeroOrMore(quoted_item) + QUOTE
+
+# Numbers can just be numbers. Only integers though.
+number = Regex('[0-9]+')
+
+# Basis characters (by exclusion) for variable / field names. The following
+# list of characters is from the btparse documentation
+any_name = Regex('[^\\s"#%\'(),={}]+')
+
+# btparse says, and the test bibs show by experiment, that macro and field names
+# cannot start with a digit. In fact entry type names cannot start with a digit
+# either (see tests/bibs). Cite keys can start with a digit
+not_digname = Regex('[^\\d\\s"#%\'(),={}][^\\s"#%\'(),={}]*')
+
+# Comment comments out to end of line
+comment = (AT + CaselessLiteral('comment') +
+ Regex(r"[\s{(].*").leaveWhitespace())
+
+# The name types with their digiteyness
+not_dig_lower = not_digname.copy().setParseAction(lambda t: t[0].lower())
+macro_def = not_dig_lower.copy()
+macro_ref = not_dig_lower.copy().setParseAction(lambda t : Macro(t[0].lower()))
+field_name = not_dig_lower.copy()
+# Spaces in names mean they cannot clash with field names
+entry_type = not_dig_lower('entry_type')
+cite_key = any_name('cite_key')
+# Number has to be before macro name
+string = (number | macro_ref | quoted_string | curly_string)
+
+# There can be hash concatenation
+field_value = string + ZeroOrMore(HASH + string)
+field_def = Group(field_name + EQUALS + field_value)
+entry_contents = Dict(ZeroOrMore(field_def + COMMA) + Optional(field_def))
+
+# Entry is surrounded either by parentheses or curlies
+entry = (AT + entry_type + bracketed(cite_key + COMMA + entry_contents))
+
+# Preamble is a macro-like thing with no name
+preamble = AT + CaselessLiteral('preamble') + bracketed(field_value)
+
+# Macros (aka strings)
+macro_contents = macro_def + EQUALS + field_value
+macro = AT + CaselessLiteral('string') + bracketed(macro_contents)
+
+# Implicit comments
+icomment = SkipTo('@').setParseAction(lambda t : t.insert(0, 'icomment'))
+
+# entries are last in the list (other than the fallback) because they have
+# arbitrary start patterns that would match comments, preamble or macro
+definitions = Group(comment |
+ preamble |
+ macro |
+ entry |
+ icomment)
+
+# Start symbol
+bibfile = ZeroOrMore(definitions)
+
+
+def parse_str(str):
+ return bibfile.parseString(str)
+
+
+if __name__ == '__main__':
+ # Run basic test
+ txt = """
+Some introductory text
+(implicit comment)
+
+@ARTICLE{Authors2011,
+ author = {First Author and Second Author and Third Author},
+ title = {An article about {S}omething},
+ journal = "Journal of Articles",
+ year = {2011},
+ volume = {16},
+ pages = {1140--1141},
+ number = {2}
+}
+"""
+ print('\n\n'.join(defn.dump() for defn in parse_str(txt)))
diff --git a/examples/builtin_parse_action_demo.py b/examples/builtin_parse_action_demo.py
new file mode 100644
index 0000000..3ec6af8
--- /dev/null
+++ b/examples/builtin_parse_action_demo.py
@@ -0,0 +1,29 @@
+#
+# builtin_parse_action_demo.py
+# Copyright, 2012 - Paul McGuire
+#
+# Simple example of using builtin functions as parse actions.
+#
+
+from pyparsing import *
+
+integer = Word(nums).setParseAction(lambda t : int(t[0]))
+
+# make an expression that will match a list of ints (which
+# will be converted to actual ints by the parse action attached
+# to integer)
+nums = OneOrMore(integer)
+
+
+test = "2 54 34 2 211 66 43 2 0"
+print(test)
+
+# try each of these builtins as parse actions
+for fn in (sum, max, min, len, sorted, reversed, list, tuple, set, any, all):
+ fn_name = fn.__name__
+ if fn is reversed:
+ # reversed returns an iterator, we really want to show the list of items
+ fn = lambda x : list(reversed(x))
+
+ # show how each builtin works as a free-standing parse action
+ print(fn_name, nums.setParseAction(fn).parseString(test))
diff --git a/examples/cLibHeader.py b/examples/cLibHeader.py
new file mode 100644
index 0000000..bb98521
--- /dev/null
+++ b/examples/cLibHeader.py
@@ -0,0 +1,25 @@
+#
+# cLibHeader.py
+#
+# A simple parser to extract API doc info from a C header file
+#
+# Copyright, 2012 - Paul McGuire
+#
+
+from pyparsing import Word, alphas, alphanums, Combine, oneOf, Optional, delimitedList, Group, Keyword
+
+testdata = """
+ int func1(float *vec, int len, double arg1);
+ int func2(float **arr, float *vec, int len, double arg1, double arg2);
+ """
+
+ident = Word(alphas, alphanums + "_")
+vartype = Combine( oneOf("float double int char") + Optional(Word("*")), adjacent = False)
+arglist = delimitedList(Group(vartype("type") + ident("name")))
+
+functionCall = Keyword("int") + ident("name") + "(" + arglist("args") + ")" + ";"
+
+for fn,s,e in functionCall.scanString(testdata):
+ print(fn.name)
+ for a in fn.args:
+ print(" - %(name)s (%(type)s)" % a)
diff --git a/examples/chemicalFormulas.py b/examples/chemicalFormulas.py
new file mode 100644
index 0000000..ce66afd
--- /dev/null
+++ b/examples/chemicalFormulas.py
@@ -0,0 +1,67 @@
+# chemicalFormulas.py
+#
+# Copyright (c) 2003, Paul McGuire
+#
+
+from pyparsing import Word, Optional, OneOrMore, Group, ParseException, Regex
+from pyparsing import alphas
+
+atomicWeight = {
+ "O" : 15.9994,
+ "H" : 1.00794,
+ "Na" : 22.9897,
+ "Cl" : 35.4527,
+ "C" : 12.0107
+ }
+
+def test( bnf, strg, fn=None ):
+ try:
+ print(strg,"->", bnf.parseString( strg ), end=' ')
+ except ParseException as pe:
+ print(pe)
+ else:
+ if fn != None:
+ print(fn( bnf.parseString( strg ) ))
+ else:
+ print()
+
+digits = "0123456789"
+
+# Version 1
+element = Regex("A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|"
+ "E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|"
+ "M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|"
+ "S[bcegimnr]?|T[abcehilm]|U(u[bhopqst])?|V|W|Xe|Yb?|Z[nr]")
+
+element = Word( alphas.upper(), alphas.lower(), max=2)
+elementRef = Group( element + Optional( Word( digits ), default="1" ) )
+formula = OneOrMore( elementRef )
+
+fn = lambda elemList : sum(atomicWeight[elem]*int(qty) for elem,qty in elemList)
+test( formula, "H2O", fn )
+test( formula, "C6H5OH", fn )
+test( formula, "NaCl", fn )
+print()
+
+# Version 2 - access parsed items by field name
+elementRef = Group( element("symbol") + Optional( Word( digits ), default="1" )("qty") )
+formula = OneOrMore( elementRef )
+
+fn = lambda elemList : sum(atomicWeight[elem.symbol]*int(elem.qty) for elem in elemList)
+test( formula, "H2O", fn )
+test( formula, "C6H5OH", fn )
+test( formula, "NaCl", fn )
+print()
+
+# Version 3 - convert integers during parsing process
+integer = Word( digits ).setParseAction(lambda t:int(t[0]))
+elementRef = Group( element("symbol") + Optional( integer, default=1 )("qty") )
+formula = OneOrMore( elementRef )
+
+fn = lambda elemList : sum(atomicWeight[elem.symbol]*elem.qty for elem in elemList)
+test( formula, "H2O", fn )
+test( formula, "C6H5OH", fn )
+test( formula, "NaCl", fn )
+
+
+
diff --git a/examples/commasep.py b/examples/commasep.py
new file mode 100644
index 0000000..3ce8546
--- /dev/null
+++ b/examples/commasep.py
@@ -0,0 +1,26 @@
+# commasep.py
+#
+# comma-separated list example, to illustrate the advantages of using
+# the pyparsing commaSeparatedList as opposed to string.split(","):
+# - leading and trailing whitespace is implicitly trimmed from list elements
+# - list elements can be quoted strings, which can safely contain commas without breaking
+# into separate elements
+#
+# Copyright (c) 2004-2016, Paul McGuire
+#
+
+from pyparsing import commaSeparatedList
+
+testData = [
+ "a,b,c,100.2,,3",
+ "d, e, j k , m ",
+ "'Hello, World', f, g , , 5.1,x",
+ "John Doe, 123 Main St., Cleveland, Ohio",
+ "Jane Doe, 456 St. James St., Los Angeles , California ",
+ "",
+ ]
+
+for line in testData:
+ print(commaSeparatedList.parseString(line))
+ print(line.split(","))
+ print()
diff --git a/examples/configParse.py b/examples/configParse.py
new file mode 100644
index 0000000..769249c
--- /dev/null
+++ b/examples/configParse.py
@@ -0,0 +1,72 @@
+#
+# configparse.py
+#
+# an example of using the parsing module to be able to process a .INI configuration file
+#
+# Copyright (c) 2003, Paul McGuire
+#
+
+from pyparsing import \
+ Literal, Word, ZeroOrMore, Group, Dict, Optional, \
+ printables, ParseException, restOfLine, empty
+import pprint
+
+
+inibnf = None
+def inifile_BNF():
+ global inibnf
+
+ if not inibnf:
+
+ # punctuation
+ lbrack = Literal("[").suppress()
+ rbrack = Literal("]").suppress()
+ equals = Literal("=").suppress()
+ semi = Literal(";")
+
+ comment = semi + Optional( restOfLine )
+
+ nonrbrack = "".join( [ c for c in printables if c != "]" ] ) + " \t"
+ nonequals = "".join( [ c for c in printables if c != "=" ] ) + " \t"
+
+ sectionDef = lbrack + Word( nonrbrack ) + rbrack
+ keyDef = ~lbrack + Word( nonequals ) + equals + empty + restOfLine
+ # strip any leading or trailing blanks from key
+ def stripKey(tokens):
+ tokens[0] = tokens[0].strip()
+ keyDef.setParseAction(stripKey)
+
+ # using Dict will allow retrieval of named data fields as attributes of the parsed results
+ inibnf = Dict( ZeroOrMore( Group( sectionDef + Dict( ZeroOrMore( Group( keyDef ) ) ) ) ) )
+
+ inibnf.ignore( comment )
+
+ return inibnf
+
+
+pp = pprint.PrettyPrinter(2)
+
+def test( strng ):
+ print(strng)
+ try:
+ iniFile = open(strng)
+ iniData = "".join( iniFile.readlines() )
+ bnf = inifile_BNF()
+ tokens = bnf.parseString( iniData )
+ pp.pprint( tokens.asList() )
+
+ except ParseException as err:
+ print(err.line)
+ print(" "*(err.column-1) + "^")
+ print(err)
+
+ iniFile.close()
+ print()
+ return tokens
+
+if __name__ == "__main__":
+ ini = test("setup.ini")
+ print("ini['Startup']['modemid'] =", ini['Startup']['modemid'])
+ print("ini.Startup =", ini.Startup)
+ print("ini.Startup.modemid =", ini.Startup.modemid)
+
diff --git a/examples/cpp_enum_parser.py b/examples/cpp_enum_parser.py
new file mode 100644
index 0000000..cd8f525
--- /dev/null
+++ b/examples/cpp_enum_parser.py
@@ -0,0 +1,52 @@
+#
+# cpp_enum_parser.py
+#
+# Posted by Mark Tolonen on comp.lang.python in August, 2009,
+# Used with permission.
+#
+# Parser that scans through C or C++ code for enum definitions, and
+# generates corresponding Python constant definitions.
+#
+#
+
+from pyparsing import *
+# sample string with enums and other stuff
+sample = '''
+ stuff before
+ enum hello {
+ Zero,
+ One,
+ Two,
+ Three,
+ Five=5,
+ Six,
+ Ten=10
+ };
+ in the middle
+ enum blah
+ {
+ alpha,
+ beta,
+ gamma = 10 ,
+ zeta = 50
+ };
+ at the end
+ '''
+
+# syntax we don't want to see in the final parse tree
+LBRACE,RBRACE,EQ,COMMA = map(Suppress,"{}=,")
+_enum = Suppress('enum')
+identifier = Word(alphas,alphanums+'_')
+integer = Word(nums)
+enumValue = Group(identifier('name') + Optional(EQ + integer('value')))
+enumList = Group(enumValue + ZeroOrMore(COMMA + enumValue))
+enum = _enum + identifier('enum') + LBRACE + enumList('names') + RBRACE
+
+# find instances of enums ignoring other syntax
+for item,start,stop in enum.scanString(sample):
+ id = 0
+ for entry in item.names:
+ if entry.value != '':
+ id = int(entry.value)
+ print('%s_%s = %d' % (item.enum.upper(),entry.name.upper(),id))
+ id += 1
diff --git a/examples/datetimeParseActions.py b/examples/datetimeParseActions.py
new file mode 100644
index 0000000..e42d2c6
--- /dev/null
+++ b/examples/datetimeParseActions.py
@@ -0,0 +1,68 @@
+# parseActions.py
+#
+# A sample program a parser to match a date string of the form "YYYY/MM/DD",
+# and return it as a datetime, or raise an exception if not a valid date.
+#
+# Copyright 2012, Paul T. McGuire
+#
+from datetime import datetime
+from pyparsing import *
+
+# define an integer string, and a parse action to convert it
+# to an integer at parse time
+integer = Word(nums).setName("integer")
+def convertToInt(tokens):
+ # no need to test for validity - we can't get here
+ # unless tokens[0] contains all numeric digits
+ return int(tokens[0])
+integer.setParseAction(convertToInt)
+# or can be written as one line as
+#integer = Word(nums).setParseAction(lambda t: int(t[0]))
+
+# define a pattern for a year/month/day date
+date_expr = integer('year') + '/' + integer('month') + '/' + integer('day')
+date_expr.ignore(pythonStyleComment)
+
+def convertToDatetime(s,loc,tokens):
+ try:
+ # note that the year, month, and day fields were already
+ # converted to ints from strings by the parse action defined
+ # on the integer expression above
+ return datetime(tokens.year, tokens.month, tokens.day).date()
+ except Exception as ve:
+ errmsg = "'%s/%s/%s' is not a valid date, %s" % \
+ (tokens.year, tokens.month, tokens.day, ve)
+ raise ParseException(s, loc, errmsg)
+date_expr.setParseAction(convertToDatetime)
+
+
+date_expr.runTests("""\
+ 2000/1/1
+
+ # invalid month
+ 2000/13/1
+
+ # 1900 was not a leap year
+ 1900/2/29
+
+ # but 2000 was
+ 2000/2/29
+ """)
+
+
+# if dates conform to ISO8601, use definitions in pyparsing_common
+date_expr = pyparsing_common.iso8601_date.setParseAction(pyparsing_common.convertToDate())
+date_expr.ignore(pythonStyleComment)
+
+date_expr.runTests("""\
+ 2000-01-01
+
+ # invalid month
+ 2000-13-01
+
+ # 1900 was not a leap year
+ 1900-02-29
+
+ # but 2000 was
+ 2000-02-29
+ """) \ No newline at end of file
diff --git a/examples/deltaTime.py b/examples/deltaTime.py
new file mode 100644
index 0000000..e38da00
--- /dev/null
+++ b/examples/deltaTime.py
@@ -0,0 +1,208 @@
+# deltaTime.py
+#
+# Parser to convert a conversational time reference such as "in a minute" or
+# "noon tomorrow" and convert it to a Python datetime. The returned
+# ParseResults object contains the results name "timeOffset" containing
+# the timedelta, and "calculatedTime" containing the computed time relative
+# to datetime.now().
+#
+# Copyright 2010, by Paul McGuire
+#
+
+from datetime import datetime, timedelta
+from pyparsing import *
+import calendar
+
+__all__ = ["nlTimeExpression"]
+
+# string conversion parse actions
+def convertToTimedelta(toks):
+ unit = toks.timeunit.lower().rstrip("s")
+ td = {
+ 'week' : timedelta(7),
+ 'day' : timedelta(1),
+ 'hour' : timedelta(0,0,0,0,0,1),
+ 'minute' : timedelta(0,0,0,0,1),
+ 'second' : timedelta(0,1),
+ }[unit]
+ if toks.qty:
+ td *= int(toks.qty)
+ if toks.dir:
+ td *= toks.dir
+ toks["timeOffset"] = td
+
+def convertToDay(toks):
+ now = datetime.now()
+ if "wkdayRef" in toks:
+ todaynum = now.weekday()
+ daynames = [n.lower() for n in calendar.day_name]
+ nameddaynum = daynames.index(toks.wkdayRef.day.lower())
+ if toks.wkdayRef.dir > 0:
+ daydiff = (nameddaynum + 7 - todaynum) % 7
+ else:
+ daydiff = -((todaynum + 7 - nameddaynum) % 7)
+ toks["absTime"] = datetime(now.year, now.month, now.day)+timedelta(daydiff)
+ else:
+ name = toks.name.lower()
+ toks["absTime"] = {
+ "now" : now,
+ "today" : datetime(now.year, now.month, now.day),
+ "yesterday" : datetime(now.year, now.month, now.day)+timedelta(-1),
+ "tomorrow" : datetime(now.year, now.month, now.day)+timedelta(+1),
+ }[name]
+
+def convertToAbsTime(toks):
+ now = datetime.now()
+ if "dayRef" in toks:
+ day = toks.dayRef.absTime
+ day = datetime(day.year, day.month, day.day)
+ else:
+ day = datetime(now.year, now.month, now.day)
+ if "timeOfDay" in toks:
+ if isinstance(toks.timeOfDay,str):
+ timeOfDay = {
+ "now" : timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond),
+ "noon" : timedelta(0,0,0,0,0,12),
+ "midnight" : timedelta(),
+ }[toks.timeOfDay]
+ else:
+ hhmmss = toks.timeparts
+ if hhmmss.miltime:
+ hh,mm = hhmmss.miltime
+ ss = 0
+ else:
+ hh,mm,ss = (hhmmss.HH % 12), hhmmss.MM, hhmmss.SS
+ if not mm: mm = 0
+ if not ss: ss = 0
+ if toks.timeOfDay.ampm == 'pm':
+ hh += 12
+ timeOfDay = timedelta(0, (hh*60+mm)*60+ss, 0)
+ else:
+ timeOfDay = timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond)
+ toks["absTime"] = day + timeOfDay
+
+def calculateTime(toks):
+ if toks.absTime:
+ absTime = toks.absTime
+ else:
+ absTime = datetime.now()
+ if toks.timeOffset:
+ absTime += toks.timeOffset
+ toks["calculatedTime"] = absTime
+
+# grammar definitions
+CL = CaselessLiteral
+today, tomorrow, yesterday, noon, midnight, now = map( CL,
+ "today tomorrow yesterday noon midnight now".split())
+plural = lambda s : Combine(CL(s) + Optional(CL("s")))
+week, day, hour, minute, second = map( plural,
+ "week day hour minute second".split())
+am = CL("am")
+pm = CL("pm")
+COLON = Suppress(':')
+
+# are these actually operators?
+in_ = CL("in").setParseAction(replaceWith(1))
+from_ = CL("from").setParseAction(replaceWith(1))
+before = CL("before").setParseAction(replaceWith(-1))
+after = CL("after").setParseAction(replaceWith(1))
+ago = CL("ago").setParseAction(replaceWith(-1))
+next_ = CL("next").setParseAction(replaceWith(1))
+last_ = CL("last").setParseAction(replaceWith(-1))
+at_ = CL("at")
+on_ = CL("on")
+
+couple = (Optional(CL("a")) + CL("couple") + Optional(CL("of"))).setParseAction(replaceWith(2))
+a_qty = CL("a").setParseAction(replaceWith(1))
+integer = Word(nums).setParseAction(lambda t:int(t[0]))
+int4 = Group(Word(nums,exact=4).setParseAction(lambda t: [int(t[0][:2]),int(t[0][2:])] ))
+def fill_timefields(t):
+ t[0]['HH'] = t[0][0]
+ t[0]['MM'] = t[0][1]
+ t[0]['ampm'] = ('am','pm')[t[0].HH >= 12]
+int4.addParseAction(fill_timefields)
+qty = integer | couple | a_qty
+dayName = oneOf( list(calendar.day_name) )
+
+dayOffset = (qty("qty") + (week | day)("timeunit"))
+dayFwdBack = (from_ + now.suppress() | ago)("dir")
+weekdayRef = (Optional(next_ | last_,1)("dir") + dayName("day"))
+dayRef = Optional( (dayOffset + (before | after | from_)("dir") ).setParseAction(convertToTimedelta) ) + \
+ ((yesterday | today | tomorrow)("name")|
+ weekdayRef("wkdayRef")).setParseAction(convertToDay)
+todayRef = (dayOffset + dayFwdBack).setParseAction(convertToTimedelta) | \
+ (in_("dir") + qty("qty") + day("timeunit")).setParseAction(convertToTimedelta)
+
+dayTimeSpec = dayRef | todayRef
+dayTimeSpec.setParseAction(calculateTime)
+
+relativeTimeUnit = (week | day | hour | minute | second)
+
+timespec = Group(ungroup(int4) |
+ integer("HH") +
+ ungroup(Optional(COLON + integer,[0]))("MM") +
+ ungroup(Optional(COLON + integer,[0]))("SS") +
+ (am | pm)("ampm")
+ )
+
+absTimeSpec = ((noon | midnight | now | timespec("timeparts"))("timeOfDay") +
+ Optional(on_) + Optional(dayRef)("dayRef") |
+ dayRef("dayRef") + at_ +
+ (noon | midnight | now | timespec("timeparts"))("timeOfDay"))
+absTimeSpec.setParseAction(convertToAbsTime,calculateTime)
+
+relTimeSpec = qty("qty") + relativeTimeUnit("timeunit") + \
+ (from_ | before | after)("dir") + \
+ Optional(at_) + \
+ absTimeSpec("absTime") | \
+ qty("qty") + relativeTimeUnit("timeunit") + ago("dir") | \
+ in_ + qty("qty") + relativeTimeUnit("timeunit")
+relTimeSpec.setParseAction(convertToTimedelta,calculateTime)
+
+nlTimeExpression = (absTimeSpec + Optional(dayTimeSpec) |
+ dayTimeSpec + Optional(Optional(at_) + absTimeSpec) |
+ relTimeSpec + Optional(absTimeSpec))
+
+if __name__ == "__main__":
+ # test grammar
+ tests = """\
+ today
+ tomorrow
+ yesterday
+ in a couple of days
+ a couple of days from now
+ a couple of days from today
+ in a day
+ 3 days ago
+ 3 days from now
+ a day ago
+ in 2 weeks
+ in 3 days at 5pm
+ now
+ 10 minutes ago
+ 10 minutes from now
+ in 10 minutes
+ in a minute
+ in a couple of minutes
+ 20 seconds ago
+ in 30 seconds
+ 20 seconds before noon
+ 20 seconds before noon tomorrow
+ noon
+ midnight
+ noon tomorrow
+ 6am tomorrow
+ 0800 yesterday
+ 12:15 AM today
+ 3pm 2 days from today
+ a week from today
+ a week from now
+ 3 weeks ago
+ noon next Sunday
+ noon Sunday
+ noon last Sunday
+ 2pm next Sunday
+ next Sunday at 2pm"""
+
+ print("(relative to %s)" % datetime.now())
+ nlTimeExpression.runTests(tests)
diff --git a/examples/dfmparse.py b/examples/dfmparse.py
new file mode 100644
index 0000000..cf83814
--- /dev/null
+++ b/examples/dfmparse.py
@@ -0,0 +1,179 @@
+"""
+This module can parse a Delphi Form (dfm) file.
+
+The main is used in experimenting (to find which files fail
+to parse, and where), but isn't useful for anything else.
+"""
+__version__ = "1.0"
+__author__ = "Daniel 'Dang' Griffith <pythondev - dang at lazytwinacres . net>"
+
+
+from pyparsing import Literal, CaselessLiteral, Word, delimitedList \
+ , Optional, Combine, Group, alphas, nums, alphanums, Forward \
+ , oneOf, sglQuotedString, OneOrMore, ZeroOrMore, CharsNotIn
+
+
+# This converts DFM character constants into Python string (unicode) values.
+def to_chr(x):
+ """chr(x) if 0 < x < 128 ; unicode(x) if x > 127."""
+ return 0 < x < 128 and chr(x) or eval("u'\\u%d'" % x )
+
+#################
+# BEGIN GRAMMAR
+#################
+
+COLON = Literal(":").suppress()
+CONCAT = Literal("+").suppress()
+EQUALS = Literal("=").suppress()
+LANGLE = Literal("<").suppress()
+LBRACE = Literal("[").suppress()
+LPAREN = Literal("(").suppress()
+PERIOD = Literal(".").suppress()
+RANGLE = Literal(">").suppress()
+RBRACE = Literal("]").suppress()
+RPAREN = Literal(")").suppress()
+
+CATEGORIES = CaselessLiteral("categories").suppress()
+END = CaselessLiteral("end").suppress()
+FONT = CaselessLiteral("font").suppress()
+HINT = CaselessLiteral("hint").suppress()
+ITEM = CaselessLiteral("item").suppress()
+OBJECT = CaselessLiteral("object").suppress()
+
+attribute_value_pair = Forward() # this is recursed in item_list_entry
+
+simple_identifier = Word(alphas, alphanums + "_")
+identifier = Combine( simple_identifier + ZeroOrMore( Literal(".") + simple_identifier ))
+object_name = identifier
+object_type = identifier
+
+# Integer and floating point values are converted to Python longs and floats, respectively.
+int_value = Combine(Optional("-") + Word(nums)).setParseAction(lambda s,l,t: [ int(t[0]) ] )
+float_value = Combine(Optional("-") + Optional(Word(nums)) + "." + Word(nums)).setParseAction(lambda s,l,t: [ float(t[0]) ] )
+number_value = float_value | int_value
+
+# Base16 constants are left in string form, including the surrounding braces.
+base16_value = Combine(Literal("{") + OneOrMore(Word("0123456789ABCDEFabcdef")) + Literal("}"), adjacent=False)
+
+# This is the first part of a hack to convert the various delphi partial sglQuotedStrings
+# into a single sglQuotedString equivalent. The gist of it is to combine
+# all sglQuotedStrings (with their surrounding quotes removed (suppressed))
+# with sequences of #xyz character constants, with "strings" concatenated
+# with a '+' sign.
+unquoted_sglQuotedString = Combine( Literal("'").suppress() + ZeroOrMore( CharsNotIn("'\n\r") ) + Literal("'").suppress() )
+
+# The parse action on this production converts repetitions of constants into a single string.
+pound_char = Combine(
+ OneOrMore((Literal("#").suppress()+Word(nums)
+ ).setParseAction( lambda s, l, t: to_chr(int(t[0]) ))))
+
+# This is the second part of the hack. It combines the various "unquoted"
+# partial strings into a single one. Then, the parse action puts
+# a single matched pair of quotes around it.
+delphi_string = Combine(
+ OneOrMore(CONCAT | pound_char | unquoted_sglQuotedString)
+ , adjacent=False
+ ).setParseAction(lambda s, l, t: "'%s'" % t[0])
+
+string_value = delphi_string | base16_value
+
+list_value = LBRACE + Optional(Group(delimitedList(identifier | number_value | string_value))) + RBRACE
+paren_list_value = LPAREN + ZeroOrMore(identifier | number_value | string_value) + RPAREN
+
+item_list_entry = ITEM + ZeroOrMore(attribute_value_pair) + END
+item_list = LANGLE + ZeroOrMore(item_list_entry) + RANGLE
+
+generic_value = identifier
+value = item_list | number_value | string_value | list_value | paren_list_value | generic_value
+
+category_attribute = CATEGORIES + PERIOD + oneOf("strings itemsvisibles visibles", True)
+event_attribute = oneOf("onactivate onclosequery onclose oncreate ondeactivate onhide onshow", True)
+font_attribute = FONT + PERIOD + oneOf("charset color height name style", True)
+hint_attribute = HINT
+layout_attribute = oneOf("left top width height", True)
+generic_attribute = identifier
+attribute = (category_attribute | event_attribute | font_attribute | hint_attribute | layout_attribute | generic_attribute)
+
+category_attribute_value_pair = category_attribute + EQUALS + paren_list_value
+event_attribute_value_pair = event_attribute + EQUALS + value
+font_attribute_value_pair = font_attribute + EQUALS + value
+hint_attribute_value_pair = hint_attribute + EQUALS + value
+layout_attribute_value_pair = layout_attribute + EQUALS + value
+generic_attribute_value_pair = attribute + EQUALS + value
+attribute_value_pair << Group(
+ category_attribute_value_pair
+ | event_attribute_value_pair
+ | font_attribute_value_pair
+ | hint_attribute_value_pair
+ | layout_attribute_value_pair
+ | generic_attribute_value_pair
+ )
+
+object_declaration = Group((OBJECT + object_name + COLON + object_type))
+object_attributes = Group(ZeroOrMore(attribute_value_pair))
+
+nested_object = Forward()
+object_definition = object_declaration + object_attributes + ZeroOrMore(nested_object) + END
+nested_object << Group(object_definition)
+
+#################
+# END GRAMMAR
+#################
+
+def printer(s, loc, tok):
+ print(tok, end=' ')
+ return tok
+
+def get_filename_list(tf):
+ import sys, glob
+ if tf == None:
+ if len(sys.argv) > 1:
+ tf = sys.argv[1:]
+ else:
+ tf = glob.glob("*.dfm")
+ elif type(tf) == str:
+ tf = [tf]
+ testfiles = []
+ for arg in tf:
+ testfiles.extend(glob.glob(arg))
+ return testfiles
+
+def main(testfiles=None, action=printer):
+ """testfiles can be None, in which case the command line arguments are used as filenames.
+ testfiles can be a string, in which case that file is parsed.
+ testfiles can be a list.
+ In all cases, the filenames will be globbed.
+ If more than one file is parsed successfully, a dictionary of ParseResults is returned.
+ Otherwise, a simple ParseResults is returned.
+ """
+ testfiles = get_filename_list(testfiles)
+ print(testfiles)
+
+ if action:
+ for i in (simple_identifier, value, item_list):
+ i.setParseAction(action)
+
+ success = 0
+ failures = []
+
+ retval = {}
+ for f in testfiles:
+ try:
+ retval[f] = object_definition.parseFile(f)
+ success += 1
+ except:
+ failures.append(f)
+
+ if failures:
+ print('\nfailed while processing %s' % ', '.join(failures))
+ print('\nsucceeded on %d of %d files' %(success, len(testfiles)))
+
+ if len(retval) == 1 and len(testfiles) == 1:
+ # if only one file is parsed, return the parseResults directly
+ return retval[list(retval.keys())[0]]
+
+ # else, return a dictionary of parseResults
+ return retval
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/examples/dhcpd_leases_parser.py b/examples/dhcpd_leases_parser.py
new file mode 100644
index 0000000..145e6ea
--- /dev/null
+++ b/examples/dhcpd_leases_parser.py
@@ -0,0 +1,87 @@
+#
+# dhcpd_leases_parser.py
+#
+# Copyright 2008, Paul McGuire
+#
+# Sample parser to parse a dhcpd.leases file to extract leases
+# and lease attributes
+#
+# format ref: http://www.linuxmanpages.com/man5/dhcpd.leases.5.php
+#
+
+sample = r"""\
+# All times in this file are in UTC (GMT), not your local timezone. This is
+# not a bug, so please don't ask about it. There is no portable way to
+# store leases in the local timezone, so please don't request this as a
+# feature. If this is inconvenient or confusing to you, we sincerely
+# apologize. Seriously, though - don't ask.
+# The format of this file is documented in the dhcpd.leases(5) manual page.
+# This lease file was written by isc-dhcp-V3.0.4
+
+lease 192.168.0.250 {
+ starts 3 2008/01/23 17:16:41;
+ ends 6 2008/02/02 17:16:41;
+ tstp 6 2008/02/02 17:16:41;
+ binding state free;
+ hardware ethernet 00:17:f2:9b:d8:19;
+ uid "\001\000\027\362\233\330\031";
+}
+lease 192.168.0.198 {
+ starts 1 2008/02/04 13:46:55;
+ ends never;
+ tstp 1 2008/02/04 17:04:14;
+ binding state free;
+ hardware ethernet 00:13:72:d3:3b:98;
+ uid "\001\000\023r\323;\230";
+}
+lease 192.168.0.239 {
+ starts 3 2008/02/06 12:12:03;
+ ends 4 2008/02/07 12:12:03;
+ tstp 4 2008/02/07 12:12:03;
+ binding state free;
+ hardware ethernet 00:1d:09:65:93:26;
+}
+"""
+
+from pyparsing import *
+import datetime,time
+
+LBRACE,RBRACE,SEMI,QUOTE = map(Suppress,'{};"')
+ipAddress = Combine(Word(nums) + ('.' + Word(nums))*3)
+hexint = Word(hexnums,exact=2)
+macAddress = Combine(hexint + (':'+hexint)*5)
+hdwType = Word(alphanums)
+
+yyyymmdd = Combine((Word(nums,exact=4)|Word(nums,exact=2))+
+ ('/'+Word(nums,exact=2))*2)
+hhmmss = Combine(Word(nums,exact=2)+(':'+Word(nums,exact=2))*2)
+dateRef = oneOf(list("0123456"))("weekday") + yyyymmdd("date") + \
+ hhmmss("time")
+
+def utcToLocalTime(tokens):
+ utctime = datetime.datetime.strptime("%(date)s %(time)s" % tokens,
+ "%Y/%m/%d %H:%M:%S")
+ localtime = utctime-datetime.timedelta(0,time.timezone,0)
+ tokens["utcdate"],tokens["utctime"] = tokens["date"],tokens["time"]
+ tokens["localdate"],tokens["localtime"] = str(localtime).split()
+ del tokens["date"]
+ del tokens["time"]
+dateRef.setParseAction(utcToLocalTime)
+
+startsStmt = "starts" + dateRef + SEMI
+endsStmt = "ends" + (dateRef | "never") + SEMI
+tstpStmt = "tstp" + dateRef + SEMI
+tsfpStmt = "tsfp" + dateRef + SEMI
+hdwStmt = "hardware" + hdwType("type") + macAddress("mac") + SEMI
+uidStmt = "uid" + QuotedString('"')("uid") + SEMI
+bindingStmt = "binding" + Word(alphanums) + Word(alphanums) + SEMI
+
+leaseStatement = startsStmt | endsStmt | tstpStmt | tsfpStmt | hdwStmt | \
+ uidStmt | bindingStmt
+leaseDef = "lease" + ipAddress("ipaddress") + LBRACE + \
+ Dict(ZeroOrMore(Group(leaseStatement))) + RBRACE
+
+for lease in leaseDef.searchString(sample):
+ print(lease.dump())
+ print(lease.ipaddress,'->',lease.hardware.mac)
+ print()
diff --git a/examples/dictExample.py b/examples/dictExample.py
new file mode 100644
index 0000000..5085aed
--- /dev/null
+++ b/examples/dictExample.py
@@ -0,0 +1,41 @@
+#
+# dictExample.py
+#
+# Illustration of using pyparsing's Dict class to process tabular data
+#
+# Copyright (c) 2003, Paul McGuire
+#
+from pyparsing import Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, delimitedList
+import pprint
+
+testData = """
++-------+------+------+------+------+------+------+------+------+
+| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |
++=======+======+======+======+======+======+======+======+======+
+| min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 |
+| max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 |
+| ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 |
+| sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 |
++-------+------+------+------+------+------+------+------+------+
+"""
+
+# define grammar for datatable
+heading = (Literal(
+"+-------+------+------+------+------+------+------+------+------+") +
+"| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |" +
+"+=======+======+======+======+======+======+======+======+======+").suppress()
+vert = Literal("|").suppress()
+number = Word(nums)
+rowData = Group( vert + Word(alphas) + vert + delimitedList(number,"|") + vert )
+trailing = Literal(
+"+-------+------+------+------+------+------+------+------+------+").suppress()
+
+datatable = heading + Dict( ZeroOrMore(rowData) ) + trailing
+
+# now parse data and print results
+data = datatable.parseString(testData)
+print(data)
+pprint.pprint(data.asList())
+print("data keys=", list(data.keys()))
+print("data['min']=", data['min'])
+print("data.max", data.max)
diff --git a/examples/dictExample2.py b/examples/dictExample2.py
new file mode 100644
index 0000000..cae463b
--- /dev/null
+++ b/examples/dictExample2.py
@@ -0,0 +1,59 @@
+#
+# dictExample2.py
+#
+# Illustration of using pyparsing's Dict class to process tabular data
+# Enhanced Dict example, courtesy of Mike Kelly
+#
+# Copyright (c) 2004, Paul McGuire
+#
+from pyparsing import Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, delimitedList, pyparsing_common
+import pprint
+
+testData = """
++-------+------+------+------+------+------+------+------+------+
+| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |
++=======+======+======+======+======+======+======+======+======+
+| min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 |
+| max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 |
+| ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 |
+| sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 |
++-------+------+------+------+------+------+------+------+------+
+"""
+
+# define grammar for datatable
+underline = Word("-=")
+number = pyparsing_common.integer
+
+vert = Literal("|").suppress()
+
+rowDelim = ("+" + ZeroOrMore( underline + "+" ) ).suppress()
+columnHeader = Group(vert + vert + delimitedList(Word(alphas + nums), "|") + vert)
+
+heading = rowDelim + columnHeader("columns") + rowDelim
+rowData = Group( vert + Word(alphas) + vert + delimitedList(number,"|") + vert )
+trailing = rowDelim
+
+datatable = heading + Dict( ZeroOrMore(rowData) ) + trailing
+
+# now parse data and print results
+data = datatable.parseString(testData)
+print(data.dump())
+print("data keys=", list(data.keys()))
+print("data['min']=", data['min'])
+print("sum(data['min']) =", sum(data['min']))
+print("data.max =", data.max)
+print("sum(data.max) =", sum(data.max))
+
+# now print transpose of data table, using column labels read from table header and
+# values from data lists
+print()
+print(" " * 5, end=' ')
+for i in range(1,len(data)):
+ print("|%5s" % data[i][0], end=' ')
+print()
+print(("-" * 6) + ("+------" * (len(data)-1)))
+for i in range(len(data.columns)):
+ print("%5s" % data.columns[i], end=' ')
+ for j in range(len(data) - 1):
+ print('|%5s' % data[j + 1][i + 1], end=' ')
+ print()
diff --git a/examples/ebnf.py b/examples/ebnf.py
new file mode 100644
index 0000000..242aed4
--- /dev/null
+++ b/examples/ebnf.py
@@ -0,0 +1,151 @@
+# This module tries to implement ISO 14977 standard with pyparsing.
+# pyparsing version 1.1 or greater is required.
+
+# ISO 14977 standardize The Extended Backus-Naur Form(EBNF) syntax.
+# You can read a final draft version here:
+# http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html
+#
+# Submitted 2004 by Seo Sanghyeon
+#
+
+from pyparsing import *
+
+
+all_names = '''
+integer
+meta_identifier
+terminal_string
+optional_sequence
+repeated_sequence
+grouped_sequence
+syntactic_primary
+syntactic_factor
+syntactic_term
+single_definition
+definitions_list
+syntax_rule
+syntax
+'''.split()
+
+
+integer = Word(nums)
+meta_identifier = Word(alphas, alphanums + '_')
+terminal_string = Suppress("'") + CharsNotIn("'") + Suppress("'") ^ \
+ Suppress('"') + CharsNotIn('"') + Suppress('"')
+definitions_list = Forward()
+optional_sequence = Suppress('[') + definitions_list + Suppress(']')
+repeated_sequence = Suppress('{') + definitions_list + Suppress('}')
+grouped_sequence = Suppress('(') + definitions_list + Suppress(')')
+syntactic_primary = optional_sequence ^ repeated_sequence ^ \
+ grouped_sequence ^ meta_identifier ^ terminal_string
+syntactic_factor = Optional(integer + Suppress('*')) + syntactic_primary
+syntactic_term = syntactic_factor + Optional(Suppress('-') + syntactic_factor)
+single_definition = delimitedList(syntactic_term, ',')
+definitions_list << delimitedList(single_definition, '|')
+syntax_rule = meta_identifier + Suppress('=') + definitions_list + \
+ Suppress(';')
+
+ebnfComment = ( "(*" +
+ ZeroOrMore( CharsNotIn("*") | ( "*" + ~Literal(")") ) ) +
+ "*)" ).streamline().setName("ebnfComment")
+
+syntax = OneOrMore(syntax_rule)
+syntax.ignore(ebnfComment)
+
+
+def do_integer(str, loc, toks):
+ return int(toks[0])
+
+def do_meta_identifier(str, loc, toks):
+ if toks[0] in symbol_table:
+ return symbol_table[toks[0]]
+ else:
+ forward_count.value += 1
+ symbol_table[toks[0]] = Forward()
+ return symbol_table[toks[0]]
+
+def do_terminal_string(str, loc, toks):
+ return Literal(toks[0])
+
+def do_optional_sequence(str, loc, toks):
+ return Optional(toks[0])
+
+def do_repeated_sequence(str, loc, toks):
+ return ZeroOrMore(toks[0])
+
+def do_grouped_sequence(str, loc, toks):
+ return Group(toks[0])
+
+def do_syntactic_primary(str, loc, toks):
+ return toks[0]
+
+def do_syntactic_factor(str, loc, toks):
+ if len(toks) == 2:
+ # integer * syntactic_primary
+ return And([toks[1]] * toks[0])
+ else:
+ # syntactic_primary
+ return [ toks[0] ]
+
+def do_syntactic_term(str, loc, toks):
+ if len(toks) == 2:
+ # syntactic_factor - syntactic_factor
+ return NotAny(toks[1]) + toks[0]
+ else:
+ # syntactic_factor
+ return [ toks[0] ]
+
+def do_single_definition(str, loc, toks):
+ toks = toks.asList()
+ if len(toks) > 1:
+ # syntactic_term , syntactic_term , ...
+ return And(toks)
+ else:
+ # syntactic_term
+ return [ toks[0] ]
+
+def do_definitions_list(str, loc, toks):
+ toks = toks.asList()
+ if len(toks) > 1:
+ # single_definition | single_definition | ...
+ return Or(toks)
+ else:
+ # single_definition
+ return [ toks[0] ]
+
+def do_syntax_rule(str, loc, toks):
+ # meta_identifier = definitions_list ;
+ assert toks[0].expr is None, "Duplicate definition"
+ forward_count.value -= 1
+ toks[0] << toks[1]
+ return [ toks[0] ]
+
+def do_syntax(str, loc, toks):
+ # syntax_rule syntax_rule ...
+ return symbol_table
+
+
+
+symbol_table = {}
+class forward_count:
+ pass
+forward_count.value = 0
+for name in all_names:
+ expr = vars()[name]
+ action = vars()['do_' + name]
+ expr.setName(name)
+ expr.setParseAction(action)
+ #~ expr.setDebug()
+
+
+def parse(ebnf, given_table={}):
+ symbol_table.clear()
+ symbol_table.update(given_table)
+ forward_count.value = 0
+ table = syntax.parseString(ebnf)[0]
+ assert forward_count.value == 0, "Missing definition"
+ for name in table:
+ expr = table[name]
+ expr.setName(name)
+ #~ expr.setDebug()
+ return table
diff --git a/examples/ebnftest.py b/examples/ebnftest.py
new file mode 100644
index 0000000..253404f
--- /dev/null
+++ b/examples/ebnftest.py
@@ -0,0 +1,72 @@
+#
+# ebnftest.py
+#
+# Test script for ebnf.py
+#
+# Submitted 2004 by Seo Sanghyeon
+#
+print('Importing pyparsing...')
+from pyparsing import *
+
+print('Constructing EBNF parser with pyparsing...')
+import ebnf
+
+
+grammar = '''
+syntax = (syntax_rule), {(syntax_rule)};
+syntax_rule = meta_identifier, '=', definitions_list, ';';
+definitions_list = single_definition, {'|', single_definition};
+single_definition = syntactic_term, {',', syntactic_term};
+syntactic_term = syntactic_factor,['-', syntactic_factor];
+syntactic_factor = [integer, '*'], syntactic_primary;
+syntactic_primary = optional_sequence | repeated_sequence |
+ grouped_sequence | meta_identifier | terminal_string;
+optional_sequence = '[', definitions_list, ']';
+repeated_sequence = '{', definitions_list, '}';
+grouped_sequence = '(', definitions_list, ')';
+(*
+terminal_string = "'", character - "'", {character - "'"}, "'" |
+ '"', character - '"', {character - '"'}, '"';
+ meta_identifier = letter, {letter | digit};
+integer = digit, {digit};
+*)
+'''
+
+table = {}
+#~ table['character'] = Word(printables, exact=1)
+#~ table['letter'] = Word(alphas + '_', exact=1)
+#~ table['digit'] = Word(nums, exact=1)
+table['terminal_string'] = sglQuotedString
+table['meta_identifier'] = Word(alphas+"_", alphas+"_"+nums)
+table['integer'] = Word(nums)
+
+print('Parsing EBNF grammar with EBNF parser...')
+parsers = ebnf.parse(grammar, table)
+ebnf_parser = parsers['syntax']
+
+commentcharcount = 0
+commentlocs = set()
+def tallyCommentChars(s,l,t):
+ global commentcharcount,commentlocs
+ # only count this comment if we haven't seen it before
+ if l not in commentlocs:
+ charCount = ( len(t[0]) - len(list(filter(str.isspace, t[0]))) )
+ commentcharcount += charCount
+ commentlocs.add(l)
+ return l,t
+
+#ordinarily, these lines wouldn't be necessary, but we are doing extra stuff with the comment expression
+ebnf.ebnfComment.setParseAction( tallyCommentChars )
+ebnf_parser.ignore( ebnf.ebnfComment )
+
+print('Parsing EBNF grammar with generated EBNF parser...\n')
+parsed_chars = ebnf_parser.parseString(grammar)
+parsed_char_len = len(parsed_chars)
+
+print("],\n".join(str( parsed_chars.asList() ).split("],")))
+
+#~ grammar_length = len(grammar) - len(filter(str.isspace, grammar))-commentcharcount
+
+#~ assert parsed_char_len == grammar_length
+
+print('Ok!')
diff --git a/examples/eval_arith.py b/examples/eval_arith.py
new file mode 100644
index 0000000..9562253
--- /dev/null
+++ b/examples/eval_arith.py
@@ -0,0 +1,227 @@
+# eval_arith.py
+#
+# Copyright 2009, 2011 Paul McGuire
+#
+# Expansion on the pyparsing example simpleArith.py, to include evaluation
+# of the parsed tokens.
+#
+# Added support for exponentiation, using right-to-left evaluation of
+# operands
+#
+from pyparsing import Word, nums, alphas, Combine, oneOf, \
+ opAssoc, infixNotation, Literal
+
+class EvalConstant(object):
+ "Class to evaluate a parsed constant or variable"
+ vars_ = {}
+ def __init__(self, tokens):
+ self.value = tokens[0]
+ def eval(self):
+ if self.value in EvalConstant.vars_:
+ return EvalConstant.vars_[self.value]
+ else:
+ return float(self.value)
+
+class EvalSignOp(object):
+ "Class to evaluate expressions with a leading + or - sign"
+ def __init__(self, tokens):
+ self.sign, self.value = tokens[0]
+ def eval(self):
+ mult = {'+':1, '-':-1}[self.sign]
+ return mult * self.value.eval()
+
+def operatorOperands(tokenlist):
+ "generator to extract operators and operands in pairs"
+ it = iter(tokenlist)
+ while 1:
+ try:
+ yield (next(it), next(it))
+ except StopIteration:
+ break
+
+class EvalPowerOp(object):
+ "Class to evaluate multiplication and division expressions"
+ def __init__(self, tokens):
+ self.value = tokens[0]
+ def eval(self):
+ res = self.value[-1].eval()
+ for val in self.value[-3::-2]:
+ res = val.eval()**res
+ return res
+
+class EvalMultOp(object):
+ "Class to evaluate multiplication and division expressions"
+ def __init__(self, tokens):
+ self.value = tokens[0]
+ def eval(self):
+ prod = self.value[0].eval()
+ for op,val in operatorOperands(self.value[1:]):
+ if op == '*':
+ prod *= val.eval()
+ if op == '/':
+ prod /= val.eval()
+ return prod
+
+class EvalAddOp(object):
+ "Class to evaluate addition and subtraction expressions"
+ def __init__(self, tokens):
+ self.value = tokens[0]
+ def eval(self):
+ sum = self.value[0].eval()
+ for op,val in operatorOperands(self.value[1:]):
+ if op == '+':
+ sum += val.eval()
+ if op == '-':
+ sum -= val.eval()
+ return sum
+
+class EvalComparisonOp(object):
+ "Class to evaluate comparison expressions"
+ opMap = {
+ "<" : lambda a,b : a < b,
+ "<=" : lambda a,b : a <= b,
+ ">" : lambda a,b : a > b,
+ ">=" : lambda a,b : a >= b,
+ "!=" : lambda a,b : a != b,
+ "=" : lambda a,b : a == b,
+ "LT" : lambda a,b : a < b,
+ "LE" : lambda a,b : a <= b,
+ "GT" : lambda a,b : a > b,
+ "GE" : lambda a,b : a >= b,
+ "NE" : lambda a,b : a != b,
+ "EQ" : lambda a,b : a == b,
+ "<>" : lambda a,b : a != b,
+ }
+ def __init__(self, tokens):
+ self.value = tokens[0]
+ def eval(self):
+ val1 = self.value[0].eval()
+ for op,val in operatorOperands(self.value[1:]):
+ fn = EvalComparisonOp.opMap[op]
+ val2 = val.eval()
+ if not fn(val1,val2):
+ break
+ val1 = val2
+ else:
+ return True
+ return False
+
+
+# define the parser
+integer = Word(nums)
+real = Combine(Word(nums) + "." + Word(nums))
+variable = Word(alphas,exact=1)
+operand = real | integer | variable
+
+signop = oneOf('+ -')
+multop = oneOf('* /')
+plusop = oneOf('+ -')
+expop = Literal('**')
+
+# use parse actions to attach EvalXXX constructors to sub-expressions
+operand.setParseAction(EvalConstant)
+arith_expr = infixNotation(operand,
+ [
+ (signop, 1, opAssoc.RIGHT, EvalSignOp),
+ (expop, 2, opAssoc.LEFT, EvalPowerOp),
+ (multop, 2, opAssoc.LEFT, EvalMultOp),
+ (plusop, 2, opAssoc.LEFT, EvalAddOp),
+ ])
+
+comparisonop = oneOf("< <= > >= != = <> LT GT LE GE EQ NE")
+comp_expr = infixNotation(arith_expr,
+ [
+ (comparisonop, 2, opAssoc.LEFT, EvalComparisonOp),
+ ])
+
+def main():
+ # sample expressions posted on comp.lang.python, asking for advice
+ # in safely evaluating them
+ rules=[
+ '( A - B ) = 0',
+ '(A + B + C + D + E + F + G + H + I) = J',
+ '(A + B + C + D + E + F + G + H) = I',
+ '(A + B + C + D + E + F) = G',
+ '(A + B + C + D + E) = (F + G + H + I + J)',
+ '(A + B + C + D + E) = (F + G + H + I)',
+ '(A + B + C + D + E) = F',
+ '(A + B + C + D) = (E + F + G + H)',
+ '(A + B + C) = (D + E + F)',
+ '(A + B) = (C + D + E + F)',
+ '(A + B) = (C + D)',
+ '(A + B) = (C - D + E - F - G + H + I + J)',
+ '(A + B) = C',
+ '(A + B) = 0',
+ '(A+B+C+D+E) = (F+G+H+I+J)',
+ '(A+B+C+D) = (E+F+G+H)',
+ '(A+B+C+D)=(E+F+G+H)',
+ '(A+B+C)=(D+E+F)',
+ '(A+B)=(C+D)',
+ '(A+B)=C',
+ '(A-B)=C',
+ '(A/(B+C))',
+ '(B/(C+D))',
+ '(G + H) = I',
+ '-0.99 LE ((A+B+C)-(D+E+F+G)) LE 0.99',
+ '-0.99 LE (A-(B+C)) LE 0.99',
+ '-1000.00 LE A LE 0.00',
+ '-5000.00 LE A LE 0.00',
+ 'A < B',
+ 'A < 7000',
+ 'A = -(B)',
+ 'A = C',
+ 'A = 0',
+ 'A GT 0',
+ 'A GT 0.00',
+ 'A GT 7.00',
+ 'A LE B',
+ 'A LT -1000.00',
+ 'A LT -5000',
+ 'A LT 0',
+ 'A=(B+C+D)',
+ 'A=B',
+ 'I = (G + H)',
+ '0.00 LE A LE 4.00',
+ '4.00 LT A LE 7.00',
+ '0.00 LE A LE 4.00 LE E > D',
+ '2**2**(A+3)',
+ ]
+ vars_={'A': 0, 'B': 1.1, 'C': 2.2, 'D': 3.3, 'E': 4.4, 'F': 5.5, 'G':
+ 6.6, 'H':7.7, 'I':8.8, 'J':9.9}
+
+ # define tests from given rules
+ tests = []
+ for t in rules:
+ t_orig = t
+ t = t.replace("=","==")
+ t = t.replace("EQ","==")
+ t = t.replace("LE","<=")
+ t = t.replace("GT",">")
+ t = t.replace("LT","<")
+ t = t.replace("GE",">=")
+ t = t.replace("LE","<=")
+ t = t.replace("NE","!=")
+ t = t.replace("<>","!=")
+ tests.append( (t_orig,eval(t,vars_)) )
+
+ # copy vars_ to EvalConstant lookup dict
+ EvalConstant.vars_ = vars_
+ failed = 0
+ for test,expected in tests:
+ ret = comp_expr.parseString(test)[0]
+ parsedvalue = ret.eval()
+ print(test, expected, parsedvalue)
+ if parsedvalue != expected:
+ print("<<< FAIL")
+ failed += 1
+ else:
+ print('')
+
+ print('')
+ if failed:
+ print(failed, "tests FAILED")
+ else:
+ print("all tests PASSED")
+
+if __name__=='__main__':
+ main()
diff --git a/examples/excelExpr.py b/examples/excelExpr.py
new file mode 100644
index 0000000..7ce8db2
--- /dev/null
+++ b/examples/excelExpr.py
@@ -0,0 +1,69 @@
+# excelExpr.py
+#
+# Copyright 2010, Paul McGuire
+#
+# A partial implementation of a parser of Excel formula expressions.
+#
+from pyparsing import (CaselessKeyword, Suppress, Word, alphas,
+ alphanums, nums, Optional, Group, oneOf, Forward, Regex,
+ infixNotation, opAssoc, dblQuotedString, delimitedList,
+ Combine, Literal, QuotedString, ParserElement, pyparsing_common)
+ParserElement.enablePackrat()
+
+EQ,LPAR,RPAR,COLON,COMMA = map(Suppress, '=():,')
+EXCL, DOLLAR = map(Literal,"!$")
+sheetRef = Word(alphas, alphanums) | QuotedString("'",escQuote="''")
+colRef = Optional(DOLLAR) + Word(alphas,max=2)
+rowRef = Optional(DOLLAR) + Word(nums)
+cellRef = Combine(Group(Optional(sheetRef + EXCL)("sheet") + colRef("col") +
+ rowRef("row")))
+
+cellRange = (Group(cellRef("start") + COLON + cellRef("end"))("range")
+ | cellRef | Word(alphas,alphanums))
+
+expr = Forward()
+
+COMPARISON_OP = oneOf("< = > >= <= != <>")
+condExpr = expr + COMPARISON_OP + expr
+
+ifFunc = (CaselessKeyword("if") -
+ LPAR +
+ Group(condExpr)("condition") +
+ COMMA + Group(expr)("if_true") +
+ COMMA + Group(expr)("if_false") + RPAR)
+
+statFunc = lambda name : Group(CaselessKeyword(name) + Group(LPAR + delimitedList(expr) + RPAR))
+sumFunc = statFunc("sum")
+minFunc = statFunc("min")
+maxFunc = statFunc("max")
+aveFunc = statFunc("ave")
+funcCall = ifFunc | sumFunc | minFunc | maxFunc | aveFunc
+
+multOp = oneOf("* /")
+addOp = oneOf("+ -")
+numericLiteral = pyparsing_common.number
+operand = numericLiteral | funcCall | cellRange | cellRef
+arithExpr = infixNotation(operand,
+ [
+ (multOp, 2, opAssoc.LEFT),
+ (addOp, 2, opAssoc.LEFT),
+ ])
+
+textOperand = dblQuotedString | cellRef
+textExpr = infixNotation(textOperand,
+ [
+ ('&', 2, opAssoc.LEFT),
+ ])
+
+expr << (arithExpr | textExpr)
+
+
+(EQ + expr).runTests("""\
+ =3*A7+5
+ =3*Sheet1!$A$7+5
+ =3*'Sheet 1'!$A$7+5"
+ =3*'O''Reilly''s sheet'!$A$7+5
+ =if(Sum(A1:A25)>42,Min(B1:B25),if(Sum(C1:C25)>3.14, (Min(C1:C25)+3)*18,Max(B1:B25)))
+ =sum(a1:a25,10,min(b1,c2,d3))
+ =if("T"&a2="TTime", "Ready", "Not ready")
+""") \ No newline at end of file
diff --git a/examples/fourFn.py b/examples/fourFn.py
new file mode 100644
index 0000000..75f3909
--- /dev/null
+++ b/examples/fourFn.py
@@ -0,0 +1,192 @@
+# fourFn.py
+#
+# Demonstration of the pyparsing module, implementing a simple 4-function expression parser,
+# with support for scientific notation, and symbols for e and pi.
+# Extended to add exponentiation and simple built-in functions.
+# Extended test cases, simplified pushFirst method.
+# Removed unnecessary expr.suppress() call (thanks Nathaniel Peterson!), and added Group
+# Changed fnumber to use a Regex, which is now the preferred method
+#
+# Copyright 2003-2009 by Paul McGuire
+#
+from pyparsing import Literal,CaselessLiteral,Word,Group,Optional,\
+ ZeroOrMore,Forward,nums,alphas,alphanums,Regex,ParseException,\
+ CaselessKeyword, Suppress
+import math
+import operator
+
+exprStack = []
+
+def pushFirst( strg, loc, toks ):
+ exprStack.append( toks[0] )
+def pushUMinus( strg, loc, toks ):
+ for t in toks:
+ if t == '-':
+ exprStack.append( 'unary -' )
+ #~ exprStack.append( '-1' )
+ #~ exprStack.append( '*' )
+ else:
+ break
+
+bnf = None
+def BNF():
+ """
+ expop :: '^'
+ multop :: '*' | '/'
+ addop :: '+' | '-'
+ integer :: ['+' | '-'] '0'..'9'+
+ atom :: PI | E | real | fn '(' expr ')' | '(' expr ')'
+ factor :: atom [ expop factor ]*
+ term :: factor [ multop factor ]*
+ expr :: term [ addop term ]*
+ """
+ global bnf
+ if not bnf:
+ point = Literal( "." )
+ # use CaselessKeyword for e and pi, to avoid accidentally matching
+ # functions that start with 'e' or 'pi' (such as 'exp'); Keyword
+ # and CaselessKeyword only match whole words
+ e = CaselessKeyword( "E" )
+ pi = CaselessKeyword( "PI" )
+ #~ fnumber = Combine( Word( "+-"+nums, nums ) +
+ #~ Optional( point + Optional( Word( nums ) ) ) +
+ #~ Optional( e + Word( "+-"+nums, nums ) ) )
+ fnumber = Regex(r"[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?")
+ ident = Word(alphas, alphanums+"_$")
+
+ plus, minus, mult, div = map(Literal, "+-*/")
+ lpar, rpar = map(Suppress, "()")
+ addop = plus | minus
+ multop = mult | div
+ expop = Literal( "^" )
+
+ expr = Forward()
+ atom = ((0,None)*minus + ( pi | e | fnumber | ident + lpar + expr + rpar | ident ).setParseAction( pushFirst ) |
+ Group( lpar + expr + rpar )).setParseAction(pushUMinus)
+
+ # by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ
+ # that is, 2^3^2 = 2^(3^2), not (2^3)^2.
+ factor = Forward()
+ factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
+
+ term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
+ expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
+ bnf = expr
+ return bnf
+
+# map operator symbols to corresponding arithmetic operations
+epsilon = 1e-12
+opn = { "+" : operator.add,
+ "-" : operator.sub,
+ "*" : operator.mul,
+ "/" : operator.truediv,
+ "^" : operator.pow }
+fn = { "sin" : math.sin,
+ "cos" : math.cos,
+ "tan" : math.tan,
+ "exp" : math.exp,
+ "abs" : abs,
+ "trunc" : lambda a: int(a),
+ "round" : round,
+ "sgn" : lambda a: (a > epsilon) - (a < -epsilon) }
+def evaluateStack( s ):
+ op = s.pop()
+ if op == 'unary -':
+ return -evaluateStack( s )
+ if op in "+-*/^":
+ op2 = evaluateStack( s )
+ op1 = evaluateStack( s )
+ return opn[op]( op1, op2 )
+ elif op == "PI":
+ return math.pi # 3.1415926535
+ elif op == "E":
+ return math.e # 2.718281828
+ elif op in fn:
+ return fn[op]( evaluateStack( s ) )
+ elif op[0].isalpha():
+ raise Exception("invalid identifier '%s'" % op)
+ else:
+ return float( op )
+
+if __name__ == "__main__":
+
+ def test( s, expVal ):
+ global exprStack
+ exprStack[:] = []
+ try:
+ results = BNF().parseString( s, parseAll=True )
+ val = evaluateStack( exprStack[:] )
+ except ParseException as e:
+ print(s, "failed parse:", str(pe))
+ except Exception as e:
+ print(s, "failed eval:", str(e))
+ else:
+ if val == expVal:
+ print(s, "=", val, results, "=>", exprStack)
+ else:
+ print(s+"!!!", val, "!=", expVal, results, "=>", exprStack)
+
+ test( "9", 9 )
+ test( "-9", -9 )
+ test( "--9", 9 )
+ test( "-E", -math.e )
+ test( "9 + 3 + 6", 9 + 3 + 6 )
+ test( "9 + 3 / 11", 9 + 3.0 / 11 )
+ test( "(9 + 3)", (9 + 3) )
+ test( "(9+3) / 11", (9+3.0) / 11 )
+ test( "9 - 12 - 6", 9 - 12 - 6 )
+ test( "9 - (12 - 6)", 9 - (12 - 6) )
+ test( "2*3.14159", 2*3.14159 )
+ test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535 / 10 )
+ test( "PI * PI / 10", math.pi * math.pi / 10 )
+ test( "PI*PI/10", math.pi*math.pi/10 )
+ test( "PI^2", math.pi**2 )
+ test( "round(PI^2)", round(math.pi**2) )
+ test( "6.02E23 * 8.048", 6.02E23 * 8.048 )
+ test( "e / 3", math.e / 3 )
+ test( "sin(PI/2)", math.sin(math.pi/2) )
+ test( "trunc(E)", int(math.e) )
+ test( "trunc(-E)", int(-math.e) )
+ test( "round(E)", round(math.e) )
+ test( "round(-E)", round(-math.e) )
+ test( "E^PI", math.e**math.pi )
+ test( "exp(0)", 1 )
+ test( "exp(1)", math.e )
+ test( "2^3^2", 2**3**2 )
+ test( "2^3+2", 2**3+2 )
+ test( "2^3+5", 2**3+5 )
+ test( "2^9", 2**9 )
+ test( "sgn(-2)", -1 )
+ test( "sgn(0)", 0 )
+ test( "foo(0.1)", None )
+ test( "sgn(0.1)", 1 )
+
+
+"""
+Test output:
+>pythonw -u fourFn.py
+9 = 9.0 ['9'] => ['9']
+9 + 3 + 6 = 18.0 ['9', '+', '3', '+', '6'] => ['9', '3', '+', '6', '+']
+9 + 3 / 11 = 9.27272727273 ['9', '+', '3', '/', '11'] => ['9', '3', '11', '/', '+']
+(9 + 3) = 12.0 [] => ['9', '3', '+']
+(9+3) / 11 = 1.09090909091 ['/', '11'] => ['9', '3', '+', '11', '/']
+9 - 12 - 6 = -9.0 ['9', '-', '12', '-', '6'] => ['9', '12', '-', '6', '-']
+9 - (12 - 6) = 3.0 ['9', '-'] => ['9', '12', '6', '-', '-']
+2*3.14159 = 6.28318 ['2', '*', '3.14159'] => ['2', '3.14159', '*']
+3.1415926535*3.1415926535 / 10 = 0.986960440053 ['3.1415926535', '*', '3.1415926535', '/', '10'] => ['3.1415926535', '3.1415926535', '*', '10', '/']
+PI * PI / 10 = 0.986960440109 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/']
+PI*PI/10 = 0.986960440109 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/']
+PI^2 = 9.86960440109 ['PI', '^', '2'] => ['PI', '2', '^']
+6.02E23 * 8.048 = 4.844896e+024 ['6.02E23', '*', '8.048'] => ['6.02E23', '8.048', '*']
+e / 3 = 0.90609394282 ['E', '/', '3'] => ['E', '3', '/']
+sin(PI/2) = 1.0 ['sin', 'PI', '/', '2'] => ['PI', '2', '/', 'sin']
+trunc(E) = 2 ['trunc', 'E'] => ['E', 'trunc']
+E^PI = 23.1406926328 ['E', '^', 'PI'] => ['E', 'PI', '^']
+2^3^2 = 512.0 ['2', '^', '3', '^', '2'] => ['2', '3', '2', '^', '^']
+2^3+2 = 10.0 ['2', '^', '3', '+', '2'] => ['2', '3', '^', '2', '+']
+2^9 = 512.0 ['2', '^', '9'] => ['2', '9', '^']
+sgn(-2) = -1 ['sgn', '-2'] => ['-2', 'sgn']
+sgn(0) = 0 ['sgn', '0'] => ['0', 'sgn']
+sgn(0.1) = 1 ['sgn', '0.1'] => ['0.1', 'sgn']
+>Exit code: 0
+"""
diff --git a/examples/gen_ctypes.py b/examples/gen_ctypes.py
new file mode 100644
index 0000000..9e74819
--- /dev/null
+++ b/examples/gen_ctypes.py
@@ -0,0 +1,174 @@
+#
+# gen_ctypes.py
+#
+# Parse a .h header file to generate ctypes argtype and return type definitions
+#
+# Copyright 2004-2016, by Paul McGuire
+#
+from pyparsing import *
+
+typemap = {
+ "byte" : "c_byte",
+ "char" : "c_char",
+ "char *" : "c_char_p",
+ "double" : "c_double",
+ "float" : "c_float",
+ "int" : "c_int",
+ "int16" : "c_int16",
+ "int32" : "c_int32",
+ "int64" : "c_int64",
+ "int8" : "c_int8",
+ "long" : "c_long",
+ "longlong" : "c_longlong",
+ "short" : "c_short",
+ "size_t" : "c_size_t",
+ "ubyte" : "c_ubyte",
+ "uchar" : "c_ubyte",
+ "u_char" : "c_ubyte",
+ "uint" : "c_uint",
+ "u_int" : "c_uint",
+ "uint16" : "c_uint16",
+ "uint32" : "c_uint32",
+ "uint64" : "c_uint64",
+ "uint8" : "c_uint8",
+ "u_long" : "c_ulong",
+ "ulong" : "c_ulong",
+ "ulonglong" : "c_ulonglong",
+ "ushort" : "c_ushort",
+ "u_short" : "c_ushort",
+ "void *" : "c_void_p",
+ "voidp" : "c_voidp",
+ "wchar" : "c_wchar",
+ "wchar *" : "c_wchar_p",
+ "Bool" : "c_bool",
+ "void" : "None",
+ }
+
+LPAR,RPAR,LBRACE,RBRACE,COMMA,SEMI = map(Suppress,"(){},;")
+ident = Word(alphas, alphanums + "_")
+integer = Regex(r"[+-]?\d+")
+hexinteger = Regex(r"0x[0-9a-fA-F]+")
+
+const = Suppress("const")
+primitiveType = oneOf(t for t in typemap if not t.endswith("*"))
+structType = Suppress("struct") + ident
+vartype = (Optional(const) +
+ (primitiveType | structType | ident) +
+ Optional(Word("*")("ptr")))
+def normalizetype(t):
+ if isinstance(t, ParseResults):
+ return ' '.join(t)
+ #~ ret = ParseResults([' '.join(t)])
+ #~ return ret
+
+vartype.setParseAction(normalizetype)
+
+arg = Group(vartype("argtype") + Optional(ident("argname")))
+func_def = (vartype("fn_type") + ident("fn_name") +
+ LPAR + Optional(delimitedList(arg|"..."))("fn_args") + RPAR + SEMI)
+def derivefields(t):
+ if t.fn_args and t.fn_args[-1] == "...":
+ t["varargs"]=True
+func_def.setParseAction(derivefields)
+
+fn_typedef = "typedef" + func_def
+var_typedef = "typedef" + primitiveType("primType") + ident("name") + SEMI
+
+enum_def = (Keyword("enum") + LBRACE +
+ delimitedList(Group(ident("name") + '=' + (hexinteger|integer)("value")))("evalues")
+ + Optional(COMMA)
+ + RBRACE)
+
+c_header = open("snmp_api.h").read()
+
+
+module = "pynetsnmp"
+
+user_defined_types = set()
+typedefs = []
+fn_typedefs = []
+functions = []
+enum_constants = []
+
+# add structures commonly included from std lib headers
+def addStdType(t,namespace=""):
+ fullname = namespace+'_'+t if namespace else t
+ typemap[t] = fullname
+ user_defined_types.add(t)
+addStdType("fd_set", "sys_select")
+addStdType("timeval", "sys_time")
+
+def getUDType(typestr):
+ key = typestr.rstrip(" *")
+ if key not in typemap:
+ user_defined_types.add(key)
+ typemap[key] = "%s_%s" % (module, key)
+
+def typeAsCtypes(typestr):
+ if typestr in typemap:
+ return typemap[typestr]
+ if typestr.endswith("*"):
+ return "POINTER(%s)" % typeAsCtypes(typestr.rstrip(" *"))
+ return typestr
+
+# scan input header text for primitive typedefs
+for td,_,_ in var_typedef.scanString(c_header):
+ typedefs.append( (td.name, td.primType) )
+ # add typedef type to typemap to map to itself
+ typemap[td.name] = td.name
+
+# scan input header text for function typedefs
+fn_typedefs = fn_typedef.searchString(c_header)
+# add each function typedef to typemap to map to itself
+for fntd in fn_typedefs:
+ typemap[fntd.fn_name] = fntd.fn_name
+
+# scan input header text, and keep running list of user-defined types
+for fn,_,_ in (cStyleComment.suppress() | fn_typedef.suppress() | func_def).scanString(c_header):
+ if not fn: continue
+ getUDType(fn.fn_type)
+ for arg in fn.fn_args:
+ if arg != "...":
+ if arg.argtype not in typemap:
+ getUDType(arg.argtype)
+ functions.append(fn)
+
+# scan input header text for enums
+enum_def.ignore(cppStyleComment)
+for en_,_,_ in enum_def.scanString(c_header):
+ for ev in en_.evalues:
+ enum_constants.append( (ev.name, ev.value) )
+
+print("from ctypes import *")
+print("%s = CDLL('%s.dll')" % (module, module))
+print()
+print("# user defined types")
+for tdname,tdtyp in typedefs:
+ print("%s = %s" % (tdname, typemap[tdtyp]))
+for fntd in fn_typedefs:
+ print("%s = CFUNCTYPE(%s)" % (fntd.fn_name,
+ ',\n '.join(typeAsCtypes(a.argtype) for a in fntd.fn_args)))
+for udtype in user_defined_types:
+ print("class %s(Structure): pass" % typemap[udtype])
+
+print()
+print("# constant definitions")
+for en,ev in enum_constants:
+ print("%s = %s" % (en,ev))
+
+print()
+print("# functions")
+for fn in functions:
+ prefix = "%s.%s" % (module, fn.fn_name)
+
+ print("%s.restype = %s" % (prefix, typeAsCtypes(fn.fn_type)))
+ if fn.varargs:
+ print("# warning - %s takes variable argument list" % prefix)
+ del fn.fn_args[-1]
+
+ if fn.fn_args.asList() != [['void']]:
+ print("%s.argtypes = (%s,)" % (prefix, ','.join(typeAsCtypes(a.argtype) for a in fn.fn_args)))
+ else:
+ print("%s.argtypes = ()" % (prefix))
+
+
diff --git a/examples/getNTPservers.py b/examples/getNTPservers.py
new file mode 100644
index 0000000..bbf1d60
--- /dev/null
+++ b/examples/getNTPservers.py
@@ -0,0 +1,30 @@
+# getNTPservers.py
+#
+# Demonstration of the parsing module, implementing a HTML page scanner,
+# to extract a list of NTP time servers from the NIST web site.
+#
+# Copyright 2004, by Paul McGuire
+#
+from pyparsing import Word, Combine, Suppress, CharsNotIn, nums
+import urllib.request, urllib.parse, urllib.error
+
+integer = Word(nums)
+ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer )
+tdStart = Suppress("<td>")
+tdEnd = Suppress("</td>")
+timeServerPattern = tdStart + ipAddress.setResultsName("ipAddr") + tdEnd + \
+ tdStart + CharsNotIn("<").setResultsName("loc") + tdEnd
+
+# get list of time servers
+nistTimeServerURL = "http://www.boulder.nist.gov/timefreq/service/time-servers.html"
+serverListPage = urllib.request.urlopen( nistTimeServerURL )
+serverListHTML = serverListPage.read()
+serverListPage.close()
+
+addrs = {}
+for srvr,startloc,endloc in timeServerPattern.scanString( serverListHTML ):
+ print(srvr.ipAddr, "-", srvr.loc)
+ addrs[srvr.ipAddr] = srvr.loc
+ # or do this:
+ #~ addr,loc = srvr
+ #~ print addr, "-", loc
diff --git a/examples/getNTPserversNew.py b/examples/getNTPserversNew.py
new file mode 100644
index 0000000..14e710c
--- /dev/null
+++ b/examples/getNTPserversNew.py
@@ -0,0 +1,35 @@
+# getNTPserversNew.py
+#
+# Demonstration of the parsing module, implementing a HTML page scanner,
+# to extract a list of NTP time servers from the NIST web site.
+#
+# Copyright 2004-2010, by Paul McGuire
+# September, 2010 - updated to more current use of setResultsName, new NIST URL
+#
+from pyparsing import (Word, Combine, Suppress, SkipTo, nums, makeHTMLTags,
+ delimitedList, alphas, alphanums)
+try:
+ import urllib.request
+ urlopen = urllib.request.urlopen
+except ImportError:
+ import urllib
+ urlopen = urllib.urlopen
+
+integer = Word(nums)
+ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer )
+hostname = delimitedList(Word(alphas,alphanums+"-_"),".",combine=True)
+tdStart,tdEnd = makeHTMLTags("td")
+timeServerPattern = (tdStart + hostname("hostname") + tdEnd +
+ tdStart + ipAddress("ipAddr") + tdEnd +
+ tdStart + SkipTo(tdEnd)("loc") + tdEnd)
+
+# get list of time servers
+nistTimeServerURL = "http://tf.nist.gov/tf-cgi/servers.cgi#"
+serverListPage = urlopen( nistTimeServerURL )
+serverListHTML = serverListPage.read().decode("UTF-8")
+serverListPage.close()
+
+addrs = {}
+for srvr,startloc,endloc in timeServerPattern.scanString( serverListHTML ):
+ print("%s (%s) - %s" % (srvr.ipAddr, srvr.hostname.strip(), srvr.loc.strip()))
+ addrs[srvr.ipAddr] = srvr.loc
diff --git a/examples/greeting.py b/examples/greeting.py
new file mode 100644
index 0000000..2e6b241
--- /dev/null
+++ b/examples/greeting.py
@@ -0,0 +1,17 @@
+# greeting.py
+#
+# Demonstration of the pyparsing module, on the prototypical "Hello, World!"
+# example
+#
+# Copyright 2003, by Paul McGuire
+#
+from pyparsing import Word, alphas
+
+# define grammar
+greet = Word( alphas ) + "," + Word( alphas ) + "!"
+
+# input string
+hello = "Hello, World!"
+
+# parse input string
+print(hello, "->", greet.parseString( hello ))
diff --git a/examples/greetingInGreek.py b/examples/greetingInGreek.py
new file mode 100644
index 0000000..c4d002f
--- /dev/null
+++ b/examples/greetingInGreek.py
@@ -0,0 +1,20 @@
+# vim:fileencoding=utf-8
+#
+# greetingInGreek.py
+#
+# Demonstration of the parsing module, on the prototypical "Hello, World!" example
+#
+# Copyright 2004-2016, by Paul McGuire
+#
+from pyparsing import Word
+
+# define grammar
+alphas = ''.join(chr(x) for x in range(0x386, 0x3ce))
+greet = Word(alphas) + ',' + Word(alphas) + '!'
+
+# input string
+hello = "Καλημέρα, κόσμε!".decode('utf-8')
+
+# parse input string
+print(greet.parseString( hello ))
+
diff --git a/examples/greetingInKorean.py b/examples/greetingInKorean.py
new file mode 100644
index 0000000..e48cc8b
--- /dev/null
+++ b/examples/greetingInKorean.py
@@ -0,0 +1,22 @@
+# vim:fileencoding=utf-8
+#
+# greetingInKorean.py
+#
+# Demonstration of the parsing module, on the prototypical "Hello, World!" example
+#
+# Copyright 2004-2016, by Paul McGuire
+#
+from pyparsing import Word, srange
+
+koreanChars = srange(r"[\0xac00-\0xd7a3]")
+koreanWord = Word(koreanChars,min=2)
+
+# define grammar
+greet = koreanWord + "," + koreanWord + "!"
+
+# input string
+hello = '\uc548\ub155, \uc5ec\ub7ec\ubd84!' #"Hello, World!" in Korean
+
+# parse input string
+print(greet.parseString( hello ))
+
diff --git a/examples/groupUsingListAllMatches.py b/examples/groupUsingListAllMatches.py
new file mode 100644
index 0000000..28cdfd6
--- /dev/null
+++ b/examples/groupUsingListAllMatches.py
@@ -0,0 +1,17 @@
+#
+# A simple example showing the use of the implied listAllMatches=True for
+# results names with a trailing '*' character.
+#
+# This example performs work similar to itertools.groupby, but without
+# having to sort the input first.
+#
+# Copyright 2004-2016, by Paul McGuire
+#
+from pyparsing import Word, ZeroOrMore, nums
+
+aExpr = Word("A", nums)
+bExpr = Word("B", nums)
+cExpr = Word("C", nums)
+grammar = ZeroOrMore(aExpr("A*") | bExpr("B*") | cExpr("C*"))
+
+grammar.runTests("A1 B1 A2 C1 B2 A3")
diff --git a/examples/holaMundo.py b/examples/holaMundo.py
new file mode 100644
index 0000000..6ae2cc5
--- /dev/null
+++ b/examples/holaMundo.py
@@ -0,0 +1,38 @@
+# -*- coding: UTF-8 -*-
+
+# escrito por Marco Alfonso, 2004 Noviembre
+
+# importamos el modulo
+from pyparsing import *
+saludo= Word(alphas) + ',' + Word(alphas) + '!'
+
+# Aqui decimos que la gramatica "saludo" DEBE contener
+# una palabra compuesta de caracteres alfanumericos
+# (Word(alphas)) mas una ',' mas otra palabra alfanumerica,
+# mas '!' y esos seian nuestros tokens
+tokens = saludo.parseString("Hola, Mundo !")
+
+# Ahora parseamos una cadena, "Hola, Mundo!",
+# el metodo parseString, nos devuelve una lista con los tokens
+# encontrados, en caso de no haber errores...
+for i in range(len(tokens)):
+ print ("Token %d -> %s" % (i,tokens[i]))
+
+#imprimimos cada uno de los tokens Y listooo!!, he aquí a salida
+# Token 0 -> Hola
+# Token 1 -> ,
+# Token 2-> Mundo
+# Token 3 -> !
+
+# Por supuesto, se pueden "reutilizar" gramáticas, por ejemplo:
+numimag = Word(nums) + 'i'
+numreal = Word(nums)
+numcomplex = numreal + '+' + numimag
+print (numcomplex.parseString("3+5i"))
+
+# Cambiar a complejo numero durante parsear:
+numcomplex.setParseAction(lambda t: complex(''.join(t).replace('i','j')))
+print (numcomplex.parseString("3+5i"))
+
+# Excelente!!, bueno, los dejo, me voy a seguir tirando código...
+
diff --git a/examples/htmlStripper.py b/examples/htmlStripper.py
new file mode 100644
index 0000000..1d7a0f0
--- /dev/null
+++ b/examples/htmlStripper.py
@@ -0,0 +1,32 @@
+#
+# htmlStripper.py
+#
+# Sample code for stripping HTML markup tags and scripts from
+# HTML source files.
+#
+# Copyright (c) 2006, 2016, Paul McGuire
+#
+from contextlib import closing
+import urllib.request, urllib.parse, urllib.error
+from pyparsing import (makeHTMLTags, SkipTo, commonHTMLEntity, replaceHTMLEntity,
+ htmlComment, anyOpenTag, anyCloseTag, LineEnd, OneOrMore, replaceWith)
+
+scriptOpen,scriptClose = makeHTMLTags("script")
+scriptBody = scriptOpen + SkipTo(scriptClose) + scriptClose
+commonHTMLEntity.setParseAction(replaceHTMLEntity)
+
+# get some HTML
+targetURL = "http://wiki.python.org/moin/PythonDecoratorLibrary"
+with closing(urllib.request.urlopen( targetURL )) as targetPage:
+ targetHTML = targetPage.read().decode("UTF-8")
+
+# first pass, strip out tags and translate entities
+firstPass = (htmlComment | scriptBody | commonHTMLEntity |
+ anyOpenTag | anyCloseTag ).suppress().transformString(targetHTML)
+
+# first pass leaves many blank lines, collapse these down
+repeatedNewlines = LineEnd() + OneOrMore(LineEnd())
+repeatedNewlines.setParseAction(replaceWith("\n\n"))
+secondPass = repeatedNewlines.transformString(firstPass)
+
+print(secondPass) \ No newline at end of file
diff --git a/examples/httpServerLogParser.py b/examples/httpServerLogParser.py
new file mode 100644
index 0000000..a147a05
--- /dev/null
+++ b/examples/httpServerLogParser.py
@@ -0,0 +1,73 @@
+# httpServerLogParser.py
+#
+# Copyright (c) 2016, Paul McGuire
+#
+"""
+Parser for HTTP server log output, of the form:
+
+195.146.134.15 - - [20/Jan/2003:08:55:36 -0800]
+"GET /path/to/page.html HTTP/1.0" 200 4649 "http://www.somedomain.com/020602/page.html"
+"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
+127.0.0.1 - u.surname@domain.com [12/Sep/2006:14:13:53 +0300]
+"GET /skins/monobook/external.png HTTP/1.0" 304 - "http://wiki.mysite.com/skins/monobook/main.css"
+"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6"
+
+You can then break it up as follows:
+IP ADDRESS - -
+Server Date / Time [SPACE]
+"GET /path/to/page
+HTTP/Type Request"
+Success Code
+Bytes Sent To Client
+Referer
+Client Software
+"""
+
+from pyparsing import alphas,nums, dblQuotedString, Combine, Word, Group, delimitedList, Suppress, removeQuotes
+import string
+
+def getCmdFields( s, l, t ):
+ t["method"],t["requestURI"],t["protocolVersion"] = t[0].strip('"').split()
+
+logLineBNF = None
+def getLogLineBNF():
+ global logLineBNF
+
+ if logLineBNF is None:
+ integer = Word( nums )
+ ipAddress = delimitedList( integer, ".", combine=True )
+
+ timeZoneOffset = Word("+-",nums)
+ month = Word(string.uppercase, string.lowercase, exact=3)
+ serverDateTime = Group( Suppress("[") +
+ Combine( integer + "/" + month + "/" + integer +
+ ":" + integer + ":" + integer + ":" + integer ) +
+ timeZoneOffset +
+ Suppress("]") )
+
+ logLineBNF = ( ipAddress.setResultsName("ipAddr") +
+ Suppress("-") +
+ ("-" | Word( alphas+nums+"@._" )).setResultsName("auth") +
+ serverDateTime.setResultsName("timestamp") +
+ dblQuotedString.setResultsName("cmd").setParseAction(getCmdFields) +
+ (integer | "-").setResultsName("statusCode") +
+ (integer | "-").setResultsName("numBytesSent") +
+ dblQuotedString.setResultsName("referrer").setParseAction(removeQuotes) +
+ dblQuotedString.setResultsName("clientSfw").setParseAction(removeQuotes) )
+ return logLineBNF
+
+testdata = """
+195.146.134.15 - - [20/Jan/2003:08:55:36 -0800] "GET /path/to/page.html HTTP/1.0" 200 4649 "http://www.somedomain.com/020602/page.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
+111.111.111.11 - - [16/Feb/2004:04:09:49 -0800] "GET /ads/redirectads/336x280redirect.htm HTTP/1.1" 304 - "http://www.foobarp.org/theme_detail.php?type=vs&cat=0&mid=27512" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
+11.111.11.111 - - [16/Feb/2004:10:35:12 -0800] "GET /ads/redirectads/468x60redirect.htm HTTP/1.1" 200 541 "http://11.11.111.11/adframe.php?n=ad1f311a&what=zone:56" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [ru\"]"
+127.0.0.1 - u.surname@domain.com [12/Sep/2006:14:13:53 +0300] "GET /skins/monobook/external.png HTTP/1.0" 304 - "http://wiki.mysite.com/skins/monobook/main.css" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6"
+"""
+for line in testdata.split("\n"):
+ if not line: continue
+ fields = getLogLineBNF().parseString(line)
+ print(fields.dump())
+ #~ print repr(fields)
+ #~ for k in fields.keys():
+ #~ print "fields." + k + " =", fields[k]
+ print(fields.asXML("LOG"))
+ print()
diff --git a/examples/idlParse.py b/examples/idlParse.py
new file mode 100644
index 0000000..b94bac4
--- /dev/null
+++ b/examples/idlParse.py
@@ -0,0 +1,173 @@
+#
+# idlparse.py
+#
+# an example of using the parsing module to be able to process a subset of the CORBA IDL grammar
+#
+# Copyright (c) 2003, Paul McGuire
+#
+
+from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
+ Forward, NotAny, delimitedList, oneOf, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
+ alphanums, printables, empty, quotedString, ParseException, ParseResults, Keyword, Regex
+import pprint
+#~ import tree2image
+
+bnf = None
+def CORBA_IDL_BNF():
+ global bnf
+
+ if not bnf:
+
+ # punctuation
+ (colon,lbrace,rbrace,lbrack,rbrack,lparen,rparen,
+ equals,comma,dot,slash,bslash,star,semi,langle,rangle) = map(Literal, r":{}[]()=,./\*;<>")
+
+ # keywords
+ (any_, attribute_, boolean_, case_, char_, const_, context_, default_, double_, enum_, exception_,
+ FALSE_, fixed_, float_, inout_, interface_, in_, long_, module_, Object_, octet_, oneway_, out_, raises_,
+ readonly_, sequence_, short_, string_, struct_, switch_, TRUE_, typedef_, unsigned_, union_, void_,
+ wchar_, wstring_) = map(Keyword, """any attribute boolean case char const context
+ default double enum exception FALSE fixed float inout interface in long module
+ Object octet oneway out raises readonly sequence short string struct switch
+ TRUE typedef unsigned union void wchar wstring""".split())
+
+ identifier = Word( alphas, alphanums + "_" ).setName("identifier")
+
+ real = Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?").setName("real")
+ integer = Regex(r"0x[0-9a-fA-F]+|[+-]?\d+").setName("int")
+
+ udTypeName = delimitedList( identifier, "::", combine=True ).setName("udType")
+ typeName = ( any_ | boolean_ | char_ | double_ | fixed_ |
+ float_ | long_ | octet_ | short_ | string_ |
+ wchar_ | wstring_ | udTypeName ).setName("type")
+ sequenceDef = Forward().setName("seq")
+ sequenceDef << Group( sequence_ + langle + ( sequenceDef | typeName ) + rangle )
+ typeDef = sequenceDef | ( typeName + Optional( lbrack + integer + rbrack ) )
+ typedefDef = Group( typedef_ + typeDef + identifier + semi ).setName("typedef")
+
+ moduleDef = Forward()
+ constDef = Group( const_ + typeDef + identifier + equals + ( real | integer | quotedString ) + semi ) #| quotedString )
+ exceptionItem = Group( typeDef + identifier + semi )
+ exceptionDef = ( exception_ + identifier + lbrace + ZeroOrMore( exceptionItem ) + rbrace + semi )
+ attributeDef = Optional( readonly_ ) + attribute_ + typeDef + identifier + semi
+ paramlist = delimitedList( Group( ( inout_ | in_ | out_ ) + typeName + identifier ) ).setName( "paramlist" )
+ operationDef = ( ( void_ ^ typeDef ) + identifier + lparen + Optional( paramlist ) + rparen + \
+ Optional( raises_ + lparen + Group( delimitedList( typeName ) ) + rparen ) + semi )
+ interfaceItem = ( constDef | exceptionDef | attributeDef | operationDef )
+ interfaceDef = Group( interface_ + identifier + Optional( colon + delimitedList( typeName ) ) + lbrace + \
+ ZeroOrMore( interfaceItem ) + rbrace + semi ).setName("opnDef")
+ moduleItem = ( interfaceDef | exceptionDef | constDef | typedefDef | moduleDef )
+ moduleDef << module_ + identifier + lbrace + ZeroOrMore( moduleItem ) + rbrace + semi
+
+ bnf = ( moduleDef | OneOrMore( moduleItem ) )
+
+ singleLineComment = "//" + restOfLine
+ bnf.ignore( singleLineComment )
+ bnf.ignore( cStyleComment )
+
+ return bnf
+
+testnum = 1
+def test( strng ):
+ global testnum
+ print(strng)
+ try:
+ bnf = CORBA_IDL_BNF()
+ tokens = bnf.parseString( strng )
+ print("tokens = ")
+ pprint.pprint( tokens.asList() )
+ imgname = "idlParse%02d.bmp" % testnum
+ testnum += 1
+ #~ tree2image.str2image( str(tokens.asList()), imgname )
+ except ParseException as err:
+ print(err.line)
+ print(" "*(err.column-1) + "^")
+ print(err)
+ print()
+
+if __name__ == "__main__":
+ test(
+ """
+ /*
+ * a block comment *
+ */
+ typedef string[10] tenStrings;
+ typedef sequence<string> stringSeq;
+ typedef sequence< sequence<string> > stringSeqSeq;
+
+ interface QoSAdmin {
+ stringSeq method1( in string arg1, inout long arg2 );
+ stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
+ string method3();
+ };
+ """
+ )
+ test(
+ """
+ /*
+ * a block comment *
+ */
+ typedef string[10] tenStrings;
+ typedef
+ /** ** *** **** *
+ * a block comment *
+ */
+ sequence<string> /*comment inside an And */ stringSeq;
+ /* */ /**/ /***/ /****/
+ typedef sequence< sequence<string> > stringSeqSeq;
+
+ interface QoSAdmin {
+ stringSeq method1( in string arg1, inout long arg2 );
+ stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3);
+ string method3();
+ };
+ """
+ )
+ test(
+ r"""
+ const string test="Test String\n";
+ const long a = 0;
+ const long b = -100;
+ const float c = 3.14159;
+ const long d = 0x007f7f7f;
+ exception TestException
+ {
+ string msg;
+ sequence<string> dataStrings;
+ };
+
+ interface TestInterface
+ {
+ void method1( in string arg1, inout long arg2 );
+ };
+ """
+ )
+ test(
+ """
+ module Test1
+ {
+ exception TestException
+ {
+ string msg;
+ ];
+
+ interface TestInterface
+ {
+ void method1( in string arg1, inout long arg2 )
+ raises ( TestException );
+ };
+ };
+ """
+ )
+ test(
+ """
+ module Test1
+ {
+ exception TestException
+ {
+ string msg;
+ };
+
+ };
+ """
+ )
diff --git a/examples/indentedGrammarExample.py b/examples/indentedGrammarExample.py
new file mode 100644
index 0000000..442e6a4
--- /dev/null
+++ b/examples/indentedGrammarExample.py
@@ -0,0 +1,54 @@
+# indentedGrammarExample.py
+#
+# Copyright (c) 2006,2016 Paul McGuire
+#
+# A sample of a pyparsing grammar using indentation for
+# grouping (like Python does).
+#
+# Updated to use indentedBlock helper method.
+#
+
+from pyparsing import *
+
+data = """\
+def A(z):
+ A1
+ B = 100
+ G = A2
+ A2
+ A3
+B
+def BB(a,b,c):
+ BB1
+ def BBA():
+ bba1
+ bba2
+ bba3
+C
+D
+def spam(x,y):
+ def eggs(z):
+ pass
+"""
+
+
+indentStack = [1]
+stmt = Forward()
+suite = indentedBlock(stmt, indentStack)
+
+identifier = Word(alphas, alphanums)
+funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")
+funcDef = Group( funcDecl + suite )
+
+rvalue = Forward()
+funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")")
+rvalue << (funcCall | identifier | Word(nums))
+assignment = Group(identifier + "=" + rvalue)
+stmt << ( funcDef | assignment | identifier )
+
+module_body = OneOrMore(stmt)
+
+print(data)
+parseTree = module_body.parseString(data)
+parseTree.pprint()
+
diff --git a/examples/invRegex.py b/examples/invRegex.py
new file mode 100644
index 0000000..aea3b55
--- /dev/null
+++ b/examples/invRegex.py
@@ -0,0 +1,257 @@
+#
+# invRegex.py
+#
+# Copyright 2008, Paul McGuire
+#
+# pyparsing script to expand a regular expression into all possible matching strings
+# Supports:
+# - {n} and {m,n} repetition, but not unbounded + or * repetition
+# - ? optional elements
+# - [] character ranges
+# - () grouping
+# - | alternation
+#
+__all__ = ["count","invert"]
+
+from pyparsing import (Literal, oneOf, printables, ParserElement, Combine,
+ SkipTo, infixNotation, ParseFatalException, Word, nums, opAssoc,
+ Suppress, ParseResults, srange)
+
+class CharacterRangeEmitter(object):
+ def __init__(self,chars):
+ # remove duplicate chars in character range, but preserve original order
+ seen = set()
+ self.charset = "".join( seen.add(c) or c for c in chars if c not in seen )
+ def __str__(self):
+ return '['+self.charset+']'
+ def __repr__(self):
+ return '['+self.charset+']'
+ def makeGenerator(self):
+ def genChars():
+ for s in self.charset:
+ yield s
+ return genChars
+
+class OptionalEmitter(object):
+ def __init__(self,expr):
+ self.expr = expr
+ def makeGenerator(self):
+ def optionalGen():
+ yield ""
+ for s in self.expr.makeGenerator()():
+ yield s
+ return optionalGen
+
+class DotEmitter(object):
+ def makeGenerator(self):
+ def dotGen():
+ for c in printables:
+ yield c
+ return dotGen
+
+class GroupEmitter(object):
+ def __init__(self,exprs):
+ self.exprs = ParseResults(exprs)
+ def makeGenerator(self):
+ def groupGen():
+ def recurseList(elist):
+ if len(elist)==1:
+ for s in elist[0].makeGenerator()():
+ yield s
+ else:
+ for s in elist[0].makeGenerator()():
+ for s2 in recurseList(elist[1:]):
+ yield s + s2
+ if self.exprs:
+ for s in recurseList(self.exprs):
+ yield s
+ return groupGen
+
+class AlternativeEmitter(object):
+ def __init__(self,exprs):
+ self.exprs = exprs
+ def makeGenerator(self):
+ def altGen():
+ for e in self.exprs:
+ for s in e.makeGenerator()():
+ yield s
+ return altGen
+
+class LiteralEmitter(object):
+ def __init__(self,lit):
+ self.lit = lit
+ def __str__(self):
+ return "Lit:"+self.lit
+ def __repr__(self):
+ return "Lit:"+self.lit
+ def makeGenerator(self):
+ def litGen():
+ yield self.lit
+ return litGen
+
+def handleRange(toks):
+ return CharacterRangeEmitter(srange(toks[0]))
+
+def handleRepetition(toks):
+ toks=toks[0]
+ if toks[1] in "*+":
+ raise ParseFatalException("",0,"unbounded repetition operators not supported")
+ if toks[1] == "?":
+ return OptionalEmitter(toks[0])
+ if "count" in toks:
+ return GroupEmitter([toks[0]] * int(toks.count))
+ if "minCount" in toks:
+ mincount = int(toks.minCount)
+ maxcount = int(toks.maxCount)
+ optcount = maxcount - mincount
+ if optcount:
+ opt = OptionalEmitter(toks[0])
+ for i in range(1,optcount):
+ opt = OptionalEmitter(GroupEmitter([toks[0],opt]))
+ return GroupEmitter([toks[0]] * mincount + [opt])
+ else:
+ return [toks[0]] * mincount
+
+def handleLiteral(toks):
+ lit = ""
+ for t in toks:
+ if t[0] == "\\":
+ if t[1] == "t":
+ lit += '\t'
+ else:
+ lit += t[1]
+ else:
+ lit += t
+ return LiteralEmitter(lit)
+
+def handleMacro(toks):
+ macroChar = toks[0][1]
+ if macroChar == "d":
+ return CharacterRangeEmitter("0123456789")
+ elif macroChar == "w":
+ return CharacterRangeEmitter(srange("[A-Za-z0-9_]"))
+ elif macroChar == "s":
+ return LiteralEmitter(" ")
+ else:
+ raise ParseFatalException("",0,"unsupported macro character (" + macroChar + ")")
+
+def handleSequence(toks):
+ return GroupEmitter(toks[0])
+
+def handleDot():
+ return CharacterRangeEmitter(printables)
+
+def handleAlternative(toks):
+ return AlternativeEmitter(toks[0])
+
+
+_parser = None
+def parser():
+ global _parser
+ if _parser is None:
+ ParserElement.setDefaultWhitespaceChars("")
+ lbrack,rbrack,lbrace,rbrace,lparen,rparen,colon,qmark = map(Literal,"[]{}():?")
+
+ reMacro = Combine("\\" + oneOf(list("dws")))
+ escapedChar = ~reMacro + Combine("\\" + oneOf(list(printables)))
+ reLiteralChar = "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t"
+
+ reRange = Combine(lbrack + SkipTo(rbrack,ignore=escapedChar) + rbrack)
+ reLiteral = ( escapedChar | oneOf(list(reLiteralChar)) )
+ reNonCaptureGroup = Suppress("?:")
+ reDot = Literal(".")
+ repetition = (
+ ( lbrace + Word(nums)("count") + rbrace ) |
+ ( lbrace + Word(nums)("minCount")+","+ Word(nums)("maxCount") + rbrace ) |
+ oneOf(list("*+?"))
+ )
+
+ reRange.setParseAction(handleRange)
+ reLiteral.setParseAction(handleLiteral)
+ reMacro.setParseAction(handleMacro)
+ reDot.setParseAction(handleDot)
+
+ reTerm = ( reLiteral | reRange | reMacro | reDot | reNonCaptureGroup)
+ reExpr = infixNotation( reTerm,
+ [
+ (repetition, 1, opAssoc.LEFT, handleRepetition),
+ (None, 2, opAssoc.LEFT, handleSequence),
+ (Suppress('|'), 2, opAssoc.LEFT, handleAlternative),
+ ]
+ )
+ _parser = reExpr
+
+ return _parser
+
+def count(gen):
+ """Simple function to count the number of elements returned by a generator."""
+ return sum(1 for _ in gen)
+
+def invert(regex):
+ r"""Call this routine as a generator to return all the strings that
+ match the input regular expression.
+ for s in invert(r"[A-Z]{3}\d{3}"):
+ print s
+ """
+ invReGenerator = GroupEmitter(parser().parseString(regex)).makeGenerator()
+ return invReGenerator()
+
+def main():
+ tests = r"""
+ [A-EA]
+ [A-D]*
+ [A-D]{3}
+ X[A-C]{3}Y
+ X[A-C]{3}\(
+ X\d
+ foobar\d\d
+ foobar{2}
+ foobar{2,9}
+ fooba[rz]{2}
+ (foobar){2}
+ ([01]\d)|(2[0-5])
+ (?:[01]\d)|(2[0-5])
+ ([01]\d\d)|(2[0-4]\d)|(25[0-5])
+ [A-C]{1,2}
+ [A-C]{0,3}
+ [A-C]\s[A-C]\s[A-C]
+ [A-C]\s?[A-C][A-C]
+ [A-C]\s([A-C][A-C])
+ [A-C]\s([A-C][A-C])?
+ [A-C]{2}\d{2}
+ @|TH[12]
+ @(@|TH[12])?
+ @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))?
+ @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))?
+ (([ECMP]|HA|AK)[SD]|HS)T
+ [A-CV]{2}
+ A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr]
+ (a|b)|(x|y)
+ (a|b) (x|y)
+ [ABCDEFG](?:#|##|b|bb)?(?:maj|min|m|sus|aug|dim)?[0-9]?(?:/[ABCDEFG](?:#|##|b|bb)?)?
+ (Fri|Mon|S(atur|un)|T(hur|ue)s|Wednes)day
+ A(pril|ugust)|((Dec|Nov|Sept)em|Octo)ber|(Febr|Jan)uary|Ju(ly|ne)|Ma(rch|y)
+ """.split('\n')
+
+ for t in tests:
+ t = t.strip()
+ if not t: continue
+ print('-'*50)
+ print(t)
+ try:
+ num = count(invert(t))
+ print(num)
+ maxprint = 30
+ for s in invert(t):
+ print(s)
+ maxprint -= 1
+ if not maxprint:
+ break
+ except ParseFatalException as pfe:
+ print(pfe.msg)
+ print('')
+ continue
+ print('')
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/javascript_grammar.g b/examples/javascript_grammar.g
new file mode 100644
index 0000000..c30eac2
--- /dev/null
+++ b/examples/javascript_grammar.g
@@ -0,0 +1,894 @@
+/*
+ Copyright 2008 Chris Lambrou.
+ All rights reserved.
+*/
+
+grammar JavaScript;
+
+options
+{
+ output=AST;
+ backtrack=true;
+ memoize=true;
+}
+
+program
+ : LT!* sourceElements LT!* EOF!
+ ;
+
+sourceElements
+ : sourceElement (LT!* sourceElement)*
+ ;
+
+sourceElement
+ : functionDeclaration
+ | statement
+ ;
+
+// functions
+functionDeclaration
+ : 'function' LT!* Identifier LT!* formalParameterList LT!* functionBody
+ ;
+
+functionExpression
+ : 'function' LT!* Identifier? LT!* formalParameterList LT!* functionBody
+ ;
+
+formalParameterList
+ : '(' (LT!* Identifier (LT!* ',' LT!* Identifier)*)? LT!* ')'
+ ;
+
+functionBody
+ : '{' LT!* sourceElements LT!* '}'
+ ;
+
+// statements
+statement
+ : statementBlock
+ | variableStatement
+ | emptyStatement
+ | expressionStatement
+ | ifStatement
+ | iterationStatement
+ | continueStatement
+ | breakStatement
+ | returnStatement
+ | withStatement
+ | labelledStatement
+ | switchStatement
+ | throwStatement
+ | tryStatement
+ ;
+
+statementBlock
+ : '{' LT!* statementList? LT!* '}'
+ ;
+
+statementList
+ : statement (LT!* statement)*
+ ;
+
+variableStatement
+ : 'var' LT!* variableDeclarationList (LT | ';')!
+ ;
+
+variableDeclarationList
+ : variableDeclaration (LT!* ',' LT!* variableDeclaration)*
+ ;
+
+variableDeclarationListNoIn
+ : variableDeclarationNoIn (LT!* ',' LT!* variableDeclarationNoIn)*
+ ;
+
+variableDeclaration
+ : Identifier LT!* initialiser?
+ ;
+
+variableDeclarationNoIn
+ : Identifier LT!* initialiserNoIn?
+ ;
+
+initialiser
+ : '=' LT!* assignmentExpression
+ ;
+
+initialiserNoIn
+ : '=' LT!* assignmentExpressionNoIn
+ ;
+
+emptyStatement
+ : ';'
+ ;
+
+expressionStatement
+ : expression (LT | ';')!
+ ;
+
+ifStatement
+ : 'if' LT!* '(' LT!* expression LT!* ')' LT!* statement (LT!* 'else' LT!* statement)?
+ ;
+
+iterationStatement
+ : doWhileStatement
+ | whileStatement
+ | forStatement
+ | forInStatement
+ ;
+
+doWhileStatement
+ : 'do' LT!* statement LT!* 'while' LT!* '(' expression ')' (LT | ';')!
+ ;
+
+whileStatement
+ : 'while' LT!* '(' LT!* expression LT!* ')' LT!* statement
+ ;
+
+forStatement
+ : 'for' LT!* '(' (LT!* forStatementInitialiserPart)? LT!* ';' (LT!* expression)? LT!* ';' (LT!* expression)? LT!* ')' LT!* statement
+ ;
+
+forStatementInitialiserPart
+ : expressionNoIn
+ | 'var' LT!* variableDeclarationListNoIn
+ ;
+
+forInStatement
+ : 'for' LT!* '(' LT!* forInStatementInitialiserPart LT!* 'in' LT!* expression LT!* ')' LT!* statement
+ ;
+
+forInStatementInitialiserPart
+ : leftHandSideExpression
+ | 'var' LT!* variableDeclarationNoIn
+ ;
+
+continueStatement
+ : 'continue' Identifier? (LT | ';')!
+ ;
+
+breakStatement
+ : 'break' Identifier? (LT | ';')!
+ ;
+
+returnStatement
+ : 'return' expression? (LT | ';')!
+ ;
+
+withStatement
+ : 'with' LT!* '(' LT!* expression LT!* ')' LT!* statement
+ ;
+
+labelledStatement
+ : Identifier LT!* ':' LT!* statement
+ ;
+
+switchStatement
+ : 'switch' LT!* '(' LT!* expression LT!* ')' LT!* caseBlock
+ ;
+
+caseBlock
+ : '{' (LT!* caseClause)* (LT!* defaultClause (LT!* caseClause)*)? LT!* '}'
+ ;
+
+caseClause
+ : 'case' LT!* expression LT!* ':' LT!* statementList?
+ ;
+
+defaultClause
+ : 'default' LT!* ':' LT!* statementList?
+ ;
+
+throwStatement
+ : 'throw' expression (LT | ';')!
+ ;
+
+tryStatement
+ : 'try' LT!* statementBlock LT!* (finallyClause | catchClause (LT!* finallyClause)?)
+ ;
+
+catchClause
+ : 'catch' LT!* '(' LT!* Identifier LT!* ')' LT!* statementBlock
+ ;
+
+finallyClause
+ : 'finally' LT!* statementBlock
+ ;
+
+// expressions
+expression
+ : assignmentExpression (LT!* ',' LT!* assignmentExpression)*
+ ;
+
+expressionNoIn
+ : assignmentExpressionNoIn (LT!* ',' LT!* assignmentExpressionNoIn)*
+ ;
+
+assignmentExpression
+ : conditionalExpression
+ | leftHandSideExpression LT!* assignmentOperator LT!* assignmentExpression
+ ;
+
+assignmentExpressionNoIn
+ : conditionalExpressionNoIn
+ | leftHandSideExpression LT!* assignmentOperator LT!* assignmentExpressionNoIn
+ ;
+
+leftHandSideExpression
+ : callExpression
+ | newExpression
+ ;
+
+newExpression
+ : memberExpression
+ | 'new' LT!* newExpression
+ ;
+
+memberExpression
+ : (primaryExpression | functionExpression | 'new' LT!* memberExpression LT!* arguments) (LT!* memberExpressionSuffix)*
+ ;
+
+memberExpressionSuffix
+ : indexSuffix
+ | propertyReferenceSuffix
+ ;
+
+callExpression
+ : memberExpression LT!* arguments (LT!* callExpressionSuffix)*
+ ;
+
+callExpressionSuffix
+ : arguments
+ | indexSuffix
+ | propertyReferenceSuffix
+ ;
+
+arguments
+ : '(' (LT!* assignmentExpression (LT!* ',' LT!* assignmentExpression)*)? LT!* ')'
+ ;
+
+indexSuffix
+ : '[' LT!* expression LT!* ']'
+ ;
+
+propertyReferenceSuffix
+ : '.' LT!* Identifier
+ ;
+
+assignmentOperator
+ : '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|='
+ ;
+
+conditionalExpression
+ : logicalORExpression (LT!* '?' LT!* assignmentExpression LT!* ':' LT!* assignmentExpression)?
+ ;
+
+conditionalExpressionNoIn
+ : logicalORExpressionNoIn (LT!* '?' LT!* assignmentExpressionNoIn LT!* ':' LT!* assignmentExpressionNoIn)?
+ ;
+
+logicalORExpression
+ : logicalANDExpression (LT!* '||' LT!* logicalANDExpression)*
+ ;
+
+logicalORExpressionNoIn
+ : logicalANDExpressionNoIn (LT!* '||' LT!* logicalANDExpressionNoIn)*
+ ;
+
+logicalANDExpression
+ : bitwiseORExpression (LT!* '&&' LT!* bitwiseORExpression)*
+ ;
+
+logicalANDExpressionNoIn
+ : bitwiseORExpressionNoIn (LT!* '&&' LT!* bitwiseORExpressionNoIn)*
+ ;
+
+bitwiseORExpression
+ : bitwiseXORExpression (LT!* '|' LT!* bitwiseXORExpression)*
+ ;
+
+bitwiseORExpressionNoIn
+ : bitwiseXORExpressionNoIn (LT!* '|' LT!* bitwiseXORExpressionNoIn)*
+ ;
+
+bitwiseXORExpression
+ : bitwiseANDExpression (LT!* '^' LT!* bitwiseANDExpression)*
+ ;
+
+bitwiseXORExpressionNoIn
+ : bitwiseANDExpressionNoIn (LT!* '^' LT!* bitwiseANDExpressionNoIn)*
+ ;
+
+bitwiseANDExpression
+ : equalityExpression (LT!* '&' LT!* equalityExpression)*
+ ;
+
+bitwiseANDExpressionNoIn
+ : equalityExpressionNoIn (LT!* '&' LT!* equalityExpressionNoIn)*
+ ;
+
+equalityExpression
+ : relationalExpression (LT!* ('==' | '!=' | '===' | '!==') LT!* relationalExpression)*
+ ;
+
+equalityExpressionNoIn
+ : relationalExpressionNoIn (LT!* ('==' | '!=' | '===' | '!==') LT!* relationalExpressionNoIn)*
+ ;
+
+relationalExpression
+ : shiftExpression (LT!* ('<' | '>' | '<=' | '>=' | 'instanceof' | 'in') LT!* shiftExpression)*
+ ;
+
+relationalExpressionNoIn
+ : shiftExpression (LT!* ('<' | '>' | '<=' | '>=' | 'instanceof') LT!* shiftExpression)*
+ ;
+
+shiftExpression
+ : additiveExpression (LT!* ('<<' | '>>' | '>>>') LT!* additiveExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression (LT!* ('+' | '-') LT!* multiplicativeExpression)*
+ ;
+
+multiplicativeExpression
+ : unaryExpression (LT!* ('*' | '/' | '%') LT!* unaryExpression)*
+ ;
+
+unaryExpression
+ : postfixExpression
+ | ('delete' | 'void' | 'typeof' | '++' | '--' | '+' | '-' | '~' | '!') unaryExpression
+ ;
+
+postfixExpression
+ : leftHandSideExpression ('++' | '--')?
+ ;
+
+primaryExpression
+ : 'this'
+ | Identifier
+ | literal
+ | arrayLiteral
+ | objectLiteral
+ | '(' LT!* expression LT!* ')'
+ ;
+
+// arrayLiteral definition.
+arrayLiteral
+ : '[' LT!* assignmentExpression? (LT!* ',' (LT!* assignmentExpression)?)* LT!* ']'
+ ;
+
+// objectLiteral definition.
+objectLiteral
+ : '{' LT!* propertyNameAndValue (LT!* ',' LT!* propertyNameAndValue)* LT!* '}'
+ ;
+
+propertyNameAndValue
+ : propertyName LT!* ':' LT!* assignmentExpression
+ ;
+
+propertyName
+ : Identifier
+ | StringLiteral
+ | NumericLiteral
+ ;
+
+// primitive literal definition.
+literal
+ : 'null'
+ | 'true'
+ | 'false'
+ | StringLiteral
+ | NumericLiteral
+ ;
+
+// lexer rules.
+StringLiteral
+ : '"' DoubleStringCharacter* '"'
+ | '\'' SingleStringCharacter* '\''
+ ;
+
+fragment DoubleStringCharacter
+ : ~('"' | '\\' | LT)
+ | '\\' EscapeSequence
+ ;
+
+fragment SingleStringCharacter
+ : ~('\'' | '\\' | LT)
+ | '\\' EscapeSequence
+ ;
+
+fragment EscapeSequence
+ : CharacterEscapeSequence
+ | '0'
+ | HexEscapeSequence
+ | UnicodeEscapeSequence
+ ;
+
+fragment CharacterEscapeSequence
+ : SingleEscapeCharacter
+ | NonEscapeCharacter
+ ;
+
+fragment NonEscapeCharacter
+ : ~(EscapeCharacter | LT)
+ ;
+
+fragment SingleEscapeCharacter
+ : '\'' | '"' | '\\' | 'b' | 'f' | 'n' | 'r' | 't' | 'v'
+ ;
+
+fragment EscapeCharacter
+ : SingleEscapeCharacter
+ | DecimalDigit
+ | 'x'
+ | 'u'
+ ;
+
+fragment HexEscapeSequence
+ : 'x' HexDigit HexDigit
+ ;
+
+fragment UnicodeEscapeSequence
+ : 'u' HexDigit HexDigit HexDigit HexDigit
+ ;
+
+NumericLiteral
+ : DecimalLiteral
+ | HexIntegerLiteral
+ ;
+
+fragment HexIntegerLiteral
+ : '0' ('x' | 'X') HexDigit+
+ ;
+
+fragment HexDigit
+ : DecimalDigit | ('a'..'f') | ('A'..'F')
+ ;
+
+fragment DecimalLiteral
+ : DecimalDigit+ '.' DecimalDigit* ExponentPart?
+ | '.'? DecimalDigit+ ExponentPart?
+ ;
+
+fragment DecimalDigit
+ : ('0'..'9')
+ ;
+
+fragment ExponentPart
+ : ('e' | 'E') ('+' | '-') ? DecimalDigit+
+ ;
+
+Identifier
+ : IdentifierStart IdentifierPart*
+ ;
+
+fragment IdentifierStart
+ : UnicodeLetter
+ | '$'
+ | '_'
+ | '\\' UnicodeEscapeSequence
+ ;
+
+fragment IdentifierPart
+ : (IdentifierStart) => IdentifierStart // Avoids ambiguity, as some IdentifierStart chars also match following alternatives.
+ | UnicodeDigit
+ | UnicodeConnectorPunctuation
+ ;
+
+fragment UnicodeLetter // Any character in the Unicode categories "Uppercase letter (Lu)",
+ : '\u0041'..'\u005A' // "Lowercase letter (Ll)", "Titlecase letter (Lt)",
+ | '\u0061'..'\u007A' // "Modifier letter (Lm)", "Other letter (Lo)", or "Letter number (Nl)".
+ | '\u00AA'
+ | '\u00B5'
+ | '\u00BA'
+ | '\u00C0'..'\u00D6'
+ | '\u00D8'..'\u00F6'
+ | '\u00F8'..'\u021F'
+ | '\u0222'..'\u0233'
+ | '\u0250'..'\u02AD'
+ | '\u02B0'..'\u02B8'
+ | '\u02BB'..'\u02C1'
+ | '\u02D0'..'\u02D1'
+ | '\u02E0'..'\u02E4'
+ | '\u02EE'
+ | '\u037A'
+ | '\u0386'
+ | '\u0388'..'\u038A'
+ | '\u038C'
+ | '\u038E'..'\u03A1'
+ | '\u03A3'..'\u03CE'
+ | '\u03D0'..'\u03D7'
+ | '\u03DA'..'\u03F3'
+ | '\u0400'..'\u0481'
+ | '\u048C'..'\u04C4'
+ | '\u04C7'..'\u04C8'
+ | '\u04CB'..'\u04CC'
+ | '\u04D0'..'\u04F5'
+ | '\u04F8'..'\u04F9'
+ | '\u0531'..'\u0556'
+ | '\u0559'
+ | '\u0561'..'\u0587'
+ | '\u05D0'..'\u05EA'
+ | '\u05F0'..'\u05F2'
+ | '\u0621'..'\u063A'
+ | '\u0640'..'\u064A'
+ | '\u0671'..'\u06D3'
+ | '\u06D5'
+ | '\u06E5'..'\u06E6'
+ | '\u06FA'..'\u06FC'
+ | '\u0710'
+ | '\u0712'..'\u072C'
+ | '\u0780'..'\u07A5'
+ | '\u0905'..'\u0939'
+ | '\u093D'
+ | '\u0950'
+ | '\u0958'..'\u0961'
+ | '\u0985'..'\u098C'
+ | '\u098F'..'\u0990'
+ | '\u0993'..'\u09A8'
+ | '\u09AA'..'\u09B0'
+ | '\u09B2'
+ | '\u09B6'..'\u09B9'
+ | '\u09DC'..'\u09DD'
+ | '\u09DF'..'\u09E1'
+ | '\u09F0'..'\u09F1'
+ | '\u0A05'..'\u0A0A'
+ | '\u0A0F'..'\u0A10'
+ | '\u0A13'..'\u0A28'
+ | '\u0A2A'..'\u0A30'
+ | '\u0A32'..'\u0A33'
+ | '\u0A35'..'\u0A36'
+ | '\u0A38'..'\u0A39'
+ | '\u0A59'..'\u0A5C'
+ | '\u0A5E'
+ | '\u0A72'..'\u0A74'
+ | '\u0A85'..'\u0A8B'
+ | '\u0A8D'
+ | '\u0A8F'..'\u0A91'
+ | '\u0A93'..'\u0AA8'
+ | '\u0AAA'..'\u0AB0'
+ | '\u0AB2'..'\u0AB3'
+ | '\u0AB5'..'\u0AB9'
+ | '\u0ABD'
+ | '\u0AD0'
+ | '\u0AE0'
+ | '\u0B05'..'\u0B0C'
+ | '\u0B0F'..'\u0B10'
+ | '\u0B13'..'\u0B28'
+ | '\u0B2A'..'\u0B30'
+ | '\u0B32'..'\u0B33'
+ | '\u0B36'..'\u0B39'
+ | '\u0B3D'
+ | '\u0B5C'..'\u0B5D'
+ | '\u0B5F'..'\u0B61'
+ | '\u0B85'..'\u0B8A'
+ | '\u0B8E'..'\u0B90'
+ | '\u0B92'..'\u0B95'
+ | '\u0B99'..'\u0B9A'
+ | '\u0B9C'
+ | '\u0B9E'..'\u0B9F'
+ | '\u0BA3'..'\u0BA4'
+ | '\u0BA8'..'\u0BAA'
+ | '\u0BAE'..'\u0BB5'
+ | '\u0BB7'..'\u0BB9'
+ | '\u0C05'..'\u0C0C'
+ | '\u0C0E'..'\u0C10'
+ | '\u0C12'..'\u0C28'
+ | '\u0C2A'..'\u0C33'
+ | '\u0C35'..'\u0C39'
+ | '\u0C60'..'\u0C61'
+ | '\u0C85'..'\u0C8C'
+ | '\u0C8E'..'\u0C90'
+ | '\u0C92'..'\u0CA8'
+ | '\u0CAA'..'\u0CB3'
+ | '\u0CB5'..'\u0CB9'
+ | '\u0CDE'
+ | '\u0CE0'..'\u0CE1'
+ | '\u0D05'..'\u0D0C'
+ | '\u0D0E'..'\u0D10'
+ | '\u0D12'..'\u0D28'
+ | '\u0D2A'..'\u0D39'
+ | '\u0D60'..'\u0D61'
+ | '\u0D85'..'\u0D96'
+ | '\u0D9A'..'\u0DB1'
+ | '\u0DB3'..'\u0DBB'
+ | '\u0DBD'
+ | '\u0DC0'..'\u0DC6'
+ | '\u0E01'..'\u0E30'
+ | '\u0E32'..'\u0E33'
+ | '\u0E40'..'\u0E46'
+ | '\u0E81'..'\u0E82'
+ | '\u0E84'
+ | '\u0E87'..'\u0E88'
+ | '\u0E8A'
+ | '\u0E8D'
+ | '\u0E94'..'\u0E97'
+ | '\u0E99'..'\u0E9F'
+ | '\u0EA1'..'\u0EA3'
+ | '\u0EA5'
+ | '\u0EA7'
+ | '\u0EAA'..'\u0EAB'
+ | '\u0EAD'..'\u0EB0'
+ | '\u0EB2'..'\u0EB3'
+ | '\u0EBD'..'\u0EC4'
+ | '\u0EC6'
+ | '\u0EDC'..'\u0EDD'
+ | '\u0F00'
+ | '\u0F40'..'\u0F6A'
+ | '\u0F88'..'\u0F8B'
+ | '\u1000'..'\u1021'
+ | '\u1023'..'\u1027'
+ | '\u1029'..'\u102A'
+ | '\u1050'..'\u1055'
+ | '\u10A0'..'\u10C5'
+ | '\u10D0'..'\u10F6'
+ | '\u1100'..'\u1159'
+ | '\u115F'..'\u11A2'
+ | '\u11A8'..'\u11F9'
+ | '\u1200'..'\u1206'
+ | '\u1208'..'\u1246'
+ | '\u1248'
+ | '\u124A'..'\u124D'
+ | '\u1250'..'\u1256'
+ | '\u1258'
+ | '\u125A'..'\u125D'
+ | '\u1260'..'\u1286'
+ | '\u1288'
+ | '\u128A'..'\u128D'
+ | '\u1290'..'\u12AE'
+ | '\u12B0'
+ | '\u12B2'..'\u12B5'
+ | '\u12B8'..'\u12BE'
+ | '\u12C0'
+ | '\u12C2'..'\u12C5'
+ | '\u12C8'..'\u12CE'
+ | '\u12D0'..'\u12D6'
+ | '\u12D8'..'\u12EE'
+ | '\u12F0'..'\u130E'
+ | '\u1310'
+ | '\u1312'..'\u1315'
+ | '\u1318'..'\u131E'
+ | '\u1320'..'\u1346'
+ | '\u1348'..'\u135A'
+ | '\u13A0'..'\u13B0'
+ | '\u13B1'..'\u13F4'
+ | '\u1401'..'\u1676'
+ | '\u1681'..'\u169A'
+ | '\u16A0'..'\u16EA'
+ | '\u1780'..'\u17B3'
+ | '\u1820'..'\u1877'
+ | '\u1880'..'\u18A8'
+ | '\u1E00'..'\u1E9B'
+ | '\u1EA0'..'\u1EE0'
+ | '\u1EE1'..'\u1EF9'
+ | '\u1F00'..'\u1F15'
+ | '\u1F18'..'\u1F1D'
+ | '\u1F20'..'\u1F39'
+ | '\u1F3A'..'\u1F45'
+ | '\u1F48'..'\u1F4D'
+ | '\u1F50'..'\u1F57'
+ | '\u1F59'
+ | '\u1F5B'
+ | '\u1F5D'
+ | '\u1F5F'..'\u1F7D'
+ | '\u1F80'..'\u1FB4'
+ | '\u1FB6'..'\u1FBC'
+ | '\u1FBE'
+ | '\u1FC2'..'\u1FC4'
+ | '\u1FC6'..'\u1FCC'
+ | '\u1FD0'..'\u1FD3'
+ | '\u1FD6'..'\u1FDB'
+ | '\u1FE0'..'\u1FEC'
+ | '\u1FF2'..'\u1FF4'
+ | '\u1FF6'..'\u1FFC'
+ | '\u207F'
+ | '\u2102'
+ | '\u2107'
+ | '\u210A'..'\u2113'
+ | '\u2115'
+ | '\u2119'..'\u211D'
+ | '\u2124'
+ | '\u2126'
+ | '\u2128'
+ | '\u212A'..'\u212D'
+ | '\u212F'..'\u2131'
+ | '\u2133'..'\u2139'
+ | '\u2160'..'\u2183'
+ | '\u3005'..'\u3007'
+ | '\u3021'..'\u3029'
+ | '\u3031'..'\u3035'
+ | '\u3038'..'\u303A'
+ | '\u3041'..'\u3094'
+ | '\u309D'..'\u309E'
+ | '\u30A1'..'\u30FA'
+ | '\u30FC'..'\u30FE'
+ | '\u3105'..'\u312C'
+ | '\u3131'..'\u318E'
+ | '\u31A0'..'\u31B7'
+ | '\u3400'
+ | '\u4DB5'
+ | '\u4E00'
+ | '\u9FA5'
+ | '\uA000'..'\uA48C'
+ | '\uAC00'
+ | '\uD7A3'
+ | '\uF900'..'\uFA2D'
+ | '\uFB00'..'\uFB06'
+ | '\uFB13'..'\uFB17'
+ | '\uFB1D'
+ | '\uFB1F'..'\uFB28'
+ | '\uFB2A'..'\uFB36'
+ | '\uFB38'..'\uFB3C'
+ | '\uFB3E'
+ | '\uFB40'..'\uFB41'
+ | '\uFB43'..'\uFB44'
+ | '\uFB46'..'\uFBB1'
+ | '\uFBD3'..'\uFD3D'
+ | '\uFD50'..'\uFD8F'
+ | '\uFD92'..'\uFDC7'
+ | '\uFDF0'..'\uFDFB'
+ | '\uFE70'..'\uFE72'
+ | '\uFE74'
+ | '\uFE76'..'\uFEFC'
+ | '\uFF21'..'\uFF3A'
+ | '\uFF41'..'\uFF5A'
+ | '\uFF66'..'\uFFBE'
+ | '\uFFC2'..'\uFFC7'
+ | '\uFFCA'..'\uFFCF'
+ | '\uFFD2'..'\uFFD7'
+ | '\uFFDA'..'\uFFDC'
+ ;
+
+fragment UnicodeCombiningMark // Any character in the Unicode categories "Non-spacing mark (Mn)"
+ : '\u0300'..'\u034E' // or "Combining spacing mark (Mc)".
+ | '\u0360'..'\u0362'
+ | '\u0483'..'\u0486'
+ | '\u0591'..'\u05A1'
+ | '\u05A3'..'\u05B9'
+ | '\u05BB'..'\u05BD'
+ | '\u05BF'
+ | '\u05C1'..'\u05C2'
+ | '\u05C4'
+ | '\u064B'..'\u0655'
+ | '\u0670'
+ | '\u06D6'..'\u06DC'
+ | '\u06DF'..'\u06E4'
+ | '\u06E7'..'\u06E8'
+ | '\u06EA'..'\u06ED'
+ | '\u0711'
+ | '\u0730'..'\u074A'
+ | '\u07A6'..'\u07B0'
+ | '\u0901'..'\u0903'
+ | '\u093C'
+ | '\u093E'..'\u094D'
+ | '\u0951'..'\u0954'
+ | '\u0962'..'\u0963'
+ | '\u0981'..'\u0983'
+ | '\u09BC'..'\u09C4'
+ | '\u09C7'..'\u09C8'
+ | '\u09CB'..'\u09CD'
+ | '\u09D7'
+ | '\u09E2'..'\u09E3'
+ | '\u0A02'
+ | '\u0A3C'
+ | '\u0A3E'..'\u0A42'
+ | '\u0A47'..'\u0A48'
+ | '\u0A4B'..'\u0A4D'
+ | '\u0A70'..'\u0A71'
+ | '\u0A81'..'\u0A83'
+ | '\u0ABC'
+ | '\u0ABE'..'\u0AC5'
+ | '\u0AC7'..'\u0AC9'
+ | '\u0ACB'..'\u0ACD'
+ | '\u0B01'..'\u0B03'
+ | '\u0B3C'
+ | '\u0B3E'..'\u0B43'
+ | '\u0B47'..'\u0B48'
+ | '\u0B4B'..'\u0B4D'
+ | '\u0B56'..'\u0B57'
+ | '\u0B82'..'\u0B83'
+ | '\u0BBE'..'\u0BC2'
+ | '\u0BC6'..'\u0BC8'
+ | '\u0BCA'..'\u0BCD'
+ | '\u0BD7'
+ | '\u0C01'..'\u0C03'
+ | '\u0C3E'..'\u0C44'
+ | '\u0C46'..'\u0C48'
+ | '\u0C4A'..'\u0C4D'
+ | '\u0C55'..'\u0C56'
+ | '\u0C82'..'\u0C83'
+ | '\u0CBE'..'\u0CC4'
+ | '\u0CC6'..'\u0CC8'
+ | '\u0CCA'..'\u0CCD'
+ | '\u0CD5'..'\u0CD6'
+ | '\u0D02'..'\u0D03'
+ | '\u0D3E'..'\u0D43'
+ | '\u0D46'..'\u0D48'
+ | '\u0D4A'..'\u0D4D'
+ | '\u0D57'
+ | '\u0D82'..'\u0D83'
+ | '\u0DCA'
+ | '\u0DCF'..'\u0DD4'
+ | '\u0DD6'
+ | '\u0DD8'..'\u0DDF'
+ | '\u0DF2'..'\u0DF3'
+ | '\u0E31'
+ | '\u0E34'..'\u0E3A'
+ | '\u0E47'..'\u0E4E'
+ | '\u0EB1'
+ | '\u0EB4'..'\u0EB9'
+ | '\u0EBB'..'\u0EBC'
+ | '\u0EC8'..'\u0ECD'
+ | '\u0F18'..'\u0F19'
+ | '\u0F35'
+ | '\u0F37'
+ | '\u0F39'
+ | '\u0F3E'..'\u0F3F'
+ | '\u0F71'..'\u0F84'
+ | '\u0F86'..'\u0F87'
+ | '\u0F90'..'\u0F97'
+ | '\u0F99'..'\u0FBC'
+ | '\u0FC6'
+ | '\u102C'..'\u1032'
+ | '\u1036'..'\u1039'
+ | '\u1056'..'\u1059'
+ | '\u17B4'..'\u17D3'
+ | '\u18A9'
+ | '\u20D0'..'\u20DC'
+ | '\u20E1'
+ | '\u302A'..'\u302F'
+ | '\u3099'..'\u309A'
+ | '\uFB1E'
+ | '\uFE20'..'\uFE23'
+ ;
+
+fragment UnicodeDigit // Any character in the Unicode category "Decimal number (Nd)".
+ : '\u0030'..'\u0039'
+ | '\u0660'..'\u0669'
+ | '\u06F0'..'\u06F9'
+ | '\u0966'..'\u096F'
+ | '\u09E6'..'\u09EF'
+ | '\u0A66'..'\u0A6F'
+ | '\u0AE6'..'\u0AEF'
+ | '\u0B66'..'\u0B6F'
+ | '\u0BE7'..'\u0BEF'
+ | '\u0C66'..'\u0C6F'
+ | '\u0CE6'..'\u0CEF'
+ | '\u0D66'..'\u0D6F'
+ | '\u0E50'..'\u0E59'
+ | '\u0ED0'..'\u0ED9'
+ | '\u0F20'..'\u0F29'
+ | '\u1040'..'\u1049'
+ | '\u1369'..'\u1371'
+ | '\u17E0'..'\u17E9'
+ | '\u1810'..'\u1819'
+ | '\uFF10'..'\uFF19'
+ ;
+
+fragment UnicodeConnectorPunctuation // Any character in the Unicode category "Connector punctuation (Pc)".
+ : '\u005F'
+ | '\u203F'..'\u2040'
+ | '\u30FB'
+ | '\uFE33'..'\uFE34'
+ | '\uFE4D'..'\uFE4F'
+ | '\uFF3F'
+ | '\uFF65'
+ ;
+
+Comment
+ : '/*' (options {greedy=false;} : .)* '*/' {$channel=HIDDEN;}
+ ;
+
+LineComment
+ : '//' ~(LT)* {$channel=HIDDEN;}
+ ;
+
+LT
+ : '\n' // Line feed.
+ | '\r' // Carriage return.
+ | '\u2028' // Line separator.
+ | '\u2029' // Paragraph separator.
+ ;
+
+WhiteSpace // Tab, vertical tab, form feed, space, non-breaking space and any other unicode "space separator".
+ : ('\t' | '\v' | '\f' | ' ' | '\u00A0') {$channel=HIDDEN;}
+ ;
diff --git a/examples/jsonParser.py b/examples/jsonParser.py
new file mode 100644
index 0000000..f080c6c
--- /dev/null
+++ b/examples/jsonParser.py
@@ -0,0 +1,107 @@
+# jsonParser.py
+#
+# Implementation of a simple JSON parser, returning a hierarchical
+# ParseResults object support both list- and dict-style data access.
+#
+# Copyright 2006, by Paul McGuire
+#
+# Updated 8 Jan 2007 - fixed dict grouping bug, and made elements and
+# members optional in array and object collections
+#
+# Updated 9 Aug 2016 - use more current pyparsing constructs/idioms
+#
+json_bnf = """
+object
+ { members }
+ {}
+members
+ string : value
+ members , string : value
+array
+ [ elements ]
+ []
+elements
+ value
+ elements , value
+value
+ string
+ number
+ object
+ array
+ true
+ false
+ null
+"""
+
+from pyparsing import *
+
+def make_keyword(kwd_str, kwd_value):
+ return Keyword(kwd_str).setParseAction(replaceWith(kwd_value))
+TRUE = make_keyword("true", True)
+FALSE = make_keyword("false", False)
+NULL = make_keyword("null", None)
+
+LBRACK, RBRACK, LBRACE, RBRACE, COLON = map(Suppress, "[]{}:")
+
+jsonString = dblQuotedString().setParseAction(removeQuotes)
+jsonNumber = pyparsing_common.number()
+
+jsonObject = Forward()
+jsonValue = Forward()
+jsonElements = delimitedList( jsonValue )
+jsonArray = Group(LBRACK + Optional(jsonElements, []) + RBRACK)
+jsonValue << (jsonString | jsonNumber | Group(jsonObject) | jsonArray | TRUE | FALSE | NULL)
+memberDef = Group(jsonString + COLON + jsonValue)
+jsonMembers = delimitedList(memberDef)
+jsonObject << Dict(LBRACE + Optional(jsonMembers) + RBRACE)
+
+jsonComment = cppStyleComment
+jsonObject.ignore(jsonComment)
+
+
+if __name__ == "__main__":
+ testdata = """
+ {
+ "glossary": {
+ "title": "example glossary",
+ "GlossDiv": {
+ "title": "S",
+ "GlossList":
+ {
+ "ID": "SGML",
+ "SortAs": "SGML",
+ "GlossTerm": "Standard Generalized Markup Language",
+ "TrueValue": true,
+ "FalseValue": false,
+ "Gravity": -9.8,
+ "LargestPrimeLessThan100": 97,
+ "AvogadroNumber": 6.02E23,
+ "EvenPrimesGreaterThan2": null,
+ "PrimesLessThan10" : [2,3,5,7],
+ "Acronym": "SGML",
+ "Abbrev": "ISO 8879:1986",
+ "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.",
+ "GlossSeeAlso": ["GML", "XML", "markup"],
+ "EmptyDict" : {},
+ "EmptyList" : []
+ }
+ }
+ }
+ }
+ """
+
+ import pprint
+ results = jsonObject.parseString(testdata)
+ pprint.pprint( results.asList() )
+ print()
+ def testPrint(x):
+ print(type(x),repr(x))
+ print(list(results.glossary.GlossDiv.GlossList.keys()))
+ testPrint( results.glossary.title )
+ testPrint( results.glossary.GlossDiv.GlossList.ID )
+ testPrint( results.glossary.GlossDiv.GlossList.FalseValue )
+ testPrint( results.glossary.GlossDiv.GlossList.Acronym )
+ testPrint( results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2 )
+ testPrint( results.glossary.GlossDiv.GlossList.PrimesLessThan10 )
+
+
diff --git a/examples/linenoExample.py b/examples/linenoExample.py
new file mode 100644
index 0000000..1186f48
--- /dev/null
+++ b/examples/linenoExample.py
@@ -0,0 +1,49 @@
+#
+# linenoExample.py
+#
+# an example of using the location value returned by pyparsing to
+# extract the line and column number of the location of the matched text,
+# or to extract the entire line of text.
+#
+# Copyright (c) 2006, Paul McGuire
+#
+from pyparsing import *
+
+data = """Now is the time
+for all good men
+to come to the aid
+of their country."""
+
+# demonstrate use of lineno, line, and col in a parse action
+def reportLongWords(st,locn,toks):
+ word = toks[0]
+ if len(word) > 3:
+ print("Found '%s' on line %d at column %d" % (word, lineno(locn,st), col(locn,st)))
+ print("The full line of text was:")
+ print("'%s'" % line(locn,st))
+ print((" "*col(locn,st))+" ^")
+ print()
+
+wd = Word(alphas).setParseAction( reportLongWords )
+OneOrMore(wd).parseString(data)
+
+
+# demonstrate returning an object from a parse action, containing more information
+# than just the matching token text
+class Token(object):
+ def __init__(self, st, locn, tokString):
+ self.tokenString = tokString
+ self.locn = locn
+ self.sourceLine = line(locn,st)
+ self.lineNo = lineno(locn,st)
+ self.col = col(locn,st)
+ def __str__(self):
+ return "%(tokenString)s (line: %(lineNo)d, col: %(col)d)" % self.__dict__
+
+def createTokenObject(st,locn,toks):
+ return Token(st,locn, toks[0])
+
+wd = Word(alphas).setParseAction( createTokenObject )
+
+for tokenObj in OneOrMore(wd).parseString(data):
+ print(tokenObj)
diff --git a/examples/list1.py b/examples/list1.py
new file mode 100644
index 0000000..49a0bff
--- /dev/null
+++ b/examples/list1.py
@@ -0,0 +1,56 @@
+#
+# list1.py
+#
+# an example of using parse actions to convert type of parsed data.
+#
+# Copyright (c) 2006-2016, Paul McGuire
+#
+from pyparsing import *
+
+# first pass
+lbrack = Literal("[")
+rbrack = Literal("]")
+integer = Word(nums).setName("integer")
+real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).setName("real")
+
+listItem = real | integer | quotedString
+
+listStr = lbrack + delimitedList(listItem) + rbrack
+
+test = "['a', 100, 3.14]"
+
+print(listStr.parseString(test))
+
+
+# second pass, cleanup and add converters
+lbrack = Literal("[").suppress()
+rbrack = Literal("]").suppress()
+cvtInt = lambda s,l,toks: int(toks[0])
+cvtReal = lambda s,l,toks: float(toks[0])
+integer = Word(nums).setName("integer").setParseAction( cvtInt )
+real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).setName("real").setParseAction( cvtReal )
+listItem = real | integer | quotedString.setParseAction( removeQuotes )
+
+listStr = lbrack + delimitedList(listItem) + rbrack
+
+test = "['a', 100, 3.14]"
+
+print(listStr.parseString(test))
+
+# third pass, add nested list support
+lbrack, rbrack = map(Suppress, "[]")
+
+cvtInt = tokenMap(int)
+cvtReal = tokenMap(float)
+
+integer = Word(nums).setName("integer").setParseAction( cvtInt )
+real = Regex(r"[+-]?\d+\.\d*").setName("real").setParseAction( cvtReal )
+
+listStr = Forward()
+listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr)
+listStr << lbrack + delimitedList(listItem) + rbrack
+
+test = "['a', 100, 3.14, [ +2.718, 'xyzzy', -1.414] ]"
+print(listStr.parseString(test)) \ No newline at end of file
diff --git a/examples/listAllMatches.py b/examples/listAllMatches.py
new file mode 100644
index 0000000..1b1bdd4
--- /dev/null
+++ b/examples/listAllMatches.py
@@ -0,0 +1,52 @@
+# listAllMatches.py
+#
+# Sample program showing how/when to use listAllMatches to get all matching tokens in a results name.
+#
+# copyright 2006, Paul McGuire
+#
+
+from pyparsing import oneOf, OneOrMore, printables, StringEnd
+
+test = "The quick brown fox named 'Aloysius' lives at 123 Main Street (and jumps over lazy dogs in his spare time)."
+nonAlphas = [ c for c in printables if not c.isalpha() ]
+
+print("Extract vowels, consonants, and special characters from this test string:")
+print("'" + test + "'")
+print('')
+
+print("Define grammar using normal results names")
+print("(only last matching symbol is saved)")
+vowels = oneOf(list("aeiouy"), caseless=True)("vowels")
+cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True)("cons")
+other = oneOf(nonAlphas)("others")
+letters = OneOrMore(cons | vowels | other) + StringEnd()
+
+results = letters.parseString(test)
+print(results)
+print(results.vowels)
+print(results.cons)
+print(results.others)
+print('')
+
+
+print("Define grammar using results names, with listAllMatches=True")
+print("(all matching symbols are saved)")
+vowels = oneOf(list("aeiouy"), caseless=True)("vowels*")
+cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True)("cons*")
+other = oneOf(nonAlphas)("others*")
+
+letters = OneOrMore(cons | vowels | other)
+
+results = letters.parseString(test, parseAll=True)
+print(results)
+print(sorted(set(results)))
+print('')
+print(results.vowels)
+print(sorted(set(results.vowels)))
+print('')
+print(results.cons)
+print(sorted(set(results.cons)))
+print('')
+print(results.others)
+print(sorted(set(results.others)))
+
diff --git a/examples/lucene_grammar.py b/examples/lucene_grammar.py
new file mode 100644
index 0000000..6e404d8
--- /dev/null
+++ b/examples/lucene_grammar.py
@@ -0,0 +1,319 @@
+#
+# lucene_grammar.py
+#
+# Copyright 2011, Paul McGuire
+#
+# implementation of Lucene grammar, as decribed
+# at http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/docs/queryparsersyntax.html
+#
+
+from pyparsing import (Literal, CaselessKeyword, Forward, Regex, QuotedString, Suppress,
+ Optional, Group, FollowedBy, infixNotation, opAssoc, ParseException, ParserElement,
+ pyparsing_common)
+ParserElement.enablePackrat()
+
+COLON,LBRACK,RBRACK,LBRACE,RBRACE,TILDE,CARAT = map(Literal,":[]{}~^")
+LPAR,RPAR = map(Suppress,"()")
+and_, or_, not_, to_ = map(CaselessKeyword, "AND OR NOT TO".split())
+keyword = and_ | or_ | not_ | to_
+
+expression = Forward()
+
+valid_word = Regex(r'([a-zA-Z0-9*_+.-]|\\[!(){}\[\]^"~*?\\:])+').setName("word")
+valid_word.setParseAction(
+ lambda t : t[0].replace('\\\\',chr(127)).replace('\\','').replace(chr(127),'\\')
+ )
+
+string = QuotedString('"')
+
+required_modifier = Literal("+")("required")
+prohibit_modifier = Literal("-")("prohibit")
+integer = Regex(r"\d+").setParseAction(lambda t:int(t[0]))
+proximity_modifier = Group(TILDE + integer("proximity"))
+number = pyparsing_common.fnumber()
+fuzzy_modifier = TILDE + Optional(number, default=0.5)("fuzzy")
+
+term = Forward()
+field_name = valid_word().setName("fieldname")
+incl_range_search = Group(LBRACK + term("lower") + to_ + term("upper") + RBRACK)
+excl_range_search = Group(LBRACE + term("lower") + to_ + term("upper") + RBRACE)
+range_search = incl_range_search("incl_range") | excl_range_search("excl_range")
+boost = (CARAT + number("boost"))
+
+string_expr = Group(string + proximity_modifier) | string
+word_expr = Group(valid_word + fuzzy_modifier) | valid_word
+term << (Optional(field_name("field") + COLON) +
+ (word_expr | string_expr | range_search | Group(LPAR + expression + RPAR)) +
+ Optional(boost))
+term.setParseAction(lambda t:[t] if 'field' in t or 'boost' in t else None)
+
+expression << infixNotation(term,
+ [
+ (required_modifier | prohibit_modifier, 1, opAssoc.RIGHT),
+ ((not_ | '!').setParseAction(lambda: "NOT"), 1, opAssoc.RIGHT),
+ ((and_ | '&&').setParseAction(lambda: "AND"), 2, opAssoc.LEFT),
+ (Optional(or_ | '||').setParseAction(lambda: "OR"), 2, opAssoc.LEFT),
+ ])
+
+# test strings taken from grammar description doc, and TestQueryParser.java
+tests = r"""
+ a and b
+ a and not b
+ a and !b
+ a && !b
+ a&&!b
+ name:a
+ name:a and not title:b
+ (a^100 c d f) and !z
+ name:"blah de blah"
+ title:(+return +"pink panther")
+ title:"The Right Way" AND text:go
+ title:"Do it right" AND right
+ title:Do it right
+ roam~
+ roam~0.8
+ "jakarta apache"~10
+ mod_date:[20020101 TO 20030101]
+ title:{Aida TO Carmen}
+ jakarta apache
+ jakarta^4 apache
+ "jakarta apache"^4 "Apache Lucene"
+ "jakarta apache" jakarta
+ "jakarta apache" OR jakarta
+ "jakarta apache" AND "Apache Lucene"
+ +jakarta lucene
+ "jakarta apache" NOT "Apache Lucene"
+ "jakarta apache" -"Apache Lucene"
+ (jakarta OR apache) AND website
+ \(1+1\)\:2
+ c\:\\windows
+ (fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo)
+ (fieldX:xxxxx fieldy:xxxxxxxx)^2 AND (fieldx:the fieldy:foo)
+ (fieldX:xxxxx~0.5 fieldy:xxxxxxxx)^2 AND (fieldx:the fieldy:foo)
+ +term -term term
+ foo:term AND field:anotherTerm
+ germ term^2.0
+ (term)^2.0
+ (foo OR bar) AND (baz OR boo)
+ +(apple \"steve jobs\") -(foo bar baz)
+ +title:(dog OR cat) -author:\"bob dole\"
+ a AND b
+ +a +b
+ (a AND b)
+ c OR (a AND b)
+ c (+a +b)
+ a AND NOT b
+ +a -b
+ a AND -b
+ a AND !b
+ a && b
+ a && ! b
+ a OR b
+ a b
+ a || b
+ a OR !b
+ a -b
+ a OR ! b
+ a OR -b
+ a - b
+ a + b
+ a ! b
+ +foo:term +anotherterm
+ hello
+ term^2.0
+ (germ term)^2.0
+ term^2
+ +(foo bar) +(baz boo)
+ ((a OR b) AND NOT c) OR d
+ (+(a b) -c) d
+ field
+ a&&b
+ .NET
+ term
+ germ
+ 3
+ term 1.0 1 2
+ term term1 term2
+ term term term
+ term*
+ term*^2
+ term*^2.0
+ term~
+ term~2.0
+ term~0.7
+ term~^3
+ term~2.0^3.0
+ term*germ
+ term*germ^3
+ term*germ^3.0
+ term~1.1
+ [A TO C]
+ t*erm*
+ *term*
+ term term^3.0 term
+ term stop^3.0 term
+ term +stop term
+ term -stop term
+ drop AND (stop) AND roll
+ +drop +roll
+ term +(stop) term
+ term -(stop) term
+ drop AND stop AND roll
+ term phrase term
+ term (phrase1 phrase2) term
+ term AND NOT phrase term
+ +term -(phrase1 phrase2) term
+ stop^3
+ stop
+ (stop)^3
+ ((stop))^3
+ (stop^3)
+ ((stop)^3)
+ (stop)
+ ((stop))
+ term +stop
+ [ a TO z]
+ [a TO z]
+ [ a TO z ]
+ { a TO z}
+ {a TO z}
+ { a TO z }
+ { a TO z }^2.0
+ {a TO z}^2.0
+ [ a TO z] OR bar
+ [a TO z] bar
+ [ a TO z] AND bar
+ +[a TO z] +bar
+ ( bar blar { a TO z})
+ bar blar {a TO z}
+ gack ( bar blar { a TO z})
+ gack (bar blar {a TO z})
+ [* TO Z]
+ [* TO z]
+ [A TO *]
+ [a TO *]
+ [* TO *]
+ [\* TO \*]
+ \!blah
+ \:blah
+ blah
+ \~blah
+ \*blah
+ a
+ a-b:c
+ a+b:c
+ a\:b:c
+ a\\b:c
+ a:b-c
+ a:b+c
+ a:b\:c
+ a:b\\c
+ a:b-c*
+ a:b+c*
+ a:b\:c*
+ a:b\\c*
+ a:b-c~2.0
+ a:b+c~2.0
+ a:b\:c~
+ a:b\\c~
+ [a- TO a+]
+ [ a\\ TO a\* ]
+ c\:\\temp\\\~foo.txt
+ abc
+ XYZ
+ (item:\\ item:ABCD\\)
+ \*
+ *
+ \\
+ a\:b\:c
+ a\\b\:c
+ a\:b\\c
+ a\:b\:c\*
+ a\:b\\\\c\*
+ a:b-c~
+ a:b+c~
+ a\:b\:c\~
+ a\:b\\c\~
+ +weltbank +worlbank
+ +term +term +term
+ term +term term
+ term term +term
+ term +term +term
+ -term term term
+ -term +term +term
+ on
+ on^1.0
+ hello^2.0
+ the^3
+ the
+ some phrase
+ xunit~
+ one two three
+ A AND B OR C AND D
+ +A +B +C +D
+ foo:zoo*
+ foo:zoo*^2
+ zoo
+ foo:*
+ foo:*^2
+ *:foo
+ a:the OR a:foo
+ a:woo OR a:the
+ *:*
+ (*:*)
+ +*:* -*:*
+ the wizard of ozzy
+ """
+
+failtests = r"""
+ field:term:with:colon some more terms
+ (sub query)^5.0^2.0 plus more
+ a:b:c
+ a:b:c~
+ a:b:c*
+ a:b:c~2.0
+ \+blah
+ \-blah
+ foo \|| bar
+ foo \AND bar
+ \a
+ a\-b:c
+ a\+b:c
+ a\b:c
+ a:b\-c
+ a:b\+c
+ a\-b\:c
+ a\+b\:c
+ a:b\c*
+ a:b\-c~
+ a:b\+c~
+ a:b\c
+ a:b\-c*
+ a:b\+c*
+ [ a\- TO a\+ ]
+ [a\ TO a*]
+ a\\\+b
+ a\+b
+ c:\temp\~foo.txt
+ XY\
+ a\u0062c
+ a:b\c~2.0
+ XY\u005a
+ XY\u005A
+ item:\ item:ABCD\
+ \
+ a\ or b
+ a\:b\-c
+ a\:b\+c
+ a\:b\-c\*
+ a\:b\+c\*
+ a\:b\-c\~
+ a\:b\+c\~
+ a:b\c~
+ [ a\ TO a* ]
+ """
+
+success1, _ = expression.runTests(tests)
+success2, _ = expression.runTests(failtests, failureTests=True)
+
+print(("FAIL", "OK")[success1 and success2])
diff --git a/examples/macroExpander.py b/examples/macroExpander.py
new file mode 100644
index 0000000..327976c
--- /dev/null
+++ b/examples/macroExpander.py
@@ -0,0 +1,60 @@
+# macroExpander.py
+#
+# Example pyparsing program for performing macro expansion, similar to
+# the C pre-processor. This program is not as fully-featured, simply
+# processing macros of the form:
+# #def xxx yyyyy
+# and replacing xxx with yyyyy in the rest of the input string. Macros
+# can also be composed using other macros, such as
+# #def zzz xxx+1
+# Since xxx was previously defined as yyyyy, then zzz will be replaced
+# with yyyyy+1.
+#
+# Copyright 2007 by Paul McGuire
+#
+from pyparsing import *
+
+# define the structure of a macro definition (the empty term is used
+# to advance to the next non-whitespace character)
+identifier = Word(alphas+"_",alphanums+"_")
+macroDef = "#def" + identifier("macro") + empty + restOfLine("value")
+
+# define a placeholder for defined macros - initially nothing
+macroExpr = Forward()
+macroExpr << NoMatch()
+
+# global dictionary for macro definitions
+macros = {}
+
+# parse action for macro definitions
+def processMacroDefn(s,l,t):
+ macroVal = macroExpander.transformString(t.value)
+ macros[t.macro] = macroVal
+ macroExpr << MatchFirst(map(Keyword, macros.keys()))
+ return "#def " + t.macro + " " + macroVal
+
+# parse action to replace macro references with their respective definition
+def processMacroRef(s,l,t):
+ return macros[t[0]]
+
+# attach parse actions to expressions
+macroExpr.setParseAction(processMacroRef)
+macroDef.setParseAction(processMacroDefn)
+
+# define pattern for scanning through the input string
+macroExpander = macroExpr | macroDef
+
+
+
+# test macro substitution using transformString
+testString = """
+ #def A 100
+ #def ALEN A+1
+
+ char Astring[ALEN];
+ char AA[A];
+ typedef char[ALEN] Acharbuf;
+ """
+
+print(macroExpander.transformString(testString))
+print(macros)
diff --git a/examples/makeHTMLTagExample.py b/examples/makeHTMLTagExample.py
new file mode 100644
index 0000000..3b771c7
--- /dev/null
+++ b/examples/makeHTMLTagExample.py
@@ -0,0 +1,21 @@
+import urllib.request, urllib.parse, urllib.error
+
+from pyparsing import makeHTMLTags, SkipTo
+
+# read HTML from a web page
+serverListPage = urllib.request.urlopen( "http://www.yahoo.com" )
+htmlText = serverListPage.read()
+serverListPage.close()
+
+# using makeHTMLTags to define opening and closing tags
+anchorStart,anchorEnd = makeHTMLTags("a")
+
+# compose an expression for an anchored reference
+anchor = anchorStart + SkipTo(anchorEnd)("body") + anchorEnd
+
+# use scanString to scan through the HTML source, extracting
+# just the anchor tags and their associated body text
+# (note the href attribute of the opening A tag is available
+# as an attribute in the returned parse results)
+for tokens,start,end in anchor.scanString(htmlText):
+ print(tokens.body,'->',tokens.href)
diff --git a/examples/matchPreviousDemo.py b/examples/matchPreviousDemo.py
new file mode 100644
index 0000000..f0812e9
--- /dev/null
+++ b/examples/matchPreviousDemo.py
@@ -0,0 +1,33 @@
+#
+# matchPreviousDemo.py
+#
+
+from pyparsing import *
+
+src = """
+class a
+...
+end a;
+
+class b
+...
+end b;
+
+class c
+...
+end d;"""
+
+
+identifier = Word(alphas)
+
+classIdent = identifier("classname") # note that this also makes a copy of identifier
+classHead = "class" + classIdent
+classBody = "..."
+classEnd = "end" + matchPreviousLiteral(classIdent) + ';'
+classDefn = classHead + classBody + classEnd
+
+# use this form to catch syntax error
+# classDefn = classHead + classBody - classEnd
+
+for tokens in classDefn.searchString(src):
+ print(tokens.classname) \ No newline at end of file
diff --git a/examples/mozilla.ics b/examples/mozilla.ics
new file mode 100644
index 0000000..e6dd3dc
--- /dev/null
+++ b/examples/mozilla.ics
@@ -0,0 +1,50 @@
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+METHOD
+ :PUBLISH
+BEGIN:VEVENT
+UID
+ :153ed0e0-1dd2-11b2-9d71-96da104537a4
+SUMMARY
+ :Test event
+DESCRIPTION
+ :Some notes
+LOCATION
+ :Somewhere over the rainbow
+CATEGORIES
+ :Personal
+URL
+ :http://personal.amec.fi
+STATUS
+ :CONFIRMED
+CLASS
+ :PRIVATE
+X
+ ;MEMBER=AlarmEmailAddress
+ :petri.savolainen@iki.fi
+X-MOZILLA-RECUR-DEFAULT-UNITS
+ :months
+RRULE
+ :FREQ=MONTHLY;UNTIL=20040914;INTERVAL=1
+EXDATE
+ :20040714T000000
+DTSTART
+ ;VALUE=DATE
+ :20040714
+DTEND
+ ;VALUE=DATE
+ :20040815
+DTSTAMP
+ :20040714T141219Z
+LAST-MODIFIED
+ :20040714T141457Z
+BEGIN:VALARM
+TRIGGER
+ ;VALUE=DURATION
+ :PT15M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/examples/mozillaCalendarParser.py b/examples/mozillaCalendarParser.py
new file mode 100644
index 0000000..210f284
--- /dev/null
+++ b/examples/mozillaCalendarParser.py
@@ -0,0 +1,81 @@
+from pyparsing import Optional, oneOf, Dict, Literal, Word, printables, Group, OneOrMore, ZeroOrMore
+
+"""
+A simple parser for calendar (*.ics) files,
+as exported by the Mozilla calendar.
+
+Any suggestions and comments welcome.
+
+Version: 0.1
+Copyright: Petri Savolainen <firstname.lastname@iki.fi>
+License: Free for any use
+"""
+
+
+# TERMINALS
+
+BEGIN = Literal("BEGIN:").suppress()
+END = Literal("END:").suppress()
+valstr = printables + "\xe4\xf6\xe5\xd6\xc4\xc5 "
+
+EQ = Literal("=").suppress()
+SEMI = Literal(";").suppress()
+COLON = Literal(":").suppress()
+
+EVENT = Literal("VEVENT").suppress()
+CALENDAR = Literal("VCALENDAR").suppress()
+ALARM = Literal("VALARM").suppress()
+
+# TOKENS
+
+CALPROP = oneOf("VERSION PRODID METHOD")
+ALMPROP = oneOf("TRIGGER")
+EVTPROP = oneOf("X-MOZILLA-RECUR-DEFAULT-INTERVAL \
+ X-MOZILLA-RECUR-DEFAULT-UNITS \
+ UID DTSTAMP LAST-MODIFIED X RRULE EXDATE")
+
+propval = Word(valstr)
+typeval = Word(valstr)
+typename = oneOf("VALUE MEMBER FREQ UNTIL INTERVAL")
+
+proptype = Group(SEMI + typename + EQ + typeval).suppress()
+
+calprop = Group(CALPROP + ZeroOrMore(proptype) + COLON + propval)
+almprop = Group(ALMPROP + ZeroOrMore(proptype) + COLON + propval)
+evtprop = Group(EVTPROP + ZeroOrMore(proptype) + COLON + propval).suppress() \
+ | "CATEGORIES" + COLON + propval.setResultsName("categories") \
+ | "CLASS" + COLON + propval.setResultsName("class") \
+ | "DESCRIPTION" + COLON + propval.setResultsName("description") \
+ | "DTSTART" + proptype + COLON + propval.setResultsName("begin") \
+ | "DTEND" + proptype + COLON + propval.setResultsName("end") \
+ | "LOCATION" + COLON + propval.setResultsName("location") \
+ | "PRIORITY" + COLON + propval.setResultsName("priority") \
+ | "STATUS" + COLON + propval.setResultsName("status") \
+ | "SUMMARY" + COLON + propval.setResultsName("summary") \
+ | "URL" + COLON + propval.setResultsName("url") \
+
+calprops = Group(OneOrMore(calprop)).suppress()
+evtprops = Group(OneOrMore(evtprop))
+almprops = Group(OneOrMore(almprop)).suppress()
+
+alarm = BEGIN + ALARM + almprops + END + ALARM
+event = BEGIN + EVENT + evtprops + Optional(alarm) + END + EVENT
+events = Group(OneOrMore(event))
+calendar = BEGIN + CALENDAR + calprops + ZeroOrMore(event) + END + CALENDAR
+calendars = OneOrMore(calendar)
+
+
+# PARSE ACTIONS
+
+def gotEvent(s,loc,toks):
+ for event in toks:
+ print(event.dump())
+
+event.setParseAction(gotEvent)
+
+
+# MAIN PROGRAM
+
+if __name__=="__main__":
+
+ calendars.parseFile("mozilla.ics")
diff --git a/examples/nested.py b/examples/nested.py
new file mode 100644
index 0000000..24cf2f4
--- /dev/null
+++ b/examples/nested.py
@@ -0,0 +1,30 @@
+#
+# nested.py
+# Copyright, 2007 - Paul McGuire
+#
+# Simple example of using nestedExpr to define expressions using
+# paired delimiters for grouping lists and sublists
+#
+
+from pyparsing import *
+import pprint
+
+data = """
+{
+ { item1 "item with } in it" }
+ {
+ {item2a item2b }
+ {item3}
+ }
+
+}
+"""
+
+# use {}'s for nested lists
+nestedItems = nestedExpr("{", "}")
+print(( (nestedItems+stringEnd).parseString(data).asList() ))
+
+# use default delimiters of ()'s
+mathExpr = nestedExpr()
+print(( mathExpr.parseString( "((( ax + by)*C) *(Z | (E^F) & D))") ))
+
diff --git a/examples/numerics.py b/examples/numerics.py
new file mode 100644
index 0000000..5ab99dd
--- /dev/null
+++ b/examples/numerics.py
@@ -0,0 +1,62 @@
+#
+# numerics.py
+#
+# Examples of parsing real and integers using various grouping and
+# decimal point characters, varying by locale.
+#
+# Copyright 2016, Paul McGuire
+#
+# Format samples from https://docs.oracle.com/cd/E19455-01/806-0169/overview-9/index.html
+#
+tests = """\
+# Canadian (English and French)
+4 294 967 295,000
+
+# Danish
+4 294 967 295,000
+
+# Finnish
+4 294 967 295,000
+
+# French
+4 294 967 295,000
+
+# German
+4 294 967 295,000
+
+# Italian
+4.294.967.295,000
+
+# Norwegian
+4.294.967.295,000
+
+# Spanish
+4.294.967.295,000
+
+# Swedish
+4 294 967 295,000
+
+# GB-English
+4,294,967,295.000
+
+# US-English
+4,294,967,295.000
+
+# Thai
+4,294,967,295.000
+"""
+
+from pyparsing import Regex
+
+comma_decimal = Regex(r'\d{1,2}(([ .])\d\d\d(\2\d\d\d)*)?,\d*')
+comma_decimal.setParseAction(lambda t: float(t[0].replace(' ','').replace('.','').replace(',','.')))
+
+dot_decimal = Regex(r'\d{1,2}(([ ,])\d\d\d(\2\d\d\d)*)?\.\d*')
+dot_decimal.setParseAction(lambda t: float(t[0].replace(' ','').replace(',','')))
+
+decimal = comma_decimal ^ dot_decimal
+decimal.runTests(tests, parseAll=True)
+
+grouped_integer = Regex(r'\d{1,2}(([ .,])\d\d\d(\2\d\d\d)*)?')
+grouped_integer.setParseAction(lambda t: int(t[0].replace(' ','').replace(',','').replace('.','')))
+grouped_integer.runTests(tests, parseAll=False)
diff --git a/examples/oc.py b/examples/oc.py
new file mode 100644
index 0000000..cf656ec
--- /dev/null
+++ b/examples/oc.py
@@ -0,0 +1,188 @@
+# oc.py
+#
+# A subset-C parser, (BNF taken from 1996 International Obfuscated C Code Contest)
+#
+# Copyright, 2010, Paul McGuire
+#
+"""
+http://www.ioccc.org/1996/august.hint
+
+The following is a description of the OC grammar:
+
+ OC grammar
+ ==========
+ Terminals are in quotes, () is used for bracketing.
+
+ program: decl*
+
+ decl: vardecl
+ fundecl
+
+ vardecl: type NAME ;
+ type NAME "[" INT "]" ;
+
+ fundecl: type NAME "(" args ")" "{" body "}"
+
+ args: /*empty*/
+ ( arg "," )* arg
+
+ arg: type NAME
+
+ body: vardecl* stmt*
+
+ stmt: ifstmt
+ whilestmt
+ dowhilestmt
+ "return" expr ";"
+ expr ";"
+ "{" stmt* "}"
+ ";"
+
+ ifstmt: "if" "(" expr ")" stmt
+ "if" "(" expr ")" stmt "else" stmt
+
+ whilestmt: "while" "(" expr ")" stmt
+
+ dowhilestmt: "do" stmt "while" "(" expr ")" ";"
+
+ expr: expr binop expr
+ unop expr
+ expr "[" expr "]"
+ "(" expr ")"
+ expr "(" exprs ")"
+ NAME
+ INT
+ CHAR
+ STRING
+
+ exprs: /*empty*/
+ (expr ",")* expr
+
+ binop: "+" | "-" | "*" | "/" | "%" |
+ "=" |
+ "<" | "==" | "!="
+
+ unop: "!" | "-" | "*"
+
+ type: "int" stars
+ "char" stars
+
+ stars: "*"*
+"""
+
+from pyparsing import *
+ParserElement.enablePackrat()
+
+LPAR,RPAR,LBRACK,RBRACK,LBRACE,RBRACE,SEMI,COMMA = map(Suppress, "()[]{};,")
+INT, CHAR, WHILE, DO, IF, ELSE, RETURN = map(Keyword,
+ "int char while do if else return".split())
+
+NAME = Word(alphas+"_", alphanums+"_")
+integer = Regex(r"[+-]?\d+")
+char = Regex(r"'.'")
+string_ = dblQuotedString
+
+TYPE = Group((INT | CHAR) + ZeroOrMore("*"))
+expr = Forward()
+func_call = Group(NAME + LPAR + Group(Optional(delimitedList(expr))) + RPAR)
+operand = func_call | NAME | integer | char | string_
+expr <<= (infixNotation(operand,
+ [
+ (oneOf('! - *'), 1, opAssoc.RIGHT),
+ (oneOf('++ --'), 1, opAssoc.RIGHT),
+ (oneOf('++ --'), 1, opAssoc.LEFT),
+ (oneOf('* / %'), 2, opAssoc.LEFT),
+ (oneOf('+ -'), 2, opAssoc.LEFT),
+ (oneOf('< == > <= >= !='), 2, opAssoc.LEFT),
+ (Regex(r'(?<!=)=(?!=)'), 2, opAssoc.LEFT),
+ ]) +
+ Optional( LBRACK + expr + RBRACK |
+ LPAR + Group(Optional(delimitedList(expr))) + RPAR )
+ )
+
+stmt = Forward()
+
+ifstmt = IF - LPAR + expr + RPAR + stmt + Optional(ELSE + stmt)
+whilestmt = WHILE - LPAR + expr + RPAR + stmt
+dowhilestmt = DO - stmt + WHILE + LPAR + expr + RPAR + SEMI
+returnstmt = RETURN - expr + SEMI
+
+stmt << Group( ifstmt |
+ whilestmt |
+ dowhilestmt |
+ returnstmt |
+ expr + SEMI |
+ LBRACE + ZeroOrMore(stmt) + RBRACE |
+ SEMI)
+
+vardecl = Group(TYPE + NAME + Optional(LBRACK + integer + RBRACK)) + SEMI
+
+arg = Group(TYPE + NAME)
+body = ZeroOrMore(vardecl) + ZeroOrMore(stmt)
+fundecl = Group(TYPE + NAME + LPAR + Optional(Group(delimitedList(arg))) + RPAR +
+ LBRACE + Group(body) + RBRACE)
+decl = fundecl | vardecl
+program = ZeroOrMore(decl)
+
+program.ignore(cStyleComment)
+
+# set parser element names
+for vname in ("ifstmt whilestmt dowhilestmt returnstmt TYPE "
+ "NAME fundecl vardecl program arg body stmt".split()):
+ v = vars()[vname]
+ v.setName(vname)
+
+#~ for vname in "fundecl stmt".split():
+ #~ v = vars()[vname]
+ #~ v.setDebug()
+
+test = r"""
+/* A factorial program */
+int
+putstr(char *s)
+{
+ while(*s)
+ putchar(*s++);
+}
+
+int
+fac(int n)
+{
+ if (n == 0)
+ return 1;
+ else
+ return n*fac(n-1);
+}
+
+int
+putn(int n)
+{
+ if (9 < n)
+ putn(n / 10);
+ putchar((n%10) + '0');
+}
+
+int
+facpr(int n)
+{
+ putstr("factorial ");
+ putn(n);
+ putstr(" = ");
+ putn(fac(n));
+ putstr("\n");
+}
+
+int
+main()
+{
+ int i;
+ i = 0;
+ if(a() == 1){}
+ while(i < 10)
+ facpr(i++);
+ return 0;
+}
+"""
+
+ast = program.parseString(test, parseAll=True)
+ast.pprint()
diff --git a/examples/parseListString.py b/examples/parseListString.py
new file mode 100644
index 0000000..d74f3af
--- /dev/null
+++ b/examples/parseListString.py
@@ -0,0 +1,82 @@
+# parseListString.py
+#
+# Copyright, 2006, by Paul McGuire
+#
+
+from pyparsing import *
+
+# first pass
+lbrack = Literal("[")
+rbrack = Literal("]")
+integer = Word(nums).setName("integer")
+real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).setName("real")
+
+listItem = real | integer | quotedString
+
+listStr = lbrack + delimitedList(listItem) + rbrack
+
+test = "['a', 100, 3.14]"
+
+print(listStr.parseString(test))
+
+
+# second pass, cleanup and add converters
+lbrack = Literal("[").suppress()
+rbrack = Literal("]").suppress()
+cvtInt = lambda s,l,toks: int(toks[0])
+integer = Word(nums).setName("integer").setParseAction( cvtInt )
+cvtReal = lambda s,l,toks: float(toks[0])
+real = Regex(r'[+-]?\d+\.\d*').setName("floating-point number").setParseAction( cvtReal )
+listItem = real | integer | quotedString.setParseAction( removeQuotes )
+
+listStr = lbrack + delimitedList(listItem) + rbrack
+
+test = "['a', 100, 3.14]"
+
+print(listStr.parseString(test))
+
+# third pass, add nested list support, and tuples, too!
+cvtInt = lambda s,l,toks: int(toks[0])
+cvtReal = lambda s,l,toks: float(toks[0])
+
+lbrack = Literal("[").suppress()
+rbrack = Literal("]").suppress()
+integer = Word(nums).setName("integer").setParseAction( cvtInt )
+real = Regex(r'[+-]?\d+\.\d*').setName("floating-point number").setParseAction( cvtReal )
+tupleStr = Forward()
+listStr = Forward()
+listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr) | tupleStr
+tupleStr << ( Suppress("(") + delimitedList(listItem) + Optional(Suppress(",")) + Suppress(")") )
+tupleStr.setParseAction( lambda t:tuple(t.asList()) )
+listStr << lbrack + delimitedList(listItem) + Optional(Suppress(",")) + rbrack
+
+test = "['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ]"
+print(listStr.parseString(test))
+
+# fourth pass, add parsing of dicts
+cvtInt = lambda s,l,toks: int(toks[0])
+cvtReal = lambda s,l,toks: float(toks[0])
+cvtDict = lambda s,l,toks: dict(toks[0])
+
+lbrack = Literal("[").suppress()
+rbrack = Literal("]").suppress()
+lbrace = Literal("{").suppress()
+rbrace = Literal("}").suppress()
+colon = Literal(":").suppress()
+integer = Word(nums).setName("integer").setParseAction( cvtInt )
+real = Regex(r'[+-]?\d+\.\d*').setName("real").setParseAction( cvtReal )
+
+tupleStr = Forward()
+listStr = Forward()
+dictStr = Forward()
+listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr) | tupleStr | dictStr
+tupleStr <<= ( Suppress("(") + delimitedList(listItem) + Optional(Suppress(",")) + Suppress(")") )
+tupleStr.setParseAction( lambda t:tuple(t.asList()) )
+listStr <<= (lbrack + Optional(delimitedList(listItem)) + Optional(Suppress(",")) + rbrack)
+dictKeyStr = real | integer | quotedString.setParseAction(removeQuotes)
+dictStr <<= lbrace + Optional(delimitedList( Group( dictKeyStr + colon + listItem ))) + Optional(Suppress(",")) + rbrace
+dictStr.setParseAction(lambda t: dict((k_v[0],(k_v[1].asList() if isinstance(k_v[1],ParseResults) else k_v[1])) for k_v in t))
+
+test = '[{0: [2], 1: []}, {0: [], 1: [], 2: [,]}, {0: [1, 2,],}]'
+print(listStr.parseString(test))
diff --git a/examples/parsePythonValue.py b/examples/parsePythonValue.py
new file mode 100644
index 0000000..53c61fc
--- /dev/null
+++ b/examples/parsePythonValue.py
@@ -0,0 +1,70 @@
+# parsePythonValue.py
+#
+# Copyright, 2006, by Paul McGuire
+#
+from __future__ import print_function
+from pyparsing import *
+
+
+cvtBool = lambda t:t[0]=='True'
+cvtInt = lambda toks: int(toks[0])
+cvtReal = lambda toks: float(toks[0])
+cvtTuple = lambda toks : tuple(toks.asList())
+cvtDict = lambda toks: dict(toks.asList())
+cvtList = lambda toks: [toks.asList()]
+
+# define punctuation as suppressed literals
+lparen,rparen,lbrack,rbrack,lbrace,rbrace,colon = \
+ map(Suppress,"()[]{}:")
+
+integer = Regex(r"[+-]?\d+")\
+ .setName("integer")\
+ .setParseAction( cvtInt )
+real = Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?")\
+ .setName("real")\
+ .setParseAction( cvtReal )
+tupleStr = Forward()
+listStr = Forward()
+dictStr = Forward()
+
+unicodeString.setParseAction(lambda t:t[0][2:-1].decode('unicode-escape'))
+quotedString.setParseAction(lambda t:t[0][1:-1].decode('string-escape'))
+boolLiteral = oneOf("True False").setParseAction(cvtBool)
+noneLiteral = Literal("None").setParseAction(replaceWith(None))
+
+listItem = real|integer|quotedString|unicodeString|boolLiteral|noneLiteral| \
+ Group(listStr) | tupleStr | dictStr
+
+tupleStr << ( Suppress("(") + Optional(delimitedList(listItem)) +
+ Optional(Suppress(",")) + Suppress(")") )
+tupleStr.setParseAction( cvtTuple )
+
+listStr << (lbrack + Optional(delimitedList(listItem) +
+ Optional(Suppress(","))) + rbrack)
+listStr.setParseAction(cvtList, lambda t: t[0])
+
+dictEntry = Group( listItem + colon + listItem )
+dictStr << (lbrace + Optional(delimitedList(dictEntry) + \
+ Optional(Suppress(","))) + rbrace)
+dictStr.setParseAction( cvtDict )
+
+tests = """['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ]
+ [{0: [2], 1: []}, {0: [], 1: [], 2: []}, {0: [1, 2]}]
+ { 'A':1, 'B':2, 'C': {'a': 1.2, 'b': 3.4} }
+ 3.14159
+ 42
+ 6.02E23
+ 6.02e+023
+ 1.0e-7
+ 'a quoted string'""".split("\n")
+
+for test in tests:
+ print("Test:", test.strip())
+ result = listItem.parseString(test)[0]
+ print("Result:", result)
+ try:
+ for dd in result:
+ if isinstance(dd,dict): print(list(dd.items()))
+ except TypeError as te:
+ pass
+ print()
diff --git a/examples/parseResultsSumExample.py b/examples/parseResultsSumExample.py
new file mode 100644
index 0000000..1fb694a
--- /dev/null
+++ b/examples/parseResultsSumExample.py
@@ -0,0 +1,26 @@
+#
+# parseResultsSumExample.py
+#
+# Sample script showing the value in merging ParseResults retrieved by searchString,
+# using Python's builtin sum() method
+#
+samplestr1 = "garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage"
+samplestr2 = "garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage"
+samplestr3 = "garbage;DOB 10-10-2010"
+samplestr4 = "garbage;ID PARI12345678;more garbage- I am cool"
+
+from pyparsing import *
+dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob")
+id_ref = "ID" + Word(alphanums,exact=12)("id")
+info_ref = "-" + restOfLine("info")
+
+person_data = dob_ref | id_ref | info_ref
+
+for test in (samplestr1,samplestr2,samplestr3,samplestr4,):
+ person = sum(person_data.searchString(test))
+ print(person.id)
+ print(person.dump())
+ print()
+
+
+ \ No newline at end of file
diff --git a/examples/parseTabularData.py b/examples/parseTabularData.py
new file mode 100644
index 0000000..3846310
--- /dev/null
+++ b/examples/parseTabularData.py
@@ -0,0 +1,50 @@
+#
+# parseTabularData.py
+#
+# Example of parsing data that is formatted in a tabular listing, with
+# potential for missing values. Uses new addCondition method on
+# ParserElements.
+#
+# Copyright 2015, Paul McGuire
+#
+from pyparsing import col,Word,Optional,alphas,nums,ParseException
+
+table = """\
+ 1 2
+12345678901234567890
+COLOR S M L
+RED 10 2 2
+BLUE 5 10
+GREEN 3 5
+PURPLE 8"""
+
+# function to create column-specific parse conditions
+def mustMatchCols(startloc,endloc):
+ return lambda s,l,t: startloc <= col(l,s) <= endloc
+
+# helper to define values in a space-delimited table
+# (change empty_cell_is_zero to True if a value of 0 is desired for empty cells)
+def tableValue(expr, colstart, colend):
+ empty_cell_is_zero = False
+ if empty_cell_is_zero:
+ return Optional(expr.copy().addCondition(mustMatchCols(colstart,colend),
+ message="text not in expected columns"),
+ default=0)
+ else:
+ return Optional(expr.copy().addCondition(mustMatchCols(colstart,colend),
+ message="text not in expected columns"))
+
+
+# define the grammar for this simple table
+colorname = Word(alphas)
+integer = Word(nums).setParseAction(lambda t: int(t[0])).setName("integer")
+row = (colorname("name") +
+ tableValue(integer, 11, 12)("S") +
+ tableValue(integer, 15, 16)("M") +
+ tableValue(integer, 19, 20)("L"))
+
+# parse the sample text - skip over the header and counter lines
+for line in table.splitlines()[3:]:
+ print(line)
+ print(row.parseString(line).dump())
+ print('')
diff --git a/examples/partial_gene_match.py b/examples/partial_gene_match.py
new file mode 100644
index 0000000..8bf5f7c
--- /dev/null
+++ b/examples/partial_gene_match.py
@@ -0,0 +1,88 @@
+# parital_gene_match.py
+#
+# Example showing how to create a customized pyparsing Token, in this case,
+# one that is very much like Literal, but which tolerates up to 'n' character
+# mismatches
+from pyparsing import *
+
+import urllib.request, urllib.parse, urllib.error
+
+# read in a bunch of genomic data
+datafile = urllib.request.urlopen("http://toxodb.org/common/downloads/release-6.0/Tgondii/TgondiiApicoplastORFsNAs_ToxoDB-6.0.fasta")
+fastasrc = datafile.read()
+datafile.close()
+
+"""
+Sample header:
+>NC_001799-6-2978-2778 | organism=Toxoplasma_gondii_RH | location=NC_001799:2778-2978(-) | length=201
+"""
+integer = Word(nums).setParseAction(lambda t:int(t[0]))
+genebit = Group(">" + Word(alphanums.upper()+"-_") + "|" +
+ Word(printables)("id") + SkipTo("length=", include=True) +
+ integer("genelen") + LineEnd() +
+ Combine(OneOrMore(Word("ACGTN")),adjacent=False)("gene"))
+
+# read gene data from .fasta file - takes just a few seconds
+genedata = OneOrMore(genebit).parseString(fastasrc)
+
+
+class CloseMatch(Token):
+ """A special subclass of Token that does *close* matches. For each
+ close match of the given string, a tuple is returned giving the
+ found close match, and a list of mismatch positions."""
+ def __init__(self, seq, maxMismatches=1):
+ super(CloseMatch,self).__init__()
+ self.name = seq
+ self.sequence = seq
+ self.maxMismatches = maxMismatches
+ self.errmsg = "Expected " + self.sequence
+ self.mayIndexError = False
+ self.mayReturnEmpty = False
+
+ def parseImpl( self, instring, loc, doActions=True ):
+ start = loc
+ instrlen = len(instring)
+ maxloc = start + len(self.sequence)
+
+ if maxloc <= instrlen:
+ seq = self.sequence
+ seqloc = 0
+ mismatches = []
+ throwException = False
+ done = False
+ while loc < maxloc and not done:
+ if instring[loc] != seq[seqloc]:
+ mismatches.append(seqloc)
+ if len(mismatches) > self.maxMismatches:
+ throwException = True
+ done = True
+ loc += 1
+ seqloc += 1
+ else:
+ throwException = True
+
+ if throwException:
+ exc = self.myException
+ exc.loc = loc
+ exc.pstr = instring
+ raise exc
+
+ return loc, (instring[start:loc],mismatches)
+
+# using the genedata extracted above, look for close matches of a gene sequence
+searchseq = CloseMatch("TTAAATCTAGAAGAT", 3)
+for g in genedata:
+ print("%s (%d)" % (g.id, g.genelen))
+ print("-"*24)
+ for t,startLoc,endLoc in searchseq.scanString(g.gene, overlap=True):
+ matched, mismatches = t[0]
+ print("MATCH:", searchseq.sequence)
+ print("FOUND:", matched)
+ if mismatches:
+ print(" ", ''.join(' ' if i not in mismatches else '*'
+ for i,c in enumerate(searchseq.sequence)))
+ else:
+ print("<exact match>")
+ print("at location", startLoc)
+ print()
+ print() \ No newline at end of file
diff --git a/examples/pgn.py b/examples/pgn.py
new file mode 100644
index 0000000..d13f83e
--- /dev/null
+++ b/examples/pgn.py
@@ -0,0 +1,94 @@
+# pgn.py rel. 1.1 17-sep-2004
+#
+# Demonstration of the parsing module, implementing a pgn parser.
+#
+# The aim of this parser is not to support database application,
+# but to create automagically a pgn annotated reading the log console file
+# of a lecture of ICC (Internet Chess Club), saved by Blitzin.
+# Of course you can modify the Abstract Syntax Tree to your purpose.
+#
+# Copyright 2004, by Alberto Santini http://www.albertosantini.it/chess/
+#
+from pyparsing import alphanums, nums, quotedString
+from pyparsing import Combine, Forward, Group, Literal, oneOf, OneOrMore, Optional, Suppress, ZeroOrMore, White, Word
+from pyparsing import ParseException
+
+#
+# define pgn grammar
+#
+
+tag = Suppress("[") + Word(alphanums) + Combine(quotedString) + Suppress("]")
+comment = Suppress("{") + Word(alphanums + " ") + Suppress("}")
+
+dot = Literal(".")
+piece = oneOf("K Q B N R")
+file_coord = oneOf("a b c d e f g h")
+rank_coord = oneOf("1 2 3 4 5 6 7 8")
+capture = oneOf("x :")
+promote = Literal("=")
+castle_queenside = oneOf("O-O-O 0-0-0 o-o-o")
+castle_kingside = oneOf("O-O 0-0 o-o")
+
+move_number = Optional(comment) + Word(nums) + dot
+m1 = file_coord + rank_coord # pawn move e.g. d4
+m2 = file_coord + capture + file_coord + rank_coord # pawn capture move e.g. dxe5
+m3 = file_coord + "8" + promote + piece # pawn promotion e.g. e8=Q
+m4 = piece + file_coord + rank_coord # piece move e.g. Be6
+m5 = piece + file_coord + file_coord + rank_coord # piece move e.g. Nbd2
+m6 = piece + rank_coord + file_coord + rank_coord # piece move e.g. R4a7
+m7 = piece + capture + file_coord + rank_coord # piece capture move e.g. Bxh7
+m8 = castle_queenside | castle_kingside # castling e.g. o-o
+
+check = oneOf("+ ++")
+mate = Literal("#")
+annotation = Word("!?", max=2)
+nag = " $" + Word(nums)
+decoration = check | mate | annotation | nag
+
+variant = Forward()
+half_move = Combine((m3 | m1 | m2 | m4 | m5 | m6 | m7 | m8) + Optional(decoration)) \
+ + Optional(comment) +Optional(variant)
+move = Suppress(move_number) + half_move + Optional(half_move)
+variant << "(" + OneOrMore(move) + ")"
+# grouping the plies (half-moves) for each move: useful to group annotations, variants...
+# suggested by Paul McGuire :)
+move = Group(Suppress(move_number) + half_move + Optional(half_move))
+variant << Group("(" + OneOrMore(move) + ")")
+game_terminator = oneOf("1-0 0-1 1/2-1/2 *")
+
+pgnGrammar = Suppress(ZeroOrMore(tag)) + ZeroOrMore(move) + Optional(Suppress(game_terminator))
+
+def parsePGN( pgn, bnf=pgnGrammar, fn=None ):
+ try:
+ return bnf.parseString( pgn )
+ except ParseException as err:
+ print(err.line)
+ print(" "*(err.column-1) + "^")
+ print(err)
+
+if __name__ == "__main__":
+ # input string
+ pgn = """
+[Event "ICC 5 0 u"]
+[Site "Internet Chess Club"]
+[Date "2004.01.25"]
+[Round "-"]
+[White "guest920"]
+[Black "IceBox"]
+[Result "0-1"]
+[ICCResult "White checkmated"]
+[BlackElo "1498"]
+[Opening "French defense"]
+[ECO "C00"]
+[NIC "FR.01"]
+[Time "04:44:56"]
+[TimeControl "300+0"]
+
+1. e4 e6 2. Nf3 d5 $2 3. exd5 (3. e5 g6 4. h4) exd5 4. Qe2+ Qe7 5. Qxe7+ Bxe7 6. d3 Nf6 7. Be3
+Bg4 8. Nbd2 c5 9. h3 Be6 10. O-O-O Nc6 11. g4 Bd6 12. g5 Nd7 13. Rg1 d4 14.
+g6 fxg6 15. Bg5 Rf8 16. a3 Bd5 17. Re1+ Nde5 18. Nxe5 Nxe5 19. Bf4 Rf5 20.
+Bxe5 Rxe5 21. Rg5 Rxe1# {Black wins} 0-1
+"""
+ # parse input string
+ tokens = parsePGN(pgn, pgnGrammar)
+ print(tokens.dump())
diff --git a/examples/position.py b/examples/position.py
new file mode 100644
index 0000000..984c018
--- /dev/null
+++ b/examples/position.py
@@ -0,0 +1,55 @@
+from pyparsing import *
+
+text = """Lorem ipsum dolor sit amet, consectetur adipisicing
+elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+aute irure dolor in reprehenderit in voluptate velit esse cillum
+dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum"""
+
+# find all words beginning with a vowel
+vowels = "aeiouAEIOU"
+initialVowelWord = Word(vowels,alphas)
+
+# Unfortunately, searchString will advance character by character through
+# the input text, so it will detect that the initial "Lorem" is not an
+# initialVowelWord, but then it will test "orem" and think that it is. So
+# we need to add a do-nothing term that will match the words that start with
+# consonants, but we will just throw them away when we match them. The key is
+# that, in having been matched, the parser will skip over them entirely when
+# looking for initialVowelWords.
+consonants = ''.join(c for c in alphas if c not in vowels)
+initialConsWord = Word(consonants, alphas).suppress()
+
+# using scanString to locate where tokens are matched
+for t,start,end in (initialConsWord|initialVowelWord).scanString(text):
+ if t:
+ print(start,':', t[0])
+
+# add parse action to annotate the parsed tokens with their location in the
+# input string
+def addLocnToTokens(s,l,t):
+ t['locn'] = l
+ t['word'] = t[0]
+initialVowelWord.setParseAction(addLocnToTokens)
+
+for ivowelInfo in (initialConsWord | initialVowelWord).searchString(text):
+ if not ivowelInfo:
+ continue
+ print(ivowelInfo.locn, ':', ivowelInfo.word)
+
+
+# alternative - add an Empty that will save the current location
+def location(name):
+ return Empty().setParseAction(lambda s,l,t: t.__setitem__(name,l))
+locateInitialVowels = location("locn") + initialVowelWord("word")
+
+# search through the input text
+for ivowelInfo in (initialConsWord | locateInitialVowels).searchString(text):
+ if not ivowelInfo:
+ continue
+ print(ivowelInfo.locn, ':', ivowelInfo.word)
+
+
diff --git a/examples/protobuf_parser.py b/examples/protobuf_parser.py
new file mode 100644
index 0000000..04ce0d8
--- /dev/null
+++ b/examples/protobuf_parser.py
@@ -0,0 +1,100 @@
+# protobuf_parser.py
+#
+# simple parser for parsing protobuf .proto files
+#
+# Copyright 2010, Paul McGuire
+#
+
+from pyparsing import (Word, alphas, alphanums, Regex, Suppress, Forward,
+ Group, oneOf, ZeroOrMore, Optional, delimitedList, Keyword,
+ restOfLine, quotedString, Dict)
+
+ident = Word(alphas+"_",alphanums+"_").setName("identifier")
+integer = Regex(r"[+-]?\d+")
+
+LBRACE,RBRACE,LBRACK,RBRACK,LPAR,RPAR,EQ,SEMI = map(Suppress,"{}[]()=;")
+
+kwds = """message required optional repeated enum extensions extends extend
+ to package service rpc returns true false option import"""
+for kw in kwds.split():
+ exec("%s_ = Keyword('%s')" % (kw.upper(), kw))
+
+messageBody = Forward()
+
+messageDefn = MESSAGE_ - ident("messageId") + LBRACE + messageBody("body") + RBRACE
+
+typespec = oneOf("""double float int32 int64 uint32 uint64 sint32 sint64
+ fixed32 fixed64 sfixed32 sfixed64 bool string bytes""") | ident
+rvalue = integer | TRUE_ | FALSE_ | ident
+fieldDirective = LBRACK + Group(ident + EQ + rvalue) + RBRACK
+fieldDefn = (( REQUIRED_ | OPTIONAL_ | REPEATED_ )("fieldQualifier") -
+ typespec("typespec") + ident("ident") + EQ + integer("fieldint") + ZeroOrMore(fieldDirective) + SEMI)
+
+# enumDefn ::= 'enum' ident '{' { ident '=' integer ';' }* '}'
+enumDefn = ENUM_("typespec") - ident('name') + LBRACE + Dict( ZeroOrMore( Group(ident + EQ + integer + SEMI) ))('values') + RBRACE
+
+# extensionsDefn ::= 'extensions' integer 'to' integer ';'
+extensionsDefn = EXTENSIONS_ - integer + TO_ + integer + SEMI
+
+# messageExtension ::= 'extend' ident '{' messageBody '}'
+messageExtension = EXTEND_ - ident + LBRACE + messageBody + RBRACE
+
+# messageBody ::= { fieldDefn | enumDefn | messageDefn | extensionsDefn | messageExtension }*
+messageBody << Group(ZeroOrMore( Group(fieldDefn | enumDefn | messageDefn | extensionsDefn | messageExtension) ))
+
+# methodDefn ::= 'rpc' ident '(' [ ident ] ')' 'returns' '(' [ ident ] ')' ';'
+methodDefn = (RPC_ - ident("methodName") +
+ LPAR + Optional(ident("methodParam")) + RPAR +
+ RETURNS_ + LPAR + Optional(ident("methodReturn")) + RPAR)
+
+# serviceDefn ::= 'service' ident '{' methodDefn* '}'
+serviceDefn = SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(methodDefn)) + RBRACE
+
+# packageDirective ::= 'package' ident [ '.' ident]* ';'
+packageDirective = Group(PACKAGE_ - delimitedList(ident, '.', combine=True) + SEMI)
+
+comment = '//' + restOfLine
+
+importDirective = IMPORT_ - quotedString("importFileSpec") + SEMI
+
+optionDirective = OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI
+
+topLevelStatement = Group(messageDefn | messageExtension | enumDefn | serviceDefn | importDirective | optionDirective)
+
+parser = Optional(packageDirective) + ZeroOrMore(topLevelStatement)
+
+parser.ignore(comment)
+
+
+test1 = """message Person {
+ required int32 id = 1;
+ required string name = 2;
+ optional string email = 3;
+}"""
+
+test2 = """package tutorial;
+
+message Person {
+ required string name = 1;
+ required int32 id = 2;
+ optional string email = 3;
+
+ enum PhoneType {
+ MOBILE = 0;
+ HOME = 1;
+ WORK = 2;
+ }
+
+ message PhoneNumber {
+ required string number = 1;
+ optional PhoneType type = 2 [default = HOME];
+ }
+
+ repeated PhoneNumber phone = 4;
+}
+
+message AddressBook {
+ repeated Person person = 1;
+}"""
+
+parser.runTests([test1, test2])
diff --git a/examples/pymicko.py b/examples/pymicko.py
new file mode 100644
index 0000000..b136689
--- /dev/null
+++ b/examples/pymicko.py
@@ -0,0 +1,1387 @@
+#!/usr/bin/python
+
+# Python/pyparsing educational microC compiler v1.0
+# Copyright (C) 2009 Zarko Zivanov
+# (largely based on flex/bison microC compiler by Zorica Suvajdzin, used with her permission;
+# current version can be found at http://www.acs.uns.ac.rs, under "Programski Prevodioci" [Serbian site])
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# A copy of the GNU General Public License can be found at <http://www.gnu.org/licenses/>.
+
+from pyparsing import *
+from sys import stdin, stdout, stderr, argv, exit
+
+#defines debug level
+# 0 - no debug
+# 1 - print parsing results
+# 2 - print parsing results and symbol table
+# 3 - print parsing results only, without executing parse actions (grammar-only testing)
+DEBUG = 0
+
+##########################################################################################
+##########################################################################################
+
+# About microC language and microC compiler
+
+# microC language and microC compiler are educational tools, and their goal is to show some basic principles
+# of writing a C language compiler. Compiler represents one (relatively simple) solution, not necessarily the best one.
+# This Python/pyparsing version is made using Python 2.6.4 and pyparsing 1.5.2 (and it may contain errors :) )
+
+##########################################################################################
+##########################################################################################
+
+# Model of the used hypothetical processor
+
+# The reason behind using a hypothetical processor is to simplify code generation and to concentrate on the compiler itself.
+# This compiler can relatively easily be ported to x86, but one must know all the little details about which register
+# can be used for what, which registers are default for various operations, etc.
+
+# The hypothetical processor has 16 registers, called %0 to %15. Register %13 is used for the function return value (x86's eax),
+# %14 is the stack frame pointer (x86's ebp) and %15 is the stack pointer (x86's esp). All data-handling instructions can be
+# unsigned (suffix U), or signed (suffix S). These are ADD, SUB, MUL and DIV. These are three-address instructions,
+# the first two operands are input, the third one is output. Whether these operands are registers, memory or constant
+# is not relevant, all combinations are possible (except that output cannot be a constant). Constants are writen with a $ prefix (10-base only).
+# Conditional jumps are handled by JXXY instructions, where XX is LT, GT, LE, GE, EQ, NE (less than, greater than, less than or equal, etc.)
+# and Y is U or S (unsigned or signed, except for JEQ i JNE). Unconditional jump is JMP. The move instruction is MOV.
+# Function handling is done using CALL, RET, PUSH and POP (C style function calls). Static data is defined using the WORD directive
+# (example: variable: WORD 1), whose only argument defines the number of locations that are reserved.
+
+##########################################################################################
+##########################################################################################
+
+# Grammar of The microC Programming Language
+# (small subset of C made for compiler course at Faculty of Technical Sciences, Chair for Applied Computer Sciences, Novi Sad, Serbia)
+
+# Patterns:
+
+# letter
+# -> "_" | "a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "E" | "f"
+# | "F" | "g" | "G" | "h" | "H" | "i" | "I" | "j" | "J" | "k" | "K" | "l"
+# | "L" | "m" | "M" | "n" | "N" | "o" | "O" | "p" | "P" | "q" | "Q" | "r"
+# | "R" | "s" | "S" | "t" | "T" | "u" | "U" | "v" | "V" | "w" | "W" | "x"
+# | "X" | "y" | "Y" | "z" | "Z"
+
+# digit
+# -> "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+# identifier
+# -> letter ( letter | digit )*
+
+# int_constant
+# -> digit +
+
+# unsigned_constant
+# -> digit + ( "u" | "U" )
+
+# Productions:
+
+# program
+# -> variable_list function_list
+# -> function_list
+
+# variable_list
+# -> variable ";"
+# -> variable_list variable ";"
+
+# variable
+# -> type identifier
+
+# type
+# -> "int"
+# -> "unsigned"
+
+# function_list
+# -> function
+# -> function_list function
+
+# function
+# -> type identifier "(" parameters ")" body
+
+# parameters
+# -> <empty>
+# -> parameter_list
+
+# parameter_list
+# -> variable
+# -> parameter_list "," variable
+
+# body
+# -> "{" variable_list statement_list "}"
+# -> "{" statement_list "}"
+
+# statement_list
+# -> <empty>
+# -> statement_list statement
+
+# statement
+# -> assignement_statement
+# -> function_call_statement
+# -> if_statement
+# -> while_statement
+# -> return_statement
+# -> compound_statement
+
+# assignement_statement
+# -> identifier "=" num_exp ";"
+
+# num_exp
+# -> mul_exp
+# -> num_exp "+" mul_exp
+# -> num_exp "-" mul_exp
+
+# mul_exp
+# -> exp
+# -> mul_exp "*" exp
+# -> mul_exp "/" exp
+
+# exp
+# -> constant
+# -> identifier
+# -> function_call
+# -> "(" num_exp ")"
+# -> "+" exp
+# -> "-" exp
+
+# constant
+# -> int_constant
+# -> unsigned_constant
+
+# function_call
+# -> identifier "(" arguments ")"
+
+# arguments
+# -> <empty>
+# -> argument_list
+
+# argument_list
+# -> num_exp
+# -> argument_list "," num_exp
+
+# function_call_statement
+# -> function_call ";"
+
+# if_statement
+# -> "if" "(" log_exp ")" statement
+# -> "if" "(" log_exp ")" statement "else" statement
+# -> -> -> -> -> -> -> -> 2
+
+# log_exp
+# -> and_exp
+# -> log_exp "||" and_exp
+
+# and_exp
+# -> rel_exp
+# -> and_exp "&&" rel_exp
+
+# rel_exp
+# -> num_exp "<" num_exp
+# -> num_exp ">" num_exp
+# -> num_exp "<=" num_exp
+# -> num_exp ">=" num_exp
+# -> num_exp "==" num_exp
+# -> num_exp "!=" num_exp
+
+# while_statement
+# -> "while" "(" log_exp ")" statement
+
+# return_statement
+# -> "return" num_exp ";"
+
+# compound_statement
+# -> "{" statement_list "}"
+
+# Comment: /* a comment */
+
+##########################################################################################
+##########################################################################################
+
+class Enumerate(dict):
+ """C enum emulation (original by Scott David Daniels)"""
+ def __init__(self, names):
+ for number, name in enumerate(names.split()):
+ setattr(self, name, number)
+ self[number] = name
+
+class SharedData(object):
+ """Data used in all three main classes"""
+
+ #Possible kinds of symbol table entries
+ KINDS = Enumerate("NO_KIND WORKING_REGISTER GLOBAL_VAR FUNCTION PARAMETER LOCAL_VAR CONSTANT")
+ #Supported types of functions and variables
+ TYPES = Enumerate("NO_TYPE INT UNSIGNED")
+
+ #bit size of variables
+ TYPE_BIT_SIZE = 16
+ #min/max values of constants
+ MIN_INT = -2 ** (TYPE_BIT_SIZE - 1)
+ MAX_INT = 2 ** (TYPE_BIT_SIZE - 1) - 1
+ MAX_UNSIGNED = 2 ** TYPE_BIT_SIZE - 1
+ #available working registers (the last one is the register for function's return value!)
+ REGISTERS = "%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13".split()
+ #register for function's return value
+ FUNCTION_REGISTER = len(REGISTERS) - 1
+ #the index of last working register
+ LAST_WORKING_REGISTER = len(REGISTERS) - 2
+ #list of relational operators
+ RELATIONAL_OPERATORS = "< > <= >= == !=".split()
+
+ def __init__(self):
+ #index of the currently parsed function
+ self.functon_index = 0
+ #name of the currently parsed function
+ self.functon_name = 0
+ #number of parameters of the currently parsed function
+ self.function_params = 0
+ #number of local variables of the currently parsed function
+ self.function_vars = 0
+
+##########################################################################################
+##########################################################################################
+
+class ExceptionSharedData(object):
+ """Class for exception handling data"""
+
+ def __init__(self):
+ #position in currently parsed text
+ self.location = 0
+ #currently parsed text
+ self.text = ""
+
+ def setpos(self, location, text):
+ """Helper function for setting curently parsed text and position"""
+ self.location = location
+ self.text = text
+
+exshared = ExceptionSharedData()
+
+class SemanticException(Exception):
+ """Exception for semantic errors found during parsing, similar to ParseException.
+ Introduced because ParseException is used internally in pyparsing and custom
+ messages got lost and replaced by pyparsing's generic errors.
+ """
+
+ def __init__(self, message, print_location=True):
+ super(SemanticException,self).__init__()
+ self._message = message
+ self.location = exshared.location
+ self.print_location = print_location
+ if exshared.location != None:
+ self.line = lineno(exshared.location, exshared.text)
+ self.col = col(exshared.location, exshared.text)
+ self.text = line(exshared.location, exshared.text)
+ else:
+ self.line = self.col = self.text = None
+
+ def _get_message(self):
+ return self._message
+ def _set_message(self, message):
+ self._message = message
+ message = property(_get_message, _set_message)
+
+ def __str__(self):
+ """String representation of the semantic error"""
+ msg = "Error"
+ if self.print_location and (self.line != None):
+ msg += " at line %d, col %d" % (self.line, self.col)
+ msg += ": %s" % self.message
+ if self.print_location and (self.line != None):
+ msg += "\n%s" % self.text
+ return msg
+
+##########################################################################################
+##########################################################################################
+
+class SymbolTableEntry(object):
+ """Class which represents one symbol table entry."""
+
+ def __init__(self, sname = "", skind = 0, stype = 0, sattr = None, sattr_name = "None"):
+ """Initialization of symbol table entry.
+ sname - symbol name
+ skind - symbol kind
+ stype - symbol type
+ sattr - symbol attribute
+ sattr_name - symbol attribute name (used only for table display)
+ """
+ self.name = sname
+ self.kind = skind
+ self.type = stype
+ self.attribute = sattr
+ self.attribute_name = sattr_name
+ self.param_types = []
+
+ def set_attribute(self, name, value):
+ """Sets attribute's name and value"""
+ self.attribute_name = name
+ self.attribute = value
+
+ def attribute_str(self):
+ """Returns attribute string (used only for table display)"""
+ return "{0}={1}".format(self.attribute_name, self.attribute) if self.attribute != None else "None"
+
+class SymbolTable(object):
+ """Class for symbol table of microC program"""
+
+ def __init__(self, shared):
+ """Initialization of the symbol table"""
+ self.table = []
+ self.lable_len = 0
+ #put working registers in the symbol table
+ for reg in range(SharedData.FUNCTION_REGISTER+1):
+ self.insert_symbol(SharedData.REGISTERS[reg], SharedData.KINDS.WORKING_REGISTER, SharedData.TYPES.NO_TYPE)
+ #shared data
+ self.shared = shared
+
+ def error(self, text=""):
+ """Symbol table error exception. It should happen only if index is out of range while accessing symbol table.
+ This exeption is not handled by the compiler, so as to allow traceback printing
+ """
+ if text == "":
+ raise Exception("Symbol table index out of range")
+ else:
+ raise Exception("Symbol table error: %s" % text)
+
+ def display(self):
+ """Displays the symbol table content"""
+ #Finding the maximum length for each column
+ sym_name = "Symbol name"
+ sym_len = max(max(len(i.name) for i in self.table),len(sym_name))
+ kind_name = "Kind"
+ kind_len = max(max(len(SharedData.KINDS[i.kind]) for i in self.table),len(kind_name))
+ type_name = "Type"
+ type_len = max(max(len(SharedData.TYPES[i.type]) for i in self.table),len(type_name))
+ attr_name = "Attribute"
+ attr_len = max(max(len(i.attribute_str()) for i in self.table),len(attr_name))
+ #print table header
+ print("{0:3s} | {1:^{2}s} | {3:^{4}s} | {5:^{6}s} | {7:^{8}} | {9:s}".format(" No", sym_name, sym_len, kind_name, kind_len, type_name, type_len, attr_name, attr_len, "Parameters"))
+ print("-----------------------------" + "-" * (sym_len + kind_len + type_len + attr_len))
+ #print symbol table
+ for i,sym in enumerate(self.table):
+ parameters = ""
+ for p in sym.param_types:
+ if parameters == "":
+ parameters = "{0}".format(SharedData.TYPES[p])
+ else:
+ parameters += ", {0}".format(SharedData.TYPES[p])
+ print("{0:3d} | {1:^{2}s} | {3:^{4}s} | {5:^{6}s} | {7:^{8}} | ({9})".format(i, sym.name, sym_len, SharedData.KINDS[sym.kind], kind_len, SharedData.TYPES[sym.type], type_len, sym.attribute_str(), attr_len, parameters))
+
+ def insert_symbol(self, sname, skind, stype):
+ """Inserts new symbol at the end of the symbol table.
+ Returns symbol index
+ sname - symbol name
+ skind - symbol kind
+ stype - symbol type
+ """
+ self.table.append(SymbolTableEntry(sname, skind, stype))
+ self.table_len = len(self.table)
+ return self.table_len-1
+
+ def clear_symbols(self, index):
+ """Clears all symbols begining with the index to the end of table"""
+ try:
+ del self.table[index:]
+ except Exception:
+ self.error()
+ self.table_len = len(self.table)
+
+ def lookup_symbol(self, sname, skind=list(SharedData.KINDS.keys()), stype=list(SharedData.TYPES.keys())):
+ """Searches for symbol, from the end to the begining.
+ Returns symbol index or None
+ sname - symbol name
+ skind - symbol kind (one kind, list of kinds, or None) deafult: any kind
+ stype - symbol type (or None) default: any type
+ """
+ skind = skind if isinstance(skind, list) else [skind]
+ stype = stype if isinstance(stype, list) else [stype]
+ for i, sym in [[x, self.table[x]] for x in range(len(self.table) - 1, SharedData.LAST_WORKING_REGISTER, -1)]:
+ if (sym.name == sname) and (sym.kind in skind) and (sym.type in stype):
+ return i
+ return None
+
+ def insert_id(self, sname, skind, skinds, stype):
+ """Inserts a new identifier at the end of the symbol table, if possible.
+ Returns symbol index, or raises an exception if the symbol alredy exists
+ sname - symbol name
+ skind - symbol kind
+ skinds - symbol kinds to check for
+ stype - symbol type
+ """
+ index = self.lookup_symbol(sname, skinds)
+ if index == None:
+ index = self.insert_symbol(sname, skind, stype)
+ return index
+ else:
+ raise SemanticException("Redefinition of '%s'" % sname)
+
+ def insert_global_var(self, vname, vtype):
+ "Inserts a new global variable"
+ return self.insert_id(vname, SharedData.KINDS.GLOBAL_VAR, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.FUNCTION], vtype)
+
+ def insert_local_var(self, vname, vtype, position):
+ "Inserts a new local variable"
+ index = self.insert_id(vname, SharedData.KINDS.LOCAL_VAR, [SharedData.KINDS.LOCAL_VAR, SharedData.KINDS.PARAMETER], vtype)
+ self.table[index].attribute = position
+
+ def insert_parameter(self, pname, ptype):
+ "Inserts a new parameter"
+ index = self.insert_id(pname, SharedData.KINDS.PARAMETER, SharedData.KINDS.PARAMETER, ptype)
+ #set parameter's attribute to it's ordinal number
+ self.table[index].set_attribute("Index", self.shared.function_params)
+ #set parameter's type in param_types list of a function
+ self.table[self.shared.function_index].param_types.append(ptype)
+ return index
+
+ def insert_function(self, fname, ftype):
+ "Inserts a new function"
+ index = self.insert_id(fname, SharedData.KINDS.FUNCTION, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.FUNCTION], ftype)
+ self.table[index].set_attribute("Params",0)
+ return index
+
+ def insert_constant(self, cname, ctype):
+ """Inserts a constant (or returns index if the constant already exists)
+ Additionally, checks for range.
+ """
+ index = self.lookup_symbol(cname, stype=ctype)
+ if index == None:
+ num = int(cname)
+ if ctype == SharedData.TYPES.INT:
+ if (num < SharedData.MIN_INT) or (num > SharedData.MAX_INT):
+ raise SemanticException("Integer constant '%s' out of range" % cname)
+ elif ctype == SharedData.TYPES.UNSIGNED:
+ if (num < 0) or (num > SharedData.MAX_UNSIGNED):
+ raise SemanticException("Unsigned constant '%s' out of range" % cname)
+ index = self.insert_symbol(cname, SharedData.KINDS.CONSTANT, ctype)
+ return index
+
+ def same_types(self, index1, index2):
+ """Returns True if both symbol table elements are of the same type"""
+ try:
+ same = self.table[index1].type == self.table[index2].type != SharedData.TYPES.NO_TYPE
+ except Exception:
+ self.error()
+ return same
+
+ def same_type_as_argument(self, index, function_index, argument_number):
+ """Returns True if index and function's argument are of the same type
+ index - index in symbol table
+ function_index - function's index in symbol table
+ argument_number - # of function's argument
+ """
+ try:
+ same = self.table[function_index].param_types[argument_number] == self.table[index].type
+ except Exception:
+ self.error()
+ return same
+
+ def get_attribute(self, index):
+ try:
+ return self.table[index].attribute
+ except Exception:
+ self.error()
+
+ def set_attribute(self, index, value):
+ try:
+ self.table[index].attribute = value
+ except Exception:
+ self.error()
+
+ def get_name(self, index):
+ try:
+ return self.table[index].name
+ except Exception:
+ self.error()
+
+ def get_kind(self, index):
+ try:
+ return self.table[index].kind
+ except Exception:
+ self.error()
+
+ def get_type(self, index):
+ try:
+ return self.table[index].type
+ except Exception:
+ self.error()
+
+ def set_type(self, index, stype):
+ try:
+ self.table[index].type = stype
+ except Exception:
+ self.error()
+
+##########################################################################################
+##########################################################################################
+
+class CodeGenerator(object):
+ """Class for code generation methods."""
+
+ #dictionary of relational operators
+ RELATIONAL_DICT = dict([op,i] for i, op in enumerate(SharedData.RELATIONAL_OPERATORS))
+ #conditional jumps for relational operators
+ CONDITIONAL_JUMPS = ["JLTS", "JGTS", "JLES", "JGES", "JEQ ", "JNE ",
+ "JLTU", "JGTU", "JLEU", "JGEU", "JEQ ", "JNE "]
+ #opposite conditional jumps for relational operators
+ OPPOSITE_JUMPS = ["JGES", "JLES", "JGTS", "JLTS", "JNE ", "JEQ ",
+ "JGEU", "JLEU", "JGTU", "JLTU", "JNE ", "JEQ "]
+ #supported operations
+ OPERATIONS = {"+" : "ADD", "-" : "SUB", "*" : "MUL", "/" : "DIV"}
+ #suffixes for signed and unsigned operations (if no type is specified, unsigned will be assumed)
+ OPSIGNS = {SharedData.TYPES.NO_TYPE : "U", SharedData.TYPES.INT : "S", SharedData.TYPES.UNSIGNED : "U"}
+ #text at start of data segment
+ DATA_START_TEXT = "#DATA"
+ #text at start of code segment
+ CODE_START_TEXT = "#CODE"
+
+ def __init__(self, shared, symtab):
+ #generated code
+ self.code = ""
+ #prefix for internal labels
+ self.internal = "@"
+ #suffix for label definition
+ self.definition = ":"
+ #list of free working registers
+ self.free_registers = list(range(SharedData.FUNCTION_REGISTER, -1, -1))
+ #list of used working registers
+ self.used_registers = []
+ #list of used registers needed when function call is inside of a function call
+ self.used_registers_stack = []
+ #shared data
+ self.shared = shared
+ #symbol table
+ self.symtab = symtab
+
+ def error(self, text):
+ """Compiler error exception. It should happen only if something is wrong with compiler.
+ This exeption is not handled by the compiler, so as to allow traceback printing
+ """
+ raise Exception("Compiler error: %s" % text)
+
+ def take_register(self, rtype = SharedData.TYPES.NO_TYPE):
+ """Reserves one working register and sets its type"""
+ if len(self.free_registers) == 0:
+ self.error("no more free registers")
+ reg = self.free_registers.pop()
+ self.used_registers.append(reg)
+ self.symtab.set_type(reg, rtype)
+ return reg
+
+ def take_function_register(self, rtype = SharedData.TYPES.NO_TYPE):
+ """Reserves register for function return value and sets its type"""
+ reg = SharedData.FUNCTION_REGISTER
+ if reg not in self.free_registers:
+ self.error("function register already taken")
+ self.free_registers.remove(reg)
+ self.used_registers.append(reg)
+ self.symtab.set_type(reg, rtype)
+ return reg
+
+ def free_register(self, reg):
+ """Releases working register"""
+ if reg not in self.used_registers:
+ self.error("register %s is not taken" % self.REGISTERS[reg])
+ self.used_registers.remove(reg)
+ self.free_registers.append(reg)
+ self.free_registers.sort(reverse = True)
+
+ def free_if_register(self, index):
+ """If index is a working register, free it, otherwise just return (helper function)"""
+ if (index < 0) or (index > SharedData.FUNCTION_REGISTER):
+ return
+ else:
+ self.free_register(index)
+
+ def label(self, name, internal=False, definition=False):
+ """Generates label name (helper function)
+ name - label name
+ internal - boolean value, adds "@" prefix to label
+ definition - boolean value, adds ":" suffix to label
+ """
+ return "{0}{1}{2}".format(self.internal if internal else "", name, self.definition if definition else "")
+
+ def symbol(self, index):
+ """Generates symbol name from index"""
+ #if index is actually a string, just return it
+ if isinstance(index, str):
+ return index
+ elif (index < 0) or (index >= self.symtab.table_len):
+ self.error("symbol table index out of range")
+ sym = self.symtab.table[index]
+ #local variables are located at negative offset from frame pointer register
+ if sym.kind == SharedData.KINDS.LOCAL_VAR:
+ return "-{0}(%14)".format(sym.attribute * 4 + 4)
+ #parameters are located at positive offset from frame pointer register
+ elif sym.kind == SharedData.KINDS.PARAMETER:
+ return "{0}(%14)".format(8 + sym.attribute * 4)
+ elif sym.kind == SharedData.KINDS.CONSTANT:
+ return "${0}".format(sym.name)
+ else:
+ return "{0}".format(sym.name)
+
+ def save_used_registers(self):
+ """Pushes all used working registers before function call"""
+ used = self.used_registers[:]
+ del self.used_registers[:]
+ self.used_registers_stack.append(used[:])
+ used.sort()
+ for reg in used:
+ self.newline_text("PUSH\t%s" % SharedData.REGISTERS[reg], True)
+ self.free_registers.extend(used)
+ self.free_registers.sort(reverse = True)
+
+ def restore_used_registers(self):
+ """Pops all used working registers after function call"""
+ used = self.used_registers_stack.pop()
+ self.used_registers = used[:]
+ used.sort(reverse = True)
+ for reg in used:
+ self.newline_text("POP \t%s" % SharedData.REGISTERS[reg], True)
+ self.free_registers.remove(reg)
+
+ def text(self, text):
+ """Inserts text into generated code"""
+ self.code += text
+
+ def prepare_data_segment(self):
+ """Inserts text at the start of data segment"""
+ self.text(self.DATA_START_TEXT)
+
+ def prepare_code_segment(self):
+ """Inserts text at the start of code segment"""
+ self.newline_text(self.CODE_START_TEXT)
+
+ def newline(self, indent=False):
+ """Inserts a newline, optionally with indentation."""
+ self.text("\n")
+ if indent:
+ self.text("\t\t\t")
+
+ def newline_text(self, text, indent = False):
+ """Inserts a newline and text, optionally with indentation (helper function)"""
+ self.newline(indent)
+ self.text(text)
+
+ def newline_label(self, name, internal=False, definition=False):
+ """Inserts a newline and a label (helper function)
+ name - label name
+ internal - boolean value, adds "@" prefix to label
+ definition - boolean value, adds ":" suffix to label
+ """
+ self.newline_text(self.label("{0}{1}{2}".format("@" if internal else "", name, ":" if definition else "")))
+
+ def global_var(self, name):
+ """Inserts a new static (global) variable definition"""
+ self.newline_label(name, False, True)
+ self.newline_text("WORD\t1", True)
+
+ def arithmetic_mnemonic(self, op_name, op_type):
+ """Generates an arithmetic instruction mnemonic"""
+ return self.OPERATIONS[op_name] + self.OPSIGNS[op_type]
+
+ def arithmetic(self, operation, operand1, operand2, operand3 = None):
+ """Generates an arithmetic instruction
+ operation - one of supporetd operations
+ operandX - index in symbol table or text representation of operand
+ First two operands are input, third one is output
+ """
+ if isinstance(operand1, int):
+ output_type = self.symtab.get_type(operand1)
+ self.free_if_register(operand1)
+ else:
+ output_type = None
+ if isinstance(operand2, int):
+ output_type = self.symtab.get_type(operand2) if output_type == None else output_type
+ self.free_if_register(operand2)
+ else:
+ output_type = SharedData.TYPES.NO_TYPE if output_type == None else output_type
+ #if operand3 is not defined, reserve one free register for it
+ output = self.take_register(output_type) if operand3 == None else operand3
+ mnemonic = self.arithmetic_mnemonic(operation, output_type)
+ self.newline_text("{0}\t{1},{2},{3}".format(mnemonic, self.symbol(operand1), self.symbol(operand2), self.symbol(output)), True)
+ return output
+
+ def relop_code(self, relop, operands_type):
+ """Returns code for relational operator
+ relop - relational operator
+ operands_type - int or unsigned
+ """
+ code = self.RELATIONAL_DICT[relop]
+ offset = 0 if operands_type == SharedData.TYPES.INT else len(SharedData.RELATIONAL_OPERATORS)
+ return code + offset
+
+ def jump(self, relcode, opposite, label):
+ """Generates a jump instruction
+ relcode - relational operator code
+ opposite - generate normal or opposite jump
+ label - jump label
+ """
+ jump = self.OPPOSITE_JUMPS[relcode] if opposite else self.CONDITIONAL_JUMPS[relcode]
+ self.newline_text("{0}\t{1}".format(jump, label), True)
+
+ def unconditional_jump(self, label):
+ """Generates an unconditional jump instruction
+ label - jump label
+ """
+ self.newline_text("JMP \t{0}".format(label), True)
+
+ def move(self,operand1, operand2):
+ """Generates a move instruction
+ If the output operand (opernad2) is a working register, sets it's type
+ operandX - index in symbol table or text representation of operand
+ """
+ if isinstance(operand1, int):
+ output_type = self.symtab.get_type(operand1)
+ self.free_if_register(operand1)
+ else:
+ output_type = SharedData.TYPES.NO_TYPE
+ self.newline_text("MOV \t{0},{1}".format(self.symbol(operand1), self.symbol(operand2)), True)
+ if isinstance(operand2, int):
+ if self.symtab.get_kind(operand2) == SharedData.KINDS.WORKING_REGISTER:
+ self.symtab.set_type(operand2, output_type)
+
+ def push(self, operand):
+ """Generates a push operation"""
+ self.newline_text("PUSH\t%s" % self.symbol(operand), True)
+
+ def pop(self, operand):
+ """Generates a pop instruction"""
+ self.newline_text("POP \t%s" % self.symbol(operand), True)
+
+ def compare(self, operand1, operand2):
+ """Generates a compare instruction
+ operandX - index in symbol table
+ """
+ typ = self.symtab.get_type(operand1)
+ self.free_if_register(operand1)
+ self.free_if_register(operand2)
+ self.newline_text("CMP{0}\t{1},{2}".format(self.OPSIGNS[typ], self.symbol(operand1), self.symbol(operand2)), True)
+
+ def function_begin(self):
+ """Inserts function name label and function frame initialization"""
+ self.newline_label(self.shared.function_name, False, True)
+ self.push("%14")
+ self.move("%15", "%14")
+
+ def function_body(self):
+ """Inserts a local variable initialization and body label"""
+ if self.shared.function_vars > 0:
+ const = self.symtab.insert_constant("{0}".format(self.shared.function_vars * 4), SharedData.TYPES.UNSIGNED)
+ self.arithmetic("-", "%15", const, "%15")
+ self.newline_label(self.shared.function_name + "_body", True, True)
+
+ def function_end(self):
+ """Inserts an exit label and function return instructions"""
+ self.newline_label(self.shared.function_name + "_exit", True, True)
+ self.move("%14", "%15")
+ self.pop("%14")
+ self.newline_text("RET", True)
+
+ def function_call(self, function, arguments):
+ """Generates code for a function call
+ function - function index in symbol table
+ arguments - list of arguments (indexes in symbol table)
+ """
+ #push each argument to stack
+ for arg in arguments:
+ self.push(self.symbol(arg))
+ self.free_if_register(arg)
+ self.newline_text("CALL\t"+self.symtab.get_name(function), True)
+ args = self.symtab.get_attribute(function)
+ #generates stack cleanup if function has arguments
+ if args > 0:
+ args_space = self.symtab.insert_constant("{0}".format(args * 4), SharedData.TYPES.UNSIGNED)
+ self.arithmetic("+", "%15", args_space, "%15")
+
+##########################################################################################
+##########################################################################################
+
+class MicroC(object):
+ """Class for microC parser/compiler"""
+
+ def __init__(self):
+ #Definitions of terminal symbols for microC programming language
+ self.tId = Word(alphas+"_",alphanums+"_")
+ self.tInteger = Word(nums).setParseAction(lambda x : [x[0], SharedData.TYPES.INT])
+ self.tUnsigned = Regex(r"[0-9]+[uU]").setParseAction(lambda x : [x[0][:-1], SharedData.TYPES.UNSIGNED])
+ self.tConstant = (self.tUnsigned | self.tInteger).setParseAction(self.constant_action)
+ self.tType = Keyword("int").setParseAction(lambda x : SharedData.TYPES.INT) | \
+ Keyword("unsigned").setParseAction(lambda x : SharedData.TYPES.UNSIGNED)
+ self.tRelOp = oneOf(SharedData.RELATIONAL_OPERATORS)
+ self.tMulOp = oneOf("* /")
+ self.tAddOp = oneOf("+ -")
+
+ #Definitions of rules for global variables
+ self.rGlobalVariable = (self.tType("type") + self.tId("name") +
+ FollowedBy(";")).setParseAction(self.global_variable_action)
+ self.rGlobalVariableList = ZeroOrMore(self.rGlobalVariable + Suppress(";"))
+
+ #Definitions of rules for numeric expressions
+ self.rExp = Forward()
+ self.rMulExp = Forward()
+ self.rNumExp = Forward()
+ self.rArguments = delimitedList(self.rNumExp("exp").setParseAction(self.argument_action))
+ self.rFunctionCall = ((self.tId("name") + FollowedBy("(")).setParseAction(self.function_call_prepare_action) +
+ Suppress("(") + Optional(self.rArguments)("args") + Suppress(")")).setParseAction(self.function_call_action)
+ self.rExp << (self.rFunctionCall |
+ self.tConstant |
+ self.tId("name").setParseAction(self.lookup_id_action) |
+ Group(Suppress("(") + self.rNumExp + Suppress(")")) |
+ Group("+" + self.rExp) |
+ Group("-" + self.rExp)).setParseAction(lambda x : x[0])
+ self.rMulExp << ((self.rExp + ZeroOrMore(self.tMulOp + self.rExp))).setParseAction(self.mulexp_action)
+ self.rNumExp << (self.rMulExp + ZeroOrMore(self.tAddOp + self.rMulExp)).setParseAction(self.numexp_action)
+
+ #Definitions of rules for logical expressions (these are without parenthesis support)
+ self.rAndExp = Forward()
+ self.rLogExp = Forward()
+ self.rRelExp = (self.rNumExp + self.tRelOp + self.rNumExp).setParseAction(self.relexp_action)
+ self.rAndExp << (self.rRelExp("exp") + ZeroOrMore(Literal("&&").setParseAction(self.andexp_action) +
+ self.rRelExp("exp")).setParseAction(lambda x : self.relexp_code))
+ self.rLogExp << (self.rAndExp("exp") + ZeroOrMore(Literal("||").setParseAction(self.logexp_action) +
+ self.rAndExp("exp")).setParseAction(lambda x : self.andexp_code))
+
+ #Definitions of rules for statements
+ self.rStatement = Forward()
+ self.rStatementList = Forward()
+ self.rReturnStatement = (Keyword("return") + self.rNumExp("exp") +
+ Suppress(";")).setParseAction(self.return_action)
+ self.rAssignmentStatement = (self.tId("var") + Suppress("=") + self.rNumExp("exp") +
+ Suppress(";")).setParseAction(self.assignment_action)
+ self.rFunctionCallStatement = self.rFunctionCall + Suppress(";")
+ self.rIfStatement = ( (Keyword("if") + FollowedBy("(")).setParseAction(self.if_begin_action) +
+ (Suppress("(") + self.rLogExp + Suppress(")")).setParseAction(self.if_body_action) +
+ (self.rStatement + Empty()).setParseAction(self.if_else_action) +
+ Optional(Keyword("else") + self.rStatement)).setParseAction(self.if_end_action)
+ self.rWhileStatement = ( (Keyword("while") + FollowedBy("(")).setParseAction(self.while_begin_action) +
+ (Suppress("(") + self.rLogExp + Suppress(")")).setParseAction(self.while_body_action) +
+ self.rStatement).setParseAction(self.while_end_action)
+ self.rCompoundStatement = Group(Suppress("{") + self.rStatementList + Suppress("}"))
+ self.rStatement << (self.rReturnStatement | self.rIfStatement | self.rWhileStatement |
+ self.rFunctionCallStatement | self.rAssignmentStatement | self.rCompoundStatement)
+ self.rStatementList << ZeroOrMore(self.rStatement)
+
+ self.rLocalVariable = (self.tType("type") + self.tId("name") + FollowedBy(";")).setParseAction(self.local_variable_action)
+ self.rLocalVariableList = ZeroOrMore(self.rLocalVariable + Suppress(";"))
+ self.rFunctionBody = Suppress("{") + Optional(self.rLocalVariableList).setParseAction(self.function_body_action) + \
+ self.rStatementList + Suppress("}")
+ self.rParameter = (self.tType("type") + self.tId("name")).setParseAction(self.parameter_action)
+ self.rParameterList = delimitedList(self.rParameter)
+ self.rFunction = ( (self.tType("type") + self.tId("name")).setParseAction(self.function_begin_action) +
+ Group(Suppress("(") + Optional(self.rParameterList)("params") + Suppress(")") +
+ self.rFunctionBody)).setParseAction(self.function_end_action)
+
+ self.rFunctionList = OneOrMore(self.rFunction)
+ self.rProgram = (Empty().setParseAction(self.data_begin_action) + self.rGlobalVariableList +
+ Empty().setParseAction(self.code_begin_action) + self.rFunctionList).setParseAction(self.program_end_action)
+
+ #shared data
+ self.shared = SharedData()
+ #symbol table
+ self.symtab = SymbolTable(self.shared)
+ #code generator
+ self.codegen = CodeGenerator(self.shared, self.symtab)
+
+ #index of the current function call
+ self.function_call_index = -1
+ #stack for the nested function calls
+ self.function_call_stack = []
+ #arguments of the current function call
+ self.function_arguments = []
+ #stack for arguments of the nested function calls
+ self.function_arguments_stack = []
+ #number of arguments for the curent function call
+ self.function_arguments_number = -1
+ #stack for the number of arguments for the nested function calls
+ self.function_arguments_number_stack = []
+
+ #last relational expression
+ self.relexp_code = None
+ #last and expression
+ self.andexp_code = None
+ #label number for "false" internal labels
+ self.false_label_number = -1
+ #label number for all other internal labels
+ self.label_number = None
+ #label stack for nested statements
+ self.label_stack = []
+
+ def warning(self, message, print_location=True):
+ """Displays warning message. Uses exshared for current location of parsing"""
+ msg = "Warning"
+ if print_location and (exshared.location != None):
+ wline = lineno(exshared.location, exshared.text)
+ wcol = col(exshared.location, exshared.text)
+ wtext = line(exshared.location, exshared.text)
+ msg += " at line %d, col %d" % (wline, wcol)
+ msg += ": %s" % message
+ if print_location and (exshared.location != None):
+ msg += "\n%s" % wtext
+ print(msg)
+
+
+ def data_begin_action(self):
+ """Inserts text at start of data segment"""
+ self.codegen.prepare_data_segment()
+
+ def code_begin_action(self):
+ """Inserts text at start of code segment"""
+ self.codegen.prepare_code_segment()
+
+ def global_variable_action(self, text, loc, var):
+ """Code executed after recognising a global variable"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("GLOBAL_VAR:",var)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ index = self.symtab.insert_global_var(var.name, var.type)
+ self.codegen.global_var(var.name)
+ return index
+
+ def local_variable_action(self, text, loc, var):
+ """Code executed after recognising a local variable"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("LOCAL_VAR:",var, var.name, var.type)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ index = self.symtab.insert_local_var(var.name, var.type, self.shared.function_vars)
+ self.shared.function_vars += 1
+ return index
+
+ def parameter_action(self, text, loc, par):
+ """Code executed after recognising a parameter"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("PARAM:",par)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ index = self.symtab.insert_parameter(par.name, par.type)
+ self.shared.function_params += 1
+ return index
+
+ def constant_action(self, text, loc, const):
+ """Code executed after recognising a constant"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("CONST:",const)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ return self.symtab.insert_constant(const[0], const[1])
+
+ def function_begin_action(self, text, loc, fun):
+ """Code executed after recognising a function definition (type and function name)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("FUN_BEGIN:",fun)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ self.shared.function_index = self.symtab.insert_function(fun.name, fun.type)
+ self.shared.function_name = fun.name
+ self.shared.function_params = 0
+ self.shared.function_vars = 0
+ self.codegen.function_begin();
+
+ def function_body_action(self, text, loc, fun):
+ """Code executed after recognising the beginning of function's body"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("FUN_BODY:",fun)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ self.codegen.function_body()
+
+ def function_end_action(self, text, loc, fun):
+ """Code executed at the end of function definition"""
+ if DEBUG > 0:
+ print("FUN_END:",fun)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #set function's attribute to number of function parameters
+ self.symtab.set_attribute(self.shared.function_index, self.shared.function_params)
+ #clear local function symbols (but leave function name)
+ self.symtab.clear_symbols(self.shared.function_index + 1)
+ self.codegen.function_end()
+
+ def return_action(self, text, loc, ret):
+ """Code executed after recognising a return statement"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("RETURN:",ret)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ if not self.symtab.same_types(self.shared.function_index, ret.exp[0]):
+ raise SemanticException("Incompatible type in return")
+ #set register for function's return value to expression value
+ reg = self.codegen.take_function_register()
+ self.codegen.move(ret.exp[0], reg)
+ #after return statement, register for function's return value is available again
+ self.codegen.free_register(reg)
+ #jump to function's exit
+ self.codegen.unconditional_jump(self.codegen.label(self.shared.function_name+"_exit", True))
+
+ def lookup_id_action(self, text, loc, var):
+ """Code executed after recognising an identificator in expression"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("EXP_VAR:",var)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ var_index = self.symtab.lookup_symbol(var.name, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.PARAMETER, SharedData.KINDS.LOCAL_VAR])
+ if var_index == None:
+ raise SemanticException("'%s' undefined" % var.name)
+ return var_index
+
+ def assignment_action(self, text, loc, assign):
+ """Code executed after recognising an assignment statement"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("ASSIGN:",assign)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ var_index = self.symtab.lookup_symbol(assign.var, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.PARAMETER, SharedData.KINDS.LOCAL_VAR])
+ if var_index == None:
+ raise SemanticException("Undefined lvalue '%s' in assignment" % assign.var)
+ if not self.symtab.same_types(var_index, assign.exp[0]):
+ raise SemanticException("Incompatible types in assignment")
+ self.codegen.move(assign.exp[0], var_index)
+
+ def mulexp_action(self, text, loc, mul):
+ """Code executed after recognising a mulexp expression (something *|/ something)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("MUL_EXP:",mul)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #iterate through all multiplications/divisions
+ m = list(mul)
+ while len(m) > 1:
+ if not self.symtab.same_types(m[0], m[2]):
+ raise SemanticException("Invalid opernads to binary '%s'" % m[1])
+ reg = self.codegen.arithmetic(m[1], m[0], m[2])
+ #replace first calculation with it's result
+ m[0:3] = [reg]
+ return m[0]
+
+ def numexp_action(self, text, loc, num):
+ """Code executed after recognising a numexp expression (something +|- something)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("NUM_EXP:",num)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #iterate through all additions/substractions
+ n = list(num)
+ while len(n) > 1:
+ if not self.symtab.same_types(n[0], n[2]):
+ raise SemanticException("Invalid opernads to binary '%s'" % n[1])
+ reg = self.codegen.arithmetic(n[1], n[0], n[2])
+ #replace first calculation with it's result
+ n[0:3] = [reg]
+ return n[0]
+
+ def function_call_prepare_action(self, text, loc, fun):
+ """Code executed after recognising a function call (type and function name)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("FUN_PREP:",fun)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ index = self.symtab.lookup_symbol(fun.name, SharedData.KINDS.FUNCTION)
+ if index == None:
+ raise SemanticException("'%s' is not a function" % fun.name)
+ #save any previous function call data (for nested function calls)
+ self.function_call_stack.append(self.function_call_index)
+ self.function_call_index = index
+ self.function_arguments_stack.append(self.function_arguments[:])
+ del self.function_arguments[:]
+ self.codegen.save_used_registers()
+
+ def argument_action(self, text, loc, arg):
+ """Code executed after recognising each of function's arguments"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("ARGUMENT:",arg.exp)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ arg_ordinal = len(self.function_arguments)
+ #check argument's type
+ if not self.symtab.same_type_as_argument(arg.exp, self.function_call_index, arg_ordinal):
+ raise SemanticException("Incompatible type for argument %d in '%s'" % (arg_ordinal + 1, self.symtab.get_name(self.function_call_index)))
+ self.function_arguments.append(arg.exp)
+
+ def function_call_action(self, text, loc, fun):
+ """Code executed after recognising the whole function call"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("FUN_CALL:",fun)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #check number of arguments
+ if len(self.function_arguments) != self.symtab.get_attribute(self.function_call_index):
+ raise SemanticException("Wrong number of arguments for function '%s'" % fun.name)
+ #arguments should be pushed to stack in reverse order
+ self.function_arguments.reverse()
+ self.codegen.function_call(self.function_call_index, self.function_arguments)
+ self.codegen.restore_used_registers()
+ return_type = self.symtab.get_type(self.function_call_index)
+ #restore previous function call data
+ self.function_call_index = self.function_call_stack.pop()
+ self.function_arguments = self.function_arguments_stack.pop()
+ register = self.codegen.take_register(return_type)
+ #move result to a new free register, to allow the next function call
+ self.codegen.move(self.codegen.take_function_register(return_type), register)
+ return register
+
+ def relexp_action(self, text, loc, arg):
+ """Code executed after recognising a relexp expression (something relop something)"""
+ if DEBUG > 0:
+ print("REL_EXP:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ exshared.setpos(loc, text)
+ if not self.symtab.same_types(arg[0], arg[2]):
+ raise SemanticException("Invalid operands for operator '{0}'".format(arg[1]))
+ self.codegen.compare(arg[0], arg[2])
+ #return relational operator's code
+ self.relexp_code = self.codegen.relop_code(arg[1], self.symtab.get_type(arg[0]))
+ return self.relexp_code
+
+ def andexp_action(self, text, loc, arg):
+ """Code executed after recognising a andexp expression (something and something)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("AND+EXP:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ label = self.codegen.label("false{0}".format(self.false_label_number), True, False)
+ self.codegen.jump(self.relexp_code, True, label)
+ self.andexp_code = self.relexp_code
+ return self.andexp_code
+
+ def logexp_action(self, text, loc, arg):
+ """Code executed after recognising logexp expression (something or something)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("LOG_EXP:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ label = self.codegen.label("true{0}".format(self.label_number), True, False)
+ self.codegen.jump(self.relexp_code, False, label)
+ self.codegen.newline_label("false{0}".format(self.false_label_number), True, True)
+ self.false_label_number += 1
+
+ def if_begin_action(self, text, loc, arg):
+ """Code executed after recognising an if statement (if keyword)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("IF_BEGIN:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ self.false_label_number += 1
+ self.label_number = self.false_label_number
+ self.codegen.newline_label("if{0}".format(self.label_number), True, True)
+
+ def if_body_action(self, text, loc, arg):
+ """Code executed after recognising if statement's body"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("IF_BODY:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #generate conditional jump (based on last compare)
+ label = self.codegen.label("false{0}".format(self.false_label_number), True, False)
+ self.codegen.jump(self.relexp_code, True, label)
+ #generate 'true' label (executes if condition is satisfied)
+ self.codegen.newline_label("true{0}".format(self.label_number), True, True)
+ #save label numbers (needed for nested if/while statements)
+ self.label_stack.append(self.false_label_number)
+ self.label_stack.append(self.label_number)
+
+ def if_else_action(self, text, loc, arg):
+ """Code executed after recognising if statement's else body"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("IF_ELSE:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #jump to exit after all statements for true condition are executed
+ self.label_number = self.label_stack.pop()
+ label = self.codegen.label("exit{0}".format(self.label_number), True, False)
+ self.codegen.unconditional_jump(label)
+ #generate final 'false' label (executes if condition isn't satisfied)
+ self.codegen.newline_label("false{0}".format(self.label_stack.pop()), True, True)
+ self.label_stack.append(self.label_number)
+
+ def if_end_action(self, text, loc, arg):
+ """Code executed after recognising a whole if statement"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("IF_END:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ self.codegen.newline_label("exit{0}".format(self.label_stack.pop()), True, True)
+
+ def while_begin_action(self, text, loc, arg):
+ """Code executed after recognising a while statement (while keyword)"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("WHILE_BEGIN:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ self.false_label_number += 1
+ self.label_number = self.false_label_number
+ self.codegen.newline_label("while{0}".format(self.label_number), True, True)
+
+ def while_body_action(self, text, loc, arg):
+ """Code executed after recognising while statement's body"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("WHILE_BODY:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #generate conditional jump (based on last compare)
+ label = self.codegen.label("false{0}".format(self.false_label_number), True, False)
+ self.codegen.jump(self.relexp_code, True, label)
+ #generate 'true' label (executes if condition is satisfied)
+ self.codegen.newline_label("true{0}".format(self.label_number), True, True)
+ self.label_stack.append(self.false_label_number)
+ self.label_stack.append(self.label_number)
+
+ def while_end_action(self, text, loc, arg):
+ """Code executed after recognising a whole while statement"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("WHILE_END:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ #jump to condition checking after while statement body
+ self.label_number = self.label_stack.pop()
+ label = self.codegen.label("while{0}".format(self.label_number), True, False)
+ self.codegen.unconditional_jump(label)
+ #generate final 'false' label and exit label
+ self.codegen.newline_label("false{0}".format(self.label_stack.pop()), True, True)
+ self.codegen.newline_label("exit{0}".format(self.label_number), True, True)
+
+ def program_end_action(self, text, loc, arg):
+ """Checks if there is a 'main' function and the type of 'main' function"""
+ exshared.setpos(loc, text)
+ if DEBUG > 0:
+ print("PROGRAM_END:",arg)
+ if DEBUG == 2: self.symtab.display()
+ if DEBUG > 2: return
+ index = self.symtab.lookup_symbol("main",SharedData.KINDS.FUNCTION)
+ if index == None:
+ raise SemanticException("Undefined reference to 'main'", False)
+ elif self.symtab.get_type(index) != SharedData.TYPES.INT:
+ self.warning("Return type of 'main' is not int", False)
+
+ def parse_text(self,text):
+ """Parse string (helper function)"""
+ try:
+ return self.rProgram.ignore(cStyleComment).parseString(text, parseAll=True)
+ except SemanticException as err:
+ print(err)
+ exit(3)
+ except ParseException as err:
+ print(err)
+ exit(3)
+
+ def parse_file(self,filename):
+ """Parse file (helper function)"""
+ try:
+ return self.rProgram.ignore(cStyleComment).parseFile(filename, parseAll=True)
+ except SemanticException as err:
+ print(err)
+ exit(3)
+ except ParseException as err:
+ print(err)
+ exit(3)
+
+##########################################################################################
+##########################################################################################
+if 0:
+ #main program
+ mc = MicroC()
+ output_file = "output.asm"
+
+ if len(argv) == 1:
+ input_file = stdin
+ elif len(argv) == 2:
+ input_file = argv[1]
+ elif len(argv) == 3:
+ input_file = argv[1]
+ output_file = argv[2]
+ else:
+ usage = """Usage: {0} [input_file [output_file]]
+ If output file is omitted, output.asm is used
+ If input file is omitted, stdin is used""".format(argv[0])
+ print(usage)
+ exit(1)
+ try:
+ parse = stdin if input_file == stdin else open(input_file,'r')
+ except Exception:
+ print("Input file '%s' open error" % input_file)
+ exit(2)
+ mc.parse_file(parse)
+ #if you want to see the final symbol table, uncomment next line
+ #mc.symtab.display()
+ try:
+ out = open(output_file, 'w')
+ out.write(mc.codegen.code)
+ out.close
+ except Exception:
+ print("Output file '%s' open error" % output_file)
+ exit(2)
+
+##########################################################################################
+##########################################################################################
+
+if __name__ == "__main__":
+
+ test_program_example = """
+ int a;
+ int b;
+ int c;
+ unsigned d;
+
+ int fun1(int x, unsigned y) {
+ return 123;
+ }
+
+ int fun2(int a) {
+ return 1 + a * fun1(a, 456u);
+ }
+
+ int main(int x, int y) {
+ int w;
+ unsigned z;
+ if (9 > 8 && 2 < 3 || 6 != 5 && a <= b && c < x || w >= y) {
+ a = b + 1;
+ if (x == y)
+ while (d < 4u)
+ x = x * w;
+ else
+ while (a + b < c - y && x > 3 || y < 2)
+ if (z > d)
+ a = a - 4;
+ else
+ b = a * b * c * x / y;
+ }
+ else
+ c = 4;
+ a = fun1(x,d) + fun2(fun1(fun2(w + 3 * 2) + 2 * c, 2u));
+ return 2;
+ }
+ """
+
+ mc = MicroC()
+ mc.parse_text(test_program_example)
+ print(mc.codegen.code) \ No newline at end of file
diff --git a/examples/pythonGrammarParser.py b/examples/pythonGrammarParser.py
new file mode 100644
index 0000000..f199917
--- /dev/null
+++ b/examples/pythonGrammarParser.py
@@ -0,0 +1,220 @@
+# pythonGrammarParser.py
+#
+# Copyright, 2006, by Paul McGuire
+#
+
+from pyparsing import *
+
+# should probably read this from the Grammar file provided with the Python source, but
+# this just skips that step and inlines the bnf text directly - this grammar was taken from
+# Python 2.4.1
+#
+grammar = r"""
+# Grammar for Python
+
+# Note: Changing the grammar specified in this file will most likely
+# require corresponding changes in the parser module
+# (../Modules/parsermodule.c). If you can't make the changes to
+# that module yourself, please co-ordinate the required changes
+# with someone who can; ask around on python-dev for help. Fred
+# Drake <fdrake@acm.org> will probably be listening there.
+
+# Commands for Kees Blom's railroad program
+#diagram:token NAME
+#diagram:token NUMBER
+#diagram:token STRING
+#diagram:token NEWLINE
+#diagram:token ENDMARKER
+#diagram:token INDENT
+#diagram:output\input python.bla
+#diagram:token DEDENT
+#diagram:output\textwidth 20.04cm\oddsidemargin 0.0cm\evensidemargin 0.0cm
+#diagram:rules
+
+# Start symbols for the grammar:
+# single_input is a single interactive statement;
+# file_input is a module or sequence of commands read from an input file;
+# eval_input is the input for the eval() and input() functions.
+# NB: compound_stmt in single_input is followed by extra NEWLINE!
+single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
+file_input: (NEWLINE | stmt)* ENDMARKER
+eval_input: testlist NEWLINE* ENDMARKER
+
+decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
+decorators: decorator+
+funcdef: [decorators] 'def' NAME parameters ':' suite
+parameters: '(' [varargslist] ')'
+varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+fpdef: NAME | '(' fplist ')'
+fplist: fpdef (',' fpdef)* [',']
+
+stmt: simple_stmt | compound_stmt
+simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
+small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
+expr_stmt: testlist (augassign testlist | ('=' testlist)*)
+augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
+# For normal assignments, additional restrictions enforced by the interpreter
+print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
+del_stmt: 'del' exprlist
+pass_stmt: 'pass'
+flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
+break_stmt: 'break'
+continue_stmt: 'continue'
+return_stmt: 'return' [testlist]
+yield_stmt: 'yield' testlist
+raise_stmt: 'raise' [test [',' test [',' test]]]
+import_stmt: import_name | import_from
+import_name: 'import' dotted_as_names
+import_from: 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names)
+import_as_name: NAME [NAME NAME]
+dotted_as_name: dotted_name [NAME NAME]
+import_as_names: import_as_name (',' import_as_name)* [',']
+dotted_as_names: dotted_as_name (',' dotted_as_name)*
+dotted_name: NAME ('.' NAME)*
+global_stmt: 'global' NAME (',' NAME)*
+exec_stmt: 'exec' expr ['in' test [',' test]]
+assert_stmt: 'assert' test [',' test]
+#35
+compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
+if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
+while_stmt: 'while' test ':' suite ['else' ':' suite]
+for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
+try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
+ ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
+# NB compile.c makes sure that the default except clause is last
+except_clause: 'except' [test [',' test]]
+suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
+
+test: and_test ('or' and_test)* | lambdef
+and_test: not_test ('and' not_test)*
+not_test: 'not' not_test | comparison
+comparison: expr (comp_op expr)*
+comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
+expr: xor_expr ('|' xor_expr)*
+xor_expr: and_expr ('^' and_expr)*
+and_expr: shift_expr ('&' shift_expr)*
+shift_expr: arith_expr (('<<'|'>>') arith_expr)*
+arith_expr: term (('+'|'-') term)*
+term: factor (('*'|'/'|'%'|'//') factor)*
+factor: ('+'|'-'|'~') factor | power
+power: atom trailer* ['**' factor]
+atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
+listmaker: test ( list_for | (',' test)* [','] )
+testlist_gexp: test ( gen_for | (',' test)* [','] )
+lambdef: 'lambda' [varargslist] ':' test
+trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
+subscriptlist: subscript (',' subscript)* [',']
+subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop]
+sliceop: ':' [test]
+exprlist: expr (',' expr)* [',']
+testlist: test (',' test)* [',']
+testlist_safe: test [(',' test)+ [',']]
+dictmaker: test ':' test (',' test ':' test)* [',']
+
+classdef: 'class' NAME ['(' testlist ')'] ':' suite
+
+arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
+argument: [test '='] test [gen_for] # Really [keyword '='] test
+
+list_iter: list_for | list_if
+list_for: 'for' exprlist 'in' testlist_safe [list_iter]
+list_if: 'if' test [list_iter]
+
+gen_iter: gen_for | gen_if
+gen_for: 'for' exprlist 'in' test [gen_iter]
+gen_if: 'if' test [gen_iter]
+
+testlist1: test (',' test)*
+
+# not used in grammar, but may appear in "node" passed from Parser to Compiler
+encoding_decl: NAME
+"""
+
+class SemanticGroup(object):
+ def __init__(self,contents):
+ self.contents = contents
+ while self.contents[-1].__class__ == self.__class__:
+ self.contents = self.contents[:-1] + self.contents[-1].contents
+
+ def __str__(self):
+ return "%s(%s)" % (self.label,
+ " ".join([isinstance(c,str) and c or str(c) for c in self.contents]) )
+
+class OrList(SemanticGroup):
+ label = "OR"
+ pass
+
+class AndList(SemanticGroup):
+ label = "AND"
+ pass
+
+class OptionalGroup(SemanticGroup):
+ label = "OPT"
+ pass
+
+class Atom(SemanticGroup):
+ def __init__(self,contents):
+ if len(contents) > 1:
+ self.rep = contents[1]
+ else:
+ self.rep = ""
+ if isinstance(contents,str):
+ self.contents = contents
+ else:
+ self.contents = contents[0]
+
+ def __str__(self):
+ return "%s%s" % (self.rep, self.contents)
+
+def makeGroupObject(cls):
+ def groupAction(s,l,t):
+ try:
+ return cls(t[0].asList())
+ except:
+ return cls(t)
+ return groupAction
+
+
+# bnf punctuation
+LPAREN = Suppress("(")
+RPAREN = Suppress(")")
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+COLON = Suppress(":")
+ALT_OP = Suppress("|")
+
+# bnf grammar
+ident = Word(alphanums+"_")
+bnfToken = Word(alphanums+"_") + ~FollowedBy(":")
+repSymbol = oneOf("* +")
+bnfExpr = Forward()
+optionalTerm = Group(LBRACK + bnfExpr + RBRACK).setParseAction(makeGroupObject(OptionalGroup))
+bnfTerm = ( (bnfToken | quotedString | optionalTerm | ( LPAREN + bnfExpr + RPAREN )) + Optional(repSymbol) ).setParseAction(makeGroupObject(Atom))
+andList = Group(bnfTerm + OneOrMore(bnfTerm)).setParseAction(makeGroupObject(AndList))
+bnfFactor = andList | bnfTerm
+orList = Group( bnfFactor + OneOrMore( ALT_OP + bnfFactor ) ).setParseAction(makeGroupObject(OrList))
+bnfExpr << ( orList | bnfFactor )
+bnfLine = ident + COLON + bnfExpr
+
+bnfComment = "#" + restOfLine
+
+# build return tokens as a dictionary
+bnf = Dict(OneOrMore(Group(bnfLine)))
+bnf.ignore(bnfComment)
+
+# bnf is defined, parse the grammar text
+bnfDefs = bnf.parseString(grammar)
+
+# correct answer is 78
+expected = 78
+assert len(bnfDefs) == expected, \
+ "Error, found %d BNF defns, expected %d" % (len(bnfDefs), expected)
+
+# list out defns in order they were parsed (to verify accuracy of parsing)
+for k,v in bnfDefs:
+ print(k,"=",v)
+print()
+
+# list out parsed grammar defns (demonstrates dictionary access to parsed tokens)
+for k in list(bnfDefs.keys()):
+ print(k,"=",bnfDefs[k])
diff --git a/examples/rangeCheck.py b/examples/rangeCheck.py
new file mode 100644
index 0000000..67cf267
--- /dev/null
+++ b/examples/rangeCheck.py
@@ -0,0 +1,62 @@
+# rangeCheck.py
+#
+# A sample program showing how parse actions can convert parsed
+# strings into a data type or object, and to validate the parsed value.
+#
+# Updated to use new addCondition method and expr() copy.
+#
+# Copyright 2011,2015 Paul T. McGuire
+#
+
+from pyparsing import Word, nums, Suppress, ParseException, empty, Optional
+from datetime import datetime
+
+def ranged_value(expr, minval=None, maxval=None):
+ # have to specify at least one range boundary
+ if minval is None and maxval is None:
+ raise ValueError("minval or maxval must be specified")
+
+ # set range testing function and error message depending on
+ # whether either or both min and max values are given
+ inRangeCondition = {
+ (True, False) : lambda s,l,t : t[0] <= maxval,
+ (False, True) : lambda s,l,t : minval <= t[0],
+ (False, False) : lambda s,l,t : minval <= t[0] <= maxval,
+ }[minval is None, maxval is None]
+ outOfRangeMessage = {
+ (True, False) : "value is greater than %s" % maxval,
+ (False, True) : "value is less than %s" % minval,
+ (False, False) : "value is not in the range (%s to %s)" % (minval,maxval),
+ }[minval is None, maxval is None]
+
+ return expr().addCondition(inRangeCondition, message=outOfRangeMessage)
+
+# define the expressions for a date of the form YYYY/MM/DD or YYYY/MM (assumes YYYY/MM/01)
+integer = Word(nums).setName("integer")
+integer.setParseAction(lambda t:int(t[0]))
+
+month = ranged_value(integer, 1, 12)
+day = ranged_value(integer, 1, 31)
+year = ranged_value(integer, 2000, None)
+
+SLASH = Suppress('/')
+dateExpr = year("year") + SLASH + month("month") + Optional(SLASH + day("day"))
+dateExpr.setName("date")
+
+# convert date fields to datetime (also validates dates as truly valid dates)
+dateExpr.setParseAction(lambda t: datetime(t.year, t.month, t.day or 1).date())
+
+# add range checking on dates
+mindate = datetime(2002,1,1).date()
+maxdate = datetime.now().date()
+dateExpr = ranged_value(dateExpr, mindate, maxdate)
+
+
+dateExpr.runTests("""
+ 2011/5/8
+ 2001/1/1
+ 2004/2/29
+ 2004/2
+ 1999/12/31""")
+
+
diff --git a/examples/readJson.py b/examples/readJson.py
new file mode 100644
index 0000000..deca53b
--- /dev/null
+++ b/examples/readJson.py
@@ -0,0 +1,1917 @@
+
+#~ url = "http://cmsdoc.cern.ch/cms/test/aprom/phedex/dev/gowri/datasvc/tbedi/requestDetails"
+#~ params = {'format':'json'}
+#~ import urllib
+#~ eparams = urllib.urlencode(params)
+#~ import urllib2
+#~ request = urllib2.Request(url,eparams)
+#~ response = urllib2.urlopen(request)
+#~ s = response.read()
+#~ response.close()
+
+#~ print s
+
+s = """
+{"phedex":{"request":[{"last_update":"1188037561", "numofapproved":"1",
+"id":"7425"}, {"last_update":"1188751826", "numofapproved":"1",
+"id":"8041"}, {"last_update":"1190116795", "numofapproved":"1",
+"id":"9281"}, {"last_update":"1190248781", "numofapproved":"1",
+"id":"9521"}, {"last_update":"1192615612", "numofapproved":"1",
+"id":"12821"}, {"last_update":"1192729887", "numofapproved":"1",
+"id":"13121"}, {"last_update":"1193152971", "numofapproved":"1",
+"id":"13501"}, {"last_update":"1194022054", "numofapproved":"1",
+"id":"14782"}, {"last_update":"1194429365", "numofapproved":"1",
+"id":"15081"}, {"last_update":"1195069848", "numofapproved":"1",
+"id":"16661"}, {"last_update":"1178403225", "numofapproved":"1",
+"id":"1281"}, {"last_update":"1179239056", "numofapproved":"1",
+"id":"1387"}, {"last_update":"1179842205", "numofapproved":"1",
+"id":"1665"}, {"last_update":"1179842040", "numofapproved":"1",
+"id":"1661"}, {"last_update":"1179935333", "numofapproved":"1",
+"id":"1741"}, {"last_update":"1183151195", "numofapproved":"1",
+"id":"3841"}, {"last_update":"1187031531", "numofapproved":"1",
+"id":"6601"}, {"last_update":"1188820478", "numofapproved":"1",
+"id":"8121"}, {"last_update":"1190652719", "numofapproved":"1",
+"id":"9983"}, {"last_update":"1192628950", "numofapproved":"1",
+"id":"12841"}, {"last_update":"1193075426", "numofapproved":"1",
+"id":"13341"}, {"last_update":"1194214609", "numofapproved":"1",
+"id":"14882"}, {"last_update":"1194387864", "numofapproved":"1",
+"id":"15062"}, {"last_update":"1195134504", "numofapproved":"1",
+"id":"16741"}, {"last_update":"1182431453", "numofapproved":"1",
+"id":"3421"}, {"last_update":"1183448188", "numofapproved":"1",
+"id":"4061"}, {"last_update":"1184588081", "numofapproved":"1",
+"id":"4908"}, {"last_update":"1184681258", "numofapproved":"1",
+"id":"4913"}, {"last_update":"1188039048", "numofapproved":"1",
+"id":"7426"}, {"last_update":"1192699041", "numofapproved":"1",
+"id":"12982"}, {"last_update":"1193219685", "numofapproved":"1",
+"id":"13529"}, {"last_update":"1193401408", "numofapproved":"1",
+"id":"14081"}, {"last_update":"1194454724", "numofapproved":"1",
+"id":"15201"}, {"last_update":"1194937690", "numofapproved":"1",
+"id":"16044"}, {"last_update":"1194947125", "numofapproved":"1",
+"id":"16103"}, {"last_update":"1195134890", "numofapproved":"1",
+"id":"16761"}, {"last_update":"1195486898", "numofapproved":"1",
+"id":"17301"}, {"last_update":"1195497774", "numofapproved":"1",
+"id":"17341"}, {"last_update":"1184744080", "numofapproved":"1",
+"id":"4941"}, {"last_update":"1186558911", "numofapproved":"1",
+"id":"6321"}, {"last_update":"1189524520", "numofapproved":"1",
+"id":"8802"}, {"last_update":"1192683178", "numofapproved":"1",
+"id":"12921"}, {"last_update":"1193260655", "numofapproved":"1",
+"id":"13530"}, {"last_update":"1194280038", "numofapproved":"1",
+"id":"15002"}, {"last_update":"1182077478", "numofapproved":"1",
+"id":"3162"}, {"last_update":"1183386650", "numofapproved":"1",
+"id":"3961"}, {"last_update":"1192063369", "numofapproved":"1",
+"id":"12182"}, {"last_update":"1181931262", "numofapproved":"1",
+"id":"3101"}, {"last_update":"1178648271", "numofapproved":"1",
+"id":"1308"}, {"last_update":"1179239923", "numofapproved":"1",
+"id":"1405"}, {"last_update":"1184370745", "numofapproved":"1",
+"id":"4861"}, {"last_update":"1185280568", "numofapproved":"1",
+"id":"5302"}, {"last_update":"1187875115", "numofapproved":"1",
+"id":"7344"}, {"last_update":"1189140441", "numofapproved":"1",
+"id":"8541"}, {"last_update":"1189180903", "numofapproved":"1",
+"id":"8661"}, {"last_update":"1189767643", "numofapproved":"1",
+"id":"9001"}, {"last_update":"1190726167", "numofapproved":"1",
+"id":"10101"}, {"last_update":"1190972990", "numofapproved":"1",
+"id":"10661"}, {"last_update":"1190990720", "numofapproved":"1",
+"id":"10712"}, {"last_update":"1192004838", "numofapproved":"1",
+"id":"12021"}, {"last_update":"1192612211", "numofapproved":"1",
+"id":"12803"}, {"last_update":"1194441407", "numofapproved":"1",
+"id":"15103"}, {"last_update":"1194792356", "numofapproved":"1",
+"id":"15681"}, {"last_update":"1194860650", "numofapproved":"1",
+"id":"15801"}, {"last_update":"1194877395", "numofapproved":"1",
+"id":"15881"}, {"last_update":"1194950552", "numofapproved":"1",
+"id":"16124"}, {"last_update":"1194992714", "numofapproved":"1",
+"id":"16421"}, {"last_update":"1195054500", "numofapproved":"1",
+"id":"16581"}, {"last_update":"1195228524", "numofapproved":"1",
+"id":"17001"}, {"last_update":"1195469382", "numofapproved":"1",
+"id":"17161"}, {"last_update":"1178035947", "numofapproved":"1",
+"id":"1202"}, {"last_update":"1178869668", "numofapproved":"1",
+"id":"1356"}, {"last_update":"1183563268", "numofapproved":"1",
+"id":"4201"}, {"last_update":"1185314677", "numofapproved":"1",
+"id":"5361"}, {"last_update":"1188467567", "numofapproved":"1",
+"id":"7781"}, {"last_update":"1190011821", "numofapproved":"1",
+"id":"9202"}, {"last_update":"1190206214", "numofapproved":"1",
+"id":"9481"}, {"last_update":"1190973037", "numofapproved":"1",
+"id":"10663"}, {"last_update":"1190819127", "numofapproved":"1",
+"id":"10342"}, {"last_update":"1192154959", "numofapproved":"1",
+"id":"12381"}, {"last_update":"1192634509", "numofapproved":"1",
+"id":"12862"}, {"last_update":"1194004677", "numofapproved":"1",
+"id":"14722"}, {"last_update":"1195548191", "numofapproved":"1",
+"id":"17501"}, {"last_update":"1195548953", "numofapproved":"1",
+"id":"17502"}, {"last_update":"1195559809", "numofapproved":"1",
+"id":"17541"}, {"last_update":"1177589103", "numofapproved":"1",
+"id":"1044"}, {"last_update":"1183416879", "numofapproved":"1",
+"id":"4041"}, {"last_update":"1186646977", "numofapproved":"1",
+"id":"6342"}, {"last_update":"1189656586", "numofapproved":"1",
+"id":"8902"}, {"last_update":"1190150645", "numofapproved":"1",
+"id":"9421"}, {"last_update":"1190409040", "numofapproved":"1",
+"id":"9741"}, {"last_update":"1190973011", "numofapproved":"1",
+"id":"10662"}, {"last_update":"1190993896", "numofapproved":"1",
+"id":"10761"}, {"last_update":"1193973610", "numofapproved":"1",
+"id":"14661"}, {"last_update":"1193973848", "numofapproved":"1",
+"id":"14664"}, {"last_update":"1194539978", "numofapproved":"1",
+"id":"15381"}, {"last_update":"1194947356", "numofapproved":"1",
+"id":"16105"}, {"last_update":"1195399589", "numofapproved":"1",
+"id":"17101"}, {"last_update":"1195464953", "numofapproved":"1",
+"id":"17141"}, {"last_update":"1171962221", "numofapproved":"1",
+"id":"109"}, {"last_update":"1173113812", "numofapproved":"1",
+"id":"247"}, {"last_update":"1173975435", "numofapproved":"1",
+"id":"343"}, {"last_update":"1174050971", "numofapproved":"1",
+"id":"353"}, {"last_update":"1174301484", "numofapproved":"1",
+"id":"393"}, {"last_update":"1172565853", "numofapproved":"1",
+"id":"208"}, {"last_update":"1172593328", "numofapproved":"1",
+"id":"215"}, {"last_update":"1175267391", "numofapproved":"1",
+"id":"565"}, {"last_update":"1171379845", "numofapproved":"1",
+"id":"25"}, {"last_update":"1171477466", "numofapproved":"1",
+"id":"53"}, {"last_update":"1171799296", "numofapproved":"1",
+"id":"77"}, {"last_update":"1172671474", "numofapproved":"1",
+"id":"223"}, {"last_update":"1174301354", "numofapproved":"1",
+"id":"388"}, {"last_update":"1174899552", "numofapproved":"1",
+"id":"511"}, {"last_update":"1174899458", "numofapproved":"1",
+"id":"505"}, {"last_update":"1175502936", "numofapproved":"1",
+"id":"604"}, {"last_update":"1175613825", "numofapproved":"1",
+"id":"665"}, {"last_update":"1175776232", "numofapproved":"1",
+"id":"673"}, {"last_update":"1171621302", "numofapproved":"1",
+"id":"68"}, {"last_update":"1171904738", "numofapproved":"1",
+"id":"98"}, {"last_update":"1171968012", "numofapproved":"1",
+"id":"115"}, {"last_update":"1172145037", "numofapproved":"1",
+"id":"168"}, {"last_update":"1172246599", "numofapproved":"1",
+"id":"185"}, {"last_update":"1173886280", "numofapproved":"1",
+"id":"318"}, {"last_update":"1174562010", "numofapproved":"1",
+"id":"423"}, {"last_update":"1176308974", "numofapproved":"1",
+"id":"884"}, {"last_update":"1176482150", "numofapproved":"1",
+"id":"943"}, {"last_update":"1176702424", "numofapproved":"1",
+"id":"1001"}, {"last_update":"1176748776", "numofapproved":"1",
+"id":"984"}, {"last_update":"1172669745", "numofapproved":"1",
+"id":"222"}, {"last_update":"1174899538", "numofapproved":"1",
+"id":"510"}, {"last_update":"1174899143", "numofapproved":"1",
+"id":"493"}, {"last_update":"1174899043", "numofapproved":"1",
+"id":"488"}, {"last_update":"1175711780", "numofapproved":"1",
+"id":"667"}, {"last_update":"1175712851", "numofapproved":"1",
+"id":"705"}, {"last_update":"1176296548", "numofapproved":"1",
+"id":"841"}, {"last_update":"1175862269", "numofapproved":"1",
+"id":"781"}, {"last_update":"1171483107", "numofapproved":"1",
+"id":"54"}, {"last_update":"1171645737", "numofapproved":"1",
+"id":"71"}, {"last_update":"1172253423", "numofapproved":"1",
+"id":"188"}, {"last_update":"1173888726", "numofapproved":"1",
+"id":"321"}, {"last_update":"1173975649", "numofapproved":"1",
+"id":"346"}, {"last_update":"1174299379", "numofapproved":"1",
+"id":"363"}, {"last_update":"1174301359", "numofapproved":"1",
+"id":"389"}, {"last_update":"1174301073", "numofapproved":"1",
+"id":"379"}, {"last_update":"1174300650", "numofapproved":"1",
+"id":"371"}, {"last_update":"1171485069", "numofapproved":"1",
+"id":"55"}, {"last_update":"1171799178", "numofapproved":"1",
+"id":"73"}, {"last_update":"1171896809", "numofapproved":"1",
+"id":"95"}, {"last_update":"1172672959", "numofapproved":"1",
+"id":"224"}, {"last_update":"1172693619", "numofapproved":"1",
+"id":"230"}, {"last_update":"1173207656", "numofapproved":"1",
+"id":"253"}, {"last_update":"1174059533", "numofapproved":"1",
+"id":"356"}, {"last_update":"1174300538", "numofapproved":"1",
+"id":"368"}, {"last_update":"1176137457", "numofapproved":"1",
+"id":"807"}, {"last_update":"1173728124", "numofapproved":"1",
+"id":"305"}, {"last_update":"1172507633", "numofapproved":"1",
+"id":"198"}, {"last_update":"1174301173", "numofapproved":"1",
+"id":"383"}, {"last_update":"1174899102", "numofapproved":"1",
+"id":"491"}, {"last_update":"1174301362", "numofapproved":"1",
+"id":"390"}, {"last_update":"1175254095", "numofapproved":"1",
+"id":"561"}, {"last_update":"1174037250", "numofapproved":"1",
+"id":"348"}, {"last_update":"1175865081", "numofapproved":"1",
+"id":"782"}, {"last_update":"1177591942", "numofapproved":"1",
+"id":"1046"}, {"last_update":"1177989191", "numofapproved":"1",
+"id":"1201"}, {"last_update":"1178743279", "numofapproved":"1",
+"id":"1323"}, {"last_update":"1178876587", "numofapproved":"1",
+"id":"1357"}, {"last_update":"1179239620", "numofapproved":"1",
+"id":"1401"}, {"last_update":"1180725458", "numofapproved":"1",
+"id":"2141"}, {"last_update":"1181205209", "numofapproved":"1",
+"id":"2421"}, {"last_update":"1181575615", "numofapproved":"1",
+"id":"2761"}, {"last_update":"1182184775", "numofapproved":"1",
+"id":"3201"}, {"last_update":"1182963728", "numofapproved":"1",
+"id":"3661"}, {"last_update":"1178727735", "numofapproved":"1",
+"id":"1349"}, {"last_update":"1182497720", "numofapproved":"1",
+"id":"3441"}, {"last_update":"1184381847", "numofapproved":"1",
+"id":"4881"}, {"last_update":"1184568423", "numofapproved":"1",
+"id":"4904"}, {"last_update":"1185364813", "numofapproved":"1",
+"id":"5421"}, {"last_update":"1188043594", "numofapproved":"1",
+"id":"7441"}, {"last_update":"1188675287", "numofapproved":"1",
+"id":"7981"}, {"last_update":"1188741594", "numofapproved":"1",
+"id":"8021"}, {"last_update":"1189144234", "numofapproved":"1",
+"id":"8561"}, {"last_update":"1189170150", "numofapproved":"1",
+"id":"8641"}, {"last_update":"1189501508", "numofapproved":"1",
+"id":"8761"}, {"last_update":"1189811918", "numofapproved":"1",
+"id":"9041"}, {"last_update":"1189812095", "numofapproved":"1",
+"id":"9042"}, {"last_update":"1177591716", "numofapproved":"1",
+"id":"1045"}, {"last_update":"1178040595", "numofapproved":"1",
+"id":"1203"}, {"last_update":"1182437936", "numofapproved":"1",
+"id":"3423"}, {"last_update":"1190480042", "numofapproved":"1",
+"id":"9781"}, {"last_update":"1190821494", "numofapproved":"1",
+"id":"10361"}, {"last_update":"1190959672", "numofapproved":"1",
+"id":"10602"}, {"last_update":"1190964023", "numofapproved":"1",
+"id":"10621"}, {"last_update":"1190991147", "numofapproved":"1",
+"id":"10721"}, {"last_update":"1190992132", "numofapproved":"1",
+"id":"10741"}, {"last_update":"1190990410", "numofapproved":"1",
+"id":"10706"}, {"last_update":"1181667132", "numofapproved":"1",
+"id":"2861"}, {"last_update":"1183746653", "numofapproved":"1",
+"id":"4321"}, {"last_update":"1191184539", "numofapproved":"1",
+"id":"10861"}, {"last_update":"1191490599", "numofapproved":"1",
+"id":"11261"}, {"last_update":"1191834884", "numofapproved":"1",
+"id":"11801"}, {"last_update":"1191834899", "numofapproved":"1",
+"id":"11802"}, {"last_update":"1191940759", "numofapproved":"1",
+"id":"11961"}, {"last_update":"1179971250", "numofapproved":"1",
+"id":"1643"}, {"last_update":"1181663618", "numofapproved":"1",
+"id":"2841"}, {"last_update":"1181932994", "numofapproved":"1",
+"id":"3102"}, {"last_update":"1182420732", "numofapproved":"1",
+"id":"3382"}, {"last_update":"1192118127", "numofapproved":"1",
+"id":"12281"}, {"last_update":"1192222036", "numofapproved":"1",
+"id":"12481"}, {"last_update":"1192155814", "numofapproved":"1",
+"id":"12364"}, {"last_update":"1192563924", "numofapproved":"1",
+"id":"12761"}, {"last_update":"1193124530", "numofapproved":"1",
+"id":"13441"}, {"last_update":"1193345545", "numofapproved":"1",
+"id":"13921"}, {"last_update":"1193396927", "numofapproved":"1",
+"id":"14041"}, {"last_update":"1180015411", "numofapproved":"1",
+"id":"1651"}, {"last_update":"1180107815", "numofapproved":"1",
+"id":"1658"}, {"last_update":"1186050394", "numofapproved":"1",
+"id":"6021"}, {"last_update":"1188519417", "numofapproved":"1",
+"id":"7841"}, {"last_update":"1193222002", "numofapproved":"1",
+"id":"13541"}, {"last_update":"1193965081", "numofapproved":"1",
+"id":"14641"}, {"last_update":"1193660582", "numofapproved":"1",
+"id":"14381"}, {"last_update":"1194088240", "numofapproved":"1",
+"id":"14821"}, {"last_update":"1194110475", "numofapproved":"1",
+"id":"14841"}, {"last_update":"1194246367", "numofapproved":"1",
+"id":"14902"}, {"last_update":"1194464283", "numofapproved":"1",
+"id":"15221"}, {"last_update":"1194622250", "numofapproved":"1",
+"id":"15461"}, {"last_update":"1194635632", "numofapproved":"1",
+"id":"15601"}, {"last_update":"1179147506", "numofapproved":"1",
+"id":"1382"}, {"last_update":"1179240025", "numofapproved":"1",
+"id":"1388"}, {"last_update":"1179748089", "numofapproved":"1",
+"id":"1561"}, {"last_update":"1179868997", "numofapproved":"1",
+"id":"1681"}, {"last_update":"1183019667", "numofapproved":"1",
+"id":"3702"}, {"last_update":"1184531598", "numofapproved":"1",
+"id":"4902"}, {"last_update":"1187294472", "numofapproved":"1",
+"id":"6841"}, {"last_update":"1189521494", "numofapproved":"1",
+"id":"8801"}, {"last_update":"1192726867", "numofapproved":"1",
+"id":"13081"}, {"last_update":"1193049178", "numofapproved":"1",
+"id":"13301"}, {"last_update":"1193387050", "numofapproved":"1",
+"id":"13947"}, {"last_update":"1194277280", "numofapproved":"1",
+"id":"14981"}, {"last_update":"1179150720", "numofapproved":"1",
+"id":"1383"}, {"last_update":"1179842104", "numofapproved":"1",
+"id":"1663"}, {"last_update":"1183766887", "numofapproved":"1",
+"id":"4341"}, {"last_update":"1185542132", "numofapproved":"1",
+"id":"5682"}, {"last_update":"1186737114", "numofapproved":"1",
+"id":"6382"}, {"last_update":"1187015679", "numofapproved":"1",
+"id":"6521"}, {"last_update":"1190326980", "numofapproved":"1",
+"id":"9641"}, {"last_update":"1191595711", "numofapproved":"1",
+"id":"11622"}, {"last_update":"1192106288", "numofapproved":"1",
+"id":"12221"}, {"last_update":"1192454432", "numofapproved":"1",
+"id":"12622"}, {"last_update":"1194339640", "numofapproved":"1",
+"id":"15021"}, {"last_update":"1177758209", "numofapproved":"1",
+"id":"1181"}, {"last_update":"1179842392", "numofapproved":"1",
+"id":"1669"}, {"last_update":"1179872870", "numofapproved":"1",
+"id":"1682"}, {"last_update":"1181233887", "numofapproved":"1",
+"id":"2541"}, {"last_update":"1182349297", "numofapproved":"1",
+"id":"3342"}, {"last_update":"1182375421", "numofapproved":"1",
+"id":"3350"}, {"last_update":"1183485259", "numofapproved":"1",
+"id":"4081"}, {"last_update":"1184319308", "numofapproved":"1",
+"id":"4821"}, {"last_update":"1187626648", "numofapproved":"1",
+"id":"6981"}, {"last_update":"1193153090", "numofapproved":"1",
+"id":"13502"}, {"last_update":"1194366368", "numofapproved":"1",
+"id":"15041"}, {"last_update":"1194617018", "numofapproved":"1",
+"id":"15421"}, {"last_update":"1195230640", "numofapproved":"1",
+"id":"17021"}, {"last_update":"1179908379", "numofapproved":"1",
+"id":"1701"}, {"last_update":"1188049228", "numofapproved":"1",
+"id":"7427"}, {"last_update":"1177581166", "numofapproved":"1",
+"id":"1061"}, {"last_update":"1187160654", "numofapproved":"1",
+"id":"6661"}, {"last_update":"1192983992", "numofapproved":"1",
+"id":"13222"}, {"last_update":"1193388978", "numofapproved":"1",
+"id":"13954"}, {"last_update":"1194617112", "numofapproved":"1",
+"id":"15422"}, {"last_update":"1195398876", "numofapproved":"1",
+"id":"17081"}, {"last_update":"1184262511", "numofapproved":"1",
+"id":"4801"}, {"last_update":"1192112284", "numofapproved":"1",
+"id":"12241"}, {"last_update":"1193082767", "numofapproved":"1",
+"id":"13401"}, {"last_update":"1193179243", "numofapproved":"1",
+"id":"13526"}, {"last_update":"1178142915", "numofapproved":"1",
+"id":"1206"}, {"last_update":"1178648333", "numofapproved":"1",
+"id":"1310"}, {"last_update":"1179279626", "numofapproved":"1",
+"id":"1391"}, {"last_update":"1182882268", "numofapproved":"1",
+"id":"3584"}, {"last_update":"1183128448", "numofapproved":"1",
+"id":"3823"}, {"last_update":"1183377394", "numofapproved":"1",
+"id":"3941"}, {"last_update":"1188582729", "numofapproved":"1",
+"id":"7902"}, {"last_update":"1189695063", "numofapproved":"1",
+"id":"8962"}, {"last_update":"1192001165", "numofapproved":"1",
+"id":"12001"}, {"last_update":"1192155647", "numofapproved":"1",
+"id":"12363"}, {"last_update":"1193418304", "numofapproved":"1",
+"id":"14202"}, {"last_update":"1193632105", "numofapproved":"1",
+"id":"14341"}, {"last_update":"1194011106", "numofapproved":"1",
+"id":"14741"}, {"last_update":"1194818628", "numofapproved":"1",
+"id":"15701"}, {"last_update":"1194875153", "numofapproved":"1",
+"id":"15861"}, {"last_update":"1194727029", "numofapproved":"1",
+"id":"15665"}, {"last_update":"1194950210", "numofapproved":"1",
+"id":"16122"}, {"last_update":"1194976681", "numofapproved":"1",
+"id":"16241"}, {"last_update":"1194979189", "numofapproved":"1",
+"id":"16281"}, {"last_update":"1194962224", "numofapproved":"1",
+"id":"16201"}, {"last_update":"1195046085", "numofapproved":"1",
+"id":"16481"}, {"last_update":"1195399919", "numofapproved":"1",
+"id":"17102"}, {"last_update":"1183113736", "numofapproved":"1",
+"id":"3782"}, {"last_update":"1183114202", "numofapproved":"1",
+"id":"3783"}, {"last_update":"1189017904", "numofapproved":"1",
+"id":"8441"}, {"last_update":"1189694944", "numofapproved":"1",
+"id":"8961"}, {"last_update":"1190766842", "numofapproved":"1",
+"id":"10181"}, {"last_update":"1190973066", "numofapproved":"1",
+"id":"10665"}, {"last_update":"1190990264", "numofapproved":"1",
+"id":"10702"}, {"last_update":"1193043204", "numofapproved":"1",
+"id":"13281"}, {"last_update":"1194627082", "numofapproved":"1",
+"id":"15561"}, {"last_update":"1194894589", "numofapproved":"1",
+"id":"15941"}, {"last_update":"1195485915", "numofapproved":"1",
+"id":"17281"}, {"last_update":"1195485806", "numofapproved":"1",
+"id":"17261"}, {"last_update":"1195498836", "numofapproved":"1",
+"id":"17361"}, {"last_update":"1195514951", "numofapproved":"1",
+"id":"17421"}, {"last_update":"1183722351", "numofapproved":"1",
+"id":"4261"}, {"last_update":"1184218083", "numofapproved":"1",
+"id":"4682"}, {"last_update":"1186848968", "numofapproved":"1",
+"id":"6441"}, {"last_update":"1187023846", "numofapproved":"1",
+"id":"6561"}, {"last_update":"1187870812", "numofapproved":"1",
+"id":"7342"}, {"last_update":"1188657717", "numofapproved":"1",
+"id":"7961"}, {"last_update":"1190541897", "numofapproved":"1",
+"id":"9841"}, {"last_update":"1190629135", "numofapproved":"1",
+"id":"9922"}, {"last_update":"1191226530", "numofapproved":"1",
+"id":"10922"}, {"last_update":"1191505214", "numofapproved":"1",
+"id":"11321"}, {"last_update":"1192304524", "numofapproved":"1",
+"id":"12541"}, {"last_update":"1193948730", "numofapproved":"1",
+"id":"14601"}, {"last_update":"1194073812", "numofapproved":"1",
+"id":"14801"}, {"last_update":"1194387224", "numofapproved":"1",
+"id":"14892"}, {"last_update":"1194464384", "numofapproved":"1",
+"id":"15223"}, {"last_update":"1194726799", "numofapproved":"1",
+"id":"15663"}, {"last_update":"1171969969", "numofapproved":"1",
+"id":"119"}, {"last_update":"1174444717", "numofapproved":"1",
+"id":"405"}, {"last_update":"1174899431", "numofapproved":"1",
+"id":"504"}, {"last_update":"1174899204", "numofapproved":"1",
+"id":"496"}, {"last_update":"1174925591", "numofapproved":"1",
+"id":"530"}, {"last_update":"1176902523", "numofapproved":"1",
+"id":"1008"}, {"last_update":"1172765523", "numofapproved":"1",
+"id":"232"}, {"last_update":"1173315950", "numofapproved":"1",
+"id":"260"}, {"last_update":"1174899524", "numofapproved":"1",
+"id":"509"}, {"last_update":"1174300691", "numofapproved":"1",
+"id":"373"}, {"last_update":"1175502917", "numofapproved":"1",
+"id":"625"}, {"last_update":"1175601578", "numofapproved":"1",
+"id":"662"}, {"last_update":"1175608600", "numofapproved":"1",
+"id":"684"}, {"last_update":"1176755309", "numofapproved":"1",
+"id":"985"}, {"last_update":"1171386411", "numofapproved":"1",
+"id":"45"}, {"last_update":"1171800366", "numofapproved":"1",
+"id":"81"}, {"last_update":"1172847417", "numofapproved":"1",
+"id":"241"}, {"last_update":"1174734904", "numofapproved":"1",
+"id":"462"}, {"last_update":"1174735234", "numofapproved":"1",
+"id":"469"}, {"last_update":"1174735074", "numofapproved":"1",
+"id":"465"}, {"last_update":"1175267646", "numofapproved":"1",
+"id":"566"}, {"last_update":"1176331857", "numofapproved":"1",
+"id":"888"}, {"last_update":"1176387926", "numofapproved":"1",
+"id":"890"}, {"last_update":"1176458401", "numofapproved":"1",
+"id":"904"}, {"last_update":"1173088626", "numofapproved":"1",
+"id":"244"}, {"last_update":"1173109009", "numofapproved":"1",
+"id":"246"}, {"last_update":"1173671557", "numofapproved":"1",
+"id":"284"}, {"last_update":"1174927658", "numofapproved":"1",
+"id":"532"}, {"last_update":"1175592399", "numofapproved":"1",
+"id":"661"}, {"last_update":"1176480402", "numofapproved":"1",
+"id":"941"}, {"last_update":"1176561564", "numofapproved":"1",
+"id":"945"}, {"last_update":"1172218707", "numofapproved":"1",
+"id":"180"}, {"last_update":"1172771475", "numofapproved":"1",
+"id":"233"}, {"last_update":"1173267863", "numofapproved":"1",
+"id":"257"}, {"last_update":"1176493803", "numofapproved":"1",
+"id":"963"}, {"last_update":"1171449646", "numofapproved":"1",
+"id":"49"}, {"last_update":"1171471549", "numofapproved":"1",
+"id":"51"}, {"last_update":"1171800487", "numofapproved":"1",
+"id":"88"}, {"last_update":"1171800431", "numofapproved":"1",
+"id":"85"}, {"last_update":"1175502995", "numofapproved":"1",
+"id":"627"}, {"last_update":"1175712797", "numofapproved":"1",
+"id":"704"}, {"last_update":"1171122384", "numofapproved":"1",
+"id":"3"}, {"last_update":"1171380774", "numofapproved":"1", "id":"26"},
+{"last_update":"1171904757", "numofapproved":"1", "id":"99"},
+{"last_update":"1174300705", "numofapproved":"1", "id":"374"},
+{"last_update":"1174924802", "numofapproved":"1", "id":"526"},
+{"last_update":"1175935441", "numofapproved":"1", "id":"801"},
+{"last_update":"1175610915", "numofapproved":"1", "id":"686"},
+{"last_update":"1171977081", "numofapproved":"1", "id":"125"},
+{"last_update":"1173165324", "numofapproved":"1", "id":"249"},
+{"last_update":"1173888337", "numofapproved":"1", "id":"319"},
+{"last_update":"1173889473", "numofapproved":"1", "id":"331"},
+{"last_update":"1172180902", "numofapproved":"1", "id":"175"},
+{"last_update":"1174058063", "numofapproved":"1", "id":"354"},
+{"last_update":"1174300674", "numofapproved":"1", "id":"372"},
+{"last_update":"1171886332", "numofapproved":"1", "id":"93"},
+{"last_update":"1176731068", "numofapproved":"1", "id":"1003"},
+{"last_update":"1178645848", "numofapproved":"1", "id":"1306"},
+{"last_update":"1178706683", "numofapproved":"1", "id":"1321"},
+{"last_update":"1179240076", "numofapproved":"1", "id":"1406"},
+{"last_update":"1180380411", "numofapproved":"1", "id":"1862"},
+{"last_update":"1180683561", "numofapproved":"1", "id":"2041"},
+{"last_update":"1181229731", "numofapproved":"1", "id":"2521"},
+{"last_update":"1182210982", "numofapproved":"1", "id":"3203"},
+{"last_update":"1182421105", "numofapproved":"1", "id":"3401"},
+{"last_update":"1182199404", "numofapproved":"1", "id":"3202"},
+{"last_update":"1182258596", "numofapproved":"1", "id":"3241"},
+{"last_update":"1183556842", "numofapproved":"1", "id":"4161"},
+{"last_update":"1184146825", "numofapproved":"1", "id":"4601"},
+{"last_update":"1184771229", "numofapproved":"1", "id":"4981"},
+{"last_update":"1185355415", "numofapproved":"1", "id":"5401"},
+{"last_update":"1185377130", "numofapproved":"1", "id":"5481"},
+{"last_update":"1185483994", "numofapproved":"1", "id":"5621"},
+{"last_update":"1186496707", "numofapproved":"1", "id":"6261"},
+{"last_update":"1187704347", "numofapproved":"1", "id":"7001"},
+{"last_update":"1187758331", "numofapproved":"1", "id":"7101"},
+{"last_update":"1187765716", "numofapproved":"1", "id":"7161"},
+{"last_update":"1188284185", "numofapproved":"1", "id":"7581"},
+{"last_update":"1188463286", "numofapproved":"1", "id":"7761"},
+{"last_update":"1189012058", "numofapproved":"1", "id":"8421"},
+{"last_update":"1189814265", "numofapproved":"1", "id":"9061"},
+{"last_update":"1180880867", "numofapproved":"1", "id":"2161"},
+{"last_update":"1181218244", "numofapproved":"1", "id":"2463"},
+{"last_update":"1183515137", "numofapproved":"1", "id":"4141"},
+{"last_update":"1183515248", "numofapproved":"1", "id":"4142"},
+{"last_update":"1188311100", "numofapproved":"1", "id":"7641"},
+{"last_update":"1190011501", "numofapproved":"1", "id":"9201"},
+{"last_update":"1190012299", "numofapproved":"1", "id":"9221"},
+{"last_update":"1190149196", "numofapproved":"1", "id":"9382"},
+{"last_update":"1190202046", "numofapproved":"1", "id":"9461"},
+{"last_update":"1190626607", "numofapproved":"1", "id":"9881"},
+{"last_update":"1190632230", "numofapproved":"1", "id":"9941"},
+{"last_update":"1190660429", "numofapproved":"1", "id":"10002"},
+{"last_update":"1190819102", "numofapproved":"1", "id":"10341"},
+{"last_update":"1190824319", "numofapproved":"1", "id":"10382"},
+{"last_update":"1190825791", "numofapproved":"1", "id":"10402"},
+{"last_update":"1190847397", "numofapproved":"1", "id":"10421"},
+{"last_update":"1190876679", "numofapproved":"1", "id":"10441"},
+{"last_update":"1190918894", "numofapproved":"1", "id":"10541"},
+{"last_update":"1190924961", "numofapproved":"1", "id":"10582"},
+{"last_update":"1190991179", "numofapproved":"1", "id":"10723"},
+{"last_update":"1190663960", "numofapproved":"1", "id":"10042"},
+{"last_update":"1191222270", "numofapproved":"1", "id":"10881"},
+{"last_update":"1178869580", "numofapproved":"1", "id":"1355"},
+{"last_update":"1180054057", "numofapproved":"1", "id":"1655"},
+{"last_update":"1180428815", "numofapproved":"1", "id":"1881"},
+{"last_update":"1183369278", "numofapproved":"1", "id":"3901"},
+{"last_update":"1185018445", "numofapproved":"1", "id":"5163"},
+{"last_update":"1185201628", "numofapproved":"1", "id":"5221"},
+{"last_update":"1189345395", "numofapproved":"1", "id":"8741"},
+{"last_update":"1191406141", "numofapproved":"1", "id":"11041"},
+{"last_update":"1191410914", "numofapproved":"1", "id":"11067"},
+{"last_update":"1191558362", "numofapproved":"1", "id":"11461"},
+{"last_update":"1191584539", "numofapproved":"1", "id":"11541"},
+{"last_update":"1191584660", "numofapproved":"1", "id":"11542"},
+{"last_update":"1191599491", "numofapproved":"1", "id":"11661"},
+{"last_update":"1191813292", "numofapproved":"1", "id":"11781"},
+{"last_update":"1191856553", "numofapproved":"1", "id":"11842"},
+{"last_update":"1191861142", "numofapproved":"1", "id":"11862"},
+{"last_update":"1177509523", "numofapproved":"1", "id":"1041"},
+{"last_update":"1190627650", "numofapproved":"1", "id":"9901"},
+{"last_update":"1192034749", "numofapproved":"1", "id":"12141"},
+{"last_update":"1192165574", "numofapproved":"1", "id":"12401"},
+{"last_update":"1192431750", "numofapproved":"1", "id":"12581"},
+{"last_update":"1192536591", "numofapproved":"1", "id":"12721"},
+{"last_update":"1193035428", "numofapproved":"1", "id":"13261"},
+{"last_update":"1193239266", "numofapproved":"1", "id":"13581"},
+{"last_update":"1193314455", "numofapproved":"1", "id":"13841"},
+{"last_update":"1193333733", "numofapproved":"1", "id":"13901"},
+{"last_update":"1193389116", "numofapproved":"1", "id":"14001"},
+{"last_update":"1184970339", "numofapproved":"1", "id":"5121"},
+{"last_update":"1190892760", "numofapproved":"1", "id":"10481"},
+{"last_update":"1192823398", "numofapproved":"1", "id":"13182"},
+{"last_update":"1193911671", "numofapproved":"1", "id":"14541"},
+{"last_update":"1193916761", "numofapproved":"1", "id":"14543"},
+{"last_update":"1194212665", "numofapproved":"1", "id":"14881"},
+{"last_update":"1194248205", "numofapproved":"1", "id":"14921"},
+{"last_update":"1194513600", "numofapproved":"1", "id":"15110"},
+{"last_update":"1194539704", "numofapproved":"1", "id":"15361"},
+{"last_update":"1194569643", "numofapproved":"1", "id":"15112"},
+{"last_update":"1194619794", "numofapproved":"1", "id":"15441"},
+{"last_update":"1194623621", "numofapproved":"1", "id":"15501"},
+{"last_update":"1194624477", "numofapproved":"1", "id":"15521"},
+{"last_update":"1194635685", "numofapproved":"1", "id":"15602"},
+{"last_update":"1179311539", "numofapproved":"1", "id":"1393"},
+{"last_update":"1179672561", "numofapproved":"1", "id":"1521"},
+{"last_update":"1180712413", "numofapproved":"1", "id":"2101"},
+{"last_update":"1181646264", "numofapproved":"1", "id":"2821"},
+{"last_update":"1181807696", "numofapproved":"1", "id":"2921"},
+{"last_update":"1181824523", "numofapproved":"1", "id":"2942"},
+{"last_update":"1181835089", "numofapproved":"1", "id":"2981"},
+{"last_update":"1182000147", "numofapproved":"1", "id":"3141"},
+{"last_update":"1182952133", "numofapproved":"1", "id":"3641"},
+{"last_update":"1188811518", "numofapproved":"1", "id":"8101"},
+{"last_update":"1188975549", "numofapproved":"1", "id":"8321"},
+{"last_update":"1190122760", "numofapproved":"1", "id":"9301"},
+{"last_update":"1190124712", "numofapproved":"1", "id":"9321"},
+{"last_update":"1194526560", "numofapproved":"1", "id":"15281"},
+{"last_update":"1195149112", "numofapproved":"1", "id":"16821"},
+{"last_update":"1179823256", "numofapproved":"1", "id":"1602"},
+{"last_update":"1186332011", "numofapproved":"1", "id":"6165"},
+{"last_update":"1187263451", "numofapproved":"1", "id":"6781"},
+{"last_update":"1190312346", "numofapproved":"1", "id":"9621"},
+{"last_update":"1193178728", "numofapproved":"1", "id":"13525"},
+{"last_update":"1193908534", "numofapproved":"1", "id":"14524"},
+{"last_update":"1194279992", "numofapproved":"1", "id":"15001"},
+{"last_update":"1194947169", "numofapproved":"1", "id":"16104"},
+{"last_update":"1195139978", "numofapproved":"1", "id":"16801"},
+{"last_update":"1195152323", "numofapproved":"1", "id":"16841"},
+{"last_update":"1188086146", "numofapproved":"1", "id":"7428"},
+{"last_update":"1192143475", "numofapproved":"1", "id":"12341"},
+{"last_update":"1192529949", "numofapproved":"1", "id":"12664"},
+{"last_update":"1192721072", "numofapproved":"1", "id":"13041"},
+{"last_update":"1193844156", "numofapproved":"1", "id":"14501"},
+{"last_update":"1177597683", "numofapproved":"1", "id":"1063"},
+{"last_update":"1180975406", "numofapproved":"1", "id":"2184"},
+{"last_update":"1184681435", "numofapproved":"1", "id":"4914"},
+{"last_update":"1187596457", "numofapproved":"1", "id":"6922"},
+{"last_update":"1190661113", "numofapproved":"1", "id":"10003"},
+{"last_update":"1192721357", "numofapproved":"1", "id":"13042"},
+{"last_update":"1193130120", "numofapproved":"1", "id":"13461"},
+{"last_update":"1193388868", "numofapproved":"1", "id":"13953"},
+{"last_update":"1194861534", "numofapproved":"1", "id":"15821"},
+{"last_update":"1182357592", "numofapproved":"1", "id":"3345"},
+{"last_update":"1183722862", "numofapproved":"1", "id":"4262"},
+{"last_update":"1186066354", "numofapproved":"1", "id":"6041"},
+{"last_update":"1192698982", "numofapproved":"1", "id":"12981"},
+{"last_update":"1181237191", "numofapproved":"1", "id":"2561"},
+{"last_update":"1184569090", "numofapproved":"1", "id":"4906"},
+{"last_update":"1185397555", "numofapproved":"1", "id":"5501"},
+{"last_update":"1185541935", "numofapproved":"1", "id":"5681"},
+{"last_update":"1193385832", "numofapproved":"1", "id":"13941"},
+{"last_update":"1185482424", "numofapproved":"1", "id":"5581"},
+{"last_update":"1195508796", "numofapproved":"1", "id":"17401"},
+{"last_update":"1178718386", "numofapproved":"1", "id":"1347"},
+{"last_update":"1178788813", "numofapproved":"1", "id":"1351"},
+{"last_update":"1178877332", "numofapproved":"1", "id":"1358"},
+{"last_update":"1183208679", "numofapproved":"1", "id":"3861"},
+{"last_update":"1187885439", "numofapproved":"1", "id":"7347"},
+{"last_update":"1188985190", "numofapproved":"1", "id":"8341"},
+{"last_update":"1189687132", "numofapproved":"1", "id":"8941"},
+{"last_update":"1189864330", "numofapproved":"1", "id":"9121"},
+{"last_update":"1190990605", "numofapproved":"1", "id":"10709"},
+{"last_update":"1192634449", "numofapproved":"1", "id":"12861"},
+{"last_update":"1194723756", "numofapproved":"1", "id":"15641"},
+{"last_update":"1194792428", "numofapproved":"1", "id":"15682"},
+{"last_update":"1194725734", "numofapproved":"1", "id":"15661"},
+{"last_update":"1194945618", "numofapproved":"1", "id":"16061"},
+{"last_update":"1194946006", "numofapproved":"1", "id":"16081"},
+{"last_update":"1194949774", "numofapproved":"1", "id":"16121"},
+{"last_update":"1194950925", "numofapproved":"1", "id":"16126"},
+{"last_update":"1194979238", "numofapproved":"1", "id":"16282"},
+{"last_update":"1195051013", "numofapproved":"1", "id":"16543"},
+{"last_update":"1195050956", "numofapproved":"1", "id":"16542"},
+{"last_update":"1195047036", "numofapproved":"1", "id":"16501"},
+{"last_update":"1195221919", "numofapproved":"1", "id":"16942"},
+{"last_update":"1178035892", "numofapproved":"1", "id":"1221"},
+{"last_update":"1178570265", "numofapproved":"1", "id":"1302"},
+{"last_update":"1178811921", "numofapproved":"1", "id":"1354"},
+{"last_update":"1182344326", "numofapproved":"1", "id":"3321"},
+{"last_update":"1184999048", "numofapproved":"1", "id":"5141"},
+{"last_update":"1188994511", "numofapproved":"1", "id":"8361"},
+{"last_update":"1189161726", "numofapproved":"1", "id":"8601"},
+{"last_update":"1190500875", "numofapproved":"1", "id":"9803"},
+{"last_update":"1190817424", "numofapproved":"1", "id":"10321"},
+{"last_update":"1191327796", "numofapproved":"1", "id":"11001"},
+{"last_update":"1191410544", "numofapproved":"1", "id":"11062"},
+{"last_update":"1192009739", "numofapproved":"1", "id":"12062"},
+{"last_update":"1193973669", "numofapproved":"1", "id":"14662"},
+{"last_update":"1194035149", "numofapproved":"1", "id":"14783"},
+{"last_update":"1194465519", "numofapproved":"1", "id":"15106"},
+{"last_update":"1194464336", "numofapproved":"1", "id":"15222"},
+{"last_update":"1194861398", "numofapproved":"1", "id":"15802"},
+{"last_update":"1194950791", "numofapproved":"1", "id":"16125"},
+{"last_update":"1195501394", "numofapproved":"1", "id":"17381"},
+{"last_update":"1195546583", "numofapproved":"1", "id":"17461"},
+{"last_update":"1177607652", "numofapproved":"1", "id":"1048"},
+{"last_update":"1182349136", "numofapproved":"1", "id":"3322"},
+{"last_update":"1184217665", "numofapproved":"1", "id":"4681"},
+{"last_update":"1185510733", "numofapproved":"1", "id":"5641"},
+{"last_update":"1187875988", "numofapproved":"1", "id":"7345"},
+{"last_update":"1188384227", "numofapproved":"1", "id":"7701"},
+{"last_update":"1188935650", "numofapproved":"1", "id":"8261"},
+{"last_update":"1188951982", "numofapproved":"1", "id":"8301"},
+{"last_update":"1190391010", "numofapproved":"1", "id":"9701"},
+{"last_update":"1191169581", "numofapproved":"1", "id":"10841"},
+{"last_update":"1194435269", "numofapproved":"1", "id":"15101"},
+{"last_update":"1171800457", "numofapproved":"1", "id":"86"},
+{"last_update":"1171968036", "numofapproved":"1", "id":"116"},
+{"last_update":"1171984640", "numofapproved":"1", "id":"129"},
+{"last_update":"1171987101", "numofapproved":"1", "id":"130"},
+{"last_update":"1172588327", "numofapproved":"1", "id":"213"},
+{"last_update":"1173736730", "numofapproved":"1", "id":"306"},
+{"last_update":"1174735009", "numofapproved":"1", "id":"463"},
+{"last_update":"1172314484", "numofapproved":"1", "id":"192"},
+{"last_update":"1172580739", "numofapproved":"1", "id":"212"},
+{"last_update":"1173889335", "numofapproved":"1", "id":"328"},
+{"last_update":"1171799339", "numofapproved":"1", "id":"79"},
+{"last_update":"1171882669", "numofapproved":"1", "id":"91"},
+{"last_update":"1172561300", "numofapproved":"1", "id":"207"},
+{"last_update":"1172565919", "numofapproved":"1", "id":"209"},
+{"last_update":"1172600401", "numofapproved":"1", "id":"217"},
+{"last_update":"1174040553", "numofapproved":"1", "id":"350"},
+{"last_update":"1174300376", "numofapproved":"1", "id":"365"},
+{"last_update":"1171800419", "numofapproved":"1", "id":"84"},
+{"last_update":"1171800471", "numofapproved":"1", "id":"87"},
+{"last_update":"1171904826", "numofapproved":"1", "id":"102"},
+{"last_update":"1171962248", "numofapproved":"1", "id":"110"},
+{"last_update":"1171968056", "numofapproved":"1", "id":"117"},
+{"last_update":"1172180757", "numofapproved":"1", "id":"174"},
+{"last_update":"1172249286", "numofapproved":"1", "id":"186"},
+{"last_update":"1172331355", "numofapproved":"1", "id":"194"},
+{"last_update":"1172838799", "numofapproved":"1", "id":"235"},
+{"last_update":"1173839361", "numofapproved":"1", "id":"316"},
+{"last_update":"1176141087", "numofapproved":"1", "id":"809"},
+{"last_update":"1176293168", "numofapproved":"1", "id":"827"},
+{"last_update":"1176314927", "numofapproved":"1", "id":"887"},
+{"last_update":"1172147490", "numofapproved":"1", "id":"169"},
+{"last_update":"1172673371", "numofapproved":"1", "id":"225"},
+{"last_update":"1175021309", "numofapproved":"1", "id":"539"},
+{"last_update":"1175719394", "numofapproved":"1", "id":"708"},
+{"last_update":"1175797177", "numofapproved":"1", "id":"741"},
+{"last_update":"1175797204", "numofapproved":"1", "id":"761"},
+{"last_update":"1173888948", "numofapproved":"1", "id":"323"},
+{"last_update":"1171050355", "numofapproved":"1", "id":"1"},
+{"last_update":"1171904868", "numofapproved":"1", "id":"104"},
+{"last_update":"1174301476", "numofapproved":"1", "id":"392"},
+{"last_update":"1174396679", "numofapproved":"1", "id":"401"},
+{"last_update":"1174735025", "numofapproved":"1", "id":"464"},
+{"last_update":"1171894147", "numofapproved":"1", "id":"94"},
+{"last_update":"1172226240", "numofapproved":"1", "id":"181"},
+{"last_update":"1172442130", "numofapproved":"1", "id":"195"},
+{"last_update":"1174300588", "numofapproved":"1", "id":"370"},
+{"last_update":"1174899082", "numofapproved":"1", "id":"490"},
+{"last_update":"1174899309", "numofapproved":"1", "id":"501"},
+{"last_update":"1173724444", "numofapproved":"1", "id":"304"},
+{"last_update":"1176314883", "numofapproved":"1", "id":"886"},
+{"last_update":"1173284377", "numofapproved":"1", "id":"259"},
+{"last_update":"1172244974", "numofapproved":"1", "id":"184"},
+{"last_update":"1173825356", "numofapproved":"1", "id":"315"},
+{"last_update":"1174898980", "numofapproved":"1", "id":"485"},
+{"last_update":"1175713133", "numofapproved":"1", "id":"706"},
+{"last_update":"1175872869", "numofapproved":"1", "id":"784"},
+{"last_update":"1174301161", "numofapproved":"1", "id":"380"},
+{"last_update":"1176710519", "numofapproved":"1", "id":"1002"},
+{"last_update":"1176776871", "numofapproved":"1", "id":"1006"},
+{"last_update":"1176383102", "numofapproved":"1", "id":"901"},
+{"last_update":"1176391153", "numofapproved":"1", "id":"902"},
+{"last_update":"1176562039", "numofapproved":"1", "id":"946"},
+{"last_update":"1175713172", "numofapproved":"1", "id":"668"},
+{"last_update":"1178045208", "numofapproved":"1", "id":"1204"},
+{"last_update":"1178648231", "numofapproved":"1", "id":"1307"},
+{"last_update":"1178876638", "numofapproved":"1", "id":"1362"},
+{"last_update":"1181120419", "numofapproved":"1", "id":"2341"},
+{"last_update":"1181217997", "numofapproved":"1", "id":"2462"},
+{"last_update":"1181292688", "numofapproved":"1", "id":"2622"},
+{"last_update":"1182246090", "numofapproved":"1", "id":"3205"},
+{"last_update":"1182982710", "numofapproved":"1", "id":"3681"},
+{"last_update":"1177496084", "numofapproved":"1", "id":"1021"},
+{"last_update":"1177496190", "numofapproved":"1", "id":"1022"},
+{"last_update":"1178310654", "numofapproved":"1", "id":"1261"},
+{"last_update":"1182861963", "numofapproved":"1", "id":"3582"},
+{"last_update":"1183392466", "numofapproved":"1", "id":"3981"},
+{"last_update":"1183971409", "numofapproved":"1", "id":"4404"},
+{"last_update":"1183984082", "numofapproved":"1", "id":"4421"},
+{"last_update":"1184101764", "numofapproved":"1", "id":"4581"},
+{"last_update":"1185805036", "numofapproved":"1", "id":"5821"},
+{"last_update":"1186071563", "numofapproved":"1", "id":"6061"},
+{"last_update":"1186331614", "numofapproved":"1", "id":"6221"},
+{"last_update":"1187103429", "numofapproved":"1", "id":"6623"},
+{"last_update":"1187359405", "numofapproved":"1", "id":"6901"},
+{"last_update":"1187764462", "numofapproved":"1", "id":"7121"},
+{"last_update":"1187765742", "numofapproved":"1", "id":"7181"},
+{"last_update":"1187821663", "numofapproved":"1", "id":"7281"},
+{"last_update":"1187851593", "numofapproved":"1", "id":"7301"},
+{"last_update":"1188829369", "numofapproved":"1", "id":"8141"},
+{"last_update":"1189006834", "numofapproved":"1", "id":"8401"},
+{"last_update":"1189656411", "numofapproved":"1", "id":"8901"},
+{"last_update":"1181824325", "numofapproved":"1", "id":"2961"},
+{"last_update":"1184699326", "numofapproved":"1", "id":"4922"},
+{"last_update":"1185981618", "numofapproved":"1", "id":"5981"},
+{"last_update":"1186476979", "numofapproved":"1", "id":"6169"},
+{"last_update":"1186501212", "numofapproved":"1", "id":"6301"},
+{"last_update":"1187111728", "numofapproved":"1", "id":"6624"},
+{"last_update":"1187275194", "numofapproved":"1", "id":"6821"},
+{"last_update":"1190232587", "numofapproved":"1", "id":"9501"},
+{"last_update":"1190379779", "numofapproved":"1", "id":"9661"},
+{"last_update":"1190500551", "numofapproved":"1", "id":"9801"},
+{"last_update":"1190555711", "numofapproved":"1", "id":"9861"},
+{"last_update":"1190664200", "numofapproved":"1", "id":"10061"},
+{"last_update":"1190662067", "numofapproved":"1", "id":"10021"},
+{"last_update":"1190887692", "numofapproved":"1", "id":"10461"},
+{"last_update":"1190887880", "numofapproved":"1", "id":"10462"},
+{"last_update":"1190924576", "numofapproved":"1", "id":"10581"},
+{"last_update":"1190990748", "numofapproved":"1", "id":"10713"},
+{"last_update":"1190990297", "numofapproved":"1", "id":"10703"},
+{"last_update":"1182792178", "numofapproved":"1", "id":"3541"},
+{"last_update":"1189505682", "numofapproved":"1", "id":"8781"},
+{"last_update":"1191410630", "numofapproved":"1", "id":"11081"},
+{"last_update":"1191431148", "numofapproved":"1", "id":"11141"},
+{"last_update":"1191446393", "numofapproved":"1", "id":"11181"},
+{"last_update":"1191559326", "numofapproved":"1", "id":"11481"},
+{"last_update":"1191860159", "numofapproved":"1", "id":"11861"},
+{"last_update":"1191933842", "numofapproved":"1", "id":"11901"},
+{"last_update":"1181765760", "numofapproved":"1", "id":"2901"},
+{"last_update":"1187098770", "numofapproved":"1", "id":"6622"},
+{"last_update":"1192155125", "numofapproved":"1", "id":"12382"},
+{"last_update":"1192449036", "numofapproved":"1", "id":"12601"},
+{"last_update":"1192604489", "numofapproved":"1", "id":"12781"},
+{"last_update":"1193265229", "numofapproved":"1", "id":"13681"},
+{"last_update":"1193304550", "numofapproved":"1", "id":"13781"},
+{"last_update":"1193401945", "numofapproved":"1", "id":"14101"},
+{"last_update":"1193305327", "numofapproved":"1", "id":"13801"},
+{"last_update":"1179912412", "numofapproved":"1", "id":"1722"},
+{"last_update":"1188295203", "numofapproved":"1", "id":"7621"},
+{"last_update":"1188580008", "numofapproved":"1", "id":"7881"},
+{"last_update":"1189115708", "numofapproved":"1", "id":"8521"},
+{"last_update":"1193864375", "numofapproved":"1", "id":"14522"},
+{"last_update":"1193973963", "numofapproved":"1", "id":"14666"},
+{"last_update":"1194003054", "numofapproved":"1", "id":"14701"},
+{"last_update":"1194262755", "numofapproved":"1", "id":"14885"},
+{"last_update":"1194262860", "numofapproved":"1", "id":"14886"},
+{"last_update":"1194366475", "numofapproved":"1", "id":"15042"},
+{"last_update":"1194505568", "numofapproved":"1", "id":"15108"},
+{"last_update":"1194507434", "numofapproved":"1", "id":"15109"},
+{"last_update":"1194625505", "numofapproved":"1", "id":"15542"},
+{"last_update":"1194635569", "numofapproved":"1", "id":"15583"},
+{"last_update":"1179319405", "numofapproved":"1", "id":"1394"},
+{"last_update":"1179409867", "numofapproved":"1", "id":"1441"},
+{"last_update":"1179431647", "numofapproved":"1", "id":"1481"},
+{"last_update":"1179842302", "numofapproved":"1", "id":"1667"},
+{"last_update":"1180710254", "numofapproved":"1", "id":"2081"},
+{"last_update":"1181855583", "numofapproved":"1", "id":"3041"},
+{"last_update":"1182100211", "numofapproved":"1", "id":"3182"},
+{"last_update":"1183377220", "numofapproved":"1", "id":"3921"},
+{"last_update":"1184677615", "numofapproved":"1", "id":"4910"},
+{"last_update":"1184679060", "numofapproved":"1", "id":"4911"},
+{"last_update":"1184679348", "numofapproved":"1", "id":"4912"},
+{"last_update":"1184749371", "numofapproved":"1", "id":"4943"},
+{"last_update":"1186734180", "numofapproved":"1", "id":"6381"},
+{"last_update":"1187012463", "numofapproved":"1", "id":"6501"},
+{"last_update":"1187209404", "numofapproved":"1", "id":"6741"},
+{"last_update":"1192687257", "numofapproved":"1", "id":"12941"},
+{"last_update":"1193385868", "numofapproved":"1", "id":"13942"},
+{"last_update":"1193386346", "numofapproved":"1", "id":"13943"},
+{"last_update":"1194937571", "numofapproved":"1", "id":"16042"},
+{"last_update":"1194855975", "numofapproved":"1", "id":"15761"},
+{"last_update":"1194960221", "numofapproved":"1", "id":"16161"},
+{"last_update":"1184058679", "numofapproved":"1", "id":"4541"},
+{"last_update":"1185865315", "numofapproved":"1", "id":"5842"},
+{"last_update":"1187178780", "numofapproved":"1", "id":"6681"},
+{"last_update":"1194884625", "numofapproved":"1", "id":"15921"},
+{"last_update":"1195134032", "numofapproved":"1", "id":"16721"},
+{"last_update":"1195164570", "numofapproved":"1", "id":"16901"},
+{"last_update":"1182336429", "numofapproved":"1", "id":"3301"},
+{"last_update":"1182415670", "numofapproved":"1", "id":"3353"},
+{"last_update":"1184575801", "numofapproved":"1", "id":"4907"},
+{"last_update":"1185483718", "numofapproved":"1", "id":"5601"},
+{"last_update":"1186402874", "numofapproved":"1", "id":"6166"},
+{"last_update":"1186750969", "numofapproved":"1", "id":"6383"},
+{"last_update":"1192725360", "numofapproved":"1", "id":"13061"},
+{"last_update":"1193314911", "numofapproved":"1", "id":"13822"},
+{"last_update":"1183448275", "numofapproved":"1", "id":"4062"},
+{"last_update":"1187321039", "numofapproved":"1", "id":"6861"},
+{"last_update":"1188287578", "numofapproved":"1", "id":"7601"},
+{"last_update":"1194464420", "numofapproved":"1", "id":"15224"},
+{"last_update":"1195139641", "numofapproved":"1", "id":"16781"},
+{"last_update":"1186147124", "numofapproved":"1", "id":"6107"},
+{"last_update":"1188821750", "numofapproved":"1", "id":"8122"},
+{"last_update":"1192531864", "numofapproved":"1", "id":"12665"},
+{"last_update":"1192984220", "numofapproved":"1", "id":"13223"},
+{"last_update":"1195225246", "numofapproved":"1", "id":"16982"},
+{"last_update":"1182410787", "numofapproved":"1", "id":"3351"},
+{"last_update":"1184531419", "numofapproved":"1", "id":"4901"},
+{"last_update":"1188801472", "numofapproved":"1", "id":"8081"},
+{"last_update":"1192524288", "numofapproved":"1", "id":"12661"},
+{"last_update":"1180950691", "numofapproved":"1", "id":"2181"},
+{"last_update":"1184016732", "numofapproved":"1", "id":"4501"},
+{"last_update":"1186074085", "numofapproved":"1", "id":"6081"},
+{"last_update":"1194937650", "numofapproved":"1", "id":"16043"},
+{"last_update":"1182937178", "numofapproved":"1", "id":"3623"},
+{"last_update":"1191419601", "numofapproved":"1", "id":"11101"},
+{"last_update":"1191856562", "numofapproved":"1", "id":"11843"},
+{"last_update":"1192525042", "numofapproved":"1", "id":"12681"},
+{"last_update":"1194625494", "numofapproved":"1", "id":"15541"},
+{"last_update":"1194982850", "numofapproved":"1", "id":"16361"},
+{"last_update":"1194989219", "numofapproved":"1", "id":"16401"},
+{"last_update":"1195066723", "numofapproved":"1", "id":"16641"},
+{"last_update":"1183971226", "numofapproved":"1", "id":"4403"},
+{"last_update":"1185526866", "numofapproved":"1", "id":"5661"},
+{"last_update":"1185741495", "numofapproved":"1", "id":"5741"},
+{"last_update":"1185905429", "numofapproved":"1", "id":"5881"},
+{"last_update":"1186137969", "numofapproved":"1", "id":"6104"},
+{"last_update":"1189267536", "numofapproved":"1", "id":"8701"},
+{"last_update":"1190115042", "numofapproved":"1", "id":"9261"},
+{"last_update":"1190664258", "numofapproved":"1", "id":"10062"},
+{"last_update":"1190774949", "numofapproved":"1", "id":"10201"},
+{"last_update":"1190965042", "numofapproved":"1", "id":"10641"},
+{"last_update":"1191493379", "numofapproved":"1", "id":"11301"},
+{"last_update":"1191578051", "numofapproved":"1", "id":"11501"},
+{"last_update":"1192188840", "numofapproved":"1", "id":"12421"},
+{"last_update":"1194000252", "numofapproved":"1", "id":"14682"},
+{"last_update":"1194622556", "numofapproved":"1", "id":"15462"},
+{"last_update":"1194981068", "numofapproved":"1", "id":"16341"},
+{"last_update":"1185795733", "numofapproved":"1", "id":"5782"},
+{"last_update":"1186646854", "numofapproved":"1", "id":"6341"},
+{"last_update":"1187087291", "numofapproved":"1", "id":"6621"},
+{"last_update":"1187951800", "numofapproved":"1", "id":"7401"},
+{"last_update":"1189170373", "numofapproved":"1", "id":"8642"},
+{"last_update":"1191007934", "numofapproved":"1", "id":"10781"},
+{"last_update":"1190985695", "numofapproved":"1", "id":"10681"},
+{"last_update":"1192009758", "numofapproved":"1", "id":"12063"},
+{"last_update":"1193062543", "numofapproved":"1", "id":"13321"},
+{"last_update":"1194950304", "numofapproved":"1", "id":"16123"},
+{"last_update":"1171882085", "numofapproved":"1", "id":"90"},
+{"last_update":"1171962264", "numofapproved":"1", "id":"111"},
+{"last_update":"1172646556", "numofapproved":"1", "id":"219"},
+{"last_update":"1174040139", "numofapproved":"1", "id":"349"},
+{"last_update":"1174059263", "numofapproved":"1", "id":"355"},
+{"last_update":"1174899063", "numofapproved":"1", "id":"489"},
+{"last_update":"1173797557", "numofapproved":"1", "id":"310"},
+{"last_update":"1174735191", "numofapproved":"1", "id":"468"},
+{"last_update":"1174899259", "numofapproved":"1", "id":"499"},
+{"last_update":"1174899354", "numofapproved":"1", "id":"502"},
+{"last_update":"1175254120", "numofapproved":"1", "id":"562"},
+{"last_update":"1171126391", "numofapproved":"1", "id":"4"},
+{"last_update":"1171800381", "numofapproved":"1", "id":"82"},
+{"last_update":"1171799224", "numofapproved":"1", "id":"75"},
+{"last_update":"1171972550", "numofapproved":"1", "id":"123"},
+{"last_update":"1174301165", "numofapproved":"1", "id":"381"},
+{"last_update":"1171904847", "numofapproved":"1", "id":"103"},
+{"last_update":"1172260956", "numofapproved":"1", "id":"190"},
+{"last_update":"1172803368", "numofapproved":"1", "id":"234"},
+{"last_update":"1173199576", "numofapproved":"1", "id":"250"},
+{"last_update":"1173206201", "numofapproved":"1", "id":"252"},
+{"last_update":"1175258941", "numofapproved":"1", "id":"563"},
+{"last_update":"1176232231", "numofapproved":"1", "id":"825"},
+{"last_update":"1176475088", "numofapproved":"1", "id":"921"},
+{"last_update":"1172082181", "numofapproved":"1", "id":"166"},
+{"last_update":"1172595205", "numofapproved":"1", "id":"216"},
+{"last_update":"1174898892", "numofapproved":"1", "id":"481"},
+{"last_update":"1174899696", "numofapproved":"1", "id":"518"},
+{"last_update":"1174924777", "numofapproved":"1", "id":"525"},
+{"last_update":"1175598588", "numofapproved":"1", "id":"682"},
+{"last_update":"1175602572", "numofapproved":"1", "id":"683"},
+{"last_update":"1175707879", "numofapproved":"1", "id":"666"},
+{"last_update":"1175710528", "numofapproved":"1", "id":"703"},
+{"last_update":"1175715728", "numofapproved":"1", "id":"707"},
+{"last_update":"1176137267", "numofapproved":"1", "id":"806"},
+{"last_update":"1176306491", "numofapproved":"1", "id":"883"},
+{"last_update":"1172069972", "numofapproved":"1", "id":"134"},
+{"last_update":"1173889144", "numofapproved":"1", "id":"324"},
+{"last_update":"1175502804", "numofapproved":"1", "id":"623"},
+{"last_update":"1175772530", "numofapproved":"1", "id":"711"},
+{"last_update":"1176297526", "numofapproved":"1", "id":"861"},
+{"last_update":"1171445818", "numofapproved":"1", "id":"47"},
+{"last_update":"1171884505", "numofapproved":"1", "id":"92"},
+{"last_update":"1172250708", "numofapproved":"1", "id":"187"},
+{"last_update":"1173749631", "numofapproved":"1", "id":"307"},
+{"last_update":"1173889164", "numofapproved":"1", "id":"325"},
+{"last_update":"1174301168", "numofapproved":"1", "id":"382"},
+{"last_update":"1171904807", "numofapproved":"1", "id":"101"},
+{"last_update":"1171970405", "numofapproved":"1", "id":"120"},
+{"last_update":"1172218677", "numofapproved":"1", "id":"179"},
+{"last_update":"1173125028", "numofapproved":"1", "id":"248"},
+{"last_update":"1171978122", "numofapproved":"1", "id":"126"},
+{"last_update":"1172676736", "numofapproved":"1", "id":"226"},
+{"last_update":"1173975473", "numofapproved":"1", "id":"344"},
+{"last_update":"1172072582", "numofapproved":"1", "id":"165"},
+{"last_update":"1173888774", "numofapproved":"1", "id":"322"},
+{"last_update":"1174560347", "numofapproved":"1", "id":"422"},
+{"last_update":"1174899242", "numofapproved":"1", "id":"498"},
+{"last_update":"1174735110", "numofapproved":"1", "id":"466"},
+{"last_update":"1176735630", "numofapproved":"1", "id":"1004"},
+{"last_update":"1175725931", "numofapproved":"1", "id":"670"},
+{"last_update":"1176498072", "numofapproved":"1", "id":"944"},
+{"last_update":"1178264233", "numofapproved":"1", "id":"1241"},
+{"last_update":"1178746727", "numofapproved":"1", "id":"1350"},
+{"last_update":"1178798992", "numofapproved":"1", "id":"1352"},
+{"last_update":"1180011647", "numofapproved":"1", "id":"1649"},
+{"last_update":"1180430823", "numofapproved":"1", "id":"1901"},
+{"last_update":"1180649952", "numofapproved":"1", "id":"2021"},
+{"last_update":"1180966506", "numofapproved":"1", "id":"2183"},
+{"last_update":"1180987142", "numofapproved":"1", "id":"2241"},
+{"last_update":"1181127788", "numofapproved":"1", "id":"2322"},
+{"last_update":"1181217668", "numofapproved":"1", "id":"2461"},
+{"last_update":"1182789542", "numofapproved":"1", "id":"3522"},
+{"last_update":"1182851714", "numofapproved":"1", "id":"3581"},
+{"last_update":"1179268837", "numofapproved":"1", "id":"1407"},
+{"last_update":"1179999486", "numofapproved":"1", "id":"1645"},
+{"last_update":"1180019568", "numofapproved":"1", "id":"1653"},
+{"last_update":"1180082061", "numofapproved":"1", "id":"1821"},
+{"last_update":"1184181871", "numofapproved":"1", "id":"4642"},
+{"last_update":"1184251955", "numofapproved":"1", "id":"4741"},
+{"last_update":"1184346893", "numofapproved":"1", "id":"4841"},
+{"last_update":"1184773981", "numofapproved":"1", "id":"5001"},
+{"last_update":"1185272905", "numofapproved":"1", "id":"5281"},
+{"last_update":"1185484083", "numofapproved":"1", "id":"5622"},
+{"last_update":"1185897961", "numofapproved":"1", "id":"5861"},
+{"last_update":"1186951708", "numofapproved":"1", "id":"6462"},
+{"last_update":"1187596311", "numofapproved":"1", "id":"6941"},
+{"last_update":"1187766852", "numofapproved":"1", "id":"7201"},
+{"last_update":"1188158133", "numofapproved":"1", "id":"7481"},
+{"last_update":"1188233835", "numofapproved":"1", "id":"7501"},
+{"last_update":"1188269273", "numofapproved":"1", "id":"7561"},
+{"last_update":"1177672684", "numofapproved":"1", "id":"1141"},
+{"last_update":"1178042016", "numofapproved":"1", "id":"1222"},
+{"last_update":"1181646022", "numofapproved":"1", "id":"2801"},
+{"last_update":"1181853920", "numofapproved":"1", "id":"3021"},
+{"last_update":"1183715836", "numofapproved":"1", "id":"4241"},
+{"last_update":"1183726859", "numofapproved":"1", "id":"4281"},
+{"last_update":"1189860355", "numofapproved":"1", "id":"9101"},
+{"last_update":"1189871747", "numofapproved":"1", "id":"9141"},
+{"last_update":"1190380660", "numofapproved":"1", "id":"9681"},
+{"last_update":"1190510808", "numofapproved":"1", "id":"9821"},
+{"last_update":"1190542013", "numofapproved":"1", "id":"9843"},
+{"last_update":"1190665412", "numofapproved":"1", "id":"10081"},
+{"last_update":"1190299519", "numofapproved":"1", "id":"9601"},
+{"last_update":"1191410594", "numofapproved":"1", "id":"11063"},
+{"last_update":"1191505786", "numofapproved":"1", "id":"11341"},
+{"last_update":"1191583652", "numofapproved":"1", "id":"11522"},
+{"last_update":"1191599712", "numofapproved":"1", "id":"11681"},
+{"last_update":"1191602931", "numofapproved":"1", "id":"11721"},
+{"last_update":"1191762572", "numofapproved":"1", "id":"11761"},
+{"last_update":"1191856256", "numofapproved":"1", "id":"11841"},
+{"last_update":"1191937041", "numofapproved":"1", "id":"11921"},
+{"last_update":"1179325639", "numofapproved":"1", "id":"1409"},
+{"last_update":"1179912165", "numofapproved":"1", "id":"1721"},
+{"last_update":"1181119430", "numofapproved":"1", "id":"2321"},
+{"last_update":"1184696743", "numofapproved":"1", "id":"4921"},
+{"last_update":"1192154847", "numofapproved":"1", "id":"12361"},
+{"last_update":"1192237071", "numofapproved":"1", "id":"12501"},
+{"last_update":"1178637394", "numofapproved":"1", "id":"1304"},
+{"last_update":"1178716778", "numofapproved":"1", "id":"1344"},
+{"last_update":"1182937057", "numofapproved":"1", "id":"3622"},
+{"last_update":"1183113642", "numofapproved":"1", "id":"3781"},
+{"last_update":"1183995467", "numofapproved":"1", "id":"4461"},
+{"last_update":"1184223331", "numofapproved":"1", "id":"4721"},
+{"last_update":"1190990692", "numofapproved":"1", "id":"10711"},
+{"last_update":"1193269310", "numofapproved":"1", "id":"13761"},
+{"last_update":"1193735756", "numofapproved":"1", "id":"14441"},
+{"last_update":"1194635738", "numofapproved":"1", "id":"15603"},
+{"last_update":"1194901721", "numofapproved":"1", "id":"15961"},
+{"last_update":"1194949951", "numofapproved":"1", "id":"16141"},
+{"last_update":"1194960695", "numofapproved":"1", "id":"16182"},
+{"last_update":"1194973974", "numofapproved":"1", "id":"16221"},
+{"last_update":"1194946810", "numofapproved":"1", "id":"16102"},
+{"last_update":"1194977452", "numofapproved":"1", "id":"16261"},
+{"last_update":"1195040385", "numofapproved":"1", "id":"16461"},
+{"last_update":"1195053483", "numofapproved":"1", "id":"16561"},
+{"last_update":"1195053518", "numofapproved":"1", "id":"16562"},
+{"last_update":"1195218698", "numofapproved":"1", "id":"16921"},
+{"last_update":"1195225049", "numofapproved":"1", "id":"16961"},
+{"last_update":"1195164270", "numofapproved":"1", "id":"16881"},
+{"last_update":"1195080947", "numofapproved":"1", "id":"16681"},
+{"last_update":"1195469884", "numofapproved":"1", "id":"17181"},
+{"last_update":"1185314804", "numofapproved":"1", "id":"5381"},
+{"last_update":"1188401767", "numofapproved":"1", "id":"7721"},
+{"last_update":"1190286841", "numofapproved":"1", "id":"9582"},
+{"last_update":"1190733096", "numofapproved":"1", "id":"10141"},
+{"last_update":"1190847451", "numofapproved":"1", "id":"10422"},
+{"last_update":"1190990526", "numofapproved":"1", "id":"10707"},
+{"last_update":"1192009711", "numofapproved":"1", "id":"12061"},
+{"last_update":"1192155478", "numofapproved":"1", "id":"12362"},
+{"last_update":"1192468382", "numofapproved":"1", "id":"12641"},
+{"last_update":"1193332032", "numofapproved":"1", "id":"13881"},
+{"last_update":"1195497290", "numofapproved":"1", "id":"17321"},
+{"last_update":"1195519935", "numofapproved":"1", "id":"17441"},
+{"last_update":"1195549826", "numofapproved":"1", "id":"17521"},
+{"last_update":"1177668131", "numofapproved":"1", "id":"1101"},
+{"last_update":"1186835348", "numofapproved":"1", "id":"6421"},
+{"last_update":"1191057903", "numofapproved":"1", "id":"10802"},
+{"last_update":"1193973906", "numofapproved":"1", "id":"14665"},
+{"last_update":"1171904780", "numofapproved":"1", "id":"100"},
+{"last_update":"1172677750", "numofapproved":"1", "id":"227"},
+{"last_update":"1172686704", "numofapproved":"1", "id":"229"},
+{"last_update":"1173101684", "numofapproved":"1", "id":"245"},
+{"last_update":"1173466151", "numofapproved":"1", "id":"282"},
+{"last_update":"1174301263", "numofapproved":"1", "id":"386"},
+{"last_update":"1174302366", "numofapproved":"1", "id":"399"},
+{"last_update":"1174501294", "numofapproved":"1", "id":"421"},
+{"last_update":"1174899635", "numofapproved":"1", "id":"515"},
+{"last_update":"1174924556", "numofapproved":"1", "id":"523"},
+{"last_update":"1175141200", "numofapproved":"1", "id":"541"},
+{"last_update":"1171799271", "numofapproved":"1", "id":"76"},
+{"last_update":"1171900163", "numofapproved":"1", "id":"97"},
+{"last_update":"1174301267", "numofapproved":"1", "id":"387"},
+{"last_update":"1174735156", "numofapproved":"1", "id":"467"},
+{"last_update":"1174899569", "numofapproved":"1", "id":"512"},
+{"last_update":"1174926970", "numofapproved":"1", "id":"531"},
+{"last_update":"1175502757", "numofapproved":"1", "id":"602"},
+{"last_update":"1175603425", "numofapproved":"1", "id":"663"},
+{"last_update":"1176194967", "numofapproved":"1", "id":"822"},
+{"last_update":"1171800398", "numofapproved":"1", "id":"83"},
+{"last_update":"1171968376", "numofapproved":"1", "id":"118"},
+{"last_update":"1172070063", "numofapproved":"1", "id":"135"},
+{"last_update":"1173821159", "numofapproved":"1", "id":"314"},
+{"last_update":"1176559052", "numofapproved":"1", "id":"964"},
+{"last_update":"1171299245", "numofapproved":"1", "id":"23"},
+{"last_update":"1171535160", "numofapproved":"1", "id":"57"},
+{"last_update":"1171564542", "numofapproved":"1", "id":"65"},
+{"last_update":"1172646592", "numofapproved":"1", "id":"220"},
+{"last_update":"1174899489", "numofapproved":"1", "id":"507"},
+{"last_update":"1174924890", "numofapproved":"1", "id":"528"},
+{"last_update":"1175687005", "numofapproved":"1", "id":"701"},
+{"last_update":"1176132888", "numofapproved":"1", "id":"805"},
+{"last_update":"1171286610", "numofapproved":"1", "id":"21"},
+{"last_update":"1172184441", "numofapproved":"1", "id":"176"},
+{"last_update":"1172187221", "numofapproved":"1", "id":"178"},
+{"last_update":"1173386668", "numofapproved":"1", "id":"261"},
+{"last_update":"1173809115", "numofapproved":"1", "id":"312"},
+{"last_update":"1175609126", "numofapproved":"1", "id":"685"},
+{"last_update":"1175791369", "numofapproved":"1", "id":"712"},
+{"last_update":"1176480434", "numofapproved":"1", "id":"942"},
+{"last_update":"1171503567", "numofapproved":"1", "id":"56"},
+{"last_update":"1171799204", "numofapproved":"1", "id":"74"},
+{"last_update":"1172236765", "numofapproved":"1", "id":"183"},
+{"last_update":"1175598013", "numofapproved":"1", "id":"681"},
+{"last_update":"1175610956", "numofapproved":"1", "id":"687"},
+{"last_update":"1175725436", "numofapproved":"1", "id":"710"},
+{"last_update":"1171905052", "numofapproved":"1", "id":"105"},
+{"last_update":"1172268920", "numofapproved":"1", "id":"191"},
+{"last_update":"1173264110", "numofapproved":"1", "id":"256"},
+{"last_update":"1173889179", "numofapproved":"1", "id":"326"},
+{"last_update":"1174301066", "numofapproved":"1", "id":"378"},
+{"last_update":"1174300399", "numofapproved":"1", "id":"366"},
+{"last_update":"1174387980", "numofapproved":"1", "id":"400"},
+{"last_update":"1176823766", "numofapproved":"1", "id":"1007"},
+{"last_update":"1171970585", "numofapproved":"1", "id":"122"},
+{"last_update":"1172071500", "numofapproved":"1", "id":"145"},
+{"last_update":"1172580279", "numofapproved":"1", "id":"211"},
+{"last_update":"1172658493", "numofapproved":"1", "id":"221"},
+{"last_update":"1174301611", "numofapproved":"1", "id":"397"},
+{"last_update":"1176900132", "numofapproved":"1", "id":"989"},
+{"last_update":"1171965754", "numofapproved":"1", "id":"114"},
+{"last_update":"1173797482", "numofapproved":"1", "id":"309"},
+{"last_update":"1174300513", "numofapproved":"1", "id":"367"},
+{"last_update":"1174301493", "numofapproved":"1", "id":"395"},
+{"last_update":"1174899124", "numofapproved":"1", "id":"492"},
+{"last_update":"1174899677", "numofapproved":"1", "id":"517"},
+{"last_update":"1174924235", "numofapproved":"1", "id":"522"},
+{"last_update":"1174925568", "numofapproved":"1", "id":"529"},
+{"last_update":"1174933088", "numofapproved":"1", "id":"533"},
+{"last_update":"1174933338", "numofapproved":"1", "id":"538"},
+{"last_update":"1174044629", "numofapproved":"1", "id":"352"},
+{"last_update":"1175713207", "numofapproved":"1", "id":"669"},
+{"last_update":"1178339569", "numofapproved":"1", "id":"1262"},
+{"last_update":"1178611427", "numofapproved":"1", "id":"1303"},
+{"last_update":"1178707269", "numofapproved":"1", "id":"1341"},
+{"last_update":"1179411388", "numofapproved":"1", "id":"1461"},
+{"last_update":"1180000879", "numofapproved":"1", "id":"1648"},
+{"last_update":"1180097993", "numofapproved":"1", "id":"1657"},
+{"last_update":"1180107947", "numofapproved":"1", "id":"1659"},
+{"last_update":"1180515935", "numofapproved":"1", "id":"1922"},
+{"last_update":"1180712418", "numofapproved":"1", "id":"2102"},
+{"last_update":"1180731895", "numofapproved":"1", "id":"2063"},
+{"last_update":"1180731763", "numofapproved":"1", "id":"2143"},
+{"last_update":"1180951519", "numofapproved":"1", "id":"2201"},
+{"last_update":"1180954763", "numofapproved":"1", "id":"2182"},
+{"last_update":"1181134185", "numofapproved":"1", "id":"2361"},
+{"last_update":"1181206368", "numofapproved":"1", "id":"2441"},
+{"last_update":"1181207556", "numofapproved":"1", "id":"2442"},
+{"last_update":"1183065868", "numofapproved":"1", "id":"3741"},
+{"last_update":"1183124436", "numofapproved":"1", "id":"3822"},
+{"last_update":"1183118631", "numofapproved":"1", "id":"3802"},
+{"last_update":"1183515629", "numofapproved":"1", "id":"4144"},
+{"last_update":"1184169495", "numofapproved":"1", "id":"4621"},
+{"last_update":"1184777700", "numofapproved":"1", "id":"5021"},
+{"last_update":"1185371099", "numofapproved":"1", "id":"5441"},
+{"last_update":"1185460060", "numofapproved":"1", "id":"5521"},
+{"last_update":"1185462514", "numofapproved":"1", "id":"5541"},
+{"last_update":"1185573050", "numofapproved":"1", "id":"5721"},
+{"last_update":"1185795586", "numofapproved":"1", "id":"5781"},
+{"last_update":"1185962181", "numofapproved":"1", "id":"5901"},
+{"last_update":"1185987024", "numofapproved":"1", "id":"6001"},
+{"last_update":"1186138150", "numofapproved":"1", "id":"6105"},
+{"last_update":"1186500528", "numofapproved":"1", "id":"6281"},
+{"last_update":"1187765075", "numofapproved":"1", "id":"7141"},
+{"last_update":"1188158263", "numofapproved":"1", "id":"7482"},
+{"last_update":"1189094579", "numofapproved":"1", "id":"8461"},
+{"last_update":"1189327635", "numofapproved":"1", "id":"8721"},
+{"last_update":"1182356521", "numofapproved":"1", "id":"3344"},
+{"last_update":"1185017921", "numofapproved":"1", "id":"5161"},
+{"last_update":"1185271167", "numofapproved":"1", "id":"5261"},
+{"last_update":"1190663796", "numofapproved":"1", "id":"10041"},
+{"last_update":"1190726728", "numofapproved":"1", "id":"10121"},
+{"last_update":"1190801144", "numofapproved":"1", "id":"10241"},
+{"last_update":"1190894441", "numofapproved":"1", "id":"10502"},
+{"last_update":"1190973098", "numofapproved":"1", "id":"10667"},
+{"last_update":"1190925124", "numofapproved":"1", "id":"10584"},
+{"last_update":"1191249884", "numofapproved":"1", "id":"10961"},
+{"last_update":"1187732431", "numofapproved":"1", "id":"7081"},
+{"last_update":"1189259179", "numofapproved":"1", "id":"8681"},
+{"last_update":"1191446517", "numofapproved":"1", "id":"11183"},
+{"last_update":"1191510643", "numofapproved":"1", "id":"11381"},
+{"last_update":"1191529640", "numofapproved":"1", "id":"11421"},
+{"last_update":"1191588726", "numofapproved":"1", "id":"11602"},
+{"last_update":"1191903050", "numofapproved":"1", "id":"11881"},
+{"last_update":"1181218459", "numofapproved":"1", "id":"2464"},
+{"last_update":"1187024536", "numofapproved":"1", "id":"6581"},
+{"last_update":"1192009094", "numofapproved":"1", "id":"12041"},
+{"last_update":"1192064048", "numofapproved":"1", "id":"12183"},
+{"last_update":"1192061973", "numofapproved":"1", "id":"12181"},
+{"last_update":"1193026780", "numofapproved":"1", "id":"13241"},
+{"last_update":"1193416409", "numofapproved":"1", "id":"14161"},
+{"last_update":"1186992495", "numofapproved":"1", "id":"6481"},
+{"last_update":"1191410811", "numofapproved":"1", "id":"11066"},
+{"last_update":"1193440748", "numofapproved":"1", "id":"14241"},
+{"last_update":"1194252005", "numofapproved":"1", "id":"14884"},
+{"last_update":"1194362364", "numofapproved":"1", "id":"14889"},
+{"last_update":"1179240103", "numofapproved":"1", "id":"1389"},
+{"last_update":"1181812262", "numofapproved":"1", "id":"2922"},
+{"last_update":"1182093916", "numofapproved":"1", "id":"3181"},
+{"last_update":"1182767688", "numofapproved":"1", "id":"3501"},
+{"last_update":"1184181747", "numofapproved":"1", "id":"4661"},
+{"last_update":"1186505570", "numofapproved":"1", "id":"6170"},
+{"last_update":"1186751068", "numofapproved":"1", "id":"6384"},
+{"last_update":"1187558925", "numofapproved":"1", "id":"6921"},
+{"last_update":"1188037477", "numofapproved":"1", "id":"7424"},
+{"last_update":"1194937530", "numofapproved":"1", "id":"16041"},
+{"last_update":"1179754250", "numofapproved":"1", "id":"1562"},
+{"last_update":"1183416194", "numofapproved":"1", "id":"4021"},
+{"last_update":"1185835616", "numofapproved":"1", "id":"5841"},
+{"last_update":"1192731190", "numofapproved":"1", "id":"13141"},
+{"last_update":"1193178120", "numofapproved":"1", "id":"13523"},
+{"last_update":"1193844805", "numofapproved":"1", "id":"14503"},
+{"last_update":"1193909242", "numofapproved":"1", "id":"14525"},
+{"last_update":"1195474767", "numofapproved":"1", "id":"17221"},
+{"last_update":"1177690781", "numofapproved":"1", "id":"1142"},
+{"last_update":"1185373614", "numofapproved":"1", "id":"5461"},
+{"last_update":"1192520088", "numofapproved":"1", "id":"12624"},
+{"last_update":"1193194444", "numofapproved":"1", "id":"13527"},
+{"last_update":"1193387684", "numofapproved":"1", "id":"13950"},
+{"last_update":"1193388786", "numofapproved":"1", "id":"13952"},
+{"last_update":"1194616895", "numofapproved":"1", "id":"15401"},
+{"last_update":"1195034817", "numofapproved":"1", "id":"16441"},
+{"last_update":"1183107374", "numofapproved":"1", "id":"3761"},
+{"last_update":"1183515040", "numofapproved":"1", "id":"4121"},
+{"last_update":"1184744160", "numofapproved":"1", "id":"4942"},
+{"last_update":"1192094830", "numofapproved":"1", "id":"12201"},
+{"last_update":"1193314411", "numofapproved":"1", "id":"13821"},
+{"last_update":"1193391901", "numofapproved":"1", "id":"13957"},
+{"last_update":"1193399824", "numofapproved":"1", "id":"14043"},
+{"last_update":"1194450353", "numofapproved":"1", "id":"15181"},
+{"last_update":"1194474719", "numofapproved":"1", "id":"15241"},
+{"last_update":"1194622799", "numofapproved":"1", "id":"15481"},
+{"last_update":"1194880827", "numofapproved":"1", "id":"15901"},
+{"last_update":"1182363929", "numofapproved":"1", "id":"3347"},
+{"last_update":"1182952243", "numofapproved":"1", "id":"3642"},
+{"last_update":"1183386876", "numofapproved":"1", "id":"3962"},
+{"last_update":"1193178314", "numofapproved":"1", "id":"13524"},
+{"last_update":"1195376577", "numofapproved":"1", "id":"17061"},
+{"last_update":"1179832847", "numofapproved":"1", "id":"1621"},
+{"last_update":"1184053269", "numofapproved":"1", "id":"4521"},
+{"last_update":"1185024744", "numofapproved":"1", "id":"5181"},
+{"last_update":"1186130324", "numofapproved":"1", "id":"6101"},
+{"last_update":"1192529640", "numofapproved":"1", "id":"12662"},
+{"last_update":"1193158482", "numofapproved":"1", "id":"13521"},
+{"last_update":"1194247788", "numofapproved":"1", "id":"14883"},
+{"last_update":"1182363717", "numofapproved":"1", "id":"3346"},
+{"last_update":"1193386824", "numofapproved":"1", "id":"13944"},
+{"last_update":"1193844655", "numofapproved":"1", "id":"14502"},
+{"last_update":"1180732326", "numofapproved":"1", "id":"2064"},
+{"last_update":"1182247493", "numofapproved":"1", "id":"3222"},
+{"last_update":"1183515318", "numofapproved":"1", "id":"4143"},
+{"last_update":"1184840285", "numofapproved":"1", "id":"5061"},
+{"last_update":"1188458821", "numofapproved":"1", "id":"7741"},
+{"last_update":"1188919582", "numofapproved":"1", "id":"8241"},
+{"last_update":"1190990231", "numofapproved":"1", "id":"10701"},
+{"last_update":"1190990557", "numofapproved":"1", "id":"10708"},
+{"last_update":"1191583611", "numofapproved":"1", "id":"11521"},
+{"last_update":"1192031263", "numofapproved":"1", "id":"12102"},
+{"last_update":"1192431349", "numofapproved":"1", "id":"12563"},
+{"last_update":"1192608972", "numofapproved":"1", "id":"12801"},
+{"last_update":"1193244196", "numofapproved":"1", "id":"13641"},
+{"last_update":"1193733530", "numofapproved":"1", "id":"14422"},
+{"last_update":"1194988770", "numofapproved":"1", "id":"16381"},
+{"last_update":"1195050890", "numofapproved":"1", "id":"16541"},
+{"last_update":"1195047262", "numofapproved":"1", "id":"16502"},
+{"last_update":"1195221672", "numofapproved":"1", "id":"16941"},
+{"last_update":"1195400016", "numofapproved":"1", "id":"17103"},
+{"last_update":"1178716622", "numofapproved":"1", "id":"1343"},
+{"last_update":"1183563126", "numofapproved":"1", "id":"4181"},
+{"last_update":"1183970953", "numofapproved":"1", "id":"4402"},
+{"last_update":"1190149151", "numofapproved":"1", "id":"9381"},
+{"last_update":"1190628937", "numofapproved":"1", "id":"9921"},
+{"last_update":"1190908511", "numofapproved":"1", "id":"10521"},
+{"last_update":"1191365468", "numofapproved":"1", "id":"11021"},
+{"last_update":"1192431054", "numofapproved":"1", "id":"12561"},
+{"last_update":"1188938163", "numofapproved":"1", "id":"8281"},
+{"last_update":"1192155298", "numofapproved":"1", "id":"12383"},
+{"last_update":"1193223714", "numofapproved":"1", "id":"13561"},
+{"last_update":"1171799359", "numofapproved":"1", "id":"80"},
+{"last_update":"1171962550", "numofapproved":"1", "id":"112"},
+{"last_update":"1171965210", "numofapproved":"1", "id":"113"},
+{"last_update":"1171980888", "numofapproved":"1", "id":"128"},
+{"last_update":"1174299174", "numofapproved":"1", "id":"361"},
+{"last_update":"1174301053", "numofapproved":"1", "id":"376"},
+{"last_update":"1174899661", "numofapproved":"1", "id":"516"},
+{"last_update":"1172646493", "numofapproved":"1", "id":"218"},
+{"last_update":"1174899018", "numofapproved":"1", "id":"487"},
+{"last_update":"1175091201", "numofapproved":"1", "id":"540"},
+{"last_update":"1175267243", "numofapproved":"1", "id":"564"},
+{"last_update":"1176293117", "numofapproved":"1", "id":"826"},
+{"last_update":"1171602873", "numofapproved":"1", "id":"67"},
+{"last_update":"1172568714", "numofapproved":"1", "id":"210"},
+{"last_update":"1174300556", "numofapproved":"1", "id":"369"},
+{"last_update":"1174301614", "numofapproved":"1", "id":"398"},
+{"last_update":"1174429050", "numofapproved":"1", "id":"404"},
+{"last_update":"1175547821", "numofapproved":"1", "id":"641"},
+{"last_update":"1175696551", "numofapproved":"1", "id":"702"},
+{"last_update":"1176223342", "numofapproved":"1", "id":"823"},
+{"last_update":"1176459077", "numofapproved":"1", "id":"905"},
+{"last_update":"1172169117", "numofapproved":"1", "id":"172"},
+{"last_update":"1172259821", "numofapproved":"1", "id":"189"},
+{"last_update":"1172847347", "numofapproved":"1", "id":"237"},
+{"last_update":"1176485274", "numofapproved":"1", "id":"961"},
+{"last_update":"1176739199", "numofapproved":"1", "id":"983"},
+{"last_update":"1171710108", "numofapproved":"1", "id":"72"},
+{"last_update":"1172147854", "numofapproved":"1", "id":"170"},
+{"last_update":"1172178657", "numofapproved":"1", "id":"173"},
+{"last_update":"1174933210", "numofapproved":"1", "id":"535"},
+{"last_update":"1175502973", "numofapproved":"1", "id":"626"},
+{"last_update":"1172071610", "numofapproved":"1", "id":"146"},
+{"last_update":"1172847402", "numofapproved":"1", "id":"240"},
+{"last_update":"1173282970", "numofapproved":"1", "id":"258"},
+{"last_update":"1175502729", "numofapproved":"1", "id":"621"},
+{"last_update":"1173889203", "numofapproved":"1", "id":"327"},
+{"last_update":"1174301604", "numofapproved":"1", "id":"396"},
+{"last_update":"1176738556", "numofapproved":"1", "id":"1005"},
+{"last_update":"1171287066", "numofapproved":"1", "id":"22"},
+{"last_update":"1171388951", "numofapproved":"1", "id":"46"},
+{"last_update":"1171645099", "numofapproved":"1", "id":"70"},
+{"last_update":"1174301489", "numofapproved":"1", "id":"394"},
+{"last_update":"1176109438", "numofapproved":"1", "id":"804"},
+{"last_update":"1173203622", "numofapproved":"1", "id":"251"},
+{"last_update":"1174300337", "numofapproved":"1", "id":"364"},
+{"last_update":"1174898999", "numofapproved":"1", "id":"486"},
+{"last_update":"1174899221", "numofapproved":"1", "id":"497"},
+{"last_update":"1174899505", "numofapproved":"1", "id":"508"},
+{"last_update":"1171905996", "numofapproved":"1", "id":"106"},
+{"last_update":"1172003938", "numofapproved":"1", "id":"131"},
+{"last_update":"1172134183", "numofapproved":"1", "id":"167"},
+{"last_update":"1178550080", "numofapproved":"1", "id":"1301"},
+{"last_update":"1178718229", "numofapproved":"1", "id":"1346"},
+{"last_update":"1178725187", "numofapproved":"1", "id":"1322"},
+{"last_update":"1179302219", "numofapproved":"1", "id":"1392"},
+{"last_update":"1180015260", "numofapproved":"1", "id":"1650"},
+{"last_update":"1180088452", "numofapproved":"1", "id":"1656"},
+{"last_update":"1180719498", "numofapproved":"1", "id":"2121"},
+{"last_update":"1180731930", "numofapproved":"1", "id":"2145"},
+{"last_update":"1180731601", "numofapproved":"1", "id":"2142"},
+{"last_update":"1181034337", "numofapproved":"1", "id":"2281"},
+{"last_update":"1181222113", "numofapproved":"1", "id":"2501"},
+{"last_update":"1181254636", "numofapproved":"1", "id":"2601"},
+{"last_update":"1181578682", "numofapproved":"1", "id":"2762"},
+{"last_update":"1181731051", "numofapproved":"1", "id":"2881"},
+{"last_update":"1177673345", "numofapproved":"1", "id":"1162"},
+{"last_update":"1183741680", "numofapproved":"1", "id":"4301"},
+{"last_update":"1183988623", "numofapproved":"1", "id":"4441"},
+{"last_update":"1184217947", "numofapproved":"1", "id":"4701"},
+{"last_update":"1186260146", "numofapproved":"1", "id":"6181"},
+{"last_update":"1186289860", "numofapproved":"1", "id":"6163"},
+{"last_update":"1186235477", "numofapproved":"1", "id":"6161"},
+{"last_update":"1186508996", "numofapproved":"1", "id":"6171"},
+{"last_update":"1187626570", "numofapproved":"1", "id":"6961"},
+{"last_update":"1187713755", "numofapproved":"1", "id":"7041"},
+{"last_update":"1187769208", "numofapproved":"1", "id":"7222"},
+{"last_update":"1187856827", "numofapproved":"1", "id":"7341"},
+{"last_update":"1188053850", "numofapproved":"1", "id":"7461"},
+{"last_update":"1188264856", "numofapproved":"1", "id":"7541"},
+{"last_update":"1188319841", "numofapproved":"1", "id":"7681"},
+{"last_update":"1188582632", "numofapproved":"1", "id":"7901"},
+{"last_update":"1188734330", "numofapproved":"1", "id":"8001"},
+{"last_update":"1189003562", "numofapproved":"1", "id":"8381"},
+{"last_update":"1179787121", "numofapproved":"1", "id":"1581"},
+{"last_update":"1181998896", "numofapproved":"1", "id":"3121"},
+{"last_update":"1182274782", "numofapproved":"1", "id":"3261"},
+{"last_update":"1186350397", "numofapproved":"1", "id":"6241"},
+{"last_update":"1187354512", "numofapproved":"1", "id":"6881"},
+{"last_update":"1188918086", "numofapproved":"1", "id":"8221"},
+{"last_update":"1190392989", "numofapproved":"1", "id":"9721"},
+{"last_update":"1190925022", "numofapproved":"1", "id":"10583"},
+{"last_update":"1190959571", "numofapproved":"1", "id":"10601"},
+{"last_update":"1190990357", "numofapproved":"1", "id":"10705"},
+{"last_update":"1190990656", "numofapproved":"1", "id":"10710"},
+{"last_update":"1191226364", "numofapproved":"1", "id":"10921"},
+{"last_update":"1180011741", "numofapproved":"1", "id":"1761"},
+{"last_update":"1180533694", "numofapproved":"1", "id":"1961"},
+{"last_update":"1180731839", "numofapproved":"1", "id":"2144"},
+{"last_update":"1181461876", "numofapproved":"1", "id":"2681"},
+{"last_update":"1181855690", "numofapproved":"1", "id":"3061"},
+{"last_update":"1189537687", "numofapproved":"1", "id":"8821"},
+{"last_update":"1189937430", "numofapproved":"1", "id":"9161"},
+{"last_update":"1190803903", "numofapproved":"1", "id":"10261"},
+{"last_update":"1190973051", "numofapproved":"1", "id":"10664"},
+{"last_update":"1191410739", "numofapproved":"1", "id":"11064"},
+{"last_update":"1191426697", "numofapproved":"1", "id":"11121"},
+{"last_update":"1191446459", "numofapproved":"1", "id":"11182"},
+{"last_update":"1191450891", "numofapproved":"1", "id":"11201"},
+{"last_update":"1191550000", "numofapproved":"1", "id":"11441"},
+{"last_update":"1191588714", "numofapproved":"1", "id":"11601"},
+{"last_update":"1191596815", "numofapproved":"1", "id":"11641"},
+{"last_update":"1191647971", "numofapproved":"1", "id":"11741"},
+{"last_update":"1191949660", "numofapproved":"1", "id":"11981"},
+{"last_update":"1180641844", "numofapproved":"1", "id":"2001"},
+{"last_update":"1188319710", "numofapproved":"1", "id":"7661"},
+{"last_update":"1189169640", "numofapproved":"1", "id":"8621"},
+{"last_update":"1192028009", "numofapproved":"1", "id":"12081"},
+{"last_update":"1192116783", "numofapproved":"1", "id":"12261"},
+{"last_update":"1192558715", "numofapproved":"1", "id":"12741"},
+{"last_update":"1192727702", "numofapproved":"1", "id":"13101"},
+{"last_update":"1193035517", "numofapproved":"1", "id":"13262"},
+{"last_update":"1193080239", "numofapproved":"1", "id":"13381"},
+{"last_update":"1193268912", "numofapproved":"1", "id":"13722"},
+{"last_update":"1193386894", "numofapproved":"1", "id":"13946"},
+{"last_update":"1193388087", "numofapproved":"1", "id":"13982"},
+{"last_update":"1179841973", "numofapproved":"1", "id":"1642"},
+{"last_update":"1179842066", "numofapproved":"1", "id":"1662"},
+{"last_update":"1185971695", "numofapproved":"1", "id":"5941"},
+{"last_update":"1186137440", "numofapproved":"1", "id":"6103"},
+{"last_update":"1192823224", "numofapproved":"1", "id":"13181"},
+{"last_update":"1193921116", "numofapproved":"1", "id":"14581"},
+{"last_update":"1193918035", "numofapproved":"1", "id":"14544"},
+{"last_update":"1193973759", "numofapproved":"1", "id":"14663"},
+{"last_update":"1194004166", "numofapproved":"1", "id":"14721"},
+{"last_update":"1194020795", "numofapproved":"1", "id":"14761"},
+{"last_update":"1194021069", "numofapproved":"1", "id":"14781"},
+{"last_update":"1194283444", "numofapproved":"1", "id":"14887"},
+{"last_update":"1194436909", "numofapproved":"1", "id":"15141"},
+{"last_update":"1194538247", "numofapproved":"1", "id":"15341"},
+{"last_update":"1180031440", "numofapproved":"1", "id":"1801"},
+{"last_update":"1181823965", "numofapproved":"1", "id":"2941"},
+{"last_update":"1182846565", "numofapproved":"1", "id":"3561"},
+{"last_update":"1185872587", "numofapproved":"1", "id":"5843"},
+{"last_update":"1186472951", "numofapproved":"1", "id":"6168"},
+{"last_update":"1189937606", "numofapproved":"1", "id":"9181"},
+{"last_update":"1193389026", "numofapproved":"1", "id":"13955"},
+{"last_update":"1192130592", "numofapproved":"1", "id":"12321"},
+{"last_update":"1194387386", "numofapproved":"1", "id":"15061"},
+{"last_update":"1179336536", "numofapproved":"1", "id":"1396"},
+{"last_update":"1182280246", "numofapproved":"1", "id":"3281"},
+{"last_update":"1183394591", "numofapproved":"1", "id":"4001"},
+{"last_update":"1184677502", "numofapproved":"1", "id":"4909"},
+{"last_update":"1186144184", "numofapproved":"1", "id":"6106"},
+{"last_update":"1187191683", "numofapproved":"1", "id":"6701"},
+{"last_update":"1193909594", "numofapproved":"1", "id":"14527"},
+{"last_update":"1194435747", "numofapproved":"1", "id":"15121"},
+{"last_update":"1184252278", "numofapproved":"1", "id":"4761"},
+{"last_update":"1194854996", "numofapproved":"1", "id":"15721"},
+{"last_update":"1194937730", "numofapproved":"1", "id":"16045"},
+{"last_update":"1193076864", "numofapproved":"1", "id":"13361"},
+{"last_update":"1194904087", "numofapproved":"1", "id":"15981"},
+{"last_update":"1181853751", "numofapproved":"1", "id":"3001"},
+{"last_update":"1182075529", "numofapproved":"1", "id":"3161"},
+{"last_update":"1184883226", "numofapproved":"1", "id":"5081"},
+{"last_update":"1186136013", "numofapproved":"1", "id":"6102"},
+{"last_update":"1193147983", "numofapproved":"1", "id":"13481"},
+{"last_update":"1194532658", "numofapproved":"1", "id":"15301"},
+{"last_update":"1194937763", "numofapproved":"1", "id":"16046"},
+{"last_update":"1195225183", "numofapproved":"1", "id":"16981"},
+{"last_update":"1180616624", "numofapproved":"1", "id":"1981"},
+{"last_update":"1183019269", "numofapproved":"1", "id":"3701"},
+{"last_update":"1188656338", "numofapproved":"1", "id":"7941"},
+{"last_update":"1178799062", "numofapproved":"1", "id":"1353"},
+{"last_update":"1178905809", "numofapproved":"1", "id":"1360"},
+{"last_update":"1179311575", "numofapproved":"1", "id":"1408"},
+{"last_update":"1182507595", "numofapproved":"1", "id":"3461"},
+{"last_update":"1184254004", "numofapproved":"1", "id":"4781"},
+{"last_update":"1187938257", "numofapproved":"1", "id":"7381"},
+{"last_update":"1188473327", "numofapproved":"1", "id":"7801"},
+{"last_update":"1189102174", "numofapproved":"1", "id":"8481"},
+{"last_update":"1191419747", "numofapproved":"1", "id":"11102"},
+{"last_update":"1193389169", "numofapproved":"1", "id":"14002"},
+{"last_update":"1194440930", "numofapproved":"1", "id":"15102"},
+{"last_update":"1194855848", "numofapproved":"1", "id":"15741"},
+{"last_update":"1194862162", "numofapproved":"1", "id":"15841"},
+{"last_update":"1194923605", "numofapproved":"1", "id":"16021"},
+{"last_update":"1194950051", "numofapproved":"1", "id":"16142"},
+{"last_update":"1194960554", "numofapproved":"1", "id":"16181"},
+{"last_update":"1194988868", "numofapproved":"1", "id":"16382"},
+{"last_update":"1195058276", "numofapproved":"1", "id":"16601"},
+{"last_update":"1195469960", "numofapproved":"1", "id":"17201"},
+{"last_update":"1178648361", "numofapproved":"1", "id":"1311"},
+{"last_update":"1183970840", "numofapproved":"1", "id":"4401"},
+{"last_update":"1184838534", "numofapproved":"1", "id":"5041"},
+{"last_update":"1190745858", "numofapproved":"1", "id":"10161"},
+{"last_update":"1191587968", "numofapproved":"1", "id":"11581"},
+{"last_update":"1189773687", "numofapproved":"1", "id":"9021"},
+{"last_update":"1192612866", "numofapproved":"1", "id":"12804"},
+{"last_update":"1193746024", "numofapproved":"1", "id":"14461"},
+{"last_update":"1193918117", "numofapproved":"1", "id":"14561"},
+{"last_update":"1194981013", "numofapproved":"1", "id":"16321"},
+{"last_update":"1195546695", "numofapproved":"1", "id":"17481"},
+{"last_update":"1177592107", "numofapproved":"1", "id":"1047"},
+{"last_update":"1183569612", "numofapproved":"1", "id":"4221"},
+{"last_update":"1186770649", "numofapproved":"1", "id":"6401"},
+{"last_update":"1187707518", "numofapproved":"1", "id":"7021"},
+{"last_update":"1187769297", "numofapproved":"1", "id":"7223"},
+{"last_update":"1187798945", "numofapproved":"1", "id":"7241"},
+{"last_update":"1187820883", "numofapproved":"1", "id":"7261"},
+{"last_update":"1190286816", "numofapproved":"1", "id":"9581"},
+{"last_update":"1190541964", "numofapproved":"1", "id":"9842"},
+{"last_update":"1190500569", "numofapproved":"1", "id":"9802"},
+{"last_update":"1190800190", "numofapproved":"1", "id":"10222"},
+{"last_update":"1190965460", "numofapproved":"1", "id":"10642"},
+{"last_update":"1192120899", "numofapproved":"1", "id":"12301"},
+{"last_update":"1193265675", "numofapproved":"1", "id":"13701"},
+{"last_update":"1194508196", "numofapproved":"1", "id":"15261"},
+{"last_update":"1172503197", "numofapproved":"1", "id":"196"},
+{"last_update":"1172847366", "numofapproved":"1", "id":"238"},
+{"last_update":"1173975764", "numofapproved":"1", "id":"347"},
+{"last_update":"1174301010", "numofapproved":"1", "id":"375"},
+{"last_update":"1174899614", "numofapproved":"1", "id":"514"},
+{"last_update":"1174924853", "numofapproved":"1", "id":"527"},
+{"last_update":"1175270318", "numofapproved":"1", "id":"567"},
+{"last_update":"1174933246", "numofapproved":"1", "id":"536"},
+{"last_update":"1176369900", "numofapproved":"1", "id":"889"},
+{"last_update":"1171102836", "numofapproved":"1", "id":"2"},
+{"last_update":"1171970451", "numofapproved":"1", "id":"121"},
+{"last_update":"1174898953", "numofapproved":"1", "id":"484"},
+{"last_update":"1175610845", "numofapproved":"1", "id":"664"},
+{"last_update":"1176313569", "numofapproved":"1", "id":"885"},
+{"last_update":"1171878648", "numofapproved":"1", "id":"89"},
+{"last_update":"1171897268", "numofapproved":"1", "id":"96"},
+{"last_update":"1172326187", "numofapproved":"1", "id":"193"},
+{"last_update":"1176106905", "numofapproved":"1", "id":"802"},
+{"last_update":"1176389540", "numofapproved":"1", "id":"891"},
+{"last_update":"1171318806", "numofapproved":"1", "id":"24"},
+{"last_update":"1171601548", "numofapproved":"1", "id":"66"},
+{"last_update":"1172148331", "numofapproved":"1", "id":"171"},
+{"last_update":"1172686680", "numofapproved":"1", "id":"228"},
+{"last_update":"1173793572", "numofapproved":"1", "id":"308"},
+{"last_update":"1174899594", "numofapproved":"1", "id":"513"},
+{"last_update":"1174898936", "numofapproved":"1", "id":"483"},
+{"last_update":"1175502773", "numofapproved":"1", "id":"622"},
+{"last_update":"1175722537", "numofapproved":"1", "id":"709"},
+{"last_update":"1175764633", "numofapproved":"1", "id":"672"},
+{"last_update":"1175797156", "numofapproved":"1", "id":"721"},
+{"last_update":"1175899070", "numofapproved":"1", "id":"785"},
+{"last_update":"1176106959", "numofapproved":"1", "id":"803"},
+{"last_update":"1176228460", "numofapproved":"1", "id":"824"},
+{"last_update":"1176488163", "numofapproved":"1", "id":"962"},
+{"last_update":"1172068869", "numofapproved":"1", "id":"133"},
+{"last_update":"1172847381", "numofapproved":"1", "id":"239"},
+{"last_update":"1173888657", "numofapproved":"1", "id":"320"},
+{"last_update":"1171449446", "numofapproved":"1", "id":"48"},
+{"last_update":"1175287424", "numofapproved":"1", "id":"581"},
+{"last_update":"1175502897", "numofapproved":"1", "id":"624"},
+{"last_update":"1175503020", "numofapproved":"1", "id":"605"},
+{"last_update":"1172848367", "numofapproved":"1", "id":"243"},
+{"last_update":"1174301060", "numofapproved":"1", "id":"377"},
+{"last_update":"1176824481", "numofapproved":"1", "id":"986"},
+{"last_update":"1171275893", "numofapproved":"1", "id":"6"},
+{"last_update":"1172546216", "numofapproved":"1", "id":"206"},
+{"last_update":"1175502705", "numofapproved":"1", "id":"601"},
+{"last_update":"1173962671", "numofapproved":"1", "id":"341"},
+{"last_update":"1173975403", "numofapproved":"1", "id":"342"},
+{"last_update":"1173816295", "numofapproved":"1", "id":"313"},
+{"last_update":"1174301256", "numofapproved":"1", "id":"384"},
+{"last_update":"1174933293", "numofapproved":"1", "id":"537"},
+{"last_update":"1176899419", "numofapproved":"1", "id":"988"},
+{"last_update":"1173975599", "numofapproved":"1", "id":"345"},
+{"last_update":"1174041960", "numofapproved":"1", "id":"351"},
+{"last_update":"1175759476", "numofapproved":"1", "id":"671"},
+{"last_update":"1178195644", "numofapproved":"1", "id":"1207"},
+{"last_update":"1178725318", "numofapproved":"1", "id":"1348"},
+{"last_update":"1179333492", "numofapproved":"1", "id":"1421"},
+{"last_update":"1179999737", "numofapproved":"1", "id":"1646"},
+{"last_update":"1180710770", "numofapproved":"1", "id":"2062"},
+{"last_update":"1182868347", "numofapproved":"1", "id":"3601"},
+{"last_update":"1182932927", "numofapproved":"1", "id":"3621"},
+{"last_update":"1183115054", "numofapproved":"1", "id":"3784"},
+{"last_update":"1180000741", "numofapproved":"1", "id":"1647"},
+{"last_update":"1181292582", "numofapproved":"1", "id":"2621"},
+{"last_update":"1184181581", "numofapproved":"1", "id":"4641"},
+{"last_update":"1185280501", "numofapproved":"1", "id":"5301"},
+{"last_update":"1185471699", "numofapproved":"1", "id":"5561"},
+{"last_update":"1185542771", "numofapproved":"1", "id":"5701"},
+{"last_update":"1186650650", "numofapproved":"1", "id":"6361"},
+{"last_update":"1186951065", "numofapproved":"1", "id":"6461"},
+{"last_update":"1187769080", "numofapproved":"1", "id":"7221"},
+{"last_update":"1187887905", "numofapproved":"1", "id":"7348"},
+{"last_update":"1188001607", "numofapproved":"1", "id":"7423"},
+{"last_update":"1188463414", "numofapproved":"1", "id":"7762"},
+{"last_update":"1188555813", "numofapproved":"1", "id":"7861"},
+{"last_update":"1188634622", "numofapproved":"1", "id":"7921"},
+{"last_update":"1189543954", "numofapproved":"1", "id":"8841"},
+{"last_update":"1177511009", "numofapproved":"1", "id":"1043"},
+{"last_update":"1181898808", "numofapproved":"1", "id":"3081"},
+{"last_update":"1182247483", "numofapproved":"1", "id":"3221"},
+{"last_update":"1187024005", "numofapproved":"1", "id":"6562"},
+{"last_update":"1189839471", "numofapproved":"1", "id":"9081"},
+{"last_update":"1190018380", "numofapproved":"1", "id":"9241"},
+{"last_update":"1190149586", "numofapproved":"1", "id":"9401"},
+{"last_update":"1190652684", "numofapproved":"1", "id":"9981"},
+{"last_update":"1190662296", "numofapproved":"1", "id":"10022"},
+{"last_update":"1190813509", "numofapproved":"1", "id":"10281"},
+{"last_update":"1190826005", "numofapproved":"1", "id":"10403"},
+{"last_update":"1190991166", "numofapproved":"1", "id":"10722"},
+{"last_update":"1191057700", "numofapproved":"1", "id":"10801"},
+{"last_update":"1191161241", "numofapproved":"1", "id":"10821"},
+{"last_update":"1191227885", "numofapproved":"1", "id":"10941"},
+{"last_update":"1182537005", "numofapproved":"1", "id":"3481"},
+{"last_update":"1185018401", "numofapproved":"1", "id":"5162"},
+{"last_update":"1186752963", "numofapproved":"1", "id":"6386"},
+{"last_update":"1190660077", "numofapproved":"1", "id":"10001"},
+{"last_update":"1191319062", "numofapproved":"1", "id":"10981"},
+{"last_update":"1191446097", "numofapproved":"1", "id":"11161"},
+{"last_update":"1191446587", "numofapproved":"1", "id":"11184"},
+{"last_update":"1191470824", "numofapproved":"1", "id":"11221"},
+{"last_update":"1191526821", "numofapproved":"1", "id":"11401"},
+{"last_update":"1191585471", "numofapproved":"1", "id":"11561"},
+{"last_update":"1191602213", "numofapproved":"1", "id":"11701"},
+{"last_update":"1191845720", "numofapproved":"1", "id":"11821"},
+{"last_update":"1191933874", "numofapproved":"1", "id":"11902"},
+{"last_update":"1191933897", "numofapproved":"1", "id":"11903"},
+{"last_update":"1177673238", "numofapproved":"1", "id":"1161"},
+{"last_update":"1181601542", "numofapproved":"1", "id":"2781"},
+{"last_update":"1182869532", "numofapproved":"1", "id":"3583"},
+{"last_update":"1183315879", "numofapproved":"1", "id":"3881"},
+{"last_update":"1187097870", "numofapproved":"1", "id":"6641"},
+{"last_update":"1190148660", "numofapproved":"1", "id":"9361"},
+{"last_update":"1192248648", "numofapproved":"1", "id":"12521"},
+{"last_update":"1192702958", "numofapproved":"1", "id":"13001"},
+{"last_update":"1193387721", "numofapproved":"1", "id":"13981"},
+{"last_update":"1193391276", "numofapproved":"1", "id":"14021"},
+{"last_update":"1193397051", "numofapproved":"1", "id":"14061"},
+{"last_update":"1193592081", "numofapproved":"1", "id":"14321"},
+{"last_update":"1188474438", "numofapproved":"1", "id":"7821"},
+{"last_update":"1190158372", "numofapproved":"1", "id":"9441"},
+{"last_update":"1193648459", "numofapproved":"1", "id":"14361"},
+{"last_update":"1193999834", "numofapproved":"1", "id":"14681"},
+{"last_update":"1194200119", "numofapproved":"1", "id":"14861"},
+{"last_update":"1194528747", "numofapproved":"1", "id":"15111"},
+{"last_update":"1179150787", "numofapproved":"1", "id":"1384"},
+{"last_update":"1179266496", "numofapproved":"1", "id":"1390"},
+{"last_update":"1179508139", "numofapproved":"1", "id":"1501"},
+{"last_update":"1179842157", "numofapproved":"1", "id":"1664"},
+{"last_update":"1179842347", "numofapproved":"1", "id":"1668"},
+{"last_update":"1181245388", "numofapproved":"1", "id":"2562"},
+{"last_update":"1181311044", "numofapproved":"1", "id":"2661"},
+{"last_update":"1181545818", "numofapproved":"1", "id":"2701"},
+{"last_update":"1181934881", "numofapproved":"1", "id":"3103"},
+{"last_update":"1187020798", "numofapproved":"1", "id":"6541"},
+{"last_update":"1187271377", "numofapproved":"1", "id":"6801"},
+{"last_update":"1196086904", "numofapproved":"1", "id":"17545"},
+{"last_update":"1196266437", "numofapproved":"2", "id":"17662"},
+{"last_update":"1196266638", "numofapproved":"2", "id":"17663"},
+{"last_update":"1197533251", "numofapproved":"1", "id":"17901"},
+{"last_update":"1197533384", "numofapproved":"1", "id":"17923"},
+{"last_update":"1197556776", "numofapproved":"2", "id":"17941"},
+{"last_update":"1200059354", "numofapproved":"1", "id":"17981"},
+{"last_update":"1200576144", "numofapproved":"1", "id":"18001"},
+{"last_update":"1200576230", "numofapproved":"1", "id":"18002"},
+{"last_update":"1200657266", "numofapproved":"1", "id":"18041"},
+{"last_update":"1201510556", "numofapproved":"1", "id":"18061"},
+{"last_update":"1196087136", "numofapproved":"1", "id":"17546"},
+{"last_update":"1196087269", "numofapproved":"1", "id":"17547"},
+{"last_update":"1196087335", "numofapproved":"1", "id":"17548"},
+{"last_update":"1196087379", "numofapproved":"1", "id":"17549"},
+{"last_update":"1196087427", "numofapproved":"1", "id":"17550"},
+{"last_update":"1196096347", "numofapproved":"1", "id":"17581"},
+{"last_update":"1196265997", "numofapproved":"2", "id":"17661"},
+{"last_update":"1196266785", "numofapproved":"1", "id":"17664"},
+{"last_update":"1196270058", "numofapproved":"1", "id":"17701"},
+{"last_update":"1196431875", "numofapproved":"1", "id":"17804"},
+{"last_update":"1197635044", "numofapproved":"1", "id":"17961"},
+{"last_update":"1202720206", "numofapproved":"2", "id":"18084"},
+{"last_update":"1196267153", "numofapproved":"1", "id":"17681"},
+{"last_update":"1196090749", "numofapproved":"1", "id":"17569"},
+{"last_update":"1196162163", "numofapproved":"2", "id":"17641"},
+{"last_update":"1196345846", "numofapproved":"1", "id":"17721"},
+{"last_update":"1196088254", "numofapproved":"1", "id":"17552"},
+{"last_update":"1196088437", "numofapproved":"1", "id":"17564"},
+{"last_update":"1196088477", "numofapproved":"1", "id":"17565"},
+{"last_update":"1196088537", "numofapproved":"1", "id":"17566"},
+{"last_update":"1196088894", "numofapproved":"1", "id":"17567"},
+{"last_update":"1196090414", "numofapproved":"1", "id":"17554"},
+{"last_update":"1196097621", "numofapproved":"1", "id":"17601"},
+{"last_update":"1196097710", "numofapproved":"1", "id":"17602"},
+{"last_update":"1196098047", "numofapproved":"1", "id":"17603"},
+{"last_update":"1196358376", "numofapproved":"2", "id":"17761"},
+{"last_update":"1196358647", "numofapproved":"1", "id":"17762"},
+{"last_update":"1196427604", "numofapproved":"1", "id":"17781"},
+{"last_update":"1196429856", "numofapproved":"1", "id":"17782"},
+{"last_update":"1196431068", "numofapproved":"2", "id":"17783"},
+{"last_update":"1196435953", "numofapproved":"2", "id":"17821"},
+{"last_update":"1204027277", "numofapproved":"1", "id":"18104"},
+{"last_update":"1196090201", "numofapproved":"1", "id":"17553"},
+{"last_update":"1196097095", "numofapproved":"1", "id":"17582"},
+{"last_update":"1196097215", "numofapproved":"1", "id":"17583"},
+{"last_update":"1196430140", "numofapproved":"2", "id":"17803"},
+{"last_update":"1196436411", "numofapproved":"2", "id":"17841"},
+{"last_update":"1196692298", "numofapproved":"1", "id":"17861"},
+{"last_update":"1196692342", "numofapproved":"2", "id":"17862"},
+{"last_update":"1196695231", "numofapproved":"2", "id":"17865"},
+{"last_update":"1197533316", "numofapproved":"1", "id":"17921"},
+{"last_update":"1201512744", "numofapproved":"1", "id":"18082"},
+{"last_update":"1201513438", "numofapproved":"2", "id":"18083"},
+{"last_update":"1196087540", "numofapproved":"1", "id":"17551"},
+{"last_update":"1196156416", "numofapproved":"2", "id":"17621"},
+{"last_update":"1196356717", "numofapproved":"1", "id":"17741"},
+{"last_update":"1196428544", "numofapproved":"2", "id":"17801"},
+{"last_update":"1196429000", "numofapproved":"2", "id":"17802"},
+{"last_update":"1196692578", "numofapproved":"1", "id":"17863"},
+{"last_update":"1196693445", "numofapproved":"2", "id":"17881"},
+{"last_update":"1196693804", "numofapproved":"2", "id":"17864"},
+{"last_update":"1197533347", "numofapproved":"1", "id":"17922"},
+{"last_update":"1200591782", "numofapproved":"1", "id":"18021"},
+{"last_update":"1201510930", "numofapproved":"1", "id":"18081"},
+{"last_update":"1192432005", "numofapproved":"1", "id":"12582"},
+{"last_update":"1192614291", "numofapproved":"1", "id":"12805"},
+{"last_update":"1192624421", "numofapproved":"1", "id":"12806"},
+{"last_update":"1192983623", "numofapproved":"1", "id":"13221"},
+{"last_update":"1193043248", "numofapproved":"1", "id":"13282"},
+{"last_update":"1193223892", "numofapproved":"1", "id":"13562"},
+{"last_update":"1193239943", "numofapproved":"1", "id":"13601"},
+{"last_update":"1193385960", "numofapproved":"1", "id":"13961"},
+{"last_update":"1193386863", "numofapproved":"1", "id":"13945"},
+{"last_update":"1193399770", "numofapproved":"1", "id":"14042"},
+{"last_update":"1193417684", "numofapproved":"1", "id":"14181"},
+{"last_update":"1193458402", "numofapproved":"1", "id":"14261"},
+{"last_update":"1193555071", "numofapproved":"1", "id":"14301"},
+{"last_update":"1185285506", "numofapproved":"1", "id":"5321"},
+{"last_update":"1188250869", "numofapproved":"1", "id":"7521"},
+{"last_update":"1191410480", "numofapproved":"1", "id":"11061"},
+{"last_update":"1193763056", "numofapproved":"1", "id":"14482"},
+{"last_update":"1193913886", "numofapproved":"1", "id":"14542"},
+{"last_update":"1194366001", "numofapproved":"1", "id":"14890"},
+{"last_update":"1194454607", "numofapproved":"1", "id":"15105"},
+{"last_update":"1194255904", "numofapproved":"1", "id":"14941"},
+{"last_update":"1179328986", "numofapproved":"1", "id":"1395"},
+{"last_update":"1180377628", "numofapproved":"1", "id":"1861"},
+{"last_update":"1181250011", "numofapproved":"1", "id":"2563"},
+{"last_update":"1181572386", "numofapproved":"1", "id":"2741"},
+{"last_update":"1183967114", "numofapproved":"1", "id":"4381"},
+{"last_update":"1192512712", "numofapproved":"1", "id":"12623"},
+{"last_update":"1193172621", "numofapproved":"1", "id":"13522"},
+{"last_update":"1193868932", "numofapproved":"1", "id":"14523"},
+{"last_update":"1194980345", "numofapproved":"1", "id":"16301"},
+{"last_update":"1182280312", "numofapproved":"1", "id":"3282"},
+{"last_update":"1184058726", "numofapproved":"1", "id":"4542"},
+{"last_update":"1188829875", "numofapproved":"1", "id":"8161"},
+{"last_update":"1190129857", "numofapproved":"1", "id":"9341"},
+{"last_update":"1190652687", "numofapproved":"1", "id":"9982"},
+{"last_update":"1193389082", "numofapproved":"1", "id":"13956"},
+{"last_update":"1195400591", "numofapproved":"1", "id":"17121"},
+{"last_update":"1184420846", "numofapproved":"1", "id":"4882"},
+{"last_update":"1184532219", "numofapproved":"1", "id":"4903"},
+{"last_update":"1192030476", "numofapproved":"1", "id":"12101"},
+{"last_update":"1192202239", "numofapproved":"1", "id":"12461"},
+{"last_update":"1192688302", "numofapproved":"1", "id":"12961"},
+{"last_update":"1192703266", "numofapproved":"1", "id":"13021"},
+{"last_update":"1193387096", "numofapproved":"1", "id":"13948"},
+{"last_update":"1193387200", "numofapproved":"1", "id":"13949"},
+{"last_update":"1193909837", "numofapproved":"1", "id":"14528"},
+{"last_update":"1181062093", "numofapproved":"1", "id":"2301"},
+{"last_update":"1182364431", "numofapproved":"1", "id":"3348"},
+{"last_update":"1182364589", "numofapproved":"1", "id":"3349"},
+{"last_update":"1184942429", "numofapproved":"1", "id":"5101"},
+{"last_update":"1192682522", "numofapproved":"1", "id":"12901"},
+{"last_update":"1184756287", "numofapproved":"1", "id":"4944"},
+{"last_update":"1190274411", "numofapproved":"1", "id":"9541"},
+{"last_update":"1193324229", "numofapproved":"1", "id":"13861"},
+{"last_update":"1195163999", "numofapproved":"1", "id":"16861"},
+{"last_update":"1181553321", "numofapproved":"1", "id":"2721"},
+{"last_update":"1178869453", "numofapproved":"1", "id":"1361"},
+{"last_update":"1181219788", "numofapproved":"1", "id":"2481"},
+{"last_update":"1178140002", "numofapproved":"1", "id":"1205"},
+{"last_update":"1178716891", "numofapproved":"1", "id":"1345"},
+{"last_update":"1180691957", "numofapproved":"1", "id":"2061"},
+{"last_update":"1182246242", "numofapproved":"1", "id":"3206"},
+{"last_update":"1182882314", "numofapproved":"1", "id":"3585"},
+{"last_update":"1183124192", "numofapproved":"1", "id":"3821"},
+{"last_update":"1183905634", "numofapproved":"1", "id":"4361"},
+{"last_update":"1191225755", "numofapproved":"1", "id":"10901"},
+{"last_update":"1192635977", "numofapproved":"1", "id":"12881"},
+{"last_update":"1193268752", "numofapproved":"1", "id":"13721"},
+{"last_update":"1193242245", "numofapproved":"1", "id":"13621"},
+{"last_update":"1193949751", "numofapproved":"1", "id":"14621"},
+{"last_update":"1194635892", "numofapproved":"1", "id":"15621"},
+{"last_update":"1194726918", "numofapproved":"1", "id":"15664"},
+{"last_update":"1194726371", "numofapproved":"1", "id":"15662"},
+{"last_update":"1194858043", "numofapproved":"1", "id":"15781"},
+{"last_update":"1194946522", "numofapproved":"1", "id":"16101"},
+{"last_update":"1195047359", "numofapproved":"1", "id":"16521"},
+{"last_update":"1195050812", "numofapproved":"1", "id":"16503"},
+{"last_update":"1195058811", "numofapproved":"1", "id":"16621"},
+{"last_update":"1195476161", "numofapproved":"1", "id":"17241"},
+{"last_update":"1178645683", "numofapproved":"1", "id":"1305"},
+{"last_update":"1183118619", "numofapproved":"1", "id":"3801"},
+{"last_update":"1186150376", "numofapproved":"1", "id":"6121"},
+{"last_update":"1189114226", "numofapproved":"1", "id":"8501"},
+{"last_update":"1190973079", "numofapproved":"1", "id":"10666"},
+{"last_update":"1190990329", "numofapproved":"1", "id":"10704"},
+{"last_update":"1191508485", "numofapproved":"1", "id":"11361"},
+{"last_update":"1183054560", "numofapproved":"1", "id":"3721"},
+{"last_update":"1185263889", "numofapproved":"1", "id":"5241"},
+{"last_update":"1187876083", "numofapproved":"1", "id":"7346"},
+{"last_update":"1189550218", "numofapproved":"1", "id":"8861"},
+{"last_update":"1190800088", "numofapproved":"1", "id":"10221"},
+{"last_update":"1193260528", "numofapproved":"1", "id":"13661"},
+{"last_update":"1172509002", "numofapproved":"1", "id":"199"},
+{"last_update":"1172509846", "numofapproved":"1", "id":"200"},
+{"last_update":"1172589855", "numofapproved":"1", "id":"214"},
+{"last_update":"1172847322", "numofapproved":"1", "id":"236"},
+{"last_update":"1172847433", "numofapproved":"1", "id":"242"},
+{"last_update":"1173607050", "numofapproved":"1", "id":"283"},
+{"last_update":"1173703535", "numofapproved":"1", "id":"301"},
+{"last_update":"1173719825", "numofapproved":"1", "id":"302"},
+{"last_update":"1174414845", "numofapproved":"1", "id":"403"},
+{"last_update":"1174650542", "numofapproved":"1", "id":"441"},
+{"last_update":"1171475944", "numofapproved":"1", "id":"52"},
+{"last_update":"1172746278", "numofapproved":"1", "id":"231"},
+{"last_update":"1173251095", "numofapproved":"1", "id":"254"},
+{"last_update":"1173259501", "numofapproved":"1", "id":"255"},
+{"last_update":"1174899183", "numofapproved":"1", "id":"495"},
+{"last_update":"1174924714", "numofapproved":"1", "id":"524"},
+{"last_update":"1171962179", "numofapproved":"1", "id":"108"},
+{"last_update":"1172522401", "numofapproved":"1", "id":"205"},
+{"last_update":"1174299349", "numofapproved":"1", "id":"362"},
+{"last_update":"1174899291", "numofapproved":"1", "id":"500"},
+{"last_update":"1175617661", "numofapproved":"1", "id":"688"},
+{"last_update":"1176302948", "numofapproved":"1", "id":"881"},
+{"last_update":"1176467393", "numofapproved":"1", "id":"893"},
+{"last_update":"1176737599", "numofapproved":"1", "id":"982"},
+{"last_update":"1171465517", "numofapproved":"1", "id":"50"},
+{"last_update":"1171924670", "numofapproved":"1", "id":"107"},
+{"last_update":"1173880505", "numofapproved":"1", "id":"317"},
+{"last_update":"1173889350", "numofapproved":"1", "id":"329"},
+{"last_update":"1173889557", "numofapproved":"1", "id":"332"},
+{"last_update":"1176391285", "numofapproved":"1", "id":"892"},
+{"last_update":"1176673529", "numofapproved":"1", "id":"981"},
+{"last_update":"1171643442", "numofapproved":"1", "id":"69"},
+{"last_update":"1172226841", "numofapproved":"1", "id":"182"},
+{"last_update":"1174899475", "numofapproved":"1", "id":"506"},
+{"last_update":"1174915327", "numofapproved":"1", "id":"521"},
+{"last_update":"1176194461", "numofapproved":"1", "id":"821"},
+{"last_update":"1172013837", "numofapproved":"1", "id":"132"},
+{"last_update":"1172184974", "numofapproved":"1", "id":"177"},
+{"last_update":"1175777908", "numofapproved":"1", "id":"674"},
+{"last_update":"1173460745", "numofapproved":"1", "id":"281"},
+{"last_update":"1174401746", "numofapproved":"1", "id":"402"},
+{"last_update":"1171274691", "numofapproved":"1", "id":"5"},
+{"last_update":"1171799314", "numofapproved":"1", "id":"78"},
+{"last_update":"1171979089", "numofapproved":"1", "id":"127"},
+{"last_update":"1172503571", "numofapproved":"1", "id":"197"},
+{"last_update":"1174301365", "numofapproved":"1", "id":"391"},
+{"last_update":"1174301259", "numofapproved":"1", "id":"385"},
+{"last_update":"1174899163", "numofapproved":"1", "id":"494"},
+{"last_update":"1174933167", "numofapproved":"1", "id":"534"},
+{"last_update":"1176139704", "numofapproved":"1", "id":"808"},
+{"last_update":"1175502855", "numofapproved":"1", "id":"603"},
+{"last_update":"1173721122", "numofapproved":"1", "id":"303"},
+{"last_update":"1173809079", "numofapproved":"1", "id":"311"},
+{"last_update":"1174734352", "numofapproved":"1", "id":"461"},
+{"last_update":"1174898917", "numofapproved":"1", "id":"482"},
+{"last_update":"1174899374", "numofapproved":"1", "id":"503"},
+{"last_update":"1176392495", "numofapproved":"1", "id":"903"},
+{"last_update":"1176829535", "numofapproved":"1", "id":"987"},
+{"last_update":"1173889385", "numofapproved":"1", "id":"330"},
+{"last_update":"1175869070", "numofapproved":"1", "id":"783"},
+{"last_update":"1177510634", "numofapproved":"1", "id":"1042"},
+{"last_update":"1177585810", "numofapproved":"1", "id":"1062"},
+{"last_update":"1178648303", "numofapproved":"1", "id":"1309"},
+{"last_update":"1178883682", "numofapproved":"1", "id":"1363"},
+{"last_update":"1179239792", "numofapproved":"1", "id":"1402"},
+{"last_update":"1179997715", "numofapproved":"1", "id":"1644"},
+{"last_update":"1180031289", "numofapproved":"1", "id":"1654"},
+{"last_update":"1180440758", "numofapproved":"1", "id":"1921"},
+{"last_update":"1180972413", "numofapproved":"1", "id":"2221"},
+{"last_update":"1181032741", "numofapproved":"1", "id":"2261"},
+{"last_update":"1181198104", "numofapproved":"1", "id":"2401"},
+{"last_update":"1181237541", "numofapproved":"1", "id":"2581"},
+{"last_update":"1181293731", "numofapproved":"1", "id":"2641"},
+{"last_update":"1182231158", "numofapproved":"1", "id":"3204"},
+{"last_update":"1177668412", "numofapproved":"1", "id":"1121"},
+{"last_update":"1178713554", "numofapproved":"1", "id":"1342"},
+{"last_update":"1179239886", "numofapproved":"1", "id":"1404"},
+{"last_update":"1184766561", "numofapproved":"1", "id":"4961"},
+{"last_update":"1185293883", "numofapproved":"1", "id":"5341"},
+{"last_update":"1185781181", "numofapproved":"1", "id":"5761"},
+{"last_update":"1185898126", "numofapproved":"1", "id":"5862"},
+{"last_update":"1186290486", "numofapproved":"1", "id":"6164"},
+{"last_update":"1186260193", "numofapproved":"1", "id":"6162"},
+{"last_update":"1186305362", "numofapproved":"1", "id":"6201"},
+{"last_update":"1187024035", "numofapproved":"1", "id":"6563"},
+{"last_update":"1187245873", "numofapproved":"1", "id":"6761"},
+{"last_update":"1187765176", "numofapproved":"1", "id":"7142"},
+{"last_update":"1187872548", "numofapproved":"1", "id":"7343"},
+{"last_update":"1188774634", "numofapproved":"1", "id":"8061"},
+{"last_update":"1188838929", "numofapproved":"1", "id":"8181"},
+{"last_update":"1189608461", "numofapproved":"1", "id":"8881"},
+{"last_update":"1189667694", "numofapproved":"1", "id":"8921"},
+{"last_update":"1179747423", "numofapproved":"1", "id":"1541"},
+{"last_update":"1181142187", "numofapproved":"1", "id":"2381"},
+{"last_update":"1185965227", "numofapproved":"1", "id":"5921"},
+{"last_update":"1190476977", "numofapproved":"1", "id":"9761"},
+{"last_update":"1190648889", "numofapproved":"1", "id":"9961"},
+{"last_update":"1190824195", "numofapproved":"1", "id":"10381"},
+{"last_update":"1190825530", "numofapproved":"1", "id":"10401"},
+{"last_update":"1190894398", "numofapproved":"1", "id":"10501"},
+{"last_update":"1178271031", "numofapproved":"1", "id":"1242"},
+{"last_update":"1178878052", "numofapproved":"1", "id":"1359"},
+{"last_update":"1178967516", "numofapproved":"1", "id":"1364"},
+{"last_update":"1180018261", "numofapproved":"1", "id":"1652"},
+{"last_update":"1180107922", "numofapproved":"1", "id":"1841"},
+{"last_update":"1180514196", "numofapproved":"1", "id":"1941"},
+{"last_update":"1181901023", "numofapproved":"1", "id":"3082"},
+{"last_update":"1182417878", "numofapproved":"1", "id":"3361"},
+{"last_update":"1182785340", "numofapproved":"1", "id":"3521"},
+{"last_update":"1183485766", "numofapproved":"1", "id":"4101"},
+{"last_update":"1189526136", "numofapproved":"1", "id":"8803"},
+{"last_update":"1191446636", "numofapproved":"1", "id":"11185"},
+{"last_update":"1191489743", "numofapproved":"1", "id":"11241"},
+{"last_update":"1191903141", "numofapproved":"1", "id":"11882"},
+{"last_update":"1191940049", "numofapproved":"1", "id":"11941"},
+{"last_update":"1179239857", "numofapproved":"1", "id":"1403"},
+{"last_update":"1185799202", "numofapproved":"1", "id":"5801"},
+{"last_update":"1190924823", "numofapproved":"1", "id":"10562"},
+{"last_update":"1191410783", "numofapproved":"1", "id":"11065"},
+{"last_update":"1192031578", "numofapproved":"1", "id":"12121"},
+{"last_update":"1192431234", "numofapproved":"1", "id":"12562"},
+{"last_update":"1192609228", "numofapproved":"1", "id":"12802"},
+{"last_update":"1192742243", "numofapproved":"1", "id":"13161"},
+{"last_update":"1192942532", "numofapproved":"1", "id":"13201"},
+{"last_update":"1193386303", "numofapproved":"1", "id":"13962"},
+{"last_update":"1193406158", "numofapproved":"1", "id":"14121"},
+{"last_update":"1193418273", "numofapproved":"1", "id":"14201"},
+{"last_update":"1193519213", "numofapproved":"1", "id":"14281"},
+{"last_update":"1193666593", "numofapproved":"1", "id":"14401"},
+{"last_update":"1193733296", "numofapproved":"1", "id":"14421"},
+{"last_update":"1193760981", "numofapproved":"1", "id":"14481"},
+{"last_update":"1182436569", "numofapproved":"1", "id":"3422"},
+{"last_update":"1184012598", "numofapproved":"1", "id":"4481"},
+{"last_update":"1189715279", "numofapproved":"1", "id":"8981"},
+{"last_update":"1192528903", "numofapproved":"1", "id":"12701"},
+{"last_update":"1194246273", "numofapproved":"1", "id":"14901"},
+{"last_update":"1194354217", "numofapproved":"1", "id":"14888"},
+{"last_update":"1194366787", "numofapproved":"1", "id":"14891"},
+{"last_update":"1194445768", "numofapproved":"1", "id":"15104"},
+{"last_update":"1194467580", "numofapproved":"1", "id":"15107"},
+{"last_update":"1194508237", "numofapproved":"1", "id":"15262"},
+{"last_update":"1194635341", "numofapproved":"1", "id":"15581"},
+{"last_update":"1194635508", "numofapproved":"1", "id":"15582"},
+{"last_update":"1179214538", "numofapproved":"1", "id":"1386"},
+{"last_update":"1186433530", "numofapproved":"1", "id":"6167"},
+{"last_update":"1187853435", "numofapproved":"1", "id":"7321"},
+{"last_update":"1187972012", "numofapproved":"1", "id":"7421"},
+{"last_update":"1188895906", "numofapproved":"1", "id":"8201"},
+{"last_update":"1190284020", "numofapproved":"1", "id":"9561"},
+{"last_update":"1190924163", "numofapproved":"1", "id":"10561"},
+{"last_update":"1192529770", "numofapproved":"1", "id":"12663"},
+{"last_update":"1192536538", "numofapproved":"1", "id":"12666"},
+{"last_update":"1193269090", "numofapproved":"1", "id":"13741"},
+{"last_update":"1193428819", "numofapproved":"1", "id":"14221"},
+{"last_update":"1193860091", "numofapproved":"1", "id":"14521"},
+{"last_update":"1193909426", "numofapproved":"1", "id":"14526"},
+{"last_update":"1194533708", "numofapproved":"1", "id":"15321"},
+{"last_update":"1179822723", "numofapproved":"1", "id":"1601"},
+{"last_update":"1179842248", "numofapproved":"1", "id":"1666"},
+{"last_update":"1182412362", "numofapproved":"1", "id":"3352"},
+{"last_update":"1185980065", "numofapproved":"1", "id":"5961"},
+{"last_update":"1186751100", "numofapproved":"1", "id":"6385"},
+{"last_update":"1187202714", "numofapproved":"1", "id":"6721"},
+{"last_update":"1187601864", "numofapproved":"1", "id":"6923"},
+{"last_update":"1191490727", "numofapproved":"1", "id":"11281"},
+{"last_update":"1194449840", "numofapproved":"1", "id":"15161"},
+{"last_update":"1180028166", "numofapproved":"1", "id":"1781"},
+{"last_update":"1185025939", "numofapproved":"1", "id":"5201"},
+{"last_update":"1192454400", "numofapproved":"1", "id":"12621"},
+{"last_update":"1193414234", "numofapproved":"1", "id":"14141"},
+{"last_update":"1194270682", "numofapproved":"1", "id":"14961"},
+{"last_update":"1184061669", "numofapproved":"1", "id":"4561"},
+{"last_update":"1186161284", "numofapproved":"1", "id":"6141"},
+{"last_update":"1187714492", "numofapproved":"1", "id":"7061"},
+{"last_update":"1187893562", "numofapproved":"1", "id":"7361"},
+{"last_update":"1190815311", "numofapproved":"1", "id":"10301"},
+{"last_update":"1193388120", "numofapproved":"1", "id":"13951"},
+{"last_update":"1195239956", "numofapproved":"1", "id":"17041"},
+{"last_update":"1179147467", "numofapproved":"1", "id":"1381"},
+{"last_update":"1182346611", "numofapproved":"1", "id":"3341"},
+{"last_update":"1184267506", "numofapproved":"1", "id":"4802"},
+{"last_update":"1192047087", "numofapproved":"1", "id":"12161"},
+{"last_update":"1192198948", "numofapproved":"1", "id":"12441"},
+{"last_update":"1193208717", "numofapproved":"1", "id":"13528"},
+{"last_update":"1194907182", "numofapproved":"1", "id":"16001"},
+{"last_update":"1179153020", "numofapproved":"1", "id":"1385"},
+{"last_update":"1179835655", "numofapproved":"1", "id":"1641"},
+{"last_update":"1181234739", "numofapproved":"1", "id":"2542"},
+{"last_update":"1182356477", "numofapproved":"1", "id":"3343"},
+{"last_update":"1182418583", "numofapproved":"1", "id":"3381"},
+{"last_update":"1184568502", "numofapproved":"1", "id":"4905"},
+{"last_update":"1189151603", "numofapproved":"1", "id":"8581"},
+{"last_update":"1191595695", "numofapproved":"1", "id":"11621"},
+{"last_update":"1193105000", "numofapproved":"1", "id":"13421"},
+{"last_update":"1195104657", "numofapproved":"1", "id":"16701"}],
+"request_timestamp":1206363392.08521, "request_call":"requestDetails",
+"instance":"tbedi", "call_time":"0.10059", "request_date":"2008-03-2412:56:32 UTC", "request_url":"http://cmsdoc.cern.ch/cms/test/aprom/phedex/dev/gowri/datasvc/tbedi/requestDetails?format=json"}}
+"""
+
+from jsonParser import jsonObject
+
+data = jsonObject.parseString(s)
+
+#~ from pprint import pprint
+#~ pprint( data[0].asList() )
+#~ print
+#~ print data.dump()
+print(data.phedex.call_time)
+print(data.phedex.instance)
+print(data.phedex.request_call)
+print(len(data.phedex.request))
+for req in data.phedex.request[:10]:
+ #~ print req.dump()
+ print("-", req.id, req.last_update)
diff --git a/examples/removeLineBreaks.py b/examples/removeLineBreaks.py
new file mode 100644
index 0000000..ba4b498
--- /dev/null
+++ b/examples/removeLineBreaks.py
@@ -0,0 +1,45 @@
+# removeLineBreaks.py
+#
+# Demonstration of the pyparsing module, converting text files
+# with hard line-breaks to text files with line breaks only
+# between paragraphs. (Helps when converting downloads from Project
+# Gutenberg - http://www.gutenberg.org - to import to word processing apps
+# that can reformat paragraphs once hard line-breaks are removed.)
+#
+# Uses parse actions and transformString to remove unwanted line breaks,
+# and to double up line breaks between paragraphs.
+#
+# Copyright 2006, by Paul McGuire
+#
+from pyparsing import *
+
+# define an expression for the body of a line of text - use a parse action to reject any
+# empty lines
+def mustBeNonBlank(s,l,t):
+ if not t[0]:
+ raise ParseException(s,l,"line body can't be empty")
+lineBody = SkipTo(lineEnd).setParseAction(mustBeNonBlank)
+
+# now define a line with a trailing lineEnd, to be replaced with a space character
+textLine = lineBody + Suppress(lineEnd).setParseAction(replaceWith(" "))
+
+# define a paragraph, with a separating lineEnd, to be replaced with a double newline
+para = OneOrMore(textLine) + Suppress(lineEnd).setParseAction(replaceWith("\n\n"))
+
+
+# run a test
+test = """
+ Now is the
+ time for
+ all
+ good men
+ to come to
+
+ the aid of their
+ country.
+"""
+print(para.transformString(test))
+
+# process an entire file
+z = para.transformString(file("Successful Methods of Public Speaking.txt").read())
+file("Successful Methods of Public Speaking(2).txt","w").write(z)
diff --git a/examples/romanNumerals.py b/examples/romanNumerals.py
new file mode 100644
index 0000000..27361f0
--- /dev/null
+++ b/examples/romanNumerals.py
@@ -0,0 +1,74 @@
+# romanNumerals.py
+#
+# Copyright (c) 2006, Paul McGuire
+#
+
+from pyparsing import *
+
+def romanNumeralLiteral(numeralString, value):
+ return Literal(numeralString).setParseAction(replaceWith(value))
+
+one = romanNumeralLiteral("I",1)
+four = romanNumeralLiteral("IV",4)
+five = romanNumeralLiteral("V",5)
+nine = romanNumeralLiteral("IX",9)
+ten = romanNumeralLiteral("X",10)
+forty = romanNumeralLiteral("XL",40)
+fifty = romanNumeralLiteral("L",50)
+ninety = romanNumeralLiteral("XC",90)
+onehundred = romanNumeralLiteral("C",100)
+fourhundred = romanNumeralLiteral("CD",400)
+fivehundred = romanNumeralLiteral("D",500)
+ninehundred = romanNumeralLiteral("CM",900)
+onethousand = romanNumeralLiteral("M",1000)
+
+numeral = ( onethousand | ninehundred | fivehundred | fourhundred |
+ onehundred | ninety | fifty | forty | ten | nine | five |
+ four | one ).leaveWhitespace()
+
+romanNumeral = OneOrMore(numeral).setParseAction( lambda s,l,t : sum(t) )
+
+# unit tests
+def makeRomanNumeral(n):
+ def addDigit(n,limit,c,s):
+ n -= limit
+ s += c
+ return n,s
+
+ ret = ""
+ while n >= 1000: n,ret = addDigit(n,1000,"M",ret)
+ while n >= 900: n,ret = addDigit(n, 900,"CM",ret)
+ while n >= 500: n,ret = addDigit(n, 500,"D",ret)
+ while n >= 400: n,ret = addDigit(n, 400,"CD",ret)
+ while n >= 100: n,ret = addDigit(n, 100,"C",ret)
+ while n >= 90: n,ret = addDigit(n, 90,"XC",ret)
+ while n >= 50: n,ret = addDigit(n, 50,"L",ret)
+ while n >= 40: n,ret = addDigit(n, 40,"XL",ret)
+ while n >= 10: n,ret = addDigit(n, 10,"X",ret)
+ while n >= 9: n,ret = addDigit(n, 9,"IX",ret)
+ while n >= 5: n,ret = addDigit(n, 5,"V",ret)
+ while n >= 4: n,ret = addDigit(n, 4,"IV",ret)
+ while n >= 1: n,ret = addDigit(n, 1,"I",ret)
+ return ret
+tests = " ".join(makeRomanNumeral(i) for i in range(1,5000+1))
+
+expected = 1
+for t,s,e in romanNumeral.scanString(tests):
+ if t[0] != expected:
+ print("{} {} {}".format("==>", t, tests[s:e]))
+ expected += 1
+
+def test(rn):
+ print("{} -> {}".format(rn, romanNumeral.parseString(rn)[0]))
+test("XVI")
+test("XXXIX")
+test("XIV")
+test("XIX")
+test("MCMLXXX")
+test("MMVI")
+
+
+
+
+
+
diff --git a/examples/scanExamples.py b/examples/scanExamples.py
new file mode 100644
index 0000000..24ae0e7
--- /dev/null
+++ b/examples/scanExamples.py
@@ -0,0 +1,75 @@
+#
+# scanExamples.py
+#
+# Illustration of using pyparsing's scanString,transformString, and searchString methods
+#
+# Copyright (c) 2004, 2006 Paul McGuire
+#
+from pyparsing import Word, alphas, alphanums, Literal, restOfLine, OneOrMore, \
+ empty, Suppress, replaceWith
+
+# simulate some C++ code
+testData = """
+#define MAX_LOCS=100
+#define USERNAME = "floyd"
+#define PASSWORD = "swordfish"
+
+a = MAX_LOCS;
+CORBA::initORB("xyzzy", USERNAME, PASSWORD );
+
+"""
+
+#################
+print("Example of an extractor")
+print("----------------------")
+
+# simple grammar to match #define's
+ident = Word(alphas, alphanums+"_")
+macroDef = Literal("#define") + ident.setResultsName("name") + "=" + restOfLine.setResultsName("value")
+for t,s,e in macroDef.scanString( testData ):
+ print(t.name,":", t.value)
+
+# or a quick way to make a dictionary of the names and values
+# (return only key and value tokens, and construct dict from key-value pairs)
+# - empty ahead of restOfLine advances past leading whitespace, does implicit lstrip during parsing
+macroDef = Suppress("#define") + ident + Suppress("=") + empty + restOfLine
+macros = dict(list(macroDef.searchString(testData)))
+print("macros =", macros)
+print()
+
+
+#################
+print("Examples of a transformer")
+print("----------------------")
+
+# convert C++ namespaces to mangled C-compatible names
+scopedIdent = ident + OneOrMore( Literal("::").suppress() + ident )
+scopedIdent.setParseAction(lambda t: "_".join(t))
+
+print("(replace namespace-scoped names with C-compatible names)")
+print(scopedIdent.transformString( testData ))
+
+
+# or a crude pre-processor (use parse actions to replace matching text)
+def substituteMacro(s,l,t):
+ if t[0] in macros:
+ return macros[t[0]]
+ident.setParseAction( substituteMacro )
+ident.ignore(macroDef)
+
+print("(simulate #define pre-processor)")
+print(ident.transformString( testData ))
+
+
+
+#################
+print("Example of a stripper")
+print("----------------------")
+
+from pyparsing import dblQuotedString, LineStart
+
+# remove all string macro definitions (after extracting to a string resource table?)
+stringMacroDef = Literal("#define") + ident + "=" + dblQuotedString + LineStart()
+stringMacroDef.setParseAction( replaceWith("") )
+
+print(stringMacroDef.transformString( testData ))
diff --git a/examples/scanYahoo.py b/examples/scanYahoo.py
new file mode 100644
index 0000000..825c169
--- /dev/null
+++ b/examples/scanYahoo.py
@@ -0,0 +1,14 @@
+from pyparsing import makeHTMLTags,SkipTo,htmlComment
+import urllib.request, urllib.parse, urllib.error
+
+serverListPage = urllib.request.urlopen( "http://www.yahoo.com" )
+htmlText = serverListPage.read()
+serverListPage.close()
+
+aStart,aEnd = makeHTMLTags("A")
+
+link = aStart + SkipTo(aEnd).setResultsName("link") + aEnd
+link.ignore(htmlComment)
+
+for toks,start,end in link.scanString(htmlText):
+ print(toks.link, "->", toks.startA.href) \ No newline at end of file
diff --git a/examples/searchParserAppDemo.py b/examples/searchParserAppDemo.py
new file mode 100644
index 0000000..259e0e3
--- /dev/null
+++ b/examples/searchParserAppDemo.py
@@ -0,0 +1,34 @@
+from searchparser import SearchQueryParser
+
+products = [ "grape juice", "grape jelly", "orange juice", "orange jujubees",
+ "strawberry jam", "prune juice", "prune butter", "orange marmalade",
+ "grapefruit juice" ]
+
+class FruitSearchParser(SearchQueryParser):
+ def GetWord(self, word):
+ return set( p for p in products if p.startswith(word + " ") )
+
+ def GetWordWildcard(self, word):
+ return set( p for p in products if p.startswith(word[:-1]) )
+
+ def GetQuotes(self, search_string, tmp_result):
+ result = Set()
+ # I have no idea how to use this feature...
+ return result
+
+ def GetNot(self, not_set):
+ return set( products ) - not_set
+
+
+parser = FruitSearchParser()
+
+tests = """\
+ grape or orange
+ grape*
+ not(grape*)
+ prune and grape""".splitlines()
+
+for t in tests:
+ print(t.strip())
+ print(parser.Parse(t))
+ print('') \ No newline at end of file
diff --git a/examples/searchparser.py b/examples/searchparser.py
new file mode 100644
index 0000000..e5b40a7
--- /dev/null
+++ b/examples/searchparser.py
@@ -0,0 +1,292 @@
+"""Search query parser
+
+version 2006-03-09
+
+This search query parser uses the excellent Pyparsing module
+(http://pyparsing.sourceforge.net/) to parse search queries by users.
+It handles:
+
+* 'and', 'or' and implicit 'and' operators;
+* parentheses;
+* quoted strings;
+* wildcards at the end of a search term (help*);
+
+Requirements:
+* Python
+* Pyparsing
+
+If you run this script, it will perform a number of tests. To use is as a
+module, you should use inheritance on the SearchQueryParser class and overwrite
+the Get... methods. The ParserTest class gives a very simple example of how this
+could work.
+
+-------------------------------------------------------------------------------
+Copyright (c) 2006, Estrate, the Netherlands
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+* Neither the name of Estrate nor the names of its contributors may be used
+ to endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+CONTRIBUTORS:
+- Steven Mooij
+- Rudolph Froger
+- Paul McGuire
+
+TODO:
+- add more docs
+- ask someone to check my English texts
+- add more kinds of wildcards ('*' at the beginning and '*' inside a word)?
+"""
+from pyparsing import Word, alphanums, Keyword, Group, Combine, Forward, Suppress, Optional, OneOrMore, oneOf
+
+class SearchQueryParser:
+
+ def __init__(self):
+ self._methods = {
+ 'and': self.evaluateAnd,
+ 'or': self.evaluateOr,
+ 'not': self.evaluateNot,
+ 'parenthesis': self.evaluateParenthesis,
+ 'quotes': self.evaluateQuotes,
+ 'word': self.evaluateWord,
+ 'wordwildcard': self.evaluateWordWildcard,
+ }
+ self._parser = self.parser()
+
+ def parser(self):
+ """
+ This function returns a parser.
+ The grammar should be like most full text search engines (Google, Tsearch, Lucene).
+
+ Grammar:
+ - a query consists of alphanumeric words, with an optional '*' wildcard
+ at the end of a word
+ - a sequence of words between quotes is a literal string
+ - words can be used together by using operators ('and' or 'or')
+ - words with operators can be grouped with parenthesis
+ - a word or group of words can be preceded by a 'not' operator
+ - the 'and' operator precedes an 'or' operator
+ - if an operator is missing, use an 'and' operator
+ """
+ operatorOr = Forward()
+
+ operatorWord = Group(Combine(Word(alphanums) + Suppress('*'))).setResultsName('wordwildcard') | \
+ Group(Word(alphanums)).setResultsName('word')
+
+ operatorQuotesContent = Forward()
+ operatorQuotesContent << (
+ (operatorWord + operatorQuotesContent) | operatorWord
+ )
+
+ operatorQuotes = Group(
+ Suppress('"') + operatorQuotesContent + Suppress('"')
+ ).setResultsName("quotes") | operatorWord
+
+ operatorParenthesis = Group(
+ (Suppress("(") + operatorOr + Suppress(")"))
+ ).setResultsName("parenthesis") | operatorQuotes
+
+ operatorNot = Forward()
+ operatorNot << (Group(
+ Suppress(Keyword("not", caseless=True)) + operatorNot
+ ).setResultsName("not") | operatorParenthesis)
+
+ operatorAnd = Forward()
+ operatorAnd << (Group(
+ operatorNot + Suppress(Keyword("and", caseless=True)) + operatorAnd
+ ).setResultsName("and") | Group(
+ operatorNot + OneOrMore(~oneOf("and or") + operatorAnd)
+ ).setResultsName("and") | operatorNot)
+
+ operatorOr << (Group(
+ operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr
+ ).setResultsName("or") | operatorAnd)
+
+ return operatorOr.parseString
+
+ def evaluateAnd(self, argument):
+ return self.evaluate(argument[0]).intersection(self.evaluate(argument[1]))
+
+ def evaluateOr(self, argument):
+ return self.evaluate(argument[0]).union(self.evaluate(argument[1]))
+
+ def evaluateNot(self, argument):
+ return self.GetNot(self.evaluate(argument[0]))
+
+ def evaluateParenthesis(self, argument):
+ return self.evaluate(argument[0])
+
+ def evaluateQuotes(self, argument):
+ """Evaluate quoted strings
+
+ First is does an 'and' on the indidual search terms, then it asks the
+ function GetQuoted to only return the subset of ID's that contain the
+ literal string.
+ """
+ r = set()
+ search_terms = []
+ for item in argument:
+ search_terms.append(item[0])
+ if len(r) == 0:
+ r = self.evaluate(item)
+ else:
+ r = r.intersection(self.evaluate(item))
+ return self.GetQuotes(' '.join(search_terms), r)
+
+ def evaluateWord(self, argument):
+ return self.GetWord(argument[0])
+
+ def evaluateWordWildcard(self, argument):
+ return self.GetWordWildcard(argument[0])
+
+ def evaluate(self, argument):
+ return self._methods[argument.getName()](argument)
+
+ def Parse(self, query):
+ #print self._parser(query)[0]
+ return self.evaluate(self._parser(query)[0])
+
+ def GetWord(self, word):
+ return set()
+
+ def GetWordWildcard(self, word):
+ return set()
+
+ def GetQuotes(self, search_string, tmp_result):
+ return set()
+
+ def GetNot(self, not_set):
+ return set().difference(not_set)
+
+
+class ParserTest(SearchQueryParser):
+ """Tests the parser with some search queries
+ tests containts a dictionary with tests and expected results.
+ """
+ tests = {
+ 'help': set([1, 2, 4, 5]),
+ 'help or hulp': set([1, 2, 3, 4, 5]),
+ 'help and hulp': set([2]),
+ 'help hulp': set([2]),
+ 'help and hulp or hilp': set([2, 3, 4]),
+ 'help or hulp and hilp': set([1, 2, 3, 4, 5]),
+ 'help or hulp or hilp or halp': set([1, 2, 3, 4, 5, 6]),
+ '(help or hulp) and (hilp or halp)': set([3, 4, 5]),
+ 'help and (hilp or halp)': set([4, 5]),
+ '(help and (hilp or halp)) or hulp': set([2, 3, 4, 5]),
+ 'not help': set([3, 6, 7, 8]),
+ 'not hulp and halp': set([5, 6]),
+ 'not (help and halp)': set([1, 2, 3, 4, 6, 7, 8]),
+ '"help me please"': set([2]),
+ '"help me please" or hulp': set([2, 3]),
+ '"help me please" or (hulp and halp)': set([2]),
+ 'help*': set([1, 2, 4, 5, 8]),
+ 'help or hulp*': set([1, 2, 3, 4, 5]),
+ 'help* and hulp': set([2]),
+ 'help and hulp* or hilp': set([2, 3, 4]),
+ 'help* or hulp or hilp or halp': set([1, 2, 3, 4, 5, 6, 8]),
+ '(help or hulp*) and (hilp* or halp)': set([3, 4, 5]),
+ 'help* and (hilp* or halp*)': set([4, 5]),
+ '(help and (hilp* or halp)) or hulp*': set([2, 3, 4, 5]),
+ 'not help* and halp': set([6]),
+ 'not (help* and helpe*)': set([1, 2, 3, 4, 5, 6, 7]),
+ '"help* me please"': set([2]),
+ '"help* me* please" or hulp*': set([2, 3]),
+ '"help me please*" or (hulp and halp)': set([2]),
+ '"help me please" not (hulp and halp)': set([2]),
+ '"help me please" hulp': set([2]),
+ 'help and hilp and not holp': set([4]),
+ 'help hilp not holp': set([4]),
+ 'help hilp and not holp': set([4]),
+ }
+
+ docs = {
+ 1: 'help',
+ 2: 'help me please hulp',
+ 3: 'hulp hilp',
+ 4: 'help hilp',
+ 5: 'halp thinks he needs help',
+ 6: 'he needs halp',
+ 7: 'nothing',
+ 8: 'helper',
+ }
+
+ index = {
+ 'help': set((1, 2, 4, 5)),
+ 'me': set((2,)),
+ 'please': set((2,)),
+ 'hulp': set((2, 3,)),
+ 'hilp': set((3, 4,)),
+ 'halp': set((5, 6,)),
+ 'thinks': set((5,)),
+ 'he': set((5, 6,)),
+ 'needs': set((5, 6,)),
+ 'nothing': set((7,)),
+ 'helper': set((8,)),
+ }
+
+ def GetWord(self, word):
+ if (word in self.index):
+ return self.index[word]
+ else:
+ return set()
+
+ def GetWordWildcard(self, word):
+ result = set()
+ for item in list(self.index.keys()):
+ if word == item[0:len(word)]:
+ result = result.union(self.index[item])
+ return result
+
+ def GetQuotes(self, search_string, tmp_result):
+ result = set()
+ for item in tmp_result:
+ if self.docs[item].count(search_string):
+ result.add(item)
+ return result
+
+ def GetNot(self, not_set):
+ all = set(list(self.docs.keys()))
+ return all.difference(not_set)
+
+ def Test(self):
+ all_ok = True
+ for item in list(self.tests.keys()):
+ print(item)
+ r = self.Parse(item)
+ e = self.tests[item]
+ print('Result: %s' % r)
+ print('Expect: %s' % e)
+ if e == r:
+ print('Test OK')
+ else:
+ all_ok = False
+ print('>>>>>>>>>>>>>>>>>>>>>>Test ERROR<<<<<<<<<<<<<<<<<<<<<')
+ print('')
+ return all_ok
+
+if __name__=='__main__':
+ if ParserTest().Test():
+ print('All tests OK')
+ else:
+ print('One or more tests FAILED')
diff --git a/examples/select_parser.py b/examples/select_parser.py
new file mode 100644
index 0000000..f969f02
--- /dev/null
+++ b/examples/select_parser.py
@@ -0,0 +1,126 @@
+# select_parser.py
+# Copyright 2010, Paul McGuire
+#
+# a simple SELECT statement parser, taken from SQLite's SELECT statement
+# definition at http://www.sqlite.org/lang_select.html
+#
+from pyparsing import *
+ParserElement.enablePackrat()
+
+LPAR,RPAR,COMMA = map(Suppress,"(),")
+select_stmt = Forward().setName("select statement")
+
+# keywords
+(UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER,
+ CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY,
+ HAVING, ORDER, BY, LIMIT, OFFSET, OR) = map(CaselessKeyword, """UNION, ALL, AND, INTERSECT,
+ EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT,
+ DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY, LIMIT, OFFSET, OR""".replace(",","").split())
+(CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS,
+ COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE,
+ CURRENT_TIMESTAMP) = map(CaselessKeyword, """CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE,
+ END, CASE, WHEN, THEN, EXISTS, COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE,
+ CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP""".replace(",","").split())
+keyword = MatchFirst((UNION, ALL, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER,
+ CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY,
+ HAVING, ORDER, BY, LIMIT, OFFSET, CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS,
+ COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE,
+ CURRENT_TIMESTAMP))
+
+identifier = ~keyword + Word(alphas, alphanums+"_")
+collation_name = identifier.copy()
+column_name = identifier.copy()
+column_alias = identifier.copy()
+table_name = identifier.copy()
+table_alias = identifier.copy()
+index_name = identifier.copy()
+function_name = identifier.copy()
+parameter_name = identifier.copy()
+database_name = identifier.copy()
+
+# expression
+expr = Forward().setName("expression")
+
+integer = Regex(r"[+-]?\d+")
+numeric_literal = Regex(r"\d+(\.\d*)?([eE][+-]?\d+)?")
+string_literal = QuotedString("'")
+blob_literal = Regex(r"[xX]'[0-9A-Fa-f]+'")
+literal_value = ( numeric_literal | string_literal | blob_literal |
+ NULL | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP )
+bind_parameter = (
+ Word("?",nums) |
+ Combine(oneOf(": @ $") + parameter_name)
+ )
+type_name = oneOf("TEXT REAL INTEGER BLOB NULL")
+
+expr_term = (
+ CAST + LPAR + expr + AS + type_name + RPAR |
+ EXISTS + LPAR + select_stmt + RPAR |
+ function_name.setName("function_name") + LPAR + Optional("*" | delimitedList(expr)) + RPAR |
+ literal_value |
+ bind_parameter |
+ Combine(identifier+('.'+identifier)*(0,2)).setName("ident")
+ )
+
+UNARY,BINARY,TERNARY=1,2,3
+expr << infixNotation(expr_term,
+ [
+ (oneOf('- + ~') | NOT, UNARY, opAssoc.RIGHT),
+ (ISNULL | NOTNULL | NOT + NULL, UNARY, opAssoc.LEFT),
+ ('||', BINARY, opAssoc.LEFT),
+ (oneOf('* / %'), BINARY, opAssoc.LEFT),
+ (oneOf('+ -'), BINARY, opAssoc.LEFT),
+ (oneOf('<< >> & |'), BINARY, opAssoc.LEFT),
+ (oneOf('< <= > >='), BINARY, opAssoc.LEFT),
+ (oneOf('= == != <>') | IS | IN | LIKE | GLOB | MATCH | REGEXP, BINARY, opAssoc.LEFT),
+ ((BETWEEN,AND), TERNARY, opAssoc.LEFT),
+ (IN + LPAR + Group(select_stmt | delimitedList(expr)) + RPAR, UNARY, opAssoc.LEFT),
+ (AND, BINARY, opAssoc.LEFT),
+ (OR, BINARY, opAssoc.LEFT),
+ ])
+
+compound_operator = (UNION + Optional(ALL) | INTERSECT | EXCEPT)
+
+ordering_term = Group(expr('order_key') + Optional(COLLATE + collation_name('collate')) + Optional(ASC | DESC)('direction'))
+
+join_constraint = Group(Optional(ON + expr | USING + LPAR + Group(delimitedList(column_name)) + RPAR))
+
+join_op = COMMA | Group(Optional(NATURAL) + Optional(INNER | CROSS | LEFT + OUTER | LEFT | OUTER) + JOIN)
+
+join_source = Forward()
+single_source = ( (Group(database_name("database") + "." + table_name("table*")) | table_name("table*")) +
+ Optional(Optional(AS) + table_alias("table_alias*")) +
+ Optional(INDEXED + BY + index_name("name") | NOT + INDEXED)("index") |
+ (LPAR + select_stmt + RPAR + Optional(Optional(AS) + table_alias)) |
+ (LPAR + join_source + RPAR) )
+
+join_source << (Group(single_source + OneOrMore(join_op + single_source + join_constraint)) |
+ single_source)
+
+result_column = "*" | table_name + "." + "*" | Group(expr + Optional(Optional(AS) + column_alias))
+select_core = (SELECT + Optional(DISTINCT | ALL) + Group(delimitedList(result_column))("columns") +
+ Optional(FROM + join_source("from*")) +
+ Optional(WHERE + expr("where_expr")) +
+ Optional(GROUP + BY + Group(delimitedList(ordering_term)("group_by_terms")) +
+ Optional(HAVING + expr("having_expr"))))
+
+select_stmt << (select_core + ZeroOrMore(compound_operator + select_core) +
+ Optional(ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms")) +
+ Optional(LIMIT + (Group(expr + OFFSET + expr) | Group(expr + COMMA + expr) | expr)("limit")))
+
+tests = """\
+ select * from xyzzy where z > 100
+ select * from xyzzy where z > 100 order by zz
+ select * from xyzzy
+ select z.* from xyzzy
+ select a, b from test_table where 1=1 and b='yes'
+ select a, b from test_table where 1=1 and b in (select bb from foo)
+ select z.a, b from test_table where 1=1 and b in (select bb from foo)
+ select z.a, b from test_table where 1=1 and b in (select bb from foo) order by b,c desc,d
+ select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo)
+ select a, db.table.b as BBB from db.table where 1=1 and BBB='yes'
+ select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes'
+ select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' limit 50
+ """
+
+select_stmt.runTests(tests)
diff --git a/examples/sexpParser.py b/examples/sexpParser.py
new file mode 100644
index 0000000..963d153
--- /dev/null
+++ b/examples/sexpParser.py
@@ -0,0 +1,167 @@
+# sexpParser.py
+#
+# Demonstration of the pyparsing module, implementing a simple S-expression
+# parser.
+#
+# Updates:
+# November, 2011 - fixed errors in precedence of alternatives in simpleString;
+# fixed exception raised in verifyLen to properly signal the input string
+# and exception location so that markInputline works correctly; fixed
+# definition of decimal to accept a single '0' and optional leading '-'
+# sign; updated tests to improve parser coverage
+#
+# Copyright 2007-2011, by Paul McGuire
+#
+"""
+BNF reference: http://theory.lcs.mit.edu/~rivest/sexp.txt
+
+<sexp> :: <string> | <list>
+<string> :: <display>? <simple-string> ;
+<simple-string> :: <raw> | <token> | <base-64> | <hexadecimal> |
+ <quoted-string> ;
+<display> :: "[" <simple-string> "]" ;
+<raw> :: <decimal> ":" <bytes> ;
+<decimal> :: <decimal-digit>+ ;
+ -- decimal numbers should have no unnecessary leading zeros
+<bytes> -- any string of bytes, of the indicated length
+<token> :: <tokenchar>+ ;
+<base-64> :: <decimal>? "|" ( <base-64-char> | <whitespace> )* "|" ;
+<hexadecimal> :: "#" ( <hex-digit> | <white-space> )* "#" ;
+<quoted-string> :: <decimal>? <quoted-string-body>
+<quoted-string-body> :: "\"" <bytes> "\""
+<list> :: "(" ( <sexp> | <whitespace> )* ")" ;
+<whitespace> :: <whitespace-char>* ;
+<token-char> :: <alpha> | <decimal-digit> | <simple-punc> ;
+<alpha> :: <upper-case> | <lower-case> | <digit> ;
+<lower-case> :: "a" | ... | "z" ;
+<upper-case> :: "A" | ... | "Z" ;
+<decimal-digit> :: "0" | ... | "9" ;
+<hex-digit> :: <decimal-digit> | "A" | ... | "F" | "a" | ... | "f" ;
+<simple-punc> :: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ;
+<whitespace-char> :: " " | "\t" | "\r" | "\n" ;
+<base-64-char> :: <alpha> | <decimal-digit> | "+" | "/" | "=" ;
+<null> :: "" ;
+"""
+
+from pyparsing import *
+from base64 import b64decode
+import pprint
+
+def verifyLen(s,l,t):
+ t = t[0]
+ if t.len is not None:
+ t1len = len(t[1])
+ if t1len != t.len:
+ raise ParseFatalException(s,l,\
+ "invalid data of length %d, expected %s" % (t1len, t.len))
+ return t[1]
+
+# define punctuation literals
+LPAR, RPAR, LBRK, RBRK, LBRC, RBRC, VBAR = map(Suppress, "()[]{}|")
+
+decimal = Regex(r'0|[1-9]\d*').setParseAction(lambda t: int(t[0]))
+hexadecimal = ("#" + OneOrMore(Word(hexnums)) + "#")\
+ .setParseAction(lambda t: int("".join(t[1:-1]),16))
+bytes = Word(printables)
+raw = Group(decimal("len") + Suppress(":") + bytes).setParseAction(verifyLen)
+token = Word(alphanums + "-./_:*+=")
+base64_ = Group(Optional(decimal|hexadecimal,default=None)("len") + VBAR
+ + OneOrMore(Word( alphanums +"+/=" )).setParseAction(lambda t: b64decode("".join(t)))
+ + VBAR).setParseAction(verifyLen)
+
+qString = Group(Optional(decimal,default=None)("len") +
+ dblQuotedString.setParseAction(removeQuotes)).setParseAction(verifyLen)
+simpleString = base64_ | raw | decimal | token | hexadecimal | qString
+
+# extended definitions
+decimal = Regex(r'-?0|[1-9]\d*').setParseAction(lambda t: int(t[0]))
+real = Regex(r"[+-]?\d+\.\d*([eE][+-]?\d+)?").setParseAction(lambda tokens: float(tokens[0]))
+token = Word(alphanums + "-./_:*+=!<>")
+
+simpleString = real | base64_ | raw | decimal | token | hexadecimal | qString
+
+display = LBRK + simpleString + RBRK
+string_ = Optional(display) + simpleString
+
+sexp = Forward()
+sexpList = Group(LPAR + ZeroOrMore(sexp) + RPAR)
+sexp << ( string_ | sexpList )
+
+######### Test data ###########
+test00 = """(snicker "abc" (#03# |YWJj|))"""
+test01 = """(certificate
+ (issuer
+ (name
+ (public-key
+ rsa-with-md5
+ (e 15 |NFGq/E3wh9f4rJIQVXhS|)
+ (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|))
+ aid-committee))
+ (subject
+ (ref
+ (public-key
+ rsa-with-md5
+ (e |NFGq/E3wh9f4rJIQVXhS|)
+ (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|))
+ tom
+ mother))
+ (not-before "1997-01-01_09:00:00")
+ (not-after "1998-01-01_09:00:00")
+ (tag
+ (spend (account "12345678") (* numeric range "1" "1000"))))
+"""
+test02 = """(lambda (x) (* x x))"""
+test03 = """(def length
+ (lambda (x)
+ (cond
+ ((not x) 0)
+ ( t (+ 1 (length (cdr x))))
+ )
+ )
+)
+"""
+test04 = """(2:XX "abc" (#03# |YWJj|))"""
+test05 = """(if (is (window_name) "XMMS") (set_workspace 2))"""
+test06 = """(if
+ (and
+ (is (application_name) "Firefox")
+ (or
+ (contains (window_name) "Enter name of file to save to")
+ (contains (window_name) "Save As")
+ (contains (window_name) "Save Image")
+ ()
+ )
+ )
+ (geometry "+140+122")
+)
+"""
+test07 = """(defun factorial (x)
+ (if (zerop x) 1
+ (* x (factorial (- x 1)))))
+ """
+test51 = """(2:XX "abc" (#30# |YWJj|))"""
+test51error = """(3:XX "abc" (#30# |YWJj|))"""
+
+test52 = """
+ (and
+ (or (> uid 1000)
+ (!= gid 20)
+ )
+ (> quota 5.0e+03)
+ )
+ """
+
+# Run tests
+t = None
+alltests = [ locals()[t] for t in sorted(locals()) if t.startswith("test") ]
+
+for t in alltests:
+ print('-'*50)
+ print(t)
+ try:
+ sexpr = sexp.parseString(t, parseAll=True)
+ pprint.pprint(sexpr.asList())
+ except ParseFatalException as pfe:
+ print("Error:", pfe.msg)
+ print(pfe.markInputline('^'))
+ print()
diff --git a/examples/shapes.py b/examples/shapes.py
new file mode 100644
index 0000000..b5a0ebd
--- /dev/null
+++ b/examples/shapes.py
@@ -0,0 +1,64 @@
+# shapes.py
+#
+# A sample program showing how parse actions can convert parsed
+# strings into a data type or object.
+#
+# Copyright 2012, Paul T. McGuire
+#
+
+# define class hierarchy of Shape classes, with polymorphic area method
+class Shape(object):
+ def __init__(self, tokens):
+ self.__dict__.update(tokens.asDict())
+
+ def area(self):
+ raise NotImplementedException()
+
+ def __str__(self):
+ return "<%s>: %s" % (self.__class__.__name__, self.__dict__)
+
+class Square(Shape):
+ def area(self):
+ return self.side**2
+
+class Rectangle(Shape):
+ def area(self):
+ return self.width * self.height
+
+class Circle(Shape):
+ def area(self):
+ return 3.14159 * self.radius**2
+
+
+from pyparsing import *
+
+number = Regex(r'-?\d+(\.\d*)?').setParseAction(lambda t:float(t[0]))
+
+# Shape expressions:
+# square : S <centerx> <centery> <side>
+# rectangle: R <centerx> <centery> <width> <height>
+# circle : C <centerx> <centery> <diameter>
+
+squareDefn = "S" + number('centerx') + number('centery') + number('side')
+rectDefn = "R" + number('centerx') + number('centery') + number('width') + number('height')
+circleDefn = "C" + number('centerx') + number('centery') + number('diameter')
+
+squareDefn.setParseAction(Square)
+rectDefn.setParseAction(Rectangle)
+
+def computeRadius(tokens):
+ tokens['radius'] = tokens.diameter/2.0
+circleDefn.setParseAction(computeRadius, Circle)
+
+shapeExpr = squareDefn | rectDefn | circleDefn
+
+tests = """\
+C 0 0 100
+R 10 10 20 50
+S -1 5 10""".splitlines()
+
+for t in tests:
+ shape = shapeExpr.parseString(t)[0]
+ print(shape)
+ print("Area:", shape.area())
+ print()
diff --git a/examples/simpleArith.py b/examples/simpleArith.py
new file mode 100644
index 0000000..825956b
--- /dev/null
+++ b/examples/simpleArith.py
@@ -0,0 +1,67 @@
+#
+# simpleArith.py
+#
+# Example of defining an arithmetic expression parser using
+# the infixNotation helper method in pyparsing.
+#
+# Copyright 2006, by Paul McGuire
+#
+
+from pyparsing import *
+
+integer = Word(nums).setParseAction(lambda t:int(t[0]))
+variable = Word(alphas,exact=1)
+operand = integer | variable
+
+expop = Literal('^')
+signop = oneOf('+ -')
+multop = oneOf('* /')
+plusop = oneOf('+ -')
+factop = Literal('!')
+
+# To use the infixNotation helper:
+# 1. Define the "atom" operand term of the grammar.
+# For this simple grammar, the smallest operand is either
+# and integer or a variable. This will be the first argument
+# to the infixNotation method.
+# 2. Define a list of tuples for each level of operator
+# precendence. Each tuple is of the form
+# (opExpr, numTerms, rightLeftAssoc, parseAction), where
+# - opExpr is the pyparsing expression for the operator;
+# may also be a string, which will be converted to a Literal
+# - numTerms is the number of terms for this operator (must
+# be 1 or 2)
+# - rightLeftAssoc is the indicator whether the operator is
+# right or left associative, using the pyparsing-defined
+# constants opAssoc.RIGHT and opAssoc.LEFT.
+# - parseAction is the parse action to be associated with
+# expressions matching this operator expression (the
+# parse action tuple member may be omitted)
+# 3. Call infixNotation passing the operand expression and
+# the operator precedence list, and save the returned value
+# as the generated pyparsing expression. You can then use
+# this expression to parse input strings, or incorporate it
+# into a larger, more complex grammar.
+#
+expr = infixNotation( operand,
+ [("!", 1, opAssoc.LEFT),
+ ("^", 2, opAssoc.RIGHT),
+ (signop, 1, opAssoc.RIGHT),
+ (multop, 2, opAssoc.LEFT),
+ (plusop, 2, opAssoc.LEFT),]
+ )
+
+test = ["9 + 2 + 3",
+ "9 + 2 * 3",
+ "(9 + 2) * 3",
+ "(9 + -2) * 3",
+ "(9 + -2) * 3^2^2",
+ "(9! + -2) * 3^2^2",
+ "M*X + B",
+ "M*(X + B)",
+ "1+2*-3^4*5+-+-6",]
+for t in test:
+ print(t)
+ print(expr.parseString(t))
+ print('')
+
diff --git a/examples/simpleBool.py b/examples/simpleBool.py
new file mode 100644
index 0000000..5f355b7
--- /dev/null
+++ b/examples/simpleBool.py
@@ -0,0 +1,102 @@
+#
+# simpleBool.py
+#
+# Example of defining a boolean logic parser using
+# the operatorGrammar helper method in pyparsing.
+#
+# In this example, parse actions associated with each
+# operator expression will "compile" the expression
+# into BoolXXX class instances, which can then
+# later be evaluated for their boolean value.
+#
+# Copyright 2006, by Paul McGuire
+# Updated 2013-Sep-14 - improved Python 2/3 cross-compatibility
+#
+from pyparsing import infixNotation, opAssoc, Keyword, Word, alphas
+
+# define classes to be built at parse time, as each matching
+# expression type is parsed
+class BoolOperand(object):
+ def __init__(self,t):
+ self.label = t[0]
+ self.value = eval(t[0])
+ def __bool__(self):
+ return self.value
+ def __str__(self):
+ return self.label
+ __repr__ = __str__
+ __nonzero__ = __bool__
+
+class BoolBinOp(object):
+ def __init__(self,t):
+ self.args = t[0][0::2]
+ def __str__(self):
+ sep = " %s " % self.reprsymbol
+ return "(" + sep.join(map(str,self.args)) + ")"
+ def __bool__(self):
+ return self.evalop(bool(a) for a in self.args)
+ __nonzero__ = __bool__
+ __repr__ = __str__
+
+class BoolAnd(BoolBinOp):
+ reprsymbol = '&'
+ evalop = all
+
+class BoolOr(BoolBinOp):
+ reprsymbol = '|'
+ evalop = any
+
+class BoolNot(object):
+ def __init__(self,t):
+ self.arg = t[0][1]
+ def __bool__(self):
+ v = bool(self.arg)
+ return not v
+ def __str__(self):
+ return "~" + str(self.arg)
+ __repr__ = __str__
+ __nonzero__ = __bool__
+
+TRUE = Keyword("True")
+FALSE = Keyword("False")
+boolOperand = TRUE | FALSE | Word(alphas,max=1)
+boolOperand.setParseAction(BoolOperand)
+
+# define expression, based on expression operand and
+# list of operations in precedence order
+boolExpr = infixNotation( boolOperand,
+ [
+ ("not", 1, opAssoc.RIGHT, BoolNot),
+ ("and", 2, opAssoc.LEFT, BoolAnd),
+ ("or", 2, opAssoc.LEFT, BoolOr),
+ ])
+
+
+if __name__ == "__main__":
+ p = True
+ q = False
+ r = True
+ tests = [("p", True),
+ ("q", False),
+ ("p and q", False),
+ ("p and not q", True),
+ ("not not p", True),
+ ("not(p and q)", True),
+ ("q or not p and r", False),
+ ("q or not p or not r", False),
+ ("q or not (p and r)", False),
+ ("p or q or r", True),
+ ("p or q or r and False", True),
+ ("(p or q or r) and False", False),
+ ]
+
+ print("p =", p)
+ print("q =", q)
+ print("r =", r)
+ print()
+ for t,expected in tests:
+ res = boolExpr.parseString(t)[0]
+ success = "PASS" if bool(res) == expected else "FAIL"
+ print (t,'\n', res, '=', bool(res),'\n', success, '\n')
+
+
diff --git a/examples/simpleSQL.py b/examples/simpleSQL.py
new file mode 100644
index 0000000..6cde6ce
--- /dev/null
+++ b/examples/simpleSQL.py
@@ -0,0 +1,88 @@
+# simpleSQL.py
+#
+# simple demo of using the parsing library to do simple-minded SQL parsing
+# could be extended to include where clauses etc.
+#
+# Copyright (c) 2003,2016, Paul McGuire
+#
+from pyparsing import Literal, CaselessLiteral, Word, delimitedList, Optional, \
+ Combine, Group, alphas, nums, alphanums, ParseException, Forward, oneOf, quotedString, \
+ ZeroOrMore, restOfLine, CaselessKeyword, pyparsing_common
+
+# define SQL tokens
+selectStmt = Forward()
+SELECT, FROM, WHERE = map(CaselessKeyword, "select from where".split())
+
+ident = Word( alphas, alphanums + "_$" ).setName("identifier")
+columnName = delimitedList(ident, ".", combine=True).setName("column name")
+columnName.addParseAction(pyparsing_common.upcaseTokens)
+columnNameList = Group( delimitedList(columnName))
+tableName = delimitedList(ident, ".", combine=True).setName("table name")
+tableName.addParseAction(pyparsing_common.upcaseTokens)
+tableNameList = Group(delimitedList(tableName))
+
+whereExpression = Forward()
+and_, or_, in_ = map(CaselessKeyword, "and or in".split())
+
+binop = oneOf("= != < > >= <= eq ne lt le gt ge", caseless=True)
+realNum = pyparsing_common.real()
+intNum = pyparsing_common.signed_integer()
+
+columnRval = realNum | intNum | quotedString | columnName # need to add support for alg expressions
+whereCondition = Group(
+ ( columnName + binop + columnRval ) |
+ ( columnName + in_ + "(" + delimitedList( columnRval ) + ")" ) |
+ ( columnName + in_ + "(" + selectStmt + ")" ) |
+ ( "(" + whereExpression + ")" )
+ )
+whereExpression << whereCondition + ZeroOrMore( ( and_ | or_ ) + whereExpression )
+
+# define the grammar
+selectStmt <<= (SELECT + ('*' | columnNameList)("columns") +
+ FROM + tableNameList( "tables" ) +
+ Optional(Group(WHERE + whereExpression), "")("where"))
+
+simpleSQL = selectStmt
+
+# define Oracle comment format, and ignore them
+oracleSqlComment = "--" + restOfLine
+simpleSQL.ignore( oracleSqlComment )
+
+if __name__ == "__main__":
+ simpleSQL.runTests("""\
+
+ # multiple tables
+ SELECT * from XYZZY, ABC
+
+ # dotted table name
+ select * from SYS.XYZZY
+
+ Select A from Sys.dual
+
+ Select A,B,C from Sys.dual
+
+ Select A, B, C from Sys.dual, Table2
+
+ # FAIL - invalid SELECT keyword
+ Xelect A, B, C from Sys.dual
+
+ # FAIL - invalid FROM keyword
+ Select A, B, C frox Sys.dual
+
+ # FAIL - incomplete statement
+ Select
+
+ # FAIL - incomplete statement
+ Select * from
+
+ # FAIL - invalid column
+ Select &&& frox Sys.dual
+
+ # where clause
+ Select A from Sys.dual where a in ('RED','GREEN','BLUE')
+
+ # compound where clause
+ Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)
+
+ # where clause with comparison operator
+ Select A,b from table1,table2 where table1.id eq table2.id""")
diff --git a/examples/simpleWiki.py b/examples/simpleWiki.py
new file mode 100644
index 0000000..7a2a0ce
--- /dev/null
+++ b/examples/simpleWiki.py
@@ -0,0 +1,32 @@
+from pyparsing import *
+
+wikiInput = """
+Here is a simple Wiki input:
+ *This is in italics.*
+ **This is in bold!**
+ ***This is in bold italics!***
+ Here's a URL to {{Pyparsing's Wiki Page->http://pyparsing.wikispaces.com}}
+"""
+
+def convertToHTML(opening,closing):
+ def conversionParseAction(s,l,t):
+ return opening + t[0] + closing
+ return conversionParseAction
+
+italicized = QuotedString("*").setParseAction(convertToHTML("<I>","</I>"))
+bolded = QuotedString("**").setParseAction(convertToHTML("<B>","</B>"))
+boldItalicized = QuotedString("***").setParseAction(convertToHTML("<B><I>","</I></B>"))
+def convertToHTML_A(s,l,t):
+ try:
+ text,url=t[0].split("->")
+ except ValueError:
+ raise ParseFatalException(s,l,"invalid URL link reference: " + t[0])
+ return '<A href="%s">%s</A>' % (url,text)
+
+urlRef = QuotedString("{{",endQuoteChar="}}").setParseAction(convertToHTML_A)
+
+wikiMarkup = urlRef | boldItalicized | bolded | italicized
+
+print(wikiInput)
+print()
+print(wikiMarkup.transformString(wikiInput))
diff --git a/examples/snmp_api.h b/examples/snmp_api.h
new file mode 100644
index 0000000..d75cb12
--- /dev/null
+++ b/examples/snmp_api.h
@@ -0,0 +1,795 @@
+#ifndef SNMP_API_H
+#define SNMP_API_H
+
+/*
+ * snmp_api.h - API for access to snmp.
+ *
+ * Caution: when using this library in a multi-threaded application,
+ * the values of global variables "snmp_errno" and "snmp_detail"
+ * cannot be reliably determined. Suggest using snmp_error()
+ * to obtain the library error codes.
+ */
+
+#ifndef DONT_SHARE_ERROR_WITH_OTHER_THREADS
+#define SET_SNMP_ERROR(x) snmp_errno=(x)
+#else
+#define SET_SNMP_ERROR(x)
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************
+ Copyright 1989 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of CMU not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+******************************************************************/
+
+
+struct variable_list;
+struct timeval;
+
+
+ /*
+ * Mimic size and alignment of 'struct sockaddr_storage' (see RFC 2553)
+ * But retain field names of traditional 'struct sockaddr'
+ */
+
+#define _UCD_SS_MAXSIZE 92 /* <= sizeof( sockaddr_un ) */
+#define _UCD_SS_ALIGNSIZE (sizeof (long))
+
+#define _UCD_SS_PAD1SIZE (_UCD_SS_ALIGNSIZE - sizeof( unsigned short ))
+#define _UCD_SS_PAD2SIZE (_UCD_SS_MAXSIZE - \
+ (sizeof( unsigned short ) + _UCD_SS_PAD1SIZE + _UCD_SS_ALIGNSIZE ))
+
+typedef struct {
+
+#ifdef STRUCT_SOCKADDR_HAS_SA_UNION_SA_GENERIC_SA_FAMILY2
+ /*
+ * Certain systems (notably Irix 6.x) have a non-traditional
+ * socket structure, and #define the traditional field names.
+ * This local definition should reproduce this structure, and still
+ * be large enough to handle any necessary Unix domain addresses.
+ */
+ union {
+ struct {
+#ifdef _HAVE_SA_LEN
+ unsigned char sa_len2;
+ unsigned char sa_family2;
+#else
+ unsigned short sa_family2;
+#endif
+ char sa_data2[ _UCD_SS_PAD1SIZE ];
+ } sa_generic;
+ long sa_align;
+ char sa_pad2[ _UCD_SS_PAD2SIZE ];
+ } sa_union;
+
+#else
+
+#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
+ unsigned char sa_len;
+ unsigned char sa_family;
+#else
+ unsigned short sa_family;
+#endif
+ char sa_data[ _UCD_SS_PAD1SIZE ];
+ long sa_align;
+ char sa_pad2[ _UCD_SS_PAD2SIZE ];
+#endif
+
+} snmp_ipaddr;
+
+#define USM_AUTH_KU_LEN 32
+#define USM_PRIV_KU_LEN 32
+
+struct snmp_pdu {
+
+ /*
+ * Protocol-version independent fields
+ */
+ long version;
+ int command; /* Type of this PDU */
+ long reqid; /* Request id - note: not incremented on retries */
+ long msgid; /* Message id for V3 messages
+ * note: incremented for each retry */
+ long transid; /* Unique ID for incoming transactions */
+ long sessid; /* Session id for AgentX messages */
+ long errstat; /* Error status (non_repeaters in GetBulk) */
+ long errindex; /* Error index (max_repetitions in GetBulk) */
+ u_long time; /* Uptime */
+ u_long flags;
+
+ int securityModel;
+ int securityLevel; /* noAuthNoPriv, authNoPriv, authPriv */
+ int msgParseModel;
+
+ snmp_ipaddr address; /* Address of peer or trap destination */
+
+ struct variable_list *variables;
+
+
+ /*
+ * SNMPv1 & SNMPv2c fields
+ */
+ u_char *community; /* community for outgoing requests. */
+ size_t community_len; /* Length of community name. */
+
+ /*
+ * Trap information
+ */
+ oid *enterprise; /* System OID */
+ size_t enterprise_length;
+ long trap_type; /* trap type */
+ long specific_type; /* specific type */
+ snmp_ipaddr agent_addr;
+
+ /*
+ * SNMPv3 fields
+ */
+ u_char *contextEngineID; /* context snmpEngineID */
+ size_t contextEngineIDLen; /* Length of contextEngineID */
+ char *contextName; /* authoritative contextName */
+ size_t contextNameLen; /* Length of contextName */
+ u_char *securityEngineID; /* authoritative snmpEngineID for security */
+ size_t securityEngineIDLen;/* Length of securityEngineID */
+ char *securityName; /* on behalf of this principal */
+ size_t securityNameLen; /* Length of securityName. */
+
+ /*
+ * AgentX fields
+ * (also uses SNMPv1 community field)
+ */
+ int priority;
+ int range_subid;
+
+ void * securityStateRef;
+};
+
+struct snmp_session;
+typedef int (*snmp_callback) (int, struct snmp_session *, int, struct snmp_pdu *, void *);
+
+struct snmp_session {
+ /*
+ * Protocol-version independent fields
+ */
+ long version;
+ int retries; /* Number of retries before timeout. */
+ long timeout; /* Number of uS until first timeout, then exponential backoff */
+ u_long flags;
+ struct snmp_session *subsession;
+ struct snmp_session *next;
+
+ char *peername; /* Domain name or dotted IP address of default peer */
+ u_short remote_port;/* UDP port number of peer. */
+ u_short local_port; /* My UDP port number, 0 for default, picked randomly */
+ /* Authentication function or NULL if null authentication is used */
+ u_char *(*authenticator) (u_char *, size_t *, u_char *, size_t);
+ snmp_callback callback; /* Function to interpret incoming data */
+ /* Pointer to data that the callback function may consider important */
+ void *callback_magic;
+
+ int s_errno; /* copy of system errno */
+ int s_snmp_errno; /* copy of library errno */
+ long sessid; /* Session id - AgentX only */
+
+ /*
+ * SNMPv1 & SNMPv2c fields
+ */
+ u_char *community; /* community for outgoing requests. */
+ size_t community_len; /* Length of community name. */
+
+ /*
+ * SNMPv3 fields
+ */
+ u_char isAuthoritative; /* are we the authoritative engine? */
+ u_char *contextEngineID; /* authoritative snmpEngineID */
+ size_t contextEngineIDLen; /* Length of contextEngineID */
+ u_int engineBoots; /* initial engineBoots for remote engine */
+ u_int engineTime; /* initial engineTime for remote engine */
+ char *contextName; /* authoritative contextName */
+ size_t contextNameLen; /* Length of contextName */
+ u_char *securityEngineID; /* authoritative snmpEngineID */
+ size_t securityEngineIDLen; /* Length of contextEngineID */
+ char *securityName; /* on behalf of this principal */
+ size_t securityNameLen; /* Length of securityName. */
+ oid *securityAuthProto; /* auth protocol oid */
+ size_t securityAuthProtoLen; /* Length of auth protocol oid */
+ u_char securityAuthKey[USM_AUTH_KU_LEN]; /* Ku for auth protocol XXX */
+ size_t securityAuthKeyLen; /* Length of Ku for auth protocol */
+ oid *securityPrivProto; /* priv protocol oid */
+ size_t securityPrivProtoLen; /* Length of priv protocol oid */
+ u_char securityPrivKey[USM_PRIV_KU_LEN]; /* Ku for privacy protocol XXX */
+ size_t securityPrivKeyLen; /* Length of Ku for priv protocol */
+ int securityModel;
+ int securityLevel; /* noAuthNoPriv, authNoPriv, authPriv */
+};
+
+/*
+ * A list of all the outstanding requests for a particular session.
+ */
+#ifdef SNMP_NEED_REQUEST_LIST
+struct request_list {
+ struct request_list *next_request;
+ long request_id; /* request id */
+ long message_id; /* message id */
+ snmp_callback callback; /* user callback per request (NULL if unused) */
+ void *cb_data; /* user callback data per request (NULL if unused) */
+ int retries; /* Number of retries */
+ u_long timeout; /* length to wait for timeout */
+ struct timeval time; /* Time this request was made */
+ struct timeval expire; /* time this request is due to expire */
+ struct snmp_session *session;
+ struct snmp_pdu *pdu; /* The pdu for this request
+ (saved so it can be retransmitted */
+};
+#endif /* SNMP_NEED_REQUEST_LIST */
+
+/*
+ * Set fields in session and pdu to the following to get a default or unconfigured value.
+ */
+#define SNMP_DEFAULT_COMMUNITY_LEN 0 /* to get a default community name */
+#define SNMP_DEFAULT_RETRIES -1
+#define SNMP_DEFAULT_TIMEOUT -1
+#define SNMP_DEFAULT_REMPORT 0
+#define SNMP_DEFAULT_REQID -1
+#define SNMP_DEFAULT_MSGID -1
+#define SNMP_DEFAULT_ERRSTAT -1
+#define SNMP_DEFAULT_ERRINDEX -1
+#define SNMP_DEFAULT_ADDRESS 0
+#define SNMP_DEFAULT_PEERNAME NULL
+#define SNMP_DEFAULT_ENTERPRISE_LENGTH 0
+#define SNMP_DEFAULT_TIME 0
+#define SNMP_DEFAULT_VERSION -1
+#define SNMP_DEFAULT_CONTEXT ""
+#define SNMP_DEFAULT_AUTH_PROTO usmHMACMD5AuthProtocol
+#define SNMP_DEFAULT_AUTH_PROTOLEN USM_LENGTH_OID_TRANSFORM
+#define SNMP_DEFAULT_PRIV_PROTO usmDESPrivProtocol
+#define SNMP_DEFAULT_PRIV_PROTOLEN USM_LENGTH_OID_TRANSFORM
+
+extern const char *snmp_api_errstring (int);
+extern void snmp_perror (const char *);
+extern void snmp_set_detail (const char *);
+
+#define SNMP_MAX_MSG_SIZE 1472 /* ethernet MTU minus IP/UDP header */
+#define SNMP_MAX_MSG_V3_HDRS (4+3+4+7+7+3+7+16) /* fudge factor=16 */
+#define SNMP_MAX_ENG_SIZE 32
+#define SNMP_MAX_SEC_NAME_SIZE 256
+#define SNMP_MAX_CONTEXT_SIZE 256
+#define SNMP_SEC_PARAM_BUF_SIZE 256
+
+/* set to one to ignore unauthenticated Reports */
+#define SNMPV3_IGNORE_UNAUTH_REPORTS 0
+
+/* authoritative engine definitions */
+#define SNMP_SESS_NONAUTHORITATIVE 0 /* should be 0 to default to this */
+#define SNMP_SESS_AUTHORITATIVE 1 /* don't learn engineIDs */
+#define SNMP_SESS_UNKNOWNAUTH 2 /* sometimes (like NRs) */
+
+/* to determine type of Report from varbind_list */
+#define REPORT_STATS_LEN 9
+#define REPORT_snmpUnknownSecurityModels_NUM 1
+#define REPORT_snmpInvalidMsgs_NUM 2
+#define REPORT_usmStatsUnsupportedSecLevels_NUM 1
+#define REPORT_usmStatsNotInTimeWindows_NUM 2
+#define REPORT_usmStatsUnknownUserNames_NUM 3
+#define REPORT_usmStatsUnknownEngineIDs_NUM 4
+#define REPORT_usmStatsWrongDigests_NUM 5
+#define REPORT_usmStatsDecryptionErrors_NUM 6
+
+#define SNMP_DETAIL_SIZE 512
+
+#define SNMP_FLAGS_DONT_PROBE 0x100 /* don't probe for an engineID */
+#define SNMP_FLAGS_STREAM_SOCKET 0x80
+#define SNMP_FLAGS_LISTENING 0x40 /* Server stream sockets only */
+#define SNMP_FLAGS_SUBSESSION 0x20
+#define SNMP_FLAGS_STRIKE2 0x02
+#define SNMP_FLAGS_STRIKE1 0x01
+
+#define CLEAR_SNMP_STRIKE_FLAGS(x) \
+ x &= ~(SNMP_FLAGS_STRIKE2|SNMP_FLAGS_STRIKE1)
+
+ /*
+ * returns '1' if the session is to be regarded as dead,
+ * otherwise set the strike flags appropriately, and return 0
+ */
+#define SET_SNMP_STRIKE_FLAGS(x) \
+ (( x & SNMP_FLAGS_STRIKE2 ) ? 1 : \
+ ((( x & SNMP_FLAGS_STRIKE1 ) ? ( x |= SNMP_FLAGS_STRIKE2 ) : \
+ ( x |= SNMP_FLAGS_STRIKE1 )), \
+ 0))
+
+/*
+ * Error return values.
+ *
+ * SNMPERR_SUCCESS is the non-PDU "success" code.
+ *
+ * XXX These should be merged with SNMP_ERR_* defines and confined
+ * to values < 0. ???
+ */
+#define SNMPERR_SUCCESS (0) /* XXX Non-PDU "success" code. */
+#define SNMPERR_GENERR (-1)
+#define SNMPERR_BAD_LOCPORT (-2)
+#define SNMPERR_BAD_ADDRESS (-3)
+#define SNMPERR_BAD_SESSION (-4)
+#define SNMPERR_TOO_LONG (-5)
+#define SNMPERR_NO_SOCKET (-6)
+#define SNMPERR_V2_IN_V1 (-7)
+#define SNMPERR_V1_IN_V2 (-8)
+#define SNMPERR_BAD_REPEATERS (-9)
+#define SNMPERR_BAD_REPETITIONS (-10)
+#define SNMPERR_BAD_ASN1_BUILD (-11)
+#define SNMPERR_BAD_SENDTO (-12)
+#define SNMPERR_BAD_PARSE (-13)
+#define SNMPERR_BAD_VERSION (-14)
+#define SNMPERR_BAD_SRC_PARTY (-15)
+#define SNMPERR_BAD_DST_PARTY (-16)
+#define SNMPERR_BAD_CONTEXT (-17)
+#define SNMPERR_BAD_COMMUNITY (-18)
+#define SNMPERR_NOAUTH_DESPRIV (-19)
+#define SNMPERR_BAD_ACL (-20)
+#define SNMPERR_BAD_PARTY (-21)
+#define SNMPERR_ABORT (-22)
+#define SNMPERR_UNKNOWN_PDU (-23)
+#define SNMPERR_TIMEOUT (-24)
+#define SNMPERR_BAD_RECVFROM (-25)
+#define SNMPERR_BAD_ENG_ID (-26)
+#define SNMPERR_BAD_SEC_NAME (-27)
+#define SNMPERR_BAD_SEC_LEVEL (-28)
+#define SNMPERR_ASN_PARSE_ERR (-29)
+#define SNMPERR_UNKNOWN_SEC_MODEL (-30)
+#define SNMPERR_INVALID_MSG (-31)
+#define SNMPERR_UNKNOWN_ENG_ID (-32)
+#define SNMPERR_UNKNOWN_USER_NAME (-33)
+#define SNMPERR_UNSUPPORTED_SEC_LEVEL (-34)
+#define SNMPERR_AUTHENTICATION_FAILURE (-35)
+#define SNMPERR_NOT_IN_TIME_WINDOW (-36)
+#define SNMPERR_DECRYPTION_ERR (-37)
+#define SNMPERR_SC_GENERAL_FAILURE (-38)
+#define SNMPERR_SC_NOT_CONFIGURED (-39)
+#define SNMPERR_KT_NOT_AVAILABLE (-40)
+#define SNMPERR_UNKNOWN_REPORT (-41)
+#define SNMPERR_USM_GENERICERROR (-42)
+#define SNMPERR_USM_UNKNOWNSECURITYNAME (-43)
+#define SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL (-44)
+#define SNMPERR_USM_ENCRYPTIONERROR (-45)
+#define SNMPERR_USM_AUTHENTICATIONFAILURE (-46)
+#define SNMPERR_USM_PARSEERROR (-47)
+#define SNMPERR_USM_UNKNOWNENGINEID (-48)
+#define SNMPERR_USM_NOTINTIMEWINDOW (-49)
+#define SNMPERR_USM_DECRYPTIONERROR (-50)
+#define SNMPERR_NOMIB (-51)
+#define SNMPERR_RANGE (-52)
+#define SNMPERR_MAX_SUBID (-53)
+#define SNMPERR_BAD_SUBID (-54)
+#define SNMPERR_LONG_OID (-55)
+#define SNMPERR_BAD_NAME (-56)
+#define SNMPERR_VALUE (-57)
+#define SNMPERR_UNKNOWN_OBJID (-58)
+#define SNMPERR_NULL_PDU (-59)
+#define SNMPERR_NO_VARS (-60)
+#define SNMPERR_VAR_TYPE (-61)
+#define SNMPERR_MALLOC (-62)
+
+#define SNMPERR_MAX (-62)
+
+#define non_repeaters errstat
+#define max_repetitions errindex
+
+
+struct variable_list {
+ struct variable_list *next_variable; /* NULL for last variable */
+ oid *name; /* Object identifier of variable */
+ size_t name_length; /* number of subid's in name */
+ u_char type; /* ASN type of variable */
+ union { /* value of variable */
+ long *integer;
+ u_char *string;
+ oid *objid;
+ u_char *bitstring;
+ struct counter64 *counter64;
+#ifdef OPAQUE_SPECIAL_TYPES
+ float *floatVal;
+ double *doubleVal;
+/* t_union *unionVal; */
+#endif /* OPAQUE_SPECIAL_TYPES */
+ } val;
+ size_t val_len;
+ oid name_loc[MAX_OID_LEN]; /* 90 percentile < 24. */
+ u_char buf[40]; /* 90 percentile < 40. */
+ void *data; /* (Opaque) hook for additional data */
+ int index;
+};
+
+
+
+/*
+ * struct snmp_session *snmp_open(session)
+ * struct snmp_session *session;
+ *
+ * Sets up the session with the snmp_session information provided
+ * by the user. Then opens and binds the necessary UDP port.
+ * A handle to the created session is returned (this is different than
+ * the pointer passed to snmp_open()). On any error, NULL is returned
+ * and snmp_errno is set to the appropriate error code.
+ */
+struct snmp_session *snmp_open (struct snmp_session *);
+
+/*
+ * int snmp_close(session)
+ * struct snmp_session *session;
+ *
+ * Close the input session. Frees all data allocated for the session,
+ * dequeues any pending requests, and closes any sockets allocated for
+ * the session. Returns 0 on error, 1 otherwise.
+ *
+ * snmp_close_sessions() does the same thing for all open sessions
+ */
+int snmp_close (struct snmp_session *);
+int snmp_close_sessions (void);
+
+
+/*
+ * int snmp_send(session, pdu)
+ * struct snmp_session *session;
+ * struct snmp_pdu *pdu;
+ *
+ * Sends the input pdu on the session after calling snmp_build to create
+ * a serialized packet. If necessary, set some of the pdu data from the
+ * session defaults. Add a request corresponding to this pdu to the list
+ * of outstanding requests on this session, then send the pdu.
+ * Returns the request id of the generated packet if applicable, otherwise 1.
+ * On any error, 0 is returned.
+ * The pdu is freed by snmp_send() unless a failure occured.
+ */
+int snmp_send (struct snmp_session *, struct snmp_pdu *);
+
+/*
+ * int snmp_async_send(session, pdu, callback, cb_data)
+ * struct snmp_session *session;
+ * struct snmp_pdu *pdu;
+ * snmp_callback callback;
+ * void *cb_data;
+ *
+ * Sends the input pdu on the session after calling snmp_build to create
+ * a serialized packet. If necessary, set some of the pdu data from the
+ * session defaults. Add a request corresponding to this pdu to the list
+ * of outstanding requests on this session and store callback and data,
+ * then send the pdu.
+ * Returns the request id of the generated packet if applicable, otherwise 1.
+ * On any error, 0 is returned.
+ * The pdu is freed by snmp_send() unless a failure occured.
+ */
+int snmp_async_send (struct snmp_session *, struct snmp_pdu *,
+ snmp_callback, void *);
+
+
+/*
+ * void snmp_read(fdset)
+ * fd_set *fdset;
+ *
+ * Checks to see if any of the fd's set in the fdset belong to
+ * snmp. Each socket with it's fd set has a packet read from it
+ * and snmp_parse is called on the packet received. The resulting pdu
+ * is passed to the callback routine for that session. If the callback
+ * routine returns successfully, the pdu and it's request are deleted.
+ */
+void snmp_read (fd_set *);
+
+
+
+/*
+ * void
+ * snmp_free_pdu(pdu)
+ * struct snmp_pdu *pdu;
+ *
+ * Frees the pdu and any malloc'd data associated with it.
+ */
+void snmp_free_pdu (struct snmp_pdu *);
+
+void snmp_free_var (struct variable_list *); /* frees just this one */
+
+void snmp_free_varbind(struct variable_list *var); /* frees all in list */
+
+/*
+ * int snmp_select_info(numfds, fdset, timeout, block)
+ * int *numfds;
+ * fd_set *fdset;
+ * struct timeval *timeout;
+ * int *block;
+ *
+ * Returns info about what snmp requires from a select statement.
+ * numfds is the number of fds in the list that are significant.
+ * All file descriptors opened for SNMP are OR'd into the fdset.
+ * If activity occurs on any of these file descriptors, snmp_read
+ * should be called with that file descriptor set.
+ *
+ * The timeout is the latest time that SNMP can wait for a timeout. The
+ * select should be done with the minimum time between timeout and any other
+ * timeouts necessary. This should be checked upon each invocation of select.
+ * If a timeout is received, snmp_timeout should be called to check if the
+ * timeout was for SNMP. (snmp_timeout is idempotent)
+ *
+ * Block is 1 if the select is requested to block indefinitely, rather than
+ * time out. If block is input as 1, the timeout value will be treated as
+ * undefined, but it must be available for setting in snmp_select_info. On
+ * return, if block is true, the value of timeout will be undefined.
+ *
+ * snmp_select_info returns the number of open sockets. (i.e. The number
+ * of sessions open)
+ */
+int snmp_select_info (int *, fd_set *, struct timeval *, int *);
+
+
+
+/*
+ * void snmp_timeout();
+ *
+ * snmp_timeout should be called whenever the timeout from snmp_select_info
+ * expires, but it is idempotent, so snmp_timeout can be polled (probably a
+ * cpu expensive proposition). snmp_timeout checks to see if any of the
+ * sessions have an outstanding request that has timed out. If it finds one
+ * (or more), and that pdu has more retries available, a new packet is formed
+ * from the pdu and is resent. If there are no more retries available, the
+ * callback for the session is used to alert the user of the timeout.
+ */
+
+void snmp_timeout (void);
+
+
+/*
+ * This routine must be supplied by the application:
+ *
+ * u_char *authenticator(pdu, length, community, community_len)
+ * u_char *pdu; The rest of the PDU to be authenticated
+ * int *length; The length of the PDU (updated by the authenticator)
+ * u_char *community; The community name to authenticate under.
+ * int community_len The length of the community name.
+ *
+ * Returns the authenticated pdu, or NULL if authentication failed.
+ * If null authentication is used, the authenticator in snmp_session can be
+ * set to NULL(0).
+ */
+
+
+
+/*
+ * This routine must be supplied by the application:
+ *
+ * int callback(operation, session, reqid, pdu, magic)
+ * int operation;
+ * struct snmp_session *session; The session authenticated under.
+ * int reqid; The request id of this pdu (0 for TRAP)
+ * struct snmp_pdu *pdu; The pdu information.
+ * void *magic A link to the data for this routine.
+ *
+ * Returns 1 if request was successful, 0 if it should be kept pending.
+ * Any data in the pdu must be copied because it will be freed elsewhere.
+ * Operations are defined below:
+ */
+
+#define RECEIVED_MESSAGE 1
+#define TIMED_OUT 2
+#define SEND_FAILED 3
+
+long snmp_get_next_msgid(void);
+long snmp_get_next_reqid(void);
+long snmp_get_next_sessid(void);
+long snmp_get_next_transid(void);
+/* provide for backwards compatibility */
+void snmp_set_dump_packet(int);
+int snmp_get_dump_packet(void);
+void snmp_set_quick_print(int);
+int snmp_get_quick_print(void);
+void snmp_set_suffix_only(int);
+int snmp_get_suffix_only(void);
+void snmp_set_full_objid(int);
+int snmp_get_full_objid(void);
+void snmp_set_random_access(int);
+int snmp_get_random_access(void);
+
+int snmp_oid_compare (const oid *, size_t, const oid *, size_t);
+void init_snmp (const char *);
+u_char *snmp_pdu_build (struct snmp_pdu *, u_char *, size_t *);
+#ifdef USE_REVERSE_ASNENCODING
+u_char *snmp_pdu_rbuild (struct snmp_pdu *, u_char *, size_t *);
+#endif
+int snmpv3_parse(struct snmp_pdu *, u_char *, size_t *, u_char **, struct snmp_session *);
+int snmpv3_dparse(struct snmp_pdu *, u_char *, size_t *, u_char **, int);
+int snmpv3_packet_build(struct snmp_pdu *pdu, u_char *packet, size_t *out_length, u_char *pdu_data, size_t pdu_data_len);
+int snmpv3_packet_rbuild(struct snmp_pdu *pdu, u_char *packet, size_t *out_length, u_char *pdu_data, size_t pdu_data_len);
+int snmpv3_make_report(struct snmp_pdu *pdu, int error);
+int snmpv3_get_report_type(struct snmp_pdu *pdu);
+int snmp_pdu_parse(struct snmp_pdu *pdu, u_char *data, size_t *length);
+int snmp_pdu_dparse(struct snmp_pdu *pdu, u_char *data, size_t *length, int);
+u_char* snmpv3_scopedPDU_parse(struct snmp_pdu *pdu, u_char *cp, size_t *length);
+u_char* snmpv3_scopedPDU_dparse(struct snmp_pdu *pdu, u_char *cp, size_t *length, int);
+void snmp_store(const char *type);
+void snmp_shutdown(const char *type);
+struct variable_list *snmp_pdu_add_variable (struct snmp_pdu *, oid *, size_t, u_char, u_char *, size_t);
+struct variable_list *snmp_varlist_add_variable(struct variable_list **varlist,
+ oid *name, size_t name_length, u_char type, u_char *value, size_t len);
+int hex_to_binary (const char *, u_char *);
+int ascii_to_binary (const char *, u_char *);
+int snmp_add_var (struct snmp_pdu *, oid*, size_t, char, const char *);
+oid *snmp_duplicate_objid(oid *objToCopy, size_t);
+u_int snmp_increment_statistic(int which);
+u_int snmp_increment_statistic_by(int which, int count);
+u_int snmp_get_statistic(int which);
+void snmp_init_statistics(void);
+int create_user_from_session(struct snmp_session *session);
+
+/* extended open */
+struct snmp_session *snmp_open_ex (struct snmp_session *,
+ int (*fpre_parse) (struct snmp_session *, snmp_ipaddr),
+ int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
+ int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
+ int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
+ int (*fcheck) (u_char *, size_t)
+);
+
+/* provided for backwards compatability. Don't use these functions.
+ See snmp_debug.h and snmp_debug.c instead.
+*/
+#if HAVE_STDARG_H
+void DEBUGP (const char *, ...);
+#else
+void DEBUGP (va_alist);
+#endif
+void DEBUGPOID(oid *, size_t);
+void snmp_set_do_debugging (int);
+int snmp_get_do_debugging (void);
+
+#ifdef CMU_COMPATIBLE
+extern int snmp_dump_packet;
+extern int quick_print;
+#endif
+
+size_t snmp_socket_length (int family);
+
+/*
+ * snmp_error - return error data
+ * Inputs : address of errno, address of snmp_errno, address of string
+ * Caller must free the string returned after use.
+ */
+void snmp_error (struct snmp_session *, int *, int *, char **);
+/*
+ * single session API.
+ *
+ * These functions perform similar actions as snmp_XX functions,
+ * but operate on a single session only.
+ *
+ * Synopsis:
+
+ void * sessp;
+ struct snmp_session session, *ss;
+ struct snmp_pdu *pdu, *response;
+
+ snmp_sess_init(&session);
+ session.retries = ...
+ session.remote_port = ...
+ sessp = snmp_sess_open(&session);
+ ss = snmp_sess_session(sessp);
+ if (ss == NULL)
+ exit(1);
+ ...
+ if (ss->community) free(ss->community);
+ ss->community = strdup(gateway);
+ ss->community_len = strlen(gateway);
+ ...
+ snmp_sess_synch_response(sessp, pdu, &response);
+ ...
+ snmp_sess_close(sessp);
+
+ * See also:
+ * snmp_sess_synch_response, in snmp_client.h.
+
+ * Notes:
+ * 1. Invoke snmp_sess_session after snmp_sess_open.
+ * 2. snmp_sess_session return value is an opaque pointer.
+ * 3. Do NOT free memory returned by snmp_sess_session.
+ * 4. Replace snmp_send(ss,pdu) with snmp_sess_send(sessp,pdu)
+ */
+
+void snmp_sess_init (struct snmp_session *);
+void * snmp_sess_open (struct snmp_session *);
+struct snmp_session * snmp_sess_session (void *);
+
+/* use return value from snmp_sess_open as void * parameter */
+
+int snmp_sess_send (void *, struct snmp_pdu *);
+int snmp_sess_async_send (void *, struct snmp_pdu *,
+ snmp_callback, void *);
+int snmp_sess_select_info (void *, int *, fd_set *,
+ struct timeval *, int *);
+int snmp_sess_read (void *, fd_set *);
+void snmp_sess_timeout (void *);
+int snmp_sess_close (void *);
+
+void snmp_sess_error (void *, int *, int *, char **);
+void snmp_sess_perror (const char *prog_string, struct snmp_session *ss);
+
+/* end single session API */
+
+/* generic statistic counters */
+
+/* snmpv3 statistics */
+
+/* mpd stats */
+#define STAT_SNMPUNKNOWNSECURITYMODELS 0
+#define STAT_SNMPINVALIDMSGS 1
+#define STAT_SNMPUNKNOWNPDUHANDLERS 2
+#define STAT_MPD_STATS_START STAT_SNMPUNKNOWNSECURITYMODELS
+#define STAT_MPD_STATS_END STAT_SNMPUNKNOWNPDUHANDLERS
+
+/* usm stats */
+#define STAT_USMSTATSUNSUPPORTEDSECLEVELS 3
+#define STAT_USMSTATSNOTINTIMEWINDOWS 4
+#define STAT_USMSTATSUNKNOWNUSERNAMES 5
+#define STAT_USMSTATSUNKNOWNENGINEIDS 6
+#define STAT_USMSTATSWRONGDIGESTS 7
+#define STAT_USMSTATSDECRYPTIONERRORS 8
+#define STAT_USM_STATS_START STAT_USMSTATSUNSUPPORTEDSECLEVELS
+#define STAT_USM_STATS_END STAT_USMSTATSDECRYPTIONERRORS
+
+/* snmp counters */
+#define STAT_SNMPINPKTS 9
+#define STAT_SNMPOUTPKTS 10
+#define STAT_SNMPINBADVERSIONS 11
+#define STAT_SNMPINBADCOMMUNITYNAMES 12
+#define STAT_SNMPINBADCOMMUNITYUSES 13
+#define STAT_SNMPINASNPARSEERRS 14
+/* #define STAT_SNMPINBADTYPES 15 */
+#define STAT_SNMPINTOOBIGS 16
+#define STAT_SNMPINNOSUCHNAMES 17
+#define STAT_SNMPINBADVALUES 18
+#define STAT_SNMPINREADONLYS 19
+#define STAT_SNMPINGENERRS 20
+#define STAT_SNMPINTOTALREQVARS 21
+#define STAT_SNMPINTOTALSETVARS 22
+#define STAT_SNMPINGETREQUESTS 23
+#define STAT_SNMPINGETNEXTS 24
+#define STAT_SNMPINSETREQUESTS 25
+#define STAT_SNMPINGETRESPONSES 26
+#define STAT_SNMPINTRAPS 27
+#define STAT_SNMPOUTTOOBIGS 28
+#define STAT_SNMPOUTNOSUCHNAMES 29
+#define STAT_SNMPOUTBADVALUES 30
+/* #define STAT_SNMPOUTREADONLYS 31 */
+#define STAT_SNMPOUTGENERRS 32
+#define STAT_SNMPOUTGETREQUESTS 33
+#define STAT_SNMPOUTGETNEXTS 34
+#define STAT_SNMPOUTSETREQUESTS 35
+#define STAT_SNMPOUTGETRESPONSES 36
+#define STAT_SNMPOUTTRAPS 37
+/* AUTHTRAPENABLE 38 */
+#define STAT_SNMPSILENTDROPS 39
+#define STAT_SNMPPROXYDROPS 40
+#define STAT_SNMP_STATS_START STAT_SNMPINPKTS
+#define STAT_SNMP_STATS_END STAT_SNMPOUTTRAPS
+
+#define MAX_STATS 41
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SNMP_API_H */
diff --git a/examples/sparser.py b/examples/sparser.py
new file mode 100644
index 0000000..7c416da
--- /dev/null
+++ b/examples/sparser.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python
+
+"""
+NAME:
+ sparser.py
+
+SYNOPSIS:
+ sparser.py [options] filename
+
+DESCRIPTION:
+ The sparser.py script is a Specified PARSER. It is unique (as far as I can
+ tell) because it doesn't care about the delimiter(s). The user specifies
+ what is expected, and the order, for each line of text. All of the heavy
+ lifting is handled by pyparsing (http://pyparsing.sf.net).
+
+OPTIONS:
+ -h,--help this message
+ -v,--version version
+ -d,--debug turn on debug messages
+
+EXAMPLES:
+ 1. As standalone
+ sparser.py myfile
+ 2. As library
+ import sparser
+ ...
+
+#Copyright (C) 2006 Tim Cera timcera@earthlink.net
+#
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+#===imports======================
+import sys
+import os
+import getopt
+import re
+import gzip
+
+from pyparsing import *
+
+
+#===globals======================
+modname = "sparser"
+__version__ = "0.1"
+
+
+#--option args--
+debug_p = 0
+#opt_b=None #string arg, default is undefined
+
+
+#---positional args, default is empty---
+pargs = []
+
+
+#---other---
+
+
+#===utilities====================
+def msg(txt):
+ """Send message to stdout."""
+ sys.stdout.write(txt)
+ sys.stdout.flush()
+
+def debug(ftn, txt):
+ """Used for debugging."""
+ if debug_p:
+ sys.stdout.write("%s.%s:%s\n" % (modname, ftn, txt))
+ sys.stdout.flush()
+
+def fatal(ftn, txt):
+ """If can't continue."""
+ msg = "%s.%s:FATAL:%s\n" % (modname, ftn, txt)
+ raise SystemExit(msg)
+
+def usage():
+ """Prints the docstring."""
+ print(__doc__)
+
+
+
+#====================================
+class ToInteger(TokenConverter):
+ """Converter to make token into an integer."""
+ def postParse( self, instring, loc, tokenlist ):
+ return int(tokenlist[0])
+
+class ToFloat(TokenConverter):
+ """Converter to make token into a float."""
+ def postParse( self, instring, loc, tokenlist ):
+ return float(tokenlist[0])
+
+class ParseFileLineByLine:
+ """
+ Bring data from text files into a program, optionally parsing each line
+ according to specifications in a parse definition file.
+
+ ParseFileLineByLine instances can be used like normal file objects (i.e. by
+ calling readline(), readlines(), and write()), but can also be used as
+ sequences of lines in for-loops.
+
+ ParseFileLineByLine objects also handle compression transparently. i.e. it
+ is possible to read lines from a compressed text file as if it were not
+ compressed. Compression is deduced from the file name suffixes '.Z'
+ (compress/uncompress), '.gz' (gzip/gunzip), and '.bz2' (bzip2).
+
+ The parse definition file name is developed based on the input file name.
+ If the input file name is 'basename.ext', then the definition file is
+ 'basename_def.ext'. If a definition file specific to the input file is not
+ found, then the program searches for the file 'sparse.def' which would be
+ the definition file for all files in that directory without a file specific
+ definition file.
+
+ Finally, ParseFileLineByLine objects accept file names that start with '~'
+ or '~user' to indicate a home directory, as well as URLs (for reading
+ only).
+
+ Constructor:
+ ParseFileLineByLine(|filename|, |mode|='"r"'), where |filename| is the name
+ of the file (or a URL) and |mode| is one of '"r"' (read), '"w"' (write) or
+ '"a"' (append, not supported for .Z files).
+ """
+
+ def __init__(self, filename, mode = 'r'):
+ """Opens input file, and if available the definition file. If the
+ definition file is available __init__ will then create some pyparsing
+ helper variables. """
+ if mode not in ['r', 'w', 'a']:
+ raise IOError(0, 'Illegal mode: ' + repr(mode))
+
+ if string.find(filename, ':/') > 1: # URL
+ if mode == 'w':
+ raise IOError("can't write to a URL")
+ import urllib.request, urllib.parse, urllib.error
+ self.file = urllib.request.urlopen(filename)
+ else:
+ filename = os.path.expanduser(filename)
+ if mode == 'r' or mode == 'a':
+ if not os.path.exists(filename):
+ raise IOError(2, 'No such file or directory: ' + filename)
+ filen, file_extension = os.path.splitext(filename)
+ command_dict = {
+ ('.Z', 'r'):
+ "self.file = os.popen('uncompress -c ' + filename, mode)",
+ ('.gz', 'r'):
+ "self.file = gzip.GzipFile(filename, 'rb')",
+ ('.bz2', 'r'):
+ "self.file = os.popen('bzip2 -dc ' + filename, mode)",
+ ('.Z', 'w'):
+ "self.file = os.popen('compress > ' + filename, mode)",
+ ('.gz', 'w'):
+ "self.file = gzip.GzipFile(filename, 'wb')",
+ ('.bz2', 'w'):
+ "self.file = os.popen('bzip2 > ' + filename, mode)",
+ ('.Z', 'a'):
+ "raise IOError, (0, 'Can\'t append to .Z files')",
+ ('.gz', 'a'):
+ "self.file = gzip.GzipFile(filename, 'ab')",
+ ('.bz2', 'a'):
+ "raise IOError, (0, 'Can\'t append to .bz2 files')",
+ }
+
+ exec(command_dict.get((file_extension, mode),
+ 'self.file = open(filename, mode)'))
+
+ self.grammar = None
+
+ # Try to find a parse ('*_def.ext') definition file. First try to find
+ # a file specific parse definition file, then look for 'sparse.def'
+ # that would be the definition file for all files within the directory.
+
+ # The definition file is pure Python. The one variable that needs to
+ # be specified is 'parse'. The 'parse' variable is a list of tuples
+ # defining the name, type, and because it is a list, the order of
+ # variables on each line in the data file. The variable name is a
+ # string, the type variable is defined as integer, real, and qString.
+
+ # parse = [
+ # ('year', integer),
+ # ('month', integer),
+ # ('day', integer),
+ # ('value', real),
+ # ]
+
+ definition_file_one = filen + "_def" + file_extension
+ definition_file_two = os.path.dirname(filen) + os.sep + "sparse.def"
+ if os.path.exists(definition_file_one):
+ self.parsedef = definition_file_one
+ elif os.path.exists(definition_file_two):
+ self.parsedef = definition_file_two
+ else:
+ self.parsedef = None
+ return None
+
+ # Create some handy pyparsing constructs. I kept 'decimal_sep' so that
+ # could easily change to parse if the decimal separator is a ",".
+ decimal_sep = "."
+ sign = oneOf("+ -")
+ # part of printables without decimal_sep, +, -
+ special_chars = string.replace('!"#$%&\'()*,./:;<=>?@[\\]^_`{|}~',
+ decimal_sep, "")
+ integer = ToInteger(
+ Combine(Optional(sign) +
+ Word(nums))).setName("integer")
+ positive_integer = ToInteger(
+ Combine(Optional("+") +
+ Word(nums))).setName("integer")
+ negative_integer = ToInteger(
+ Combine("-" +
+ Word(nums))).setName("integer")
+ real = ToFloat(
+ Combine(Optional(sign) +
+ Word(nums) +
+ decimal_sep +
+ Optional(Word(nums)) +
+ Optional(oneOf("E e") +
+ Word(nums)))).setName("real")
+ positive_real = ToFloat(
+ Combine(Optional("+") +
+ Word(nums) +
+ decimal_sep +
+ Optional(Word(nums)) +
+ Optional(oneOf("E e") +
+ Word(nums)))).setName("real")
+ negative_real = ToFloat(
+ Combine("-" +
+ Word(nums) +
+ decimal_sep +
+ Optional(Word(nums)) +
+ Optional(oneOf("E e") +
+ Word(nums)))).setName("real")
+ qString = ( sglQuotedString | dblQuotedString ).setName("qString")
+
+ # add other characters we should skip over between interesting fields
+ integer_junk = Optional(
+ Suppress(
+ Word(alphas +
+ special_chars +
+ decimal_sep))).setName("integer_junk")
+ real_junk = Optional(
+ Suppress(
+ Word(alphas +
+ special_chars))).setName("real_junk")
+ qString_junk = SkipTo(qString).setName("qString_junk")
+
+ # Now that 'integer', 'real', and 'qString' have been assigned I can
+ # execute the definition file.
+ exec(compile(open(self.parsedef).read(), self.parsedef, 'exec'))
+
+ # Build the grammar, combination of the 'integer', 'real, 'qString',
+ # and '*_junk' variables assigned above in the order specified in the
+ # definition file.
+ grammar = []
+ for nam, expr in parse:
+ grammar.append( eval(expr.name + "_junk"))
+ grammar.append( expr.setResultsName(nam) )
+ self.grammar = And( grammar[1:] + [restOfLine] )
+
+ def __del__(self):
+ """Delete (close) the file wrapper."""
+ self.close()
+
+ def __getitem__(self, item):
+ """Used in 'for line in fp:' idiom."""
+ line = self.readline()
+ if not line:
+ raise IndexError
+ return line
+
+ def readline(self):
+ """Reads (and optionally parses) a single line."""
+ line = self.file.readline()
+ if self.grammar and line:
+ try:
+ return self.grammar.parseString(line).asDict()
+ except ParseException:
+ return self.readline()
+ else:
+ return line
+
+ def readlines(self):
+ """Returns a list of all lines (optionally parsed) in the file."""
+ if self.grammar:
+ tot = []
+ # Used this way instead of a 'for' loop against
+ # self.file.readlines() so that there wasn't two copies of the file
+ # in memory.
+ while 1:
+ line = self.file.readline()
+ if not line:
+ break
+ tot.append(line)
+ return tot
+ return self.file.readlines()
+
+ def write(self, data):
+ """Write to a file."""
+ self.file.write(data)
+
+ def writelines(self, list):
+ """Write a list to a file. Each item in the list is a line in the
+ file.
+ """
+ for line in list:
+ self.file.write(line)
+
+ def close(self):
+ """Close the file."""
+ self.file.close()
+
+ def flush(self):
+ """Flush in memory contents to file."""
+ self.file.flush()
+
+
+#=============================
+def main(pargs):
+ """This should only be used for testing. The primary mode of operation is
+ as an imported library.
+ """
+ input_file = sys.argv[1]
+ fp = ParseFileLineByLine(input_file)
+ for i in fp:
+ print(i)
+
+
+#-------------------------
+if __name__ == '__main__':
+ ftn = "main"
+ opts, pargs = getopt.getopt(sys.argv[1:], 'hvd',
+ ['help', 'version', 'debug', 'bb='])
+ for opt in opts:
+ if opt[0] == '-h' or opt[0] == '--help':
+ print(modname+": version="+__version__)
+ usage()
+ sys.exit(0)
+ elif opt[0] == '-v' or opt[0] == '--version':
+ print(modname+": version="+__version__)
+ sys.exit(0)
+ elif opt[0] == '-d' or opt[0] == '--debug':
+ debug_p = 1
+ elif opt[0] == '--bb':
+ opt_b = opt[1]
+
+ #---make the object and run it---
+ main(pargs)
+
+#===Revision Log===
+#Created by mkpythonproj:
+#2006-02-06 Tim Cera
+#
diff --git a/examples/sql2dot.py b/examples/sql2dot.py
new file mode 100644
index 0000000..1156207
--- /dev/null
+++ b/examples/sql2dot.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+
+# sql2dot.py
+#
+# Creates table graphics by parsing SQL table DML commands and
+# generating DOT language output.
+#
+# Adapted from a post at http://energyblog.blogspot.com/2006/04/blog-post_20.html.
+#
+sampleSQL = """
+create table student
+(
+student_id integer primary key,
+firstname varchar(20),
+lastname varchar(40),
+address1 varchar(80),
+address2 varchar(80),
+city varchar(30),
+state varchar(2),
+zipcode varchar(10),
+dob date
+);
+
+create table classes
+(
+class_id integer primary key,
+id varchar(8),
+maxsize integer,
+instructor varchar(40)
+);
+
+create table student_registrations
+(
+reg_id integer primary key,
+student_id integer,
+class_id integer
+);
+
+alter table only student_registrations
+ add constraint students_link
+ foreign key
+ (student_id) references students(student_id);
+
+alter table only student_registrations
+ add constraint classes_link
+ foreign key
+ (class_id) references classes(class_id);
+""".upper()
+
+from pyparsing import Literal, CaselessLiteral, Word, delimitedList \
+ ,Optional, Combine, Group, alphas, nums, alphanums, Forward \
+ , oneOf, sglQuotedString, OneOrMore, ZeroOrMore, CharsNotIn \
+ , replaceWith
+
+skobki = "(" + ZeroOrMore(CharsNotIn(")")) + ")"
+field_def = OneOrMore(Word(alphas,alphanums+"_\"':-") | skobki)
+
+def field_act(s,loc,tok):
+ return ("<"+tok[0]+"> " + " ".join(tok)).replace("\"","\\\"")
+
+field_def.setParseAction(field_act)
+
+field_list_def = delimitedList( field_def )
+def field_list_act(toks):
+ return " | ".join(toks)
+
+field_list_def.setParseAction(field_list_act)
+
+create_table_def = Literal("CREATE") + "TABLE" + Word(alphas,alphanums+"_").setResultsName("tablename") + \
+ "("+field_list_def.setResultsName("columns")+")"+ ";"
+
+def create_table_act(toks):
+ return """"%(tablename)s" [\n\t label="<%(tablename)s> %(tablename)s | %(columns)s"\n\t shape="record"\n];""" % toks
+create_table_def.setParseAction(create_table_act)
+
+add_fkey_def=Literal("ALTER")+"TABLE"+"ONLY" + Word(alphanums+"_").setResultsName("fromtable") + "ADD" \
+ + "CONSTRAINT" + Word(alphanums+"_") + "FOREIGN"+"KEY"+"("+Word(alphanums+"_").setResultsName("fromcolumn")+")" \
+ +"REFERENCES"+Word(alphanums+"_").setResultsName("totable")+"("+Word(alphanums+"_").setResultsName("tocolumn")+")"+";"
+
+def add_fkey_act(toks):
+ return """ "%(fromtable)s":%(fromcolumn)s -> "%(totable)s":%(tocolumn)s """ % toks
+add_fkey_def.setParseAction(add_fkey_act)
+
+other_statement_def = ( OneOrMore(CharsNotIn(";") ) + ";")
+other_statement_def.setParseAction( replaceWith("") )
+comment_def = "--" + ZeroOrMore(CharsNotIn("\n"))
+comment_def.setParseAction( replaceWith("") )
+
+statement_def = comment_def | create_table_def | add_fkey_def | other_statement_def
+defs = OneOrMore(statement_def)
+
+print("""digraph g { graph [ rankdir = "LR" ]; """)
+for i in defs.parseString(sampleSQL):
+ if i!="":
+ print(i)
+print("}") \ No newline at end of file
diff --git a/examples/stackish.py b/examples/stackish.py
new file mode 100644
index 0000000..f80b4d6
--- /dev/null
+++ b/examples/stackish.py
@@ -0,0 +1,81 @@
+# stackish.py
+#
+# Stackish is a data representation syntax, similar to JSON or YAML. For more info on
+# stackish, see http://www.savingtheinternetwithhate.com/stackish.html
+#
+# Copyright 2008, Paul McGuire
+#
+
+"""
+NUMBER A simple integer type that's just any series of digits.
+FLOAT A simple floating point type.
+STRING A string is double quotes with anything inside that's not a " or
+ newline character. You can include \n and \" to include these
+ characters.
+MARK Marks a point in the stack that demarcates the boundary for a nested
+ group.
+WORD Marks the root node of a group, with the other end being the nearest
+ MARK.
+GROUP Acts as the root node of an anonymous group.
+ATTRIBUTE Assigns an attribute name to the previously processed node.
+ This means that just about anything can be an attribute, unlike in XML.
+BLOB A BLOB is unique to Stackish and allows you to record any content
+ (even binary content) inside the structure. This is done by pre-
+ sizing the data with the NUMBER similar to Dan Bernstein's netstrings
+ setup.
+SPACE White space is basically ignored. This is interesting because since
+ Stackish is serialized consistently this means you can use \n as the
+ separation character and perform reasonable diffs on two structures.
+"""
+
+from pyparsing import Suppress,Word,nums,alphas,alphanums,Combine,oneOf,\
+ Optional,QuotedString,Forward,Group,ZeroOrMore,printables,srange
+
+MARK,UNMARK,AT,COLON,QUOTE = map(Suppress,"[]@:'")
+
+NUMBER = Word(nums)
+NUMBER.setParseAction(lambda t:int(t[0]))
+FLOAT = Combine(oneOf("+ -") + Word(nums) + "." + Optional(Word(nums)))
+FLOAT.setParseAction(lambda t:float(t[0]))
+STRING = QuotedString('"', multiline=True)
+WORD = Word(alphas,alphanums+"_:")
+ATTRIBUTE = Combine(AT + WORD)
+
+strBody = Forward()
+def setBodyLength(tokens):
+ strBody << Word(srange(r'[\0x00-\0xffff]'), exact=int(tokens[0]))
+ return ""
+BLOB = Combine(QUOTE + Word(nums).setParseAction(setBodyLength) +
+ COLON + strBody + QUOTE)
+
+item = Forward()
+def assignUsing(s):
+ def assignPA(tokens):
+ if s in tokens:
+ tokens[tokens[s]] = tokens[0]
+ del tokens[s]
+ return assignPA
+GROUP = (MARK +
+ Group( ZeroOrMore(
+ (item +
+ Optional(ATTRIBUTE)("attr")
+ ).setParseAction(assignUsing("attr"))
+ )
+ ) +
+ ( WORD("name") | UNMARK )
+ ).setParseAction(assignUsing("name"))
+item << (NUMBER | FLOAT | STRING | BLOB | GROUP )
+
+tests = """\
+[ '10:1234567890' @name 25 @age +0.45 @percentage person:zed
+[ [ "hello" 1 child root
+[ "child" [ 200 '4:like' "I" "hello" things root
+[ [ "data" [ 2 1 ] @numbers child root
+[ [ 1 2 3 ] @test 4 5 6 root
+""".splitlines()
+
+for test in tests:
+ if test:
+ print(test)
+ print(item.parseString(test).dump())
+ print()
diff --git a/examples/stateMachine2.py b/examples/stateMachine2.py
new file mode 100644
index 0000000..eb6633d
--- /dev/null
+++ b/examples/stateMachine2.py
@@ -0,0 +1,258 @@
+# stateMachine.py
+#
+# module to define .pystate import handler
+#
+#import imputil
+import sys
+import os
+import types
+import urllib.parse
+
+DEBUG = False
+
+from pyparsing import Word, Group, ZeroOrMore, alphas, \
+ alphanums, ParserElement, ParseException, ParseSyntaxException, \
+ Empty, LineEnd, OneOrMore, col, Keyword, pythonStyleComment, \
+ StringEnd, traceParseAction
+
+
+ident = Word(alphas+"_", alphanums+"_$")
+
+pythonKeywords = """and as assert break class continue def
+ del elif else except exec finally for from global if import
+ in is lambda None not or pass print raise return try while with
+ yield True False"""
+pythonKeywords = set(pythonKeywords.split())
+def no_keywords_allowed(s,l,t):
+ wd = t[0]
+ if wd in pythonKeywords:
+ errmsg = "cannot not use keyword '%s' " \
+ "as an identifier" % wd
+ raise ParseException(s,l,errmsg)
+ident.setParseAction(no_keywords_allowed)
+
+stateTransition = ident("fromState") + "->" + ident("toState")
+stateMachine = Keyword("statemachine") + \
+ ident("name") + ":" + \
+ OneOrMore(Group(stateTransition))("transitions")
+
+namedStateTransition = (ident("fromState") + \
+ "-(" + ident("transition") + ")->" + \
+ ident("toState"))
+namedStateMachine = Keyword("statemachine") + \
+ ident("name") + ":" + \
+ OneOrMore(Group(namedStateTransition))("transitions")
+
+def expand_state_definition(source, loc, tokens):
+ indent = " " * (col(loc,source)-1)
+ statedef = []
+
+ # build list of states
+ states = set()
+ fromTo = {}
+ for tn in tokens.transitions:
+ states.add(tn.fromState)
+ states.add(tn.toState)
+ fromTo[tn.fromState] = tn.toState
+
+ # define base class for state classes
+ baseStateClass = tokens.name + "State"
+ statedef.extend([
+ "class %s(object):" % baseStateClass,
+ " def __str__(self):",
+ " return self.__class__.__name__",
+ " def next_state(self):",
+ " return self._next_state_class()" ])
+
+ # define all state classes
+ statedef.extend(
+ "class %s(%s): pass" % (s,baseStateClass)
+ for s in states )
+ statedef.extend(
+ "%s._next_state_class = %s" % (s,fromTo[s])
+ for s in states if s in fromTo )
+
+ return indent + ("\n"+indent).join(statedef)+"\n"
+
+stateMachine.setParseAction(expand_state_definition)
+
+def expand_named_state_definition(source,loc,tokens):
+ indent = " " * (col(loc,source)-1)
+ statedef = []
+ # build list of states and transitions
+ states = set()
+ transitions = set()
+
+ baseStateClass = tokens.name + "State"
+
+ fromTo = {}
+ for tn in tokens.transitions:
+ states.add(tn.fromState)
+ states.add(tn.toState)
+ transitions.add(tn.transition)
+ if tn.fromState in fromTo:
+ fromTo[tn.fromState][tn.transition] = tn.toState
+ else:
+ fromTo[tn.fromState] = {tn.transition:tn.toState}
+
+ # add entries for terminal states
+ for s in states:
+ if s not in fromTo:
+ fromTo[s] = {}
+
+ # define state transition class
+ statedef.extend([
+ "class %sTransition:" % baseStateClass,
+ " def __str__(self):",
+ " return self.transitionName",
+ ])
+ statedef.extend(
+ "%s = %sTransition()" % (tn,baseStateClass)
+ for tn in transitions)
+ statedef.extend("%s.transitionName = '%s'" % (tn,tn)
+ for tn in transitions)
+
+ # define base class for state classes
+ excmsg = "'" + tokens.name + \
+ '.%s does not support transition "%s"' \
+ "'% (self, tn)"
+ statedef.extend([
+ "class %s(object):" % baseStateClass,
+ " def __str__(self):",
+ " return self.__class__.__name__",
+ " def next_state(self,tn):",
+ " try:",
+ " return self.tnmap[tn]()",
+ " except KeyError:",
+ " raise Exception(%s)" % excmsg,
+ " def __getattr__(self,name):",
+ " raise Exception(%s)" % excmsg,
+ ])
+
+ # define all state classes
+ for s in states:
+ statedef.append("class %s(%s): pass" %
+ (s,baseStateClass))
+
+ # define state transition maps and transition methods
+ for s in states:
+ trns = list(fromTo[s].items())
+ statedef.append("%s.tnmap = {%s}" %
+ (s, ",".join("%s:%s" % tn for tn in trns)) )
+ statedef.extend([
+ "%s.%s = staticmethod(lambda : %s())" %
+ (s,tn_,to_)
+ for tn_,to_ in trns
+ ])
+
+ return indent + ("\n"+indent).join(statedef) + "\n"
+
+namedStateMachine.setParseAction(
+ expand_named_state_definition)
+
+#======================================================================
+# NEW STUFF - Matt Anderson, 2009-11-26
+#======================================================================
+class SuffixImporter(object):
+
+ """An importer designed using the mechanism defined in :pep:`302`. I read
+ the PEP, and also used Doug Hellmann's PyMOTW article `Modules and
+ Imports`_, as a pattern.
+
+ .. _`Modules and Imports`: http://www.doughellmann.com/PyMOTW/sys/imports.html
+
+ Define a subclass that specifies a :attr:`suffix` attribute, and
+ implements a :meth:`process_filedata` method. Then call the classmethod
+ :meth:`register` on your class to actually install it in the appropriate
+ places in :mod:`sys`. """
+
+ scheme = 'suffix'
+ suffix = None
+ path_entry = None
+
+ @classmethod
+ def trigger_url(cls):
+ if cls.suffix is None:
+ raise ValueError('%s.suffix is not set' % cls.__name__)
+ return 'suffix:%s' % cls.suffix
+
+ @classmethod
+ def register(cls):
+ sys.path_hooks.append(cls)
+ sys.path.append(cls.trigger_url())
+
+ def __init__(self, path_entry):
+ pr = urllib.parse.urlparse(str(path_entry))
+ if pr.scheme != self.scheme or pr.path != self.suffix:
+ raise ImportError()
+ self.path_entry = path_entry
+ self._found = {}
+
+ def checkpath_iter(self, fullname):
+ for dirpath in sys.path:
+ # if the value in sys.path_importer_cache is None, then this
+ # path *should* be imported by the builtin mechanism, and the
+ # entry is thus a path to a directory on the filesystem;
+ # if it's not None, then some other importer is in charge, and
+ # it probably isn't even a filesystem path
+ if sys.path_importer_cache.get(dirpath,False) is None:
+ checkpath = os.path.join(
+ dirpath,'%s.%s' % (fullname,self.suffix))
+ yield checkpath
+
+ def find_module(self, fullname, path=None):
+ for checkpath in self.checkpath_iter(fullname):
+ if os.path.isfile(checkpath):
+ self._found[fullname] = checkpath
+ return self
+ return None
+
+ def load_module(self, fullname):
+ assert fullname in self._found
+ if fullname in sys.modules:
+ module = sys.modules[fullname]
+ else:
+ sys.modules[fullname] = module = types.ModuleType(fullname)
+ data = None
+ f = open(self._found[fullname])
+ try:
+ data = f.read()
+ finally:
+ f.close()
+
+ module.__dict__.clear()
+ module.__file__ = self._found[fullname]
+ module.__name__ = fullname
+ module.__loader__ = self
+ self.process_filedata(module, data)
+ return module
+
+ def process_filedata(self, module, data):
+ pass
+
+class PystateImporter(SuffixImporter):
+ suffix = 'pystate'
+
+ def process_filedata(self, module, data):
+ # MATT-NOTE: re-worked :func:`get_state_machine`
+
+ # convert any statemachine expressions
+ stateMachineExpr = (stateMachine |
+ namedStateMachine).ignore(
+ pythonStyleComment)
+ generated_code = stateMachineExpr.transformString(data)
+
+ if DEBUG: print(generated_code)
+
+ # compile code object from generated code
+ # (strip trailing spaces and tabs, compile doesn't like
+ # dangling whitespace)
+ COMPILE_MODE = 'exec'
+
+ codeobj = compile(generated_code.rstrip(" \t"),
+ module.__file__,
+ COMPILE_MODE)
+
+ exec(codeobj, module.__dict__)
+
+PystateImporter.register()
diff --git a/examples/test_bibparse.py b/examples/test_bibparse.py
new file mode 100644
index 0000000..7440a66
--- /dev/null
+++ b/examples/test_bibparse.py
@@ -0,0 +1,195 @@
+""" Test for bibparse grammar """
+
+from os.path import join as pjoin, dirname
+
+from pyparsing import ParseException
+from btpyparse import Macro
+import btpyparse as bp
+
+from nose.tools import assert_true, assert_false, assert_equal, assert_raises
+
+
+def test_names():
+ # check various types of names
+ # All names can contains alphas, but not some special chars
+ bad_chars = '"#%\'(),={}'
+ for name_type, dig1f in ((bp.macro_def, False),
+ (bp.field_name, False),
+ (bp.entry_type, False),
+ (bp.cite_key, True)):
+ if dig1f: # can start with digit
+ assert_equal(name_type.parseString('2t')[0], '2t')
+ else:
+ assert_raises(ParseException, name_type.parseString, '2t')
+ # All of the names cannot contain some characters
+ for char in bad_chars:
+ assert_raises(ParseException, name_type.parseString, char)
+ # standard strings all OK
+ assert_equal(name_type.parseString('simple_test')[0], 'simple_test')
+ # Test macro ref
+ mr = bp.macro_ref
+ # can't start with digit
+ assert_raises(ParseException, mr.parseString, '2t')
+ for char in bad_chars:
+ assert_raises(ParseException, mr.parseString, char)
+ assert_equal(mr.parseString('simple_test')[0].name, 'simple_test')
+
+
+def test_numbers():
+ assert_equal(bp.number.parseString('1066')[0], '1066')
+ assert_equal(bp.number.parseString('0')[0], '0')
+ assert_raises(ParseException, bp.number.parseString, '-4')
+ assert_raises(ParseException, bp.number.parseString, '+4')
+ assert_raises(ParseException, bp.number.parseString, '.4')
+ # something point something leaves a trailing .4 unmatched
+ assert_equal(bp.number.parseString('0.4')[0], '0')
+
+
+def test_parse_string():
+ # test string building blocks
+ assert_equal(bp.chars_no_quotecurly.parseString('x')[0], 'x')
+ assert_equal(bp.chars_no_quotecurly.parseString("a string")[0], 'a string')
+ assert_equal(bp.chars_no_quotecurly.parseString('a "string')[0], 'a ')
+ assert_equal(bp.chars_no_curly.parseString('x')[0], 'x')
+ assert_equal(bp.chars_no_curly.parseString("a string")[0], 'a string')
+ assert_equal(bp.chars_no_curly.parseString('a {string')[0], 'a ')
+ assert_equal(bp.chars_no_curly.parseString('a }string')[0], 'a ')
+ # test more general strings together
+ for obj in (bp.curly_string, bp.string, bp.field_value):
+ assert_equal(obj.parseString('{}').asList(), [])
+ assert_equal(obj.parseString('{a "string}')[0], 'a "string')
+ assert_equal(obj.parseString('{a {nested} string}').asList(),
+ ['a ', ['nested'], ' string'])
+ assert_equal(obj.parseString('{a {double {nested}} string}').asList(),
+ ['a ', ['double ', ['nested']], ' string'])
+ for obj in (bp.quoted_string, bp.string, bp.field_value):
+ assert_equal(obj.parseString('""').asList(), [])
+ assert_equal(obj.parseString('"a string"')[0], 'a string')
+ assert_equal(obj.parseString('"a {nested} string"').asList(),
+ ['a ', ['nested'], ' string'])
+ assert_equal(obj.parseString('"a {double {nested}} string"').asList(),
+ ['a ', ['double ', ['nested']], ' string'])
+ # check macro def in string
+ assert_equal(bp.string.parseString('someascii')[0], Macro('someascii'))
+ assert_raises(ParseException, bp.string.parseString, '%#= validstring')
+ # check number in string
+ assert_equal(bp.string.parseString('1994')[0], '1994')
+
+
+def test_parse_field():
+ # test field value - hashes included
+ fv = bp.field_value
+ # Macro
+ assert_equal(fv.parseString('aname')[0], Macro('aname'))
+ assert_equal(fv.parseString('ANAME')[0], Macro('aname'))
+ # String and macro
+ assert_equal(fv.parseString('aname # "some string"').asList(),
+ [Macro('aname'), 'some string'])
+ # Nested string
+ assert_equal(fv.parseString('aname # {some {string}}').asList(),
+ [Macro('aname'), 'some ', ['string']])
+ # String and number
+ assert_equal(fv.parseString('"a string" # 1994').asList(),
+ ['a string', '1994'])
+ # String and number and macro
+ assert_equal(fv.parseString('"a string" # 1994 # a_macro').asList(),
+ ['a string', '1994', Macro('a_macro')])
+
+
+def test_comments():
+ res = bp.comment.parseString('@Comment{about something}')
+ assert_equal(res.asList(), ['comment', '{about something}'])
+ assert_equal(
+ bp.comment.parseString('@COMMENT{about something').asList(),
+ ['comment', '{about something'])
+ assert_equal(
+ bp.comment.parseString('@comment(about something').asList(),
+ ['comment', '(about something'])
+ assert_equal(
+ bp.comment.parseString('@COMment about something').asList(),
+ ['comment', ' about something'])
+ assert_raises(ParseException, bp.comment.parseString,
+ '@commentabout something')
+ assert_raises(ParseException, bp.comment.parseString,
+ '@comment+about something')
+ assert_raises(ParseException, bp.comment.parseString,
+ '@comment"about something')
+
+
+def test_preamble():
+ res = bp.preamble.parseString('@preamble{"about something"}')
+ assert_equal(res.asList(), ['preamble', 'about something'])
+ assert_equal(bp.preamble.parseString(
+ '@PREamble{{about something}}').asList(),
+ ['preamble', 'about something'])
+ assert_equal(bp.preamble.parseString("""@PREamble{
+ {about something}
+ }""").asList(),
+ ['preamble', 'about something'])
+
+
+def test_macro():
+ res = bp.macro.parseString('@string{ANAME = "about something"}')
+ assert_equal(res.asList(), ['string', 'aname', 'about something'])
+ assert_equal(
+ bp.macro.parseString('@string{aname = {about something}}').asList(),
+ ['string', 'aname', 'about something'])
+
+
+def test_entry():
+ txt = """@some_entry{akey, aname = "about something",
+ another={something else}}"""
+ res = bp.entry.parseString(txt)
+ assert_equal(res.asList(),
+ ['some_entry', 'akey',
+ ['aname', 'about something'], ['another', 'something else']])
+ # Case conversion
+ txt = """@SOME_ENTRY{akey, ANAME = "about something",
+ another={something else}}"""
+ res = bp.entry.parseString(txt)
+ assert_equal(res.asList(),
+ ['some_entry', 'akey',
+ ['aname', 'about something'], ['another', 'something else']])
+
+
+def test_bibfile():
+ txt = """@some_entry{akey, aname = "about something",
+ another={something else}}"""
+ res = bp.bibfile.parseString(txt)
+ assert_equal(res.asList(),
+ [['some_entry', 'akey',
+ ['aname', 'about something'],
+ ['another', 'something else']]])
+
+
+def test_bib1():
+ # First pass whole bib-like tests
+ txt = """
+Some introductory text
+(implicit comment)
+
+ @ARTICLE{Brett2002marsbar,
+ author = {Matthew Brett and Jean-Luc Anton and Romain Valabregue and Jean-Baptise
+ Poline},
+ title = {{Region of interest analysis using an SPM toolbox}},
+ journal = {Neuroimage},
+ year = {2002},
+ volume = {16},
+ pages = {1140--1141},
+ number = {2}
+}
+
+@some_entry{akey, aname = "about something",
+another={something else}}
+"""
+ res = bp.bibfile.parseString(txt)
+ assert_equal(len(res), 3)
+ res2 = bp.parse_str(txt)
+ assert_equal(res.asList(), res2.asList())
+ res3 = [r.asList()[0] for r, start, end in bp.definitions.scanString(txt)]
+ assert_equal(res.asList(), res3)
+
+
+if __name__ == '__main__':
+ import nose
+ nose.main()
diff --git a/examples/urlExtractor.py b/examples/urlExtractor.py
new file mode 100644
index 0000000..2c66d78
--- /dev/null
+++ b/examples/urlExtractor.py
@@ -0,0 +1,33 @@
+# URL extractor
+# Copyright 2004, Paul McGuire
+from pyparsing import makeHTMLTags, SkipTo, pyparsing_common
+import urllib.request
+from contextlib import closing
+import pprint
+
+linkOpenTag, linkCloseTag = makeHTMLTags('a')
+
+linkBody = SkipTo(linkCloseTag)
+linkBody.setParseAction(pyparsing_common.stripHTMLTags)
+linkBody.addParseAction(lambda toks: ' '.join(toks[0].strip().split()))
+
+link = linkOpenTag + linkBody("body") + linkCloseTag.suppress()
+
+# Go get some HTML with some links in it.
+with closing(urllib.request.urlopen("http://www.yahoo.com")) as serverListPage:
+ htmlText = serverListPage.read().decode("UTF-8")
+
+# scanString is a generator that loops through the input htmlText, and for each
+# match yields the tokens and start and end locations (for this application, we are
+# not interested in the start and end values).
+for toks,strt,end in link.scanString(htmlText):
+ print(toks.asList())
+
+# Create dictionary from list comprehension, assembled from each pair of tokens returned
+# from a matched URL.
+pprint.pprint(
+ dict((toks.body, toks.href) for toks,strt,end in link.scanString(htmlText))
+ )
+
+
+
diff --git a/examples/urlExtractorNew.py b/examples/urlExtractorNew.py
new file mode 100644
index 0000000..0aac875
--- /dev/null
+++ b/examples/urlExtractorNew.py
@@ -0,0 +1,35 @@
+# URL extractor
+# Copyright 2004, Paul McGuire
+from pyparsing import Literal,Suppress,CharsNotIn,CaselessLiteral,\
+ Word,dblQuotedString,alphanums,SkipTo,makeHTMLTags
+import urllib.request, urllib.parse, urllib.error
+import pprint
+
+# Define the pyparsing grammar for a URL, that is:
+# URLlink ::= <a href= URL>linkText</a>
+# URL ::= doubleQuotedString | alphanumericWordPath
+# Note that whitespace may appear just about anywhere in the link. Note also
+# that it is not necessary to explicitly show this in the pyparsing grammar; by default,
+# pyparsing skips over whitespace between tokens.
+linkOpenTag,linkCloseTag = makeHTMLTags("a")
+link = linkOpenTag + SkipTo(linkCloseTag)("body") + linkCloseTag.suppress()
+
+# Go get some HTML with some links in it.
+serverListPage = urllib.request.urlopen( "http://www.google.com" )
+htmlText = serverListPage.read()
+serverListPage.close()
+
+# scanString is a generator that loops through the input htmlText, and for each
+# match yields the tokens and start and end locations (for this application, we are
+# not interested in the start and end values).
+for toks,strt,end in link.scanString(htmlText):
+ print(toks.startA.href,"->",toks.body)
+
+# Create dictionary from list comprehension, assembled from each pair of tokens returned
+# from a matched URL.
+pprint.pprint(
+ dict( [ (toks.body,toks.startA.href) for toks,strt,end in link.scanString(htmlText) ] )
+ )
+
+
+
diff --git a/examples/verilogParse.py b/examples/verilogParse.py
new file mode 100644
index 0000000..05650df
--- /dev/null
+++ b/examples/verilogParse.py
@@ -0,0 +1,720 @@
+#
+# verilogParse.py
+#
+# an example of using the pyparsing module to be able to process Verilog files
+# uses BNF defined at http://www.verilog.com/VerilogBNF.html
+#
+# Copyright (c) 2004-2011 Paul T. McGuire. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# If you find this software to be useful, please make a donation to one
+# of the following charities:
+# - the Red Cross (http://www.redcross.org)
+# - Hospice Austin (http://www.hospiceaustin.org)
+#
+# DISCLAIMER:
+# THIS SOFTWARE IS PROVIDED BY PAUL T. McGUIRE ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+# EVENT SHALL PAUL T. McGUIRE OR CO-CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OFUSE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# For questions or inquiries regarding this license, or commercial use of
+# this software, contact the author via e-mail: ptmcg@users.sourceforge.net
+#
+# Todo:
+# - add pre-process pass to implement compilerDirectives (ifdef, include, etc.)
+#
+# Revision History:
+#
+# 1.0 - Initial release
+# 1.0.1 - Fixed grammar errors:
+# . real declaration was incorrect
+# . tolerant of '=>' for '*>' operator
+# . tolerant of '?' as hex character
+# . proper handling of mintypmax_expr within path delays
+# 1.0.2 - Performance tuning (requires pyparsing 1.3)
+# 1.0.3 - Performance updates, using Regex (requires pyparsing 1.4)
+# 1.0.4 - Performance updates, enable packrat parsing (requires pyparsing 1.4.2)
+# 1.0.5 - Converted keyword Literals to Keywords, added more use of Group to
+# group parsed results tokens
+# 1.0.6 - Added support for module header with no ports list (thanks, Thomas Dejanovic!)
+# 1.0.7 - Fixed erroneous '<<' Forward definition in timCheckCond, omitting ()'s
+# 1.0.8 - Re-released under MIT license
+# 1.0.9 - Enhanced udpInstance to handle identifiers with leading '\' and subscripting
+# 1.0.10 - Fixed change added in 1.0.9 to work for all identifiers, not just those used
+# for udpInstance.
+# 1.0.11 - Fixed bug in inst_args, content alternatives were reversed
+#
+import pdb
+import time
+import pprint
+import sys
+
+__version__ = "1.0.11"
+
+from pyparsing import Literal, CaselessLiteral, Keyword, Word, OneOrMore, ZeroOrMore, \
+ Forward, NotAny, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
+ alphanums, printables, dblQuotedString, empty, ParseException, ParseResults, MatchFirst, oneOf, GoToColumn, \
+ ParseResults,StringEnd, FollowedBy, ParserElement, And, Regex, cppStyleComment#,__version__
+import pyparsing
+usePackrat = False
+usePsyco = False
+
+packratOn = False
+psycoOn = False
+
+if usePackrat:
+ try:
+ ParserElement.enablePackrat()
+ except:
+ pass
+ else:
+ packratOn = True
+
+# comment out this section to disable psyco function compilation
+if usePsyco:
+ try:
+ import psyco
+ psyco.full()
+ except:
+ print("failed to import psyco Python optimizer")
+ else:
+ psycoOn = True
+
+
+def dumpTokens(s,l,t):
+ import pprint
+ pprint.pprint( t.asList() )
+
+verilogbnf = None
+def Verilog_BNF():
+ global verilogbnf
+
+ if verilogbnf is None:
+
+ # compiler directives
+ compilerDirective = Combine( "`" + \
+ oneOf("define undef ifdef else endif default_nettype "
+ "include resetall timescale unconnected_drive "
+ "nounconnected_drive celldefine endcelldefine") + \
+ restOfLine ).setName("compilerDirective")
+
+ # primitives
+ SEMI,COLON,LPAR,RPAR,LBRACE,RBRACE,LBRACK,RBRACK,DOT,COMMA,EQ = map(Literal,";:(){}[].,=")
+
+ identLead = alphas+"$_"
+ identBody = alphanums+"$_"
+ identifier1 = Regex( r"\.?["+identLead+"]["+identBody+r"]*(\.["+identLead+"]["+identBody+"]*)*"
+ ).setName("baseIdent")
+ identifier2 = Regex(r"\\\S+").setParseAction(lambda t:t[0][1:]).setName("escapedIdent")#.setDebug()
+ identifier = identifier1 | identifier2
+ assert(identifier2 == r'\abc')
+
+ hexnums = nums + "abcdefABCDEF" + "_?"
+ base = Regex("'[bBoOdDhH]").setName("base")
+ basedNumber = Combine( Optional( Word(nums + "_") ) + base + Word(hexnums+"xXzZ"),
+ joinString=" ", adjacent=False ).setName("basedNumber")
+ #~ number = ( basedNumber | Combine( Word( "+-"+spacedNums, spacedNums ) +
+ #~ Optional( DOT + Optional( Word( spacedNums ) ) ) +
+ #~ Optional( e + Word( "+-"+spacedNums, spacedNums ) ) ).setName("numeric") )
+ number = ( basedNumber | \
+ Regex(r"[+-]?[0-9_]+(\.[0-9_]*)?([Ee][+-]?[0-9_]+)?") \
+ ).setName("numeric")
+ #~ decnums = nums + "_"
+ #~ octnums = "01234567" + "_"
+ expr = Forward().setName("expr")
+ concat = Group( LBRACE + delimitedList( expr ) + RBRACE )
+ multiConcat = Group("{" + expr + concat + "}").setName("multiConcat")
+ funcCall = Group(identifier + LPAR + Optional( delimitedList( expr ) ) + RPAR).setName("funcCall")
+
+ subscrRef = Group(LBRACK + delimitedList( expr, COLON ) + RBRACK)
+ subscrIdentifier = Group( identifier + Optional( subscrRef ) )
+ #~ scalarConst = "0" | (( FollowedBy('1') + oneOf("1'b0 1'b1 1'bx 1'bX 1'B0 1'B1 1'Bx 1'BX 1") ))
+ scalarConst = Regex("0|1('[Bb][01xX])?")
+ mintypmaxExpr = Group( expr + COLON + expr + COLON + expr ).setName("mintypmax")
+ primary = (
+ number |
+ (LPAR + mintypmaxExpr + RPAR ) |
+ ( LPAR + Group(expr) + RPAR ).setName("nestedExpr") |
+ multiConcat |
+ concat |
+ dblQuotedString |
+ funcCall |
+ subscrIdentifier
+ )
+
+ unop = oneOf( "+ - ! ~ & ~& | ^| ^ ~^" ).setName("unop")
+ binop = oneOf( "+ - * / % == != === !== && "
+ "|| < <= > >= & | ^ ^~ >> << ** <<< >>>" ).setName("binop")
+
+ expr << (
+ ( unop + expr ) | # must be first!
+ ( primary + "?" + expr + COLON + expr ) |
+ ( primary + Optional( binop + expr ) )
+ )
+
+ lvalue = subscrIdentifier | concat
+
+ # keywords
+ if_ = Keyword("if")
+ else_ = Keyword("else")
+ edge = Keyword("edge")
+ posedge = Keyword("posedge")
+ negedge = Keyword("negedge")
+ specify = Keyword("specify")
+ endspecify = Keyword("endspecify")
+ fork = Keyword("fork")
+ join = Keyword("join")
+ begin = Keyword("begin")
+ end = Keyword("end")
+ default = Keyword("default")
+ forever = Keyword("forever")
+ repeat = Keyword("repeat")
+ while_ = Keyword("while")
+ for_ = Keyword("for")
+ case = oneOf( "case casez casex" )
+ endcase = Keyword("endcase")
+ wait = Keyword("wait")
+ disable = Keyword("disable")
+ deassign = Keyword("deassign")
+ force = Keyword("force")
+ release = Keyword("release")
+ assign = Keyword("assign")
+
+ eventExpr = Forward()
+ eventTerm = ( posedge + expr ) | ( negedge + expr ) | expr | ( LPAR + eventExpr + RPAR )
+ eventExpr << (
+ Group( delimitedList( eventTerm, Keyword("or") ) )
+ )
+ eventControl = Group( "@" + ( ( LPAR + eventExpr + RPAR ) | identifier | "*" ) ).setName("eventCtrl")
+
+ delayArg = ( number |
+ Word(alphanums+"$_") | #identifier |
+ ( LPAR + Group( delimitedList( mintypmaxExpr | expr ) ) + RPAR )
+ ).setName("delayArg")#.setDebug()
+ delay = Group( "#" + delayArg ).setName("delay")#.setDebug()
+ delayOrEventControl = delay | eventControl
+
+ assgnmt = Group( lvalue + EQ + Optional( delayOrEventControl ) + expr ).setName( "assgnmt" )
+ nbAssgnmt = Group(( lvalue + "<=" + Optional( delay ) + expr ) |
+ ( lvalue + "<=" + Optional( eventControl ) + expr )).setName( "nbassgnmt" )
+
+ range = LBRACK + expr + COLON + expr + RBRACK
+
+ paramAssgnmt = Group( identifier + EQ + expr ).setName("paramAssgnmt")
+ parameterDecl = Group( "parameter" + Optional( range ) + delimitedList( paramAssgnmt ) + SEMI).setName("paramDecl")
+
+ inputDecl = Group( "input" + Optional( range ) + delimitedList( identifier ) + SEMI )
+ outputDecl = Group( "output" + Optional( range ) + delimitedList( identifier ) + SEMI )
+ inoutDecl = Group( "inout" + Optional( range ) + delimitedList( identifier ) + SEMI )
+
+ regIdentifier = Group( identifier + Optional( LBRACK + expr + COLON + expr + RBRACK ) )
+ regDecl = Group( "reg" + Optional("signed") + Optional( range ) + delimitedList( regIdentifier ) + SEMI ).setName("regDecl")
+ timeDecl = Group( "time" + delimitedList( regIdentifier ) + SEMI )
+ integerDecl = Group( "integer" + delimitedList( regIdentifier ) + SEMI )
+
+ strength0 = oneOf("supply0 strong0 pull0 weak0 highz0")
+ strength1 = oneOf("supply1 strong1 pull1 weak1 highz1")
+ driveStrength = Group( LPAR + ( ( strength0 + COMMA + strength1 ) |
+ ( strength1 + COMMA + strength0 ) ) + RPAR ).setName("driveStrength")
+ nettype = oneOf("wire tri tri1 supply0 wand triand tri0 supply1 wor trior trireg")
+ expandRange = Optional( oneOf("scalared vectored") ) + range
+ realDecl = Group( "real" + delimitedList( identifier ) + SEMI )
+
+ eventDecl = Group( "event" + delimitedList( identifier ) + SEMI )
+
+ blockDecl = (
+ parameterDecl |
+ regDecl |
+ integerDecl |
+ realDecl |
+ timeDecl |
+ eventDecl
+ )
+
+ stmt = Forward().setName("stmt")#.setDebug()
+ stmtOrNull = stmt | SEMI
+ caseItem = ( delimitedList( expr ) + COLON + stmtOrNull ) | \
+ ( default + Optional(":") + stmtOrNull )
+ stmt << Group(
+ ( begin + Group( ZeroOrMore( stmt ) ) + end ).setName("begin-end") |
+ ( if_ + Group(LPAR + expr + RPAR) + stmtOrNull + Optional( else_ + stmtOrNull ) ).setName("if") |
+ ( delayOrEventControl + stmtOrNull ) |
+ ( case + LPAR + expr + RPAR + OneOrMore( caseItem ) + endcase ) |
+ ( forever + stmt ) |
+ ( repeat + LPAR + expr + RPAR + stmt ) |
+ ( while_ + LPAR + expr + RPAR + stmt ) |
+ ( for_ + LPAR + assgnmt + SEMI + Group( expr ) + SEMI + assgnmt + RPAR + stmt ) |
+ ( fork + ZeroOrMore( stmt ) + join ) |
+ ( fork + COLON + identifier + ZeroOrMore( blockDecl ) + ZeroOrMore( stmt ) + end ) |
+ ( wait + LPAR + expr + RPAR + stmtOrNull ) |
+ ( "->" + identifier + SEMI ) |
+ ( disable + identifier + SEMI ) |
+ ( assign + assgnmt + SEMI ) |
+ ( deassign + lvalue + SEMI ) |
+ ( force + assgnmt + SEMI ) |
+ ( release + lvalue + SEMI ) |
+ ( begin + COLON + identifier + ZeroOrMore( blockDecl ) + ZeroOrMore( stmt ) + end ).setName("begin:label-end") |
+ # these *have* to go at the end of the list!!!
+ ( assgnmt + SEMI ) |
+ ( nbAssgnmt + SEMI ) |
+ ( Combine( Optional("$") + identifier ) + Optional( LPAR + delimitedList(expr|empty) + RPAR ) + SEMI )
+ ).setName("stmtBody")
+ """
+ x::=<blocking_assignment> ;
+ x||= <non_blocking_assignment> ;
+ x||= if ( <expression> ) <statement_or_null>
+ x||= if ( <expression> ) <statement_or_null> else <statement_or_null>
+ x||= case ( <expression> ) <case_item>+ endcase
+ x||= casez ( <expression> ) <case_item>+ endcase
+ x||= casex ( <expression> ) <case_item>+ endcase
+ x||= forever <statement>
+ x||= repeat ( <expression> ) <statement>
+ x||= while ( <expression> ) <statement>
+ x||= for ( <assignment> ; <expression> ; <assignment> ) <statement>
+ x||= <delay_or_event_control> <statement_or_null>
+ x||= wait ( <expression> ) <statement_or_null>
+ x||= -> <name_of_event> ;
+ x||= <seq_block>
+ x||= <par_block>
+ x||= <task_enable>
+ x||= <system_task_enable>
+ x||= disable <name_of_task> ;
+ x||= disable <name_of_block> ;
+ x||= assign <assignment> ;
+ x||= deassign <lvalue> ;
+ x||= force <assignment> ;
+ x||= release <lvalue> ;
+ """
+ alwaysStmt = Group( "always" + Optional(eventControl) + stmt ).setName("alwaysStmt")
+ initialStmt = Group( "initial" + stmt ).setName("initialStmt")
+
+ chargeStrength = Group( LPAR + oneOf( "small medium large" ) + RPAR ).setName("chargeStrength")
+
+ continuousAssign = Group(
+ assign + Optional( driveStrength ) + Optional( delay ) + delimitedList( assgnmt ) + SEMI
+ ).setName("continuousAssign")
+
+
+ tfDecl = (
+ parameterDecl |
+ inputDecl |
+ outputDecl |
+ inoutDecl |
+ regDecl |
+ timeDecl |
+ integerDecl |
+ realDecl
+ )
+
+ functionDecl = Group(
+ "function" + Optional( range | "integer" | "real" ) + identifier + SEMI +
+ Group( OneOrMore( tfDecl ) ) +
+ Group( ZeroOrMore( stmt ) ) +
+ "endfunction"
+ )
+
+ inputOutput = oneOf("input output")
+ netDecl1Arg = ( nettype +
+ Optional( expandRange ) +
+ Optional( delay ) +
+ Group( delimitedList( ~inputOutput + identifier ) ) )
+ netDecl2Arg = ( "trireg" +
+ Optional( chargeStrength ) +
+ Optional( expandRange ) +
+ Optional( delay ) +
+ Group( delimitedList( ~inputOutput + identifier ) ) )
+ netDecl3Arg = ( nettype +
+ Optional( driveStrength ) +
+ Optional( expandRange ) +
+ Optional( delay ) +
+ Group( delimitedList( assgnmt ) ) )
+ netDecl1 = Group(netDecl1Arg + SEMI).setName("netDecl1")
+ netDecl2 = Group(netDecl2Arg + SEMI).setName("netDecl2")
+ netDecl3 = Group(netDecl3Arg + SEMI).setName("netDecl3")
+
+ gateType = oneOf("and nand or nor xor xnor buf bufif0 bufif1 "
+ "not notif0 notif1 pulldown pullup nmos rnmos "
+ "pmos rpmos cmos rcmos tran rtran tranif0 "
+ "rtranif0 tranif1 rtranif1" )
+ gateInstance = Optional( Group( identifier + Optional( range ) ) ) + \
+ LPAR + Group( delimitedList( expr ) ) + RPAR
+ gateDecl = Group( gateType +
+ Optional( driveStrength ) +
+ Optional( delay ) +
+ delimitedList( gateInstance) +
+ SEMI )
+
+ udpInstance = Group( Group( identifier + Optional(range | subscrRef) ) +
+ LPAR + Group( delimitedList( expr ) ) + RPAR )
+ udpInstantiation = Group( identifier -
+ Optional( driveStrength ) +
+ Optional( delay ) +
+ delimitedList( udpInstance ) +
+ SEMI ).setName("udpInstantiation")
+
+ parameterValueAssignment = Group( Literal("#") + LPAR + Group( delimitedList( expr ) ) + RPAR )
+ namedPortConnection = Group( DOT + identifier + LPAR + expr + RPAR ).setName("namedPortConnection")#.setDebug()
+ assert(r'.\abc (abc )' == namedPortConnection)
+ modulePortConnection = expr | empty
+ #~ moduleInstance = Group( Group ( identifier + Optional(range) ) +
+ #~ ( delimitedList( modulePortConnection ) |
+ #~ delimitedList( namedPortConnection ) ) )
+ inst_args = Group( LPAR + (delimitedList( namedPortConnection ) |
+ delimitedList( modulePortConnection )) + RPAR).setName("inst_args")
+ moduleInstance = Group( Group ( identifier + Optional(range) ) + inst_args ).setName("moduleInstance")#.setDebug()
+
+ moduleInstantiation = Group( identifier +
+ Optional( parameterValueAssignment ) +
+ delimitedList( moduleInstance ).setName("moduleInstanceList") +
+ SEMI ).setName("moduleInstantiation")
+
+ parameterOverride = Group( "defparam" + delimitedList( paramAssgnmt ) + SEMI )
+ task = Group( "task" + identifier + SEMI +
+ ZeroOrMore( tfDecl ) +
+ stmtOrNull +
+ "endtask" )
+
+ specparamDecl = Group( "specparam" + delimitedList( paramAssgnmt ) + SEMI )
+
+ pathDescr1 = Group( LPAR + subscrIdentifier + "=>" + subscrIdentifier + RPAR )
+ pathDescr2 = Group( LPAR + Group( delimitedList( subscrIdentifier ) ) + "*>" +
+ Group( delimitedList( subscrIdentifier ) ) + RPAR )
+ pathDescr3 = Group( LPAR + Group( delimitedList( subscrIdentifier ) ) + "=>" +
+ Group( delimitedList( subscrIdentifier ) ) + RPAR )
+ pathDelayValue = Group( ( LPAR + Group( delimitedList( mintypmaxExpr | expr ) ) + RPAR ) |
+ mintypmaxExpr |
+ expr )
+ pathDecl = Group( ( pathDescr1 | pathDescr2 | pathDescr3 ) + EQ + pathDelayValue + SEMI ).setName("pathDecl")
+
+ portConditionExpr = Forward()
+ portConditionTerm = Optional(unop) + subscrIdentifier
+ portConditionExpr << portConditionTerm + Optional( binop + portConditionExpr )
+ polarityOp = oneOf("+ -")
+ levelSensitivePathDecl1 = Group(
+ if_ + Group(LPAR + portConditionExpr + RPAR) +
+ subscrIdentifier + Optional( polarityOp ) + "=>" + subscrIdentifier + EQ +
+ pathDelayValue +
+ SEMI )
+ levelSensitivePathDecl2 = Group(
+ if_ + Group(LPAR + portConditionExpr + RPAR) +
+ LPAR + Group( delimitedList( subscrIdentifier ) ) + Optional( polarityOp ) + "*>" +
+ Group( delimitedList( subscrIdentifier ) ) + RPAR + EQ +
+ pathDelayValue +
+ SEMI )
+ levelSensitivePathDecl = levelSensitivePathDecl1 | levelSensitivePathDecl2
+
+ edgeIdentifier = posedge | negedge
+ edgeSensitivePathDecl1 = Group(
+ Optional( if_ + Group(LPAR + expr + RPAR) ) +
+ LPAR + Optional( edgeIdentifier ) +
+ subscrIdentifier + "=>" +
+ LPAR + subscrIdentifier + Optional( polarityOp ) + COLON + expr + RPAR + RPAR +
+ EQ +
+ pathDelayValue +
+ SEMI )
+ edgeSensitivePathDecl2 = Group(
+ Optional( if_ + Group(LPAR + expr + RPAR) ) +
+ LPAR + Optional( edgeIdentifier ) +
+ subscrIdentifier + "*>" +
+ LPAR + delimitedList( subscrIdentifier ) + Optional( polarityOp ) + COLON + expr + RPAR + RPAR +
+ EQ +
+ pathDelayValue +
+ SEMI )
+ edgeSensitivePathDecl = edgeSensitivePathDecl1 | edgeSensitivePathDecl2
+
+ edgeDescr = oneOf("01 10 0x x1 1x x0").setName("edgeDescr")
+
+ timCheckEventControl = Group( posedge | negedge | (edge + LBRACK + delimitedList( edgeDescr ) + RBRACK ))
+ timCheckCond = Forward()
+ timCondBinop = oneOf("== === != !==")
+ timCheckCondTerm = ( expr + timCondBinop + scalarConst ) | ( Optional("~") + expr )
+ timCheckCond << ( ( LPAR + timCheckCond + RPAR ) | timCheckCondTerm )
+ timCheckEvent = Group( Optional( timCheckEventControl ) +
+ subscrIdentifier +
+ Optional( "&&&" + timCheckCond ) )
+ timCheckLimit = expr
+ controlledTimingCheckEvent = Group( timCheckEventControl + subscrIdentifier +
+ Optional( "&&&" + timCheckCond ) )
+ notifyRegister = identifier
+
+ systemTimingCheck1 = Group( "$setup" +
+ LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck2 = Group( "$hold" +
+ LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck3 = Group( "$period" +
+ LPAR + controlledTimingCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck4 = Group( "$width" +
+ LPAR + controlledTimingCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + expr + COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck5 = Group( "$skew" +
+ LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck6 = Group( "$recovery" +
+ LPAR + controlledTimingCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck7 = Group( "$setuphold" +
+ LPAR + timCheckEvent + COMMA + timCheckEvent + COMMA + timCheckLimit + COMMA + timCheckLimit +
+ Optional( COMMA + notifyRegister ) + RPAR +
+ SEMI )
+ systemTimingCheck = (FollowedBy('$') + ( systemTimingCheck1 | systemTimingCheck2 | systemTimingCheck3 |
+ systemTimingCheck4 | systemTimingCheck5 | systemTimingCheck6 | systemTimingCheck7 )).setName("systemTimingCheck")
+ sdpd = if_ + Group(LPAR + expr + RPAR) + \
+ ( pathDescr1 | pathDescr2 ) + EQ + pathDelayValue + SEMI
+
+ specifyItem = ~Keyword("endspecify") +(
+ specparamDecl |
+ pathDecl |
+ levelSensitivePathDecl |
+ edgeSensitivePathDecl |
+ systemTimingCheck |
+ sdpd
+ )
+ """
+ x::= <specparam_declaration>
+ x||= <path_declaration>
+ x||= <level_sensitive_path_declaration>
+ x||= <edge_sensitive_path_declaration>
+ x||= <system_timing_check>
+ x||= <sdpd>
+ """
+ specifyBlock = Group( "specify" + ZeroOrMore( specifyItem ) + "endspecify" ).setName("specifyBlock")
+
+ moduleItem = ~Keyword("endmodule") + (
+ parameterDecl |
+ inputDecl |
+ outputDecl |
+ inoutDecl |
+ regDecl |
+ netDecl3 |
+ netDecl1 |
+ netDecl2 |
+ timeDecl |
+ integerDecl |
+ realDecl |
+ eventDecl |
+ gateDecl |
+ parameterOverride |
+ continuousAssign |
+ specifyBlock |
+ initialStmt |
+ alwaysStmt |
+ task |
+ functionDecl |
+ # these have to be at the end - they start with identifiers
+ moduleInstantiation |
+ udpInstantiation
+ )
+ """ All possible moduleItems, from Verilog grammar spec
+ x::= <parameter_declaration>
+ x||= <input_declaration>
+ x||= <output_declaration>
+ x||= <inout_declaration>
+ ?||= <net_declaration> (spec does not seem consistent for this item)
+ x||= <reg_declaration>
+ x||= <time_declaration>
+ x||= <integer_declaration>
+ x||= <real_declaration>
+ x||= <event_declaration>
+ x||= <gate_declaration>
+ x||= <UDP_instantiation>
+ x||= <module_instantiation>
+ x||= <parameter_override>
+ x||= <continuous_assign>
+ x||= <specify_block>
+ x||= <initial_statement>
+ x||= <always_statement>
+ x||= <task>
+ x||= <function>
+ """
+ portRef = subscrIdentifier
+ portExpr = portRef | Group( LBRACE + delimitedList( portRef ) + RBRACE )
+ port = portExpr | Group( ( DOT + identifier + LPAR + portExpr + RPAR ) )
+
+ moduleHdr = Group ( oneOf("module macromodule") + identifier +
+ Optional( LPAR + Group( Optional( delimitedList(
+ Group(oneOf("input output") +
+ (netDecl1Arg | netDecl2Arg | netDecl3Arg) ) |
+ port ) ) ) +
+ RPAR ) + SEMI ).setName("moduleHdr")
+
+ module = Group( moduleHdr +
+ Group( ZeroOrMore( moduleItem ) ) +
+ "endmodule" ).setName("module")#.setDebug()
+
+ udpDecl = outputDecl | inputDecl | regDecl
+ #~ udpInitVal = oneOf("1'b0 1'b1 1'bx 1'bX 1'B0 1'B1 1'Bx 1'BX 1 0 x X")
+ udpInitVal = (Regex("1'[bB][01xX]") | Regex("[01xX]")).setName("udpInitVal")
+ udpInitialStmt = Group( "initial" +
+ identifier + EQ + udpInitVal + SEMI ).setName("udpInitialStmt")
+
+ levelSymbol = oneOf("0 1 x X ? b B")
+ levelInputList = Group( OneOrMore( levelSymbol ).setName("levelInpList") )
+ outputSymbol = oneOf("0 1 x X")
+ combEntry = Group( levelInputList + COLON + outputSymbol + SEMI )
+ edgeSymbol = oneOf("r R f F p P n N *")
+ edge = Group( LPAR + levelSymbol + levelSymbol + RPAR ) | \
+ Group( edgeSymbol )
+ edgeInputList = Group( ZeroOrMore( levelSymbol ) + edge + ZeroOrMore( levelSymbol ) )
+ inputList = levelInputList | edgeInputList
+ seqEntry = Group( inputList + COLON + levelSymbol + COLON + ( outputSymbol | "-" ) + SEMI ).setName("seqEntry")
+ udpTableDefn = Group( "table" +
+ OneOrMore( combEntry | seqEntry ) +
+ "endtable" ).setName("table")
+
+ """
+ <UDP>
+ ::= primitive <name_of_UDP> ( <name_of_variable> <,<name_of_variable>>* ) ;
+ <UDP_declaration>+
+ <UDP_initial_statement>?
+ <table_definition>
+ endprimitive
+ """
+ udp = Group( "primitive" + identifier +
+ LPAR + Group( delimitedList( identifier ) ) + RPAR + SEMI +
+ OneOrMore( udpDecl ) +
+ Optional( udpInitialStmt ) +
+ udpTableDefn +
+ "endprimitive" )
+
+ verilogbnf = OneOrMore( module | udp ) + StringEnd()
+
+ verilogbnf.ignore( cppStyleComment )
+ verilogbnf.ignore( compilerDirective )
+
+ return verilogbnf
+
+
+def test( strng ):
+ tokens = []
+ try:
+ tokens = Verilog_BNF().parseString( strng )
+ except ParseException as err:
+ print(err.line)
+ print(" "*(err.column-1) + "^")
+ print(err)
+ return tokens
+
+
+#~ if __name__ == "__main__":
+if 0:
+ import pprint
+ toptest = """
+ module TOP( in, out );
+ input [7:0] in;
+ output [5:0] out;
+ COUNT_BITS8 count_bits( .IN( in ), .C( out ) );
+ endmodule"""
+ pprint.pprint( test(toptest).asList() )
+
+else:
+ def main():
+ print("Verilog parser test (V %s)" % __version__)
+ print(" - using pyparsing version", pyparsing.__version__)
+ print(" - using Python version", sys.version)
+ if packratOn: print(" - using packrat parsing")
+ if psycoOn: print(" - using psyco runtime optimization")
+ print()
+
+ import os
+ import gc
+
+ failCount = 0
+ Verilog_BNF()
+ numlines = 0
+ startTime = time.clock()
+ fileDir = "verilog"
+ #~ fileDir = "verilog/new"
+ #~ fileDir = "verilog/new2"
+ #~ fileDir = "verilog/new3"
+ allFiles = [f for f in os.listdir(fileDir) if f.endswith(".v")]
+ #~ allFiles = [ "list_path_delays_test.v" ]
+ #~ allFiles = [ "escapedIdent.v" ]
+ #~ allFiles = filter( lambda f : f.startswith("a") and f.endswith(".v"), os.listdir(fileDir) )
+ #~ allFiles = filter( lambda f : f.startswith("c") and f.endswith(".v"), os.listdir(fileDir) )
+ #~ allFiles = [ "ff.v" ]
+
+ pp = pprint.PrettyPrinter( indent=2 )
+ totalTime = 0
+ for vfile in allFiles:
+ gc.collect()
+ fnam = fileDir + "/"+vfile
+ infile = open(fnam)
+ filelines = infile.readlines()
+ infile.close()
+ print(fnam, len(filelines), end=' ')
+ numlines += len(filelines)
+ teststr = "".join(filelines)
+ time1 = time.clock()
+ tokens = test( teststr )
+ time2 = time.clock()
+ elapsed = time2-time1
+ totalTime += elapsed
+ if ( len( tokens ) ):
+ print("OK", elapsed)
+ #~ print "tokens="
+ #~ pp.pprint( tokens.asList() )
+ #~ print
+
+ ofnam = fileDir + "/parseOutput/" + vfile + ".parsed.txt"
+ outfile = open(ofnam,"w")
+ outfile.write( teststr )
+ outfile.write("\n")
+ outfile.write("\n")
+ outfile.write(pp.pformat(tokens.asList()))
+ outfile.write("\n")
+ outfile.close()
+ else:
+ print("failed", elapsed)
+ failCount += 1
+ for i,line in enumerate(filelines,1):
+ print("%4d: %s" % (i,line.rstrip()))
+ endTime = time.clock()
+ print("Total parse time:", totalTime)
+ print("Total source lines:", numlines)
+ print("Average lines/sec:", ( "%.1f" % (float(numlines)/(totalTime+.05 ) ) ))
+ if failCount:
+ print("FAIL - %d files failed to parse" % failCount)
+ else:
+ print("SUCCESS - all files parsed")
+
+ return 0
+
+ #~ from line_profiler import LineProfiler
+ #~ from pyparsing import ParseResults
+ #~ lp = LineProfiler(ParseResults.__init__)
+
+ main()
+
+ #~ lp.print_stats()
+ #~ import hotshot
+ #~ p = hotshot.Profile("vparse.prof",1,1)
+ #~ p.start()
+ #~ main()
+ #~ p.stop()
+ #~ p.close()
diff --git a/examples/withAttribute.py b/examples/withAttribute.py
new file mode 100644
index 0000000..062c9ae
--- /dev/null
+++ b/examples/withAttribute.py
@@ -0,0 +1,24 @@
+#
+# withAttribute.py
+# Copyright, 2007 - Paul McGuire
+#
+# Simple example of using withAttribute parse action helper
+# to define
+#
+data = """\
+ <td align=right width=80><font size=2 face="New Times Roman,Times,Serif">&nbsp;49.950&nbsp;</font></td>
+ <td align=left width=80><font size=2 face="New Times Roman,Times,Serif">&nbsp;50.950&nbsp;</font></td>
+ <td align=right width=80><font size=2 face="New Times Roman,Times,Serif">&nbsp;51.950&nbsp;</font></td>
+ """
+
+from pyparsing import *
+
+tdS,tdE = makeHTMLTags("TD")
+fontS,fontE = makeHTMLTags("FONT")
+realNum = Combine( Word(nums) + "." + Word(nums) ).setParseAction(lambda t:float(t[0]))
+NBSP = Literal("&nbsp;")
+patt = tdS + fontS + NBSP + realNum("value") + NBSP + fontE + tdE
+
+tdS.setParseAction( withAttribute(align="right",width="80") )
+for s in patt.searchString(data):
+ print(s.value)
diff --git a/examples/wordsToNum.py b/examples/wordsToNum.py
new file mode 100644
index 0000000..7cebbff
--- /dev/null
+++ b/examples/wordsToNum.py
@@ -0,0 +1,106 @@
+# wordsToNum.py
+# Copyright 2006, Paul McGuire
+#
+# Sample parser grammar to read a number given in words, and return the numeric value.
+#
+from pyparsing import *
+from operator import mul
+from functools import reduce
+
+def makeLit(s,val):
+ ret = CaselessLiteral(s).setName(s)
+ return ret.setParseAction( replaceWith(val) )
+
+unitDefinitions = [
+ ("zero", 0),
+ ("oh", 0),
+ ("zip", 0),
+ ("zilch", 0),
+ ("nada", 0),
+ ("bupkis", 0),
+ ("one", 1),
+ ("two", 2),
+ ("three", 3),
+ ("four", 4),
+ ("five", 5),
+ ("six", 6),
+ ("seven", 7),
+ ("eight", 8),
+ ("nine", 9),
+ ("ten", 10),
+ ("eleven", 11),
+ ("twelve", 12),
+ ("thirteen", 13),
+ ("fourteen", 14),
+ ("fifteen", 15),
+ ("sixteen", 16),
+ ("seventeen", 17),
+ ("eighteen", 18),
+ ("nineteen", 19),
+ ]
+units = Or(makeLit(s,v) for s,v in unitDefinitions)
+
+tensDefinitions = [
+ ("ten", 10),
+ ("twenty", 20),
+ ("thirty", 30),
+ ("forty", 40),
+ ("fourty", 40), # for the spelling-challenged...
+ ("fifty", 50),
+ ("sixty", 60),
+ ("seventy", 70),
+ ("eighty", 80),
+ ("ninety", 90),
+ ]
+tens = Or(makeLit(s,v) for s,v in tensDefinitions)
+
+hundreds = makeLit("hundred", 100)
+
+majorDefinitions = [
+ ("thousand", int(1e3)),
+ ("million", int(1e6)),
+ ("billion", int(1e9)),
+ ("trillion", int(1e12)),
+ ("quadrillion", int(1e15)),
+ ("quintillion", int(1e18)),
+ ]
+mag = Or(makeLit(s,v) for s,v in majorDefinitions)
+
+wordprod = lambda t: reduce(mul,t)
+wordsum = lambda t: sum(t)
+numPart = (((( units + Optional(hundreds) ).setParseAction(wordprod) +
+ Optional(tens)).setParseAction(wordsum)
+ ^ tens )
+ + Optional(units) ).setParseAction(wordsum)
+numWords = OneOrMore( (numPart + Optional(mag)).setParseAction(wordprod)
+ ).setParseAction(wordsum) + StringEnd()
+numWords.ignore(Literal("-"))
+numWords.ignore(CaselessLiteral("and"))
+
+def test(s,expected):
+ try:
+ fail_expected = (expected is None)
+ success, results_tup = numWords.runTests(s, failureTests=fail_expected)
+ assert success, "Failed test!"
+ if not fail_expected:
+ teststr, results = results_tup[0]
+ observed = results[0]
+ assert expected == observed, "incorrect parsed value, {} -> {}, should be {}".format(teststr, observed, expected)
+ except Exception as exc:
+ print("{}: {}".format(type(exc).__name__, exc))
+
+test("one hundred twenty hundred", None)
+test("one hundred and twennty", None)
+test("one hundred and twenty", 120)
+test("one hundred and three", 103)
+test("one hundred twenty-three", 123)
+test("one hundred and twenty three", 123)
+test("one hundred twenty three million", 123000000)
+test("one hundred and twenty three million", 123000000)
+test("one hundred twenty three million and three", 123000003)
+test("fifteen hundred and sixty five", 1565)
+test("seventy-seven thousand eight hundred and nineteen", 77819)
+test("seven hundred seventy-seven thousand seven hundred and seventy-seven", 777777)
+test("zero", 0)
+test("forty two", 42)
+test("fourty two", 42) \ No newline at end of file