summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2012-10-02 04:55:56 +0000
committerptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2012-10-02 04:55:56 +0000
commitb8d7d6e994ba837f197f36f23bbad10fe3e24cc8 (patch)
tree57ea8bcf2e66532a36c833a7bc57cff9d5d0e4dd
parent0edced5724b253771cc9631184096a98f0432f2a (diff)
downloadpyparsing-b8d7d6e994ba837f197f36f23bbad10fe3e24cc8.tar.gz
Add example files to SVN
git-svn-id: svn://svn.code.sf.net/p/pyparsing/code/trunk@238 9bf210a0-9d2d-494c-87cf-cfb32e7dff7b
-rw-r--r--src/examples/0README.html287
-rw-r--r--src/examples/AcManForm.dfm885
-rw-r--r--src/examples/LAparser.py417
-rw-r--r--src/examples/SimpleCalc.py118
-rw-r--r--src/examples/SingleForm.dfm751
-rw-r--r--src/examples/TAP.py217
-rw-r--r--src/examples/adventureEngine.py648
-rw-r--r--src/examples/antlr_grammar.py218
-rw-r--r--src/examples/antlr_grammar_tests.py85
-rw-r--r--src/examples/apicheck.py55
-rw-r--r--src/examples/btpyparse.py128
-rw-r--r--src/examples/builtin_parse_action_demo.py29
-rw-r--r--src/examples/cLibHeader.py25
-rw-r--r--src/examples/chemicalFormulas.py67
-rw-r--r--src/examples/commasep.py23
-rw-r--r--src/examples/configParse.py68
-rw-r--r--src/examples/cpp_enum_parser.py52
-rw-r--r--src/examples/deltaTime.py205
-rw-r--r--src/examples/dfmparse.py176
-rw-r--r--src/examples/dhcpd_leases_parser.py87
-rw-r--r--src/examples/dictExample.py41
-rw-r--r--src/examples/dictExample2.py60
-rw-r--r--src/examples/ebnf.py149
-rw-r--r--src/examples/ebnftest.py66
-rw-r--r--src/examples/eval_arith.py227
-rw-r--r--src/examples/excelExpr.py72
-rw-r--r--src/examples/fourFn.py189
-rw-r--r--src/examples/fourFn.pycbin0 -> 5355 bytes
-rw-r--r--src/examples/gen_ctypes.py167
-rw-r--r--src/examples/getNTPservers.py30
-rw-r--r--src/examples/getNTPserversNew.py30
-rw-r--r--src/examples/greeting.py17
-rw-r--r--src/examples/greetingInGreek.py18
-rw-r--r--src/examples/greetingInKorean.py20
-rw-r--r--src/examples/groupUsingListAllMatches.py16
-rw-r--r--src/examples/holaMundo.py28
-rw-r--r--src/examples/htmlStripper.py39
-rw-r--r--src/examples/httpServerLogParser.py71
-rw-r--r--src/examples/idlParse.py222
-rw-r--r--src/examples/indentedGrammarExample.py78
-rw-r--r--src/examples/invRegex.py250
-rw-r--r--src/examples/javascript_grammar.g894
-rw-r--r--src/examples/jsonParser.py111
-rw-r--r--src/examples/linenoExample.py49
-rw-r--r--src/examples/list1.py50
-rw-r--r--src/examples/listAllMatches.py52
-rw-r--r--src/examples/lucene_grammar.py330
-rw-r--r--src/examples/macroExpander.py59
-rw-r--r--src/examples/makeHTMLTagExample.py21
-rw-r--r--src/examples/matchPreviousDemo.py33
-rw-r--r--src/examples/mozilla.ics50
-rw-r--r--src/examples/mozillaCalendarParser.py83
-rw-r--r--src/examples/nested.py30
-rw-r--r--src/examples/oc.py195
-rw-r--r--src/examples/parseListString.py100
-rw-r--r--src/examples/parsePythonValue.py67
-rw-r--r--src/examples/parseResultsSumExample.py26
-rw-r--r--src/examples/partial_gene_match.py88
-rw-r--r--src/examples/pgn.py94
-rw-r--r--src/examples/pgn.pycbin0 -> 2803 bytes
-rw-r--r--src/examples/protobuf_parser.py103
-rw-r--r--src/examples/pymicko.py1387
-rw-r--r--src/examples/pythonGrammarParser.py220
-rw-r--r--src/examples/readJson.py1917
-rw-r--r--src/examples/removeLineBreaks.py45
-rw-r--r--src/examples/romanNumerals.py77
-rw-r--r--src/examples/scanExamples.py75
-rw-r--r--src/examples/scanYahoo.py14
-rw-r--r--src/examples/searchParserAppDemo.py34
-rw-r--r--src/examples/searchparser.py293
-rw-r--r--src/examples/select_parser.py135
-rw-r--r--src/examples/sexpParser.py167
-rw-r--r--src/examples/simpleArith.py67
-rw-r--r--src/examples/simpleBool.py88
-rw-r--r--src/examples/simpleSQL.py142
-rw-r--r--src/examples/simpleWiki.py32
-rw-r--r--src/examples/snmp_api.h795
-rw-r--r--src/examples/sparser.py365
-rw-r--r--src/examples/sql2dot.py96
-rw-r--r--src/examples/stackish.py81
-rw-r--r--src/examples/stateMachine2.py1
-rw-r--r--src/examples/tagCapture.py35
-rw-r--r--src/examples/test_bibparse.py195
-rw-r--r--src/examples/urlExtractor.py42
-rw-r--r--src/examples/urlExtractorNew.py35
-rw-r--r--src/examples/verilogParse.py720
-rw-r--r--src/examples/withAttribute.py24
-rw-r--r--src/examples/wordsToNum.py108
88 files changed, 15956 insertions, 0 deletions
diff --git a/src/examples/0README.html b/src/examples/0README.html
new file mode 100644
index 0000000..b8b654f
--- /dev/null
+++ b/src/examples/0README.html
@@ -0,0 +1,287 @@
+<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>
+
+
+</ul>
+
+</body></html>
diff --git a/src/examples/AcManForm.dfm b/src/examples/AcManForm.dfm
new file mode 100644
index 0000000..db80f6a
--- /dev/null
+++ b/src/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/src/examples/LAparser.py b/src/examples/LAparser.py
new file mode 100644
index 0000000..6e3ddbd
--- /dev/null
+++ b/src/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,err:
+ print >>sys.stderr, 'Parse Failure'
+ print >>sys.stderr, err.line
+ print >>sys.stderr, " "*(err.column-1) + "^"
+ print >>sys.stderr, err
+ 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 >>sys.stderr,"Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."%input_string
+ raise
+ except UnaryUnsupportedError:
+ print >>sys.stderr,"Unary negation is not supported for vectors and matrices: '%s'"%input_string
+ raise
+
+ # Create final assignment and print it.
+ if debug_flag: print "var=",targetvar
+ if targetvar != None:
+ try:
+ result = _assignfunc(targetvar,result)
+ except TypeError:
+ print >>sys.stderr,"Left side tag does not match right side of '%s'"%input_string
+ raise
+ except UnaryUnsupportedError:
+ print >>sys.stderr,"Unary negation is not supported for vectors and matrices: '%s'"%input_string
+ raise
+
+ return result
+ else:
+ print >>sys.stderr, "Empty left side in '%s'"%input_string
+ 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 = raw_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 = raw_input("> ")
+
+ # if user types 'quit' then say goodbye
+ print "Good bye!"
+
+
diff --git a/src/examples/SimpleCalc.py b/src/examples/SimpleCalc.py
new file mode 100644
index 0000000..577c8e3
--- /dev/null
+++ b/src/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!
+#
+#
+
+from __future__ import division
+
+# 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 = raw_input("> ")
+
+ while input_string != 'quit':
+ if input_string.lower() == 'debug':
+ debug_flag=True
+ input_string = raw_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,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,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 = raw_input("> ")
+
+ # if user type 'quit' then say goodbye
+ print "Good bye!"
+
+
diff --git a/src/examples/SingleForm.dfm b/src/examples/SingleForm.dfm
new file mode 100644
index 0000000..7a52734
--- /dev/null
+++ b/src/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/src/examples/TAP.py b/src/examples/TAP.py
new file mode 100644
index 0000000..dd551ab
--- /dev/null
+++ b/src/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 = range(1, int(results.plan.ubound)+1)
+ else:
+ expected = 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/src/examples/adventureEngine.py b/src/examples/adventureEngine.py
new file mode 100644
index 0000000..5817105
--- /dev/null
+++ b/src/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, pe:
+ print pe.msg
+ except ParseException, 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,basestring):
+ r = rooms[r]
+ r.addItem( Item.items[i] )
+
+def playGame(p,startRoom):
+ # create parser
+ parser = Parser()
+ p.moveTo( startRoom )
+ while not p.gameOver:
+ cmdstr = raw_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/src/examples/antlr_grammar.py b/src/examples/antlr_grammar.py
new file mode 100644
index 0000000..b355ab5
--- /dev/null
+++ b/src/examples/antlr_grammar.py
@@ -0,0 +1,218 @@
+'''
+antlr_grammar.py
+
+Created on 4 sept. 2010
+
+@author: luca
+
+(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 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 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/src/examples/antlr_grammar_tests.py b/src/examples/antlr_grammar_tests.py
new file mode 100644
index 0000000..31aab29
--- /dev/null
+++ b/src/examples/antlr_grammar_tests.py
@@ -0,0 +1,85 @@
+'''
+Created on 4 sept. 2010
+
+@author: luca
+'''
+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/src/examples/apicheck.py b/src/examples/apicheck.py
new file mode 100644
index 0000000..b5b9358
--- /dev/null
+++ b/src/examples/apicheck.py
@@ -0,0 +1,55 @@
+# apicheck.py
+# A simple source code scanner for finding patterns of the form
+# [ procname1 $arg1 $arg2 ]
+# and verifying the number of arguments
+
+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 = api_scanner.next()
+ print "found %s on line %d" % (t.procname, lineno(s,test))
+ except ParseSyntaxException, 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
+ \ No newline at end of file
diff --git a/src/examples/btpyparse.py b/src/examples/btpyparse.py
new file mode 100644
index 0000000..9700ff2
--- /dev/null
+++ b/src/examples/btpyparse.py
@@ -0,0 +1,128 @@
+""" 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.
+
+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("[\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/src/examples/builtin_parse_action_demo.py b/src/examples/builtin_parse_action_demo.py
new file mode 100644
index 0000000..ef42640
--- /dev/null
+++ b/src/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/src/examples/cLibHeader.py b/src/examples/cLibHeader.py
new file mode 100644
index 0000000..115aa08
--- /dev/null
+++ b/src/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/src/examples/chemicalFormulas.py b/src/examples/chemicalFormulas.py
new file mode 100644
index 0000000..63eff13
--- /dev/null
+++ b/src/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 ),
+ except ParseException, 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/src/examples/commasep.py b/src/examples/commasep.py
new file mode 100644
index 0000000..d753eca
--- /dev/null
+++ b/src/examples/commasep.py
@@ -0,0 +1,23 @@
+# 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
+
+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/src/examples/configParse.py b/src/examples/configParse.py
new file mode 100644
index 0000000..a01bef8
--- /dev/null
+++ b/src/examples/configParse.py
@@ -0,0 +1,68 @@
+#
+# 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
+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 + restOfLine
+
+ # 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 = file(strng)
+ iniData = "".join( iniFile.readlines() )
+ bnf = inifile_BNF()
+ tokens = bnf.parseString( iniData )
+ pp.pprint( tokens.asList() )
+
+ except ParseException, err:
+ print err.line
+ print " "*(err.column-1) + "^"
+ print err
+
+ iniFile.close()
+ print
+ return tokens
+
+
+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/src/examples/cpp_enum_parser.py b/src/examples/cpp_enum_parser.py
new file mode 100644
index 0000000..70d60c0
--- /dev/null
+++ b/src/examples/cpp_enum_parser.py
@@ -0,0 +1,52 @@
+#
+# cpp_enum_parser.py
+#
+# Posted by Mark Tolenen 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/src/examples/deltaTime.py b/src/examples/deltaTime.py
new file mode 100644
index 0000000..8bfcf64
--- /dev/null
+++ b/src/examples/deltaTime.py
@@ -0,0 +1,205 @@
+# 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,basestring):
+ 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")
+
+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:])] ))
+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(int4("miltime") |
+ integer("HH") +
+ Optional(COLON + integer("MM")) +
+ Optional(COLON + integer("SS")) + (am | pm)("ampm")
+ )
+absTimeSpec = ((noon | midnight | now | timespec("timeparts"))("timeOfDay") +
+ 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))
+
+# 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""".splitlines()
+
+for t in tests:
+ print t, "(relative to %s)" % datetime.now()
+ res = nlTimeExpression.parseString(t)
+ if "calculatedTime" in res:
+ print res.calculatedTime
+ else:
+ print "???"
+ print
diff --git a/src/examples/dfmparse.py b/src/examples/dfmparse.py
new file mode 100644
index 0000000..1523497
--- /dev/null
+++ b/src/examples/dfmparse.py
@@ -0,0 +1,176 @@
+"""
+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: [ long(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,
+ return tok
+
+def get_filename_list(tf):
+ import sys, glob
+ if tf == None:
+ tf = sys.argv[1:]
+ elif type(tf) == str:
+ tf = [tf]
+ testfiles = []
+ for arg in tf:
+ for i in glob.glob(arg):
+ testfiles.append(i)
+ 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)
+
+ 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[retval.keys()[0]]
+
+ # else, return a dictionary of parseResults
+ return retval
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/src/examples/dhcpd_leases_parser.py b/src/examples/dhcpd_leases_parser.py
new file mode 100644
index 0000000..6a5a87a
--- /dev/null
+++ b/src/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/src/examples/dictExample.py b/src/examples/dictExample.py
new file mode 100644
index 0000000..7fbadf1
--- /dev/null
+++ b/src/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=", data.keys()
+print "data['min']=", data['min']
+print "data.max", data.max
diff --git a/src/examples/dictExample2.py b/src/examples/dictExample2.py
new file mode 100644
index 0000000..9e990ad
--- /dev/null
+++ b/src/examples/dictExample2.py
@@ -0,0 +1,60 @@
+#
+# 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
+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 = Word(nums).setParseAction( lambda t : int(t[0]) )
+vert = Literal("|").suppress()
+
+rowDelim = ("+" + ZeroOrMore( underline + "+" ) ).suppress()
+columnHeader = Group(vert + vert + delimitedList(Word(alphas + nums), "|") + vert)
+
+heading = rowDelim + columnHeader.setResultsName("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
+print data.asXML("DATA")
+pprint.pprint(data.asList())
+print "data keys=", 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,
+for i in range(1,len(data)):
+ print "|%5s" % data[i][0],
+print
+print ("-" * 6) + ("+------" * (len(data)-1))
+for i in range(len(data.columns)):
+ print "%5s" % data.columns[i],
+ for j in range(len(data) - 1):
+ print '|%5s' % data[j + 1][i + 1],
+ print
diff --git a/src/examples/ebnf.py b/src/examples/ebnf.py
new file mode 100644
index 0000000..8dfcaea
--- /dev/null
+++ b/src/examples/ebnf.py
@@ -0,0 +1,149 @@
+# 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
+
+
+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/src/examples/ebnftest.py b/src/examples/ebnftest.py
new file mode 100644
index 0000000..f0ce654
--- /dev/null
+++ b/src/examples/ebnftest.py
@@ -0,0 +1,66 @@
+print 'Importing pyparsing...'
+from pyparsing import *
+
+print 'Constructing EBNF parser with pyparsing...'
+import ebnf
+import sets
+
+
+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 = sets.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(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/src/examples/eval_arith.py b/src/examples/eval_arith.py
new file mode 100644
index 0000000..4d7683c
--- /dev/null
+++ b/src/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, operatorPrecedence, 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 (it.next(), it.next())
+ 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 = operatorPrecedence(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 = operatorPrecedence(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/src/examples/excelExpr.py b/src/examples/excelExpr.py
new file mode 100644
index 0000000..c759345
--- /dev/null
+++ b/src/examples/excelExpr.py
@@ -0,0 +1,72 @@
+# 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,
+ operatorPrecedence, opAssoc, dblQuotedString, delimitedList,
+ Combine, Literal, QuotedString)
+
+EQ,EXCL,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 + expr("if_true") +
+ COMMA + expr("if_false") + RPAR)
+
+statFunc = lambda name : CaselessKeyword(name) + 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 = Regex(r"\-?\d+(\.\d+)?")
+operand = numericLiteral | funcCall | cellRange | cellRef
+arithExpr = operatorPrecedence(operand,
+ [
+ (multOp, 2, opAssoc.LEFT),
+ (addOp, 2, opAssoc.LEFT),
+ ])
+
+textOperand = dblQuotedString | cellRef
+textExpr = operatorPrecedence(textOperand,
+ [
+ ('&', 2, opAssoc.LEFT),
+ ])
+expr << (arithExpr | textExpr)
+
+
+test1 = "=3*A7+5"
+test2 = "=3*Sheet1!$A$7+5"
+test2a ="=3*'Sheet 1'!$A$7+5"
+test2b ="=3*'O''Reilly''s sheet'!$A$7+5"
+test3 = "=if(Sum(A1:A25)>42,Min(B1:B25), " \
+ "if(Sum(C1:C25)>3.14, (Min(C1:C25)+3)*18,Max(B1:B25)))"
+test3a = "=sum(a1:a25,10,min(b1,c2,d3))"
+
+import pprint
+tests = [locals()[t] for t in locals().keys() if t.startswith("test")]
+for test in tests:
+ print test
+ pprint.pprint( (EQ + expr).parseString(test,parseAll=True).asList() )
+ print
diff --git a/src/examples/fourFn.py b/src/examples/fourFn.py
new file mode 100644
index 0000000..e49227c
--- /dev/null
+++ b/src/examples/fourFn.py
@@ -0,0 +1,189 @@
+# 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,Regex,ParseException
+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( "." )
+ e = CaselessLiteral( "E" )
+ #~ 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, alphas+nums+"_$")
+
+ plus = Literal( "+" )
+ minus = Literal( "-" )
+ mult = Literal( "*" )
+ div = Literal( "/" )
+ lpar = Literal( "(" ).suppress()
+ rpar = Literal( ")" ).suppress()
+ addop = plus | minus
+ multop = mult | div
+ expop = Literal( "^" )
+ pi = CaselessLiteral( "PI" )
+
+ 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,
+ "abs" : abs,
+ "trunc" : lambda a: int(a),
+ "round" : round,
+ "sgn" : lambda a: abs(a)>epsilon and cmp(a,0) or 0}
+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( "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)", 1 )
+ 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/src/examples/fourFn.pyc b/src/examples/fourFn.pyc
new file mode 100644
index 0000000..c20e9e0
--- /dev/null
+++ b/src/examples/fourFn.pyc
Binary files differ
diff --git a/src/examples/gen_ctypes.py b/src/examples/gen_ctypes.py
new file mode 100644
index 0000000..0fb62e4
--- /dev/null
+++ b/src/examples/gen_ctypes.py
@@ -0,0 +1,167 @@
+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/src/examples/getNTPservers.py b/src/examples/getNTPservers.py
new file mode 100644
index 0000000..586bc5f
--- /dev/null
+++ b/src/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
+
+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.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/src/examples/getNTPserversNew.py b/src/examples/getNTPserversNew.py
new file mode 100644
index 0000000..47d5439
--- /dev/null
+++ b/src/examples/getNTPserversNew.py
@@ -0,0 +1,30 @@
+# 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)
+import urllib
+
+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 = urllib.urlopen( nistTimeServerURL )
+serverListHTML = serverListPage.read()
+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/src/examples/greeting.py b/src/examples/greeting.py
new file mode 100644
index 0000000..46108b8
--- /dev/null
+++ b/src/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/src/examples/greetingInGreek.py b/src/examples/greetingInGreek.py
new file mode 100644
index 0000000..7869b68
--- /dev/null
+++ b/src/examples/greetingInGreek.py
@@ -0,0 +1,18 @@
+# vim:fileencoding=utf-8
+#
+# greetingInGreek.py
+#
+# Demonstration of the parsing module, on the prototypical "Hello, World!" example
+#
+from pyparsing import Word
+
+# define grammar
+alphas = u''.join(unichr(x) for x in xrange(0x386, 0x3ce))
+greet = Word(alphas) + u',' + Word(alphas) + u'!'
+
+# input string
+hello = "ΚαλημέÏα, κόσμε!".decode('utf-8')
+
+# parse input string
+print greet.parseString( hello )
+
diff --git a/src/examples/greetingInKorean.py b/src/examples/greetingInKorean.py
new file mode 100644
index 0000000..800a7fc
--- /dev/null
+++ b/src/examples/greetingInKorean.py
@@ -0,0 +1,20 @@
+# vim:fileencoding=utf-8
+#
+# greetingInKorean.py
+#
+# Demonstration of the parsing module, on the prototypical "Hello, World!" example
+#
+from pyparsing import Word, srange
+
+koreanChars = srange(r"[\0xac00-\0xd7a3]")
+koreanWord = Word(koreanChars,min=2)
+
+# define grammar
+greet = koreanWord + "," + koreanWord + "!"
+
+# input string
+hello = u'\uc548\ub155, \uc5ec\ub7ec\ubd84!' #"Hello, World!" in Korean
+
+# parse input string
+print greet.parseString( hello )
+
diff --git a/src/examples/groupUsingListAllMatches.py b/src/examples/groupUsingListAllMatches.py
new file mode 100644
index 0000000..ca9e5ab
--- /dev/null
+++ b/src/examples/groupUsingListAllMatches.py
@@ -0,0 +1,16 @@
+#
+# 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.
+#
+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*"))
+
+results = grammar.parseString("A1 B1 A2 C1 B2 A3")
+print results.dump()
diff --git a/src/examples/holaMundo.py b/src/examples/holaMundo.py
new file mode 100644
index 0000000..0e10069
--- /dev/null
+++ b/src/examples/holaMundo.py
@@ -0,0 +1,28 @@
+# 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í la 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")
+
+# Excelente!!, bueno, los dejo, me voy a seguir tirando código…
diff --git a/src/examples/htmlStripper.py b/src/examples/htmlStripper.py
new file mode 100644
index 0000000..502acc5
--- /dev/null
+++ b/src/examples/htmlStripper.py
@@ -0,0 +1,39 @@
+#
+# htmlStripper.py
+#
+# Sample code for stripping HTML markup tags and scripts from
+# HTML source files.
+#
+# Copyright (c) 2006, Paul McGuire
+#
+from pyparsing import *
+import urllib
+
+removeText = replaceWith("")
+scriptOpen,scriptClose = makeHTMLTags("script")
+scriptBody = scriptOpen + SkipTo(scriptClose) + scriptClose
+scriptBody.setParseAction(removeText)
+
+anyTag,anyClose = makeHTMLTags(Word(alphas,alphanums+":_"))
+anyTag.setParseAction(removeText)
+anyClose.setParseAction(removeText)
+htmlComment.setParseAction(removeText)
+
+commonHTMLEntity.setParseAction(replaceHTMLEntity)
+
+# get some HTML
+targetURL = "http://wiki.python.org/moin/PythonDecoratorLibrary"
+targetPage = urllib.urlopen( targetURL )
+targetHTML = targetPage.read()
+targetPage.close()
+
+# first pass, strip out tags and translate entities
+firstPass = (htmlComment | scriptBody | commonHTMLEntity |
+ anyTag | anyClose ).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/src/examples/httpServerLogParser.py b/src/examples/httpServerLogParser.py
new file mode 100644
index 0000000..9f5584d
--- /dev/null
+++ b/src/examples/httpServerLogParser.py
@@ -0,0 +1,71 @@
+# httpServerLogParser.py
+#
+"""
+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/src/examples/idlParse.py b/src/examples/idlParse.py
new file mode 100644
index 0000000..c1d5e4f
--- /dev/null
+++ b/src/examples/idlParse.py
@@ -0,0 +1,222 @@
+#
+# 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, Upcase, 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 = Literal(":")
+ lbrace = Literal("{")
+ rbrace = Literal("}")
+ lbrack = Literal("[")
+ rbrack = Literal("]")
+ lparen = Literal("(")
+ rparen = Literal(")")
+ equals = Literal("=")
+ comma = Literal(",")
+ dot = Literal(".")
+ slash = Literal("/")
+ bslash = Literal("\\")
+ star = Literal("*")
+ semi = Literal(";")
+ langle = Literal("<")
+ rangle = Literal(">")
+
+ # keywords
+ any_ = Keyword("any")
+ attribute_ = Keyword("attribute")
+ boolean_ = Keyword("boolean")
+ case_ = Keyword("case")
+ char_ = Keyword("char")
+ const_ = Keyword("const")
+ context_ = Keyword("context")
+ default_ = Keyword("default")
+ double_ = Keyword("double")
+ enum_ = Keyword("enum")
+ exception_ = Keyword("exception")
+ false_ = Keyword("FALSE")
+ fixed_ = Keyword("fixed")
+ float_ = Keyword("float")
+ inout_ = Keyword("inout")
+ interface_ = Keyword("interface")
+ in_ = Keyword("in")
+ long_ = Keyword("long")
+ module_ = Keyword("module")
+ object_ = Keyword("Object")
+ octet_ = Keyword("octet")
+ oneway_ = Keyword("oneway")
+ out_ = Keyword("out")
+ raises_ = Keyword("raises")
+ readonly_ = Keyword("readonly")
+ sequence_ = Keyword("sequence")
+ short_ = Keyword("short")
+ string_ = Keyword("string")
+ struct_ = Keyword("struct")
+ switch_ = Keyword("switch")
+ true_ = Keyword("TRUE")
+ typedef_ = Keyword("typedef")
+ unsigned_ = Keyword("unsigned")
+ union_ = Keyword("union")
+ void_ = Keyword("void")
+ wchar_ = Keyword("wchar")
+ wstring_ = Keyword("wstring")
+
+ identifier = Word( alphas, alphanums + "_" ).setName("identifier")
+
+ #~ real = Combine( Word(nums+"+-", nums) + dot + Optional( Word(nums) )
+ #~ + Optional( CaselessLiteral("E") + Word(nums+"+-",nums) ) )
+ real = Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?").setName("real")
+ #~ integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) |
+ #~ Word( nums+"+-", nums ) ).setName("int")
+ integer = Regex(r"0x[0-9a-fA-F]+|[+-]?\d+").setName("int")
+
+ udTypeName = delimitedList( identifier, "::", combine=True ).setName("udType")
+ # have to use longest match for type, in case a user-defined type name starts with a keyword type, like "stringSeq" or "longArray"
+ 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, 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/src/examples/indentedGrammarExample.py b/src/examples/indentedGrammarExample.py
new file mode 100644
index 0000000..e7b8cb7
--- /dev/null
+++ b/src/examples/indentedGrammarExample.py
@@ -0,0 +1,78 @@
+# indentedGrammarExample.py
+#
+# Copyright (c) 2006, Paul McGuire
+#
+# A sample of a pyparsing grammar using indentation for
+# grouping (like Python does).
+#
+
+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]
+
+def checkPeerIndent(s,l,t):
+ curCol = col(l,s)
+ if curCol != indentStack[-1]:
+ if (not indentStack) or curCol > indentStack[-1]:
+ raise ParseFatalException(s,l,"illegal nesting")
+ raise ParseException(s,l,"not a peer entry")
+
+def checkSubIndent(s,l,t):
+ curCol = col(l,s)
+ if curCol > indentStack[-1]:
+ indentStack.append( curCol )
+ else:
+ raise ParseException(s,l,"not a subentry")
+
+def checkUnindent(s,l,t):
+ if l >= len(s): return
+ curCol = col(l,s)
+ if not(curCol < indentStack[-1] and curCol <= indentStack[-2]):
+ raise ParseException(s,l,"not an unindent")
+
+def doUnindent():
+ indentStack.pop()
+
+INDENT = lineEnd.suppress() + empty + empty.copy().setParseAction(checkSubIndent)
+UNDENT = FollowedBy(empty).setParseAction(checkUnindent)
+UNDENT.setParseAction(doUnindent)
+
+stmt = Forward()
+suite = Group( OneOrMore( empty + stmt.setParseAction( checkPeerIndent ) ) )
+
+identifier = Word(alphas, alphanums)
+funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")
+funcDef = Group( funcDecl + INDENT + suite + UNDENT )
+
+rvalue = Forward()
+funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")")
+rvalue << (funcCall | identifier | Word(nums))
+assignment = Group(identifier + "=" + rvalue)
+stmt << ( funcDef | assignment | identifier )
+
+print data
+parseTree = suite.parseString(data)
+
+import pprint
+pprint.pprint( parseTree.asList() )
diff --git a/src/examples/invRegex.py b/src/examples/invRegex.py
new file mode 100644
index 0000000..6493974
--- /dev/null
+++ b/src/examples/invRegex.py
@@ -0,0 +1,250 @@
+#
+# 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, operatorPrecedence, 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 = 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)) )
+ reDot = Literal(".")
+ repetition = (
+ ( lbrace + Word(nums).setResultsName("count") + rbrace ) |
+ ( lbrace + Word(nums).setResultsName("minCount")+","+ Word(nums).setResultsName("maxCount") + rbrace ) |
+ oneOf(list("*+?"))
+ )
+
+ reRange.setParseAction(handleRange)
+ reLiteral.setParseAction(handleLiteral)
+ reMacro.setParseAction(handleMacro)
+ reDot.setParseAction(handleDot)
+
+ reTerm = ( reLiteral | reRange | reMacro | reDot )
+ reExpr = operatorPrecedence( 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."""
+ i = 0
+ for s in gen:
+ i += 1
+ return i
+
+def invert(regex):
+ """Call this routine as a generator to return all the strings that
+ match the input regular expression.
+ for s in invert("[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\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)
+ """.split('\n')
+
+ for t in tests:
+ t = t.strip()
+ if not t: continue
+ print '-'*50
+ print t
+ try:
+ print count(invert(t))
+ for s in invert(t):
+ print s
+ except ParseFatalException,pfe:
+ print pfe.msg
+ print
+ continue
+ print
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/src/examples/javascript_grammar.g b/src/examples/javascript_grammar.g
new file mode 100644
index 0000000..c30eac2
--- /dev/null
+++ b/src/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/src/examples/jsonParser.py b/src/examples/jsonParser.py
new file mode 100644
index 0000000..e1d71ac
--- /dev/null
+++ b/src/examples/jsonParser.py
@@ -0,0 +1,111 @@
+# 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
+#
+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 *
+
+TRUE = Keyword("true").setParseAction( replaceWith(True) )
+FALSE = Keyword("false").setParseAction( replaceWith(False) )
+NULL = Keyword("null").setParseAction( replaceWith(None) )
+
+jsonString = dblQuotedString.setParseAction( removeQuotes )
+jsonNumber = Combine( Optional('-') + ( '0' | Word('123456789',nums) ) +
+ Optional( '.' + Word(nums) ) +
+ Optional( Word('eE',exact=1) + Word(nums+'+-',nums) ) )
+
+jsonObject = Forward()
+jsonValue = Forward()
+jsonElements = delimitedList( jsonValue )
+jsonArray = Group(Suppress('[') + Optional(jsonElements) + Suppress(']') )
+jsonValue << ( jsonString | jsonNumber | Group(jsonObject) | jsonArray | TRUE | FALSE | NULL )
+memberDef = Group( jsonString + Suppress(':') + jsonValue )
+jsonMembers = delimitedList( memberDef )
+jsonObject << Dict( Suppress('{') + Optional(jsonMembers) + Suppress('}') )
+
+jsonComment = cppStyleComment
+jsonObject.ignore( jsonComment )
+
+def convertNumbers(s,l,toks):
+ n = toks[0]
+ try:
+ return int(n)
+ except ValueError, ve:
+ return float(n)
+
+jsonNumber.setParseAction( convertNumbers )
+
+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 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/src/examples/linenoExample.py b/src/examples/linenoExample.py
new file mode 100644
index 0000000..751822c
--- /dev/null
+++ b/src/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/src/examples/list1.py b/src/examples/list1.py
new file mode 100644
index 0000000..db3f34f
--- /dev/null
+++ b/src/examples/list1.py
@@ -0,0 +1,50 @@
+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 = 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
+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 = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).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/src/examples/listAllMatches.py b/src/examples/listAllMatches.py
new file mode 100644
index 0000000..fa28c8b
--- /dev/null
+++ b/src/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).setResultsName("vowels")
+cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True).setResultsName("cons")
+other = oneOf(list(nonAlphas)).setResultsName("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).setResultsName("vowels",listAllMatches=True)
+cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True).setResultsName("cons",listAllMatches=True)
+other = oneOf(list(nonAlphas)).setResultsName("others",listAllMatches=True)
+
+letters = OneOrMore(cons | vowels | other) + StringEnd()
+
+results = letters.parseString(test)
+print results
+print sorted(list(set(results)))
+print
+print results.vowels
+print sorted(list(set(results.vowels)))
+print
+print results.cons
+print sorted(list(set(results.cons)))
+print
+print results.others
+print sorted(list(set(results.others)))
+
diff --git a/src/examples/lucene_grammar.py b/src/examples/lucene_grammar.py
new file mode 100644
index 0000000..27c7aeb
--- /dev/null
+++ b/src/examples/lucene_grammar.py
@@ -0,0 +1,330 @@
+#
+# 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, operatorPrecedence, opAssoc, ParseException, ParserElement)
+ParserElement.enablePackrat()
+
+COLON,LBRACK,RBRACK,LBRACE,RBRACE,TILDE,CARAT = map(Literal,":[]{}~^")
+LPAR,RPAR = map(Suppress,"()")
+and_ = CaselessKeyword("AND")
+or_ = CaselessKeyword("OR")
+not_ = CaselessKeyword("NOT")
+to_ = CaselessKeyword("TO")
+keyword = and_ | or_ | not_
+
+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 = Regex(r'\d+(\.\d+)?').setParseAction(lambda t:float(t[0]))
+fuzzy_modifier = TILDE + Optional(number, default=0.5)("fuzzy")
+
+term = Forward()
+field_name = valid_word.copy().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 << operatorPrecedence(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
+ """.splitlines()
+
+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* ]
+ """.splitlines()
+
+allpass = True
+for t in filter(None,map(str.strip,tests)):
+ print t
+ try:
+ #~ expression.parseString(t,parseAll=True)
+ print expression.parseString(t,parseAll=True)
+ except ParseException, pe:
+ print t
+ print pe
+ allpass = False
+ print
+
+print ("OK", "FAIL")[not allpass]
diff --git a/src/examples/macroExpander.py b/src/examples/macroExpander.py
new file mode 100644
index 0000000..2bd599f
--- /dev/null
+++ b/src/examples/macroExpander.py
@@ -0,0 +1,59 @@
+# 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)
+macroDef = "#def" + Word(alphas+"_",alphanums+"_").setResultsName("macro") + \
+ empty + restOfLine.setResultsName("value")
+
+# define a placeholder for defined macros - initially nothing
+macroExpr = Forward()
+
+# 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/src/examples/makeHTMLTagExample.py b/src/examples/makeHTMLTagExample.py
new file mode 100644
index 0000000..e3baf40
--- /dev/null
+++ b/src/examples/makeHTMLTagExample.py
@@ -0,0 +1,21 @@
+import urllib
+
+from pyparsing import makeHTMLTags, SkipTo
+
+# read HTML from a web page
+serverListPage = urllib.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/src/examples/matchPreviousDemo.py b/src/examples/matchPreviousDemo.py
new file mode 100644
index 0000000..91d7eb1
--- /dev/null
+++ b/src/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/src/examples/mozilla.ics b/src/examples/mozilla.ics
new file mode 100644
index 0000000..e6dd3dc
--- /dev/null
+++ b/src/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/src/examples/mozillaCalendarParser.py b/src/examples/mozillaCalendarParser.py
new file mode 100644
index 0000000..15929a6
--- /dev/null
+++ b/src/examples/mozillaCalendarParser.py
@@ -0,0 +1,83 @@
+# -*- coding: UTF-8 -*-
+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()
+str = printables + "äöåÖÄÅ"
+valstr = str + " "
+
+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['summary'], "from", event["begin"], "to", event["end"]
+
+event.setParseAction(gotEvent)
+
+
+# MAIN PROGRAM
+
+if __name__=="__main__":
+
+ calendars.parseFile("mozilla.ics")
diff --git a/src/examples/nested.py b/src/examples/nested.py
new file mode 100644
index 0000000..bd529f5
--- /dev/null
+++ b/src/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/src/examples/oc.py b/src/examples/oc.py
new file mode 100644
index 0000000..0cd6990
--- /dev/null
+++ b/src/examples/oc.py
@@ -0,0 +1,195 @@
+# 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 *
+
+LPAR,RPAR,LBRACK,RBRACK,LBRACE,RBRACE,SEMI,COMMA = map(Suppress, "()[]{};,")
+INT = Keyword("int")
+CHAR = Keyword("char")
+WHILE = Keyword("while")
+DO = Keyword("do")
+IF = Keyword("if")
+ELSE = Keyword("else")
+RETURN = Keyword("return")
+
+NAME = Word(alphas+"_", alphanums+"_")
+integer = Regex(r"[+-]?\d+")
+char = Regex(r"'.'")
+string_ = dblQuotedString
+
+INT = Keyword("int")
+CHAR = Keyword("char")
+TYPE = Group((INT | CHAR) + ZeroOrMore("*"))
+
+expr = Forward()
+operand = NAME | integer | char | string_
+expr << (operatorPrecedence(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;
+ while(i < 10)
+ facpr(i++);
+ return 0;
+}
+"""
+
+ast = program.parseString(test,parseAll=True)
+
+import pprint
+pprint.pprint(ast.asList()) \ No newline at end of file
diff --git a/src/examples/parseListString.py b/src/examples/parseListString.py
new file mode 100644
index 0000000..eb784c7
--- /dev/null
+++ b/src/examples/parseListString.py
@@ -0,0 +1,100 @@
+# 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 = 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, 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 = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).setName("real").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, just parsing tuples of numbers
+#~ from pyparsing import *
+
+#~ integer = (Word(nums)|Word('-+',nums)).setName("integer")
+#~ real = Combine(integer + "." + Optional(Word(nums))).setName("real")
+#~ tupleStr = Forward().setName("tuple")
+#~ tupleItem = real | integer | tupleStr
+#~ tupleStr << ( Suppress("(") + delimitedList(tupleItem) +
+ #~ Optional(Suppress(",")) + Suppress(")") )
+
+#~ # add parse actions to do conversion during parsing
+#~ integer.setParseAction( lambda toks: int(toks[0]) )
+#~ real.setParseAction( lambda toks: float(toks[0]) )
+#~ tupleStr.setParseAction( lambda toks: tuple(toks) )
+
+#~ s = '((1,2), (3,4), (-5,9.2),)'
+#~ print tupleStr.parseString(s)[0]
+
+
+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 = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
+ Optional(Word(nums))).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 + delimitedList(listItem) + Optional(Suppress(",")) + rbrack
+dictStr << rbrace + delimitedList( Group( listItem + colon + listItem ) ) + rbrace
+test = "['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ]"
+test = '[{0: [2], 1: []}, {0: [], 1: [], 2: []}, {0: [1, 2]}]'
+print listStr.parseString(test)
diff --git a/src/examples/parsePythonValue.py b/src/examples/parsePythonValue.py
new file mode 100644
index 0000000..d9671fa
--- /dev/null
+++ b/src/examples/parsePythonValue.py
@@ -0,0 +1,67 @@
+# parsePythonValue.py
+#
+# Copyright, 2006, by Paul McGuire
+#
+
+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())
+
+# 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)
+
+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 dd.items()
+ except TypeError,te:
+ pass
+ print
diff --git a/src/examples/parseResultsSumExample.py b/src/examples/parseResultsSumExample.py
new file mode 100644
index 0000000..6da5e84
--- /dev/null
+++ b/src/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/src/examples/partial_gene_match.py b/src/examples/partial_gene_match.py
new file mode 100644
index 0000000..57723c1
--- /dev/null
+++ b/src/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
+
+# read in a bunch of genomic data
+datafile = urllib.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/src/examples/pgn.py b/src/examples/pgn.py
new file mode 100644
index 0000000..8f6574d
--- /dev/null
+++ b/src/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 = Literal("O-O-O") | Literal("0-0-0") | Literal("o-o-o")
+castle_kingside = Literal("O-O") | Literal("0-0") | Literal("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, 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 = ", tokens
diff --git a/src/examples/pgn.pyc b/src/examples/pgn.pyc
new file mode 100644
index 0000000..ee2d88f
--- /dev/null
+++ b/src/examples/pgn.pyc
Binary files differ
diff --git a/src/examples/protobuf_parser.py b/src/examples/protobuf_parser.py
new file mode 100644
index 0000000..8940e14
--- /dev/null
+++ b/src/examples/protobuf_parser.py
@@ -0,0 +1,103 @@
+# 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)
+
+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_ - ident + LBRACE + ZeroOrMore( Group(ident + EQ + integer + SEMI) ) + 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;
+}"""
+
+from pprint import pprint
+#~ print parser.parseString(test2, parseAll=True).dump()
+pprint( parser.parseString(test2, parseAll=True).asList())
+
diff --git a/src/examples/pymicko.py b/src/examples/pymicko.py
new file mode 100644
index 0000000..1ae4efe
--- /dev/null
+++ b/src/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=SharedData.KINDS.keys(), stype=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 = 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, err:
+ print err
+ exit(3)
+ except ParseException, 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, err:
+ print err
+ exit(3)
+ except ParseException, 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/src/examples/pythonGrammarParser.py b/src/examples/pythonGrammarParser.py
new file mode 100644
index 0000000..eb9c560
--- /dev/null
+++ b/src/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 = """
+# 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,basestring) 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,basestring):
+ 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 bnfDefs.keys():
+ print k,"=",bnfDefs[k]
diff --git a/src/examples/readJson.py b/src/examples/readJson.py
new file mode 100644
index 0000000..8ec2f99
--- /dev/null
+++ b/src/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/src/examples/removeLineBreaks.py b/src/examples/removeLineBreaks.py
new file mode 100644
index 0000000..232034f
--- /dev/null
+++ b/src/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/src/examples/romanNumerals.py b/src/examples/romanNumerals.py
new file mode 100644
index 0000000..1561ac8
--- /dev/null
+++ b/src/examples/romanNumerals.py
@@ -0,0 +1,77 @@
+# 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):
+ if n >= limit:
+ 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 "==>",
+ print t,tests[s:e]
+ expected += 1
+print
+
+def test(rn):
+ print rn,romanNumeral.parseString(rn)
+test("XVI")
+test("XXXIX")
+test("XIV")
+test("XIX")
+test("MCMLXXX")
+test("MMVI")
+
+
+
+
+
+
diff --git a/src/examples/scanExamples.py b/src/examples/scanExamples.py
new file mode 100644
index 0000000..995ace9
--- /dev/null
+++ b/src/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/src/examples/scanYahoo.py b/src/examples/scanYahoo.py
new file mode 100644
index 0000000..0596fad
--- /dev/null
+++ b/src/examples/scanYahoo.py
@@ -0,0 +1,14 @@
+from pyparsing import makeHTMLTags,SkipTo,htmlComment
+import urllib
+
+serverListPage = urllib.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/src/examples/searchParserAppDemo.py b/src/examples/searchParserAppDemo.py
new file mode 100644
index 0000000..b6ea064
--- /dev/null
+++ b/src/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/src/examples/searchparser.py b/src/examples/searchparser.py
new file mode 100644
index 0000000..f9ee428
--- /dev/null
+++ b/src/examples/searchparser.py
@@ -0,0 +1,293 @@
+"""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
+from sets import Set
+
+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 (self.index.has_key(word)):
+ return self.index[word]
+ else:
+ return Set()
+
+ def GetWordWildcard(self, word):
+ result = Set()
+ for item in 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(self.docs.keys())
+ return all.difference(not_set)
+
+ def Test(self):
+ all_ok = True
+ for item in 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/src/examples/select_parser.py b/src/examples/select_parser.py
new file mode 100644
index 0000000..45c7d01
--- /dev/null
+++ b/src/examples/select_parser.py
@@ -0,0 +1,135 @@
+# 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 << operatorPrecedence(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),
+ ('||', 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""".splitlines()
+tests = """\
+ 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
+ """.splitlines()
+for t in tests:
+ t = t.strip()
+ if not t: continue
+ print t
+ try:
+ print select_stmt.parseString(t).dump()
+ except ParseException, pe:
+ print pe.msg
+ print
diff --git a/src/examples/sexpParser.py b/src/examples/sexpParser.py
new file mode 100644
index 0000000..c67b6f8
--- /dev/null
+++ b/src/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, pfe:
+ print "Error:", pfe.msg
+ print pfe.markInputline('^')
+ print
diff --git a/src/examples/simpleArith.py b/src/examples/simpleArith.py
new file mode 100644
index 0000000..d7fc6a9
--- /dev/null
+++ b/src/examples/simpleArith.py
@@ -0,0 +1,67 @@
+#
+# simpleArith.py
+#
+# Example of defining an arithmetic expression parser using
+# the operatorPrecedence 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 operatorPrecedence 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 operatorPrecedence 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 operatorPrecedence 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 = operatorPrecedence( 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/src/examples/simpleBool.py b/src/examples/simpleBool.py
new file mode 100644
index 0000000..cea08cc
--- /dev/null
+++ b/src/examples/simpleBool.py
@@ -0,0 +1,88 @@
+#
+# 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 BoolOperand subclass objects, which can then
+# later be evaluated for their boolean value.
+#
+# Copyright 2006, by Paul McGuire
+#
+
+from pyparsing import *
+
+class BoolOperand(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)) + ")"
+
+class BoolAnd(BoolOperand):
+ reprsymbol = '&'
+ def __nonzero__(self):
+ for a in self.args:
+ if isinstance(a,basestring):
+ v = eval(a)
+ else:
+ v = bool(a)
+ if not v:
+ return False
+ return True
+
+class BoolOr(BoolOperand):
+ reprsymbol = '|'
+ def __nonzero__(self):
+ for a in self.args:
+ if isinstance(a,basestring):
+ v = eval(a)
+ else:
+ v = bool(a)
+ if v:
+ return True
+ return False
+
+class BoolNot(BoolOperand):
+ def __init__(self,t):
+ self.arg = t[0][1]
+ def __str__(self):
+ return "~" + str(self.arg)
+ def __nonzero__(self):
+ if isinstance(self.arg,basestring):
+ v = eval(self.arg)
+ else:
+ v = bool(self.arg)
+ return not v
+
+boolOperand = Word(alphas,max=1) | oneOf("True False")
+boolExpr = operatorPrecedence( boolOperand,
+ [
+ ("not", 1, opAssoc.RIGHT, BoolNot),
+ ("and", 2, opAssoc.LEFT, BoolAnd),
+ ("or", 2, opAssoc.LEFT, BoolOr),
+ ])
+test = ["p and not q",
+ "not not p",
+ "not(p and q)",
+ "q or not p and r",
+ "q or not p or not r",
+ "q or not (p and r)",
+ "p or q or r",
+ "p or q or r and False",
+ "(p or q or r) and False",
+ ]
+
+p = True
+q = False
+r = True
+print "p =", p
+print "q =", q
+print "r =", r
+print
+for t in test:
+ res = boolExpr.parseString(t)[0]
+ print t,'\n', res, '=', bool(res),'\n'
+
diff --git a/src/examples/simpleSQL.py b/src/examples/simpleSQL.py
new file mode 100644
index 0000000..fc9e408
--- /dev/null
+++ b/src/examples/simpleSQL.py
@@ -0,0 +1,142 @@
+# 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, Paul McGuire
+#
+from pyparsing import Literal, CaselessLiteral, Word, Upcase, delimitedList, Optional, \
+ Combine, Group, alphas, nums, alphanums, ParseException, Forward, oneOf, quotedString, \
+ ZeroOrMore, restOfLine, Keyword
+
+def test( str ):
+ print str,"->"
+ try:
+ tokens = simpleSQL.parseString( str )
+ print "tokens = ", tokens
+ print "tokens.columns =", tokens.columns
+ print "tokens.tables =", tokens.tables
+ print "tokens.where =", tokens.where
+ except ParseException, err:
+ print " "*err.loc + "^\n" + err.msg
+ print err
+ print
+
+
+# define SQL tokens
+selectStmt = Forward()
+selectToken = Keyword("select", caseless=True)
+fromToken = Keyword("from", caseless=True)
+
+ident = Word( alphas, alphanums + "_$" ).setName("identifier")
+columnName = Upcase( delimitedList( ident, ".", combine=True ) )
+columnNameList = Group( delimitedList( columnName ) )
+tableName = Upcase( delimitedList( ident, ".", combine=True ) )
+tableNameList = Group( delimitedList( tableName ) )
+
+whereExpression = Forward()
+and_ = Keyword("and", caseless=True)
+or_ = Keyword("or", caseless=True)
+in_ = Keyword("in", caseless=True)
+
+E = CaselessLiteral("E")
+binop = oneOf("= != < > >= <= eq ne lt le gt ge", caseless=True)
+arithSign = Word("+-",exact=1)
+realNum = Combine( Optional(arithSign) + ( Word( nums ) + "." + Optional( Word(nums) ) |
+ ( "." + Word(nums) ) ) +
+ Optional( E + Optional(arithSign) + Word(nums) ) )
+intNum = Combine( Optional(arithSign) + Word( nums ) +
+ Optional( E + Optional("+") + Word(nums) ) )
+
+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 << ( selectToken +
+ ( '*' | columnNameList ).setResultsName( "columns" ) +
+ fromToken +
+ tableNameList.setResultsName( "tables" ) +
+ Optional( Group( CaselessLiteral("where") + whereExpression ), "" ).setResultsName("where") )
+
+simpleSQL = selectStmt
+
+# define Oracle comment format, and ignore them
+oracleSqlComment = "--" + restOfLine
+simpleSQL.ignore( oracleSqlComment )
+
+
+test( "SELECT * from XYZZY, ABC" )
+test( "select * from SYS.XYZZY" )
+test( "Select A from Sys.dual" )
+test( "Select A,B,C from Sys.dual" )
+test( "Select A, B, C from Sys.dual" )
+test( "Select A, B, C from Sys.dual, Table2 " )
+test( "Xelect A, B, C from Sys.dual" )
+test( "Select A, B, C frox Sys.dual" )
+test( "Select" )
+test( "Select &&& frox Sys.dual" )
+test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE')" )
+test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)" )
+test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators" )
+
+"""
+Test output:
+>pythonw -u simpleSQL.py
+SELECT * from XYZZY, ABC ->
+tokens = ['select', '*', 'from', ['XYZZY', 'ABC']]
+tokens.columns = *
+tokens.tables = ['XYZZY', 'ABC']
+
+select * from SYS.XYZZY ->
+tokens = ['select', '*', 'from', ['SYS.XYZZY']]
+tokens.columns = *
+tokens.tables = ['SYS.XYZZY']
+
+Select A from Sys.dual ->
+tokens = ['select', ['A'], 'from', ['SYS.DUAL']]
+tokens.columns = ['A']
+tokens.tables = ['SYS.DUAL']
+
+Select A,B,C from Sys.dual ->
+tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']]
+tokens.columns = ['A', 'B', 'C']
+tokens.tables = ['SYS.DUAL']
+
+Select A, B, C from Sys.dual ->
+tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']]
+tokens.columns = ['A', 'B', 'C']
+tokens.tables = ['SYS.DUAL']
+
+Select A, B, C from Sys.dual, Table2 ->
+tokens = ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL', 'TABLE2']]
+tokens.columns = ['A', 'B', 'C']
+tokens.tables = ['SYS.DUAL', 'TABLE2']
+
+Xelect A, B, C from Sys.dual ->
+^
+Expected 'select'
+Expected 'select' (0), (1,1)
+
+Select A, B, C frox Sys.dual ->
+ ^
+Expected 'from'
+Expected 'from' (15), (1,16)
+
+Select ->
+ ^
+Expected '*'
+Expected '*' (6), (1,7)
+
+Select &&& frox Sys.dual ->
+ ^
+Expected '*'
+Expected '*' (7), (1,8)
+
+>Exit code: 0
+""" \ No newline at end of file
diff --git a/src/examples/simpleWiki.py b/src/examples/simpleWiki.py
new file mode 100644
index 0000000..fb50a0f
--- /dev/null
+++ b/src/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/src/examples/snmp_api.h b/src/examples/snmp_api.h
new file mode 100644
index 0000000..d75cb12
--- /dev/null
+++ b/src/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/src/examples/sparser.py b/src/examples/sparser.py
new file mode 100644
index 0000000..7217a11
--- /dev/null
+++ b/src/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
+ self.file = urllib.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.
+ execfile(self.parsedef)
+
+ # 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/src/examples/sql2dot.py b/src/examples/sql2dot.py
new file mode 100644
index 0000000..7fab65f
--- /dev/null
+++ b/src/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/src/examples/stackish.py b/src/examples/stackish.py
new file mode 100644
index 0000000..1c4d84c
--- /dev/null
+++ b/src/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 \ No newline at end of file
diff --git a/src/examples/stateMachine2.py b/src/examples/stateMachine2.py
new file mode 100644
index 0000000..286266b
--- /dev/null
+++ b/src/examples/stateMachine2.py
@@ -0,0 +1 @@
+# stateMachine.py # # module to define .pystate import handler # #import imputil import sys import os import types import urlparse 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 = 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 = urlparse.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 in module.__dict__ PystateImporter.register() \ No newline at end of file
diff --git a/src/examples/tagCapture.py b/src/examples/tagCapture.py
new file mode 100644
index 0000000..c9077ff
--- /dev/null
+++ b/src/examples/tagCapture.py
@@ -0,0 +1,35 @@
+#
+# tagCapture.py
+#
+# Simple demo showing how to match HTML tags
+#
+
+from pyparsing import *
+
+src = "this is test <b> bold <i>text</i> </b> normal text "
+
+def matchingCloseTag(other):
+ ret = Forward()
+ ret << anyCloseTag.copy()
+
+ def setupMatchingClose(tokens):
+ opentag = tokens[0]
+
+ def mustMatch(tokens):
+ if tokens[0][0].strip('<>/') != opentag:
+ raise ParseException("",0,"")
+
+ ret.setParseAction(mustMatch)
+
+ other.addParseAction(setupMatchingClose)
+
+ return ret
+
+for m in originalTextFor(anyOpenTag + SkipTo(matchingCloseTag(anyOpenTag),
+ include=True,
+ failOn=anyOpenTag) ).searchString(src):
+ print m.dump()
+
+for m in originalTextFor(anyOpenTag + SkipTo(matchingCloseTag(anyOpenTag),
+ include=True) ).searchString(src):
+ print m.dump()
diff --git a/src/examples/test_bibparse.py b/src/examples/test_bibparse.py
new file mode 100644
index 0000000..7440a66
--- /dev/null
+++ b/src/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/src/examples/urlExtractor.py b/src/examples/urlExtractor.py
new file mode 100644
index 0000000..2e5f7be
--- /dev/null
+++ b/src/examples/urlExtractor.py
@@ -0,0 +1,42 @@
+# URL extractor
+# Copyright 2004, Paul McGuire
+from pyparsing import Literal,Suppress,CharsNotIn,CaselessLiteral,\
+ Word,dblQuotedString,alphanums,SkipTo
+import urllib
+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 = (Literal("<") + "a" + "href" + "=").suppress() + \
+ ( dblQuotedString | Word(alphanums+"/") ) + \
+ Suppress(">")
+linkCloseTag = Literal("<") + "/" + CaselessLiteral("a") + ">"
+link = linkOpenTag + SkipTo(linkCloseTag) + linkCloseTag.suppress()
+
+# Go get some HTML with some links in it.
+serverListPage = urllib.urlopen( "http://www.yahoo.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.asList()
+
+# Rerun scanString, but this time create a dict of text:URL key-value pairs.
+# Need to reverse the tokens returned by link, using a parse action.
+link.setParseAction( lambda st,loc,toks: [ toks[1], toks[0] ] )
+
+# Create dictionary from list comprehension, assembled from each pair of tokens returned
+# from a matched URL.
+pprint.pprint(
+ dict( [ toks for toks,strt,end in link.scanString(htmlText) ] )
+ )
+
+
+
diff --git a/src/examples/urlExtractorNew.py b/src/examples/urlExtractorNew.py
new file mode 100644
index 0000000..276e112
--- /dev/null
+++ b/src/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
+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).setResultsName("body") + linkCloseTag.suppress()
+
+# Go get some HTML with some links in it.
+serverListPage = urllib.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/src/examples/verilogParse.py b/src/examples/verilogParse.py
new file mode 100644
index 0000000..cc7772d
--- /dev/null
+++ b/src/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, Upcase, 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+"]*(\.["+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, 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 = filter( lambda f : f.endswith(".v"), os.listdir(fileDir) )
+ #~ 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 = file(fnam)
+ filelines = infile.readlines()
+ infile.close()
+ print fnam, len(filelines),
+ 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 = file(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/src/examples/withAttribute.py b/src/examples/withAttribute.py
new file mode 100644
index 0000000..af7edf3
--- /dev/null
+++ b/src/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/src/examples/wordsToNum.py b/src/examples/wordsToNum.py
new file mode 100644
index 0000000..e40adb2
--- /dev/null
+++ b/src/examples/wordsToNum.py
@@ -0,0 +1,108 @@
+# 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
+
+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("-")
+numWords.ignore(CaselessLiteral("and"))
+
+def test(s,expected):
+ try:
+ val = numWords.parseString(s)[0]
+ except ParseException, pe:
+ print "Parsing failed:"
+ print s
+ print "%s^" % (' '*(pe.col-1))
+ print pe.msg
+ else:
+ print "'%s' -> %d" % (s, val),
+ if val == expected:
+ print "CORRECT"
+ else:
+ print "***WRONG***, expected %d" % expected
+
+test("one hundred twenty hundred", 120)
+test("one hundred and twennty", 120)
+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