From 0b19bb71ba5a4afa84e673a8239935426fa0db23 Mon Sep 17 00:00:00 2001 From: ptmcg Date: Tue, 9 Aug 2016 21:50:19 +0000 Subject: Remove incorrect tag directory git-svn-id: svn://svn.code.sf.net/p/pyparsing/code/tags/pyparsing_2.1.6@405 9bf210a0-9d2d-494c-87cf-cfb32e7dff7b --- trunk/src/CHANGES | 2139 --------- trunk/src/HowToUsePyparsing.html | 1289 ------ trunk/src/HowToUsePyparsing.txt | 993 ---- trunk/src/LICENSE | 18 - trunk/src/MANIFEST.in_bdist | 7 - trunk/src/MANIFEST.in_src | 7 - trunk/src/README | 80 - trunk/src/examples/0README.html | 309 -- trunk/src/examples/AcManForm.dfm | 885 ---- trunk/src/examples/LAparser.py | 417 -- trunk/src/examples/Setup.ini | 73 - trunk/src/examples/SimpleCalc.py | 118 - trunk/src/examples/SingleForm.dfm | 751 --- trunk/src/examples/TAP.py | 217 - trunk/src/examples/__init__.py | 0 trunk/src/examples/adventureEngine.py | 648 --- trunk/src/examples/antlr_grammar.py | 218 - trunk/src/examples/antlr_grammar_tests.py | 85 - trunk/src/examples/apicheck.py | 55 - trunk/src/examples/btpyparse.py | 128 - trunk/src/examples/builtin_parse_action_demo.py | 29 - trunk/src/examples/cLibHeader.py | 25 - trunk/src/examples/chemicalFormulas.py | 67 - trunk/src/examples/commasep.py | 23 - trunk/src/examples/configParse.py | 72 - trunk/src/examples/cpp_enum_parser.py | 52 - trunk/src/examples/datetimeParseActions.py | 43 - trunk/src/examples/deltaTime.py | 208 - trunk/src/examples/dfmparse.py | 176 - trunk/src/examples/dhcpd_leases_parser.py | 87 - trunk/src/examples/dictExample.py | 41 - trunk/src/examples/dictExample2.py | 59 - trunk/src/examples/ebnf.py | 149 - trunk/src/examples/ebnftest.py | 66 - trunk/src/examples/eval_arith.py | 227 - trunk/src/examples/excelExpr.py | 68 - trunk/src/examples/fourFn.py | 192 - trunk/src/examples/gen_ctypes.py | 167 - trunk/src/examples/getNTPservers.py | 30 - trunk/src/examples/getNTPserversNew.py | 35 - trunk/src/examples/greeting.py | 17 - trunk/src/examples/greetingInGreek.py | 18 - trunk/src/examples/greetingInKorean.py | 20 - trunk/src/examples/groupUsingListAllMatches.py | 16 - trunk/src/examples/holaMundo.py | 30 - trunk/src/examples/htmlStripper.py | 39 - trunk/src/examples/httpServerLogParser.py | 71 - trunk/src/examples/idlParse.py | 222 - trunk/src/examples/indentedGrammarExample.py | 54 - trunk/src/examples/invRegex.py | 257 -- trunk/src/examples/javascript_grammar.g | 894 ---- trunk/src/examples/jsonParser.py | 111 - trunk/src/examples/linenoExample.py | 49 - trunk/src/examples/list1.py | 50 - trunk/src/examples/listAllMatches.py | 52 - trunk/src/examples/lucene_grammar.py | 330 -- trunk/src/examples/macroExpander.py | 60 - trunk/src/examples/makeHTMLTagExample.py | 21 - trunk/src/examples/matchPreviousDemo.py | 33 - trunk/src/examples/mozilla.ics | 50 - trunk/src/examples/mozillaCalendarParser.py | 81 - trunk/src/examples/nested.py | 30 - trunk/src/examples/numerics.py | 62 - trunk/src/examples/oc.py | 193 - trunk/src/examples/parseListString.py | 82 - trunk/src/examples/parsePythonValue.py | 70 - trunk/src/examples/parseResultsSumExample.py | 26 - trunk/src/examples/parseTabularData.py | 50 - trunk/src/examples/partial_gene_match.py | 88 - trunk/src/examples/pgn.py | 94 - trunk/src/examples/position.py | 55 - trunk/src/examples/protobuf_parser.py | 100 - trunk/src/examples/pymicko.py | 1387 ------ trunk/src/examples/pythonGrammarParser.py | 220 - trunk/src/examples/rangeCheck.py | 62 - trunk/src/examples/readJson.py | 1917 -------- trunk/src/examples/removeLineBreaks.py | 45 - trunk/src/examples/romanNumerals.py | 74 - trunk/src/examples/scanExamples.py | 75 - trunk/src/examples/scanYahoo.py | 14 - trunk/src/examples/searchParserAppDemo.py | 34 - trunk/src/examples/searchparser.py | 292 -- trunk/src/examples/select_parser.py | 126 - trunk/src/examples/sexpParser.py | 167 - trunk/src/examples/shapes.py | 64 - trunk/src/examples/simpleArith.py | 67 - trunk/src/examples/simpleBool.py | 102 - trunk/src/examples/simpleSQL.py | 72 - trunk/src/examples/simpleWiki.py | 32 - trunk/src/examples/snmp_api.h | 795 ---- trunk/src/examples/sparser.py | 365 -- trunk/src/examples/sql2dot.py | 96 - trunk/src/examples/stackish.py | 81 - trunk/src/examples/stateMachine2.py | 258 -- trunk/src/examples/test_bibparse.py | 195 - trunk/src/examples/urlExtractor.py | 33 - trunk/src/examples/urlExtractorNew.py | 35 - trunk/src/examples/verilogParse.py | 720 --- trunk/src/examples/withAttribute.py | 24 - trunk/src/examples/wordsToNum.py | 98 - trunk/src/genEpydoc.bat | 2 - trunk/src/makeRelease.bat | 24 - trunk/src/pyparsing.py | 5528 ----------------------- trunk/src/pyparsingClassDiagram.JPG | Bin 236402 -> 0 bytes trunk/src/pyparsingClassDiagram.PNG | Bin 141354 -> 0 bytes trunk/src/setup.cfg | 5 - trunk/src/setup.py | 37 - trunk/src/test/__init__.py | 0 trunk/src/test/jsonParserTests.py | 360 -- trunk/src/test/karthik.ini | 14 - trunk/src/test/parsefiletest_input_file.txt | 1 - trunk/src/unitTests.py | 3169 ------------- trunk/src/update_pyparsing_timestamp.py | 17 - 113 files changed, 30185 deletions(-) delete mode 100644 trunk/src/CHANGES delete mode 100644 trunk/src/HowToUsePyparsing.html delete mode 100644 trunk/src/HowToUsePyparsing.txt delete mode 100644 trunk/src/LICENSE delete mode 100644 trunk/src/MANIFEST.in_bdist delete mode 100644 trunk/src/MANIFEST.in_src delete mode 100644 trunk/src/README delete mode 100644 trunk/src/examples/0README.html delete mode 100644 trunk/src/examples/AcManForm.dfm delete mode 100644 trunk/src/examples/LAparser.py delete mode 100644 trunk/src/examples/Setup.ini delete mode 100644 trunk/src/examples/SimpleCalc.py delete mode 100644 trunk/src/examples/SingleForm.dfm delete mode 100644 trunk/src/examples/TAP.py delete mode 100644 trunk/src/examples/__init__.py delete mode 100644 trunk/src/examples/adventureEngine.py delete mode 100644 trunk/src/examples/antlr_grammar.py delete mode 100644 trunk/src/examples/antlr_grammar_tests.py delete mode 100644 trunk/src/examples/apicheck.py delete mode 100644 trunk/src/examples/btpyparse.py delete mode 100644 trunk/src/examples/builtin_parse_action_demo.py delete mode 100644 trunk/src/examples/cLibHeader.py delete mode 100644 trunk/src/examples/chemicalFormulas.py delete mode 100644 trunk/src/examples/commasep.py delete mode 100644 trunk/src/examples/configParse.py delete mode 100644 trunk/src/examples/cpp_enum_parser.py delete mode 100644 trunk/src/examples/datetimeParseActions.py delete mode 100644 trunk/src/examples/deltaTime.py delete mode 100644 trunk/src/examples/dfmparse.py delete mode 100644 trunk/src/examples/dhcpd_leases_parser.py delete mode 100644 trunk/src/examples/dictExample.py delete mode 100644 trunk/src/examples/dictExample2.py delete mode 100644 trunk/src/examples/ebnf.py delete mode 100644 trunk/src/examples/ebnftest.py delete mode 100644 trunk/src/examples/eval_arith.py delete mode 100644 trunk/src/examples/excelExpr.py delete mode 100644 trunk/src/examples/fourFn.py delete mode 100644 trunk/src/examples/gen_ctypes.py delete mode 100644 trunk/src/examples/getNTPservers.py delete mode 100644 trunk/src/examples/getNTPserversNew.py delete mode 100644 trunk/src/examples/greeting.py delete mode 100644 trunk/src/examples/greetingInGreek.py delete mode 100644 trunk/src/examples/greetingInKorean.py delete mode 100644 trunk/src/examples/groupUsingListAllMatches.py delete mode 100644 trunk/src/examples/holaMundo.py delete mode 100644 trunk/src/examples/htmlStripper.py delete mode 100644 trunk/src/examples/httpServerLogParser.py delete mode 100644 trunk/src/examples/idlParse.py delete mode 100644 trunk/src/examples/indentedGrammarExample.py delete mode 100644 trunk/src/examples/invRegex.py delete mode 100644 trunk/src/examples/javascript_grammar.g delete mode 100644 trunk/src/examples/jsonParser.py delete mode 100644 trunk/src/examples/linenoExample.py delete mode 100644 trunk/src/examples/list1.py delete mode 100644 trunk/src/examples/listAllMatches.py delete mode 100644 trunk/src/examples/lucene_grammar.py delete mode 100644 trunk/src/examples/macroExpander.py delete mode 100644 trunk/src/examples/makeHTMLTagExample.py delete mode 100644 trunk/src/examples/matchPreviousDemo.py delete mode 100644 trunk/src/examples/mozilla.ics delete mode 100644 trunk/src/examples/mozillaCalendarParser.py delete mode 100644 trunk/src/examples/nested.py delete mode 100644 trunk/src/examples/numerics.py delete mode 100644 trunk/src/examples/oc.py delete mode 100644 trunk/src/examples/parseListString.py delete mode 100644 trunk/src/examples/parsePythonValue.py delete mode 100644 trunk/src/examples/parseResultsSumExample.py delete mode 100644 trunk/src/examples/parseTabularData.py delete mode 100644 trunk/src/examples/partial_gene_match.py delete mode 100644 trunk/src/examples/pgn.py delete mode 100644 trunk/src/examples/position.py delete mode 100644 trunk/src/examples/protobuf_parser.py delete mode 100644 trunk/src/examples/pymicko.py delete mode 100644 trunk/src/examples/pythonGrammarParser.py delete mode 100644 trunk/src/examples/rangeCheck.py delete mode 100644 trunk/src/examples/readJson.py delete mode 100644 trunk/src/examples/removeLineBreaks.py delete mode 100644 trunk/src/examples/romanNumerals.py delete mode 100644 trunk/src/examples/scanExamples.py delete mode 100644 trunk/src/examples/scanYahoo.py delete mode 100644 trunk/src/examples/searchParserAppDemo.py delete mode 100644 trunk/src/examples/searchparser.py delete mode 100644 trunk/src/examples/select_parser.py delete mode 100644 trunk/src/examples/sexpParser.py delete mode 100644 trunk/src/examples/shapes.py delete mode 100644 trunk/src/examples/simpleArith.py delete mode 100644 trunk/src/examples/simpleBool.py delete mode 100644 trunk/src/examples/simpleSQL.py delete mode 100644 trunk/src/examples/simpleWiki.py delete mode 100644 trunk/src/examples/snmp_api.h delete mode 100644 trunk/src/examples/sparser.py delete mode 100644 trunk/src/examples/sql2dot.py delete mode 100644 trunk/src/examples/stackish.py delete mode 100644 trunk/src/examples/stateMachine2.py delete mode 100644 trunk/src/examples/test_bibparse.py delete mode 100644 trunk/src/examples/urlExtractor.py delete mode 100644 trunk/src/examples/urlExtractorNew.py delete mode 100644 trunk/src/examples/verilogParse.py delete mode 100644 trunk/src/examples/withAttribute.py delete mode 100644 trunk/src/examples/wordsToNum.py delete mode 100644 trunk/src/genEpydoc.bat delete mode 100644 trunk/src/makeRelease.bat delete mode 100644 trunk/src/pyparsing.py delete mode 100644 trunk/src/pyparsingClassDiagram.JPG delete mode 100644 trunk/src/pyparsingClassDiagram.PNG delete mode 100644 trunk/src/setup.cfg delete mode 100644 trunk/src/setup.py delete mode 100644 trunk/src/test/__init__.py delete mode 100644 trunk/src/test/jsonParserTests.py delete mode 100644 trunk/src/test/karthik.ini delete mode 100644 trunk/src/test/parsefiletest_input_file.txt delete mode 100644 trunk/src/unitTests.py delete mode 100644 trunk/src/update_pyparsing_timestamp.py diff --git a/trunk/src/CHANGES b/trunk/src/CHANGES deleted file mode 100644 index 0e48b21..0000000 --- a/trunk/src/CHANGES +++ /dev/null @@ -1,2139 +0,0 @@ -========== -Change Log -========== - -Version 2.1.6 - ------------------------------- -- *Major packrat upgrade*, inspired by patch provided by Tal Einat - - many, many, thanks to Tal for working on this! Tal's tests show - faster parsing performance (2X in some tests), *and* memory reduction - from 3GB down to ~100MB! Requires no changes to existing code using - packratting. (Uses OrderedDict, available in Python 2.7 and later. - For Python 2.6 users, will attempt to import from ordereddict - backport. If not present, will implement pure-Python Fifo dict.) - -- Minor API change - to better distinguish between the flexible - numeric types defined in pyparsing_common, I've changed "numeric" - (which parsed numbers of different types and returned int for ints, - float for floats, etc.) and "number" (which parsed numbers of int - or float type, and returned all floats) to "number" and "fnumber" - respectively. I hope the "f" prefix of "fnumber" will be a better - indicator of its internal conversion of parsed values to floats, - while the generic "number" is similar to the flexible number syntax - in other languages. Also fixed a bug in pyparsing_common.numeric - (now renamed to pyparsing_common.number), integers were parsed and - returned as floats instead of being retained as ints. - -- Fixed bug in upcaseTokens and downcaseTokens introduced in 2.1.5, - when the parse action was used in conjunction with results names. - Reported by Steven Arcangeli from the dql project, thanks for your - patience, Steven! - -- Major change to docs! After seeing some comments on reddit about - general issue with docs of Python modules, and thinking that I'm a - little overdue in doing some doc tuneup on pyparsing, I decided to - following the suggestions of the redditor and add more inline examples - to the pyparsing reference documentation. I hope this addition - will clarify some of the more common questions people have, especially - when first starting with pyparsing/Python. - -- Deprecated ParseResults.asXML. I've never been too happy with this - method, and it usually forces some unnatural code in the parsers in - order to get decent tag names. The amount of guesswork that asXML - has to do to try to match names with values should have been a red - flag from day one. If you are using asXML, you will need to implement - your own ParseResults->XML serialization. Or consider migrating to - a more current format such as JSON (which is very easy to do: - results_as_json = json.dumps(parse_result.asDict()) Hopefully, when - I remove this code in a future version, I'll also be able to simplify - some of the craziness in ParseResults, which IIRC was only there to try - to make asXML work. - -- Updated traceParseAction parse action decorator to show the repr - of the input and output tokens, instead of the str format, since - str has been simplified to just show the token list content. - - (The change to ParseResults.__str__ occurred in pyparsing 2.0.4, but - it seems that didn't make it into the release notes - sorry! Too - many users, especially beginners, were confused by the - "([token_list], {names_dict})" str format for ParseResults, thinking - they were getting a tuple containing a list and a dict. The full form - can be seen if using repr().) - - For tracing tokens in and out of parse actions, the more complete - repr form provides important information when debugging parse actions. - - -Verison 2.1.5 - June, 2016 ------------------------------- -- Added ParserElement.split() generator method, similar to re.split(). - Includes optional arguments maxsplit (to limit the number of splits), - and includeSeparators (to include the separating matched text in the - returned output, default=False). - -- Added a new parse action construction helper tokenMap, which will - apply a function and optional arguments to each element in a - ParseResults. So this parse action: - - def lowercase_all(tokens): - return [str(t).lower() for t in tokens] - OneOrMore(Word(alphas)).setParseAction(lowercase_all) - - can now be written: - - OneOrMore(Word(alphas)).setParseAction(tokenMap(str.lower)) - - Also simplifies writing conversion parse actions like: - - integer = Word(nums).setParseAction(lambda t: int(t[0])) - - to just: - - integer = Word(nums).setParseAction(tokenMap(int)) - - If additional arguments are necessary, they can be included in the - call to tokenMap, as in: - - hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16)) - -- Added more expressions to pyparsing_common: - . IPv4 and IPv6 addresses (including long, short, and mixed forms - of IPv6) - . MAC address - . ISO8601 date and date time strings (with named fields for year, month, etc.) - . UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) - . hex integer (returned as int) - . fraction (integer '/' integer, returned as float) - . mixed integer (integer '-' fraction, or just fraction, returned as float) - . stripHTMLTags (parse action to remove tags from HTML source) - . parse action helpers convertToDate and convertToDatetime to do custom parse - time conversions of parsed ISO8601 strings - -- runTests now returns a two-tuple: success if all tests succeed, - and an output list of each test and its output lines. - -- Added failureTests argument (default=False) to runTests, so that - tests can be run that are expected failures, and runTests' success - value will return True only if all tests *fail* as expected. Also, - parseAll now defaults to True. - -- New example numerics.py, shows samples of parsing integer and real - numbers using locale-dependent formats: - - 4.294.967.295,000 - 4 294 967 295,000 - 4,294,967,295.000 - - -Version 2.1.4 - May, 2016 ------------------------------- -- Split out the '==' behavior in ParserElement, now implemented - as the ParserElement.matches() method. Using '==' for string test - purposes will be removed in a future release. - -- Expanded capabilities of runTests(). Will now accept embedded - comments (default is Python style, leading '#' character, but - customizable). Comments will be emitted along with the tests and - test output. Useful during test development, to create a test string - consisting only of test case description comments separated by - blank lines, and then fill in the test cases. Will also highlight - ParseFatalExceptions with "(FATAL)". - -- Added a 'pyparsing_common' class containing common/helpful little - expressions such as integer, float, identifier, etc. I used this - class as a sort of embedded namespace, to contain these helpers - without further adding to pyparsing's namespace bloat. - -- Minor enhancement to traceParseAction decorator, to retain the - parse action's name for the trace output. - -- Added optional 'fatal' keyword arg to addCondition, to indicate that - a condition failure should halt parsing immediately. - - -Version 2.1.3 - May, 2016 ------------------------------- -- _trim_arity fix in 2.1.2 was very version-dependent on Py 3.5.0. - Now works for Python 2.x, 3.3, 3.4, 3.5.0, and 3.5.1 (and hopefully - beyond). - - -Version 2.1.2 - May, 2016 ------------------------------- -- Fixed bug in _trim_arity when pyparsing code is included in a - PyInstaller, reported by maluwa. - -- Fixed catastrophic regex backtracking in implementation of the - quoted string expressions (dblQuotedString, sglQuotedString, and - quotedString). Reported on the pyparsing wiki by webpentest, - good catch! (Also tuned up some other expressions susceptible to the - same backtracking problem, such as cStyleComment, cppStyleComment, - etc.) - - -Version 2.1.1 - March, 2016 ---------------------------- -- Added support for assigning to ParseResults using slices. - -- Fixed bug in ParseResults.toDict(), in which dict values were always - converted to dicts, even if they were just unkeyed lists of tokens. - Reported on SO by Gerald Thibault, thanks Gerald! - -- Fixed bug in SkipTo when using failOn, reported by robyschek, thanks! - -- Fixed bug in Each introduced in 2.1.0, reported by AND patch and - unit test submitted by robyschek, well done! - -- Removed use of functools.partial in replaceWith, as this creates - an ambiguous signature for the generated parse action, which fails in - PyPy. Reported by Evan Hubinger, thanks Evan! - -- Added default behavior to QuotedString to convert embedded '\t', '\n', - etc. characters to their whitespace counterparts. Found during Q&A - exchange on SO with Maxim. - - -Version 2.1.0 - February, 2016 ------------------------------- -- Modified the internal _trim_arity method to distinguish between - TypeError's raised while trying to determine parse action arity and - those raised within the parse action itself. This will clear up those - confusing "() takes exactly 1 argument (0 given)" error - messages when there is an actual TypeError in the body of the parse - action. Thanks to all who have raised this issue in the past, and - most recently to Michael Cohen, who sent in a proposed patch, and got - me to finally tackle this problem. - -- Added compatibility for pickle protocols 2-4 when pickling ParseResults. - In Python 2.x, protocol 0 was the default, and protocol 2 did not work. - In Python 3.x, protocol 3 is the default, so explicitly naming - protocol 0 or 1 was required to pickle ParseResults. With this release, - all protocols 0-4 are supported. Thanks for reporting this on StackOverflow, - Arne Wolframm, and for providing a nice simple test case! - -- Added optional 'stopOn' argument to ZeroOrMore and OneOrMore, to - simplify breaking on stop tokens that would match the repetition - expression. - - It is a common problem to fail to look ahead when matching repetitive - tokens if the sentinel at the end also matches the repetition - expression, as when parsing "BEGIN aaa bbb ccc END" with: - - "BEGIN" + OneOrMore(Word(alphas)) + "END" - - Since "END" matches the repetition expression "Word(alphas)", it will - never get parsed as the terminating sentinel. Up until now, this has - to be resolved by the user inserting their own negative lookahead: - - "BEGIN" + OneOrMore(~Literal("END") + Word(alphas)) + "END" - - Using stopOn, they can more easily write: - - "BEGIN" + OneOrMore(Word(alphas), stopOn="END") + "END" - - The stopOn argument can be a literal string or a pyparsing expression. - Inspired by a question by Lamakaha on StackOverflow (and many previous - questions with the same negative-lookahead resolution). - -- Added expression names for many internal and builtin expressions, to - reduce name and error message overhead during parsing. - -- Converted helper lambdas to functions to refactor and add docstring - support. - -- Fixed ParseResults.asDict() to correctly convert nested ParseResults - values to dicts. - -- Cleaned up some examples, fixed typo in fourFn.py identified by - aristotle2600 on reddit. - -- Removed keepOriginalText helper method, which was deprecated ages ago. - Superceded by originalTextFor. - -- Same for the Upcase class, which was long ago deprecated and replaced - with the upcaseTokens method. - - - -Version 2.0.7 - December, 2015 ------------------------------- -- Simplified string representation of Forward class, to avoid memory - and performance errors while building ParseException messages. Thanks, - Will McGugan, Andrea Censi, and Martijn Vermaat for the bug reports and - test code. - -- Cleaned up additional issues from enhancing the error messages for - Or and MatchFirst, handling Unicode values in expressions. Fixes Unicode - encoding issues in Python 2, thanks to Evan Hubinger for the bug report. - -- Fixed implementation of dir() for ParseResults - was leaving out all the - defined methods and just adding the custom results names. - -- Fixed bug in ignore() that was introduced in pyparsing 1.5.3, that would - not accept a string literal as the ignore expression. - -- Added new example parseTabularData.py to illustrate parsing of data - formatted in columns, with detection of empty cells. - -- Updated a number of examples to more current Python and pyparsing - forms. - - -Version 2.0.6 - November, 2015 ------------------------------- -- Fixed a bug in Each when multiple Optional elements are present. - Thanks for reporting this, whereswalden on SO. - -- Fixed another bug in Each, when Optional elements have results names - or parse actions, reported by Max Rothman - thank you, Max! - -- Added optional parseAll argument to runTests, whether tests should - require the entire input string to be parsed or not (similar to - parseAll argument to parseString). Plus a little neaten-up of the - output on Python 2 (no stray ()'s). - -- Modified exception messages from MatchFirst and Or expressions. These - were formerly misleading as they would only give the first or longest - exception mismatch error message. Now the error message includes all - the alternatives that were possible matches. Originally proposed by - a pyparsing user, but I've lost the email thread - finally figured out - a fairly clean way to do this. - -- Fixed a bug in Or, when a parse action on an alternative raises an - exception, other potentially matching alternatives were not always tried. - Reported by TheVeryOmni on the pyparsing wiki, thanks! - -- Fixed a bug to dump() introduced in 2.0.4, where list values were shown - in duplicate. - - -Version 2.0.5 - October, 2015 ------------------------------ -- (&$(@#&$(@!!!! Some "print" statements snuck into pyparsing v2.0.4, - breaking Python 3 compatibility! Fixed. Reported by jenshn, thanks! - - -Version 2.0.4 - October, 2015 ------------------------------ -- Added ParserElement.addCondition, to simplify adding parse actions - that act primarily as filters. If the given condition evaluates False, - pyparsing will raise a ParseException. The condition should be a method - with the same method signature as a parse action, but should return a - boolean. Suggested by Victor Porton, nice idea Victor, thanks! - -- Slight mod to srange to accept unicode literals for the input string, - such as "[а-яА-Я]" instead of "[\u0430-\u044f\u0410-\u042f]". Thanks - to Alexandr Suchkov for the patch! - -- Enhanced implementation of replaceWith. - -- Fixed enhanced ParseResults.dump() method when the results consists - only of an unnamed array of sub-structure results. Reported by Robin - Siebler, thanks for your patience and persistence, Robin! - -- Fixed bug in fourFn.py example code, where pi and e were defined using - CaselessLiteral instead of CaselessKeyword. This was not a problem until - adding a new function 'exp', and the leading 'e' of 'exp' was accidentally - parsed as the mathematical constant 'e'. Nice catch, Tom Grydeland - thanks! - -- Adopt new-fangled Python features, like decorators and ternary expressions, - per suggestions from Williamzjc - thanks William! (Oh yeah, I'm not - supporting Python 2.3 with this code any more...) Plus, some additional - code fixes/cleanup - thanks again! - -- Added ParserElement.runTests, a little test bench for quickly running - an expression against a list of sample input strings. Basically, I got - tired of writing the same test code over and over, and finally added it - as a test point method on ParserElement. - -- Added withClass helper method, a simplified version of withAttribute for - the common but annoying case when defining a filter on a div's class - - made difficult because 'class' is a Python reserved word. - - -Version 2.0.3 - October, 2014 ------------------------------ -- Fixed escaping behavior in QuotedString. Formerly, only quotation - marks (or characters designated as quotation marks in the QuotedString - constructor) would be escaped. Now all escaped characters will be - escaped, and the escaping backslashes will be removed. - -- Fixed regression in ParseResults.pop() - pop() was pretty much - broken after I added *improvements* in 2.0.2. Reported by Iain - Shelvington, thanks Iain! - -- Fixed bug in And class when initializing using a generator. - -- Enhanced ParseResults.dump() method to list out nested ParseResults that - are unnamed arrays of sub-structures. - -- Fixed UnboundLocalError under Python 3.4 in oneOf method, reported - on Sourceforge by aldanor, thanks! - -- Fixed bug in ParseResults __init__ method, when returning non-ParseResults - types from parse actions that implement __eq__. Raised during discussion - on the pyparsing wiki with cyrfer. - - -Version 2.0.2 - April, 2014 ---------------------------- -- Extended "expr(name)" shortcut (same as "expr.setResultsName(name)") - to accept "expr()" as a shortcut for "expr.copy()". - -- Added "locatedExpr(expr)" helper, to decorate any returned tokens - with their location within the input string. Adds the results names - locn_start and locn_end to the output parse results. - -- Added "pprint()" method to ParseResults, to simplify troubleshooting - and prettified output. Now instead of importing the pprint module - and then writing "pprint.pprint(result)", you can just write - "result.pprint()". This method also accepts addtional positional and - keyword arguments (such as indent, width, etc.), which get passed - through directly to the pprint method - (see http://docs.python.org/2/library/pprint.html#pprint.pprint). - -- Removed deprecation warnings when using '<<' for Forward expression - assignment. '<<=' is still preferred, but '<<' will be retained - for cases whre '<<=' operator is not suitable (such as in defining - lambda expressions). - -- Expanded argument compatibility for classes and functions that - take list arguments, to now accept generators as well. - -- Extended list-like behavior of ParseResults, adding support for - append and extend. NOTE: if you have existing applications using - these names as results names, you will have to access them using - dict-style syntax: res["append"] and res["extend"] - -- ParseResults emulates the change in list vs. iterator semantics for - methods like keys(), values(), and items(). Under Python 2.x, these - methods will return lists, under Python 3.x, these methods will - return iterators. - -- ParseResults now has a method haskeys() which returns True or False - depending on whether any results names have been defined. This simplifies - testing for the existence of results names under Python 3.x, which - returns keys() as an iterator, not a list. - -- ParseResults now supports both list and dict semantics for pop(). - If passed no argument or an integer argument, it will use list semantics - and pop tokens from the list of parsed tokens. If passed a non-integer - argument (most likely a string), it will use dict semantics and - pop the corresponding value from any defined results names. A - second default return value argument is supported, just as in - dict.pop(). - -- Fixed bug in markInputline, thanks for reporting this, Matt Grant! - -- Cleaned up my unit test environment, now runs with Python 2.6 and - 3.3. - - -Version 2.0.1 - July, 2013 --------------------------- -- Removed use of "nonlocal" that prevented using this version of - pyparsing with Python 2.6 and 2.7. This will make it easier to - install for packages that depend on pyparsing, under Python - versions 2.6 and later. Those using older versions of Python - will have to manually install pyparsing 1.5.7. - -- Fixed implementation of <<= operator to return self; reported by - Luc J. Bourhis, with patch fix by Mathias Mamsch - thanks, Luc - and Mathias! - - -Version 2.0.0 - November, 2012 ------------------------------- -- Rather than release another combined Python 2.x/3.x release - I've decided to start a new major version that is only - compatible with Python 3.x (and consequently Python 2.7 as - well due to backporting of key features). This version will - be the main development path from now on, with little follow-on - development on the 1.5.x path. - -- Operator '<<' is now deprecated, in favor of operator '<<=' for - attaching parsing expressions to Forward() expressions. This is - being done to address precedence of operations problems with '<<'. - Operator '<<' will be removed in a future version of pyparsing. - - -Version 1.5.7 - November, 2012 ------------------------------ -- NOTE: This is the last release of pyparsing that will try to - maintain compatibility with Python versions < 2.6. The next - release of pyparsing will be version 2.0.0, using new Python - syntax that will not be compatible for Python version 2.5 or - older. - -- An awesome new example is included in this release, submitted - by Luca DellOlio, for parsing ANTLR grammar definitions, nice - work Luca! - -- Fixed implementation of ParseResults.__str__ to use Pythonic - ''.join() instead of repeated string concatenation. This - purportedly has been a performance issue under PyPy. - -- Fixed bug in ParseResults.__dir__ under Python 3, reported by - Thomas Kluyver, thank you Thomas! - -- Added ParserElement.inlineLiteralsUsing static method, to - override pyparsing's default behavior of converting string - literals to Literal instances, to use other classes (such - as Suppress or CaselessLiteral). - -- Added new operator '<<=', which will eventually replace '<<' for - storing the contents of a Forward(). '<<=' does not have the same - operator precedence problems that '<<' does. - -- 'operatorPrecedence' is being renamed 'infixNotation' as a better - description of what this helper function creates. 'operatorPrecedence' - is deprecated, and will be dropped entirely in a future release. - -- Added optional arguments lpar and rpar to operatorPrecedence, so that - expressions that use it can override the default suppression of the - grouping characters. - -- Added support for using single argument builtin functions as parse - actions. Now you can write 'expr.setParseAction(len)' and get back - the length of the list of matched tokens. Supported builtins are: - sum, len, sorted, reversed, list, tuple, set, any, all, min, and max. - A script demonstrating this feature is included in the examples - directory. - -- Improved linking in generated docs, proposed on the pyparsing wiki - by techtonik, thanks! - -- Fixed a bug in the definition of 'alphas', which was based on the - string.uppercase and string.lowercase "constants", which in fact - *aren't* constant, but vary with locale settings. This could make - parsers locale-sensitive in a subtle way. Thanks to Kef Schecter for - his diligence in following through on reporting and monitoring - this bugfix! - -- Fixed a bug in the Py3 version of pyparsing, during exception - handling with packrat parsing enabled, reported by Catherine - Devlin - thanks Catherine! - -- Fixed typo in ParseBaseException.__dir__, reported anonymously on - the SourceForge bug tracker, thank you Pyparsing User With No Name. - -- Fixed bug in srange when using '\x###' hex character codes. - -- Addeed optional 'intExpr' argument to countedArray, so that you - can define your own expression that will evaluate to an integer, - to be used as the count for the following elements. Allows you - to define a countedArray with the count given in hex, for example, - by defining intExpr as "Word(hexnums).setParseAction(int(t[0],16))". - - -Version 1.5.6 - June, 2011 ----------------------------- -- Cleanup of parse action normalizing code, to be more version-tolerant, - and robust in the face of future Python versions - much thanks to - Raymond Hettinger for this rewrite! - -- Removal of exception cacheing, addressing a memory leak condition - in Python 3. Thanks to Michael Droettboom and the Cape Town PUG for - their analysis and work on this problem! - -- Fixed bug when using packrat parsing, where a previously parsed - expression would duplicate subsequent tokens - reported by Frankie - Ribery on stackoverflow, thanks! - -- Added 'ungroup' helper method, to address token grouping done - implicitly by And expressions, even if only one expression in the - And actually returns any text - also inspired by stackoverflow - discussion with Frankie Ribery! - -- Fixed bug in srange, which accepted escaped hex characters of the - form '\0x##', but should be '\x##'. Both forms will be supported - for backwards compatibility. - -- Enhancement to countedArray, accepting an optional expression to be - used for matching the leading integer count - proposed by Mathias on - the pyparsing mailing list, good idea! - -- Added the Verilog parser to the provided set of examples, under the - MIT license. While this frees up this parser for any use, if you find - yourself using it in a commercial purpose, please consider making a - charitable donation as described in the parser's header. - -- Added the excludeChars argument to the Word class, to simplify defining - a word composed of all characters in a large range except for one or - two. Suggested by JesterEE on the pyparsing wiki. - -- Added optional overlap parameter to scanString, to return overlapping - matches found in the source text. - -- Updated oneOf internal regular expression generation, with improved - parse time performance. - -- Slight performance improvement in transformString, removing empty - strings from the list of string fragments built while scanning the - source text, before calling ''.join. Especially useful when using - transformString to strip out selected text. - -- Enhanced form of using the "expr('name')" style of results naming, - in lieu of calling setResultsName. If name ends with an '*', then - this is equivalent to expr.setResultsName('name',listAllMatches=True). - -- Fixed up internal list flattener to use iteration instead of recursion, - to avoid stack overflow when transforming large files. - -- Added other new examples: - . protobuf parser - parses Google's protobuf language - . btpyparse - a BibTex parser contributed by Matthew Brett, - with test suite test_bibparse.py (thanks, Matthew!) - . groupUsingListAllMatches.py - demo using trailing '*' for results - names - - -Version 1.5.5 - August, 2010 ----------------------------- - -- Typo in Python3 version of pyparsing, "builtin" should be "builtins". - (sigh) - - -Version 1.5.4 - August, 2010 ----------------------------- - -- Fixed __builtins__ and file references in Python 3 code, thanks to - Greg Watson, saulspatz, sminos, and Mark Summerfield for reporting - their Python 3 experiences. - -- Added new example, apicheck.py, as a sample of scanning a Tcl-like - language for functions with incorrect number of arguments (difficult - to track down in Tcl languages). This example uses some interesting - methods for capturing exceptions while scanning through source - code. - -- Added new example deltaTime.py, that takes everyday time references - like "an hour from now", "2 days ago", "next Sunday at 2pm". - - -Version 1.5.3 - June, 2010 --------------------------- - -- ======= NOTE: API CHANGE!!!!!!! =============== - With this release, and henceforward, the pyparsing module is - imported as "pyparsing" on both Python 2.x and Python 3.x versions. - -- Fixed up setup.py to auto-detect Python version and install the - correct version of pyparsing - suggested by Alex Martelli, - thanks, Alex! (and my apologies to all those who struggled with - those spurious installation errors caused by my earlier - fumblings!) - -- Fixed bug on Python3 when using parseFile, getting bytes instead of - a str from the input file. - -- Fixed subtle bug in originalTextFor, if followed by - significant whitespace (like a newline) - discovered by - Francis Vidal, thanks! - -- Fixed very sneaky bug in Each, in which Optional elements were - not completely recognized as optional - found by Tal Weiss, thanks - for your patience. - -- Fixed off-by-1 bug in line() method when the first line of the - input text was an empty line. Thanks to John Krukoff for submitting - a patch! - -- Fixed bug in transformString if grammar contains Group expressions, - thanks to patch submitted by barnabas79, nice work! - -- Fixed bug in originalTextFor in which trailing comments or otherwised - ignored text got slurped in with the matched expression. Thanks to - michael_ramirez44 on the pyparsing wiki for reporting this just in - time to get into this release! - -- Added better support for summing ParseResults, see the new example, - parseResultsSumExample.py. - -- Added support for composing a Regex using a compiled RE object; - thanks to my new colleague, Mike Thornton! - -- In version 1.5.2, I changed the way exceptions are raised in order - to simplify the stacktraces reported during parsing. An anonymous - user posted a bug report on SF that this behavior makes it difficult - to debug some complex parsers, or parsers nested within parsers. In - this release I've added a class attribute ParserElement.verbose_stacktrace, - with a default value of False. If you set this to True, pyparsing will - report stacktraces using the pre-1.5.2 behavior. - -- New examples: - - . pymicko.py, a MicroC compiler submitted by Zarko Zivanov. - (Note: this example is separately licensed under the GPLv3, - and requires Python 2.6 or higher.) Thank you, Zarko! - - . oc.py, a subset C parser, using the BNF from the 1996 Obfuscated C - Contest. - - . stateMachine2.py, a modified version of stateMachine.py submitted - by Matt Anderson, that is compatible with Python versions 2.7 and - above - thanks so much, Matt! - - . select_parser.py, a parser for reading SQLite SELECT statements, - as specified at http://www.sqlite.org/lang_select.html; this goes - into much more detail than the simple SQL parser included in pyparsing's - source code - - . excelExpr.py, a *simplistic* first-cut at a parser for Excel - expressions, which I originally posted on comp.lang.python in January, - 2010; beware, this parser omits many common Excel cases (addition of - numbers represented as strings, references to named ranges) - - . cpp_enum_parser.py, a nice little parser posted my Mark Tolonen on - comp.lang.python in August, 2009 (redistributed here with Mark's - permission). Thanks a bunch, Mark! - - . partial_gene_match.py, a sample I posted to Stackoverflow.com, - implementing a special variation on Literal that does "close" matching, - up to a given number of allowed mismatches. The application was to - find matching gene sequences, with allowance for one or two mismatches. - - . tagCapture.py, a sample showing how to use a Forward placeholder to - enforce matching of text parsed in a previous expression. - - . matchPreviousDemo.py, simple demo showing how the matchPreviousLiteral - helper method is used to match a previously parsed token. - - -Version 1.5.2 - April, 2009 ------------------------------- -- Added pyparsing_py3.py module, so that Python 3 users can use - pyparsing by changing their pyparsing import statement to: - - import pyparsing_py3 - - Thanks for help from Patrick Laban and his friend Geremy - Condra on the pyparsing wiki. - -- Removed __slots__ declaration on ParseBaseException, for - compatibility with IronPython 2.0.1. Raised by David - Lawler on the pyparsing wiki, thanks David! - -- Fixed bug in SkipTo/failOn handling - caught by eagle eye - cpennington on the pyparsing wiki! - -- Fixed second bug in SkipTo when using the ignore constructor - argument, reported by Catherine Devlin, thanks! - -- Fixed obscure bug reported by Eike Welk when using a class - as a ParseAction with an errant __getitem__ method. - -- Simplified exception stack traces when reporting parse - exceptions back to caller of parseString or parseFile - thanks - to a tip from Peter Otten on comp.lang.python. - -- Changed behavior of scanString to avoid infinitely looping on - expressions that match zero-length strings. Prompted by a - question posted by ellisonbg on the wiki. - -- Enhanced classes that take a list of expressions (And, Or, - MatchFirst, and Each) to accept generator expressions also. - This can be useful when generating lists of alternative - expressions, as in this case, where the user wanted to match - any repetitions of '+', '*', '#', or '.', but not mixtures - of them (that is, match '+++', but not '+-+'): - - codes = "+*#." - format = MatchFirst(Word(c) for c in codes) - - Based on a problem posed by Denis Spir on the Python tutor - list. - -- Added new example eval_arith.py, which extends the example - simpleArith.py to actually evaluate the parsed expressions. - - -Version 1.5.1 - October, 2008 -------------------------------- -- Added new helper method originalTextFor, to replace the use of - the current keepOriginalText parse action. Now instead of - using the parse action, as in: - - fullName = Word(alphas) + Word(alphas) - fullName.setParseAction(keepOriginalText) - - (in this example, we used keepOriginalText to restore any white - space that may have been skipped between the first and last - names) - You can now write: - - fullName = originalTextFor(Word(alphas) + Word(alphas)) - - The implementation of originalTextFor is simpler and faster than - keepOriginalText, and does not depend on using the inspect or - imp modules. - -- Added optional parseAll argument to parseFile, to be consistent - with parseAll argument to parseString. Posted by pboucher on the - pyparsing wiki, thanks! - -- Added failOn argument to SkipTo, so that grammars can define - literal strings or pyparsing expressions which, if found in the - skipped text, will cause SkipTo to fail. Useful to prevent - SkipTo from reading past terminating expression. Instigated by - question posed by Aki Niimura on the pyparsing wiki. - -- Fixed bug in nestedExpr if multi-character expressions are given - for nesting delimiters. Patch provided by new pyparsing user, - Hans-Martin Gaudecker - thanks, H-M! - -- Removed dependency on xml.sax.saxutils.escape, and included - internal implementation instead - proposed by Mike Droettboom on - the pyparsing mailing list, thanks Mike! Also fixed erroneous - mapping in replaceHTMLEntity of " to ', now correctly maps - to ". (Also added support for mapping ' to '.) - -- Fixed typo in ParseResults.insert, found by Alejandro Dubrovsky, - good catch! - -- Added __dir__() methods to ParseBaseException and ParseResults, - to support new dir() behavior in Py2.6 and Py3.0. If dir() is - called on a ParseResults object, the returned list will include - the base set of attribute names, plus any results names that are - defined. - -- Fixed bug in ParseResults.asXML(), in which the first named - item within a ParseResults gets reported with an tag - instead of with the correct results name. - -- Fixed bug in '-' error stop, when '-' operator is used inside a - Combine expression. - -- Reverted generator expression to use list comprehension, for - better compatibility with old versions of Python. Reported by - jester/artixdesign on the SourceForge pyparsing discussion list. - -- Fixed bug in parseString(parseAll=True), when the input string - ends with a comment or whitespace. - -- Fixed bug in LineStart and LineEnd that did not recognize any - special whitespace chars defined using ParserElement.setDefault- - WhitespaceChars, found while debugging an issue for Marek Kubica, - thanks for the new test case, Marek! - -- Made Forward class more tolerant of subclassing. - - -Version 1.5.0 - June, 2008 --------------------------- -This version of pyparsing includes work on two long-standing -FAQ's: support for forcing parsing of the complete input string -(without having to explicitly append StringEnd() to the grammar), -and a method to improve the mechanism of detecting where syntax -errors occur in an input string with various optional and -alternative paths. This release also includes a helper method -to simplify definition of indentation-based grammars. With -these changes (and the past few minor updates), I thought it was -finally time to bump the minor rev number on pyparsing - so -1.5.0 is now available! Read on... - -- AT LAST!!! You can now call parseString and have it raise - an exception if the expression does not parse the entire - input string. This has been an FAQ for a LONG time. - - The parseString method now includes an optional parseAll - argument (default=False). If parseAll is set to True, then - the given parse expression must parse the entire input - string. (This is equivalent to adding StringEnd() to the - end of the expression.) The default value is False to - retain backward compatibility. - - Inspired by MANY requests over the years, most recently by - ecir-hana on the pyparsing wiki! - -- Added new operator '-' for composing grammar sequences. '-' - behaves just like '+' in creating And expressions, but '-' - is used to mark grammar structures that should stop parsing - immediately and report a syntax error, rather than just - backtracking to the last successful parse and trying another - alternative. For instance, running the following code: - - port_definition = Keyword("port") + '=' + Word(nums) - entity_definition = Keyword("entity") + "{" + - Optional(port_definition) + "}" - - entity_definition.parseString("entity { port 100 }") - - pyparsing fails to detect the missing '=' in the port definition. - But, since this expression is optional, pyparsing then proceeds - to try to match the closing '}' of the entity_definition. Not - finding it, pyparsing reports that there was no '}' after the '{' - character. Instead, we would like pyparsing to parse the 'port' - keyword, and if not followed by an equals sign and an integer, - to signal this as a syntax error. - - This can now be done simply by changing the port_definition to: - - port_definition = Keyword("port") - '=' + Word(nums) - - Now after successfully parsing 'port', pyparsing must also find - an equals sign and an integer, or it will raise a fatal syntax - exception. - - By judicious insertion of '-' operators, a pyparsing developer - can have their grammar report much more informative syntax error - messages. - - Patches and suggestions proposed by several contributors on - the pyparsing mailing list and wiki - special thanks to - Eike Welk and Thomas/Poldy on the pyparsing wiki! - -- Added indentedBlock helper method, to encapsulate the parse - actions and indentation stack management needed to keep track of - indentation levels. Use indentedBlock to define grammars for - indentation-based grouping grammars, like Python's. - - indentedBlock takes up to 3 parameters: - - blockStatementExpr - expression defining syntax of statement - that is repeated within the indented block - - indentStack - list created by caller to manage indentation - stack (multiple indentedBlock expressions - within a single grammar should share a common indentStack) - - indent - boolean indicating whether block must be indented - beyond the the current level; set to False for block of - left-most statements (default=True) - - A valid block must contain at least one indented statement. - -- Fixed bug in nestedExpr in which ignored expressions needed - to be set off with whitespace. Reported by Stefaan Himpe, - nice catch! - -- Expanded multiplication of an expression by a tuple, to - accept tuple values of None: - . expr*(n,None) or expr*(n,) is equivalent - to expr*n + ZeroOrMore(expr) - (read as "at least n instances of expr") - . expr*(None,n) is equivalent to expr*(0,n) - (read as "0 to n instances of expr") - . expr*(None,None) is equivalent to ZeroOrMore(expr) - . expr*(1,None) is equivalent to OneOrMore(expr) - - Note that expr*(None,n) does not raise an exception if - more than n exprs exist in the input stream; that is, - expr*(None,n) does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - expr*(None,n) + ~expr - -- Added None as a possible operator for operatorPrecedence. - None signifies "no operator", as in multiplying m times x - in "y=mx+b". - -- Fixed bug in Each, reported by Michael Ramirez, in which the - order of terms in the Each affected the parsing of the results. - Problem was due to premature grouping of the expressions in - the overall Each during grammar construction, before the - complete Each was defined. Thanks, Michael! - -- Also fixed bug in Each in which Optional's with default values - were not getting the defaults added to the results of the - overall Each expression. - -- Fixed a bug in Optional in which results names were not - assigned if a default value was supplied. - -- Cleaned up Py3K compatibility statements, including exception - construction statements, and better equivalence between _ustr - and basestring, and __nonzero__ and __bool__. - - -Version 1.4.11 - February, 2008 -------------------------------- -- With help from Robert A. Clark, this version of pyparsing - is compatible with Python 3.0a3. Thanks for the help, - Robert! - -- Added WordStart and WordEnd positional classes, to support - expressions that must occur at the start or end of a word. - Proposed by piranha on the pyparsing wiki, good idea! - -- Added matchOnlyAtCol helper parser action, to simplify - parsing log or data files that have optional fields that are - column dependent. Inspired by a discussion thread with - hubritic on comp.lang.python. - -- Added withAttribute.ANY_VALUE as a match-all value when using - withAttribute. Used to ensure that an attribute is present, - without having to match on the actual attribute value. - -- Added get() method to ParseResults, similar to dict.get(). - Suggested by new pyparsing user, Alejandro Dubrovksy, thanks! - -- Added '==' short-cut to see if a given string matches a - pyparsing expression. For instance, you can now write: - - integer = Word(nums) - if "123" == integer: - # do something - - print [ x for x in "123 234 asld".split() if x==integer ] - # prints ['123', '234'] - -- Simplified the use of nestedExpr when using an expression for - the opening or closing delimiters. Now the content expression - will not have to explicitly negate closing delimiters. Found - while working with dfinnie on GHOP Task #277, thanks! - -- Fixed bug when defining ignorable expressions that are - later enclosed in a wrapper expression (such as ZeroOrMore, - OneOrMore, etc.) - found while working with Prabhu - Gurumurthy, thanks Prahbu! - -- Fixed bug in withAttribute in which keys were automatically - converted to lowercase, making it impossible to match XML - attributes with uppercase characters in them. Using with- - Attribute requires that you reference attributes in all - lowercase if parsing HTML, and in correct case when parsing - XML. - -- Changed '<<' operator on Forward to return None, since this - is really used as a pseudo-assignment operator, not as a - left-shift operator. By returning None, it is easier to - catch faulty statements such as a << b | c, where precedence - of operations causes the '|' operation to be performed - *after* inserting b into a, so no alternation is actually - implemented. The correct form is a << (b | c). With this - change, an error will be reported instead of silently - clipping the alternative term. (Note: this may break some - existing code, but if it does, the code had a silent bug in - it anyway.) Proposed by wcbarksdale on the pyparsing wiki, - thanks! - -- Several unit tests were added to pyparsing's regression - suite, courtesy of the Google Highly-Open Participation - Contest. Thanks to all who administered and took part in - this event! - - -Version 1.4.10 - December 9, 2007 ---------------------------------- -- Fixed bug introduced in v1.4.8, parse actions were called for - intermediate operator levels, not just the deepest matching - operation level. Again, big thanks to Torsten Marek for - helping isolate this problem! - - -Version 1.4.9 - December 8, 2007 --------------------------------- -- Added '*' multiplication operator support when creating - grammars, accepting either an integer, or a two-integer - tuple multiplier, as in: - ipAddress = Word(nums) + ('.'+Word(nums))*3 - usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2) - If multiplying by a tuple, the two integer values represent - min and max multiples. Suggested by Vincent of eToy.com, - great idea, Vincent! - -- Fixed bug in nestedExpr, original version was overly greedy! - Thanks to Michael Ramirez for raising this issue. - -- Fixed internal bug in ParseResults - when an item was deleted, - the key indices were not updated. Thanks to Tim Mitchell for - posting a bugfix patch to the SF bug tracking system! - -- Fixed internal bug in operatorPrecedence - when the results of - a right-associative term were sent to a parse action, the wrong - tokens were sent. Reported by Torsten Marek, nice job! - -- Added pop() method to ParseResults. If pop is called with an - integer or with no arguments, it will use list semantics and - update the ParseResults' list of tokens. If pop is called with - a non-integer (a string, for instance), then it will use dict - semantics and update the ParseResults' internal dict. - Suggested by Donn Ingle, thanks Donn! - -- Fixed quoted string built-ins to accept '\xHH' hex characters - within the string. - - -Version 1.4.8 - October, 2007 ------------------------------ -- Added new helper method nestedExpr to easily create expressions - that parse lists of data in nested parentheses, braces, brackets, - etc. - -- Added withAttribute parse action helper, to simplify creating - filtering parse actions to attach to expressions returned by - makeHTMLTags and makeXMLTags. Use withAttribute to qualify a - starting tag with one or more required attribute values, to avoid - false matches on common tags such as or
. - -- Added new examples nested.py and withAttribute.py to demonstrate - the new features. - -- Added performance speedup to grammars using operatorPrecedence, - instigated by Stefan Reichör - thanks for the feedback, Stefan! - -- Fixed bug/typo when deleting an element from a ParseResults by - using the element's results name. - -- Fixed whitespace-skipping bug in wrapper classes (such as Group, - Suppress, Combine, etc.) and when using setDebug(), reported by - new pyparsing user dazzawazza on SourceForge, nice job! - -- Added restriction to prevent defining Word or CharsNotIn expressions - with minimum length of 0 (should use Optional if this is desired), - and enhanced docstrings to reflect this limitation. Issue was - raised by Joey Tallieu, who submitted a patch with a slightly - different solution. Thanks for taking the initiative, Joey, and - please keep submitting your ideas! - -- Fixed bug in makeHTMLTags that did not detect HTML tag attributes - with no '= value' portion (such as ""), reported by - hamidh on the pyparsing wiki - thanks! - -- Fixed minor bug in makeHTMLTags and makeXMLTags, which did not - accept whitespace in closing tags. - - -Version 1.4.7 - July, 2007 --------------------------- -- NEW NOTATION SHORTCUT: ParserElement now accepts results names using - a notational shortcut, following the expression with the results name - in parentheses. So this: - - stats = "AVE:" + realNum.setResultsName("average") + \ - "MIN:" + realNum.setResultsName("min") + \ - "MAX:" + realNum.setResultsName("max") - - can now be written as this: - - stats = "AVE:" + realNum("average") + \ - "MIN:" + realNum("min") + \ - "MAX:" + realNum("max") - - The intent behind this change is to make it simpler to define results - names for significant fields within the expression, while keeping - the grammar syntax clean and uncluttered. - -- Fixed bug when packrat parsing is enabled, with cached ParseResults - being updated by subsequent parsing. Reported on the pyparsing - wiki by Kambiz, thanks! - -- Fixed bug in operatorPrecedence for unary operators with left - associativity, if multiple operators were given for the same term. - -- Fixed bug in example simpleBool.py, corrected precedence of "and" vs. - "or" operations. - -- Fixed bug in Dict class, in which keys were converted to strings - whether they needed to be or not. Have narrowed this logic to - convert keys to strings only if the keys are ints (which would - confuse __getitem__ behavior for list indexing vs. key lookup). - -- Added ParserElement method setBreak(), which will invoke the pdb - module's set_trace() function when this expression is about to be - parsed. - -- Fixed bug in StringEnd in which reading off the end of the input - string raises an exception - should match. Resolved while - answering a question for Shawn on the pyparsing wiki. - - -Version 1.4.6 - April, 2007 ---------------------------- -- Simplified constructor for ParseFatalException, to support common - exception construction idiom: - raise ParseFatalException, "unexpected text: 'Spanish Inquisition'" - -- Added method getTokensEndLoc(), to be called from within a parse action, - for those parse actions that need both the starting *and* ending - location of the parsed tokens within the input text. - -- Enhanced behavior of keepOriginalText so that named parse fields are - preserved, even though tokens are replaced with the original input - text matched by the current expression. Also, cleaned up the stack - traversal to be more robust. Suggested by Tim Arnold - thanks, Tim! - -- Fixed subtle bug in which countedArray (and similar dynamic - expressions configured in parse actions) failed to match within Or, - Each, FollowedBy, or NotAny. Reported by Ralf Vosseler, thanks for - your patience, Ralf! - -- Fixed Unicode bug in upcaseTokens and downcaseTokens parse actions, - scanString, and default debugging actions; reported (and patch submitted) - by Nikolai Zamkovoi, spasibo! - -- Fixed bug when saving a tuple as a named result. The returned - token list gave the proper tuple value, but accessing the result by - name only gave the first element of the tuple. Reported by - Poromenos, nice catch! - -- Fixed bug in makeHTMLTags/makeXMLTags, which failed to match tag - attributes with namespaces. - -- Fixed bug in SkipTo when setting include=True, to have the skipped-to - tokens correctly included in the returned data. Reported by gunars on - the pyparsing wiki, thanks! - -- Fixed typobug in OnceOnly.reset method, omitted self argument. - Submitted by eike welk, thanks for the lint-picking! - -- Added performance enhancement to Forward class, suggested by - akkartik on the pyparsing Wiki discussion, nice work! - -- Added optional asKeyword to Word constructor, to indicate that the - given word pattern should be matched only as a keyword, that is, it - should only match if it is within word boundaries. - -- Added S-expression parser to examples directory. - -- Added macro substitution example to examples directory. - -- Added holaMundo.py example, excerpted from Marco Alfonso's blog - - muchas gracias, Marco! - -- Modified internal cyclic references in ParseResults to use weakrefs; - this should help reduce the memory footprint of large parsing - programs, at some cost to performance (3-5%). Suggested by bca48150 on - the pyparsing wiki, thanks! - -- Enhanced the documentation describing the vagaries and idiosyncracies - of parsing strings with embedded tabs, and the impact on: - . parse actions - . scanString - . col and line helper functions - (Suggested by eike welk in response to some unexplained inconsistencies - between parsed location and offsets in the input string.) - -- Cleaned up internal decorators to preserve function names, - docstrings, etc. - - -Version 1.4.5 - December, 2006 ------------------------------- -- Removed debugging print statement from QuotedString class. Sorry - for not stripping this out before the 1.4.4 release! - -- A significant performance improvement, the first one in a while! - For my Verilog parser, this version of pyparsing is about double the - speed - YMMV. - -- Added support for pickling of ParseResults objects. (Reported by - Jeff Poole, thanks Jeff!) - -- Fixed minor bug in makeHTMLTags that did not recognize tag attributes - with embedded '-' or '_' characters. Also, added support for - passing expressions to makeHTMLTags and makeXMLTags, and used this - feature to define the globals anyOpenTag and anyCloseTag. - -- Fixed error in alphas8bit, I had omitted the y-with-umlaut character. - -- Added punc8bit string to complement alphas8bit - it contains all the - non-alphabetic, non-blank 8-bit characters. - -- Added commonHTMLEntity expression, to match common HTML "ampersand" - codes, such as "<", ">", "&", " ", and """. This - expression also defines a results name 'entity', which can be used - to extract the entity field (that is, "lt", "gt", etc.). Also added - built-in parse action replaceHTMLEntity, which can be attached to - commonHTMLEntity to translate "<", ">", "&", " ", and - """ to "<", ">", "&", " ", and "'". - -- Added example, htmlStripper.py, that strips HTML tags and scripts - from HTML pages. It also translates common HTML entities to their - respective characters. - - -Version 1.4.4 - October, 2006 -------------------------------- -- Fixed traceParseAction decorator to also trap and record exception - returns from parse actions, and to handle parse actions with 0, - 1, 2, or 3 arguments. - -- Enhanced parse action normalization to support using classes as - parse actions; that is, the class constructor is called at parse - time and the __init__ function is called with 0, 1, 2, or 3 - arguments. If passing a class as a parse action, the __init__ - method must use one of the valid parse action parameter list - formats. (This technique is useful when using pyparsing to compile - parsed text into a series of application objects - see the new - example simpleBool.py.) - -- Fixed bug in ParseResults when setting an item using an integer - index. (Reported by Christopher Lambacher, thanks!) - -- Fixed whitespace-skipping bug, patch submitted by Paolo Losi - - grazie, Paolo! - -- Fixed bug when a Combine contained an embedded Forward expression, - reported by cie on the pyparsing wiki - good catch! - -- Fixed listAllMatches bug, when a listAllMatches result was - nested within another result. (Reported by don pasquale on - comp.lang.python, well done!) - -- Fixed bug in ParseResults items() method, when returning an item - marked as listAllMatches=True - -- Fixed bug in definition of cppStyleComment (and javaStyleComment) - in which '//' line comments were not continued to the next line - if the line ends with a '\'. (Reported by eagle-eyed Ralph - Corderoy!) - -- Optimized re's for cppStyleComment and quotedString for better - re performance - also provided by Ralph Corderoy, thanks! - -- Added new example, indentedGrammarExample.py, showing how to - define a grammar using indentation to show grouping (as Python - does for defining statement nesting). Instigated by an e-mail - discussion with Andrew Dalke, thanks Andrew! - -- Added new helper operatorPrecedence (based on e-mail list discussion - with Ralph Corderoy and Paolo Losi), to facilitate definition of - grammars for expressions with unary and binary operators. For - instance, this grammar defines a 6-function arithmetic expression - grammar, with unary plus and minus, proper operator precedence,and - right- and left-associativity: - - expr = operatorPrecedence( operand, - [("!", 1, opAssoc.LEFT), - ("^", 2, opAssoc.RIGHT), - (oneOf("+ -"), 1, opAssoc.RIGHT), - (oneOf("* /"), 2, opAssoc.LEFT), - (oneOf("+ -"), 2, opAssoc.LEFT),] - ) - - Also added example simpleArith.py and simpleBool.py to provide - more detailed code samples using this new helper method. - -- Added new helpers matchPreviousLiteral and matchPreviousExpr, for - creating adaptive parsing expressions that match the same content - as was parsed in a previous parse expression. For instance: - - first = Word(nums) - matchExpr = first + ":" + matchPreviousLiteral(first) - - will match "1:1", but not "1:2". Since this matches at the literal - level, this will also match the leading "1:1" in "1:10". - - In contrast: - - first = Word(nums) - matchExpr = first + ":" + matchPreviousExpr(first) - - will *not* match the leading "1:1" in "1:10"; the expressions are - evaluated first, and then compared, so "1" is compared with "10". - -- Added keepOriginalText parse action. Sometimes pyparsing's - whitespace-skipping leaves out too much whitespace. Adding this - parse action will restore any internal whitespace for a parse - expression. This is especially useful when defining expressions - for scanString or transformString applications. - -- Added __add__ method for ParseResults class, to better support - using Python sum built-in for summing ParseResults objects returned - from scanString. - -- Added reset method for the new OnlyOnce class wrapper for parse - actions (to allow a grammar to be used multiple times). - -- Added optional maxMatches argument to scanString and searchString, - to short-circuit scanning after 'n' expression matches are found. - - -Version 1.4.3 - July, 2006 ------------------------------- -- Fixed implementation of multiple parse actions for an expression - (added in 1.4.2). - . setParseAction() reverts to its previous behavior, setting - one (or more) actions for an expression, overwriting any - action or actions previously defined - . new method addParseAction() appends one or more parse actions - to the list of parse actions attached to an expression - Now it is harder to accidentally append parse actions to an - expression, when what you wanted to do was overwrite whatever had - been defined before. (Thanks, Jean-Paul Calderone!) - -- Simplified interface to parse actions that do not require all 3 - parse action arguments. Very rarely do parse actions require more - than just the parsed tokens, yet parse actions still require all - 3 arguments including the string being parsed and the location - within the string where the parse expression was matched. With this - release, parse actions may now be defined to be called as: - . fn(string,locn,tokens) (the current form) - . fn(locn,tokens) - . fn(tokens) - . fn() - The setParseAction and addParseAction methods will internally decorate - the provided parse actions with compatible wrappers to conform to - the full (string,locn,tokens) argument sequence. - -- REMOVED SUPPORT FOR RETURNING PARSE LOCATION FROM A PARSE ACTION. - I announced this in March, 2004, and gave a final warning in the last - release. Now you can return a tuple from a parse action, and it will - be treated like any other return value (i.e., the tuple will be - substituted for the incoming tokens passed to the parse action, - which is useful when trying to parse strings into tuples). - -- Added setFailAction method, taking a callable function fn that - takes the arguments fn(s,loc,expr,err) where: - . s - string being parsed - . loc - location where expression match was attempted and failed - . expr - the parse expression that failed - . err - the exception thrown - The function returns no values. It may throw ParseFatalException - if it is desired to stop parsing immediately. - (Suggested by peter21081944 on wikispaces.com) - -- Added class OnlyOnce as helper wrapper for parse actions. OnlyOnce - only permits a parse action to be called one time, after which - all subsequent calls throw a ParseException. - -- Added traceParseAction decorator to help debug parse actions. - Simply insert "@traceParseAction" ahead of the definition of your - parse action, and each invocation will be displayed, along with - incoming arguments, and returned value. - -- Fixed bug when copying ParserElements using copy() or - setResultsName(). (Reported by Dan Thill, great catch!) - -- Fixed bug in asXML() where token text contains <, >, and & - characters - generated XML now escapes these as <, > and - &. (Reported by Jacek Sieka, thanks!) - -- Fixed bug in SkipTo() when searching for a StringEnd(). (Reported - by Pete McEvoy, thanks Pete!) - -- Fixed "except Exception" statements, the most critical added as part - of the packrat parsing enhancement. (Thanks, Erick Tryzelaar!) - -- Fixed end-of-string infinite looping on LineEnd and StringEnd - expressions. (Thanks again to Erick Tryzelaar.) - -- Modified setWhitespaceChars to return self, to be consistent with - other ParserElement modifiers. (Suggested by Erick Tryzelaar.) - -- Fixed bug/typo in new ParseResults.dump() method. - -- Fixed bug in searchString() method, in which only the first token of - an expression was returned. searchString() now returns a - ParseResults collection of all search matches. - -- Added example program removeLineBreaks.py, a string transformer that - converts text files with hard line-breaks into one with line breaks - only between paragraphs. - -- Added example program listAllMatches.py, to illustrate using the - listAllMatches option when specifying results names (also shows new - support for passing lists to oneOf). - -- Added example program linenoExample.py, to illustrate using the - helper methods lineno, line, and col, and returning objects from a - parse action. - -- Added example program parseListString.py, to which can parse the - string representation of a Python list back into a true list. Taken - mostly from my PyCon presentation examples, but now with support - for tuple elements, too! - - - -Version 1.4.2 - April 1, 2006 (No foolin'!) -------------------------------------------- -- Significant speedup from memoizing nested expressions (a technique - known as "packrat parsing"), thanks to Chris Lesniewski-Laas! Your - mileage may vary, but my Verilog parser almost doubled in speed to - over 600 lines/sec! - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method ParserElement.enablePackrat(). If - your program uses psyco to "compile as you go", you must call - enablePackrat before calling psyco.full(). If you do not do this, - Python will crash. For best results, call enablePackrat() immediately - after importing pyparsing. - -- Added new helper method countedArray(expr), for defining patterns that - start with a leading integer to indicate the number of array elements, - followed by that many elements, matching the given expr parse - expression. For instance, this two-liner: - wordArray = countedArray(Word(alphas)) - print wordArray.parseString("3 Practicality beats purity")[0] - returns the parsed array of words: - ['Practicality', 'beats', 'purity'] - The leading token '3' is suppressed, although it is easily obtained - from the length of the returned array. - (Inspired by e-mail discussion with Ralf Vosseler.) - -- Added support for attaching multiple parse actions to a single - ParserElement. (Suggested by Dan "Dang" Griffith - nice idea, Dan!) - -- Added support for asymmetric quoting characters in the recently-added - QuotedString class. Now you can define your own quoted string syntax - like "<>". To define - this custom form of QuotedString, your code would define: - dblAngleQuotedString = QuotedString('<<',endQuoteChar='>>') - QuotedString also supports escaped quotes, escape character other - than '\', and multiline. - -- Changed the default value returned internally by Optional, so that - None can be used as a default value. (Suggested by Steven Bethard - - I finally saw the light!) - -- Added dump() method to ParseResults, to make it easier to list out - and diagnose values returned from calling parseString. - -- A new example, a search query string parser, submitted by Steven - Mooij and Rudolph Froger - a very interesting application, thanks! - -- Added an example that parses the BNF in Python's Grammar file, in - support of generating Python grammar documentation. (Suggested by - J H Stovall.) - -- A new example, submitted by Tim Cera, of a flexible parser module, - using a simple config variable to adjust parsing for input formats - that have slight variations - thanks, Tim! - -- Added an example for parsing Roman numerals, showing the capability - of parse actions to "compile" Roman numerals into their integer - values during parsing. - -- Added a new docs directory, for additional documentation or help. - Currently, this includes the text and examples from my recent - presentation at PyCon. - -- Fixed another typo in CaselessKeyword, thanks Stefan Behnel. - -- Expanded oneOf to also accept tuples, not just lists. This really - should be sufficient... - -- Added deprecation warnings when tuple is returned from a parse action. - Looking back, I see that I originally deprecated this feature in March, - 2004, so I'm guessing people really shouldn't have been using this - feature - I'll drop it altogether in the next release, which will - allow users to return a tuple from a parse action (which is really - handy when trying to reconstuct tuples from a tuple string - representation!). - - -Version 1.4.1 - February, 2006 ------------------------------- -- Converted generator expression in QuotedString class to list - comprehension, to retain compatibility with Python 2.3. (Thanks, Titus - Brown for the heads-up!) - -- Added searchString() method to ParserElement, as an alternative to - using "scanString(instring).next()[0][0]" to search through a string - looking for a substring matching a given parse expression. (Inspired by - e-mail conversation with Dave Feustel.) - -- Modified oneOf to accept lists of strings as well as a single string - of space-delimited literals. (Suggested by Jacek Sieka - thanks!) - -- Removed deprecated use of Upcase in pyparsing test code. (Also caught by - Titus Brown.) - -- Removed lstrip() call from Literal - too aggressive in stripping - whitespace which may be valid for some grammars. (Point raised by Jacek - Sieka). Also, made Literal more robust in the event of passing an empty - string. - -- Fixed bug in replaceWith when returning None. - -- Added cautionary documentation for Forward class when assigning a - MatchFirst expression, as in: - fwdExpr << a | b | c - Precedence of operators causes this to be evaluated as: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. Users must - explicitly group the values inserted into the Forward: - fwdExpr << (a | b | c) - (Suggested by Scot Wilcoxon - thanks, Scot!) - - -Version 1.4 - January 18, 2006 ------------------------------- -- Added Regex class, to permit definition of complex embedded expressions - using regular expressions. (Enhancement provided by John Beisley, great - job!) - -- Converted implementations of Word, oneOf, quoted string, and comment - helpers to utilize regular expression matching. Performance improvements - in the 20-40% range. - -- Added QuotedString class, to support definition of non-standard quoted - strings (Suggested by Guillaume Proulx, thanks!) - -- Added CaselessKeyword class, to streamline grammars with, well, caseless - keywords (Proposed by Stefan Behnel, thanks!) - -- Fixed bug in SkipTo, when using an ignoreable expression. (Patch provided - by Anonymous, thanks, whoever-you-are!) - -- Fixed typo in NoMatch class. (Good catch, Stefan Behnel!) - -- Fixed minor bug in _makeTags(), using string.printables instead of - pyparsing.printables. - -- Cleaned up some of the expressions created by makeXXXTags helpers, to - suppress extraneous <> characters. - -- Added some grammar definition-time checking to verify that a grammar is - being built using proper ParserElements. - -- Added examples: - . LAparser.py - linear algebra C preprocessor (submitted by Mike Ellis, - thanks Mike!) - . wordsToNum.py - converts word description of a number back to - the original number (such as 'one hundred and twenty three' -> 123) - . updated fourFn.py to support unary minus, added BNF comments - - -Version 1.3.3 - September 12, 2005 ----------------------------------- -- Improved support for Unicode strings that would be returned using - srange. Added greetingInKorean.py example, for a Korean version of - "Hello, World!" using Unicode. (Thanks, June Kim!) - -- Added 'hexnums' string constant (nums+"ABCDEFabcdef") for defining - hexadecimal value expressions. - -- NOTE: ===THIS CHANGE MAY BREAK EXISTING CODE=== - Modified tag and results definitions returned by makeHTMLTags(), - to better support the looseness of HTML parsing. Tags to be - parsed are now caseless, and keys generated for tag attributes are - now converted to lower case. - - Formerly, makeXMLTags("XYZ") would return a tag with results - name of "startXYZ", this has been changed to "startXyz". If this - tag is matched against '', the - matched keys formerly would be "Abc", "DEF", and "ghi"; keys are - now converted to lower case, giving keys of "abc", "def", and - "ghi". These changes were made to try to address the lax - case sensitivity agreement between start and end tags in many - HTML pages. - - No changes were made to makeXMLTags(), which assumes more rigorous - parsing rules. - - Also, cleaned up case-sensitivity bugs in closing tags, and - switched to using Keyword instead of Literal class for tags. - (Thanks, Steve Young, for getting me to look at these in more - detail!) - -- Added two helper parse actions, upcaseTokens and downcaseTokens, - which will convert matched text to all uppercase or lowercase, - respectively. - -- Deprecated Upcase class, to be replaced by upcaseTokens parse - action. - -- Converted messages sent to stderr to use warnings module, such as - when constructing a Literal with an empty string, one should use - the Empty() class or the empty helper instead. - -- Added ' ' (space) as an escapable character within a quoted - string. - -- Added helper expressions for common comment types, in addition - to the existing cStyleComment (/*...*/) and htmlStyleComment - () - . dblSlashComment = // ... (to end of line) - . cppStyleComment = cStyleComment or dblSlashComment - . javaStyleComment = cppStyleComment - . pythonStyleComment = # ... (to end of line) - - - -Version 1.3.2 - July 24, 2005 ------------------------------ -- Added Each class as an enhanced version of And. 'Each' requires - that all given expressions be present, but may occur in any order. - Special handling is provided to group ZeroOrMore and OneOrMore - elements that occur out-of-order in the input string. You can also - construct 'Each' objects by joining expressions with the '&' - operator. When using the Each class, results names are strongly - recommended for accessing the matched tokens. (Suggested by Pradam - Amini - thanks, Pradam!) - -- Stricter interpretation of 'max' qualifier on Word elements. If the - 'max' attribute is specified, matching will fail if an input field - contains more than 'max' consecutive body characters. For example, - previously, Word(nums,max=3) would match the first three characters - of '0123456', returning '012' and continuing parsing at '3'. Now, - when constructed using the max attribute, Word will raise an - exception with this string. - -- Cleaner handling of nested dictionaries returned by Dict. No - longer necessary to dereference sub-dictionaries as element [0] of - their parents. - === NOTE: THIS CHANGE MAY BREAK SOME EXISTING CODE, BUT ONLY IF - PARSING NESTED DICTIONARIES USING THE LITTLE-USED DICT CLASS === - (Prompted by discussion thread on the Python Tutor list, with - contributions from Danny Yoo, Kent Johnson, and original post by - Liam Clarke - thanks all!) - - - -Version 1.3.1 - June, 2005 ----------------------------------- -- Added markInputline() method to ParseException, to display the input - text line location of the parsing exception. (Thanks, Stefan Behnel!) - -- Added setDefaultKeywordChars(), so that Keyword definitions using a - custom keyword character set do not all need to add the keywordChars - constructor argument (similar to setDefaultWhitespaceChars()). - (suggested by rzhanka on the SourceForge pyparsing forum.) - -- Simplified passing debug actions to setDebugAction(). You can now - pass 'None' for a debug action if you want to take the default - debug behavior. To suppress a particular debug action, you can pass - the pyparsing method nullDebugAction. - -- Refactored parse exception classes, moved all behavior to - ParseBaseException, and the former ParseException is now a subclass of - ParseBaseException. Added a second subclass, ParseFatalException, as - a subclass of ParseBaseException. User-defined parse actions can raise - ParseFatalException if a data inconsistency is detected (such as a - begin-tag/end-tag mismatch), and this will stop all parsing immediately. - (Inspired by e-mail thread with Michele Petrazzo - thanks, Michelle!) - -- Added helper methods makeXMLTags and makeHTMLTags, that simplify the - definition of XML or HTML tag parse expressions for a given tagname. - Both functions return a pair of parse expressions, one for the opening - tag (that is, '') and one for the closing tag (''). - The opening tagame also recognizes any attribute definitions that have - been included in the opening tag, as well as an empty tag (one with a - trailing '/', as in '' which is equivalent to ''). - makeXMLTags uses stricter XML syntax for attributes, requiring that they - be enclosed in double quote characters - makeHTMLTags is more lenient, - and accepts single-quoted strings or any contiguous string of characters - up to the next whitespace character or '>' character. Attributes can - be retrieved as dictionary or attribute values of the returned results - from the opening tag. - -- Added example minimath2.py, a refinement on fourFn.py that adds - an interactive session and support for variables. (Thanks, Steven Siew!) - -- Added performance improvement, up to 20% reduction! (Found while working - with Wolfgang Borgert on performance tuning of his TTCN3 parser.) - -- And another performance improvement, up to 25%, when using scanString! - (Found while working with Henrik Westlund on his C header file scanner.) - -- Updated UML diagrams to reflect latest class/method changes. - - -Version 1.3 - March, 2005 ----------------------------------- -- Added new Keyword class, as a special form of Literal. Keywords - must be followed by whitespace or other non-keyword characters, to - distinguish them from variables or other identifiers that just - happen to start with the same characters as a keyword. For instance, - the input string containing "ifOnlyIfOnly" will match a Literal("if") - at the beginning and in the middle, but will fail to match a - Keyword("if"). Keyword("if") will match only strings such as "if only" - or "if(only)". (Proposed by Wolfgang Borgert, and Berteun Damman - separately requested this on comp.lang.python - great idea!) - -- Added setWhitespaceChars() method to override the characters to be - skipped as whitespace before matching a particular ParseElement. Also - added the class-level method setDefaultWhitespaceChars(), to allow - users to override the default set of whitespace characters (space, - tab, newline, and return) for all subsequently defined ParseElements. - (Inspired by Klaas Hofstra's inquiry on the Sourceforge pyparsing - forum.) - -- Added helper parse actions to support some very common parse - action use cases: - . replaceWith(replStr) - replaces the matching tokens with the - provided replStr replacement string; especially useful with - transformString() - . removeQuotes - removes first and last character from string enclosed - in quotes (note - NOT the same as the string strip() method, as only - a single character is removed at each end) - -- Added copy() method to ParseElement, to make it easier to define - different parse actions for the same basic parse expression. (Note, copy - is implicitly called when using setResultsName().) - - - (The following changes were posted to CVS as Version 1.2.3 - - October-December, 2004) - -- Added support for Unicode strings in creating grammar definitions. - (Big thanks to Gavin Panella!) - -- Added constant alphas8bit to include the following 8-bit characters: - ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ - -- Added srange() function to simplify definition of Word elements, using - regexp-like '[A-Za-z0-9]' syntax. This also simplifies referencing - common 8-bit characters. - -- Fixed bug in Dict when a single element Dict was embedded within another - Dict. (Thanks Andy Yates for catching this one!) - -- Added 'formatted' argument to ParseResults.asXML(). If set to False, - suppresses insertion of whitespace for pretty-print formatting. Default - equals True for backward compatibility. - -- Added setDebugActions() function to ParserElement, to allow user-defined - debugging actions. - -- Added support for escaped quotes (either in \', \", or doubled quote - form) to the predefined expressions for quoted strings. (Thanks, Ero - Carrera!) - -- Minor performance improvement (~5%) converting "char in string" tests - to "char in dict". (Suggested by Gavin Panella, cool idea!) - - -Version 1.2.2 - September 27, 2004 ----------------------------------- -- Modified delimitedList to accept an expression as the delimiter, instead - of only accepting strings. - -- Modified ParseResults, to convert integer field keys to strings (to - avoid confusion with list access). - -- Modified Combine, to convert all embedded tokens to strings before - combining. - -- Fixed bug in MatchFirst in which parse actions would be called for - expressions that only partially match. (Thanks, John Hunter!) - -- Fixed bug in fourFn.py example that fixes right-associativity of ^ - operator. (Thanks, Andrea Griffini!) - -- Added class FollowedBy(expression), to look ahead in the input string - without consuming tokens. - -- Added class NoMatch that never matches any input. Can be useful in - debugging, and in very specialized grammars. - -- Added example pgn.py, for parsing chess game files stored in Portable - Game Notation. (Thanks, Alberto Santini!) - - -Version 1.2.1 - August 19, 2004 -------------------------------- -- Added SkipTo(expression) token type, simplifying grammars that only - want to specify delimiting expressions, and want to match any characters - between them. - -- Added helper method dictOf(key,value), making it easier to work with - the Dict class. (Inspired by Pavel Volkovitskiy, thanks!). - -- Added optional argument listAllMatches (default=False) to - setResultsName(). Setting listAllMatches to True overrides the default - modal setting of tokens to results names; instead, the results name - acts as an accumulator for all matching tokens within the local - repetition group. (Suggested by Amaury Le Leyzour - thanks!) - -- Fixed bug in ParseResults, throwing exception when trying to extract - slice, or make a copy using [:]. (Thanks, Wilson Fowlie!) - -- Fixed bug in transformString() when the input string contains 's - (Thanks, Rick Walia!). - -- Fixed bug in returning tokens from un-Grouped And's, Or's and - MatchFirst's, where too many tokens would be included in the results, - confounding parse actions and returned results. - -- Fixed bug in naming ParseResults returned by And's, Or's, and Match - First's. - -- Fixed bug in LineEnd() - matching this token now correctly consumes - and returns the end of line "\n". - -- Added a beautiful example for parsing Mozilla calendar files (Thanks, - Petri Savolainen!). - -- Added support for dynamically modifying Forward expressions during - parsing. - - -Version 1.2 - 20 June 2004 --------------------------- -- Added definition for htmlComment to help support HTML scanning and - parsing. - -- Fixed bug in generating XML for Dict classes, in which trailing item was - duplicated in the output XML. - -- Fixed release bug in which scanExamples.py was omitted from release - files. - -- Fixed bug in transformString() when parse actions are not defined on the - outermost parser element. - -- Added example urlExtractor.py, as another example of using scanString - and parse actions. - - -Version 1.2beta3 - 4 June 2004 ------------------------------- -- Added White() token type, analogous to Word, to match on whitespace - characters. Use White in parsers with significant whitespace (such as - configuration file parsers that use indentation to indicate grouping). - Construct White with a string containing the whitespace characters to be - matched. Similar to Word, White also takes optional min, max, and exact - parameters. - -- As part of supporting whitespace-signficant parsing, added parseWithTabs() - method to ParserElement, to override the default behavior in parseString - of automatically expanding tabs to spaces. To retain tabs during - parsing, call parseWithTabs() before calling parseString(), parseFile() or - scanString(). (Thanks, Jean-Guillaume Paradis for catching this, and for - your suggestions on whitespace-significant parsing.) - -- Added transformString() method to ParseElement, as a complement to - scanString(). To use transformString, define a grammar and attach a parse - action to the overall grammar that modifies the returned token list. - Invoking transformString() on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. transformString() returns the resulting transformed string. - (Note: transformString() does *not* automatically expand tabs to spaces.) - Also added scanExamples.py to the examples directory to show sample uses of - scanString() and transformString(). - -- Removed group() method that was introduced in beta2. This turns out NOT to - be equivalent to nesting within a Group() object, and I'd prefer not to sow - more seeds of confusion. - -- Fixed behavior of asXML() where tags for groups were incorrectly duplicated. - (Thanks, Brad Clements!) - -- Changed beta version message to display to stderr instead of stdout, to - make asXML() easier to use. (Thanks again, Brad.) - - -Version 1.2beta2 - 19 May 2004 ------------------------------- -- *** SIMPLIFIED API *** - Parse actions that do not modify the list of tokens - no longer need to return a value. This simplifies those parse actions that - use the list of tokens to update a counter or record or display some of the - token content; these parse actions can simply end without having to specify - 'return toks'. - -- *** POSSIBLE API INCOMPATIBILITY *** - Fixed CaselessLiteral bug, where the - returned token text was not the original string (as stated in the docs), - but the original string converted to upper case. (Thanks, Dang Griffith!) - **NOTE: this may break some code that relied on this erroneous behavior. - Users should scan their code for uses of CaselessLiteral.** - -- *** POSSIBLE CODE INCOMPATIBILITY *** - I have renamed the internal - attributes on ParseResults from 'dict' and 'list' to '__tokdict' and - '__toklist', to avoid collisions with user-defined data fields named 'dict' - and 'list'. Any client code that accesses these attributes directly will - need to be modified. Hopefully the implementation of methods such as keys(), - items(), len(), etc. on ParseResults will make such direct attribute - accessess unnecessary. - -- Added asXML() method to ParseResults. This greatly simplifies the process - of parsing an input data file and generating XML-structured data. - -- Added getName() method to ParseResults. This method is helpful when - a grammar specifies ZeroOrMore or OneOrMore of a MatchFirst or Or - expression, and the parsing code needs to know which expression matched. - (Thanks, Eric van der Vlist, for this idea!) - -- Added items() and values() methods to ParseResults, to better support using - ParseResults as a Dictionary. - -- Added parseFile() as a convenience function to parse the contents of an - entire text file. Accepts either a file name or a file object. (Thanks - again, Dang!) - -- Added group() method to And, Or, and MatchFirst, as a short-cut alternative - to enclosing a construct inside a Group object. - -- Extended fourFn.py to support exponentiation, and simple built-in functions. - -- Added EBNF parser to examples, including a demo where it parses its own - EBNF! (Thanks to Seo Sanghyeon!) - -- Added Delphi Form parser to examples, dfmparse.py, plus a couple of - sample Delphi forms as tests. (Well done, Dang!) - -- Another performance speedup, 5-10%, inspired by Dang! Plus about a 20% - speedup, by pre-constructing and cacheing exception objects instead of - constructing them on the fly. - -- Fixed minor bug when specifying oneOf() with 'caseless=True'. - -- Cleaned up and added a few more docstrings, to improve the generated docs. - - -Version 1.1.2 - 21 Mar 2004 ---------------------------- -- Fixed minor bug in scanString(), so that start location is at the start of - the matched tokens, not at the start of the whitespace before the matched - tokens. - -- Inclusion of HTML documentation, generated using Epydoc. Reformatted some - doc strings to better generate readable docs. (Beautiful work, Ed Loper, - thanks for Epydoc!) - -- Minor performance speedup, 5-15% - -- And on a process note, I've used the unittest module to define a series of - unit tests, to help avoid the embarrassment of the version 1.1 snafu. - - -Version 1.1.1 - 6 Mar 2004 --------------------------- -- Fixed critical bug introduced in 1.1, which broke MatchFirst(!) token - matching. - **THANK YOU, SEO SANGHYEON!!!** - -- Added "from future import __generators__" to permit running under - pre-Python 2.3. - -- Added example getNTPservers.py, showing how to use pyparsing to extract - a text pattern from the HTML of a web page. - - -Version 1.1 - 3 Mar 2004 -------------------------- -- ***Changed API*** - While testing out parse actions, I found that the value - of loc passed in was not the starting location of the matched tokens, but - the location of the next token in the list. With this version, the location - passed to the parse action is now the starting location of the tokens that - matched. - - A second part of this change is that the return value of parse actions no - longer needs to return a tuple containing both the location and the parsed - tokens (which may optionally be modified); parse actions only need to return - the list of tokens. Parse actions that return a tuple are deprecated; they - will still work properly for conversion/compatibility, but this behavior will - be removed in a future version. - -- Added validate() method, to help diagnose infinite recursion in a grammar tree. - validate() is not 100% fool-proof, but it can help track down nasty infinite - looping due to recursively referencing the same grammar construct without some - intervening characters. - -- Cleaned up default listing of some parse element types, to more closely match - ordinary BNF. Instead of the form :[contents-list], some changes - are: - . And(token1,token2,token3) is "{ token1 token2 token3 }" - . Or(token1,token2,token3) is "{ token1 ^ token2 ^ token3 }" - . MatchFirst(token1,token2,token3) is "{ token1 | token2 | token3 }" - . Optional(token) is "[ token ]" - . OneOrMore(token) is "{ token }..." - . ZeroOrMore(token) is "[ token ]..." - -- Fixed an infinite loop in oneOf if the input string contains a duplicated - option. (Thanks Brad Clements) - -- Fixed a bug when specifying a results name on an Optional token. (Thanks - again, Brad Clements) - -- Fixed a bug introduced in 1.0.6 when I converted quotedString to use - CharsNotIn; I accidentally permitted quoted strings to span newlines. I have - fixed this in this version to go back to the original behavior, in which - quoted strings do *not* span newlines. - -- Fixed minor bug in HTTP server log parser. (Thanks Jim Richardson) - - -Version 1.0.6 - 13 Feb 2004 ----------------------------- -- Added CharsNotIn class (Thanks, Lee SangYeong). This is the opposite of - Word, in that it is constructed with a set of characters *not* to be matched. - (This enhancement also allowed me to clean up and simplify some of the - definitions for quoted strings, cStyleComment, and restOfLine.) - -- **MINOR API CHANGE** - Added joinString argument to the __init__ method of - Combine (Thanks, Thomas Kalka). joinString defaults to "", but some - applications might choose some other string to use instead, such as a blank - or newline. joinString was inserted as the second argument to __init__, - so if you have code that specifies an adjacent value, without using - 'adjacent=', this code will break. - -- Modified LineStart to recognize the start of an empty line. - -- Added optional caseless flag to oneOf(), to create a list of CaselessLiteral - tokens instead of Literal tokens. - -- Added some enhancements to the SQL example: - . Oracle-style comments (Thanks to Harald Armin Massa) - . simple WHERE clause - -- Minor performance speedup - 5-15% - - -Version 1.0.5 - 19 Jan 2004 ----------------------------- -- Added scanString() generator method to ParseElement, to support regex-like - pattern-searching - -- Added items() list to ParseResults, to return named results as a - list of (key,value) pairs - -- Fixed memory overflow in asList() for deeply nested ParseResults (Thanks, - Sverrir Valgeirsson) - -- Minor performance speedup - 10-15% - - -Version 1.0.4 - 8 Jan 2004 ---------------------------- -- Added positional tokens StringStart, StringEnd, LineStart, and LineEnd - -- Added commaSeparatedList to pre-defined global token definitions; also added - commasep.py to the examples directory, to demonstrate the differences between - parsing comma-separated data and simple line-splitting at commas - -- Minor API change: delimitedList does not automatically enclose the - list elements in a Group, but makes this the responsibility of the caller; - also, if invoked using 'combine=True', the list delimiters are also included - in the returned text (good for scoped variables, such as a.b.c or a::b::c, or - for directory paths such as a/b/c) - -- Performance speed-up again, 30-40% - -- Added httpServerLogParser.py to examples directory, as this is - a common parsing task - - -Version 1.0.3 - 23 Dec 2003 ---------------------------- -- Performance speed-up again, 20-40% - -- Added Python distutils installation setup.py, etc. (thanks, Dave Kuhlman) - - -Version 1.0.2 - 18 Dec 2003 ---------------------------- -- **NOTE: Changed API again!!!** (for the last time, I hope) - - + Renamed module from parsing to pyparsing, to better reflect Python - linkage. - -- Also added dictExample.py to examples directory, to illustrate - usage of the Dict class. - - -Version 1.0.1 - 17 Dec 2003 ---------------------------- -- **NOTE: Changed API!** - - + Renamed 'len' argument on Word.__init__() to 'exact' - -- Performance speed-up, 10-30% - - -Version 1.0.0 - 15 Dec 2003 ---------------------------- -- Initial public release - -Version 0.1.1 thru 0.1.17 - October-November, 2003 --------------------------------------------------- -- initial development iterations: - - added Dict, Group - - added helper methods oneOf, delimitedList - - added helpers quotedString (and double and single), restOfLine, cStyleComment - - added MatchFirst as an alternative to the slower Or - - added UML class diagram - - fixed various logic bugs diff --git a/trunk/src/HowToUsePyparsing.html b/trunk/src/HowToUsePyparsing.html deleted file mode 100644 index 1bd180b..0000000 --- a/trunk/src/HowToUsePyparsing.html +++ /dev/null @@ -1,1289 +0,0 @@ - - - - - - -Using the pyparsing module - - - - - - -
-

Using the pyparsing module

- --- - - - - - - - - - - - -
Author:Paul McGuire
Address:
-ptmcg@users.sourceforge.net
-
-
Revision:2.0.1
Date:July, 2013
Copyright:Copyright © 2003-2013 Paul McGuire.
- --- - - - -
abstract:This document provides how-to instructions for the -pyparsing library, an easy-to-use Python module for constructing -and executing basic text parsers. The pyparsing module is useful -for evaluating user-definable -expressions, processing custom application language commands, or -extracting data from formatted reports.
- -
-

1   Steps to follow

-

To parse an incoming data string, the client code must follow these steps:

-
    -
  1. First define the tokens and patterns to be matched, and assign -this to a program variable. Optional results names or parsing -actions can also be defined at this time.
  2. -
  3. Call parseString() or scanString() on this variable, passing in -the string to -be parsed. During the matching process, whitespace between -tokens is skipped by default (although this can be changed). -When token matches occur, any defined parse action methods are -called.
  4. -
  5. Process the parsed results, returned as a list of strings. -Matching results may also be accessed as named attributes of -the returned results, if names are defined in the definition of -the token pattern, using setResultsName().
  6. -
-
-

1.1   Hello, World!

-

The following complete Python program will parse the greeting "Hello, World!", -or any other greeting of the form "<salutation>, <addressee>!":

-
-from pyparsing import Word, alphas
-
-greet = Word( alphas ) + "," + Word( alphas ) + "!"
-greeting = greet.parseString( "Hello, World!" )
-print greeting
-
-

The parsed tokens are returned in the following form:

-
-['Hello', ',', 'World', '!']
-
-
-
-

1.2   Usage notes

-
    -
  • The pyparsing module can be used to interpret simple command -strings or algebraic expressions, or can be used to extract data -from text reports with complicated format and structure ("screen -or report scraping"). However, it is possible that your defined -matching patterns may accept invalid inputs. Use pyparsing to -extract data from strings assumed to be well-formatted.

    -
  • -
  • To keep up the readability of your code, use operators such as +, |, -^, and ~ to combine expressions. You can also combine -string literals with ParseExpressions - they will be -automatically converted to Literal objects. For example:

    -
    -integer  = Word( nums )            # simple unsigned integer
    -variable = Word( alphas, max=1 )   # single letter variable, such as x, z, m, etc.
    -arithOp  = Word( "+-*/", max=1 )   # arithmetic operators
    -equation = variable + "=" + integer + arithOp + integer    # will match "x=2+2", etc.
    -
    -

    In the definition of equation, the string "=" will get added as -a Literal("="), but in a more readable way.

    -
  • -
  • The pyparsing module's default behavior is to ignore whitespace. This is the -case for 99% of all parsers ever written. This allows you to write simple, clean, -grammars, such as the above equation, without having to clutter it up with -extraneous ws markers. The equation grammar will successfully parse all of the -following statements:

    -
    -x=2+2
    -x = 2+2
    -a = 10   *   4
    -r= 1234/ 100000
    -
    -

    Of course, it is quite simple to extend this example to support more elaborate expressions, with -nesting with parentheses, floating point numbers, scientific notation, and named constants -(such as e or pi). See fourFn.py, included in the examples directory.

    -
  • -
  • To modify pyparsing's default whitespace skipping, you can use one or -more of the following methods:

    -
      -
    • use the static method ParserElement.setDefaultWhitespaceChars -to override the normal set of whitespace chars (' tn'). For instance -when defining a grammar in which newlines are significant, you should -call ParserElement.setDefaultWhitespaceChars(' \t') to remove -newline from the set of skippable whitespace characters. Calling -this method will affect all pyparsing expressions defined afterward.

      -
    • -
    • call leaveWhitespace() on individual expressions, to suppress the -skipping of whitespace before trying to match the expression

      -
    • -
    • use Combine to require that successive expressions must be -adjacent in the input string. For instance, this expression:

      -
      -real = Word(nums) + '.' + Word(nums)
      -
      -

      will match "3.14159", but will also match "3 . 12". It will also -return the matched results as ['3', '.', '14159']. By changing this -expression to:

      -
      -real = Combine( Word(nums) + '.' + Word(nums) )
      -
      -

      it will not match numbers with embedded spaces, and it will return a -single concatenated string '3.14159' as the parsed token.

      -
    • -
    -
  • -
  • Repetition of expressions can be indicated using the '*' operator. An -expression may be multiplied by an integer value (to indicate an exact -repetition count), or by a tuple containing -two integers, or None and an integer, representing min and max repetitions -(with None representing no min or no max, depending whether it is the first or -second tuple element). See the following examples, where n is used to -indicate an integer value:

    -
      -
    • expr*3 is equivalent to expr + expr + expr
    • -
    • expr*(2,3) is equivalent to expr + expr + Optional(expr)
    • -
    • expr*(n,None) or expr*(n,) is equivalent -to expr*n + ZeroOrMore(expr) (read as "at least n instances of expr")
    • -
    • expr*(None,n) is equivalent to expr*(0,n) -(read as "0 to n instances of expr")
    • -
    • expr*(None,None) is equivalent to ZeroOrMore(expr)
    • -
    • expr*(1,None) is equivalent to OneOrMore(expr)
    • -
    -

    Note that expr*(None,n) does not raise an exception if -more than n exprs exist in the input stream; that is, -expr*(None,n) does not enforce a maximum number of expr -occurrences. If this behavior is desired, then write -expr*(None,n) + ~expr.

    -
  • -
  • MatchFirst expressions are matched left-to-right, and the first -match found will skip all later expressions within, so be sure -to define less-specific patterns after more-specific patterns. -If you are not sure which expressions are most specific, use Or -expressions (defined using the ^ operator) - they will always -match the longest expression, although they are more -compute-intensive.

    -
  • -
  • Or expressions will evaluate all of the specified subexpressions -to determine which is the "best" match, that is, which matches -the longest string in the input data. In case of a tie, the -left-most expression in the Or list will win.

    -
  • -
  • If parsing the contents of an entire file, pass it to the -parseFile method using:

    -
    -expr.parseFile( sourceFile )
    -
    -
  • -
  • ParseExceptions will report the location where an expected token -or expression failed to match. For example, if we tried to use our -"Hello, World!" parser to parse "Hello World!" (leaving out the separating -comma), we would get an exception, with the message:

    -
    -pyparsing.ParseException: Expected "," (6), (1,7)
    -
    -

    In the case of complex -expressions, the reported location may not be exactly where you -would expect. See more information under ParseException .

    -
  • -
  • Use the Group class to enclose logical groups of tokens within a -sublist. This will help organize your results into more -hierarchical form (the default behavior is to return matching -tokens as a flat list of matching input strings).

    -
  • -
  • Punctuation may be significant for matching, but is rarely of -much interest in the parsed results. Use the suppress() method -to keep these tokens from cluttering up your returned lists of -tokens. For example, delimitedList() matches a succession of -one or more expressions, separated by delimiters (commas by -default), but only returns a list of the actual expressions - -the delimiters are used for parsing, but are suppressed from the -returned output.

    -
  • -
  • Parse actions can be used to convert values from strings to -other data types (ints, floats, booleans, etc.).

    -
  • -
  • Results names are recommended for retrieving tokens from complex -expressions. It is much easier to access a token using its field -name than using a positional index, especially if the expression -contains optional elements. You can also shortcut -the setResultsName call:

    -
    -stats = "AVE:" + realNum.setResultsName("average") + \
    -        "MIN:" + realNum.setResultsName("min") + \
    -        "MAX:" + realNum.setResultsName("max")
    -
    -

    can now be written as this:

    -
    -stats = "AVE:" + realNum("average") + \
    -        "MIN:" + realNum("min") + \
    -        "MAX:" + realNum("max")
    -
    -
  • -
  • Be careful when defining parse actions that modify global variables or -data structures (as in fourFn.py), especially for low level tokens -or expressions that may occur within an And expression; an early element -of an And may match, but the overall expression may fail.

    -
  • -
  • Performance of pyparsing may be slow for complex grammars and/or large -input strings. The psyco package can be used to improve the speed of the -pyparsing module with no changes to grammar or program logic - observed -improvments have been in the 20-50% range.

    -
  • -
-
-
-
-

2   Classes

-
-

2.1   Classes in the pyparsing module

-

ParserElement - abstract base class for all pyparsing classes; -methods for code to use are:

-
    -
  • parseString( sourceString, parseAll=False ) - only called once, on the overall -matching pattern; returns a ParseResults object that makes the -matched tokens available as a list, and optionally as a dictionary, -or as an object with named attributes; if parseAll is set to True, then -parseString will raise a ParseException if the grammar does not process -the complete input string.

    -
  • -
  • parseFile( sourceFile ) - a convenience function, that accepts an -input file object or filename. The file contents are passed as a -string to parseString(). parseFile also supports the parseAll argument.

    -
  • -
  • scanString( sourceString ) - generator function, used to find and -extract matching text in the given source string; for each matched text, -returns a tuple of:

    -
      -
    • matched tokens (packaged as a ParseResults object)
    • -
    • start location of the matched text in the given source string
    • -
    • end location in the given source string
    • -
    -

    scanString allows you to scan through the input source string for -random matches, instead of exhaustively defining the grammar for the entire -source text (as would be required with parseString).

    -
  • -
  • transformString( sourceString ) - convenience wrapper function for -scanString, to process the input source string, and replace matching -text with the tokens returned from parse actions defined in the grammar -(see setParseAction).

    -
  • -
  • searchString( sourceString ) - another convenience wrapper function for -scanString, returns a list of the matching tokens returned from each -call to scanString.

    -
  • -
  • setName( name ) - associate a short descriptive name for this -element, useful in displaying exceptions and trace information

    -
  • -
  • setResultsName( string, listAllMatches=False ) - name to be given -to tokens matching -the element; if multiple tokens within -a repetition group (such as ZeroOrMore or delimitedList) the -default is to return only the last matching token - if listAllMatches -is set to True, then a list of all the matching tokens is returned. -(New in 1.5.6 - a results name with a trailing '*' character will be -interpreted as setting listAllMatches to True.) -Note: -setResultsName returns a copy of the element so that a single -basic element can be referenced multiple times and given -different names within a complex grammar.

    -
  • -
-
    -
  • setParseAction( *fn ) - specify one or more functions to call after successful -matching of the element; each function is defined as fn( s, -loc, toks ), where:

    -
      -
    • s is the original parse string
    • -
    • loc is the location in the string where matching started
    • -
    • toks is the list of the matched tokens, packaged as a ParseResults object
    • -
    -

    Multiple functions can be attached to a ParserElement by specifying multiple -arguments to setParseAction, or by calling setParseAction multiple times.

    -

    Each parse action function can return a modified toks list, to perform conversion, or -string modifications. For brevity, fn may also be a -lambda - here is an example of using a parse action to convert matched -integer tokens from strings to integers:

    -
    -intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] )
    -
    -

    If fn does not modify the toks list, it does not need to return -anything at all.

    -
  • -
  • setBreak( breakFlag=True ) - if breakFlag is True, calls pdb.set_break() -as this expression is about to be parsed

    -
  • -
  • copy() - returns a copy of a ParserElement; can be used to use the same -parse expression in different places in a grammar, with different parse actions -attached to each

    -
  • -
  • leaveWhitespace() - change default behavior of skipping -whitespace before starting matching (mostly used internally to the -pyparsing module, rarely used by client code)

    -
  • -
  • setWhitespaceChars( chars ) - define the set of chars to be ignored -as whitespace before trying to match a specific ParserElement, in place of the -default set of whitespace (space, tab, newline, and return)

    -
  • -
  • setDefaultWhitespaceChars( chars ) - class-level method to override -the default set of whitespace chars for all subsequently created ParserElements -(including copies); useful when defining grammars that treat one or more of the -default whitespace characters as significant (such as a line-sensitive grammar, to -omit newline from the list of ignorable whitespace)

    -
  • -
  • suppress() - convenience function to suppress the output of the -given element, instead of wrapping it with a Suppress object.

    -
  • -
  • ignore( expr ) - function to specify parse expression to be -ignored while matching defined patterns; can be called -repeatedly to specify multiple expressions; useful to specify -patterns of comment syntax, for example

    -
  • -
  • setDebug( dbgFlag=True ) - function to enable/disable tracing output -when trying to match this element

    -
  • -
  • validate() - function to verify that the defined grammar does not -contain infinitely recursive constructs

    -
  • -
-
    -
  • parseWithTabs() - function to override default behavior of converting -tabs to spaces before parsing the input string; rarely used, except when -specifying whitespace-significant grammars using the White class.
  • -
  • enablePackrat() - a class-level static method to enable a memoizing -performance enhancement, known as "packrat parsing". packrat parsing is -disabled by default, since it may conflict with some user programs that use -parse actions. To activate the packrat feature, your -program must call the class method ParserElement.enablePackrat(). If -your program uses psyco to "compile as you go", you must call -enablePackrat before calling psyco.full(). If you do not do this, -Python will crash. For best results, call enablePackrat() immediately -after importing pyparsing.
  • -
-
-
-

2.2   Basic ParserElement subclasses

-
    -
  • Literal - construct with a string to be matched exactly
  • -
  • CaselessLiteral - construct with a string to be matched, but -without case checking; results are always returned as the -defining literal, NOT as they are found in the input string
  • -
  • Keyword - similar to Literal, but must be immediately followed by -whitespace, punctuation, or other non-keyword characters; prevents -accidental matching of a non-keyword that happens to begin with a -defined keyword
  • -
  • CaselessKeyword - similar to Keyword, but with caseless matching -behavior
  • -
-
    -
  • Word - one or more contiguous characters; construct with a -string containing the set of allowed initial characters, and an -optional second string of allowed body characters; for instance, -a common Word construct is to match a code identifier - in C, a -valid identifier must start with an alphabetic character or an -underscore ('_'), followed by a body that can also include numeric -digits. That is, a, i, MAX_LENGTH, _a1, b_109_, and -plan9FromOuterSpace -are all valid identifiers; 9b7z, $a, .section, and 0debug -are not. To -define an identifier using a Word, use either of the following:

    -
    -- Word( alphas+"_", alphanums+"_" )
    -- Word( srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]") )
    -
    -

    If only one -string given, it specifies that the same character set defined -for the initial character is used for the word body; for instance, to -define an identifier that can only be composed of capital letters and -underscores, use:

    -
    -- Word( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" )
    -- Word( srange("[A-Z_]") )
    -
    -

    A Word may -also be constructed with any of the following optional parameters:

    -
      -
    • min - indicating a minimum length of matching characters
    • -
    • max - indicating a maximum length of matching characters
    • -
    • exact - indicating an exact length of matching characters
    • -
    -

    If exact is specified, it will override any values for min or max.

    -

    New in 1.5.6 - Sometimes you want to define a word using all -characters in a range except for one or two of them; you can do this -with the new excludeChars argument. This is helpful if you want to define -a word with all printables except for a single delimiter character, such -as '.'. Previously, you would have to create a custom string to pass to Word. -With this change, you can just create Word(printables, excludeChars='.').

    -
  • -
  • CharsNotIn - similar to Word, but matches characters not -in the given constructor string (accepts only one string for both -initial and body characters); also supports min, max, and exact -optional parameters.

    -
  • -
  • Regex - a powerful construct, that accepts a regular expression -to be matched at the current parse position; accepts an optional -flags parameter, corresponding to the flags parameter in the re.compile -method; if the expression includes named sub-fields, they will be -represented in the returned ParseResults

    -
  • -
  • QuotedString - supports the definition of custom quoted string -formats, in addition to pyparsing's built-in dblQuotedString and -sglQuotedString. QuotedString allows you to specify the following -parameters:

    -
      -
    • quoteChar - string of one or more characters defining the quote delimiting string
    • -
    • escChar - character to escape quotes, typically backslash (default=None)
    • -
    • escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
    • -
    • multiline - boolean indicating whether quotes can span multiple lines (default=False)
    • -
    • unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
    • -
    • endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
    • -
    -
  • -
  • SkipTo - skips ahead in the input string, accepting any -characters up to the specified pattern; may be constructed with -the following optional parameters:

    -
      -
    • include - if set to true, also consumes the match expression -(default is False)
    • -
    • ignore - allows the user to specify patterns to not be matched, -to prevent false matches
    • -
    • failOn - if a literal string or expression is given for this argument, it defines an expression that -should cause the SkipTo expression to fail, and not skip over that expression
    • -
    -
  • -
-
    -
  • White - also similar to Word, but matches whitespace -characters. Not usually needed, as whitespace is implicitly -ignored by pyparsing. However, some grammars are whitespace-sensitive, -such as those that use leading tabs or spaces to indicating grouping -or hierarchy. (If matching on tab characters, be sure to call -parseWithTabs on the top-level parse element.)
  • -
  • Empty - a null expression, requiring no characters - will always -match; useful for debugging and for specialized grammars
  • -
  • NoMatch - opposite of Empty, will never match; useful for debugging -and for specialized grammars
  • -
-
-
-

2.3   Expression subclasses

-
    -
  • And - construct with a list of ParserElements, all of which must -match for And to match; can also be created using the '+' -operator; multiple expressions can be Anded together using the '*' -operator as in:

    -
    -ipAddress = Word(nums) + ('.'+Word(nums))*3
    -
    -

    A tuple can be used as the multiplier, indicating a min/max:

    -
    -usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2)
    -
    -

    A special form of And is created if the '-' operator is used -instead of the '+' operator. In the ipAddress example above, if -no trailing '.' and Word(nums) are found after matching the initial -Word(nums), then pyparsing will back up in the grammar and try other -alternatives to ipAddress. However, if ipAddress is defined as:

    -
    -strictIpAddress = Word(nums) - ('.'+Word(nums))*3
    -
    -

    then no backing up is done. If the first Word(nums) of strictIpAddress -is matched, then any mismatch after that will raise a ParseSyntaxException, -which will halt the parsing process immediately. By careful use of the -'-' operator, grammars can provide meaningful error messages close to -the location where the incoming text does not match the specified -grammar.

    -
  • -
  • Or - construct with a list of ParserElements, any of which must -match for Or to match; if more than one expression matches, the -expression that makes the longest match will be used; can also -be created using the '^' operator

    -
  • -
  • MatchFirst - construct with a list of ParserElements, any of -which must match for MatchFirst to match; matching is done -left-to-right, taking the first expression that matches; can -also be created using the '|' operator

    -
  • -
  • Each - similar to And, in that all of the provided expressions -must match; however, Each permits matching to be done in any order; -can also be created using the '&' operator

    -
  • -
  • Optional - construct with a ParserElement, but this element is -not required to match; can be constructed with an optional default argument, -containing a default string or object to be supplied if the given optional -parse element is not found in the input string; parse action will only -be called if a match is found, or if a default is specified

    -
  • -
  • ZeroOrMore - similar to Optional, but can be repeated

    -
  • -
  • OneOrMore - similar to ZeroOrMore, but at least one match must -be present

    -
  • -
  • FollowedBy - a lookahead expression, requires matching of the given -expressions, but does not advance the parsing position within the input string

    -
  • -
  • NotAny - a negative lookahead expression, prevents matching of named -expressions, does not advance the parsing position within the input string; -can also be created using the unary '~' operator

    -
  • -
-
-
-

2.4   Expression operators

-
    -
  • ~ - creates NotAny using the expression after the operator
  • -
  • + - creates And using the expressions before and after the operator
  • -
  • | - creates MatchFirst (first left-to-right match) using the expressions before and after the operator
  • -
  • ^ - creates Or (longest match) using the expressions before and after the operator
  • -
  • & - creates Each using the expressions before and after the operator
  • -
  • * - creates And by multiplying the expression by the integer operand; if -expression is multiplied by a 2-tuple, creates an And of (min,max) -expressions (similar to "{min,max}" form in regular expressions); if -min is None, intepret as (0,max); if max is None, interpret as -expr*min + ZeroOrMore(expr)
  • -
  • - - like + but with no backup and retry of alternatives
  • -
  • * - repetition of expression
  • -
  • == - matching expression to string; returns True if the string matches the given expression
  • -
  • <<= - inserts the expression following the operator as the body of the -Forward expression before the operator (formerly <<, which is now deprecated)
  • -
-
-
-

2.5   Positional subclasses

-
    -
  • StringStart - matches beginning of the text
  • -
  • StringEnd - matches the end of the text
  • -
  • LineStart - matches beginning of a line (lines delimited by \n characters)
  • -
  • LineEnd - matches the end of a line
  • -
  • WordStart - matches a leading word boundary
  • -
  • WordEnd - matches a trailing word boundary
  • -
-
-
-

2.6   Converter subclasses

-
    -
  • Upcase - converts matched tokens to uppercase (deprecated - -use upcaseTokens parse action instead)
  • -
  • Combine - joins all matched tokens into a single string, using -specified joinString (default joinString=""); expects -all matching tokens to be adjacent, with no intervening -whitespace (can be overridden by specifying adjacent=False in constructor)
  • -
  • Suppress - clears matched tokens; useful to keep returned -results from being cluttered with required but uninteresting -tokens (such as list delimiters)
  • -
-
-
-

2.7   Special subclasses

-
    -
  • Group - causes the matched tokens to be enclosed in a list; -useful in repeated elements like ZeroOrMore and OneOrMore to -break up matched tokens into groups for each repeated pattern
  • -
  • Dict - like Group, but also constructs a dictionary, using the -[0]'th elements of all enclosed token lists as the keys, and -each token list as the value
  • -
  • SkipTo - catch-all matching expression that accepts all characters -up until the given pattern is found to match; useful for specifying -incomplete grammars
  • -
  • Forward - placeholder token used to define recursive token -patterns; when defining the actual expression later in the -program, insert it into the Forward object using the <<= -operator (see fourFn.py for an example).
  • -
-
-
-

2.8   Other classes

-
    -
  • ParseResults - class used to contain and manage the lists of tokens -created from parsing the input using the user-defined parse -expression. ParseResults can be accessed in a number of ways:

    -
      -
    • as a list
        -
      • total list of elements can be found using len()
      • -
      • individual elements can be found using [0], [1], [-1], etc.
      • -
      • elements can be deleted using del
      • -
      • the -1th element can be extracted and removed in a single operation -using pop(), or any element can be extracted and removed -using pop(n)
      • -
      -
    • -
    • as a dictionary
        -
      • if setResultsName() is used to name elements within the -overall parse expression, then these fields can be referenced -as dictionary elements or as attributes
      • -
      • the Dict class generates dictionary entries using the data of the -input text - in addition to ParseResults listed as [ [ a1, b1, c1, ...], [ a2, b2, c2, ...]  ] -it also acts as a dictionary with entries defined as { a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }; -this is especially useful when processing tabular data where the first column contains a key -value for that line of data
      • -
      • list elements that are deleted using del will still be accessible by their -dictionary keys
      • -
      • supports get(), items() and keys() methods, similar to a dictionary
      • -
      • a keyed item can be extracted and removed using pop(key). Here -key must be non-numeric (such as a string), in order to use dict -extraction instead of list extraction.
      • -
      • new named elements can be added (in a parse action, for instance), using the same -syntax as adding an item to a dict (parseResults["X"]="new item"); named elements can be removed using del parseResults["X"]
      • -
      -
    • -
    • as a nested list
        -
      • results returned from the Group class are encapsulated within their -own list structure, so that the tokens can be handled as a hierarchical -tree
      • -
      -
    • -
    -

    ParseResults can also be converted to an ordinary list of strings -by calling asList(). Note that this will strip the results of any -field names that have been defined for any embedded parse elements. -(The pprint module is especially good at printing out the nested contents -given by asList().)

    -

    Finally, ParseResults can be converted to an XML string by calling asXML(). Where -possible, results will be tagged using the results names defined for the respective -ParseExpressions. asXML() takes two optional arguments:

    -
      -
    • doctagname - for ParseResults that do not have a defined name, this argument -will wrap the resulting XML in a set of opening and closing tags <doctagname> -and </doctagname>.
    • -
    • namedItemsOnly (default=False) - flag to indicate if the generated XML should -skip items that do not have defined names. If a nested group item is named, then all -embedded items will be included, whether they have names or not.
    • -
    -
  • -
-
-
-

2.9   Exception classes and Troubleshooting

-
    -
  • ParseException - exception returned when a grammar parse fails; -ParseExceptions have attributes loc, msg, line, lineno, and column; to view the -text line and location where the reported ParseException occurs, use:

    -
    -except ParseException, err:
    -    print err.line
    -    print " "*(err.column-1) + "^"
    -    print err
    -
    -
  • -
  • RecursiveGrammarException - exception returned by validate() if -the grammar contains a recursive infinite loop, such as:

    -
    -badGrammar = Forward()
    -goodToken = Literal("A")
    -badGrammar <<= Optional(goodToken) + badGrammar
    -
    -
  • -
  • ParseFatalException - exception that parse actions can raise to stop parsing -immediately. Should be used when a semantic error is found in the input text, such -as a mismatched XML tag.

    -
  • -
  • ParseSyntaxException - subclass of ParseFatalException raised when a -syntax error is found, based on the use of the '-' operator when defining -a sequence of expressions in an And expression.

    -
  • -
-

You can also get some insights into the parsing logic using diagnostic parse actions, -and setDebug(), or test the matching of expression fragments by testing them using -scanString().

-
-
-
-

3   Miscellaneous attributes and methods

-
-

3.1   Helper methods

-
    -
  • delimitedList( expr, delim=',') - convenience function for -matching one or more occurrences of expr, separated by delim. -By default, the delimiters are suppressed, so the returned results contain -only the separate list elements. Can optionally specify combine=True, -indicating that the expressions and delimiters should be returned as one -combined value (useful for scoped variables, such as "a.b.c", or -"a::b::c", or paths such as "a/b/c").

    -
  • -
  • countedArray( expr ) - convenience function for a pattern where an list of -instances of the given expression are preceded by an integer giving the count of -elements in the list. Returns an expression that parses the leading integer, -reads exactly that many expressions, and returns the array of expressions in the -parse results - the leading integer is suppressed from the results (although it -is easily reconstructed by using len on the returned array).

    -
  • -
  • oneOf( string, caseless=False ) - convenience function for quickly declaring an -alternative set of Literal tokens, by splitting the given string on -whitespace boundaries. The tokens are sorted so that longer -matches are attempted first; this ensures that a short token does -not mask a longer one that starts with the same characters. If caseless=True, -will create an alternative set of CaselessLiteral tokens.

    -
  • -
  • dictOf( key, value ) - convenience function for quickly declaring a -dictionary pattern of Dict( ZeroOrMore( Group( key + value ) ) ).

    -
  • -
  • makeHTMLTags( tagName ) and makeXMLTags( tagName ) - convenience -functions to create definitions of opening and closing tag expressions. Returns -a pair of expressions, for the corresponding <tag> and </tag> strings. Includes -support for attributes in the opening tag, such as <tag attr1="abc"> - attributes -are returned as keyed tokens in the returned ParseResults. makeHTMLTags is less -restrictive than makeXMLTags, especially with respect to case sensitivity.

    -
  • -
  • infixNotation(baseOperand, operatorList) - (formerly named operatorPrecedence) convenience function to define a -grammar for parsing infix notation -expressions with a hierarchical precedence of operators. To use the infixNotation -helper:

    -
      -
    1. Define the base "atom" operand term of the grammar. -For this simple grammar, the smallest operand is either -and integer or a variable. This will be the first argument -to the infixNotation method.
    2. -
    3. 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; if -None, indicates an empty operator, such as the implied -multiplication operation between 'm' and 'x' in "y = mx + b". -If numTerms parameter is 3, this must be a 2-tuple containing the 2 delimiting operators.
      • -
      • numTerms is the number of terms for this operator (must -be 1,2, or 3)
      • -
      • 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)
      • -
      -
    4. -
    5. Call infixNotation passing the operand expression and -the operator precedence list, and save the returned value -as the generated pyparsing expression. You can then use -this expression to parse input strings, or incorporate it -into a larger, more complex grammar.
    6. -
    -
  • -
  • matchPreviousLiteral and matchPreviousExpr - function to define and -expression that matches the same content -as was parsed in a previous parse expression. For instance:

    -
    -first = Word(nums)
    -matchExpr = first + ":" + matchPreviousLiteral(first)
    -
    -

    will match "1:1", but not "1:2". Since this matches at the literal -level, this will also match the leading "1:1" in "1:10".

    -

    In contrast:

    -
    -first = Word(nums)
    -matchExpr = first + ":" + matchPreviousExpr(first)
    -
    -

    will not match the leading "1:1" in "1:10"; the expressions are -evaluated first, and then compared, so "1" is compared with "10".

    -
  • -
  • nestedExpr(opener, closer, content=None, ignoreExpr=quotedString) - method for defining nested -lists enclosed in opening and closing delimiters.

    -
      -
    • opener - opening character for a nested list (default="("); can also be a pyparsing expression
    • -
    • closer - closing character for a nested list (default=")"); can also be a pyparsing expression
    • -
    • content - expression for items within the nested lists (default=None)
    • -
    • ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString)
    • -
    -

    If an expression is not provided for the content argument, the nested -expression will capture all whitespace-delimited content between delimiters -as a list of separate values.

    -

    Use the ignoreExpr argument to define expressions that may contain -opening or closing characters that should not be treated as opening -or closing characters for nesting, such as quotedString or a comment -expression. Specify multiple expressions using an Or or MatchFirst. -The default is quotedString, but if no expressions are to be ignored, -then pass None for this argument.

    -
  • -
  • indentedBlock( statementExpr, indentationStackVar, indent=True) - -function to define an indented block of statements, similar to -indentation-based blocking in Python source code:

    -
      -
    • statementExpr - the expression defining a statement that -will be found in the indented block; a valid indentedBlock -must contain at least 1 matching statementExpr
    • -
    • indentationStackVar - a Python list variable; this variable -should be common to all indentedBlock expressions defined -within the same grammar, and should be reinitialized to [1] -each time the grammar is to be used
    • -
    • indent - a boolean flag indicating whether the expressions -within the block must be indented from the current parse -location; if using indentedBlock to define the left-most -statements (all starting in column 1), set indent to False
    • -
    -
  • -
-
    -
  • originalTextFor( expr ) - helper function to preserve the originally parsed text, regardless of any -token processing or conversion done by the contained expression. For instance, the following expression:

    -
    -fullName = Word(alphas) + Word(alphas)
    -
    -

    will return the parse of "John Smith" as ['John', 'Smith']. In some applications, the actual name as it -was given in the input string is what is desired. To do this, use originalTextFor:

    -
    -fullName = originalTextFor(Word(alphas) + Word(alphas))
    -
    -
  • -
  • ungroup( expr ) - function to "ungroup" returned tokens; useful -to undo the default behavior of And to always group the returned tokens, even -if there is only one in the list. (New in 1.5.6)

    -
  • -
  • lineno( loc, string ) - function to give the line number of the -location within the string; the first line is line 1, newlines -start new rows

    -
  • -
  • col( loc, string ) - function to give the column number of the -location within the string; the first column is column 1, -newlines reset the column number to 1

    -
  • -
  • line( loc, string ) - function to retrieve the line of text -representing lineno( loc, string ); useful when printing out diagnostic -messages for exceptions

    -
  • -
  • srange( rangeSpec ) - function to define a string of characters, -given a string of the form used by regexp string ranges, such as "[0-9]" for -all numeric digits, "[A-Z_]" for uppercase characters plus underscore, and -so on (note that rangeSpec does not include support for generic regular -expressions, just string range specs)

    -
  • -
  • getTokensEndLoc() - function to call from within a parse action to get -the ending location for the matched tokens

    -
  • -
  • traceParseAction(fn) - decorator function to debug parse actions. Lists -each call, called arguments, and return value or exception

    -
  • -
-
-
-

3.2   Helper parse actions

-
    -
  • removeQuotes - removes the first and last characters of a quoted string; -useful to remove the delimiting quotes from quoted strings

    -
  • -
  • replaceWith(replString) - returns a parse action that simply returns the -replString; useful when using transformString, or converting HTML entities, as in:

    -
    -nbsp = Literal("&nbsp;").setParseAction( replaceWith("<BLANK>") )
    -
    -
  • -
  • keepOriginalText- (deprecated, use originalTextFor instead) restores any internal whitespace or suppressed -text within the tokens for a matched parse -expression. This is especially useful when defining expressions -for scanString or transformString applications.

    -
  • -
  • withAttribute( *args, **kwargs ) - helper to create a validating parse action to be used with start tags created -with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag -with a required attribute value, to avoid false matches on common tags such as -<TD> or <DIV>.

    -

    withAttribute can be called with:

    -
      -
    • keyword arguments, as in (class="Customer",align="right"), or
    • -
    • a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") )
    • -
    -

    An attribute can be specified to have the special value -withAttribute.ANY_VALUE, which will match any value - use this to -ensure that an attribute is present but any attribute value is -acceptable.

    -
  • -
  • downcaseTokens - converts all matched tokens to lowercase

    -
  • -
  • upcaseTokens - converts all matched tokens to uppercase

    -
  • -
  • matchOnlyAtCol( columnNumber ) - a parse action that verifies that -an expression was matched at a particular column, raising a -ParseException if matching at a different column number; useful when parsing -tabular data

    -
  • -
-
-
-

3.3   Common string and token constants

-
    -
  • alphas - same as string.letters

    -
  • -
  • nums - same as string.digits

    -
  • -
  • alphanums - a string containing alphas + nums

    -
  • -
  • alphas8bit - a string containing alphabetic 8-bit characters:

    -
    -ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ
    -
    -
  • -
  • printables - same as string.printable, minus the space (' ') character

    -
  • -
  • empty - a global Empty(); will always match

    -
  • -
  • sglQuotedString - a string of characters enclosed in 's; may -include whitespace, but not newlines

    -
  • -
  • dblQuotedString - a string of characters enclosed in "s; may -include whitespace, but not newlines

    -
  • -
  • quotedString - sglQuotedString | dblQuotedString

    -
  • -
  • cStyleComment - a comment block delimited by '/*' and '*/' sequences; can span -multiple lines, but does not support nesting of comments

    -
  • -
  • htmlComment - a comment block delimited by '<!--' and '-->' sequences; can span -multiple lines, but does not support nesting of comments

    -
  • -
  • commaSeparatedList - similar to delimitedList, except that the -list expressions can be any text value, or a quoted string; quoted strings can -safely include commas without incorrectly breaking the string into two tokens

    -
  • -
  • restOfLine - all remaining printable characters up to but not including the next -newline

    -
  • -
-
-
-
- - diff --git a/trunk/src/HowToUsePyparsing.txt b/trunk/src/HowToUsePyparsing.txt deleted file mode 100644 index 71d5313..0000000 --- a/trunk/src/HowToUsePyparsing.txt +++ /dev/null @@ -1,993 +0,0 @@ -========================== -Using the pyparsing module -========================== - -:author: Paul McGuire -:address: ptmcg@users.sourceforge.net - -:revision: 2.0.1 -:date: July, 2013 - -:copyright: Copyright |copy| 2003-2013 Paul McGuire. - -.. |copy| unicode:: 0xA9 - -:abstract: This document provides how-to instructions for the - pyparsing library, an easy-to-use Python module for constructing - and executing basic text parsers. The pyparsing module is useful - for evaluating user-definable - expressions, processing custom application language commands, or - extracting data from formatted reports. - -.. sectnum:: :depth: 4 - -.. contents:: :depth: 4 - - -Steps to follow -=============== - -To parse an incoming data string, the client code must follow these steps: - -1. First define the tokens and patterns to be matched, and assign - this to a program variable. Optional results names or parsing - actions can also be defined at this time. - -2. Call ``parseString()`` or ``scanString()`` on this variable, passing in - the string to - be parsed. During the matching process, whitespace between - tokens is skipped by default (although this can be changed). - When token matches occur, any defined parse action methods are - called. - -3. Process the parsed results, returned as a list of strings. - Matching results may also be accessed as named attributes of - the returned results, if names are defined in the definition of - the token pattern, using ``setResultsName()``. - - -Hello, World! -------------- - -The following complete Python program will parse the greeting "Hello, World!", -or any other greeting of the form ", !":: - - from pyparsing import Word, alphas - - greet = Word( alphas ) + "," + Word( alphas ) + "!" - greeting = greet.parseString( "Hello, World!" ) - print greeting - -The parsed tokens are returned in the following form:: - - ['Hello', ',', 'World', '!'] - - -Usage notes ------------ - -- The pyparsing module can be used to interpret simple command - strings or algebraic expressions, or can be used to extract data - from text reports with complicated format and structure ("screen - or report scraping"). However, it is possible that your defined - matching patterns may accept invalid inputs. Use pyparsing to - extract data from strings assumed to be well-formatted. - -- To keep up the readability of your code, use operators_ such as ``+``, ``|``, - ``^``, and ``~`` to combine expressions. You can also combine - string literals with ParseExpressions - they will be - automatically converted to Literal objects. For example:: - - integer = Word( nums ) # simple unsigned integer - variable = Word( alphas, max=1 ) # single letter variable, such as x, z, m, etc. - arithOp = Word( "+-*/", max=1 ) # arithmetic operators - equation = variable + "=" + integer + arithOp + integer # will match "x=2+2", etc. - - In the definition of ``equation``, the string ``"="`` will get added as - a ``Literal("=")``, but in a more readable way. - -- The pyparsing module's default behavior is to ignore whitespace. This is the - case for 99% of all parsers ever written. This allows you to write simple, clean, - grammars, such as the above ``equation``, without having to clutter it up with - extraneous ``ws`` markers. The ``equation`` grammar will successfully parse all of the - following statements:: - - x=2+2 - x = 2+2 - a = 10 * 4 - r= 1234/ 100000 - - Of course, it is quite simple to extend this example to support more elaborate expressions, with - nesting with parentheses, floating point numbers, scientific notation, and named constants - (such as ``e`` or ``pi``). See ``fourFn.py``, included in the examples directory. - -- To modify pyparsing's default whitespace skipping, you can use one or - more of the following methods: - - - use the static method ``ParserElement.setDefaultWhitespaceChars`` - to override the normal set of whitespace chars (' \t\n'). For instance - when defining a grammar in which newlines are significant, you should - call ``ParserElement.setDefaultWhitespaceChars(' \t')`` to remove - newline from the set of skippable whitespace characters. Calling - this method will affect all pyparsing expressions defined afterward. - - - call ``leaveWhitespace()`` on individual expressions, to suppress the - skipping of whitespace before trying to match the expression - - - use ``Combine`` to require that successive expressions must be - adjacent in the input string. For instance, this expression:: - - real = Word(nums) + '.' + Word(nums) - - will match "3.14159", but will also match "3 . 12". It will also - return the matched results as ['3', '.', '14159']. By changing this - expression to:: - - real = Combine( Word(nums) + '.' + Word(nums) ) - - it will not match numbers with embedded spaces, and it will return a - single concatenated string '3.14159' as the parsed token. - -- Repetition of expressions can be indicated using the '*' operator. An - expression may be multiplied by an integer value (to indicate an exact - repetition count), or by a tuple containing - two integers, or None and an integer, representing min and max repetitions - (with None representing no min or no max, depending whether it is the first or - second tuple element). See the following examples, where n is used to - indicate an integer value: - - - ``expr*3`` is equivalent to ``expr + expr + expr`` - - - ``expr*(2,3)`` is equivalent to ``expr + expr + Optional(expr)`` - - - ``expr*(n,None)`` or ``expr*(n,)`` is equivalent - to ``expr*n + ZeroOrMore(expr)`` (read as "at least n instances of expr") - - - ``expr*(None,n)`` is equivalent to ``expr*(0,n)`` - (read as "0 to n instances of expr") - - - ``expr*(None,None)`` is equivalent to ``ZeroOrMore(expr)`` - - - ``expr*(1,None)`` is equivalent to ``OneOrMore(expr)`` - - Note that ``expr*(None,n)`` does not raise an exception if - more than n exprs exist in the input stream; that is, - ``expr*(None,n)`` does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - ``expr*(None,n) + ~expr``. - -- ``MatchFirst`` expressions are matched left-to-right, and the first - match found will skip all later expressions within, so be sure - to define less-specific patterns after more-specific patterns. - If you are not sure which expressions are most specific, use Or - expressions (defined using the ``^`` operator) - they will always - match the longest expression, although they are more - compute-intensive. - -- ``Or`` expressions will evaluate all of the specified subexpressions - to determine which is the "best" match, that is, which matches - the longest string in the input data. In case of a tie, the - left-most expression in the ``Or`` list will win. - -- If parsing the contents of an entire file, pass it to the - ``parseFile`` method using:: - - expr.parseFile( sourceFile ) - -- ``ParseExceptions`` will report the location where an expected token - or expression failed to match. For example, if we tried to use our - "Hello, World!" parser to parse "Hello World!" (leaving out the separating - comma), we would get an exception, with the message:: - - pyparsing.ParseException: Expected "," (6), (1,7) - - In the case of complex - expressions, the reported location may not be exactly where you - would expect. See more information under ParseException_ . - -- Use the ``Group`` class to enclose logical groups of tokens within a - sublist. This will help organize your results into more - hierarchical form (the default behavior is to return matching - tokens as a flat list of matching input strings). - -- Punctuation may be significant for matching, but is rarely of - much interest in the parsed results. Use the ``suppress()`` method - to keep these tokens from cluttering up your returned lists of - tokens. For example, ``delimitedList()`` matches a succession of - one or more expressions, separated by delimiters (commas by - default), but only returns a list of the actual expressions - - the delimiters are used for parsing, but are suppressed from the - returned output. - -- Parse actions can be used to convert values from strings to - other data types (ints, floats, booleans, etc.). - -- Results names are recommended for retrieving tokens from complex - expressions. It is much easier to access a token using its field - name than using a positional index, especially if the expression - contains optional elements. You can also shortcut - the ``setResultsName`` call:: - - stats = "AVE:" + realNum.setResultsName("average") + \ - "MIN:" + realNum.setResultsName("min") + \ - "MAX:" + realNum.setResultsName("max") - - can now be written as this:: - - stats = "AVE:" + realNum("average") + \ - "MIN:" + realNum("min") + \ - "MAX:" + realNum("max") - -- Be careful when defining parse actions that modify global variables or - data structures (as in ``fourFn.py``), especially for low level tokens - or expressions that may occur within an ``And`` expression; an early element - of an ``And`` may match, but the overall expression may fail. - -- Performance of pyparsing may be slow for complex grammars and/or large - input strings. The psyco_ package can be used to improve the speed of the - pyparsing module with no changes to grammar or program logic - observed - improvments have been in the 20-50% range. - -.. _psyco: http://psyco.sourceforge.net/ - - -Classes -======= - -Classes in the pyparsing module -------------------------------- - -``ParserElement`` - abstract base class for all pyparsing classes; -methods for code to use are: - -- ``parseString( sourceString, parseAll=False )`` - only called once, on the overall - matching pattern; returns a ParseResults_ object that makes the - matched tokens available as a list, and optionally as a dictionary, - or as an object with named attributes; if parseAll is set to True, then - parseString will raise a ParseException if the grammar does not process - the complete input string. - -- ``parseFile( sourceFile )`` - a convenience function, that accepts an - input file object or filename. The file contents are passed as a - string to ``parseString()``. ``parseFile`` also supports the ``parseAll`` argument. - -- ``scanString( sourceString )`` - generator function, used to find and - extract matching text in the given source string; for each matched text, - returns a tuple of: - - - matched tokens (packaged as a ParseResults_ object) - - - start location of the matched text in the given source string - - - end location in the given source string - - ``scanString`` allows you to scan through the input source string for - random matches, instead of exhaustively defining the grammar for the entire - source text (as would be required with ``parseString``). - -- ``transformString( sourceString )`` - convenience wrapper function for - ``scanString``, to process the input source string, and replace matching - text with the tokens returned from parse actions defined in the grammar - (see setParseAction_). - -- ``searchString( sourceString )`` - another convenience wrapper function for - ``scanString``, returns a list of the matching tokens returned from each - call to ``scanString``. - -- ``setName( name )`` - associate a short descriptive name for this - element, useful in displaying exceptions and trace information - -- ``setResultsName( string, listAllMatches=False )`` - name to be given - to tokens matching - the element; if multiple tokens within - a repetition group (such as ``ZeroOrMore`` or ``delimitedList``) the - default is to return only the last matching token - if listAllMatches - is set to True, then a list of all the matching tokens is returned. - (New in 1.5.6 - a results name with a trailing '*' character will be - interpreted as setting listAllMatches to True.) - Note: - ``setResultsName`` returns a *copy* of the element so that a single - basic element can be referenced multiple times and given - different names within a complex grammar. - -.. _setParseAction: - -- ``setParseAction( *fn )`` - specify one or more functions to call after successful - matching of the element; each function is defined as ``fn( s, - loc, toks )``, where: - - - ``s`` is the original parse string - - - ``loc`` is the location in the string where matching started - - - ``toks`` is the list of the matched tokens, packaged as a ParseResults_ object - - Multiple functions can be attached to a ParserElement by specifying multiple - arguments to setParseAction, or by calling setParseAction multiple times. - - Each parse action function can return a modified ``toks`` list, to perform conversion, or - string modifications. For brevity, ``fn`` may also be a - lambda - here is an example of using a parse action to convert matched - integer tokens from strings to integers:: - - intNumber = Word(nums).setParseAction( lambda s,l,t: [ int(t[0]) ] ) - - If ``fn`` does not modify the ``toks`` list, it does not need to return - anything at all. - -- ``setBreak( breakFlag=True )`` - if breakFlag is True, calls pdb.set_break() - as this expression is about to be parsed - -- ``copy()`` - returns a copy of a ParserElement; can be used to use the same - parse expression in different places in a grammar, with different parse actions - attached to each - -- ``leaveWhitespace()`` - change default behavior of skipping - whitespace before starting matching (mostly used internally to the - pyparsing module, rarely used by client code) - -- ``setWhitespaceChars( chars )`` - define the set of chars to be ignored - as whitespace before trying to match a specific ParserElement, in place of the - default set of whitespace (space, tab, newline, and return) - -- ``setDefaultWhitespaceChars( chars )`` - class-level method to override - the default set of whitespace chars for all subsequently created ParserElements - (including copies); useful when defining grammars that treat one or more of the - default whitespace characters as significant (such as a line-sensitive grammar, to - omit newline from the list of ignorable whitespace) - -- ``suppress()`` - convenience function to suppress the output of the - given element, instead of wrapping it with a Suppress object. - -- ``ignore( expr )`` - function to specify parse expression to be - ignored while matching defined patterns; can be called - repeatedly to specify multiple expressions; useful to specify - patterns of comment syntax, for example - -- ``setDebug( dbgFlag=True )`` - function to enable/disable tracing output - when trying to match this element - -- ``validate()`` - function to verify that the defined grammar does not - contain infinitely recursive constructs - -.. _parseWithTabs: - -- ``parseWithTabs()`` - function to override default behavior of converting - tabs to spaces before parsing the input string; rarely used, except when - specifying whitespace-significant grammars using the White_ class. - -- ``enablePackrat()`` - a class-level static method to enable a memoizing - performance enhancement, known as "packrat parsing". packrat parsing is - disabled by default, since it may conflict with some user programs that use - parse actions. To activate the packrat feature, your - program must call the class method ParserElement.enablePackrat(). If - your program uses psyco to "compile as you go", you must call - enablePackrat before calling psyco.full(). If you do not do this, - Python will crash. For best results, call enablePackrat() immediately - after importing pyparsing. - - -Basic ParserElement subclasses ------------------------------- - -- ``Literal`` - construct with a string to be matched exactly - -- ``CaselessLiteral`` - construct with a string to be matched, but - without case checking; results are always returned as the - defining literal, NOT as they are found in the input string - -- ``Keyword`` - similar to Literal, but must be immediately followed by - whitespace, punctuation, or other non-keyword characters; prevents - accidental matching of a non-keyword that happens to begin with a - defined keyword - -- ``CaselessKeyword`` - similar to Keyword, but with caseless matching - behavior - -.. _Word: - -- ``Word`` - one or more contiguous characters; construct with a - string containing the set of allowed initial characters, and an - optional second string of allowed body characters; for instance, - a common Word construct is to match a code identifier - in C, a - valid identifier must start with an alphabetic character or an - underscore ('_'), followed by a body that can also include numeric - digits. That is, ``a``, ``i``, ``MAX_LENGTH``, ``_a1``, ``b_109_``, and - ``plan9FromOuterSpace`` - are all valid identifiers; ``9b7z``, ``$a``, ``.section``, and ``0debug`` - are not. To - define an identifier using a Word, use either of the following:: - - - Word( alphas+"_", alphanums+"_" ) - - Word( srange("[a-zA-Z_]"), srange("[a-zA-Z0-9_]") ) - - If only one - string given, it specifies that the same character set defined - for the initial character is used for the word body; for instance, to - define an identifier that can only be composed of capital letters and - underscores, use:: - - - Word( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" ) - - Word( srange("[A-Z_]") ) - - A Word may - also be constructed with any of the following optional parameters: - - - ``min`` - indicating a minimum length of matching characters - - - ``max`` - indicating a maximum length of matching characters - - - ``exact`` - indicating an exact length of matching characters - - If ``exact`` is specified, it will override any values for ``min`` or ``max``. - - New in 1.5.6 - Sometimes you want to define a word using all - characters in a range except for one or two of them; you can do this - with the new ``excludeChars`` argument. This is helpful if you want to define - a word with all printables except for a single delimiter character, such - as '.'. Previously, you would have to create a custom string to pass to Word. - With this change, you can just create ``Word(printables, excludeChars='.')``. - -- ``CharsNotIn`` - similar to Word_, but matches characters not - in the given constructor string (accepts only one string for both - initial and body characters); also supports ``min``, ``max``, and ``exact`` - optional parameters. - -- ``Regex`` - a powerful construct, that accepts a regular expression - to be matched at the current parse position; accepts an optional - ``flags`` parameter, corresponding to the flags parameter in the re.compile - method; if the expression includes named sub-fields, they will be - represented in the returned ParseResults_ - -- ``QuotedString`` - supports the definition of custom quoted string - formats, in addition to pyparsing's built-in ``dblQuotedString`` and - ``sglQuotedString``. ``QuotedString`` allows you to specify the following - parameters: - - - ``quoteChar`` - string of one or more characters defining the quote delimiting string - - - ``escChar`` - character to escape quotes, typically backslash (default=None) - - - ``escQuote`` - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None) - - - ``multiline`` - boolean indicating whether quotes can span multiple lines (default=False) - - - ``unquoteResults`` - boolean indicating whether the matched text should be unquoted (default=True) - - - ``endQuoteChar`` - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar) - -- ``SkipTo`` - skips ahead in the input string, accepting any - characters up to the specified pattern; may be constructed with - the following optional parameters: - - - ``include`` - if set to true, also consumes the match expression - (default is false) - - - ``ignore`` - allows the user to specify patterns to not be matched, - to prevent false matches - - - ``failOn`` - if a literal string or expression is given for this argument, it defines an expression that - should cause the ``SkipTo`` expression to fail, and not skip over that expression - -.. _White: - -- ``White`` - also similar to Word_, but matches whitespace - characters. Not usually needed, as whitespace is implicitly - ignored by pyparsing. However, some grammars are whitespace-sensitive, - such as those that use leading tabs or spaces to indicating grouping - or hierarchy. (If matching on tab characters, be sure to call - parseWithTabs_ on the top-level parse element.) - -- ``Empty`` - a null expression, requiring no characters - will always - match; useful for debugging and for specialized grammars - -- ``NoMatch`` - opposite of Empty, will never match; useful for debugging - and for specialized grammars - - -Expression subclasses ---------------------- - -- ``And`` - construct with a list of ParserElements, all of which must - match for And to match; can also be created using the '+' - operator; multiple expressions can be Anded together using the '*' - operator as in:: - - ipAddress = Word(nums) + ('.'+Word(nums))*3 - - A tuple can be used as the multiplier, indicating a min/max:: - - usPhoneNumber = Word(nums) + ('-'+Word(nums))*(1,2) - - A special form of ``And`` is created if the '-' operator is used - instead of the '+' operator. In the ipAddress example above, if - no trailing '.' and Word(nums) are found after matching the initial - Word(nums), then pyparsing will back up in the grammar and try other - alternatives to ipAddress. However, if ipAddress is defined as:: - - strictIpAddress = Word(nums) - ('.'+Word(nums))*3 - - then no backing up is done. If the first Word(nums) of strictIpAddress - is matched, then any mismatch after that will raise a ParseSyntaxException, - which will halt the parsing process immediately. By careful use of the - '-' operator, grammars can provide meaningful error messages close to - the location where the incoming text does not match the specified - grammar. - -- ``Or`` - construct with a list of ParserElements, any of which must - match for Or to match; if more than one expression matches, the - expression that makes the longest match will be used; can also - be created using the '^' operator - -- ``MatchFirst`` - construct with a list of ParserElements, any of - which must match for MatchFirst to match; matching is done - left-to-right, taking the first expression that matches; can - also be created using the '|' operator - -- ``Each`` - similar to And, in that all of the provided expressions - must match; however, Each permits matching to be done in any order; - can also be created using the '&' operator - -- ``Optional`` - construct with a ParserElement, but this element is - not required to match; can be constructed with an optional ``default`` argument, - containing a default string or object to be supplied if the given optional - parse element is not found in the input string; parse action will only - be called if a match is found, or if a default is specified - -- ``ZeroOrMore`` - similar to Optional, but can be repeated - -- ``OneOrMore`` - similar to ZeroOrMore, but at least one match must - be present - -- ``FollowedBy`` - a lookahead expression, requires matching of the given - expressions, but does not advance the parsing position within the input string - -- ``NotAny`` - a negative lookahead expression, prevents matching of named - expressions, does not advance the parsing position within the input string; - can also be created using the unary '~' operator - - -.. _operators: - -Expression operators --------------------- - -- ``~`` - creates NotAny using the expression after the operator - -- ``+`` - creates And using the expressions before and after the operator - -- ``|`` - creates MatchFirst (first left-to-right match) using the expressions before and after the operator - -- ``^`` - creates Or (longest match) using the expressions before and after the operator - -- ``&`` - creates Each using the expressions before and after the operator - -- ``*`` - creates And by multiplying the expression by the integer operand; if - expression is multiplied by a 2-tuple, creates an And of (min,max) - expressions (similar to "{min,max}" form in regular expressions); if - min is None, intepret as (0,max); if max is None, interpret as - expr*min + ZeroOrMore(expr) - -- ``-`` - like ``+`` but with no backup and retry of alternatives - -- ``*`` - repetition of expression - -- ``==`` - matching expression to string; returns True if the string matches the given expression - -- ``<<=`` - inserts the expression following the operator as the body of the - Forward expression before the operator - - - -Positional subclasses ---------------------- - -- ``StringStart`` - matches beginning of the text - -- ``StringEnd`` - matches the end of the text - -- ``LineStart`` - matches beginning of a line (lines delimited by ``\n`` characters) - -- ``LineEnd`` - matches the end of a line - -- ``WordStart`` - matches a leading word boundary - -- ``WordEnd`` - matches a trailing word boundary - - - -Converter subclasses --------------------- - -- ``Upcase`` - converts matched tokens to uppercase (deprecated - - use ``upcaseTokens`` parse action instead) - -- ``Combine`` - joins all matched tokens into a single string, using - specified joinString (default ``joinString=""``); expects - all matching tokens to be adjacent, with no intervening - whitespace (can be overridden by specifying ``adjacent=False`` in constructor) - -- ``Suppress`` - clears matched tokens; useful to keep returned - results from being cluttered with required but uninteresting - tokens (such as list delimiters) - - -Special subclasses ------------------- - -- ``Group`` - causes the matched tokens to be enclosed in a list; - useful in repeated elements like ``ZeroOrMore`` and ``OneOrMore`` to - break up matched tokens into groups for each repeated pattern - -- ``Dict`` - like ``Group``, but also constructs a dictionary, using the - [0]'th elements of all enclosed token lists as the keys, and - each token list as the value - -- ``SkipTo`` - catch-all matching expression that accepts all characters - up until the given pattern is found to match; useful for specifying - incomplete grammars - -- ``Forward`` - placeholder token used to define recursive token - patterns; when defining the actual expression later in the - program, insert it into the ``Forward`` object using the ``<<`` - operator (see ``fourFn.py`` for an example). - - -Other classes -------------- -.. _ParseResults: - -- ``ParseResults`` - class used to contain and manage the lists of tokens - created from parsing the input using the user-defined parse - expression. ParseResults can be accessed in a number of ways: - - - as a list - - - total list of elements can be found using len() - - - individual elements can be found using [0], [1], [-1], etc. - - - elements can be deleted using ``del`` - - - the -1th element can be extracted and removed in a single operation - using ``pop()``, or any element can be extracted and removed - using ``pop(n)`` - - - as a dictionary - - - if ``setResultsName()`` is used to name elements within the - overall parse expression, then these fields can be referenced - as dictionary elements or as attributes - - - the Dict class generates dictionary entries using the data of the - input text - in addition to ParseResults listed as ``[ [ a1, b1, c1, ...], [ a2, b2, c2, ...] ]`` - it also acts as a dictionary with entries defined as ``{ a1 : [ b1, c1, ... ] }, { a2 : [ b2, c2, ... ] }``; - this is especially useful when processing tabular data where the first column contains a key - value for that line of data - - - list elements that are deleted using ``del`` will still be accessible by their - dictionary keys - - - supports ``get()``, ``items()`` and ``keys()`` methods, similar to a dictionary - - - a keyed item can be extracted and removed using ``pop(key)``. Here - key must be non-numeric (such as a string), in order to use dict - extraction instead of list extraction. - - - new named elements can be added (in a parse action, for instance), using the same - syntax as adding an item to a dict (``parseResults["X"]="new item"``); named elements can be removed using ``del parseResults["X"]`` - - - as a nested list - - - results returned from the Group class are encapsulated within their - own list structure, so that the tokens can be handled as a hierarchical - tree - - ParseResults can also be converted to an ordinary list of strings - by calling ``asList()``. Note that this will strip the results of any - field names that have been defined for any embedded parse elements. - (The ``pprint`` module is especially good at printing out the nested contents - given by ``asList()``.) - - Finally, ParseResults can be converted to an XML string by calling ``asXML()``. Where - possible, results will be tagged using the results names defined for the respective - ParseExpressions. ``asXML()`` takes two optional arguments: - - - ``doctagname`` - for ParseResults that do not have a defined name, this argument - will wrap the resulting XML in a set of opening and closing tags ```` - and ````. - - - ``namedItemsOnly`` (default=``False``) - flag to indicate if the generated XML should - skip items that do not have defined names. If a nested group item is named, then all - embedded items will be included, whether they have names or not. - - -Exception classes and Troubleshooting -------------------------------------- - -.. _ParseException: - -- ``ParseException`` - exception returned when a grammar parse fails; - ParseExceptions have attributes loc, msg, line, lineno, and column; to view the - text line and location where the reported ParseException occurs, use:: - - except ParseException, err: - print err.line - print " "*(err.column-1) + "^" - print err - -- ``RecursiveGrammarException`` - exception returned by ``validate()`` if - the grammar contains a recursive infinite loop, such as:: - - badGrammar = Forward() - goodToken = Literal("A") - badGrammar <<= Optional(goodToken) + badGrammar - -- ``ParseFatalException`` - exception that parse actions can raise to stop parsing - immediately. Should be used when a semantic error is found in the input text, such - as a mismatched XML tag. - -- ``ParseSyntaxException`` - subclass of ``ParseFatalException`` raised when a - syntax error is found, based on the use of the '-' operator when defining - a sequence of expressions in an ``And`` expression. - -You can also get some insights into the parsing logic using diagnostic parse actions, -and setDebug(), or test the matching of expression fragments by testing them using -scanString(). - - -Miscellaneous attributes and methods -==================================== - -Helper methods --------------- - -- ``delimitedList( expr, delim=',')`` - convenience function for - matching one or more occurrences of expr, separated by delim. - By default, the delimiters are suppressed, so the returned results contain - only the separate list elements. Can optionally specify ``combine=True``, - indicating that the expressions and delimiters should be returned as one - combined value (useful for scoped variables, such as "a.b.c", or - "a::b::c", or paths such as "a/b/c"). - -- ``countedArray( expr )`` - convenience function for a pattern where an list of - instances of the given expression are preceded by an integer giving the count of - elements in the list. Returns an expression that parses the leading integer, - reads exactly that many expressions, and returns the array of expressions in the - parse results - the leading integer is suppressed from the results (although it - is easily reconstructed by using len on the returned array). - -- ``oneOf( string, caseless=False )`` - convenience function for quickly declaring an - alternative set of ``Literal`` tokens, by splitting the given string on - whitespace boundaries. The tokens are sorted so that longer - matches are attempted first; this ensures that a short token does - not mask a longer one that starts with the same characters. If ``caseless=True``, - will create an alternative set of CaselessLiteral tokens. - -- ``dictOf( key, value )`` - convenience function for quickly declaring a - dictionary pattern of ``Dict( ZeroOrMore( Group( key + value ) ) )``. - -- ``makeHTMLTags( tagName )`` and ``makeXMLTags( tagName )`` - convenience - functions to create definitions of opening and closing tag expressions. Returns - a pair of expressions, for the corresponding and strings. Includes - support for attributes in the opening tag, such as - attributes - are returned as keyed tokens in the returned ParseResults. ``makeHTMLTags`` is less - restrictive than ``makeXMLTags``, especially with respect to case sensitivity. - -- ``infixNotation(baseOperand, operatorList)`` - (formerly named ``operatorPrecedence``) convenience function to define a - grammar for parsing infix notation - expressions with a hierarchical precedence of operators. To use the ``infixNotation`` - helper: - - 1. Define the base "atom" operand term of the grammar. - For this simple grammar, the smallest operand is either - and integer or a variable. This will be the first argument - to the ``infixNotation`` method. - - 2. Define a list of tuples for each level of operator - precendence. Each tuple is of the form - ``(opExpr, numTerms, rightLeftAssoc, parseAction)``, where: - - - ``opExpr`` - the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; if - None, indicates an empty operator, such as the implied - multiplication operation between 'm' and 'x' in "y = mx + b". - - - ``numTerms`` - the number of terms for this operator (must - be 1, 2, or 3) - - - ``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 - ``parseAction`` tuple member may be omitted) - - 3. Call ``infixNotation`` passing the operand expression and - the operator precedence list, and save the returned value - as the generated pyparsing expression. You can then use - this expression to parse input strings, or incorporate it - into a larger, more complex grammar. - -- ``matchPreviousLiteral`` and ``matchPreviousExpr`` - function to define and - expression that matches the same content - as was parsed in a previous parse expression. For instance:: - - first = Word(nums) - matchExpr = first + ":" + matchPreviousLiteral(first) - - will match "1:1", but not "1:2". Since this matches at the literal - level, this will also match the leading "1:1" in "1:10". - - In contrast:: - - first = Word(nums) - matchExpr = first + ":" + matchPreviousExpr(first) - - will *not* match the leading "1:1" in "1:10"; the expressions are - evaluated first, and then compared, so "1" is compared with "10". - -- ``nestedExpr(opener, closer, content=None, ignoreExpr=quotedString)`` - method for defining nested - lists enclosed in opening and closing delimiters. - - - ``opener`` - opening character for a nested list (default="("); can also be a pyparsing expression - - - ``closer`` - closing character for a nested list (default=")"); can also be a pyparsing expression - - - ``content`` - expression for items within the nested lists (default=None) - - - ``ignoreExpr`` - expression for ignoring opening and closing delimiters (default=quotedString) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the ignoreExpr argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an Or or MatchFirst. - The default is quotedString, but if no expressions are to be ignored, - then pass None for this argument. - - -- ``indentedBlock( statementExpr, indentationStackVar, indent=True)`` - - function to define an indented block of statements, similar to - indentation-based blocking in Python source code: - - - ``statementExpr`` - the expression defining a statement that - will be found in the indented block; a valid ``indentedBlock`` - must contain at least 1 matching ``statementExpr`` - - - ``indentationStackVar`` - a Python list variable; this variable - should be common to all ``indentedBlock`` expressions defined - within the same grammar, and should be reinitialized to [1] - each time the grammar is to be used - - - ``indent`` - a boolean flag indicating whether the expressions - within the block must be indented from the current parse - location; if using ``indentedBlock`` to define the left-most - statements (all starting in column 1), set ``indent`` to False - -.. _originalTextFor: - -- ``originalTextFor( expr )`` - helper function to preserve the originally parsed text, regardless of any - token processing or conversion done by the contained expression. For instance, the following expression:: - - fullName = Word(alphas) + Word(alphas) - - will return the parse of "John Smith" as ['John', 'Smith']. In some applications, the actual name as it - was given in the input string is what is desired. To do this, use ``originalTextFor``:: - - fullName = originalTextFor(Word(alphas) + Word(alphas)) - -- ``ungroup( expr )`` - function to "ungroup" returned tokens; useful - to undo the default behavior of And to always group the returned tokens, even - if there is only one in the list. (New in 1.5.6) - -- ``lineno( loc, string )`` - function to give the line number of the - location within the string; the first line is line 1, newlines - start new rows - -- ``col( loc, string )`` - function to give the column number of the - location within the string; the first column is column 1, - newlines reset the column number to 1 - -- ``line( loc, string )`` - function to retrieve the line of text - representing ``lineno( loc, string )``; useful when printing out diagnostic - messages for exceptions - -- ``srange( rangeSpec )`` - function to define a string of characters, - given a string of the form used by regexp string ranges, such as ``"[0-9]"`` for - all numeric digits, ``"[A-Z_]"`` for uppercase characters plus underscore, and - so on (note that rangeSpec does not include support for generic regular - expressions, just string range specs) - -- ``getTokensEndLoc()`` - function to call from within a parse action to get - the ending location for the matched tokens - -- ``traceParseAction(fn)`` - decorator function to debug parse actions. Lists - each call, called arguments, and return value or exception - - - -Helper parse actions --------------------- - -- ``removeQuotes`` - removes the first and last characters of a quoted string; - useful to remove the delimiting quotes from quoted strings - -- ``replaceWith(replString)`` - returns a parse action that simply returns the - replString; useful when using transformString, or converting HTML entities, as in:: - - nbsp = Literal(" ").setParseAction( replaceWith("") ) - -- ``keepOriginalText``- (deprecated, use originalTextFor_ instead) restores any internal whitespace or suppressed - text within the tokens for a matched parse - expression. This is especially useful when defining expressions - for scanString or transformString applications. - -- ``withAttribute( *args, **kwargs )`` - helper to create a validating parse action to be used with start tags created - with ``makeXMLTags`` or ``makeHTMLTags``. Use ``withAttribute`` to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - ```` or ``
``. - - ``withAttribute`` can be called with: - - - keyword arguments, as in ``(class="Customer",align="right")``, or - - - a list of name-value tuples, as in ``( ("ns1:class", "Customer"), ("ns2:align","right") )`` - - An attribute can be specified to have the special value - ``withAttribute.ANY_VALUE``, which will match any value - use this to - ensure that an attribute is present but any attribute value is - acceptable. - -- ``downcaseTokens`` - converts all matched tokens to lowercase - -- ``upcaseTokens`` - converts all matched tokens to uppercase - -- ``matchOnlyAtCol( columnNumber )`` - a parse action that verifies that - an expression was matched at a particular column, raising a - ParseException if matching at a different column number; useful when parsing - tabular data - - - -Common string and token constants ---------------------------------- - -- ``alphas`` - same as ``string.letters`` - -- ``nums`` - same as ``string.digits`` - -- ``alphanums`` - a string containing ``alphas + nums`` - -- ``alphas8bit`` - a string containing alphabetic 8-bit characters:: - - - -- ``printables`` - same as ``string.printable``, minus the space (``' '``) character - -- ``empty`` - a global ``Empty()``; will always match - -- ``sglQuotedString`` - a string of characters enclosed in 's; may - include whitespace, but not newlines - -- ``dblQuotedString`` - a string of characters enclosed in "s; may - include whitespace, but not newlines - -- ``quotedString`` - ``sglQuotedString | dblQuotedString`` - -- ``cStyleComment`` - a comment block delimited by ``'/*'`` and ``'*/'`` sequences; can span - multiple lines, but does not support nesting of comments - -- ``htmlComment`` - a comment block delimited by ``''`` sequences; can span - multiple lines, but does not support nesting of comments - -- ``commaSeparatedList`` - similar to ``delimitedList``, except that the - list expressions can be any text value, or a quoted string; quoted strings can - safely include commas without incorrectly breaking the string into two tokens - -- ``restOfLine`` - all remaining printable characters up to but not including the next - newline diff --git a/trunk/src/LICENSE b/trunk/src/LICENSE deleted file mode 100644 index bbc959e..0000000 --- a/trunk/src/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -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. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/trunk/src/MANIFEST.in_bdist b/trunk/src/MANIFEST.in_bdist deleted file mode 100644 index 5f2b98b..0000000 --- a/trunk/src/MANIFEST.in_bdist +++ /dev/null @@ -1,7 +0,0 @@ -include pyparsing.py -include HowToUsePyparsing.html pyparsingClassDiagram.* -include README CHANGES LICENSE -include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html -include htmldoc/*.* -include docs/*.* -include robots.txt diff --git a/trunk/src/MANIFEST.in_src b/trunk/src/MANIFEST.in_src deleted file mode 100644 index 5f2b98b..0000000 --- a/trunk/src/MANIFEST.in_src +++ /dev/null @@ -1,7 +0,0 @@ -include pyparsing.py -include HowToUsePyparsing.html pyparsingClassDiagram.* -include README CHANGES LICENSE -include examples/*.py examples/Setup.ini examples/*.dfm examples/*.ics examples/*.html -include htmldoc/*.* -include docs/*.* -include robots.txt diff --git a/trunk/src/README b/trunk/src/README deleted file mode 100644 index dc959ec..0000000 --- a/trunk/src/README +++ /dev/null @@ -1,80 +0,0 @@ -==================================== -PyParsing -- A Python Parsing Module -==================================== - -Introduction -============ - -The pyparsing module is an alternative approach to creating and executing -simple grammars, vs. the traditional lex/yacc approach, or the use of -regular expressions. The pyparsing module provides a library of classes -that client code uses to construct the grammar directly in Python code. - -Here is a program to parse "Hello, World!" (or any greeting of the form -", !"): - - from pyparsing import Word, alphas - greet = Word( alphas ) + "," + Word( alphas ) + "!" - hello = "Hello, World!" - print hello, "->", greet.parseString( hello ) - -The program outputs the following: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the -self-explanatory class names, and the use of '+', '|' and '^' operator -definitions. - -The parsed results returned from parseString() can be accessed as a -nested list, a dictionary, or an object with named attributes. - -The pyparsing module handles some of the problems that are typically -vexing when writing text parsers: -- extra or missing whitespace (the above program will also handle - "Hello,World!", "Hello , World !", etc.) -- quoted strings -- embedded comments - -The .zip file includes examples of a simple SQL parser, simple CORBA IDL -parser, a config file parser, a chemical formula parser, and a four- -function algebraic notation parser. It also includes a simple how-to -document, and a UML class diagram of the library's classes. - - - -Installation -============ - -Do the usual: - - python setup.py install - -(pyparsing requires Python 2.6 or later.) - -Or corresponding commands using pip, easy_install, or wheel: - - pip install pyparsing - - easy_install pyparsing - - wheel install pyparsing - - -Documentation -============= - -See: - - HowToUsePyparsing.html - - -License -======= - - MIT License. See header of pyparsing.py - -History -======= - - See CHANGES file. diff --git a/trunk/src/examples/0README.html b/trunk/src/examples/0README.html deleted file mode 100644 index 303d44d..0000000 --- a/trunk/src/examples/0README.html +++ /dev/null @@ -1,309 +0,0 @@ - -pyparsing Examples - -

pyparsing Examples

-

-This directory contains a number of Python scripts that can get you started in learning to use pyparsing. - -

    -
  • greeting.py
    -Parse "Hello, World!". -
  • -

    - -

  • greetingInKorean.py ~ submission by June Kim
    -Unicode example to parse "Hello, World!" in Korean. -
  • -

    - -

  • greetingInGreek.py ~ submission by ???
    -Unicode example to parse "Hello, World!" in Greek. -
  • -

    - -

  • holaMundo.py ~ submission by Marco Alfonso
    -"Hello, World!" example translated to Spanish, from Marco Alfonso's blog. -
  • -

    - -

  • chemicalFormulas.py
    -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. -
  • -

    - -

  • wordsToNum.py
    -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. -
  • -

    - -

  • pythonGrammarparser.py ~ suggested by JH Stovall
    -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. -
  • -

    - -

  • commasep.py
    -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(','). -
  • -

    - -

  • dictExample.py
    -A demonstration of using the Dict class, to parse a table of ASCII tabulated data. -
  • -

    - -

  • dictExample2.py ~ submission by Mike Kelly
    -An extended version of dictExample.py, in which Mike Kelly also parses the column headers, and generates a transposed version of the original table! -
  • -

    - -

  • scanExamples.py
    -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. -
  • -

    - -

  • urlExtractor.py
    -Another example using scanString, this time to extract all HREF references found on Yahoo!'s home page, and return them as a dictionary. -
  • -

    - -

  • makeHTMLTagExample.py
    -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. -
  • -

    - -

  • urlExtractorNew.py
    -Another updated version of urlExtractor.py, using the new makeHTMLTags() method. -
  • -

    - -

  • fourFn.py
    -A simple algebraic expression parser, that performs +,-,*,/, and ^ arithmetic operations. (With suggestions and bug-fixes graciously offered by Andrea Griffini.) -
  • -

    - -

  • SimpleCalc.py ~ submission by Steven Siew
    -An interactive version of fourFn.py, with support for variables. -
  • -

    - -

  • LAParser.py ~ submission by Mike Ellis
    -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. -
  • -

    - -

  • configParse.py
    -A simple alternative to Python's ConfigParse module, demonstrating the use of the Dict class to return nested dictionary access to configuration values. -
  • -

    - -

  • getNTPservers.py
    -Yet another scanString example, to read/extract the list of NTP servers from NIST's web site. -
  • -

    - -

  • getNTPserversNew.py
    -An updated version of getNTPservers.py, using the new makeHTMLTags() method. -
  • -

    - -

  • httpServerLogParser.py
    -Parser for Apache server log files. -
  • -

    - -

  • idlParse.py
    -Parser for CORBA IDL files. -
  • -

    - -

  • mozillaCalendarParser.py -~ submission by Petri Savolainen
    -Parser for Mozilla calendar (*.ics) files. -
  • -

    - -

  • pgn.py ~ submission by Alberto Santini
    -Parser for PGN (Portable Game Notation) files, the standard form for documenting the moves in chess games. -
  • -

    - -

  • simpleSQL.py
    -A simple parser that will extract table and column names from SQL SELECT statements.. -
  • -

    - -

  • dfmparse.py ~ submission by Dan Griffith
    -Parser for Delphi forms. -
  • -

    - -

  • ebnf.py / ebnftest.py ~ submission by Seo Sanghyeon
    -An EBNF-compiler that reads EBNF and generates a pyparsing grammar! Including a test that compiles... EBNF itself! -
  • -

    - -

  • searchparser.py ~ submission by Steven Mooij and Rudolph Froger
    -An expression parser that parses search strings, with special keyword and expression operations using (), not, and, or, and quoted strings. -
  • -

    - -

  • sparser.py ~ submission by Tim Cera
    -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. -

    -See mayport_florida_8720220_data_def.txt for an -example configuration file. -

  • -

    - -

  • romanNumerals.py
    -A Roman numeral generator and parser example, showing the power of parse actions -to compile Roman numerals into their integer values. -
  • -

    - -

  • removeLineBreaks.py
    -A string transformer that converts text files with hard line-breaks into one with line breaks -only between paragraphs. Useful when converting downloads from -Project Gutenberg 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. -

    -See Successful Methods of Public Speaking.txt and -Successful Methods of Public Speaking(2).txt for a sample -before and after (text file courtesy of Project Gutenberg). -

  • -

    - -

  • listAllMatches.py
    -An example program showing the utility of the listAllMatches option when specifying results naming. -
  • -

    - -

  • linenoExample.py
    -An example program showing how to use the string location to extract line and column numbers, or the -source line of text. -
  • -

    - -

  • parseListString.py
    -An example program showing a progression of steps, how to parse a string representation of a Python -list back into a true list. -
  • -

    - -

  • parsePythonValue.py
    -An extension of parseListString.py to parse tuples and dicts, including nested values, -returning a Python value of the original type. -
  • -

    - -

  • indentedGrammarExample.py
    -An example program showing how to parse a grammar using indentation for grouping, -such as is done in Python. -
  • -

    - -

  • simpleArith.py
    -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. -
  • -

    - -

  • simpleBool.py
    -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. -
  • -

    - -

  • simpleWiki.py
    -An example program showing how to use transformString to implement a simple Wiki markup parser. -
  • -

    - -

  • sql2dot.py~ submission by EnErGy [CSDX]
    -A nice graphing program that generates schema diagrams from SQL table definition statements. -
  • -

    - -

  • htmlStripper.py
    -An example implementation of a common application, removing HTML markup tags from an HTML page, -leaving just the text content. -
  • -

    - -

  • macroExpansion.py
    -An example implementation of a simple preprocessor, that will read embedded macro definitions -and replace macro references with the defined substitution string. -
  • -

    - -

  • sexpParser.py
    -A parser that uses a recursive grammar to parse S-expressions. -
  • -

    - -

  • nested.py
    -An example using nestedExpr, a helper method to simplify definitions of expressions of nested lists. -
  • -

    - -

  • withAttribute.py
    -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 <DIV> and <TD>. -
  • -

    - -

  • stackish.py
    -A parser for the data representation format, Stackish. -
  • -

    - -

  • builtin_parse_action_demo.py
    -New in version 1.5.7
    -Demonstration of using builtins (min, max, sum, len, etc.) as parse actions. -
  • -

    - -

  • antlr_grammar.py~ submission by Luca DellOlio
    -New in version 1.5.7
    -Pyparsing example parsing ANTLR .a files and generating a working pyparsing parser. -
  • -

    - -

  • shapes.py
    -New in version 1.5.7
    -Parse actions example simple shape definition syntax, and returning the matched tokens as -domain objects instead of just strings. -
  • -

    - -

  • datetimeParseActions.py
    -New in version 1.5.7
    -Parse actions example showing a parse action returning a datetime object instead of -string tokens, and doing validation of the tokens, raising a ParseException if the -given YYYY/MM/DD string does not represent a valid date. -
  • -

    - -

  • position.py
    -New in version 1.5.7
    -Demonstration of a couple of different ways to capture the location a particular -expression was found within the overall input string. -
  • -

    - - -

- - diff --git a/trunk/src/examples/AcManForm.dfm b/trunk/src/examples/AcManForm.dfm deleted file mode 100644 index db80f6a..0000000 --- a/trunk/src/examples/AcManForm.dfm +++ /dev/null @@ -1,885 +0,0 @@ -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/trunk/src/examples/LAparser.py b/trunk/src/examples/LAparser.py deleted file mode 100644 index ec75d6c..0000000 --- a/trunk/src/examples/LAparser.py +++ /dev/null @@ -1,417 +0,0 @@ -""" -Purpose: Linear Algebra Parser -Based on: SimpleCalc.py example (author Paul McGuire) in pyparsing-1.3.3 -Author: Mike Ellis -Copyright: Ellis & Grant, Inc. 2005 -License: You may freely use, modify, and distribute this software. -Warranty: THIS SOFTWARE HAS NO WARRANTY WHATSOEVER. USE AT YOUR OWN RISK. -Notes: Parses infix linear algebra (LA) notation for vectors, matrices, and scalars. - Output is C code function calls. The parser can be run as an interactive - interpreter or included as module to use for in-place substitution into C files - containing LA equations. - - Supported operations are: - OPERATION: INPUT OUTPUT - Scalar addition: "a = b+c" "a=(b+c)" - Scalar subtraction: "a = b-c" "a=(b-c)" - Scalar multiplication: "a = b*c" "a=b*c" - Scalar division: "a = b/c" "a=b/c" - Scalar exponentiation: "a = b^c" "a=pow(b,c)" - Vector scaling: "V3_a = V3_b * c" "vCopy(a,vScale(b,c))" - Vector addition: "V3_a = V3_b + V3_c" "vCopy(a,vAdd(b,c))" - Vector subtraction: "V3_a = V3_b - V3_c" "vCopy(a,vSubtract(b,c))" - Vector dot product: "a = V3_b * V3_c" "a=vDot(b,c)" - Vector outer product: "M3_a = V3_b @ V3_c" "a=vOuterProduct(b,c)" - Vector magn. squared: "a = V3_b^Mag2" "a=vMagnitude2(b)" - Vector magnitude: "a = V3_b^Mag" "a=sqrt(vMagnitude2(b))" - Matrix scaling: "M3_a = M3_b * c" "mCopy(a,mScale(b,c))" - Matrix addition: "M3_a = M3_b + M3_c" "mCopy(a,mAdd(b,c))" - Matrix subtraction: "M3_a = M3_b - M3_c" "mCopy(a,mSubtract(b,c))" - Matrix multiplication: "M3_a = M3_b * M3_c" "mCopy(a,mMultiply(b,c))" - Matrix by vector mult.: "V3_a = M3_b * V3_c" "vCopy(a,mvMultiply(b,c))" - Matrix inversion: "M3_a = M3_b^-1" "mCopy(a,mInverse(b))" - Matrix transpose: "M3_a = M3_b^T" "mCopy(a,mTranspose(b))" - Matrix determinant: "a = M3_b^Det" "a=mDeterminant(b)" - - The parser requires the expression to be an equation. Each non-scalar variable - must be prefixed with a type tag, 'M3_' for 3x3 matrices and 'V3_' for 3-vectors. - For proper compilation of the C code, the variables need to be declared without - the prefix as float[3] for vectors and float[3][3] for matrices. The operations do - not modify any variables on the right-hand side of the equation. - - Equations may include nested expressions within parentheses. The allowed binary - operators are '+-*/^' for scalars, and '+-*^@' for vectors and matrices with the - meanings defined in the table above. - - Specifying an improper combination of operands, e.g. adding a vector to a matrix, - is detected by the parser and results in a Python TypeError Exception. The usual cause - of this is omitting one or more tag prefixes. The parser knows nothing about a - a variable's C declaration and relies entirely on the type tags. Errors in C - declarations are not caught until compile time. - -Usage: To process LA equations embedded in source files, import this module and - pass input and output file objects to the fprocess() function. You can - can also invoke the parser from the command line, e.g. 'python LAparser.py', - to run a small test suite and enter an interactive loop where you can enter - LA equations and see the resulting C code. - -""" - -import re,os,sys -from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \ -, Combine, Optional, nums, Or, Forward, OneOrMore, ZeroOrMore, \ - FollowedBy, StringStart, StringEnd, alphanums -import math - -# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False" -debug_flag=False - -#---------------------------------------------------------------------------- -# Variables that hold intermediate parsing results and a couple of -# helper functions. -exprStack = [] # Holds operators and operands parsed from input. -targetvar = None # Holds variable name to left of '=' sign in LA equation. - - -def _pushFirst( str, loc, toks ): - if debug_flag: print("pushing ", toks[0], "str is ", str) - exprStack.append( toks[0] ) - -def _assignVar( str, loc, toks ): - global targetvar - targetvar = toks[0] - -#----------------------------------------------------------------------------- -# The following statements define the grammar for the parser. - -point = Literal('.') -e = CaselessLiteral('E') -plusorminus = Literal('+') | Literal('-') -number = Word(nums) -integer = Combine( Optional(plusorminus) + number ) -floatnumber = Combine( integer + - Optional( point + Optional(number) ) + - Optional( e + integer ) - ) - -lbracket = Literal("[") -rbracket = Literal("]") -ident = Forward() -## The definition below treats array accesses as identifiers. This means your expressions -## can include references to array elements, rows and columns, e.g., a = b[i] + 5. -## Expressions within []'s are not presently supported, so a = b[i+1] will raise -## a ParseException. -ident = Combine(Word(alphas + '-',alphanums + '_') + \ - ZeroOrMore(lbracket + (Word(alphas + '-',alphanums + '_')|integer) + rbracket) \ - ) - -plus = Literal( "+" ) -minus = Literal( "-" ) -mult = Literal( "*" ) -div = Literal( "/" ) -outer = Literal( "@" ) -lpar = Literal( "(" ).suppress() -rpar = Literal( ")" ).suppress() -addop = plus | minus -multop = mult | div | outer -expop = Literal( "^" ) -assignop = Literal( "=" ) - -expr = Forward() -atom = ( ( e | floatnumber | integer | ident ).setParseAction(_pushFirst) | - ( lpar + expr.suppress() + rpar ) - ) -factor = Forward() -factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( _pushFirst ) ) - -term = factor + ZeroOrMore( ( multop + factor ).setParseAction( _pushFirst ) ) -expr << term + ZeroOrMore( ( addop + term ).setParseAction( _pushFirst ) ) -equation = (ident + assignop).setParseAction(_assignVar) + expr + StringEnd() - -# End of grammar definition -#----------------------------------------------------------------------------- -## The following are helper variables and functions used by the Binary Infix Operator -## Functions described below. - -vprefix = 'V3_' -vplen = len(vprefix) -mprefix = 'M3_' -mplen = len(mprefix) - -## We don't support unary negation for vectors and matrices -class UnaryUnsupportedError(Exception): pass - -def _isvec(ident): - if ident[0] == '-' and ident[1:vplen+1] == vprefix: - raise UnaryUnsupportedError - else: return ident[0:vplen] == vprefix - -def _ismat(ident): - if ident[0] == '-' and ident[1:mplen+1] == mprefix: - raise UnaryUnsupportedError - else: return ident[0:mplen] == mprefix - -def _isscalar(ident): return not (_isvec(ident) or _ismat(ident)) - -## Binary infix operator (BIO) functions. These are called when the stack evaluator -## pops a binary operator like '+' or '*". The stack evaluator pops the two operand, a and b, -## and calls the function that is mapped to the operator with a and b as arguments. Thus, -## 'x + y' yields a call to addfunc(x,y). Each of the BIO functions checks the prefixes of its -## arguments to determine whether the operand is scalar, vector, or matrix. This information -## is used to generate appropriate C code. For scalars, this is essentially the input string, e.g. -## 'a + b*5' as input yields 'a + b*5' as output. For vectors and matrices, the input is translated to -## nested function calls, e.g. "V3_a + V3_b*5" yields "V3_vAdd(a,vScale(b,5)". Note that prefixes are -## stripped from operands and function names within the argument list to the outer function and -## the appropriate prefix is placed on the outer function for removal later as the stack evaluation -## recurses toward the final assignment statement. - -def _addfunc(a,b): - if _isscalar(a) and _isscalar(b): return "(%s+%s)"%(a,b) - if _isvec(a) and _isvec(b): return "%svAdd(%s,%s)"%(vprefix,a[vplen:],b[vplen:]) - if _ismat(a) and _ismat(b): return "%smAdd(%s,%s)"%(mprefix,a[mplen:],b[mplen:]) - else: raise TypeError - -def _subfunc(a,b): - if _isscalar(a) and _isscalar(b): return "(%s-%s)"%(a,b) - if _isvec(a) and _isvec(b): return "%svSubtract(%s,%s)"%(vprefix,a[vplen:],b[vplen:]) - if _ismat(a) and _ismat(b): return "%smSubtract(%s,%s)"%(mprefix,a[mplen:],b[mplen:]) - else: raise TypeError - -def _mulfunc(a,b): - if _isscalar(a) and _isscalar(b): return "%s*%s"%(a,b) - if _isvec(a) and _isvec(b): return "vDot(%s,%s)"%(a[vplen:],b[vplen:]) - if _ismat(a) and _ismat(b): return "%smMultiply(%s,%s)"%(mprefix,a[mplen:],b[mplen:]) - if _ismat(a) and _isvec(b): return "%smvMultiply(%s,%s)"%(vprefix,a[mplen:],b[vplen:]) - if _ismat(a) and _isscalar(b): return "%smScale(%s,%s)"%(mprefix,a[mplen:],b) - if _isvec(a) and _isscalar(b): return "%svScale(%s,%s)"%(vprefix,a[mplen:],b) - else: raise TypeError - -def _outermulfunc(a,b): - ## The '@' operator is used for the vector outer product. - if _isvec(a) and _isvec(b): - return "%svOuterProduct(%s,%s)"%(mprefix,a[vplen:],b[vplen:]) - else: raise TypeError - -def _divfunc(a,b): - ## The '/' operator is used only for scalar division - if _isscalar(a) and _isscalar(b): return "%s/%s"%(a,b) - else: raise TypeError - -def _expfunc(a,b): - ## The '^' operator is used for exponentiation on scalars and - ## as a marker for unary operations on vectors and matrices. - if _isscalar(a) and _isscalar(b): return "pow(%s,%s)"%(str(a),str(b)) - if _ismat(a) and b=='-1': return "%smInverse(%s)"%(mprefix,a[mplen:]) - if _ismat(a) and b=='T': return "%smTranspose(%s)"%(mprefix,a[mplen:]) - if _ismat(a) and b=='Det': return "mDeterminant(%s)"%(a[mplen:]) - if _isvec(a) and b=='Mag': return "sqrt(vMagnitude2(%s))"%(a[vplen:]) - if _isvec(a) and b=='Mag2': return "vMagnitude2(%s)"%(a[vplen:]) - else: raise TypeError - -def _assignfunc(a,b): - ## The '=' operator is used for assignment - if _isscalar(a) and _isscalar(b): return "%s=%s"%(a,b) - if _isvec(a) and _isvec(b): return "vCopy(%s,%s)"%(a[vplen:],b[vplen:]) - if _ismat(a) and _ismat(b): return "mCopy(%s,%s)"%(a[mplen:],b[mplen:]) - else: raise TypeError - -## End of BIO func definitions -##---------------------------------------------------------------------------- - -# Map operator symbols to corresponding BIO funcs -opn = { "+" : ( _addfunc ), - "-" : ( _subfunc ), - "*" : ( _mulfunc ), - "@" : ( _outermulfunc ), - "/" : ( _divfunc), - "^" : ( _expfunc ), } - - -##---------------------------------------------------------------------------- -# Recursive function that evaluates the expression stack -def _evaluateStack( s ): - op = s.pop() - if op in "+-*/@^": - op2 = _evaluateStack( s ) - op1 = _evaluateStack( s ) - result = opn[op]( op1, op2 ) - if debug_flag: print(result) - return result - else: - return op - -##---------------------------------------------------------------------------- -# The parse function that invokes all of the above. -def parse(input_string): - """ - Accepts an input string containing an LA equation, e.g., - "M3_mymatrix = M3_anothermatrix^-1" returns C code function - calls that implement the expression. - """ - - global exprStack - global targetvar - - # Start with a blank exprStack and a blank targetvar - exprStack = [] - targetvar=None - - if input_string != '': - # try parsing the input string - try: - L=equation.parseString( input_string ) - except ParseException as err: - print('Parse Failure', file=sys.stderr) - print(err.line, file=sys.stderr) - print(" "*(err.column-1) + "^", file=sys.stderr) - print(err, file=sys.stderr) - raise - - # show result of parsing the input string - if debug_flag: - print(input_string, "->", L) - print("exprStack=", exprStack) - - # Evaluate the stack of parsed operands, emitting C code. - try: - result=_evaluateStack(exprStack) - except TypeError: - print("Unsupported operation on right side of '%s'.\nCheck for missing or incorrect tags on non-scalar operands."%input_string, file=sys.stderr) - raise - except UnaryUnsupportedError: - print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr) - raise - - # Create final assignment and print it. - if debug_flag: print("var=",targetvar) - if targetvar != None: - try: - result = _assignfunc(targetvar,result) - except TypeError: - print("Left side tag does not match right side of '%s'"%input_string, file=sys.stderr) - raise - except UnaryUnsupportedError: - print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr) - raise - - return result - else: - print("Empty left side in '%s'"%input_string, file=sys.stderr) - raise TypeError - -##----------------------------------------------------------------------------------- -def fprocess(infilep,outfilep): - """ - Scans an input file for LA equations between double square brackets, - e.g. [[ M3_mymatrix = M3_anothermatrix^-1 ]], and replaces the expression - with a comment containing the equation followed by nested function calls - that implement the equation as C code. A trailing semi-colon is appended. - The equation within [[ ]] should NOT end with a semicolon as that will raise - a ParseException. However, it is ok to have a semicolon after the right brackets. - - Other text in the file is unaltered. - - The arguments are file objects (NOT file names) opened for reading and - writing, respectively. - """ - pattern = r'\[\[\s*(.*?)\s*\]\]' - eqn = re.compile(pattern,re.DOTALL) - s = infilep.read() - def parser(mo): - ccode = parse(mo.group(1)) - return "/* %s */\n%s;\nLAParserBufferReset();\n"%(mo.group(1),ccode) - - content = eqn.sub(parser,s) - outfilep.write(content) - -##----------------------------------------------------------------------------------- -def test(): - """ - Tests the parsing of various supported expressions. Raises - an AssertError if the output is not what is expected. Prints the - input, expected output, and actual output for all tests. - """ - print("Testing LAParser") - testcases = [ - ("Scalar addition","a = b+c","a=(b+c)"), - ("Vector addition","V3_a = V3_b + V3_c","vCopy(a,vAdd(b,c))"), - ("Vector addition","V3_a=V3_b+V3_c","vCopy(a,vAdd(b,c))"), - ("Matrix addition","M3_a = M3_b + M3_c","mCopy(a,mAdd(b,c))"), - ("Matrix addition","M3_a=M3_b+M3_c","mCopy(a,mAdd(b,c))"), - ("Scalar subtraction","a = b-c","a=(b-c)"), - ("Vector subtraction","V3_a = V3_b - V3_c","vCopy(a,vSubtract(b,c))"), - ("Matrix subtraction","M3_a = M3_b - M3_c","mCopy(a,mSubtract(b,c))"), - ("Scalar multiplication","a = b*c","a=b*c"), - ("Scalar division","a = b/c","a=b/c"), - ("Vector multiplication (dot product)","a = V3_b * V3_c","a=vDot(b,c)"), - ("Vector multiplication (outer product)","M3_a = V3_b @ V3_c","mCopy(a,vOuterProduct(b,c))"), - ("Matrix multiplication","M3_a = M3_b * M3_c","mCopy(a,mMultiply(b,c))"), - ("Vector scaling","V3_a = V3_b * c","vCopy(a,vScale(b,c))"), - ("Matrix scaling","M3_a = M3_b * c","mCopy(a,mScale(b,c))"), - ("Matrix by vector multiplication","V3_a = M3_b * V3_c","vCopy(a,mvMultiply(b,c))"), - ("Scalar exponentiation","a = b^c","a=pow(b,c)"), - ("Matrix inversion","M3_a = M3_b^-1","mCopy(a,mInverse(b))"), - ("Matrix transpose","M3_a = M3_b^T","mCopy(a,mTranspose(b))"), - ("Matrix determinant","a = M3_b^Det","a=mDeterminant(b)"), - ("Vector magnitude squared","a = V3_b^Mag2","a=vMagnitude2(b)"), - ("Vector magnitude","a = V3_b^Mag","a=sqrt(vMagnitude2(b))"), - ("Complicated expression", "myscalar = (M3_amatrix * V3_bvector)^Mag + 5*(-xyz[i] + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(-xyz[i]+pow(2.03,2)))"), - ("Complicated Multiline", "myscalar = \n(M3_amatrix * V3_bvector)^Mag +\n 5*(xyz + 2.03^2)","myscalar=(sqrt(vMagnitude2(mvMultiply(amatrix,bvector)))+5*(xyz+pow(2.03,2)))") - - ] - - for t in testcases: - name,input,expected = t - print(name) - print(" %s input"%input) - print(" %s expected"%expected) - result = parse(input) - print(" %s received"%result) - print("") - assert expected == result - - ##TODO: Write testcases with invalid expressions and test that the expected - ## exceptions are raised. - - print("Tests completed!") -##---------------------------------------------------------------------------- -## The following is executed only when this module is executed as -## command line script. It runs a small test suite (see above) -## and then enters an interactive loop where you -## can enter expressions and see the resulting C code as output. - -if __name__ == '__main__': - # run testcases - test() - - # input_string - input_string='' - - # Display instructions on how to use the program interactively - interactiveusage = """ - Entering interactive mode: - Type in an equation to be parsed or 'quit' to exit the program. - Type 'debug on' to print parsing details as each string is processed. - Type 'debug off' to stop printing parsing details - """ - print(interactiveusage) - input_string = input("> ") - - while input_string != 'quit': - if input_string == "debug on": - debug_flag = True - elif input_string == "debug off": - debug_flag = False - else: - try: - print(parse(input_string)) - except: - pass - - # obtain new input string - input_string = input("> ") - - # if user types 'quit' then say goodbye - print("Good bye!") - - diff --git a/trunk/src/examples/Setup.ini b/trunk/src/examples/Setup.ini deleted file mode 100644 index 4574b1c..0000000 --- a/trunk/src/examples/Setup.ini +++ /dev/null @@ -1,73 +0,0 @@ -[Startup] -AppName=M3i.comm -stname = Utility -modemid=125D&DEV_1999 -audioid=125D&DEV_1998 -win98path= -winmepath= -win2kpath= -winxppath= -win95path= -winnt4path= - -stupgrade =Install/Upgrade Drivers -stuninstall =Uninstall Drivers -stchoose =Choose One Function to Process -stchoosez3 =Choose Devices to Process - -copycompl =Copying files completed - -RemString1=Set up has finished remove ESS device driver and cleaned your system. Click Finish to exit. -RemString2=ESS devices is removed completely.No need to reboot. If you want to reinstall, run the setup again with driver package. -stshowmsg1=Setup will clean the installed files and update registry. -stshowmsg2=Setup is updating system's registry .... -stshowmsg3=Setup is starting - -sysdriver=es56cvmp.sys -mdmzn=mdmm3com.inf -mdmznp=esmdm_98.inf -mdmzna=mdmessa.inf -spkname=essspk.exe -remvess=remvess.exe -slmcat=allem3m.cat -audiocat=allem3.cat -audioinf=M3i -sysaudio=es198xdl.sys -audiovxd=es198x.vxd - -[Languages] -Default=0x0009 -count=30 -key0=0x002d -key1=0x0003 -key2=0x0804 -key3=0x0404 -key4=0x001a -key5=0x0005 -key6=0x0006 -key7=0x0013 -key8=0x0009 -key9=0x000b -key10=0x0c0c -key11=0x040c -key12=0x0007 -key13=0x0008 -key14=0x000e -key15=0x0021 -key16=0x0010 -key17=0x0011 -key18=0x0012 -key19=0x0014 -key20=0x0015 -key21=0x0416 -key22=0x0816 -key23=0x0019 -key24=0x001b -key25=0x0024 -key26=0x000a -key27=0x001d -key28=0x001e -key29=0x001f - -[test] -foo=bar diff --git a/trunk/src/examples/SimpleCalc.py b/trunk/src/examples/SimpleCalc.py deleted file mode 100644 index 46a5dff..0000000 --- a/trunk/src/examples/SimpleCalc.py +++ /dev/null @@ -1,118 +0,0 @@ -# SimpleCalc.py -# -# Demonstration of the parsing module, -# Sample usage -# -# $ python SimpleCalc.py -# Type in the string to be parse or 'quit' to exit the program -# > g=67.89 + 7/5 -# 69.29 -# > g -# 69.29 -# > h=(6*g+8.8)-g -# 355.25 -# > h + 1 -# 356.25 -# > 87.89 + 7/5 -# 89.29 -# > ans+10 -# 99.29 -# > quit -# Good bye! -# -# - - - -# Uncomment the line below for readline support on interactive terminal -# import readline -from pyparsing import ParseException, Word, alphas, alphanums -import math - -# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False" -debug_flag=False - -variables = {} - -from fourFn import BNF, exprStack, fn, opn -def evaluateStack( s ): - op = s.pop() - if op == 'unary -': - return -evaluateStack( s ) - if op in "+-*/^": - op2 = evaluateStack( s ) - op1 = evaluateStack( s ) - return opn[op]( op1, op2 ) - elif op == "PI": - return math.pi # 3.1415926535 - elif op == "E": - return math.e # 2.718281828 - elif op in fn: - return fn[op]( evaluateStack( s ) ) - elif op[0].isalpha(): - if op in variables: - return variables[op] - raise Exception("invalid identifier '%s'" % op) - else: - return float( op ) - -arithExpr = BNF() -ident = Word(alphas, alphanums).setName("identifier") -assignment = ident("varname") + '=' + arithExpr -pattern = assignment | arithExpr - -if __name__ == '__main__': - # input_string - input_string='' - - # Display instructions on how to quit the program - print("Type in the string to be parsed or 'quit' to exit the program") - input_string = input("> ") - - while input_string != 'quit': - if input_string.lower() == 'debug': - debug_flag=True - input_string = input("> ") - continue - - # Reset to an empty exprStack - del exprStack[:] - - if input_string != '': - # try parsing the input string - try: - L=pattern.parseString( input_string, parseAll=True ) - except ParseException as err: - L=['Parse Failure',input_string] - - # show result of parsing the input string - if debug_flag: print(input_string, "->", L) - if len(L)==0 or L[0] != 'Parse Failure': - if debug_flag: print("exprStack=", exprStack) - - # calculate result , store a copy in ans , display the result to user - try: - result=evaluateStack(exprStack) - except Exception as e: - print(str(e)) - else: - variables['ans']=result - print(result) - - # Assign result to a variable if required - if L.varname: - variables[L.varname] = result - if debug_flag: print("variables=",variables) - else: - print('Parse Failure') - print(err.line) - print(" "*(err.column-1) + "^") - print(err) - - # obtain new input string - input_string = input("> ") - - # if user type 'quit' then say goodbye - print("Good bye!") - - diff --git a/trunk/src/examples/SingleForm.dfm b/trunk/src/examples/SingleForm.dfm deleted file mode 100644 index 7a52734..0000000 --- a/trunk/src/examples/SingleForm.dfm +++ /dev/null @@ -1,751 +0,0 @@ -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/trunk/src/examples/TAP.py b/trunk/src/examples/TAP.py deleted file mode 100644 index 139e47c..0000000 --- a/trunk/src/examples/TAP.py +++ /dev/null @@ -1,217 +0,0 @@ -# -# TAP.py - TAP parser -# -# A pyparsing parser to process the output of the Perl -# "Test Anything Protocol" -# (http://search.cpan.org/~petdance/TAP-1.00/TAP.pm) -# -# TAP output lines are preceded or followed by a test number range: -# 1..n -# with 'n' TAP output lines. -# -# The general format of a TAP output line is: -# ok/not ok (required) -# Test number (recommended) -# Description (recommended) -# Directive (only when necessary) -# -# A TAP output line may also indicate abort of the test suit with the line: -# Bail out! -# optionally followed by a reason for bailing -# -# Copyright 2008, by Paul McGuire -# - -from pyparsing import ParserElement,LineEnd,Optional,Word,nums,Regex,\ - Literal,CaselessLiteral,Group,OneOrMore,Suppress,restOfLine,\ - FollowedBy,empty - -__all__ = ['tapOutputParser', 'TAPTest', 'TAPSummary'] - -# newlines are significant whitespace, so set default skippable -# whitespace to just spaces and tabs -ParserElement.setDefaultWhitespaceChars(" \t") -NL = LineEnd().suppress() - -integer = Word(nums) -plan = '1..' + integer("ubound") - -OK,NOT_OK = map(Literal,['ok','not ok']) -testStatus = (OK | NOT_OK) - -description = Regex("[^#\n]+") -description.setParseAction(lambda t:t[0].lstrip('- ')) - -TODO,SKIP = map(CaselessLiteral,'TODO SKIP'.split()) -directive = Group(Suppress('#') + (TODO + restOfLine | - FollowedBy(SKIP) + - restOfLine.copy().setParseAction(lambda t:['SKIP',t[0]]) )) - -commentLine = Suppress("#") + empty + restOfLine - -testLine = Group( - Optional(OneOrMore(commentLine + NL))("comments") + - testStatus("passed") + - Optional(integer)("testNumber") + - Optional(description)("description") + - Optional(directive)("directive") - ) -bailLine = Group(Literal("Bail out!")("BAIL") + - empty + Optional(restOfLine)("reason")) - -tapOutputParser = Optional(Group(plan)("plan") + NL) & \ - Group(OneOrMore((testLine|bailLine) + NL))("tests") - -class TAPTest(object): - def __init__(self,results): - self.num = results.testNumber - self.passed = (results.passed=="ok") - self.skipped = self.todo = False - if results.directive: - self.skipped = (results.directive[0][0]=='SKIP') - self.todo = (results.directive[0][0]=='TODO') - @classmethod - def bailedTest(cls,num): - ret = TAPTest(empty.parseString("")) - ret.num = num - ret.skipped = True - return ret - -class TAPSummary(object): - def __init__(self,results): - self.passedTests = [] - self.failedTests = [] - self.skippedTests = [] - self.todoTests = [] - self.bonusTests = [] - self.bail = False - if results.plan: - expected = list(range(1, int(results.plan.ubound)+1)) - else: - expected = list(range(1,len(results.tests)+1)) - - for i,res in enumerate(results.tests): - # test for bail out - if res.BAIL: - #~ print "Test suite aborted: " + res.reason - #~ self.failedTests += expected[i:] - self.bail = True - self.skippedTests += [ TAPTest.bailedTest(ii) for ii in expected[i:] ] - self.bailReason = res.reason - break - - #~ print res.dump() - testnum = i+1 - if res.testNumber != "": - if testnum != int(res.testNumber): - print("ERROR! test %(testNumber)s out of sequence" % res) - testnum = int(res.testNumber) - res["testNumber"] = testnum - - test = TAPTest(res) - if test.passed: - self.passedTests.append(test) - else: - self.failedTests.append(test) - if test.skipped: self.skippedTests.append(test) - if test.todo: self.todoTests.append(test) - if test.todo and test.passed: self.bonusTests.append(test) - - self.passedSuite = not self.bail and (set(self.failedTests)-set(self.todoTests) == set()) - - def summary(self, showPassed=False, showAll=False): - testListStr = lambda tl : "[" + ",".join(str(t.num) for t in tl) + "]" - summaryText = [] - if showPassed or showAll: - summaryText.append( "PASSED: %s" % testListStr(self.passedTests) ) - if self.failedTests or showAll: - summaryText.append( "FAILED: %s" % testListStr(self.failedTests) ) - if self.skippedTests or showAll: - summaryText.append( "SKIPPED: %s" % testListStr(self.skippedTests) ) - if self.todoTests or showAll: - summaryText.append( "TODO: %s" % testListStr(self.todoTests) ) - if self.bonusTests or showAll: - summaryText.append( "BONUS: %s" % testListStr(self.bonusTests) ) - if self.passedSuite: - summaryText.append( "PASSED" ) - else: - summaryText.append( "FAILED" ) - return "\n".join(summaryText) - -# create TAPSummary objects from tapOutput parsed results, by setting -# class as parse action -tapOutputParser.setParseAction(TAPSummary) - - -if __name__ == "__main__": - test1 = """\ - 1..4 - ok 1 - Input file opened - not ok 2 - First line of the input valid - ok 3 - Read the rest of the file - not ok 4 - Summarized correctly # TODO Not written yet - """ - test2 = """\ - ok 1 - not ok 2 some description # TODO with a directive - ok 3 a description only, no directive - ok 4 # TODO directive only - ok a description only, no directive - ok # Skipped only a directive, no description - ok - """ - test3 = """\ - ok - created Board - ok - ok - not ok - ok - ok - ok - ok - # +------+------+------+------+ - # | |16G | |05C | - # | |G N C | |C C G | - # | | G | | C +| - # +------+------+------+------+ - # |10C |01G | |03C | - # |R N G |G A G | |C C C | - # | R | G | | C +| - # +------+------+------+------+ - # | |01G |17C |00C | - # | |G A G |G N R |R N R | - # | | G | R | G | - # +------+------+------+------+ - ok - board has 7 tiles + starter tile - 1..9 - """ - test4 = """\ - 1..4 - ok 1 - Creating test program - ok 2 - Test program runs, no error - not ok 3 - infinite loop # TODO halting problem unsolved - not ok 4 - infinite loop 2 # TODO halting problem unsolved - """ - test5 = """\ - 1..20 - ok - database handle - not ok - failed database login - Bail out! Couldn't connect to database. - """ - test6 = """\ - ok 1 - retrieving servers from the database - # need to ping 6 servers - ok 2 - pinged diamond - ok 3 - pinged ruby - not ok 4 - pinged sapphire - ok 5 - pinged onyx - not ok 6 - pinged quartz - ok 7 - pinged gold - 1..7 - """ - - for test in (test1,test2,test3,test4,test5,test6): - print(test) - tapResult = tapOutputParser.parseString(test)[0] - print(tapResult.summary(showAll=True)) - print() diff --git a/trunk/src/examples/__init__.py b/trunk/src/examples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/trunk/src/examples/adventureEngine.py b/trunk/src/examples/adventureEngine.py deleted file mode 100644 index be09770..0000000 --- a/trunk/src/examples/adventureEngine.py +++ /dev/null @@ -1,648 +0,0 @@ -# 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("") - self.desc = "broken " + self.desc - self.isBroken = True - - def isUsable(self, player, target): - if self.usableConditionTest: - return self.usableConditionTest( player, target ) - else: - return False - - def useItem(self, player, target): - if self.useAction: - self.useAction(player, self, target) - -class OpenableItem(Item): - def __init__(self, desc, contents=None): - super(OpenableItem,self).__init__(desc) - self.isOpenable = True - self.isOpened = False - if contents is not None: - if isinstance(contents, Item): - self.contents = [contents,] - else: - self.contents = contents - else: - self.contents = [] - - def openItem(self, player): - if not self.isOpened: - self.isOpened = not self.isOpened - if self.contents is not None: - for item in self.contents: - player.room.addItem( item ) - self.contents = [] - self.desc = "open " + self.desc - - def closeItem(self, player): - if self.isOpened: - self.isOpened = not self.isOpened - if self.desc.startswith("open "): - self.desc = self.desc[5:] - - -class Command(object): - "Base class for commands" - def __init__(self, verb, verbProg): - self.verb = verb - self.verbProg = verbProg - - @staticmethod - def helpDescription(): - return "" - - def _doCommand(self, player): - pass - - def __call__(self, player ): - print(self.verbProg.capitalize()+"...") - self._doCommand(player) - - -class MoveCommand(Command): - def __init__(self, quals): - super(MoveCommand,self).__init__("MOVE", "moving") - self.direction = quals.direction[0] - - @staticmethod - def helpDescription(): - return """MOVE or GO - go NORTH, SOUTH, EAST, or WEST - (can abbreviate as 'GO N' and 'GO W', or even just 'E' and 'S')""" - - def _doCommand(self, player): - rm = player.room - nextRoom = rm.doors[ - { - "N":0, - "S":1, - "E":2, - "W":3, - }[self.direction] - ] - if nextRoom: - player.moveTo( nextRoom ) - else: - print("Can't go that way.") - - -class TakeCommand(Command): - def __init__(self, quals): - super(TakeCommand,self).__init__("TAKE", "taking") - self.subject = quals.item - - @staticmethod - def helpDescription(): - return "TAKE or PICKUP or PICK UP - pick up an object (but some are deadly)" - - def _doCommand(self, player): - rm = player.room - subj = Item.items[self.subject] - if subj in rm.inv and subj.isVisible: - if subj.isTakeable: - rm.removeItem(subj) - player.take(subj) - else: - print(subj.cantTakeMessage) - else: - print("There is no %s here." % subj) - - -class DropCommand(Command): - def __init__(self, quals): - super(DropCommand,self).__init__("DROP", "dropping") - self.subject = quals.item - - @staticmethod - def helpDescription(): - return "DROP or LEAVE - drop an object (but fragile items may break)" - - def _doCommand(self, player): - rm = player.room - subj = Item.items[self.subject] - if subj in player.inv: - rm.addItem(subj) - player.drop(subj) - else: - print("You don't have %s." % (aOrAn(subj))) - -class InventoryCommand(Command): - def __init__(self, quals): - super(InventoryCommand,self).__init__("INV", "taking inventory") - - @staticmethod - def helpDescription(): - return "INVENTORY or INV or I - lists what items you have" - - def _doCommand(self, player): - print("You have %s." % enumerateItems( player.inv )) - -class LookCommand(Command): - def __init__(self, quals): - super(LookCommand,self).__init__("LOOK", "looking") - - @staticmethod - def helpDescription(): - return "LOOK or L - describes the current room and any objects in it" - - def _doCommand(self, player): - player.room.describe() - -class DoorsCommand(Command): - def __init__(self, quals): - super(DoorsCommand,self).__init__("DOORS", "looking for doors") - - @staticmethod - def helpDescription(): - return "DOORS - display what doors are visible from this room" - - def _doCommand(self, player): - rm = player.room - numDoors = sum([1 for r in rm.doors if r is not None]) - if numDoors == 0: - reply = "There are no doors in any direction." - else: - if numDoors == 1: - reply = "There is a door to the " - else: - reply = "There are doors to the " - doorNames = [ {0:"north", 1:"south", 2:"east", 3:"west"}[i] - for i,d in enumerate(rm.doors) if d is not None ] - #~ print doorNames - reply += enumerateDoors( doorNames ) - reply += "." - print(reply) - -class UseCommand(Command): - def __init__(self, quals): - super(UseCommand,self).__init__("USE", "using") - self.subject = Item.items[quals.usedObj] - if quals.targetObj: - self.target = Item.items[quals.targetObj] - else: - self.target = None - - @staticmethod - def helpDescription(): - return "USE or U - use an object, optionally IN or ON another object" - - def _doCommand(self, player): - rm = player.room - availItems = rm.inv + player.inv - if self.subject in availItems: - if self.subject.isUsable( player, self.target ): - self.subject.useItem( player, self.target ) - else: - print("You can't use that here.") - else: - print("There is no %s here to use." % self.subject) - -class OpenCommand(Command): - def __init__(self, quals): - super(OpenCommand,self).__init__("OPEN", "opening") - self.subject = Item.items[quals.item] - - @staticmethod - def helpDescription(): - return "OPEN or O - open an object" - - def _doCommand(self, player): - rm = player.room - availItems = rm.inv+player.inv - if self.subject in availItems: - if self.subject.isOpenable: - if not self.subject.isOpened: - self.subject.openItem( player ) - else: - print("It's already open.") - else: - print("You can't open that.") - else: - print("There is no %s here to open." % self.subject) - -class CloseCommand(Command): - def __init__(self, quals): - super(CloseCommand,self).__init__("CLOSE", "closing") - self.subject = Item.items[quals.item] - - @staticmethod - def helpDescription(): - return "CLOSE or CL - close an object" - - def _doCommand(self, player): - rm = player.room - availItems = rm.inv+player.inv - if self.subject in availItems: - if self.subject.isOpenable: - if self.subject.isOpened: - self.subject.closeItem( player ) - else: - print("You can't close that, it's not open.") - else: - print("You can't close that.") - else: - print("There is no %s here to close." % self.subject) - -class QuitCommand(Command): - def __init__(self, quals): - super(QuitCommand,self).__init__("QUIT", "quitting") - - @staticmethod - def helpDescription(): - return "QUIT or Q - ends the game" - - def _doCommand(self, player): - print("Ok....") - player.gameOver = True - -class HelpCommand(Command): - def __init__(self, quals): - super(HelpCommand,self).__init__("HELP", "helping") - - @staticmethod - def helpDescription(): - return "HELP or H or ? - displays this help message" - - def _doCommand(self, player): - print("Enter any of the following commands (not case sensitive):") - for cmd in [ - InventoryCommand, - DropCommand, - TakeCommand, - UseCommand, - OpenCommand, - CloseCommand, - MoveCommand, - LookCommand, - DoorsCommand, - QuitCommand, - HelpCommand, - ]: - print(" - %s" % cmd.helpDescription()) - print() - -class AppParseException(ParseException): - pass - -class Parser(object): - def __init__(self): - self.bnf = self.makeBNF() - - def makeBNF(self): - invVerb = oneOf("INV INVENTORY I", caseless=True) - dropVerb = oneOf("DROP LEAVE", caseless=True) - takeVerb = oneOf("TAKE PICKUP", caseless=True) | \ - (CaselessLiteral("PICK") + CaselessLiteral("UP") ) - moveVerb = oneOf("MOVE GO", caseless=True) | empty - useVerb = oneOf("USE U", caseless=True) - openVerb = oneOf("OPEN O", caseless=True) - closeVerb = oneOf("CLOSE CL", caseless=True) - quitVerb = oneOf("QUIT Q", caseless=True) - lookVerb = oneOf("LOOK L", caseless=True) - doorsVerb = CaselessLiteral("DOORS") - helpVerb = oneOf("H HELP ?",caseless=True) - - itemRef = OneOrMore(Word(alphas)).setParseAction( self.validateItemName ) - nDir = oneOf("N NORTH",caseless=True).setParseAction(replaceWith("N")) - sDir = oneOf("S SOUTH",caseless=True).setParseAction(replaceWith("S")) - eDir = oneOf("E EAST",caseless=True).setParseAction(replaceWith("E")) - wDir = oneOf("W WEST",caseless=True).setParseAction(replaceWith("W")) - moveDirection = nDir | sDir | eDir | wDir - - invCommand = invVerb - dropCommand = dropVerb + itemRef("item") - takeCommand = takeVerb + itemRef("item") - useCommand = useVerb + itemRef("usedObj") + \ - Optional(oneOf("IN ON",caseless=True)) + \ - Optional(itemRef,default=None)("targetObj") - openCommand = openVerb + itemRef("item") - closeCommand = closeVerb + itemRef("item") - moveCommand = moveVerb + moveDirection("direction") - quitCommand = quitVerb - lookCommand = lookVerb - doorsCommand = doorsVerb - helpCommand = helpVerb - - # attach command classes to expressions - invCommand.setParseAction(InventoryCommand) - dropCommand.setParseAction(DropCommand) - takeCommand.setParseAction(TakeCommand) - useCommand.setParseAction(UseCommand) - openCommand.setParseAction(OpenCommand) - closeCommand.setParseAction(CloseCommand) - moveCommand.setParseAction(MoveCommand) - quitCommand.setParseAction(QuitCommand) - lookCommand.setParseAction(LookCommand) - doorsCommand.setParseAction(DoorsCommand) - helpCommand.setParseAction(HelpCommand) - - # define parser using all command expressions - return ( invCommand | - useCommand | - openCommand | - closeCommand | - dropCommand | - takeCommand | - moveCommand | - lookCommand | - doorsCommand | - helpCommand | - quitCommand )("command") + LineEnd() - - def validateItemName(self,s,l,t): - iname = " ".join(t) - if iname not in Item.items: - raise AppParseException(s,l,"No such item '%s'." % iname) - return iname - - def parseCmd(self, cmdstr): - try: - ret = self.bnf.parseString(cmdstr) - return ret - except AppParseException as pe: - print(pe.msg) - except ParseException as pe: - print(random.choice([ "Sorry, I don't understand that.", - "Huh?", - "Excuse me?", - "???", - "What?" ] )) - -class Player(object): - def __init__(self, name): - self.name = name - self.gameOver = False - self.inv = [] - - def moveTo(self, rm): - self.room = rm - rm.enter(self) - if self.gameOver: - if rm.desc: - rm.describe() - print("Game over!") - else: - rm.describe() - - def take(self,it): - if it.isDeadly: - print("Aaaagh!...., the %s killed me!" % it) - self.gameOver = True - else: - self.inv.append(it) - - def drop(self,it): - self.inv.remove(it) - if it.isFragile: - it.breakItem() - - -def createRooms( rm ): - """ - create rooms, using multiline string showing map layout - string contains symbols for the following: - A-Z, a-z indicate rooms, and rooms will be stored in a dictionary by - reference letter - -, | symbols indicate connection between rooms - <, >, ^, . symbols indicate one-way connection between rooms - """ - # start with empty dictionary of rooms - ret = {} - - # look for room symbols, and initialize dictionary - # - exit room is always marked 'Z' - for c in rm: - if c in string.ascii_letters: - if c != "Z": - ret[c] = Room(c) - else: - ret[c] = Exit() - - # scan through input string looking for connections between rooms - rows = rm.split("\n") - for row,line in enumerate(rows): - for col,c in enumerate(line): - if c in string.ascii_letters: - room = ret[c] - n = None - s = None - e = None - w = None - - # look in neighboring cells for connection symbols (must take - # care to guard that neighboring cells exist before testing - # contents) - if col > 0 and line[col-1] in "<-": - other = line[col-2] - w = ret[other] - if col < len(line)-1 and line[col+1] in "->": - other = line[col+2] - e = ret[other] - if row > 1 and col < len(rows[row-1]) and rows[row-1][col] in '|^': - other = rows[row-2][col] - n = ret[other] - if row < len(rows)-1 and col < len(rows[row+1]) and rows[row+1][col] in '|.': - other = rows[row+2][col] - s = ret[other] - - # set connections to neighboring rooms - room.doors=[n,s,e,w] - - return ret - -# put items in rooms -def putItemInRoom(i,r): - if isinstance(r,str): - r = rooms[r] - r.addItem( Item.items[i] ) - -def playGame(p,startRoom): - # create parser - parser = Parser() - p.moveTo( startRoom ) - while not p.gameOver: - cmdstr = input(">> ") - cmd = parser.parseCmd(cmdstr) - if cmd is not None: - cmd.command( p ) - print() - print("You ended the game with:") - for i in p.inv: - print(" -", aOrAn(i)) - - -#==================== -# start game definition -roomMap = """ - d-Z - | - f-c-e - . | - q'+"'")) | ('u' + Word(hexnums, exact=4)) | Word(printables, exact=1)) -LITERAL_CHAR = ESC | ~(Literal("'") | Literal('\\')) + Word(printables, exact=1) -CHAR_LITERAL = Suppress("'") + LITERAL_CHAR + Suppress("'") -STRING_LITERAL = Suppress("'") + Combine(OneOrMore(LITERAL_CHAR)) + Suppress("'") -DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"' -DOUBLE_ANGLE_STRING_LITERAL = '<<' + ZeroOrMore(Word(printables, exact=1)) + '>>' -TOKEN_REF = Word(alphas.upper(), alphanums+'_') -RULE_REF = Word(alphas.lower(), alphanums+'_') -ACTION_ESC = (Suppress("\\") + Suppress("'")) | Suppress('\\"') | Suppress('\\') + (~(Literal("'") | Literal('"')) + Word(printables, exact=1)) -ACTION_CHAR_LITERAL = Suppress("'") + (ACTION_ESC | ~(Literal('\\') | Literal("'")) + Word(printables, exact=1)) + Suppress("'") -ACTION_STRING_LITERAL = Suppress('"') + ZeroOrMore(ACTION_ESC | ~(Literal('\\') | Literal('"')) + Word(printables, exact=1)) + Suppress('"') -SRC = Suppress('src') + ACTION_STRING_LITERAL("file") + INT("line") -id = TOKEN_REF | RULE_REF -SL_COMMENT = Suppress('//') + Suppress('$ANTLR') + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL -ML_COMMENT = cStyleComment -WS = OneOrMore(Suppress(' ') | Suppress('\t') | (Optional(Suppress('\r')) + Literal('\n'))) -WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT) -NESTED_ARG_ACTION = Forward() -NESTED_ARG_ACTION << Suppress('[') + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress(']') -ARG_ACTION = NESTED_ARG_ACTION -NESTED_ACTION = Forward() -NESTED_ACTION << Suppress('{') + ZeroOrMore(NESTED_ACTION | SL_COMMENT | ML_COMMENT | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress('}') -ACTION = NESTED_ACTION + Optional('?') -SCOPE = Suppress('scope') -OPTIONS = Suppress('options') + Suppress('{') # + WS_LOOP + Suppress('{') -TOKENS = Suppress('tokens') + Suppress('{') # + WS_LOOP + Suppress('{') -FRAGMENT = 'fragment'; -TREE_BEGIN = Suppress('^(') -ROOT = Suppress('^') -BANG = Suppress('!') -RANGE = Suppress('..') -REWRITE = Suppress('->') - -# General Parser Definitions - -# Grammar heading -optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal('*').setName("s") - -option = Group(id("id") + Suppress('=') + optionValue("value"))("option") -optionsSpec = OPTIONS + Group(OneOrMore(option + Suppress(';')))("options") + Suppress('}') -tokenSpec = Group(TOKEN_REF("token_ref") + (Suppress('=') + (STRING_LITERAL | CHAR_LITERAL)("lit")))("token") + Suppress(';') -tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + Suppress('}') -attrScope = Suppress('scope') + id + ACTION -grammarType = Keyword('lexer') + Keyword('parser') + Keyword('tree') -actionScopeName = id | Keyword('lexer')("l") | Keyword('parser')("p") -action = Suppress('@') + Optional(actionScopeName + Suppress('::')) + id + ACTION - -grammarHeading = Optional(ML_COMMENT("ML_COMMENT")) + Optional(grammarType) + Suppress('grammar') + id("grammarName") + Suppress(';') + Optional(optionsSpec) + Optional(tokensSpec) + ZeroOrMore(attrScope) + ZeroOrMore(action) - -modifier = Keyword('protected') | Keyword('public') | Keyword('private') | Keyword('fragment') -ruleAction = Suppress('@') + id + ACTION -throwsSpec = Suppress('throws') + delimitedList(id) -ruleScopeSpec = (Suppress('scope') + ACTION) | (Suppress('scope') + delimitedList(id) + Suppress(';')) | (Suppress('scope') + ACTION + Suppress('scope') + delimitedList(id) + Suppress(';')) -unary_op = oneOf("^ !") -notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL -terminal = (CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | '.') + Optional(unary_op) -block = Forward() -notSet = Suppress('~') + (notTerminal | block) -rangeNotPython = CHAR_LITERAL("c1") + RANGE + CHAR_LITERAL("c2") -atom = Group(rangeNotPython + Optional(unary_op)("op")) | terminal | (notSet + Optional(unary_op)("op")) | (RULE_REF + Optional(ARG_ACTION("arg")) + Optional(unary_op)("op")) -element = Forward() -treeSpec = Suppress('^(') + element*(2,) + Suppress(')') -ebnfSuffix = oneOf("? * +") -ebnf = block + Optional(ebnfSuffix("op") | '=>') -elementNoOptionSpec = (id("result_name") + oneOf('= +=')("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + oneOf('= +=')("labelOp") + block + Optional(ebnfSuffix)) | atom("atom") + Optional(ebnfSuffix) | ebnf | ACTION | (treeSpec + Optional(ebnfSuffix)) # | SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED ) -element << Group(elementNoOptionSpec)("element") -alternative = Group(Group(OneOrMore(element))("elements")) # Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure? -rewrite = Optional(Literal('TODO REWRITE RULES TODO')) -block << Suppress('(') + Optional(Optional(optionsSpec("opts")) + Suppress(':')) + Group(alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives"))("block") + Suppress(')') -altList = alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives") -exceptionHandler = Suppress('catch') + ARG_ACTION + ACTION -finallyClause = Suppress('finally') + ACTION -exceptionGroup = (OneOrMore(exceptionHandler) + Optional(finallyClause)) | finallyClause - -ruleHeading = Optional(ML_COMMENT)("ruleComment") + Optional(modifier)("modifier") + id("ruleName") + Optional("!") + Optional(ARG_ACTION("arg")) + Optional(Suppress('returns') + ARG_ACTION("rt")) + Optional(throwsSpec) + Optional(optionsSpec) + Optional(ruleScopeSpec) + ZeroOrMore(ruleAction) -rule = Group(ruleHeading + Suppress(':') + altList + Suppress(';') + Optional(exceptionGroup))("rule") - -grammarDef = grammarHeading + Group(OneOrMore(rule))("rules") - -def grammar(): - return grammarDef - -def __antlrAlternativesConverter(pyparsingRules, antlrBlock): - rule = None - if hasattr(antlrBlock, 'alternatives') and antlrBlock.alternatives != '' and len(antlrBlock.alternatives) > 0: - alternatives = [] - alternatives.append(__antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)) - for alternative in antlrBlock.alternatives: - alternatives.append(__antlrAlternativeConverter(pyparsingRules, alternative)) - rule = MatchFirst(alternatives)("anonymous_or") - elif hasattr(antlrBlock, 'a1') and antlrBlock.a1 != '': - rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1) - else: - raise Exception('Not yet implemented') - assert rule != None - return rule - -def __antlrAlternativeConverter(pyparsingRules, antlrAlternative): - elementList = [] - for element in antlrAlternative.elements: - rule = None - if hasattr(element.atom, 'c1') and element.atom.c1 != '': - regex = r'['+str(element.atom.c1[0])+'-'+str(element.atom.c2[0]+']') - rule = Regex(regex)("anonymous_regex") - elif hasattr(element, 'block') and element.block != '': - rule = __antlrAlternativesConverter(pyparsingRules, element.block) - else: - ruleRef = element.atom - assert ruleRef in pyparsingRules - rule = pyparsingRules[element.atom](element.atom) - if hasattr(element, 'op') and element.op != '': - if element.op == '+': - rule = Group(OneOrMore(rule))("anonymous_one_or_more") - elif element.op == '*': - rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more") - elif element.op == '?': - rule = Optional(rule) - else: - raise Exception('rule operator not yet implemented : ' + element.op) - rule = rule - elementList.append(rule) - if len(elementList) > 1: - rule = Group(And(elementList))("anonymous_and") - else: - rule = elementList[0] - assert rule != None - return rule - -def __antlrRuleConverter(pyparsingRules, antlrRule): - rule = None - rule = __antlrAlternativesConverter(pyparsingRules, antlrRule) - assert rule != None - rule(antlrRule.ruleName) - return rule - -def antlrConverter(antlrGrammarTree): - pyparsingRules = {} - antlrTokens = {} - for antlrToken in antlrGrammarTree.tokens: - antlrTokens[antlrToken.token_ref] = antlrToken.lit - for antlrTokenName, antlrToken in list(antlrTokens.items()): - pyparsingRules[antlrTokenName] = Literal(antlrToken) - antlrRules = {} - for antlrRule in antlrGrammarTree.rules: - antlrRules[antlrRule.ruleName] = antlrRule - pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar - for antlrRuleName, antlrRule in list(antlrRules.items()): - pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule) - assert pyparsingRule != None - pyparsingRules[antlrRuleName] << pyparsingRule - return pyparsingRules - -if __name__ == "__main__": - - text = """grammar SimpleCalc; - -options { - language = Python; -} - -tokens { - PLUS = '+' ; - MINUS = '-' ; - MULT = '*' ; - DIV = '/' ; -} - -/*------------------------------------------------------------------ - * PARSER RULES - *------------------------------------------------------------------*/ - -expr : term ( ( PLUS | MINUS ) term )* ; - -term : factor ( ( MULT | DIV ) factor )* ; - -factor : NUMBER ; - - -/*------------------------------------------------------------------ - * LEXER RULES - *------------------------------------------------------------------*/ - -NUMBER : (DIGIT)+ ; - -/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */ - -fragment DIGIT : '0'..'9' ; - -""" - - grammar().validate() - antlrGrammarTree = grammar().parseString(text) - print(antlrGrammarTree.asXML("antlrGrammarTree")) - pyparsingRules = antlrConverter(antlrGrammarTree) - pyparsingRule = pyparsingRules["expr"] - pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25") - print(pyparsingTree.asXML("pyparsingTree")) diff --git a/trunk/src/examples/antlr_grammar_tests.py b/trunk/src/examples/antlr_grammar_tests.py deleted file mode 100644 index 31aab29..0000000 --- a/trunk/src/examples/antlr_grammar_tests.py +++ /dev/null @@ -1,85 +0,0 @@ -''' -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/trunk/src/examples/apicheck.py b/trunk/src/examples/apicheck.py deleted file mode 100644 index 4315ac9..0000000 --- a/trunk/src/examples/apicheck.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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 = next(api_scanner) - print("found %s on line %d" % (t.procname, lineno(s,test))) - except ParseSyntaxException as pe: - print("invalid arg count on line", pe.lineno) - print(pe.lineno,':',pe.line) - # reset api scanner to start after this exception location - test = "\n"*(pe.lineno-1)+test[pe.loc+1:] - api_scanner = apiRef.scanString(test) - except StopIteration: - break - diff --git a/trunk/src/examples/btpyparse.py b/trunk/src/examples/btpyparse.py deleted file mode 100644 index f3c11ae..0000000 --- a/trunk/src/examples/btpyparse.py +++ /dev/null @@ -1,128 +0,0 @@ -""" 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/trunk/src/examples/builtin_parse_action_demo.py b/trunk/src/examples/builtin_parse_action_demo.py deleted file mode 100644 index 3ec6af8..0000000 --- a/trunk/src/examples/builtin_parse_action_demo.py +++ /dev/null @@ -1,29 +0,0 @@ -# -# 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/trunk/src/examples/cLibHeader.py b/trunk/src/examples/cLibHeader.py deleted file mode 100644 index bb98521..0000000 --- a/trunk/src/examples/cLibHeader.py +++ /dev/null @@ -1,25 +0,0 @@ -# -# 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/trunk/src/examples/chemicalFormulas.py b/trunk/src/examples/chemicalFormulas.py deleted file mode 100644 index ce66afd..0000000 --- a/trunk/src/examples/chemicalFormulas.py +++ /dev/null @@ -1,67 +0,0 @@ -# chemicalFormulas.py -# -# Copyright (c) 2003, Paul McGuire -# - -from pyparsing import Word, Optional, OneOrMore, Group, ParseException, Regex -from pyparsing import alphas - -atomicWeight = { - "O" : 15.9994, - "H" : 1.00794, - "Na" : 22.9897, - "Cl" : 35.4527, - "C" : 12.0107 - } - -def test( bnf, strg, fn=None ): - try: - print(strg,"->", bnf.parseString( strg ), end=' ') - except ParseException as pe: - print(pe) - else: - if fn != None: - print(fn( bnf.parseString( strg ) )) - else: - print() - -digits = "0123456789" - -# Version 1 -element = Regex("A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|" - "E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|" - "M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|" - "S[bcegimnr]?|T[abcehilm]|U(u[bhopqst])?|V|W|Xe|Yb?|Z[nr]") - -element = Word( alphas.upper(), alphas.lower(), max=2) -elementRef = Group( element + Optional( Word( digits ), default="1" ) ) -formula = OneOrMore( elementRef ) - -fn = lambda elemList : sum(atomicWeight[elem]*int(qty) for elem,qty in elemList) -test( formula, "H2O", fn ) -test( formula, "C6H5OH", fn ) -test( formula, "NaCl", fn ) -print() - -# Version 2 - access parsed items by field name -elementRef = Group( element("symbol") + Optional( Word( digits ), default="1" )("qty") ) -formula = OneOrMore( elementRef ) - -fn = lambda elemList : sum(atomicWeight[elem.symbol]*int(elem.qty) for elem in elemList) -test( formula, "H2O", fn ) -test( formula, "C6H5OH", fn ) -test( formula, "NaCl", fn ) -print() - -# Version 3 - convert integers during parsing process -integer = Word( digits ).setParseAction(lambda t:int(t[0])) -elementRef = Group( element("symbol") + Optional( integer, default=1 )("qty") ) -formula = OneOrMore( elementRef ) - -fn = lambda elemList : sum(atomicWeight[elem.symbol]*elem.qty for elem in elemList) -test( formula, "H2O", fn ) -test( formula, "C6H5OH", fn ) -test( formula, "NaCl", fn ) - - - diff --git a/trunk/src/examples/commasep.py b/trunk/src/examples/commasep.py deleted file mode 100644 index 7696871..0000000 --- a/trunk/src/examples/commasep.py +++ /dev/null @@ -1,23 +0,0 @@ -# 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/trunk/src/examples/configParse.py b/trunk/src/examples/configParse.py deleted file mode 100644 index 769249c..0000000 --- a/trunk/src/examples/configParse.py +++ /dev/null @@ -1,72 +0,0 @@ -# -# configparse.py -# -# an example of using the parsing module to be able to process a .INI configuration file -# -# Copyright (c) 2003, Paul McGuire -# - -from pyparsing import \ - Literal, Word, ZeroOrMore, Group, Dict, Optional, \ - printables, ParseException, restOfLine, empty -import pprint - - -inibnf = None -def inifile_BNF(): - global inibnf - - if not inibnf: - - # punctuation - lbrack = Literal("[").suppress() - rbrack = Literal("]").suppress() - equals = Literal("=").suppress() - semi = Literal(";") - - comment = semi + Optional( restOfLine ) - - nonrbrack = "".join( [ c for c in printables if c != "]" ] ) + " \t" - nonequals = "".join( [ c for c in printables if c != "=" ] ) + " \t" - - sectionDef = lbrack + Word( nonrbrack ) + rbrack - keyDef = ~lbrack + Word( nonequals ) + equals + empty + restOfLine - # strip any leading or trailing blanks from key - def stripKey(tokens): - tokens[0] = tokens[0].strip() - keyDef.setParseAction(stripKey) - - # using Dict will allow retrieval of named data fields as attributes of the parsed results - inibnf = Dict( ZeroOrMore( Group( sectionDef + Dict( ZeroOrMore( Group( keyDef ) ) ) ) ) ) - - inibnf.ignore( comment ) - - return inibnf - - -pp = pprint.PrettyPrinter(2) - -def test( strng ): - print(strng) - try: - iniFile = open(strng) - iniData = "".join( iniFile.readlines() ) - bnf = inifile_BNF() - tokens = bnf.parseString( iniData ) - pp.pprint( tokens.asList() ) - - except ParseException as err: - print(err.line) - print(" "*(err.column-1) + "^") - print(err) - - iniFile.close() - print() - return tokens - -if __name__ == "__main__": - ini = test("setup.ini") - print("ini['Startup']['modemid'] =", ini['Startup']['modemid']) - print("ini.Startup =", ini.Startup) - print("ini.Startup.modemid =", ini.Startup.modemid) - diff --git a/trunk/src/examples/cpp_enum_parser.py b/trunk/src/examples/cpp_enum_parser.py deleted file mode 100644 index cbd0932..0000000 --- a/trunk/src/examples/cpp_enum_parser.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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/trunk/src/examples/datetimeParseActions.py b/trunk/src/examples/datetimeParseActions.py deleted file mode 100644 index 26d96a3..0000000 --- a/trunk/src/examples/datetimeParseActions.py +++ /dev/null @@ -1,43 +0,0 @@ -# parseActions.py -# -# A sample program a parser to match a date string of the form "YYYY/MM/DD", -# and return it as a datetime, or raise an exception if not a valid date. -# -# Copyright 2012, Paul T. McGuire -# -from datetime import datetime -from pyparsing import * - -# define an integer string, and a parse action to convert it -# to an integer at parse time -integer = Word(nums).setName("integer") -def convertToInt(tokens): - # no need to test for validity - we can't get here - # unless tokens[0] contains all numeric digits - return int(tokens[0]) -integer.setParseAction(convertToInt) -# or can be written as one line as -#integer = Word(nums).setParseAction(lambda t: int(t[0])) - -# define a pattern for a year/month/day date -date_expr = integer('year') + '/' + integer('month') + '/' + integer('day') - -def convertToDatetime(s,loc,tokens): - try: - # note that the year, month, and day fields were already - # converted to ints from strings by the parse action defined - # on the integer expression above - return datetime(tokens.year, tokens.month, tokens.day).date() - except Exception as ve: - errmsg = "'%d/%d/%d' is not a valid date, %s" % \ - (tokens.year, tokens.month, tokens.day, ve) - raise ParseException(s, loc, errmsg) -date_expr.setParseAction(convertToDatetime) - - -date_expr.runTests("""\ - 2000/1/1 - 2000/13/1 # invalid month - 1900/2/29 # 1900 was not a leap year - 2000/2/29 # but 2000 was - """) \ No newline at end of file diff --git a/trunk/src/examples/deltaTime.py b/trunk/src/examples/deltaTime.py deleted file mode 100644 index e38da00..0000000 --- a/trunk/src/examples/deltaTime.py +++ /dev/null @@ -1,208 +0,0 @@ -# deltaTime.py -# -# Parser to convert a conversational time reference such as "in a minute" or -# "noon tomorrow" and convert it to a Python datetime. The returned -# ParseResults object contains the results name "timeOffset" containing -# the timedelta, and "calculatedTime" containing the computed time relative -# to datetime.now(). -# -# Copyright 2010, by Paul McGuire -# - -from datetime import datetime, timedelta -from pyparsing import * -import calendar - -__all__ = ["nlTimeExpression"] - -# string conversion parse actions -def convertToTimedelta(toks): - unit = toks.timeunit.lower().rstrip("s") - td = { - 'week' : timedelta(7), - 'day' : timedelta(1), - 'hour' : timedelta(0,0,0,0,0,1), - 'minute' : timedelta(0,0,0,0,1), - 'second' : timedelta(0,1), - }[unit] - if toks.qty: - td *= int(toks.qty) - if toks.dir: - td *= toks.dir - toks["timeOffset"] = td - -def convertToDay(toks): - now = datetime.now() - if "wkdayRef" in toks: - todaynum = now.weekday() - daynames = [n.lower() for n in calendar.day_name] - nameddaynum = daynames.index(toks.wkdayRef.day.lower()) - if toks.wkdayRef.dir > 0: - daydiff = (nameddaynum + 7 - todaynum) % 7 - else: - daydiff = -((todaynum + 7 - nameddaynum) % 7) - toks["absTime"] = datetime(now.year, now.month, now.day)+timedelta(daydiff) - else: - name = toks.name.lower() - toks["absTime"] = { - "now" : now, - "today" : datetime(now.year, now.month, now.day), - "yesterday" : datetime(now.year, now.month, now.day)+timedelta(-1), - "tomorrow" : datetime(now.year, now.month, now.day)+timedelta(+1), - }[name] - -def convertToAbsTime(toks): - now = datetime.now() - if "dayRef" in toks: - day = toks.dayRef.absTime - day = datetime(day.year, day.month, day.day) - else: - day = datetime(now.year, now.month, now.day) - if "timeOfDay" in toks: - if isinstance(toks.timeOfDay,str): - timeOfDay = { - "now" : timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond), - "noon" : timedelta(0,0,0,0,0,12), - "midnight" : timedelta(), - }[toks.timeOfDay] - else: - hhmmss = toks.timeparts - if hhmmss.miltime: - hh,mm = hhmmss.miltime - ss = 0 - else: - hh,mm,ss = (hhmmss.HH % 12), hhmmss.MM, hhmmss.SS - if not mm: mm = 0 - if not ss: ss = 0 - if toks.timeOfDay.ampm == 'pm': - hh += 12 - timeOfDay = timedelta(0, (hh*60+mm)*60+ss, 0) - else: - timeOfDay = timedelta(0, (now.hour*60+now.minute)*60+now.second, now.microsecond) - toks["absTime"] = day + timeOfDay - -def calculateTime(toks): - if toks.absTime: - absTime = toks.absTime - else: - absTime = datetime.now() - if toks.timeOffset: - absTime += toks.timeOffset - toks["calculatedTime"] = absTime - -# grammar definitions -CL = CaselessLiteral -today, tomorrow, yesterday, noon, midnight, now = map( CL, - "today tomorrow yesterday noon midnight now".split()) -plural = lambda s : Combine(CL(s) + Optional(CL("s"))) -week, day, hour, minute, second = map( plural, - "week day hour minute second".split()) -am = CL("am") -pm = CL("pm") -COLON = Suppress(':') - -# are these actually operators? -in_ = CL("in").setParseAction(replaceWith(1)) -from_ = CL("from").setParseAction(replaceWith(1)) -before = CL("before").setParseAction(replaceWith(-1)) -after = CL("after").setParseAction(replaceWith(1)) -ago = CL("ago").setParseAction(replaceWith(-1)) -next_ = CL("next").setParseAction(replaceWith(1)) -last_ = CL("last").setParseAction(replaceWith(-1)) -at_ = CL("at") -on_ = CL("on") - -couple = (Optional(CL("a")) + CL("couple") + Optional(CL("of"))).setParseAction(replaceWith(2)) -a_qty = CL("a").setParseAction(replaceWith(1)) -integer = Word(nums).setParseAction(lambda t:int(t[0])) -int4 = Group(Word(nums,exact=4).setParseAction(lambda t: [int(t[0][:2]),int(t[0][2:])] )) -def fill_timefields(t): - t[0]['HH'] = t[0][0] - t[0]['MM'] = t[0][1] - t[0]['ampm'] = ('am','pm')[t[0].HH >= 12] -int4.addParseAction(fill_timefields) -qty = integer | couple | a_qty -dayName = oneOf( list(calendar.day_name) ) - -dayOffset = (qty("qty") + (week | day)("timeunit")) -dayFwdBack = (from_ + now.suppress() | ago)("dir") -weekdayRef = (Optional(next_ | last_,1)("dir") + dayName("day")) -dayRef = Optional( (dayOffset + (before | after | from_)("dir") ).setParseAction(convertToTimedelta) ) + \ - ((yesterday | today | tomorrow)("name")| - weekdayRef("wkdayRef")).setParseAction(convertToDay) -todayRef = (dayOffset + dayFwdBack).setParseAction(convertToTimedelta) | \ - (in_("dir") + qty("qty") + day("timeunit")).setParseAction(convertToTimedelta) - -dayTimeSpec = dayRef | todayRef -dayTimeSpec.setParseAction(calculateTime) - -relativeTimeUnit = (week | day | hour | minute | second) - -timespec = Group(ungroup(int4) | - integer("HH") + - ungroup(Optional(COLON + integer,[0]))("MM") + - ungroup(Optional(COLON + integer,[0]))("SS") + - (am | pm)("ampm") - ) - -absTimeSpec = ((noon | midnight | now | timespec("timeparts"))("timeOfDay") + - Optional(on_) + Optional(dayRef)("dayRef") | - dayRef("dayRef") + at_ + - (noon | midnight | now | timespec("timeparts"))("timeOfDay")) -absTimeSpec.setParseAction(convertToAbsTime,calculateTime) - -relTimeSpec = qty("qty") + relativeTimeUnit("timeunit") + \ - (from_ | before | after)("dir") + \ - Optional(at_) + \ - absTimeSpec("absTime") | \ - qty("qty") + relativeTimeUnit("timeunit") + ago("dir") | \ - in_ + qty("qty") + relativeTimeUnit("timeunit") -relTimeSpec.setParseAction(convertToTimedelta,calculateTime) - -nlTimeExpression = (absTimeSpec + Optional(dayTimeSpec) | - dayTimeSpec + Optional(Optional(at_) + absTimeSpec) | - relTimeSpec + Optional(absTimeSpec)) - -if __name__ == "__main__": - # test grammar - tests = """\ - today - tomorrow - yesterday - in a couple of days - a couple of days from now - a couple of days from today - in a day - 3 days ago - 3 days from now - a day ago - in 2 weeks - in 3 days at 5pm - now - 10 minutes ago - 10 minutes from now - in 10 minutes - in a minute - in a couple of minutes - 20 seconds ago - in 30 seconds - 20 seconds before noon - 20 seconds before noon tomorrow - noon - midnight - noon tomorrow - 6am tomorrow - 0800 yesterday - 12:15 AM today - 3pm 2 days from today - a week from today - a week from now - 3 weeks ago - noon next Sunday - noon Sunday - noon last Sunday - 2pm next Sunday - next Sunday at 2pm""" - - print("(relative to %s)" % datetime.now()) - nlTimeExpression.runTests(tests) diff --git a/trunk/src/examples/dfmparse.py b/trunk/src/examples/dfmparse.py deleted file mode 100644 index 96afbad..0000000 --- a/trunk/src/examples/dfmparse.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -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 " - - -from pyparsing import Literal, CaselessLiteral, Word, delimitedList \ - , Optional, Combine, Group, alphas, nums, alphanums, Forward \ - , oneOf, sglQuotedString, OneOrMore, ZeroOrMore, CharsNotIn - - -# This converts DFM character constants into Python string (unicode) values. -def to_chr(x): - """chr(x) if 0 < x < 128 ; unicode(x) if x > 127.""" - return 0 < x < 128 and chr(x) or eval("u'\\u%d'" % x ) - -################# -# BEGIN GRAMMAR -################# - -COLON = Literal(":").suppress() -CONCAT = Literal("+").suppress() -EQUALS = Literal("=").suppress() -LANGLE = Literal("<").suppress() -LBRACE = Literal("[").suppress() -LPAREN = Literal("(").suppress() -PERIOD = Literal(".").suppress() -RANGLE = Literal(">").suppress() -RBRACE = Literal("]").suppress() -RPAREN = Literal(")").suppress() - -CATEGORIES = CaselessLiteral("categories").suppress() -END = CaselessLiteral("end").suppress() -FONT = CaselessLiteral("font").suppress() -HINT = CaselessLiteral("hint").suppress() -ITEM = CaselessLiteral("item").suppress() -OBJECT = CaselessLiteral("object").suppress() - -attribute_value_pair = Forward() # this is recursed in item_list_entry - -simple_identifier = Word(alphas, alphanums + "_") -identifier = Combine( simple_identifier + ZeroOrMore( Literal(".") + simple_identifier )) -object_name = identifier -object_type = identifier - -# Integer and floating point values are converted to Python longs and floats, respectively. -int_value = Combine(Optional("-") + Word(nums)).setParseAction(lambda s,l,t: [ int(t[0]) ] ) -float_value = Combine(Optional("-") + Optional(Word(nums)) + "." + Word(nums)).setParseAction(lambda s,l,t: [ float(t[0]) ] ) -number_value = float_value | int_value - -# Base16 constants are left in string form, including the surrounding braces. -base16_value = Combine(Literal("{") + OneOrMore(Word("0123456789ABCDEFabcdef")) + Literal("}"), adjacent=False) - -# This is the first part of a hack to convert the various delphi partial sglQuotedStrings -# into a single sglQuotedString equivalent. The gist of it is to combine -# all sglQuotedStrings (with their surrounding quotes removed (suppressed)) -# with sequences of #xyz character constants, with "strings" concatenated -# with a '+' sign. -unquoted_sglQuotedString = Combine( Literal("'").suppress() + ZeroOrMore( CharsNotIn("'\n\r") ) + Literal("'").suppress() ) - -# The parse action on this production converts repetitions of constants into a single string. -pound_char = Combine( - OneOrMore((Literal("#").suppress()+Word(nums) - ).setParseAction( lambda s, l, t: to_chr(int(t[0]) )))) - -# This is the second part of the hack. It combines the various "unquoted" -# partial strings into a single one. Then, the parse action puts -# a single matched pair of quotes around it. -delphi_string = Combine( - OneOrMore(CONCAT | pound_char | unquoted_sglQuotedString) - , adjacent=False - ).setParseAction(lambda s, l, t: "'%s'" % t[0]) - -string_value = delphi_string | base16_value - -list_value = LBRACE + Optional(Group(delimitedList(identifier | number_value | string_value))) + RBRACE -paren_list_value = LPAREN + ZeroOrMore(identifier | number_value | string_value) + RPAREN - -item_list_entry = ITEM + ZeroOrMore(attribute_value_pair) + END -item_list = LANGLE + ZeroOrMore(item_list_entry) + RANGLE - -generic_value = identifier -value = item_list | number_value | string_value | list_value | paren_list_value | generic_value - -category_attribute = CATEGORIES + PERIOD + oneOf("strings itemsvisibles visibles", True) -event_attribute = oneOf("onactivate onclosequery onclose oncreate ondeactivate onhide onshow", True) -font_attribute = FONT + PERIOD + oneOf("charset color height name style", True) -hint_attribute = HINT -layout_attribute = oneOf("left top width height", True) -generic_attribute = identifier -attribute = (category_attribute | event_attribute | font_attribute | hint_attribute | layout_attribute | generic_attribute) - -category_attribute_value_pair = category_attribute + EQUALS + paren_list_value -event_attribute_value_pair = event_attribute + EQUALS + value -font_attribute_value_pair = font_attribute + EQUALS + value -hint_attribute_value_pair = hint_attribute + EQUALS + value -layout_attribute_value_pair = layout_attribute + EQUALS + value -generic_attribute_value_pair = attribute + EQUALS + value -attribute_value_pair << Group( - category_attribute_value_pair - | event_attribute_value_pair - | font_attribute_value_pair - | hint_attribute_value_pair - | layout_attribute_value_pair - | generic_attribute_value_pair - ) - -object_declaration = Group((OBJECT + object_name + COLON + object_type)) -object_attributes = Group(ZeroOrMore(attribute_value_pair)) - -nested_object = Forward() -object_definition = object_declaration + object_attributes + ZeroOrMore(nested_object) + END -nested_object << Group(object_definition) - -################# -# END GRAMMAR -################# - -def printer(s, loc, tok): - print(tok, end=' ') - return tok - -def get_filename_list(tf): - import sys, glob - if tf == None: - 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[list(retval.keys())[0]] - - # else, return a dictionary of parseResults - return retval - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/trunk/src/examples/dhcpd_leases_parser.py b/trunk/src/examples/dhcpd_leases_parser.py deleted file mode 100644 index 145e6ea..0000000 --- a/trunk/src/examples/dhcpd_leases_parser.py +++ /dev/null @@ -1,87 +0,0 @@ -# -# 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/trunk/src/examples/dictExample.py b/trunk/src/examples/dictExample.py deleted file mode 100644 index 5085aed..0000000 --- a/trunk/src/examples/dictExample.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# dictExample.py -# -# Illustration of using pyparsing's Dict class to process tabular data -# -# Copyright (c) 2003, Paul McGuire -# -from pyparsing import Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, delimitedList -import pprint - -testData = """ -+-------+------+------+------+------+------+------+------+------+ -| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 | -+=======+======+======+======+======+======+======+======+======+ -| min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 | -| max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 | -| ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 | -| sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 | -+-------+------+------+------+------+------+------+------+------+ -""" - -# define grammar for datatable -heading = (Literal( -"+-------+------+------+------+------+------+------+------+------+") + -"| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |" + -"+=======+======+======+======+======+======+======+======+======+").suppress() -vert = Literal("|").suppress() -number = Word(nums) -rowData = Group( vert + Word(alphas) + vert + delimitedList(number,"|") + vert ) -trailing = Literal( -"+-------+------+------+------+------+------+------+------+------+").suppress() - -datatable = heading + Dict( ZeroOrMore(rowData) ) + trailing - -# now parse data and print results -data = datatable.parseString(testData) -print(data) -pprint.pprint(data.asList()) -print("data keys=", list(data.keys())) -print("data['min']=", data['min']) -print("data.max", data.max) diff --git a/trunk/src/examples/dictExample2.py b/trunk/src/examples/dictExample2.py deleted file mode 100644 index cae463b..0000000 --- a/trunk/src/examples/dictExample2.py +++ /dev/null @@ -1,59 +0,0 @@ -# -# dictExample2.py -# -# Illustration of using pyparsing's Dict class to process tabular data -# Enhanced Dict example, courtesy of Mike Kelly -# -# Copyright (c) 2004, Paul McGuire -# -from pyparsing import Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, delimitedList, pyparsing_common -import pprint - -testData = """ -+-------+------+------+------+------+------+------+------+------+ -| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 | -+=======+======+======+======+======+======+======+======+======+ -| min | 7 | 43 | 7 | 15 | 82 | 98 | 1 | 37 | -| max | 11 | 52 | 10 | 17 | 85 | 112 | 4 | 39 | -| ave | 9 | 47 | 8 | 16 | 84 | 106 | 3 | 38 | -| sdev | 1 | 3 | 1 | 1 | 1 | 3 | 1 | 1 | -+-------+------+------+------+------+------+------+------+------+ -""" - -# define grammar for datatable -underline = Word("-=") -number = pyparsing_common.integer - -vert = Literal("|").suppress() - -rowDelim = ("+" + ZeroOrMore( underline + "+" ) ).suppress() -columnHeader = Group(vert + vert + delimitedList(Word(alphas + nums), "|") + vert) - -heading = rowDelim + columnHeader("columns") + rowDelim -rowData = Group( vert + Word(alphas) + vert + delimitedList(number,"|") + vert ) -trailing = rowDelim - -datatable = heading + Dict( ZeroOrMore(rowData) ) + trailing - -# now parse data and print results -data = datatable.parseString(testData) -print(data.dump()) -print("data keys=", list(data.keys())) -print("data['min']=", data['min']) -print("sum(data['min']) =", sum(data['min'])) -print("data.max =", data.max) -print("sum(data.max) =", sum(data.max)) - -# now print transpose of data table, using column labels read from table header and -# values from data lists -print() -print(" " * 5, end=' ') -for i in range(1,len(data)): - print("|%5s" % data[i][0], end=' ') -print() -print(("-" * 6) + ("+------" * (len(data)-1))) -for i in range(len(data.columns)): - print("%5s" % data.columns[i], end=' ') - for j in range(len(data) - 1): - print('|%5s' % data[j + 1][i + 1], end=' ') - print() diff --git a/trunk/src/examples/ebnf.py b/trunk/src/examples/ebnf.py deleted file mode 100644 index 8dfcaea..0000000 --- a/trunk/src/examples/ebnf.py +++ /dev/null @@ -1,149 +0,0 @@ -# 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/trunk/src/examples/ebnftest.py b/trunk/src/examples/ebnftest.py deleted file mode 100644 index 32c7fed..0000000 --- a/trunk/src/examples/ebnftest.py +++ /dev/null @@ -1,66 +0,0 @@ -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(list(filter(str.isspace, t[0]))) ) - commentcharcount += charCount - commentlocs.add(l) - return l,t - -#ordinarily, these lines wouldn't be necessary, but we are doing extra stuff with the comment expression -ebnf.ebnfComment.setParseAction( tallyCommentChars ) -ebnf_parser.ignore( ebnf.ebnfComment ) - -print('Parsing EBNF grammar with generated EBNF parser...\n') -parsed_chars = ebnf_parser.parseString(grammar) -parsed_char_len = len(parsed_chars) - -print("],\n".join(str( parsed_chars.asList() ).split("],"))) - -#~ grammar_length = len(grammar) - len(filter(str.isspace, grammar))-commentcharcount - -#~ assert parsed_char_len == grammar_length - -print('Ok!') diff --git a/trunk/src/examples/eval_arith.py b/trunk/src/examples/eval_arith.py deleted file mode 100644 index 9562253..0000000 --- a/trunk/src/examples/eval_arith.py +++ /dev/null @@ -1,227 +0,0 @@ -# eval_arith.py -# -# Copyright 2009, 2011 Paul McGuire -# -# Expansion on the pyparsing example simpleArith.py, to include evaluation -# of the parsed tokens. -# -# Added support for exponentiation, using right-to-left evaluation of -# operands -# -from pyparsing import Word, nums, alphas, Combine, oneOf, \ - opAssoc, infixNotation, Literal - -class EvalConstant(object): - "Class to evaluate a parsed constant or variable" - vars_ = {} - def __init__(self, tokens): - self.value = tokens[0] - def eval(self): - if self.value in EvalConstant.vars_: - return EvalConstant.vars_[self.value] - else: - return float(self.value) - -class EvalSignOp(object): - "Class to evaluate expressions with a leading + or - sign" - def __init__(self, tokens): - self.sign, self.value = tokens[0] - def eval(self): - mult = {'+':1, '-':-1}[self.sign] - return mult * self.value.eval() - -def operatorOperands(tokenlist): - "generator to extract operators and operands in pairs" - it = iter(tokenlist) - while 1: - try: - yield (next(it), next(it)) - except StopIteration: - break - -class EvalPowerOp(object): - "Class to evaluate multiplication and division expressions" - def __init__(self, tokens): - self.value = tokens[0] - def eval(self): - res = self.value[-1].eval() - for val in self.value[-3::-2]: - res = val.eval()**res - return res - -class EvalMultOp(object): - "Class to evaluate multiplication and division expressions" - def __init__(self, tokens): - self.value = tokens[0] - def eval(self): - prod = self.value[0].eval() - for op,val in operatorOperands(self.value[1:]): - if op == '*': - prod *= val.eval() - if op == '/': - prod /= val.eval() - return prod - -class EvalAddOp(object): - "Class to evaluate addition and subtraction expressions" - def __init__(self, tokens): - self.value = tokens[0] - def eval(self): - sum = self.value[0].eval() - for op,val in operatorOperands(self.value[1:]): - if op == '+': - sum += val.eval() - if op == '-': - sum -= val.eval() - return sum - -class EvalComparisonOp(object): - "Class to evaluate comparison expressions" - opMap = { - "<" : lambda a,b : a < b, - "<=" : lambda a,b : a <= b, - ">" : lambda a,b : a > b, - ">=" : lambda a,b : a >= b, - "!=" : lambda a,b : a != b, - "=" : lambda a,b : a == b, - "LT" : lambda a,b : a < b, - "LE" : lambda a,b : a <= b, - "GT" : lambda a,b : a > b, - "GE" : lambda a,b : a >= b, - "NE" : lambda a,b : a != b, - "EQ" : lambda a,b : a == b, - "<>" : lambda a,b : a != b, - } - def __init__(self, tokens): - self.value = tokens[0] - def eval(self): - val1 = self.value[0].eval() - for op,val in operatorOperands(self.value[1:]): - fn = EvalComparisonOp.opMap[op] - val2 = val.eval() - if not fn(val1,val2): - break - val1 = val2 - else: - return True - return False - - -# define the parser -integer = Word(nums) -real = Combine(Word(nums) + "." + Word(nums)) -variable = Word(alphas,exact=1) -operand = real | integer | variable - -signop = oneOf('+ -') -multop = oneOf('* /') -plusop = oneOf('+ -') -expop = Literal('**') - -# use parse actions to attach EvalXXX constructors to sub-expressions -operand.setParseAction(EvalConstant) -arith_expr = infixNotation(operand, - [ - (signop, 1, opAssoc.RIGHT, EvalSignOp), - (expop, 2, opAssoc.LEFT, EvalPowerOp), - (multop, 2, opAssoc.LEFT, EvalMultOp), - (plusop, 2, opAssoc.LEFT, EvalAddOp), - ]) - -comparisonop = oneOf("< <= > >= != = <> LT GT LE GE EQ NE") -comp_expr = infixNotation(arith_expr, - [ - (comparisonop, 2, opAssoc.LEFT, EvalComparisonOp), - ]) - -def main(): - # sample expressions posted on comp.lang.python, asking for advice - # in safely evaluating them - rules=[ - '( A - B ) = 0', - '(A + B + C + D + E + F + G + H + I) = J', - '(A + B + C + D + E + F + G + H) = I', - '(A + B + C + D + E + F) = G', - '(A + B + C + D + E) = (F + G + H + I + J)', - '(A + B + C + D + E) = (F + G + H + I)', - '(A + B + C + D + E) = F', - '(A + B + C + D) = (E + F + G + H)', - '(A + B + C) = (D + E + F)', - '(A + B) = (C + D + E + F)', - '(A + B) = (C + D)', - '(A + B) = (C - D + E - F - G + H + I + J)', - '(A + B) = C', - '(A + B) = 0', - '(A+B+C+D+E) = (F+G+H+I+J)', - '(A+B+C+D) = (E+F+G+H)', - '(A+B+C+D)=(E+F+G+H)', - '(A+B+C)=(D+E+F)', - '(A+B)=(C+D)', - '(A+B)=C', - '(A-B)=C', - '(A/(B+C))', - '(B/(C+D))', - '(G + H) = I', - '-0.99 LE ((A+B+C)-(D+E+F+G)) LE 0.99', - '-0.99 LE (A-(B+C)) LE 0.99', - '-1000.00 LE A LE 0.00', - '-5000.00 LE A LE 0.00', - 'A < B', - 'A < 7000', - 'A = -(B)', - 'A = C', - 'A = 0', - 'A GT 0', - 'A GT 0.00', - 'A GT 7.00', - 'A LE B', - 'A LT -1000.00', - 'A LT -5000', - 'A LT 0', - 'A=(B+C+D)', - 'A=B', - 'I = (G + H)', - '0.00 LE A LE 4.00', - '4.00 LT A LE 7.00', - '0.00 LE A LE 4.00 LE E > D', - '2**2**(A+3)', - ] - vars_={'A': 0, 'B': 1.1, 'C': 2.2, 'D': 3.3, 'E': 4.4, 'F': 5.5, 'G': - 6.6, 'H':7.7, 'I':8.8, 'J':9.9} - - # define tests from given rules - tests = [] - for t in rules: - t_orig = t - t = t.replace("=","==") - t = t.replace("EQ","==") - t = t.replace("LE","<=") - t = t.replace("GT",">") - t = t.replace("LT","<") - t = t.replace("GE",">=") - t = t.replace("LE","<=") - t = t.replace("NE","!=") - t = t.replace("<>","!=") - tests.append( (t_orig,eval(t,vars_)) ) - - # copy vars_ to EvalConstant lookup dict - EvalConstant.vars_ = vars_ - failed = 0 - for test,expected in tests: - ret = comp_expr.parseString(test)[0] - parsedvalue = ret.eval() - print(test, expected, parsedvalue) - if parsedvalue != expected: - print("<<< FAIL") - failed += 1 - else: - print('') - - print('') - if failed: - print(failed, "tests FAILED") - else: - print("all tests PASSED") - -if __name__=='__main__': - main() diff --git a/trunk/src/examples/excelExpr.py b/trunk/src/examples/excelExpr.py deleted file mode 100644 index 2700100..0000000 --- a/trunk/src/examples/excelExpr.py +++ /dev/null @@ -1,68 +0,0 @@ -# excelExpr.py -# -# Copyright 2010, Paul McGuire -# -# A partial implementation of a parser of Excel formula expressions. -# -from pyparsing import (CaselessKeyword, Suppress, Word, alphas, - alphanums, nums, Optional, Group, oneOf, Forward, Regex, - infixNotation, opAssoc, dblQuotedString, delimitedList, - Combine, Literal, QuotedString, ParserElement) -ParserElement.enablePackrat() - -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 + Group(expr)("if_true") + - COMMA + Group(expr)("if_false") + RPAR) - -statFunc = lambda name : Group(CaselessKeyword(name) + Group(LPAR + delimitedList(expr) + RPAR)) -sumFunc = statFunc("sum") -minFunc = statFunc("min") -maxFunc = statFunc("max") -aveFunc = statFunc("ave") -funcCall = ifFunc | sumFunc | minFunc | maxFunc | aveFunc - -multOp = oneOf("* /") -addOp = oneOf("+ -") -numericLiteral = Regex(r"\-?\d+(\.\d+)?") -operand = numericLiteral | funcCall | cellRange | cellRef -arithExpr = infixNotation(operand, - [ - (multOp, 2, opAssoc.LEFT), - (addOp, 2, opAssoc.LEFT), - ]) - -textOperand = dblQuotedString | cellRef -textExpr = infixNotation(textOperand, - [ - ('&', 2, opAssoc.LEFT), - ]) - -expr << (arithExpr | textExpr) - - -(EQ + expr).runTests("""\ - =3*A7+5" - =3*Sheet1!$A$7+5" - =3*'Sheet 1'!$A$7+5" - =3*'O''Reilly''s sheet'!$A$7+5" - =if(Sum(A1:A25)>42,Min(B1:B25),if(Sum(C1:C25)>3.14, (Min(C1:C25)+3)*18,Max(B1:B25)))" - =sum(a1:a25,10,min(b1,c2,d3)) -""") \ No newline at end of file diff --git a/trunk/src/examples/fourFn.py b/trunk/src/examples/fourFn.py deleted file mode 100644 index 75f3909..0000000 --- a/trunk/src/examples/fourFn.py +++ /dev/null @@ -1,192 +0,0 @@ -# fourFn.py -# -# Demonstration of the pyparsing module, implementing a simple 4-function expression parser, -# with support for scientific notation, and symbols for e and pi. -# Extended to add exponentiation and simple built-in functions. -# Extended test cases, simplified pushFirst method. -# Removed unnecessary expr.suppress() call (thanks Nathaniel Peterson!), and added Group -# Changed fnumber to use a Regex, which is now the preferred method -# -# Copyright 2003-2009 by Paul McGuire -# -from pyparsing import Literal,CaselessLiteral,Word,Group,Optional,\ - ZeroOrMore,Forward,nums,alphas,alphanums,Regex,ParseException,\ - CaselessKeyword, Suppress -import math -import operator - -exprStack = [] - -def pushFirst( strg, loc, toks ): - exprStack.append( toks[0] ) -def pushUMinus( strg, loc, toks ): - for t in toks: - if t == '-': - exprStack.append( 'unary -' ) - #~ exprStack.append( '-1' ) - #~ exprStack.append( '*' ) - else: - break - -bnf = None -def BNF(): - """ - expop :: '^' - multop :: '*' | '/' - addop :: '+' | '-' - integer :: ['+' | '-'] '0'..'9'+ - atom :: PI | E | real | fn '(' expr ')' | '(' expr ')' - factor :: atom [ expop factor ]* - term :: factor [ multop factor ]* - expr :: term [ addop term ]* - """ - global bnf - if not bnf: - point = Literal( "." ) - # use CaselessKeyword for e and pi, to avoid accidentally matching - # functions that start with 'e' or 'pi' (such as 'exp'); Keyword - # and CaselessKeyword only match whole words - e = CaselessKeyword( "E" ) - pi = CaselessKeyword( "PI" ) - #~ fnumber = Combine( Word( "+-"+nums, nums ) + - #~ Optional( point + Optional( Word( nums ) ) ) + - #~ Optional( e + Word( "+-"+nums, nums ) ) ) - fnumber = Regex(r"[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?") - ident = Word(alphas, alphanums+"_$") - - plus, minus, mult, div = map(Literal, "+-*/") - lpar, rpar = map(Suppress, "()") - addop = plus | minus - multop = mult | div - expop = Literal( "^" ) - - expr = Forward() - atom = ((0,None)*minus + ( pi | e | fnumber | ident + lpar + expr + rpar | ident ).setParseAction( pushFirst ) | - Group( lpar + expr + rpar )).setParseAction(pushUMinus) - - # by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ - # that is, 2^3^2 = 2^(3^2), not (2^3)^2. - factor = Forward() - factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) ) - - term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) ) - expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) ) - bnf = expr - return bnf - -# map operator symbols to corresponding arithmetic operations -epsilon = 1e-12 -opn = { "+" : operator.add, - "-" : operator.sub, - "*" : operator.mul, - "/" : operator.truediv, - "^" : operator.pow } -fn = { "sin" : math.sin, - "cos" : math.cos, - "tan" : math.tan, - "exp" : math.exp, - "abs" : abs, - "trunc" : lambda a: int(a), - "round" : round, - "sgn" : lambda a: (a > epsilon) - (a < -epsilon) } -def evaluateStack( s ): - op = s.pop() - if op == 'unary -': - return -evaluateStack( s ) - if op in "+-*/^": - op2 = evaluateStack( s ) - op1 = evaluateStack( s ) - return opn[op]( op1, op2 ) - elif op == "PI": - return math.pi # 3.1415926535 - elif op == "E": - return math.e # 2.718281828 - elif op in fn: - return fn[op]( evaluateStack( s ) ) - elif op[0].isalpha(): - raise Exception("invalid identifier '%s'" % op) - else: - return float( op ) - -if __name__ == "__main__": - - def test( s, expVal ): - global exprStack - exprStack[:] = [] - try: - results = BNF().parseString( s, parseAll=True ) - val = evaluateStack( exprStack[:] ) - except ParseException as e: - print(s, "failed parse:", str(pe)) - except Exception as e: - print(s, "failed eval:", str(e)) - else: - if val == expVal: - print(s, "=", val, results, "=>", exprStack) - else: - print(s+"!!!", val, "!=", expVal, results, "=>", exprStack) - - test( "9", 9 ) - test( "-9", -9 ) - test( "--9", 9 ) - test( "-E", -math.e ) - test( "9 + 3 + 6", 9 + 3 + 6 ) - test( "9 + 3 / 11", 9 + 3.0 / 11 ) - test( "(9 + 3)", (9 + 3) ) - test( "(9+3) / 11", (9+3.0) / 11 ) - test( "9 - 12 - 6", 9 - 12 - 6 ) - test( "9 - (12 - 6)", 9 - (12 - 6) ) - test( "2*3.14159", 2*3.14159 ) - test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535 / 10 ) - test( "PI * PI / 10", math.pi * math.pi / 10 ) - test( "PI*PI/10", math.pi*math.pi/10 ) - test( "PI^2", math.pi**2 ) - test( "round(PI^2)", round(math.pi**2) ) - test( "6.02E23 * 8.048", 6.02E23 * 8.048 ) - test( "e / 3", math.e / 3 ) - test( "sin(PI/2)", math.sin(math.pi/2) ) - test( "trunc(E)", int(math.e) ) - test( "trunc(-E)", int(-math.e) ) - test( "round(E)", round(math.e) ) - test( "round(-E)", round(-math.e) ) - test( "E^PI", math.e**math.pi ) - test( "exp(0)", 1 ) - test( "exp(1)", math.e ) - test( "2^3^2", 2**3**2 ) - test( "2^3+2", 2**3+2 ) - test( "2^3+5", 2**3+5 ) - test( "2^9", 2**9 ) - test( "sgn(-2)", -1 ) - test( "sgn(0)", 0 ) - test( "foo(0.1)", None ) - test( "sgn(0.1)", 1 ) - - -""" -Test output: ->pythonw -u fourFn.py -9 = 9.0 ['9'] => ['9'] -9 + 3 + 6 = 18.0 ['9', '+', '3', '+', '6'] => ['9', '3', '+', '6', '+'] -9 + 3 / 11 = 9.27272727273 ['9', '+', '3', '/', '11'] => ['9', '3', '11', '/', '+'] -(9 + 3) = 12.0 [] => ['9', '3', '+'] -(9+3) / 11 = 1.09090909091 ['/', '11'] => ['9', '3', '+', '11', '/'] -9 - 12 - 6 = -9.0 ['9', '-', '12', '-', '6'] => ['9', '12', '-', '6', '-'] -9 - (12 - 6) = 3.0 ['9', '-'] => ['9', '12', '6', '-', '-'] -2*3.14159 = 6.28318 ['2', '*', '3.14159'] => ['2', '3.14159', '*'] -3.1415926535*3.1415926535 / 10 = 0.986960440053 ['3.1415926535', '*', '3.1415926535', '/', '10'] => ['3.1415926535', '3.1415926535', '*', '10', '/'] -PI * PI / 10 = 0.986960440109 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/'] -PI*PI/10 = 0.986960440109 ['PI', '*', 'PI', '/', '10'] => ['PI', 'PI', '*', '10', '/'] -PI^2 = 9.86960440109 ['PI', '^', '2'] => ['PI', '2', '^'] -6.02E23 * 8.048 = 4.844896e+024 ['6.02E23', '*', '8.048'] => ['6.02E23', '8.048', '*'] -e / 3 = 0.90609394282 ['E', '/', '3'] => ['E', '3', '/'] -sin(PI/2) = 1.0 ['sin', 'PI', '/', '2'] => ['PI', '2', '/', 'sin'] -trunc(E) = 2 ['trunc', 'E'] => ['E', 'trunc'] -E^PI = 23.1406926328 ['E', '^', 'PI'] => ['E', 'PI', '^'] -2^3^2 = 512.0 ['2', '^', '3', '^', '2'] => ['2', '3', '2', '^', '^'] -2^3+2 = 10.0 ['2', '^', '3', '+', '2'] => ['2', '3', '^', '2', '+'] -2^9 = 512.0 ['2', '^', '9'] => ['2', '9', '^'] -sgn(-2) = -1 ['sgn', '-2'] => ['-2', 'sgn'] -sgn(0) = 0 ['sgn', '0'] => ['0', 'sgn'] -sgn(0.1) = 1 ['sgn', '0.1'] => ['0.1', 'sgn'] ->Exit code: 0 -""" diff --git a/trunk/src/examples/gen_ctypes.py b/trunk/src/examples/gen_ctypes.py deleted file mode 100644 index 2c909e4..0000000 --- a/trunk/src/examples/gen_ctypes.py +++ /dev/null @@ -1,167 +0,0 @@ -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/trunk/src/examples/getNTPservers.py b/trunk/src/examples/getNTPservers.py deleted file mode 100644 index bbf1d60..0000000 --- a/trunk/src/examples/getNTPservers.py +++ /dev/null @@ -1,30 +0,0 @@ -# getNTPservers.py -# -# Demonstration of the parsing module, implementing a HTML page scanner, -# to extract a list of NTP time servers from the NIST web site. -# -# Copyright 2004, by Paul McGuire -# -from pyparsing import Word, Combine, Suppress, CharsNotIn, nums -import urllib.request, urllib.parse, urllib.error - -integer = Word(nums) -ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer ) -tdStart = Suppress("") -tdEnd = Suppress("") -timeServerPattern = tdStart + ipAddress.setResultsName("ipAddr") + tdEnd + \ - tdStart + CharsNotIn("<").setResultsName("loc") + tdEnd - -# get list of time servers -nistTimeServerURL = "http://www.boulder.nist.gov/timefreq/service/time-servers.html" -serverListPage = urllib.request.urlopen( nistTimeServerURL ) -serverListHTML = serverListPage.read() -serverListPage.close() - -addrs = {} -for srvr,startloc,endloc in timeServerPattern.scanString( serverListHTML ): - print(srvr.ipAddr, "-", srvr.loc) - addrs[srvr.ipAddr] = srvr.loc - # or do this: - #~ addr,loc = srvr - #~ print addr, "-", loc diff --git a/trunk/src/examples/getNTPserversNew.py b/trunk/src/examples/getNTPserversNew.py deleted file mode 100644 index 14e710c..0000000 --- a/trunk/src/examples/getNTPserversNew.py +++ /dev/null @@ -1,35 +0,0 @@ -# getNTPserversNew.py -# -# Demonstration of the parsing module, implementing a HTML page scanner, -# to extract a list of NTP time servers from the NIST web site. -# -# Copyright 2004-2010, by Paul McGuire -# September, 2010 - updated to more current use of setResultsName, new NIST URL -# -from pyparsing import (Word, Combine, Suppress, SkipTo, nums, makeHTMLTags, - delimitedList, alphas, alphanums) -try: - import urllib.request - urlopen = urllib.request.urlopen -except ImportError: - import urllib - urlopen = urllib.urlopen - -integer = Word(nums) -ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer ) -hostname = delimitedList(Word(alphas,alphanums+"-_"),".",combine=True) -tdStart,tdEnd = makeHTMLTags("td") -timeServerPattern = (tdStart + hostname("hostname") + tdEnd + - tdStart + ipAddress("ipAddr") + tdEnd + - tdStart + SkipTo(tdEnd)("loc") + tdEnd) - -# get list of time servers -nistTimeServerURL = "http://tf.nist.gov/tf-cgi/servers.cgi#" -serverListPage = urlopen( nistTimeServerURL ) -serverListHTML = serverListPage.read().decode("UTF-8") -serverListPage.close() - -addrs = {} -for srvr,startloc,endloc in timeServerPattern.scanString( serverListHTML ): - print("%s (%s) - %s" % (srvr.ipAddr, srvr.hostname.strip(), srvr.loc.strip())) - addrs[srvr.ipAddr] = srvr.loc diff --git a/trunk/src/examples/greeting.py b/trunk/src/examples/greeting.py deleted file mode 100644 index 2e6b241..0000000 --- a/trunk/src/examples/greeting.py +++ /dev/null @@ -1,17 +0,0 @@ -# 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/trunk/src/examples/greetingInGreek.py b/trunk/src/examples/greetingInGreek.py deleted file mode 100644 index 07a8f0a..0000000 --- a/trunk/src/examples/greetingInGreek.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim:fileencoding=utf-8 -# -# greetingInGreek.py -# -# Demonstration of the parsing module, on the prototypical "Hello, World!" example -# -from pyparsing import Word - -# define grammar -alphas = ''.join(chr(x) for x in range(0x386, 0x3ce)) -greet = Word(alphas) + ',' + Word(alphas) + '!' - -# input string -hello = "Καλημέρα, κόσμε!".decode('utf-8') - -# parse input string -print(greet.parseString( hello )) - diff --git a/trunk/src/examples/greetingInKorean.py b/trunk/src/examples/greetingInKorean.py deleted file mode 100644 index d0ea0e5..0000000 --- a/trunk/src/examples/greetingInKorean.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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 = '\uc548\ub155, \uc5ec\ub7ec\ubd84!' #"Hello, World!" in Korean - -# parse input string -print(greet.parseString( hello )) - diff --git a/trunk/src/examples/groupUsingListAllMatches.py b/trunk/src/examples/groupUsingListAllMatches.py deleted file mode 100644 index d5037b8..0000000 --- a/trunk/src/examples/groupUsingListAllMatches.py +++ /dev/null @@ -1,16 +0,0 @@ -# -# 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/trunk/src/examples/holaMundo.py b/trunk/src/examples/holaMundo.py deleted file mode 100644 index 357e3c8..0000000 --- a/trunk/src/examples/holaMundo.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: UTF-8 -*- - -# escrito por Marco Alfonso, 2004 Noviembre - -# importamos el modulo -from pyparsing import * -saludo= Word(alphas) + ',' + Word(alphas) + '!' - -# Aqui decimos que la gramatica "saludo" DEBE contener -# una palabra compuesta de caracteres alfanumericos -# (Word(alphas)) mas una ',' mas otra palabra alfanumerica, -# mas '!' y esos seian nuestros tokens -tokens = saludo.parseString("Hola, Mundo !") - -# Ahora parseamos una cadena, "Hola, Mundo!", -# el metodo parseString, nos devuelve una lista con los tokens -# encontrados, en caso de no haber errores... -for i in range(len(tokens)): - print ("Token %d -> %s" % (i,tokens[i])) - -#imprimimos cada uno de los tokens Y listooo!!, he aqu la salida -# Token 0> Hola Token 1> , Token 2> Mundo Token 3> ! - -# Por supuesto, se pueden reutilizar gramticas, 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 cdigo diff --git a/trunk/src/examples/htmlStripper.py b/trunk/src/examples/htmlStripper.py deleted file mode 100644 index 0b0f459..0000000 --- a/trunk/src/examples/htmlStripper.py +++ /dev/null @@ -1,39 +0,0 @@ -# -# 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.request, urllib.parse, urllib.error - -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.request.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/trunk/src/examples/httpServerLogParser.py b/trunk/src/examples/httpServerLogParser.py deleted file mode 100644 index 1a808ae..0000000 --- a/trunk/src/examples/httpServerLogParser.py +++ /dev/null @@ -1,71 +0,0 @@ -# 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/trunk/src/examples/idlParse.py b/trunk/src/examples/idlParse.py deleted file mode 100644 index dd556e5..0000000 --- a/trunk/src/examples/idlParse.py +++ /dev/null @@ -1,222 +0,0 @@ -# -# idlparse.py -# -# an example of using the parsing module to be able to process a subset of the CORBA IDL grammar -# -# Copyright (c) 2003, Paul McGuire -# - -from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ - Forward, NotAny, delimitedList, oneOf, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ - alphanums, printables, empty, quotedString, ParseException, ParseResults, Keyword, Regex -import pprint -#~ import tree2image - -bnf = None -def CORBA_IDL_BNF(): - global bnf - - if not bnf: - - # punctuation - colon = 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 as err: - print(err.line) - print(" "*(err.column-1) + "^") - print(err) - print() - -if __name__ == "__main__": - test( - """ - /* - * a block comment * - */ - typedef string[10] tenStrings; - typedef sequence stringSeq; - typedef sequence< sequence > 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 /*comment inside an And */ stringSeq; - /* */ /**/ /***/ /****/ - typedef sequence< sequence > 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 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/trunk/src/examples/indentedGrammarExample.py b/trunk/src/examples/indentedGrammarExample.py deleted file mode 100644 index 442e6a4..0000000 --- a/trunk/src/examples/indentedGrammarExample.py +++ /dev/null @@ -1,54 +0,0 @@ -# indentedGrammarExample.py -# -# Copyright (c) 2006,2016 Paul McGuire -# -# A sample of a pyparsing grammar using indentation for -# grouping (like Python does). -# -# Updated to use indentedBlock helper method. -# - -from pyparsing import * - -data = """\ -def A(z): - A1 - B = 100 - G = A2 - A2 - A3 -B -def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 -C -D -def spam(x,y): - def eggs(z): - pass -""" - - -indentStack = [1] -stmt = Forward() -suite = indentedBlock(stmt, indentStack) - -identifier = Word(alphas, alphanums) -funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") -funcDef = Group( funcDecl + suite ) - -rvalue = Forward() -funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") -rvalue << (funcCall | identifier | Word(nums)) -assignment = Group(identifier + "=" + rvalue) -stmt << ( funcDef | assignment | identifier ) - -module_body = OneOrMore(stmt) - -print(data) -parseTree = module_body.parseString(data) -parseTree.pprint() - diff --git a/trunk/src/examples/invRegex.py b/trunk/src/examples/invRegex.py deleted file mode 100644 index b6fe1f1..0000000 --- a/trunk/src/examples/invRegex.py +++ /dev/null @@ -1,257 +0,0 @@ -# -# invRegex.py -# -# Copyright 2008, Paul McGuire -# -# pyparsing script to expand a regular expression into all possible matching strings -# Supports: -# - {n} and {m,n} repetition, but not unbounded + or * repetition -# - ? optional elements -# - [] character ranges -# - () grouping -# - | alternation -# -__all__ = ["count","invert"] - -from pyparsing import (Literal, oneOf, printables, ParserElement, Combine, - SkipTo, infixNotation, ParseFatalException, Word, nums, opAssoc, - Suppress, ParseResults, srange) - -class CharacterRangeEmitter(object): - def __init__(self,chars): - # remove duplicate chars in character range, but preserve original order - seen = set() - self.charset = "".join( seen.add(c) or c for c in chars if c not in seen ) - def __str__(self): - return '['+self.charset+']' - def __repr__(self): - return '['+self.charset+']' - def makeGenerator(self): - def genChars(): - for s in self.charset: - yield s - return genChars - -class OptionalEmitter(object): - def __init__(self,expr): - self.expr = expr - def makeGenerator(self): - def optionalGen(): - yield "" - for s in self.expr.makeGenerator()(): - yield s - return optionalGen - -class DotEmitter(object): - def makeGenerator(self): - def dotGen(): - for c in printables: - yield c - return dotGen - -class GroupEmitter(object): - def __init__(self,exprs): - self.exprs = ParseResults(exprs) - def makeGenerator(self): - def groupGen(): - def recurseList(elist): - if len(elist)==1: - for s in elist[0].makeGenerator()(): - yield s - else: - for s in elist[0].makeGenerator()(): - for s2 in recurseList(elist[1:]): - yield s + s2 - if self.exprs: - for s in recurseList(self.exprs): - yield s - return groupGen - -class AlternativeEmitter(object): - def __init__(self,exprs): - self.exprs = exprs - def makeGenerator(self): - def altGen(): - for e in self.exprs: - for s in e.makeGenerator()(): - yield s - return altGen - -class LiteralEmitter(object): - def __init__(self,lit): - self.lit = lit - def __str__(self): - return "Lit:"+self.lit - def __repr__(self): - return "Lit:"+self.lit - def makeGenerator(self): - def litGen(): - yield self.lit - return litGen - -def handleRange(toks): - return CharacterRangeEmitter(srange(toks[0])) - -def handleRepetition(toks): - toks=toks[0] - if toks[1] in "*+": - raise ParseFatalException("",0,"unbounded repetition operators not supported") - if toks[1] == "?": - return OptionalEmitter(toks[0]) - if "count" in toks: - return GroupEmitter([toks[0]] * int(toks.count)) - if "minCount" in toks: - mincount = int(toks.minCount) - maxcount = int(toks.maxCount) - optcount = maxcount - mincount - if optcount: - opt = OptionalEmitter(toks[0]) - for i in range(1,optcount): - opt = OptionalEmitter(GroupEmitter([toks[0],opt])) - return GroupEmitter([toks[0]] * mincount + [opt]) - else: - return [toks[0]] * mincount - -def handleLiteral(toks): - lit = "" - for t in toks: - if t[0] == "\\": - if t[1] == "t": - lit += '\t' - else: - lit += t[1] - else: - lit += t - return LiteralEmitter(lit) - -def handleMacro(toks): - macroChar = toks[0][1] - if macroChar == "d": - return CharacterRangeEmitter("0123456789") - elif macroChar == "w": - return CharacterRangeEmitter(srange("[A-Za-z0-9_]")) - elif macroChar == "s": - return LiteralEmitter(" ") - else: - raise ParseFatalException("",0,"unsupported macro character (" + macroChar + ")") - -def handleSequence(toks): - return GroupEmitter(toks[0]) - -def handleDot(): - return CharacterRangeEmitter(printables) - -def handleAlternative(toks): - return AlternativeEmitter(toks[0]) - - -_parser = None -def parser(): - global _parser - if _parser is None: - ParserElement.setDefaultWhitespaceChars("") - lbrack,rbrack,lbrace,rbrace,lparen,rparen,colon,qmark = map(Literal,"[]{}():?") - - reMacro = Combine("\\" + oneOf(list("dws"))) - escapedChar = ~reMacro + Combine("\\" + oneOf(list(printables))) - reLiteralChar = "".join(c for c in printables if c not in r"\[]{}().*?+|") + " \t" - - reRange = Combine(lbrack + SkipTo(rbrack,ignore=escapedChar) + rbrack) - reLiteral = ( escapedChar | oneOf(list(reLiteralChar)) ) - reNonCaptureGroup = Suppress("?:") - reDot = Literal(".") - repetition = ( - ( lbrace + Word(nums)("count") + rbrace ) | - ( lbrace + Word(nums)("minCount")+","+ Word(nums)("maxCount") + rbrace ) | - oneOf(list("*+?")) - ) - - reRange.setParseAction(handleRange) - reLiteral.setParseAction(handleLiteral) - reMacro.setParseAction(handleMacro) - reDot.setParseAction(handleDot) - - reTerm = ( reLiteral | reRange | reMacro | reDot | reNonCaptureGroup) - reExpr = infixNotation( reTerm, - [ - (repetition, 1, opAssoc.LEFT, handleRepetition), - (None, 2, opAssoc.LEFT, handleSequence), - (Suppress('|'), 2, opAssoc.LEFT, handleAlternative), - ] - ) - _parser = reExpr - - return _parser - -def count(gen): - """Simple function to count the number of elements returned by a generator.""" - return sum(1 for _ in gen) - -def invert(regex): - """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)|(2[0-5]) - ([01]\d\d)|(2[0-4]\d)|(25[0-5]) - [A-C]{1,2} - [A-C]{0,3} - [A-C]\s[A-C]\s[A-C] - [A-C]\s?[A-C][A-C] - [A-C]\s([A-C][A-C]) - [A-C]\s([A-C][A-C])? - [A-C]{2}\d{2} - @|TH[12] - @(@|TH[12])? - @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9]))? - @(@|TH[12]|AL[12]|SP[123]|TB(1[0-9]?|20?|[3-9])|OH(1[0-9]?|2[0-9]?|30?|[4-9]))? - (([ECMP]|HA|AK)[SD]|HS)T - [A-CV]{2} - A[cglmrstu]|B[aehikr]?|C[adeflmorsu]?|D[bsy]|E[rsu]|F[emr]?|G[ade]|H[efgos]?|I[nr]?|Kr?|L[airu]|M[dgnot]|N[abdeiop]?|Os?|P[abdmortu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilm]|Uu[bhopqst]|U|V|W|Xe|Yb?|Z[nr] - (a|b)|(x|y) - (a|b) (x|y) - [ABCDEFG](?:#|##|b|bb)?(?:maj|min|m|sus|aug|dim)?[0-9]?(?:/[ABCDEFG](?:#|##|b|bb)?)? - (Fri|Mon|S(atur|un)|T(hur|ue)s|Wednes)day - A(pril|ugust)|((Dec|Nov|Sept)em|Octo)ber|(Febr|Jan)uary|Ju(ly|ne)|Ma(rch|y) - """.split('\n') - - for t in tests: - t = t.strip() - if not t: continue - print('-'*50) - print(t) - try: - num = count(invert(t)) - print(num) - maxprint = 30 - for s in invert(t): - print(s) - maxprint -= 1 - if not maxprint: - break - except ParseFatalException as pfe: - print(pfe.msg) - print('') - continue - print('') - -if __name__ == "__main__": - main() diff --git a/trunk/src/examples/javascript_grammar.g b/trunk/src/examples/javascript_grammar.g deleted file mode 100644 index c30eac2..0000000 --- a/trunk/src/examples/javascript_grammar.g +++ /dev/null @@ -1,894 +0,0 @@ -/* - 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/trunk/src/examples/jsonParser.py b/trunk/src/examples/jsonParser.py deleted file mode 100644 index 45cdef3..0000000 --- a/trunk/src/examples/jsonParser.py +++ /dev/null @@ -1,111 +0,0 @@ -# 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 as 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(list(results.glossary.GlossDiv.GlossList.keys())) - testPrint( results.glossary.title ) - testPrint( results.glossary.GlossDiv.GlossList.ID ) - testPrint( results.glossary.GlossDiv.GlossList.FalseValue ) - testPrint( results.glossary.GlossDiv.GlossList.Acronym ) - testPrint( results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2 ) - testPrint( results.glossary.GlossDiv.GlossList.PrimesLessThan10 ) - - diff --git a/trunk/src/examples/linenoExample.py b/trunk/src/examples/linenoExample.py deleted file mode 100644 index 1186f48..0000000 --- a/trunk/src/examples/linenoExample.py +++ /dev/null @@ -1,49 +0,0 @@ -# -# 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/trunk/src/examples/list1.py b/trunk/src/examples/list1.py deleted file mode 100644 index e410070..0000000 --- a/trunk/src/examples/list1.py +++ /dev/null @@ -1,50 +0,0 @@ -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/trunk/src/examples/listAllMatches.py b/trunk/src/examples/listAllMatches.py deleted file mode 100644 index 1b1bdd4..0000000 --- a/trunk/src/examples/listAllMatches.py +++ /dev/null @@ -1,52 +0,0 @@ -# listAllMatches.py -# -# Sample program showing how/when to use listAllMatches to get all matching tokens in a results name. -# -# copyright 2006, Paul McGuire -# - -from pyparsing import oneOf, OneOrMore, printables, StringEnd - -test = "The quick brown fox named 'Aloysius' lives at 123 Main Street (and jumps over lazy dogs in his spare time)." -nonAlphas = [ c for c in printables if not c.isalpha() ] - -print("Extract vowels, consonants, and special characters from this test string:") -print("'" + test + "'") -print('') - -print("Define grammar using normal results names") -print("(only last matching symbol is saved)") -vowels = oneOf(list("aeiouy"), caseless=True)("vowels") -cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True)("cons") -other = oneOf(nonAlphas)("others") -letters = OneOrMore(cons | vowels | other) + StringEnd() - -results = letters.parseString(test) -print(results) -print(results.vowels) -print(results.cons) -print(results.others) -print('') - - -print("Define grammar using results names, with listAllMatches=True") -print("(all matching symbols are saved)") -vowels = oneOf(list("aeiouy"), caseless=True)("vowels*") -cons = oneOf(list("bcdfghjklmnpqrstvwxz"), caseless=True)("cons*") -other = oneOf(nonAlphas)("others*") - -letters = OneOrMore(cons | vowels | other) - -results = letters.parseString(test, parseAll=True) -print(results) -print(sorted(set(results))) -print('') -print(results.vowels) -print(sorted(set(results.vowels))) -print('') -print(results.cons) -print(sorted(set(results.cons))) -print('') -print(results.others) -print(sorted(set(results.others))) - diff --git a/trunk/src/examples/lucene_grammar.py b/trunk/src/examples/lucene_grammar.py deleted file mode 100644 index 179f25e..0000000 --- a/trunk/src/examples/lucene_grammar.py +++ /dev/null @@ -1,330 +0,0 @@ -# -# lucene_grammar.py -# -# Copyright 2011, Paul McGuire -# -# implementation of Lucene grammar, as decribed -# at http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/docs/queryparsersyntax.html -# - -from pyparsing import (Literal, CaselessKeyword, Forward, Regex, QuotedString, Suppress, - Optional, Group, FollowedBy, infixNotation, opAssoc, ParseException, ParserElement) -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 << infixNotation(term, - [ - (required_modifier | prohibit_modifier, 1, opAssoc.RIGHT), - ((not_ | '!').setParseAction(lambda:"NOT"), 1, opAssoc.RIGHT), - ((and_ | '&&').setParseAction(lambda:"AND"), 2, opAssoc.LEFT), - (Optional(or_ | '||').setParseAction(lambda:"OR"), 2, opAssoc.LEFT), - ]) - -# test strings taken from grammar description doc, and TestQueryParser.java -tests = r""" - a and b - a and not b - a and !b - a && !b - a&&!b - name:a - name:a and not title:b - (a^100 c d f) and !z - name:"blah de blah" - title:(+return +"pink panther") - title:"The Right Way" AND text:go - title:"Do it right" AND right - title:Do it right - roam~ - roam~0.8 - "jakarta apache"~10 - mod_date:[20020101 TO 20030101] - title:{Aida TO Carmen} - jakarta apache - jakarta^4 apache - "jakarta apache"^4 "Apache Lucene" - "jakarta apache" jakarta - "jakarta apache" OR jakarta - "jakarta apache" AND "Apache Lucene" - +jakarta lucene - "jakarta apache" NOT "Apache Lucene" - "jakarta apache" -"Apache Lucene" - (jakarta OR apache) AND website - \(1+1\)\:2 - c\:\\windows - (fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo) - (fieldX:xxxxx fieldy:xxxxxxxx)^2 AND (fieldx:the fieldy:foo) - (fieldX:xxxxx~0.5 fieldy:xxxxxxxx)^2 AND (fieldx:the fieldy:foo) - +term -term term - foo:term AND field:anotherTerm - germ term^2.0 - (term)^2.0 - (foo OR bar) AND (baz OR boo) - +(apple \"steve jobs\") -(foo bar baz) - +title:(dog OR cat) -author:\"bob dole\" - a AND b - +a +b - (a AND b) - c OR (a AND b) - c (+a +b) - a AND NOT b - +a -b - a AND -b - a AND !b - a && b - a && ! b - a OR b - a b - a || b - a OR !b - a -b - a OR ! b - a OR -b - a - b - a + b - a ! b - +foo:term +anotherterm - hello - term^2.0 - (germ term)^2.0 - term^2 - +(foo bar) +(baz boo) - ((a OR b) AND NOT c) OR d - (+(a b) -c) d - field - a&&b - .NET - term - germ - 3 - term 1.0 1 2 - term term1 term2 - term term term - term* - term*^2 - term*^2.0 - term~ - term~2.0 - term~0.7 - term~^3 - term~2.0^3.0 - term*germ - term*germ^3 - term*germ^3.0 - term~1.1 - [A TO C] - t*erm* - *term* - term term^3.0 term - term stop^3.0 term - term +stop term - term -stop term - drop AND (stop) AND roll - +drop +roll - term +(stop) term - term -(stop) term - drop AND stop AND roll - term phrase term - term (phrase1 phrase2) term - term AND NOT phrase term - +term -(phrase1 phrase2) term - stop^3 - stop - (stop)^3 - ((stop))^3 - (stop^3) - ((stop)^3) - (stop) - ((stop)) - term +stop - [ a TO z] - [a TO z] - [ a TO z ] - { a TO z} - {a TO z} - { a TO z } - { a TO z }^2.0 - {a TO z}^2.0 - [ a TO z] OR bar - [a TO z] bar - [ a TO z] AND bar - +[a TO z] +bar - ( bar blar { a TO z}) - bar blar {a TO z} - gack ( bar blar { a TO z}) - gack (bar blar {a TO z}) - [* TO Z] - [* TO z] - [A TO *] - [a TO *] - [* TO *] - [\* TO \*] - \!blah - \:blah - blah - \~blah - \*blah - a - a-b:c - a+b:c - a\:b:c - a\\b:c - a:b-c - a:b+c - a:b\:c - a:b\\c - a:b-c* - a:b+c* - a:b\:c* - a:b\\c* - a:b-c~2.0 - a:b+c~2.0 - a:b\:c~ - a:b\\c~ - [a- TO a+] - [ a\\ TO a\* ] - c\:\\temp\\\~foo.txt - abc - XYZ - (item:\\ item:ABCD\\) - \* - * - \\ - a\:b\:c - a\\b\:c - a\:b\\c - a\:b\:c\* - a\:b\\\\c\* - a:b-c~ - a:b+c~ - a\:b\:c\~ - a\:b\\c\~ - +weltbank +worlbank - +term +term +term - term +term term - term term +term - term +term +term - -term term term - -term +term +term - on - on^1.0 - hello^2.0 - the^3 - the - some phrase - xunit~ - one two three - A AND B OR C AND D - +A +B +C +D - foo:zoo* - foo:zoo*^2 - zoo - foo:* - foo:*^2 - *:foo - a:the OR a:foo - a:woo OR a:the - *:* - (*:*) - +*:* -*:* - the wizard of ozzy - """.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 [_f for _f in map(str.strip,tests) if _f]: - print(t) - try: - #~ expression.parseString(t,parseAll=True) - print(expression.parseString(t,parseAll=True)) - except ParseException as pe: - print(t) - print(pe) - allpass = False - print('') - -print(("FAIL", "OK")[allpass]) diff --git a/trunk/src/examples/macroExpander.py b/trunk/src/examples/macroExpander.py deleted file mode 100644 index 327976c..0000000 --- a/trunk/src/examples/macroExpander.py +++ /dev/null @@ -1,60 +0,0 @@ -# macroExpander.py -# -# Example pyparsing program for performing macro expansion, similar to -# the C pre-processor. This program is not as fully-featured, simply -# processing macros of the form: -# #def xxx yyyyy -# and replacing xxx with yyyyy in the rest of the input string. Macros -# can also be composed using other macros, such as -# #def zzz xxx+1 -# Since xxx was previously defined as yyyyy, then zzz will be replaced -# with yyyyy+1. -# -# Copyright 2007 by Paul McGuire -# -from pyparsing import * - -# define the structure of a macro definition (the empty term is used -# to advance to the next non-whitespace character) -identifier = Word(alphas+"_",alphanums+"_") -macroDef = "#def" + identifier("macro") + empty + restOfLine("value") - -# define a placeholder for defined macros - initially nothing -macroExpr = Forward() -macroExpr << NoMatch() - -# global dictionary for macro definitions -macros = {} - -# parse action for macro definitions -def processMacroDefn(s,l,t): - macroVal = macroExpander.transformString(t.value) - macros[t.macro] = macroVal - macroExpr << MatchFirst(map(Keyword, macros.keys())) - return "#def " + t.macro + " " + macroVal - -# parse action to replace macro references with their respective definition -def processMacroRef(s,l,t): - return macros[t[0]] - -# attach parse actions to expressions -macroExpr.setParseAction(processMacroRef) -macroDef.setParseAction(processMacroDefn) - -# define pattern for scanning through the input string -macroExpander = macroExpr | macroDef - - - -# test macro substitution using transformString -testString = """ - #def A 100 - #def ALEN A+1 - - char Astring[ALEN]; - char AA[A]; - typedef char[ALEN] Acharbuf; - """ - -print(macroExpander.transformString(testString)) -print(macros) diff --git a/trunk/src/examples/makeHTMLTagExample.py b/trunk/src/examples/makeHTMLTagExample.py deleted file mode 100644 index 3b771c7..0000000 --- a/trunk/src/examples/makeHTMLTagExample.py +++ /dev/null @@ -1,21 +0,0 @@ -import urllib.request, urllib.parse, urllib.error - -from pyparsing import makeHTMLTags, SkipTo - -# read HTML from a web page -serverListPage = urllib.request.urlopen( "http://www.yahoo.com" ) -htmlText = serverListPage.read() -serverListPage.close() - -# using makeHTMLTags to define opening and closing tags -anchorStart,anchorEnd = makeHTMLTags("a") - -# compose an expression for an anchored reference -anchor = anchorStart + SkipTo(anchorEnd)("body") + anchorEnd - -# use scanString to scan through the HTML source, extracting -# just the anchor tags and their associated body text -# (note the href attribute of the opening A tag is available -# as an attribute in the returned parse results) -for tokens,start,end in anchor.scanString(htmlText): - print(tokens.body,'->',tokens.href) diff --git a/trunk/src/examples/matchPreviousDemo.py b/trunk/src/examples/matchPreviousDemo.py deleted file mode 100644 index f0812e9..0000000 --- a/trunk/src/examples/matchPreviousDemo.py +++ /dev/null @@ -1,33 +0,0 @@ -# -# 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/trunk/src/examples/mozilla.ics b/trunk/src/examples/mozilla.ics deleted file mode 100644 index e6dd3dc..0000000 --- a/trunk/src/examples/mozilla.ics +++ /dev/null @@ -1,50 +0,0 @@ -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/trunk/src/examples/mozillaCalendarParser.py b/trunk/src/examples/mozillaCalendarParser.py deleted file mode 100644 index 210f284..0000000 --- a/trunk/src/examples/mozillaCalendarParser.py +++ /dev/null @@ -1,81 +0,0 @@ -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 -License: Free for any use -""" - - -# TERMINALS - -BEGIN = Literal("BEGIN:").suppress() -END = Literal("END:").suppress() -valstr = printables + "\xe4\xf6\xe5\xd6\xc4\xc5 " - -EQ = Literal("=").suppress() -SEMI = Literal(";").suppress() -COLON = Literal(":").suppress() - -EVENT = Literal("VEVENT").suppress() -CALENDAR = Literal("VCALENDAR").suppress() -ALARM = Literal("VALARM").suppress() - -# TOKENS - -CALPROP = oneOf("VERSION PRODID METHOD") -ALMPROP = oneOf("TRIGGER") -EVTPROP = oneOf("X-MOZILLA-RECUR-DEFAULT-INTERVAL \ - X-MOZILLA-RECUR-DEFAULT-UNITS \ - UID DTSTAMP LAST-MODIFIED X RRULE EXDATE") - -propval = Word(valstr) -typeval = Word(valstr) -typename = oneOf("VALUE MEMBER FREQ UNTIL INTERVAL") - -proptype = Group(SEMI + typename + EQ + typeval).suppress() - -calprop = Group(CALPROP + ZeroOrMore(proptype) + COLON + propval) -almprop = Group(ALMPROP + ZeroOrMore(proptype) + COLON + propval) -evtprop = Group(EVTPROP + ZeroOrMore(proptype) + COLON + propval).suppress() \ - | "CATEGORIES" + COLON + propval.setResultsName("categories") \ - | "CLASS" + COLON + propval.setResultsName("class") \ - | "DESCRIPTION" + COLON + propval.setResultsName("description") \ - | "DTSTART" + proptype + COLON + propval.setResultsName("begin") \ - | "DTEND" + proptype + COLON + propval.setResultsName("end") \ - | "LOCATION" + COLON + propval.setResultsName("location") \ - | "PRIORITY" + COLON + propval.setResultsName("priority") \ - | "STATUS" + COLON + propval.setResultsName("status") \ - | "SUMMARY" + COLON + propval.setResultsName("summary") \ - | "URL" + COLON + propval.setResultsName("url") \ - -calprops = Group(OneOrMore(calprop)).suppress() -evtprops = Group(OneOrMore(evtprop)) -almprops = Group(OneOrMore(almprop)).suppress() - -alarm = BEGIN + ALARM + almprops + END + ALARM -event = BEGIN + EVENT + evtprops + Optional(alarm) + END + EVENT -events = Group(OneOrMore(event)) -calendar = BEGIN + CALENDAR + calprops + ZeroOrMore(event) + END + CALENDAR -calendars = OneOrMore(calendar) - - -# PARSE ACTIONS - -def gotEvent(s,loc,toks): - for event in toks: - print(event.dump()) - -event.setParseAction(gotEvent) - - -# MAIN PROGRAM - -if __name__=="__main__": - - calendars.parseFile("mozilla.ics") diff --git a/trunk/src/examples/nested.py b/trunk/src/examples/nested.py deleted file mode 100644 index 24cf2f4..0000000 --- a/trunk/src/examples/nested.py +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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/trunk/src/examples/numerics.py b/trunk/src/examples/numerics.py deleted file mode 100644 index 5ab99dd..0000000 --- a/trunk/src/examples/numerics.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# numerics.py -# -# Examples of parsing real and integers using various grouping and -# decimal point characters, varying by locale. -# -# Copyright 2016, Paul McGuire -# -# Format samples from https://docs.oracle.com/cd/E19455-01/806-0169/overview-9/index.html -# -tests = """\ -# Canadian (English and French) -4 294 967 295,000 - -# Danish -4 294 967 295,000 - -# Finnish -4 294 967 295,000 - -# French -4 294 967 295,000 - -# German -4 294 967 295,000 - -# Italian -4.294.967.295,000 - -# Norwegian -4.294.967.295,000 - -# Spanish -4.294.967.295,000 - -# Swedish -4 294 967 295,000 - -# GB-English -4,294,967,295.000 - -# US-English -4,294,967,295.000 - -# Thai -4,294,967,295.000 -""" - -from pyparsing import Regex - -comma_decimal = Regex(r'\d{1,2}(([ .])\d\d\d(\2\d\d\d)*)?,\d*') -comma_decimal.setParseAction(lambda t: float(t[0].replace(' ','').replace('.','').replace(',','.'))) - -dot_decimal = Regex(r'\d{1,2}(([ ,])\d\d\d(\2\d\d\d)*)?\.\d*') -dot_decimal.setParseAction(lambda t: float(t[0].replace(' ','').replace(',',''))) - -decimal = comma_decimal ^ dot_decimal -decimal.runTests(tests, parseAll=True) - -grouped_integer = Regex(r'\d{1,2}(([ .,])\d\d\d(\2\d\d\d)*)?') -grouped_integer.setParseAction(lambda t: int(t[0].replace(' ','').replace(',','').replace('.',''))) -grouped_integer.runTests(tests, parseAll=False) diff --git a/trunk/src/examples/oc.py b/trunk/src/examples/oc.py deleted file mode 100644 index 77ea195..0000000 --- a/trunk/src/examples/oc.py +++ /dev/null @@ -1,193 +0,0 @@ -# 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 << (infixNotation(operand, - [ - (oneOf('! - *'), 1, opAssoc.RIGHT), - (oneOf('++ --'), 1, opAssoc.RIGHT), - (oneOf('++ --'), 1, opAssoc.LEFT), - (oneOf('* / %'), 2, opAssoc.LEFT), - (oneOf('+ -'), 2, opAssoc.LEFT), - (oneOf('< == > <= >= !='), 2, opAssoc.LEFT), - (Regex(r'=[^=]'), 2, opAssoc.LEFT), - ]) + - Optional( LBRACK + expr + RBRACK | - LPAR + Group(Optional(delimitedList(expr))) + RPAR ) - ) - -stmt = Forward() - -ifstmt = IF - LPAR + expr + RPAR + stmt + Optional(ELSE + stmt) -whilestmt = WHILE - LPAR + expr + RPAR + stmt -dowhilestmt = DO - stmt + WHILE + LPAR + expr + RPAR + SEMI -returnstmt = RETURN - expr + SEMI - -stmt << Group( ifstmt | - whilestmt | - dowhilestmt | - returnstmt | - expr + SEMI | - LBRACE + ZeroOrMore(stmt) + RBRACE | - SEMI) - -vardecl = Group(TYPE + NAME + Optional(LBRACK + integer + RBRACK)) + SEMI - -arg = Group(TYPE + NAME) -body = ZeroOrMore(vardecl) + ZeroOrMore(stmt) -fundecl = Group(TYPE + NAME + LPAR + Optional(Group(delimitedList(arg))) + RPAR + - LBRACE + Group(body) + RBRACE) -decl = fundecl | vardecl -program = ZeroOrMore(decl) - -program.ignore(cStyleComment) - -# set parser element names -for vname in ("ifstmt whilestmt dowhilestmt returnstmt TYPE " - "NAME fundecl vardecl program arg body stmt".split()): - v = vars()[vname] - v.setName(vname) - -#~ for vname in "fundecl stmt".split(): - #~ v = vars()[vname] - #~ v.setDebug() - -test = r""" -/* A factorial program */ -int -putstr(char *s) -{ - while(*s) - putchar(*s++); -} - -int -fac(int n) -{ - if (n == 0) - return 1; - else - return n*fac(n-1); -} - -int -putn(int n) -{ - if (9 < n) - putn(n / 10); - putchar((n%10) + '0'); -} - -int -facpr(int n) -{ - putstr("factorial "); - putn(n); - putstr(" = "); - putn(fac(n)); - putstr("\n"); -} - -int -main() -{ - int i; - i = 0; - while(i < 10) - facpr(i++); - return 0; -} -""" - -ast = program.parseString(test,parseAll=True) -ast.pprint() diff --git a/trunk/src/examples/parseListString.py b/trunk/src/examples/parseListString.py deleted file mode 100644 index d74f3af..0000000 --- a/trunk/src/examples/parseListString.py +++ /dev/null @@ -1,82 +0,0 @@ -# parseListString.py -# -# Copyright, 2006, by Paul McGuire -# - -from pyparsing import * - -# first pass -lbrack = Literal("[") -rbrack = Literal("]") -integer = Word(nums).setName("integer") -real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." + - Optional(Word(nums))).setName("real") - -listItem = real | integer | quotedString - -listStr = lbrack + delimitedList(listItem) + rbrack - -test = "['a', 100, 3.14]" - -print(listStr.parseString(test)) - - -# second pass, cleanup and add converters -lbrack = Literal("[").suppress() -rbrack = Literal("]").suppress() -cvtInt = lambda s,l,toks: int(toks[0]) -integer = Word(nums).setName("integer").setParseAction( cvtInt ) -cvtReal = lambda s,l,toks: float(toks[0]) -real = Regex(r'[+-]?\d+\.\d*').setName("floating-point number").setParseAction( cvtReal ) -listItem = real | integer | quotedString.setParseAction( removeQuotes ) - -listStr = lbrack + delimitedList(listItem) + rbrack - -test = "['a', 100, 3.14]" - -print(listStr.parseString(test)) - -# third pass, add nested list support, and tuples, too! -cvtInt = lambda s,l,toks: int(toks[0]) -cvtReal = lambda s,l,toks: float(toks[0]) - -lbrack = Literal("[").suppress() -rbrack = Literal("]").suppress() -integer = Word(nums).setName("integer").setParseAction( cvtInt ) -real = Regex(r'[+-]?\d+\.\d*').setName("floating-point number").setParseAction( cvtReal ) -tupleStr = Forward() -listStr = Forward() -listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr) | tupleStr -tupleStr << ( Suppress("(") + delimitedList(listItem) + Optional(Suppress(",")) + Suppress(")") ) -tupleStr.setParseAction( lambda t:tuple(t.asList()) ) -listStr << lbrack + delimitedList(listItem) + Optional(Suppress(",")) + rbrack - -test = "['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ]" -print(listStr.parseString(test)) - -# fourth pass, add parsing of dicts -cvtInt = lambda s,l,toks: int(toks[0]) -cvtReal = lambda s,l,toks: float(toks[0]) -cvtDict = lambda s,l,toks: dict(toks[0]) - -lbrack = Literal("[").suppress() -rbrack = Literal("]").suppress() -lbrace = Literal("{").suppress() -rbrace = Literal("}").suppress() -colon = Literal(":").suppress() -integer = Word(nums).setName("integer").setParseAction( cvtInt ) -real = Regex(r'[+-]?\d+\.\d*').setName("real").setParseAction( cvtReal ) - -tupleStr = Forward() -listStr = Forward() -dictStr = Forward() -listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr) | tupleStr | dictStr -tupleStr <<= ( Suppress("(") + delimitedList(listItem) + Optional(Suppress(",")) + Suppress(")") ) -tupleStr.setParseAction( lambda t:tuple(t.asList()) ) -listStr <<= (lbrack + Optional(delimitedList(listItem)) + Optional(Suppress(",")) + rbrack) -dictKeyStr = real | integer | quotedString.setParseAction(removeQuotes) -dictStr <<= lbrace + Optional(delimitedList( Group( dictKeyStr + colon + listItem ))) + Optional(Suppress(",")) + rbrace -dictStr.setParseAction(lambda t: dict((k_v[0],(k_v[1].asList() if isinstance(k_v[1],ParseResults) else k_v[1])) for k_v in t)) - -test = '[{0: [2], 1: []}, {0: [], 1: [], 2: [,]}, {0: [1, 2,],}]' -print(listStr.parseString(test)) diff --git a/trunk/src/examples/parsePythonValue.py b/trunk/src/examples/parsePythonValue.py deleted file mode 100644 index 53c61fc..0000000 --- a/trunk/src/examples/parsePythonValue.py +++ /dev/null @@ -1,70 +0,0 @@ -# parsePythonValue.py -# -# Copyright, 2006, by Paul McGuire -# -from __future__ import print_function -from pyparsing import * - - -cvtBool = lambda t:t[0]=='True' -cvtInt = lambda toks: int(toks[0]) -cvtReal = lambda toks: float(toks[0]) -cvtTuple = lambda toks : tuple(toks.asList()) -cvtDict = lambda toks: dict(toks.asList()) -cvtList = lambda toks: [toks.asList()] - -# define punctuation as suppressed literals -lparen,rparen,lbrack,rbrack,lbrace,rbrace,colon = \ - map(Suppress,"()[]{}:") - -integer = Regex(r"[+-]?\d+")\ - .setName("integer")\ - .setParseAction( cvtInt ) -real = Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?")\ - .setName("real")\ - .setParseAction( cvtReal ) -tupleStr = Forward() -listStr = Forward() -dictStr = Forward() - -unicodeString.setParseAction(lambda t:t[0][2:-1].decode('unicode-escape')) -quotedString.setParseAction(lambda t:t[0][1:-1].decode('string-escape')) -boolLiteral = oneOf("True False").setParseAction(cvtBool) -noneLiteral = Literal("None").setParseAction(replaceWith(None)) - -listItem = real|integer|quotedString|unicodeString|boolLiteral|noneLiteral| \ - Group(listStr) | tupleStr | dictStr - -tupleStr << ( Suppress("(") + Optional(delimitedList(listItem)) + - Optional(Suppress(",")) + Suppress(")") ) -tupleStr.setParseAction( cvtTuple ) - -listStr << (lbrack + Optional(delimitedList(listItem) + - Optional(Suppress(","))) + rbrack) -listStr.setParseAction(cvtList, lambda t: t[0]) - -dictEntry = Group( listItem + colon + listItem ) -dictStr << (lbrace + Optional(delimitedList(dictEntry) + \ - Optional(Suppress(","))) + rbrace) -dictStr.setParseAction( cvtDict ) - -tests = """['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ] - [{0: [2], 1: []}, {0: [], 1: [], 2: []}, {0: [1, 2]}] - { 'A':1, 'B':2, 'C': {'a': 1.2, 'b': 3.4} } - 3.14159 - 42 - 6.02E23 - 6.02e+023 - 1.0e-7 - 'a quoted string'""".split("\n") - -for test in tests: - print("Test:", test.strip()) - result = listItem.parseString(test)[0] - print("Result:", result) - try: - for dd in result: - if isinstance(dd,dict): print(list(dd.items())) - except TypeError as te: - pass - print() diff --git a/trunk/src/examples/parseResultsSumExample.py b/trunk/src/examples/parseResultsSumExample.py deleted file mode 100644 index 1fb694a..0000000 --- a/trunk/src/examples/parseResultsSumExample.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# 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/trunk/src/examples/parseTabularData.py b/trunk/src/examples/parseTabularData.py deleted file mode 100644 index 3846310..0000000 --- a/trunk/src/examples/parseTabularData.py +++ /dev/null @@ -1,50 +0,0 @@ -# -# parseTabularData.py -# -# Example of parsing data that is formatted in a tabular listing, with -# potential for missing values. Uses new addCondition method on -# ParserElements. -# -# Copyright 2015, Paul McGuire -# -from pyparsing import col,Word,Optional,alphas,nums,ParseException - -table = """\ - 1 2 -12345678901234567890 -COLOR S M L -RED 10 2 2 -BLUE 5 10 -GREEN 3 5 -PURPLE 8""" - -# function to create column-specific parse conditions -def mustMatchCols(startloc,endloc): - return lambda s,l,t: startloc <= col(l,s) <= endloc - -# helper to define values in a space-delimited table -# (change empty_cell_is_zero to True if a value of 0 is desired for empty cells) -def tableValue(expr, colstart, colend): - empty_cell_is_zero = False - if empty_cell_is_zero: - return Optional(expr.copy().addCondition(mustMatchCols(colstart,colend), - message="text not in expected columns"), - default=0) - else: - return Optional(expr.copy().addCondition(mustMatchCols(colstart,colend), - message="text not in expected columns")) - - -# define the grammar for this simple table -colorname = Word(alphas) -integer = Word(nums).setParseAction(lambda t: int(t[0])).setName("integer") -row = (colorname("name") + - tableValue(integer, 11, 12)("S") + - tableValue(integer, 15, 16)("M") + - tableValue(integer, 19, 20)("L")) - -# parse the sample text - skip over the header and counter lines -for line in table.splitlines()[3:]: - print(line) - print(row.parseString(line).dump()) - print('') diff --git a/trunk/src/examples/partial_gene_match.py b/trunk/src/examples/partial_gene_match.py deleted file mode 100644 index 8bf5f7c..0000000 --- a/trunk/src/examples/partial_gene_match.py +++ /dev/null @@ -1,88 +0,0 @@ -# parital_gene_match.py -# -# Example showing how to create a customized pyparsing Token, in this case, -# one that is very much like Literal, but which tolerates up to 'n' character -# mismatches -from pyparsing import * - -import urllib.request, urllib.parse, urllib.error - -# read in a bunch of genomic data -datafile = urllib.request.urlopen("http://toxodb.org/common/downloads/release-6.0/Tgondii/TgondiiApicoplastORFsNAs_ToxoDB-6.0.fasta") -fastasrc = datafile.read() -datafile.close() - -""" -Sample header: ->NC_001799-6-2978-2778 | organism=Toxoplasma_gondii_RH | location=NC_001799:2778-2978(-) | length=201 -""" -integer = Word(nums).setParseAction(lambda t:int(t[0])) -genebit = Group(">" + Word(alphanums.upper()+"-_") + "|" + - Word(printables)("id") + SkipTo("length=", include=True) + - integer("genelen") + LineEnd() + - Combine(OneOrMore(Word("ACGTN")),adjacent=False)("gene")) - -# read gene data from .fasta file - takes just a few seconds -genedata = OneOrMore(genebit).parseString(fastasrc) - - -class CloseMatch(Token): - """A special subclass of Token that does *close* matches. For each - close match of the given string, a tuple is returned giving the - found close match, and a list of mismatch positions.""" - def __init__(self, seq, maxMismatches=1): - super(CloseMatch,self).__init__() - self.name = seq - self.sequence = seq - self.maxMismatches = maxMismatches - self.errmsg = "Expected " + self.sequence - self.mayIndexError = False - self.mayReturnEmpty = False - - def parseImpl( self, instring, loc, doActions=True ): - start = loc - instrlen = len(instring) - maxloc = start + len(self.sequence) - - if maxloc <= instrlen: - seq = self.sequence - seqloc = 0 - mismatches = [] - throwException = False - done = False - while loc < maxloc and not done: - if instring[loc] != seq[seqloc]: - mismatches.append(seqloc) - if len(mismatches) > self.maxMismatches: - throwException = True - done = True - loc += 1 - seqloc += 1 - else: - throwException = True - - if throwException: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - return loc, (instring[start:loc],mismatches) - -# using the genedata extracted above, look for close matches of a gene sequence -searchseq = CloseMatch("TTAAATCTAGAAGAT", 3) -for g in genedata: - print("%s (%d)" % (g.id, g.genelen)) - print("-"*24) - for t,startLoc,endLoc in searchseq.scanString(g.gene, overlap=True): - matched, mismatches = t[0] - print("MATCH:", searchseq.sequence) - print("FOUND:", matched) - if mismatches: - print(" ", ''.join(' ' if i not in mismatches else '*' - for i,c in enumerate(searchseq.sequence))) - else: - print("") - print("at location", startLoc) - print() - print() \ No newline at end of file diff --git a/trunk/src/examples/pgn.py b/trunk/src/examples/pgn.py deleted file mode 100644 index d13f83e..0000000 --- a/trunk/src/examples/pgn.py +++ /dev/null @@ -1,94 +0,0 @@ -# pgn.py rel. 1.1 17-sep-2004 -# -# Demonstration of the parsing module, implementing a pgn parser. -# -# The aim of this parser is not to support database application, -# but to create automagically a pgn annotated reading the log console file -# of a lecture of ICC (Internet Chess Club), saved by Blitzin. -# Of course you can modify the Abstract Syntax Tree to your purpose. -# -# Copyright 2004, by Alberto Santini http://www.albertosantini.it/chess/ -# -from pyparsing import alphanums, nums, quotedString -from pyparsing import Combine, Forward, Group, Literal, oneOf, OneOrMore, Optional, Suppress, ZeroOrMore, White, Word -from pyparsing import ParseException - -# -# define pgn grammar -# - -tag = Suppress("[") + Word(alphanums) + Combine(quotedString) + Suppress("]") -comment = Suppress("{") + Word(alphanums + " ") + Suppress("}") - -dot = Literal(".") -piece = oneOf("K Q B N R") -file_coord = oneOf("a b c d e f g h") -rank_coord = oneOf("1 2 3 4 5 6 7 8") -capture = oneOf("x :") -promote = Literal("=") -castle_queenside = oneOf("O-O-O 0-0-0 o-o-o") -castle_kingside = oneOf("O-O 0-0 o-o") - -move_number = Optional(comment) + Word(nums) + dot -m1 = file_coord + rank_coord # pawn move e.g. d4 -m2 = file_coord + capture + file_coord + rank_coord # pawn capture move e.g. dxe5 -m3 = file_coord + "8" + promote + piece # pawn promotion e.g. e8=Q -m4 = piece + file_coord + rank_coord # piece move e.g. Be6 -m5 = piece + file_coord + file_coord + rank_coord # piece move e.g. Nbd2 -m6 = piece + rank_coord + file_coord + rank_coord # piece move e.g. R4a7 -m7 = piece + capture + file_coord + rank_coord # piece capture move e.g. Bxh7 -m8 = castle_queenside | castle_kingside # castling e.g. o-o - -check = oneOf("+ ++") -mate = Literal("#") -annotation = Word("!?", max=2) -nag = " $" + Word(nums) -decoration = check | mate | annotation | nag - -variant = Forward() -half_move = Combine((m3 | m1 | m2 | m4 | m5 | m6 | m7 | m8) + Optional(decoration)) \ - + Optional(comment) +Optional(variant) -move = Suppress(move_number) + half_move + Optional(half_move) -variant << "(" + OneOrMore(move) + ")" -# grouping the plies (half-moves) for each move: useful to group annotations, variants... -# suggested by Paul McGuire :) -move = Group(Suppress(move_number) + half_move + Optional(half_move)) -variant << Group("(" + OneOrMore(move) + ")") -game_terminator = oneOf("1-0 0-1 1/2-1/2 *") - -pgnGrammar = Suppress(ZeroOrMore(tag)) + ZeroOrMore(move) + Optional(Suppress(game_terminator)) - -def parsePGN( pgn, bnf=pgnGrammar, fn=None ): - try: - return bnf.parseString( pgn ) - except ParseException as err: - print(err.line) - print(" "*(err.column-1) + "^") - print(err) - -if __name__ == "__main__": - # input string - pgn = """ -[Event "ICC 5 0 u"] -[Site "Internet Chess Club"] -[Date "2004.01.25"] -[Round "-"] -[White "guest920"] -[Black "IceBox"] -[Result "0-1"] -[ICCResult "White checkmated"] -[BlackElo "1498"] -[Opening "French defense"] -[ECO "C00"] -[NIC "FR.01"] -[Time "04:44:56"] -[TimeControl "300+0"] - -1. e4 e6 2. Nf3 d5 $2 3. exd5 (3. e5 g6 4. h4) exd5 4. Qe2+ Qe7 5. Qxe7+ Bxe7 6. d3 Nf6 7. Be3 -Bg4 8. Nbd2 c5 9. h3 Be6 10. O-O-O Nc6 11. g4 Bd6 12. g5 Nd7 13. Rg1 d4 14. -g6 fxg6 15. Bg5 Rf8 16. a3 Bd5 17. Re1+ Nde5 18. Nxe5 Nxe5 19. Bf4 Rf5 20. -Bxe5 Rxe5 21. Rg5 Rxe1# {Black wins} 0-1 -""" - # parse input string - tokens = parsePGN(pgn, pgnGrammar) - print(tokens.dump()) diff --git a/trunk/src/examples/position.py b/trunk/src/examples/position.py deleted file mode 100644 index 984c018..0000000 --- a/trunk/src/examples/position.py +++ /dev/null @@ -1,55 +0,0 @@ -from pyparsing import * - -text = """Lorem ipsum dolor sit amet, consectetur adipisicing -elit, sed do eiusmod tempor incididunt ut labore et dolore magna -aliqua. Ut enim ad minim veniam, quis nostrud exercitation -ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis -aute irure dolor in reprehenderit in voluptate velit esse cillum -dolore eu fugiat nulla pariatur. Excepteur sint occaecat -cupidatat non proident, sunt in culpa qui officia deserunt -mollit anim id est laborum""" - -# find all words beginning with a vowel -vowels = "aeiouAEIOU" -initialVowelWord = Word(vowels,alphas) - -# Unfortunately, searchString will advance character by character through -# the input text, so it will detect that the initial "Lorem" is not an -# initialVowelWord, but then it will test "orem" and think that it is. So -# we need to add a do-nothing term that will match the words that start with -# consonants, but we will just throw them away when we match them. The key is -# that, in having been matched, the parser will skip over them entirely when -# looking for initialVowelWords. -consonants = ''.join(c for c in alphas if c not in vowels) -initialConsWord = Word(consonants, alphas).suppress() - -# using scanString to locate where tokens are matched -for t,start,end in (initialConsWord|initialVowelWord).scanString(text): - if t: - print(start,':', t[0]) - -# add parse action to annotate the parsed tokens with their location in the -# input string -def addLocnToTokens(s,l,t): - t['locn'] = l - t['word'] = t[0] -initialVowelWord.setParseAction(addLocnToTokens) - -for ivowelInfo in (initialConsWord | initialVowelWord).searchString(text): - if not ivowelInfo: - continue - print(ivowelInfo.locn, ':', ivowelInfo.word) - - -# alternative - add an Empty that will save the current location -def location(name): - return Empty().setParseAction(lambda s,l,t: t.__setitem__(name,l)) -locateInitialVowels = location("locn") + initialVowelWord("word") - -# search through the input text -for ivowelInfo in (initialConsWord | locateInitialVowels).searchString(text): - if not ivowelInfo: - continue - print(ivowelInfo.locn, ':', ivowelInfo.word) - - diff --git a/trunk/src/examples/protobuf_parser.py b/trunk/src/examples/protobuf_parser.py deleted file mode 100644 index 04ce0d8..0000000 --- a/trunk/src/examples/protobuf_parser.py +++ /dev/null @@ -1,100 +0,0 @@ -# protobuf_parser.py -# -# simple parser for parsing protobuf .proto files -# -# Copyright 2010, Paul McGuire -# - -from pyparsing import (Word, alphas, alphanums, Regex, Suppress, Forward, - Group, oneOf, ZeroOrMore, Optional, delimitedList, Keyword, - restOfLine, quotedString, Dict) - -ident = Word(alphas+"_",alphanums+"_").setName("identifier") -integer = Regex(r"[+-]?\d+") - -LBRACE,RBRACE,LBRACK,RBRACK,LPAR,RPAR,EQ,SEMI = map(Suppress,"{}[]()=;") - -kwds = """message required optional repeated enum extensions extends extend - to package service rpc returns true false option import""" -for kw in kwds.split(): - exec("%s_ = Keyword('%s')" % (kw.upper(), kw)) - -messageBody = Forward() - -messageDefn = MESSAGE_ - ident("messageId") + LBRACE + messageBody("body") + RBRACE - -typespec = oneOf("""double float int32 int64 uint32 uint64 sint32 sint64 - fixed32 fixed64 sfixed32 sfixed64 bool string bytes""") | ident -rvalue = integer | TRUE_ | FALSE_ | ident -fieldDirective = LBRACK + Group(ident + EQ + rvalue) + RBRACK -fieldDefn = (( REQUIRED_ | OPTIONAL_ | REPEATED_ )("fieldQualifier") - - typespec("typespec") + ident("ident") + EQ + integer("fieldint") + ZeroOrMore(fieldDirective) + SEMI) - -# enumDefn ::= 'enum' ident '{' { ident '=' integer ';' }* '}' -enumDefn = ENUM_("typespec") - ident('name') + LBRACE + Dict( ZeroOrMore( Group(ident + EQ + integer + SEMI) ))('values') + RBRACE - -# extensionsDefn ::= 'extensions' integer 'to' integer ';' -extensionsDefn = EXTENSIONS_ - integer + TO_ + integer + SEMI - -# messageExtension ::= 'extend' ident '{' messageBody '}' -messageExtension = EXTEND_ - ident + LBRACE + messageBody + RBRACE - -# messageBody ::= { fieldDefn | enumDefn | messageDefn | extensionsDefn | messageExtension }* -messageBody << Group(ZeroOrMore( Group(fieldDefn | enumDefn | messageDefn | extensionsDefn | messageExtension) )) - -# methodDefn ::= 'rpc' ident '(' [ ident ] ')' 'returns' '(' [ ident ] ')' ';' -methodDefn = (RPC_ - ident("methodName") + - LPAR + Optional(ident("methodParam")) + RPAR + - RETURNS_ + LPAR + Optional(ident("methodReturn")) + RPAR) - -# serviceDefn ::= 'service' ident '{' methodDefn* '}' -serviceDefn = SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(methodDefn)) + RBRACE - -# packageDirective ::= 'package' ident [ '.' ident]* ';' -packageDirective = Group(PACKAGE_ - delimitedList(ident, '.', combine=True) + SEMI) - -comment = '//' + restOfLine - -importDirective = IMPORT_ - quotedString("importFileSpec") + SEMI - -optionDirective = OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI - -topLevelStatement = Group(messageDefn | messageExtension | enumDefn | serviceDefn | importDirective | optionDirective) - -parser = Optional(packageDirective) + ZeroOrMore(topLevelStatement) - -parser.ignore(comment) - - -test1 = """message Person { - required int32 id = 1; - required string name = 2; - optional string email = 3; -}""" - -test2 = """package tutorial; - -message Person { - required string name = 1; - required int32 id = 2; - optional string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - required string number = 1; - optional PhoneType type = 2 [default = HOME]; - } - - repeated PhoneNumber phone = 4; -} - -message AddressBook { - repeated Person person = 1; -}""" - -parser.runTests([test1, test2]) diff --git a/trunk/src/examples/pymicko.py b/trunk/src/examples/pymicko.py deleted file mode 100644 index b136689..0000000 --- a/trunk/src/examples/pymicko.py +++ /dev/null @@ -1,1387 +0,0 @@ -#!/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 . - -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 -# -> -# -> parameter_list - -# parameter_list -# -> variable -# -> parameter_list "," variable - -# body -# -> "{" variable_list statement_list "}" -# -> "{" statement_list "}" - -# statement_list -# -> -# -> 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 -# -> -# -> argument_list - -# argument_list -# -> num_exp -# -> argument_list "," num_exp - -# function_call_statement -# -> function_call ";" - -# if_statement -# -> "if" "(" log_exp ")" statement -# -> "if" "(" log_exp ")" statement "else" statement -# -> -> -> -> -> -> -> -> 2 - -# log_exp -# -> and_exp -# -> log_exp "||" and_exp - -# and_exp -# -> rel_exp -# -> and_exp "&&" rel_exp - -# rel_exp -# -> num_exp "<" num_exp -# -> num_exp ">" num_exp -# -> num_exp "<=" num_exp -# -> num_exp ">=" num_exp -# -> num_exp "==" num_exp -# -> num_exp "!=" num_exp - -# while_statement -# -> "while" "(" log_exp ")" statement - -# return_statement -# -> "return" num_exp ";" - -# compound_statement -# -> "{" statement_list "}" - -# Comment: /* a comment */ - -########################################################################################## -########################################################################################## - -class Enumerate(dict): - """C enum emulation (original by Scott David Daniels)""" - def __init__(self, names): - for number, name in enumerate(names.split()): - setattr(self, name, number) - self[number] = name - -class SharedData(object): - """Data used in all three main classes""" - - #Possible kinds of symbol table entries - KINDS = Enumerate("NO_KIND WORKING_REGISTER GLOBAL_VAR FUNCTION PARAMETER LOCAL_VAR CONSTANT") - #Supported types of functions and variables - TYPES = Enumerate("NO_TYPE INT UNSIGNED") - - #bit size of variables - TYPE_BIT_SIZE = 16 - #min/max values of constants - MIN_INT = -2 ** (TYPE_BIT_SIZE - 1) - MAX_INT = 2 ** (TYPE_BIT_SIZE - 1) - 1 - MAX_UNSIGNED = 2 ** TYPE_BIT_SIZE - 1 - #available working registers (the last one is the register for function's return value!) - REGISTERS = "%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13".split() - #register for function's return value - FUNCTION_REGISTER = len(REGISTERS) - 1 - #the index of last working register - LAST_WORKING_REGISTER = len(REGISTERS) - 2 - #list of relational operators - RELATIONAL_OPERATORS = "< > <= >= == !=".split() - - def __init__(self): - #index of the currently parsed function - self.functon_index = 0 - #name of the currently parsed function - self.functon_name = 0 - #number of parameters of the currently parsed function - self.function_params = 0 - #number of local variables of the currently parsed function - self.function_vars = 0 - -########################################################################################## -########################################################################################## - -class ExceptionSharedData(object): - """Class for exception handling data""" - - def __init__(self): - #position in currently parsed text - self.location = 0 - #currently parsed text - self.text = "" - - def setpos(self, location, text): - """Helper function for setting curently parsed text and position""" - self.location = location - self.text = text - -exshared = ExceptionSharedData() - -class SemanticException(Exception): - """Exception for semantic errors found during parsing, similar to ParseException. - Introduced because ParseException is used internally in pyparsing and custom - messages got lost and replaced by pyparsing's generic errors. - """ - - def __init__(self, message, print_location=True): - super(SemanticException,self).__init__() - self._message = message - self.location = exshared.location - self.print_location = print_location - if exshared.location != None: - self.line = lineno(exshared.location, exshared.text) - self.col = col(exshared.location, exshared.text) - self.text = line(exshared.location, exshared.text) - else: - self.line = self.col = self.text = None - - def _get_message(self): - return self._message - def _set_message(self, message): - self._message = message - message = property(_get_message, _set_message) - - def __str__(self): - """String representation of the semantic error""" - msg = "Error" - if self.print_location and (self.line != None): - msg += " at line %d, col %d" % (self.line, self.col) - msg += ": %s" % self.message - if self.print_location and (self.line != None): - msg += "\n%s" % self.text - return msg - -########################################################################################## -########################################################################################## - -class SymbolTableEntry(object): - """Class which represents one symbol table entry.""" - - def __init__(self, sname = "", skind = 0, stype = 0, sattr = None, sattr_name = "None"): - """Initialization of symbol table entry. - sname - symbol name - skind - symbol kind - stype - symbol type - sattr - symbol attribute - sattr_name - symbol attribute name (used only for table display) - """ - self.name = sname - self.kind = skind - self.type = stype - self.attribute = sattr - self.attribute_name = sattr_name - self.param_types = [] - - def set_attribute(self, name, value): - """Sets attribute's name and value""" - self.attribute_name = name - self.attribute = value - - def attribute_str(self): - """Returns attribute string (used only for table display)""" - return "{0}={1}".format(self.attribute_name, self.attribute) if self.attribute != None else "None" - -class SymbolTable(object): - """Class for symbol table of microC program""" - - def __init__(self, shared): - """Initialization of the symbol table""" - self.table = [] - self.lable_len = 0 - #put working registers in the symbol table - for reg in range(SharedData.FUNCTION_REGISTER+1): - self.insert_symbol(SharedData.REGISTERS[reg], SharedData.KINDS.WORKING_REGISTER, SharedData.TYPES.NO_TYPE) - #shared data - self.shared = shared - - def error(self, text=""): - """Symbol table error exception. It should happen only if index is out of range while accessing symbol table. - This exeption is not handled by the compiler, so as to allow traceback printing - """ - if text == "": - raise Exception("Symbol table index out of range") - else: - raise Exception("Symbol table error: %s" % text) - - def display(self): - """Displays the symbol table content""" - #Finding the maximum length for each column - sym_name = "Symbol name" - sym_len = max(max(len(i.name) for i in self.table),len(sym_name)) - kind_name = "Kind" - kind_len = max(max(len(SharedData.KINDS[i.kind]) for i in self.table),len(kind_name)) - type_name = "Type" - type_len = max(max(len(SharedData.TYPES[i.type]) for i in self.table),len(type_name)) - attr_name = "Attribute" - attr_len = max(max(len(i.attribute_str()) for i in self.table),len(attr_name)) - #print table header - print("{0:3s} | {1:^{2}s} | {3:^{4}s} | {5:^{6}s} | {7:^{8}} | {9:s}".format(" No", sym_name, sym_len, kind_name, kind_len, type_name, type_len, attr_name, attr_len, "Parameters")) - print("-----------------------------" + "-" * (sym_len + kind_len + type_len + attr_len)) - #print symbol table - for i,sym in enumerate(self.table): - parameters = "" - for p in sym.param_types: - if parameters == "": - parameters = "{0}".format(SharedData.TYPES[p]) - else: - parameters += ", {0}".format(SharedData.TYPES[p]) - print("{0:3d} | {1:^{2}s} | {3:^{4}s} | {5:^{6}s} | {7:^{8}} | ({9})".format(i, sym.name, sym_len, SharedData.KINDS[sym.kind], kind_len, SharedData.TYPES[sym.type], type_len, sym.attribute_str(), attr_len, parameters)) - - def insert_symbol(self, sname, skind, stype): - """Inserts new symbol at the end of the symbol table. - Returns symbol index - sname - symbol name - skind - symbol kind - stype - symbol type - """ - self.table.append(SymbolTableEntry(sname, skind, stype)) - self.table_len = len(self.table) - return self.table_len-1 - - def clear_symbols(self, index): - """Clears all symbols begining with the index to the end of table""" - try: - del self.table[index:] - except Exception: - self.error() - self.table_len = len(self.table) - - def lookup_symbol(self, sname, skind=list(SharedData.KINDS.keys()), stype=list(SharedData.TYPES.keys())): - """Searches for symbol, from the end to the begining. - Returns symbol index or None - sname - symbol name - skind - symbol kind (one kind, list of kinds, or None) deafult: any kind - stype - symbol type (or None) default: any type - """ - skind = skind if isinstance(skind, list) else [skind] - stype = stype if isinstance(stype, list) else [stype] - for i, sym in [[x, self.table[x]] for x in range(len(self.table) - 1, SharedData.LAST_WORKING_REGISTER, -1)]: - if (sym.name == sname) and (sym.kind in skind) and (sym.type in stype): - return i - return None - - def insert_id(self, sname, skind, skinds, stype): - """Inserts a new identifier at the end of the symbol table, if possible. - Returns symbol index, or raises an exception if the symbol alredy exists - sname - symbol name - skind - symbol kind - skinds - symbol kinds to check for - stype - symbol type - """ - index = self.lookup_symbol(sname, skinds) - if index == None: - index = self.insert_symbol(sname, skind, stype) - return index - else: - raise SemanticException("Redefinition of '%s'" % sname) - - def insert_global_var(self, vname, vtype): - "Inserts a new global variable" - return self.insert_id(vname, SharedData.KINDS.GLOBAL_VAR, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.FUNCTION], vtype) - - def insert_local_var(self, vname, vtype, position): - "Inserts a new local variable" - index = self.insert_id(vname, SharedData.KINDS.LOCAL_VAR, [SharedData.KINDS.LOCAL_VAR, SharedData.KINDS.PARAMETER], vtype) - self.table[index].attribute = position - - def insert_parameter(self, pname, ptype): - "Inserts a new parameter" - index = self.insert_id(pname, SharedData.KINDS.PARAMETER, SharedData.KINDS.PARAMETER, ptype) - #set parameter's attribute to it's ordinal number - self.table[index].set_attribute("Index", self.shared.function_params) - #set parameter's type in param_types list of a function - self.table[self.shared.function_index].param_types.append(ptype) - return index - - def insert_function(self, fname, ftype): - "Inserts a new function" - index = self.insert_id(fname, SharedData.KINDS.FUNCTION, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.FUNCTION], ftype) - self.table[index].set_attribute("Params",0) - return index - - def insert_constant(self, cname, ctype): - """Inserts a constant (or returns index if the constant already exists) - Additionally, checks for range. - """ - index = self.lookup_symbol(cname, stype=ctype) - if index == None: - num = int(cname) - if ctype == SharedData.TYPES.INT: - if (num < SharedData.MIN_INT) or (num > SharedData.MAX_INT): - raise SemanticException("Integer constant '%s' out of range" % cname) - elif ctype == SharedData.TYPES.UNSIGNED: - if (num < 0) or (num > SharedData.MAX_UNSIGNED): - raise SemanticException("Unsigned constant '%s' out of range" % cname) - index = self.insert_symbol(cname, SharedData.KINDS.CONSTANT, ctype) - return index - - def same_types(self, index1, index2): - """Returns True if both symbol table elements are of the same type""" - try: - same = self.table[index1].type == self.table[index2].type != SharedData.TYPES.NO_TYPE - except Exception: - self.error() - return same - - def same_type_as_argument(self, index, function_index, argument_number): - """Returns True if index and function's argument are of the same type - index - index in symbol table - function_index - function's index in symbol table - argument_number - # of function's argument - """ - try: - same = self.table[function_index].param_types[argument_number] == self.table[index].type - except Exception: - self.error() - return same - - def get_attribute(self, index): - try: - return self.table[index].attribute - except Exception: - self.error() - - def set_attribute(self, index, value): - try: - self.table[index].attribute = value - except Exception: - self.error() - - def get_name(self, index): - try: - return self.table[index].name - except Exception: - self.error() - - def get_kind(self, index): - try: - return self.table[index].kind - except Exception: - self.error() - - def get_type(self, index): - try: - return self.table[index].type - except Exception: - self.error() - - def set_type(self, index, stype): - try: - self.table[index].type = stype - except Exception: - self.error() - -########################################################################################## -########################################################################################## - -class CodeGenerator(object): - """Class for code generation methods.""" - - #dictionary of relational operators - RELATIONAL_DICT = dict([op,i] for i, op in enumerate(SharedData.RELATIONAL_OPERATORS)) - #conditional jumps for relational operators - CONDITIONAL_JUMPS = ["JLTS", "JGTS", "JLES", "JGES", "JEQ ", "JNE ", - "JLTU", "JGTU", "JLEU", "JGEU", "JEQ ", "JNE "] - #opposite conditional jumps for relational operators - OPPOSITE_JUMPS = ["JGES", "JLES", "JGTS", "JLTS", "JNE ", "JEQ ", - "JGEU", "JLEU", "JGTU", "JLTU", "JNE ", "JEQ "] - #supported operations - OPERATIONS = {"+" : "ADD", "-" : "SUB", "*" : "MUL", "/" : "DIV"} - #suffixes for signed and unsigned operations (if no type is specified, unsigned will be assumed) - OPSIGNS = {SharedData.TYPES.NO_TYPE : "U", SharedData.TYPES.INT : "S", SharedData.TYPES.UNSIGNED : "U"} - #text at start of data segment - DATA_START_TEXT = "#DATA" - #text at start of code segment - CODE_START_TEXT = "#CODE" - - def __init__(self, shared, symtab): - #generated code - self.code = "" - #prefix for internal labels - self.internal = "@" - #suffix for label definition - self.definition = ":" - #list of free working registers - self.free_registers = list(range(SharedData.FUNCTION_REGISTER, -1, -1)) - #list of used working registers - self.used_registers = [] - #list of used registers needed when function call is inside of a function call - self.used_registers_stack = [] - #shared data - self.shared = shared - #symbol table - self.symtab = symtab - - def error(self, text): - """Compiler error exception. It should happen only if something is wrong with compiler. - This exeption is not handled by the compiler, so as to allow traceback printing - """ - raise Exception("Compiler error: %s" % text) - - def take_register(self, rtype = SharedData.TYPES.NO_TYPE): - """Reserves one working register and sets its type""" - if len(self.free_registers) == 0: - self.error("no more free registers") - reg = self.free_registers.pop() - self.used_registers.append(reg) - self.symtab.set_type(reg, rtype) - return reg - - def take_function_register(self, rtype = SharedData.TYPES.NO_TYPE): - """Reserves register for function return value and sets its type""" - reg = SharedData.FUNCTION_REGISTER - if reg not in self.free_registers: - self.error("function register already taken") - self.free_registers.remove(reg) - self.used_registers.append(reg) - self.symtab.set_type(reg, rtype) - return reg - - def free_register(self, reg): - """Releases working register""" - if reg not in self.used_registers: - self.error("register %s is not taken" % self.REGISTERS[reg]) - self.used_registers.remove(reg) - self.free_registers.append(reg) - self.free_registers.sort(reverse = True) - - def free_if_register(self, index): - """If index is a working register, free it, otherwise just return (helper function)""" - if (index < 0) or (index > SharedData.FUNCTION_REGISTER): - return - else: - self.free_register(index) - - def label(self, name, internal=False, definition=False): - """Generates label name (helper function) - name - label name - internal - boolean value, adds "@" prefix to label - definition - boolean value, adds ":" suffix to label - """ - return "{0}{1}{2}".format(self.internal if internal else "", name, self.definition if definition else "") - - def symbol(self, index): - """Generates symbol name from index""" - #if index is actually a string, just return it - if isinstance(index, str): - return index - elif (index < 0) or (index >= self.symtab.table_len): - self.error("symbol table index out of range") - sym = self.symtab.table[index] - #local variables are located at negative offset from frame pointer register - if sym.kind == SharedData.KINDS.LOCAL_VAR: - return "-{0}(%14)".format(sym.attribute * 4 + 4) - #parameters are located at positive offset from frame pointer register - elif sym.kind == SharedData.KINDS.PARAMETER: - return "{0}(%14)".format(8 + sym.attribute * 4) - elif sym.kind == SharedData.KINDS.CONSTANT: - return "${0}".format(sym.name) - else: - return "{0}".format(sym.name) - - def save_used_registers(self): - """Pushes all used working registers before function call""" - used = self.used_registers[:] - del self.used_registers[:] - self.used_registers_stack.append(used[:]) - used.sort() - for reg in used: - self.newline_text("PUSH\t%s" % SharedData.REGISTERS[reg], True) - self.free_registers.extend(used) - self.free_registers.sort(reverse = True) - - def restore_used_registers(self): - """Pops all used working registers after function call""" - used = self.used_registers_stack.pop() - self.used_registers = used[:] - used.sort(reverse = True) - for reg in used: - self.newline_text("POP \t%s" % SharedData.REGISTERS[reg], True) - self.free_registers.remove(reg) - - def text(self, text): - """Inserts text into generated code""" - self.code += text - - def prepare_data_segment(self): - """Inserts text at the start of data segment""" - self.text(self.DATA_START_TEXT) - - def prepare_code_segment(self): - """Inserts text at the start of code segment""" - self.newline_text(self.CODE_START_TEXT) - - def newline(self, indent=False): - """Inserts a newline, optionally with indentation.""" - self.text("\n") - if indent: - self.text("\t\t\t") - - def newline_text(self, text, indent = False): - """Inserts a newline and text, optionally with indentation (helper function)""" - self.newline(indent) - self.text(text) - - def newline_label(self, name, internal=False, definition=False): - """Inserts a newline and a label (helper function) - name - label name - internal - boolean value, adds "@" prefix to label - definition - boolean value, adds ":" suffix to label - """ - self.newline_text(self.label("{0}{1}{2}".format("@" if internal else "", name, ":" if definition else ""))) - - def global_var(self, name): - """Inserts a new static (global) variable definition""" - self.newline_label(name, False, True) - self.newline_text("WORD\t1", True) - - def arithmetic_mnemonic(self, op_name, op_type): - """Generates an arithmetic instruction mnemonic""" - return self.OPERATIONS[op_name] + self.OPSIGNS[op_type] - - def arithmetic(self, operation, operand1, operand2, operand3 = None): - """Generates an arithmetic instruction - operation - one of supporetd operations - operandX - index in symbol table or text representation of operand - First two operands are input, third one is output - """ - if isinstance(operand1, int): - output_type = self.symtab.get_type(operand1) - self.free_if_register(operand1) - else: - output_type = None - if isinstance(operand2, int): - output_type = self.symtab.get_type(operand2) if output_type == None else output_type - self.free_if_register(operand2) - else: - output_type = SharedData.TYPES.NO_TYPE if output_type == None else output_type - #if operand3 is not defined, reserve one free register for it - output = self.take_register(output_type) if operand3 == None else operand3 - mnemonic = self.arithmetic_mnemonic(operation, output_type) - self.newline_text("{0}\t{1},{2},{3}".format(mnemonic, self.symbol(operand1), self.symbol(operand2), self.symbol(output)), True) - return output - - def relop_code(self, relop, operands_type): - """Returns code for relational operator - relop - relational operator - operands_type - int or unsigned - """ - code = self.RELATIONAL_DICT[relop] - offset = 0 if operands_type == SharedData.TYPES.INT else len(SharedData.RELATIONAL_OPERATORS) - return code + offset - - def jump(self, relcode, opposite, label): - """Generates a jump instruction - relcode - relational operator code - opposite - generate normal or opposite jump - label - jump label - """ - jump = self.OPPOSITE_JUMPS[relcode] if opposite else self.CONDITIONAL_JUMPS[relcode] - self.newline_text("{0}\t{1}".format(jump, label), True) - - def unconditional_jump(self, label): - """Generates an unconditional jump instruction - label - jump label - """ - self.newline_text("JMP \t{0}".format(label), True) - - def move(self,operand1, operand2): - """Generates a move instruction - If the output operand (opernad2) is a working register, sets it's type - operandX - index in symbol table or text representation of operand - """ - if isinstance(operand1, int): - output_type = self.symtab.get_type(operand1) - self.free_if_register(operand1) - else: - output_type = SharedData.TYPES.NO_TYPE - self.newline_text("MOV \t{0},{1}".format(self.symbol(operand1), self.symbol(operand2)), True) - if isinstance(operand2, int): - if self.symtab.get_kind(operand2) == SharedData.KINDS.WORKING_REGISTER: - self.symtab.set_type(operand2, output_type) - - def push(self, operand): - """Generates a push operation""" - self.newline_text("PUSH\t%s" % self.symbol(operand), True) - - def pop(self, operand): - """Generates a pop instruction""" - self.newline_text("POP \t%s" % self.symbol(operand), True) - - def compare(self, operand1, operand2): - """Generates a compare instruction - operandX - index in symbol table - """ - typ = self.symtab.get_type(operand1) - self.free_if_register(operand1) - self.free_if_register(operand2) - self.newline_text("CMP{0}\t{1},{2}".format(self.OPSIGNS[typ], self.symbol(operand1), self.symbol(operand2)), True) - - def function_begin(self): - """Inserts function name label and function frame initialization""" - self.newline_label(self.shared.function_name, False, True) - self.push("%14") - self.move("%15", "%14") - - def function_body(self): - """Inserts a local variable initialization and body label""" - if self.shared.function_vars > 0: - const = self.symtab.insert_constant("{0}".format(self.shared.function_vars * 4), SharedData.TYPES.UNSIGNED) - self.arithmetic("-", "%15", const, "%15") - self.newline_label(self.shared.function_name + "_body", True, True) - - def function_end(self): - """Inserts an exit label and function return instructions""" - self.newline_label(self.shared.function_name + "_exit", True, True) - self.move("%14", "%15") - self.pop("%14") - self.newline_text("RET", True) - - def function_call(self, function, arguments): - """Generates code for a function call - function - function index in symbol table - arguments - list of arguments (indexes in symbol table) - """ - #push each argument to stack - for arg in arguments: - self.push(self.symbol(arg)) - self.free_if_register(arg) - self.newline_text("CALL\t"+self.symtab.get_name(function), True) - args = self.symtab.get_attribute(function) - #generates stack cleanup if function has arguments - if args > 0: - args_space = self.symtab.insert_constant("{0}".format(args * 4), SharedData.TYPES.UNSIGNED) - self.arithmetic("+", "%15", args_space, "%15") - -########################################################################################## -########################################################################################## - -class MicroC(object): - """Class for microC parser/compiler""" - - def __init__(self): - #Definitions of terminal symbols for microC programming language - self.tId = Word(alphas+"_",alphanums+"_") - self.tInteger = Word(nums).setParseAction(lambda x : [x[0], SharedData.TYPES.INT]) - self.tUnsigned = Regex(r"[0-9]+[uU]").setParseAction(lambda x : [x[0][:-1], SharedData.TYPES.UNSIGNED]) - self.tConstant = (self.tUnsigned | self.tInteger).setParseAction(self.constant_action) - self.tType = Keyword("int").setParseAction(lambda x : SharedData.TYPES.INT) | \ - Keyword("unsigned").setParseAction(lambda x : SharedData.TYPES.UNSIGNED) - self.tRelOp = oneOf(SharedData.RELATIONAL_OPERATORS) - self.tMulOp = oneOf("* /") - self.tAddOp = oneOf("+ -") - - #Definitions of rules for global variables - self.rGlobalVariable = (self.tType("type") + self.tId("name") + - FollowedBy(";")).setParseAction(self.global_variable_action) - self.rGlobalVariableList = ZeroOrMore(self.rGlobalVariable + Suppress(";")) - - #Definitions of rules for numeric expressions - self.rExp = Forward() - self.rMulExp = Forward() - self.rNumExp = Forward() - self.rArguments = delimitedList(self.rNumExp("exp").setParseAction(self.argument_action)) - self.rFunctionCall = ((self.tId("name") + FollowedBy("(")).setParseAction(self.function_call_prepare_action) + - Suppress("(") + Optional(self.rArguments)("args") + Suppress(")")).setParseAction(self.function_call_action) - self.rExp << (self.rFunctionCall | - self.tConstant | - self.tId("name").setParseAction(self.lookup_id_action) | - Group(Suppress("(") + self.rNumExp + Suppress(")")) | - Group("+" + self.rExp) | - Group("-" + self.rExp)).setParseAction(lambda x : x[0]) - self.rMulExp << ((self.rExp + ZeroOrMore(self.tMulOp + self.rExp))).setParseAction(self.mulexp_action) - self.rNumExp << (self.rMulExp + ZeroOrMore(self.tAddOp + self.rMulExp)).setParseAction(self.numexp_action) - - #Definitions of rules for logical expressions (these are without parenthesis support) - self.rAndExp = Forward() - self.rLogExp = Forward() - self.rRelExp = (self.rNumExp + self.tRelOp + self.rNumExp).setParseAction(self.relexp_action) - self.rAndExp << (self.rRelExp("exp") + ZeroOrMore(Literal("&&").setParseAction(self.andexp_action) + - self.rRelExp("exp")).setParseAction(lambda x : self.relexp_code)) - self.rLogExp << (self.rAndExp("exp") + ZeroOrMore(Literal("||").setParseAction(self.logexp_action) + - self.rAndExp("exp")).setParseAction(lambda x : self.andexp_code)) - - #Definitions of rules for statements - self.rStatement = Forward() - self.rStatementList = Forward() - self.rReturnStatement = (Keyword("return") + self.rNumExp("exp") + - Suppress(";")).setParseAction(self.return_action) - self.rAssignmentStatement = (self.tId("var") + Suppress("=") + self.rNumExp("exp") + - Suppress(";")).setParseAction(self.assignment_action) - self.rFunctionCallStatement = self.rFunctionCall + Suppress(";") - self.rIfStatement = ( (Keyword("if") + FollowedBy("(")).setParseAction(self.if_begin_action) + - (Suppress("(") + self.rLogExp + Suppress(")")).setParseAction(self.if_body_action) + - (self.rStatement + Empty()).setParseAction(self.if_else_action) + - Optional(Keyword("else") + self.rStatement)).setParseAction(self.if_end_action) - self.rWhileStatement = ( (Keyword("while") + FollowedBy("(")).setParseAction(self.while_begin_action) + - (Suppress("(") + self.rLogExp + Suppress(")")).setParseAction(self.while_body_action) + - self.rStatement).setParseAction(self.while_end_action) - self.rCompoundStatement = Group(Suppress("{") + self.rStatementList + Suppress("}")) - self.rStatement << (self.rReturnStatement | self.rIfStatement | self.rWhileStatement | - self.rFunctionCallStatement | self.rAssignmentStatement | self.rCompoundStatement) - self.rStatementList << ZeroOrMore(self.rStatement) - - self.rLocalVariable = (self.tType("type") + self.tId("name") + FollowedBy(";")).setParseAction(self.local_variable_action) - self.rLocalVariableList = ZeroOrMore(self.rLocalVariable + Suppress(";")) - self.rFunctionBody = Suppress("{") + Optional(self.rLocalVariableList).setParseAction(self.function_body_action) + \ - self.rStatementList + Suppress("}") - self.rParameter = (self.tType("type") + self.tId("name")).setParseAction(self.parameter_action) - self.rParameterList = delimitedList(self.rParameter) - self.rFunction = ( (self.tType("type") + self.tId("name")).setParseAction(self.function_begin_action) + - Group(Suppress("(") + Optional(self.rParameterList)("params") + Suppress(")") + - self.rFunctionBody)).setParseAction(self.function_end_action) - - self.rFunctionList = OneOrMore(self.rFunction) - self.rProgram = (Empty().setParseAction(self.data_begin_action) + self.rGlobalVariableList + - Empty().setParseAction(self.code_begin_action) + self.rFunctionList).setParseAction(self.program_end_action) - - #shared data - self.shared = SharedData() - #symbol table - self.symtab = SymbolTable(self.shared) - #code generator - self.codegen = CodeGenerator(self.shared, self.symtab) - - #index of the current function call - self.function_call_index = -1 - #stack for the nested function calls - self.function_call_stack = [] - #arguments of the current function call - self.function_arguments = [] - #stack for arguments of the nested function calls - self.function_arguments_stack = [] - #number of arguments for the curent function call - self.function_arguments_number = -1 - #stack for the number of arguments for the nested function calls - self.function_arguments_number_stack = [] - - #last relational expression - self.relexp_code = None - #last and expression - self.andexp_code = None - #label number for "false" internal labels - self.false_label_number = -1 - #label number for all other internal labels - self.label_number = None - #label stack for nested statements - self.label_stack = [] - - def warning(self, message, print_location=True): - """Displays warning message. Uses exshared for current location of parsing""" - msg = "Warning" - if print_location and (exshared.location != None): - wline = lineno(exshared.location, exshared.text) - wcol = col(exshared.location, exshared.text) - wtext = line(exshared.location, exshared.text) - msg += " at line %d, col %d" % (wline, wcol) - msg += ": %s" % message - if print_location and (exshared.location != None): - msg += "\n%s" % wtext - print(msg) - - - def data_begin_action(self): - """Inserts text at start of data segment""" - self.codegen.prepare_data_segment() - - def code_begin_action(self): - """Inserts text at start of code segment""" - self.codegen.prepare_code_segment() - - def global_variable_action(self, text, loc, var): - """Code executed after recognising a global variable""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("GLOBAL_VAR:",var) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - index = self.symtab.insert_global_var(var.name, var.type) - self.codegen.global_var(var.name) - return index - - def local_variable_action(self, text, loc, var): - """Code executed after recognising a local variable""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("LOCAL_VAR:",var, var.name, var.type) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - index = self.symtab.insert_local_var(var.name, var.type, self.shared.function_vars) - self.shared.function_vars += 1 - return index - - def parameter_action(self, text, loc, par): - """Code executed after recognising a parameter""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("PARAM:",par) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - index = self.symtab.insert_parameter(par.name, par.type) - self.shared.function_params += 1 - return index - - def constant_action(self, text, loc, const): - """Code executed after recognising a constant""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("CONST:",const) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - return self.symtab.insert_constant(const[0], const[1]) - - def function_begin_action(self, text, loc, fun): - """Code executed after recognising a function definition (type and function name)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("FUN_BEGIN:",fun) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - self.shared.function_index = self.symtab.insert_function(fun.name, fun.type) - self.shared.function_name = fun.name - self.shared.function_params = 0 - self.shared.function_vars = 0 - self.codegen.function_begin(); - - def function_body_action(self, text, loc, fun): - """Code executed after recognising the beginning of function's body""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("FUN_BODY:",fun) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - self.codegen.function_body() - - def function_end_action(self, text, loc, fun): - """Code executed at the end of function definition""" - if DEBUG > 0: - print("FUN_END:",fun) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #set function's attribute to number of function parameters - self.symtab.set_attribute(self.shared.function_index, self.shared.function_params) - #clear local function symbols (but leave function name) - self.symtab.clear_symbols(self.shared.function_index + 1) - self.codegen.function_end() - - def return_action(self, text, loc, ret): - """Code executed after recognising a return statement""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("RETURN:",ret) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - if not self.symtab.same_types(self.shared.function_index, ret.exp[0]): - raise SemanticException("Incompatible type in return") - #set register for function's return value to expression value - reg = self.codegen.take_function_register() - self.codegen.move(ret.exp[0], reg) - #after return statement, register for function's return value is available again - self.codegen.free_register(reg) - #jump to function's exit - self.codegen.unconditional_jump(self.codegen.label(self.shared.function_name+"_exit", True)) - - def lookup_id_action(self, text, loc, var): - """Code executed after recognising an identificator in expression""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("EXP_VAR:",var) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - var_index = self.symtab.lookup_symbol(var.name, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.PARAMETER, SharedData.KINDS.LOCAL_VAR]) - if var_index == None: - raise SemanticException("'%s' undefined" % var.name) - return var_index - - def assignment_action(self, text, loc, assign): - """Code executed after recognising an assignment statement""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("ASSIGN:",assign) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - var_index = self.symtab.lookup_symbol(assign.var, [SharedData.KINDS.GLOBAL_VAR, SharedData.KINDS.PARAMETER, SharedData.KINDS.LOCAL_VAR]) - if var_index == None: - raise SemanticException("Undefined lvalue '%s' in assignment" % assign.var) - if not self.symtab.same_types(var_index, assign.exp[0]): - raise SemanticException("Incompatible types in assignment") - self.codegen.move(assign.exp[0], var_index) - - def mulexp_action(self, text, loc, mul): - """Code executed after recognising a mulexp expression (something *|/ something)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("MUL_EXP:",mul) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #iterate through all multiplications/divisions - m = list(mul) - while len(m) > 1: - if not self.symtab.same_types(m[0], m[2]): - raise SemanticException("Invalid opernads to binary '%s'" % m[1]) - reg = self.codegen.arithmetic(m[1], m[0], m[2]) - #replace first calculation with it's result - m[0:3] = [reg] - return m[0] - - def numexp_action(self, text, loc, num): - """Code executed after recognising a numexp expression (something +|- something)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("NUM_EXP:",num) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #iterate through all additions/substractions - n = list(num) - while len(n) > 1: - if not self.symtab.same_types(n[0], n[2]): - raise SemanticException("Invalid opernads to binary '%s'" % n[1]) - reg = self.codegen.arithmetic(n[1], n[0], n[2]) - #replace first calculation with it's result - n[0:3] = [reg] - return n[0] - - def function_call_prepare_action(self, text, loc, fun): - """Code executed after recognising a function call (type and function name)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("FUN_PREP:",fun) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - index = self.symtab.lookup_symbol(fun.name, SharedData.KINDS.FUNCTION) - if index == None: - raise SemanticException("'%s' is not a function" % fun.name) - #save any previous function call data (for nested function calls) - self.function_call_stack.append(self.function_call_index) - self.function_call_index = index - self.function_arguments_stack.append(self.function_arguments[:]) - del self.function_arguments[:] - self.codegen.save_used_registers() - - def argument_action(self, text, loc, arg): - """Code executed after recognising each of function's arguments""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("ARGUMENT:",arg.exp) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - arg_ordinal = len(self.function_arguments) - #check argument's type - if not self.symtab.same_type_as_argument(arg.exp, self.function_call_index, arg_ordinal): - raise SemanticException("Incompatible type for argument %d in '%s'" % (arg_ordinal + 1, self.symtab.get_name(self.function_call_index))) - self.function_arguments.append(arg.exp) - - def function_call_action(self, text, loc, fun): - """Code executed after recognising the whole function call""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("FUN_CALL:",fun) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #check number of arguments - if len(self.function_arguments) != self.symtab.get_attribute(self.function_call_index): - raise SemanticException("Wrong number of arguments for function '%s'" % fun.name) - #arguments should be pushed to stack in reverse order - self.function_arguments.reverse() - self.codegen.function_call(self.function_call_index, self.function_arguments) - self.codegen.restore_used_registers() - return_type = self.symtab.get_type(self.function_call_index) - #restore previous function call data - self.function_call_index = self.function_call_stack.pop() - self.function_arguments = self.function_arguments_stack.pop() - register = self.codegen.take_register(return_type) - #move result to a new free register, to allow the next function call - self.codegen.move(self.codegen.take_function_register(return_type), register) - return register - - def relexp_action(self, text, loc, arg): - """Code executed after recognising a relexp expression (something relop something)""" - if DEBUG > 0: - print("REL_EXP:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - exshared.setpos(loc, text) - if not self.symtab.same_types(arg[0], arg[2]): - raise SemanticException("Invalid operands for operator '{0}'".format(arg[1])) - self.codegen.compare(arg[0], arg[2]) - #return relational operator's code - self.relexp_code = self.codegen.relop_code(arg[1], self.symtab.get_type(arg[0])) - return self.relexp_code - - def andexp_action(self, text, loc, arg): - """Code executed after recognising a andexp expression (something and something)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("AND+EXP:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - label = self.codegen.label("false{0}".format(self.false_label_number), True, False) - self.codegen.jump(self.relexp_code, True, label) - self.andexp_code = self.relexp_code - return self.andexp_code - - def logexp_action(self, text, loc, arg): - """Code executed after recognising logexp expression (something or something)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("LOG_EXP:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - label = self.codegen.label("true{0}".format(self.label_number), True, False) - self.codegen.jump(self.relexp_code, False, label) - self.codegen.newline_label("false{0}".format(self.false_label_number), True, True) - self.false_label_number += 1 - - def if_begin_action(self, text, loc, arg): - """Code executed after recognising an if statement (if keyword)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("IF_BEGIN:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - self.false_label_number += 1 - self.label_number = self.false_label_number - self.codegen.newline_label("if{0}".format(self.label_number), True, True) - - def if_body_action(self, text, loc, arg): - """Code executed after recognising if statement's body""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("IF_BODY:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #generate conditional jump (based on last compare) - label = self.codegen.label("false{0}".format(self.false_label_number), True, False) - self.codegen.jump(self.relexp_code, True, label) - #generate 'true' label (executes if condition is satisfied) - self.codegen.newline_label("true{0}".format(self.label_number), True, True) - #save label numbers (needed for nested if/while statements) - self.label_stack.append(self.false_label_number) - self.label_stack.append(self.label_number) - - def if_else_action(self, text, loc, arg): - """Code executed after recognising if statement's else body""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("IF_ELSE:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #jump to exit after all statements for true condition are executed - self.label_number = self.label_stack.pop() - label = self.codegen.label("exit{0}".format(self.label_number), True, False) - self.codegen.unconditional_jump(label) - #generate final 'false' label (executes if condition isn't satisfied) - self.codegen.newline_label("false{0}".format(self.label_stack.pop()), True, True) - self.label_stack.append(self.label_number) - - def if_end_action(self, text, loc, arg): - """Code executed after recognising a whole if statement""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("IF_END:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - self.codegen.newline_label("exit{0}".format(self.label_stack.pop()), True, True) - - def while_begin_action(self, text, loc, arg): - """Code executed after recognising a while statement (while keyword)""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("WHILE_BEGIN:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - self.false_label_number += 1 - self.label_number = self.false_label_number - self.codegen.newline_label("while{0}".format(self.label_number), True, True) - - def while_body_action(self, text, loc, arg): - """Code executed after recognising while statement's body""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("WHILE_BODY:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #generate conditional jump (based on last compare) - label = self.codegen.label("false{0}".format(self.false_label_number), True, False) - self.codegen.jump(self.relexp_code, True, label) - #generate 'true' label (executes if condition is satisfied) - self.codegen.newline_label("true{0}".format(self.label_number), True, True) - self.label_stack.append(self.false_label_number) - self.label_stack.append(self.label_number) - - def while_end_action(self, text, loc, arg): - """Code executed after recognising a whole while statement""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("WHILE_END:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - #jump to condition checking after while statement body - self.label_number = self.label_stack.pop() - label = self.codegen.label("while{0}".format(self.label_number), True, False) - self.codegen.unconditional_jump(label) - #generate final 'false' label and exit label - self.codegen.newline_label("false{0}".format(self.label_stack.pop()), True, True) - self.codegen.newline_label("exit{0}".format(self.label_number), True, True) - - def program_end_action(self, text, loc, arg): - """Checks if there is a 'main' function and the type of 'main' function""" - exshared.setpos(loc, text) - if DEBUG > 0: - print("PROGRAM_END:",arg) - if DEBUG == 2: self.symtab.display() - if DEBUG > 2: return - index = self.symtab.lookup_symbol("main",SharedData.KINDS.FUNCTION) - if index == None: - raise SemanticException("Undefined reference to 'main'", False) - elif self.symtab.get_type(index) != SharedData.TYPES.INT: - self.warning("Return type of 'main' is not int", False) - - def parse_text(self,text): - """Parse string (helper function)""" - try: - return self.rProgram.ignore(cStyleComment).parseString(text, parseAll=True) - except SemanticException as err: - print(err) - exit(3) - except ParseException as err: - print(err) - exit(3) - - def parse_file(self,filename): - """Parse file (helper function)""" - try: - return self.rProgram.ignore(cStyleComment).parseFile(filename, parseAll=True) - except SemanticException as err: - print(err) - exit(3) - except ParseException as err: - print(err) - exit(3) - -########################################################################################## -########################################################################################## -if 0: - #main program - mc = MicroC() - output_file = "output.asm" - - if len(argv) == 1: - input_file = stdin - elif len(argv) == 2: - input_file = argv[1] - elif len(argv) == 3: - input_file = argv[1] - output_file = argv[2] - else: - usage = """Usage: {0} [input_file [output_file]] - If output file is omitted, output.asm is used - If input file is omitted, stdin is used""".format(argv[0]) - print(usage) - exit(1) - try: - parse = stdin if input_file == stdin else open(input_file,'r') - except Exception: - print("Input file '%s' open error" % input_file) - exit(2) - mc.parse_file(parse) - #if you want to see the final symbol table, uncomment next line - #mc.symtab.display() - try: - out = open(output_file, 'w') - out.write(mc.codegen.code) - out.close - except Exception: - print("Output file '%s' open error" % output_file) - exit(2) - -########################################################################################## -########################################################################################## - -if __name__ == "__main__": - - test_program_example = """ - int a; - int b; - int c; - unsigned d; - - int fun1(int x, unsigned y) { - return 123; - } - - int fun2(int a) { - return 1 + a * fun1(a, 456u); - } - - int main(int x, int y) { - int w; - unsigned z; - if (9 > 8 && 2 < 3 || 6 != 5 && a <= b && c < x || w >= y) { - a = b + 1; - if (x == y) - while (d < 4u) - x = x * w; - else - while (a + b < c - y && x > 3 || y < 2) - if (z > d) - a = a - 4; - else - b = a * b * c * x / y; - } - else - c = 4; - a = fun1(x,d) + fun2(fun1(fun2(w + 3 * 2) + 2 * c, 2u)); - return 2; - } - """ - - mc = MicroC() - mc.parse_text(test_program_example) - print(mc.codegen.code) \ No newline at end of file diff --git a/trunk/src/examples/pythonGrammarParser.py b/trunk/src/examples/pythonGrammarParser.py deleted file mode 100644 index f0631b8..0000000 --- a/trunk/src/examples/pythonGrammarParser.py +++ /dev/null @@ -1,220 +0,0 @@ -# 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 will probably be listening there. - -# Commands for Kees Blom's railroad program -#diagram:token NAME -#diagram:token NUMBER -#diagram:token STRING -#diagram:token NEWLINE -#diagram:token ENDMARKER -#diagram:token INDENT -#diagram:output\input python.bla -#diagram:token DEDENT -#diagram:output\textwidth 20.04cm\oddsidemargin 0.0cm\evensidemargin 0.0cm -#diagram:rules - -# Start symbols for the grammar: -# single_input is a single interactive statement; -# file_input is a module or sequence of commands read from an input file; -# eval_input is the input for the eval() and input() functions. -# NB: compound_stmt in single_input is followed by extra NEWLINE! -single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE -file_input: (NEWLINE | stmt)* ENDMARKER -eval_input: testlist NEWLINE* ENDMARKER - -decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE -decorators: decorator+ -funcdef: [decorators] 'def' NAME parameters ':' suite -parameters: '(' [varargslist] ')' -varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] -fpdef: NAME | '(' fplist ')' -fplist: fpdef (',' fpdef)* [','] - -stmt: simple_stmt | compound_stmt -simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE -small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt -expr_stmt: testlist (augassign testlist | ('=' testlist)*) -augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' -# For normal assignments, additional restrictions enforced by the interpreter -print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] ) -del_stmt: 'del' exprlist -pass_stmt: 'pass' -flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt -break_stmt: 'break' -continue_stmt: 'continue' -return_stmt: 'return' [testlist] -yield_stmt: 'yield' testlist -raise_stmt: 'raise' [test [',' test [',' test]]] -import_stmt: import_name | import_from -import_name: 'import' dotted_as_names -import_from: 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) -import_as_name: NAME [NAME NAME] -dotted_as_name: dotted_name [NAME NAME] -import_as_names: import_as_name (',' import_as_name)* [','] -dotted_as_names: dotted_as_name (',' dotted_as_name)* -dotted_name: NAME ('.' NAME)* -global_stmt: 'global' NAME (',' NAME)* -exec_stmt: 'exec' expr ['in' test [',' test]] -assert_stmt: 'assert' test [',' test] -#35 -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef -if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] -while_stmt: 'while' test ':' suite ['else' ':' suite] -for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] -try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break - ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite) -# NB compile.c makes sure that the default except clause is last -except_clause: 'except' [test [',' test]] -suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT - -test: and_test ('or' and_test)* | lambdef -and_test: not_test ('and' not_test)* -not_test: 'not' not_test | comparison -comparison: expr (comp_op expr)* -comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' -expr: xor_expr ('|' xor_expr)* -xor_expr: and_expr ('^' and_expr)* -and_expr: shift_expr ('&' shift_expr)* -shift_expr: arith_expr (('<<'|'>>') arith_expr)* -arith_expr: term (('+'|'-') term)* -term: factor (('*'|'/'|'%'|'//') factor)* -factor: ('+'|'-'|'~') factor | power -power: atom trailer* ['**' factor] -atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+ -listmaker: test ( list_for | (',' test)* [','] ) -testlist_gexp: test ( gen_for | (',' test)* [','] ) -lambdef: 'lambda' [varargslist] ':' test -trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME -subscriptlist: subscript (',' subscript)* [','] -subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] -sliceop: ':' [test] -exprlist: expr (',' expr)* [','] -testlist: test (',' test)* [','] -testlist_safe: test [(',' test)+ [',']] -dictmaker: test ':' test (',' test ':' test)* [','] - -classdef: 'class' NAME ['(' testlist ')'] ':' suite - -arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) -argument: [test '='] test [gen_for] # Really [keyword '='] test - -list_iter: list_for | list_if -list_for: 'for' exprlist 'in' testlist_safe [list_iter] -list_if: 'if' test [list_iter] - -gen_iter: gen_for | gen_if -gen_for: 'for' exprlist 'in' test [gen_iter] -gen_if: 'if' test [gen_iter] - -testlist1: test (',' test)* - -# not used in grammar, but may appear in "node" passed from Parser to Compiler -encoding_decl: NAME -""" - -class SemanticGroup(object): - def __init__(self,contents): - self.contents = contents - while self.contents[-1].__class__ == self.__class__: - self.contents = self.contents[:-1] + self.contents[-1].contents - - def __str__(self): - return "%s(%s)" % (self.label, - " ".join([isinstance(c,str) and c or str(c) for c in self.contents]) ) - -class OrList(SemanticGroup): - label = "OR" - pass - -class AndList(SemanticGroup): - label = "AND" - pass - -class OptionalGroup(SemanticGroup): - label = "OPT" - pass - -class Atom(SemanticGroup): - def __init__(self,contents): - if len(contents) > 1: - self.rep = contents[1] - else: - self.rep = "" - if isinstance(contents,str): - self.contents = contents - else: - self.contents = contents[0] - - def __str__(self): - return "%s%s" % (self.rep, self.contents) - -def makeGroupObject(cls): - def groupAction(s,l,t): - try: - return cls(t[0].asList()) - except: - return cls(t) - return groupAction - - -# bnf punctuation -LPAREN = Suppress("(") -RPAREN = Suppress(")") -LBRACK = Suppress("[") -RBRACK = Suppress("]") -COLON = Suppress(":") -ALT_OP = Suppress("|") - -# bnf grammar -ident = Word(alphanums+"_") -bnfToken = Word(alphanums+"_") + ~FollowedBy(":") -repSymbol = oneOf("* +") -bnfExpr = Forward() -optionalTerm = Group(LBRACK + bnfExpr + RBRACK).setParseAction(makeGroupObject(OptionalGroup)) -bnfTerm = ( (bnfToken | quotedString | optionalTerm | ( LPAREN + bnfExpr + RPAREN )) + Optional(repSymbol) ).setParseAction(makeGroupObject(Atom)) -andList = Group(bnfTerm + OneOrMore(bnfTerm)).setParseAction(makeGroupObject(AndList)) -bnfFactor = andList | bnfTerm -orList = Group( bnfFactor + OneOrMore( ALT_OP + bnfFactor ) ).setParseAction(makeGroupObject(OrList)) -bnfExpr << ( orList | bnfFactor ) -bnfLine = ident + COLON + bnfExpr - -bnfComment = "#" + restOfLine - -# build return tokens as a dictionary -bnf = Dict(OneOrMore(Group(bnfLine))) -bnf.ignore(bnfComment) - -# bnf is defined, parse the grammar text -bnfDefs = bnf.parseString(grammar) - -# correct answer is 78 -expected = 78 -assert len(bnfDefs) == expected, \ - "Error, found %d BNF defns, expected %d" % (len(bnfDefs), expected) - -# list out defns in order they were parsed (to verify accuracy of parsing) -for k,v in bnfDefs: - print(k,"=",v) -print() - -# list out parsed grammar defns (demonstrates dictionary access to parsed tokens) -for k in list(bnfDefs.keys()): - print(k,"=",bnfDefs[k]) diff --git a/trunk/src/examples/rangeCheck.py b/trunk/src/examples/rangeCheck.py deleted file mode 100644 index 67cf267..0000000 --- a/trunk/src/examples/rangeCheck.py +++ /dev/null @@ -1,62 +0,0 @@ -# rangeCheck.py -# -# A sample program showing how parse actions can convert parsed -# strings into a data type or object, and to validate the parsed value. -# -# Updated to use new addCondition method and expr() copy. -# -# Copyright 2011,2015 Paul T. McGuire -# - -from pyparsing import Word, nums, Suppress, ParseException, empty, Optional -from datetime import datetime - -def ranged_value(expr, minval=None, maxval=None): - # have to specify at least one range boundary - if minval is None and maxval is None: - raise ValueError("minval or maxval must be specified") - - # set range testing function and error message depending on - # whether either or both min and max values are given - inRangeCondition = { - (True, False) : lambda s,l,t : t[0] <= maxval, - (False, True) : lambda s,l,t : minval <= t[0], - (False, False) : lambda s,l,t : minval <= t[0] <= maxval, - }[minval is None, maxval is None] - outOfRangeMessage = { - (True, False) : "value is greater than %s" % maxval, - (False, True) : "value is less than %s" % minval, - (False, False) : "value is not in the range (%s to %s)" % (minval,maxval), - }[minval is None, maxval is None] - - return expr().addCondition(inRangeCondition, message=outOfRangeMessage) - -# define the expressions for a date of the form YYYY/MM/DD or YYYY/MM (assumes YYYY/MM/01) -integer = Word(nums).setName("integer") -integer.setParseAction(lambda t:int(t[0])) - -month = ranged_value(integer, 1, 12) -day = ranged_value(integer, 1, 31) -year = ranged_value(integer, 2000, None) - -SLASH = Suppress('/') -dateExpr = year("year") + SLASH + month("month") + Optional(SLASH + day("day")) -dateExpr.setName("date") - -# convert date fields to datetime (also validates dates as truly valid dates) -dateExpr.setParseAction(lambda t: datetime(t.year, t.month, t.day or 1).date()) - -# add range checking on dates -mindate = datetime(2002,1,1).date() -maxdate = datetime.now().date() -dateExpr = ranged_value(dateExpr, mindate, maxdate) - - -dateExpr.runTests(""" - 2011/5/8 - 2001/1/1 - 2004/2/29 - 2004/2 - 1999/12/31""") - - diff --git a/trunk/src/examples/readJson.py b/trunk/src/examples/readJson.py deleted file mode 100644 index deca53b..0000000 --- a/trunk/src/examples/readJson.py +++ /dev/null @@ -1,1917 +0,0 @@ - -#~ 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/trunk/src/examples/removeLineBreaks.py b/trunk/src/examples/removeLineBreaks.py deleted file mode 100644 index ba4b498..0000000 --- a/trunk/src/examples/removeLineBreaks.py +++ /dev/null @@ -1,45 +0,0 @@ -# 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/trunk/src/examples/romanNumerals.py b/trunk/src/examples/romanNumerals.py deleted file mode 100644 index 27361f0..0000000 --- a/trunk/src/examples/romanNumerals.py +++ /dev/null @@ -1,74 +0,0 @@ -# romanNumerals.py -# -# Copyright (c) 2006, Paul McGuire -# - -from pyparsing import * - -def romanNumeralLiteral(numeralString, value): - return Literal(numeralString).setParseAction(replaceWith(value)) - -one = romanNumeralLiteral("I",1) -four = romanNumeralLiteral("IV",4) -five = romanNumeralLiteral("V",5) -nine = romanNumeralLiteral("IX",9) -ten = romanNumeralLiteral("X",10) -forty = romanNumeralLiteral("XL",40) -fifty = romanNumeralLiteral("L",50) -ninety = romanNumeralLiteral("XC",90) -onehundred = romanNumeralLiteral("C",100) -fourhundred = romanNumeralLiteral("CD",400) -fivehundred = romanNumeralLiteral("D",500) -ninehundred = romanNumeralLiteral("CM",900) -onethousand = romanNumeralLiteral("M",1000) - -numeral = ( onethousand | ninehundred | fivehundred | fourhundred | - onehundred | ninety | fifty | forty | ten | nine | five | - four | one ).leaveWhitespace() - -romanNumeral = OneOrMore(numeral).setParseAction( lambda s,l,t : sum(t) ) - -# unit tests -def makeRomanNumeral(n): - def addDigit(n,limit,c,s): - n -= limit - s += c - return n,s - - ret = "" - while n >= 1000: n,ret = addDigit(n,1000,"M",ret) - while n >= 900: n,ret = addDigit(n, 900,"CM",ret) - while n >= 500: n,ret = addDigit(n, 500,"D",ret) - while n >= 400: n,ret = addDigit(n, 400,"CD",ret) - while n >= 100: n,ret = addDigit(n, 100,"C",ret) - while n >= 90: n,ret = addDigit(n, 90,"XC",ret) - while n >= 50: n,ret = addDigit(n, 50,"L",ret) - while n >= 40: n,ret = addDigit(n, 40,"XL",ret) - while n >= 10: n,ret = addDigit(n, 10,"X",ret) - while n >= 9: n,ret = addDigit(n, 9,"IX",ret) - while n >= 5: n,ret = addDigit(n, 5,"V",ret) - while n >= 4: n,ret = addDigit(n, 4,"IV",ret) - while n >= 1: n,ret = addDigit(n, 1,"I",ret) - return ret -tests = " ".join(makeRomanNumeral(i) for i in range(1,5000+1)) - -expected = 1 -for t,s,e in romanNumeral.scanString(tests): - if t[0] != expected: - print("{} {} {}".format("==>", t, tests[s:e])) - expected += 1 - -def test(rn): - print("{} -> {}".format(rn, romanNumeral.parseString(rn)[0])) -test("XVI") -test("XXXIX") -test("XIV") -test("XIX") -test("MCMLXXX") -test("MMVI") - - - - - - diff --git a/trunk/src/examples/scanExamples.py b/trunk/src/examples/scanExamples.py deleted file mode 100644 index 24ae0e7..0000000 --- a/trunk/src/examples/scanExamples.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# 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/trunk/src/examples/scanYahoo.py b/trunk/src/examples/scanYahoo.py deleted file mode 100644 index 825c169..0000000 --- a/trunk/src/examples/scanYahoo.py +++ /dev/null @@ -1,14 +0,0 @@ -from pyparsing import makeHTMLTags,SkipTo,htmlComment -import urllib.request, urllib.parse, urllib.error - -serverListPage = urllib.request.urlopen( "http://www.yahoo.com" ) -htmlText = serverListPage.read() -serverListPage.close() - -aStart,aEnd = makeHTMLTags("A") - -link = aStart + SkipTo(aEnd).setResultsName("link") + aEnd -link.ignore(htmlComment) - -for toks,start,end in link.scanString(htmlText): - print(toks.link, "->", toks.startA.href) \ No newline at end of file diff --git a/trunk/src/examples/searchParserAppDemo.py b/trunk/src/examples/searchParserAppDemo.py deleted file mode 100644 index 259e0e3..0000000 --- a/trunk/src/examples/searchParserAppDemo.py +++ /dev/null @@ -1,34 +0,0 @@ -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/trunk/src/examples/searchparser.py b/trunk/src/examples/searchparser.py deleted file mode 100644 index e5b40a7..0000000 --- a/trunk/src/examples/searchparser.py +++ /dev/null @@ -1,292 +0,0 @@ -"""Search query parser - -version 2006-03-09 - -This search query parser uses the excellent Pyparsing module -(http://pyparsing.sourceforge.net/) to parse search queries by users. -It handles: - -* 'and', 'or' and implicit 'and' operators; -* parentheses; -* quoted strings; -* wildcards at the end of a search term (help*); - -Requirements: -* Python -* Pyparsing - -If you run this script, it will perform a number of tests. To use is as a -module, you should use inheritance on the SearchQueryParser class and overwrite -the Get... methods. The ParserTest class gives a very simple example of how this -could work. - -------------------------------------------------------------------------------- -Copyright (c) 2006, Estrate, the Netherlands -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of Estrate nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -CONTRIBUTORS: -- Steven Mooij -- Rudolph Froger -- Paul McGuire - -TODO: -- add more docs -- ask someone to check my English texts -- add more kinds of wildcards ('*' at the beginning and '*' inside a word)? -""" -from pyparsing import Word, alphanums, Keyword, Group, Combine, Forward, Suppress, Optional, OneOrMore, oneOf - -class SearchQueryParser: - - def __init__(self): - self._methods = { - 'and': self.evaluateAnd, - 'or': self.evaluateOr, - 'not': self.evaluateNot, - 'parenthesis': self.evaluateParenthesis, - 'quotes': self.evaluateQuotes, - 'word': self.evaluateWord, - 'wordwildcard': self.evaluateWordWildcard, - } - self._parser = self.parser() - - def parser(self): - """ - This function returns a parser. - The grammar should be like most full text search engines (Google, Tsearch, Lucene). - - Grammar: - - a query consists of alphanumeric words, with an optional '*' wildcard - at the end of a word - - a sequence of words between quotes is a literal string - - words can be used together by using operators ('and' or 'or') - - words with operators can be grouped with parenthesis - - a word or group of words can be preceded by a 'not' operator - - the 'and' operator precedes an 'or' operator - - if an operator is missing, use an 'and' operator - """ - operatorOr = Forward() - - operatorWord = Group(Combine(Word(alphanums) + Suppress('*'))).setResultsName('wordwildcard') | \ - Group(Word(alphanums)).setResultsName('word') - - operatorQuotesContent = Forward() - operatorQuotesContent << ( - (operatorWord + operatorQuotesContent) | operatorWord - ) - - operatorQuotes = Group( - Suppress('"') + operatorQuotesContent + Suppress('"') - ).setResultsName("quotes") | operatorWord - - operatorParenthesis = Group( - (Suppress("(") + operatorOr + Suppress(")")) - ).setResultsName("parenthesis") | operatorQuotes - - operatorNot = Forward() - operatorNot << (Group( - Suppress(Keyword("not", caseless=True)) + operatorNot - ).setResultsName("not") | operatorParenthesis) - - operatorAnd = Forward() - operatorAnd << (Group( - operatorNot + Suppress(Keyword("and", caseless=True)) + operatorAnd - ).setResultsName("and") | Group( - operatorNot + OneOrMore(~oneOf("and or") + operatorAnd) - ).setResultsName("and") | operatorNot) - - operatorOr << (Group( - operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr - ).setResultsName("or") | operatorAnd) - - return operatorOr.parseString - - def evaluateAnd(self, argument): - return self.evaluate(argument[0]).intersection(self.evaluate(argument[1])) - - def evaluateOr(self, argument): - return self.evaluate(argument[0]).union(self.evaluate(argument[1])) - - def evaluateNot(self, argument): - return self.GetNot(self.evaluate(argument[0])) - - def evaluateParenthesis(self, argument): - return self.evaluate(argument[0]) - - def evaluateQuotes(self, argument): - """Evaluate quoted strings - - First is does an 'and' on the indidual search terms, then it asks the - function GetQuoted to only return the subset of ID's that contain the - literal string. - """ - r = set() - search_terms = [] - for item in argument: - search_terms.append(item[0]) - if len(r) == 0: - r = self.evaluate(item) - else: - r = r.intersection(self.evaluate(item)) - return self.GetQuotes(' '.join(search_terms), r) - - def evaluateWord(self, argument): - return self.GetWord(argument[0]) - - def evaluateWordWildcard(self, argument): - return self.GetWordWildcard(argument[0]) - - def evaluate(self, argument): - return self._methods[argument.getName()](argument) - - def Parse(self, query): - #print self._parser(query)[0] - return self.evaluate(self._parser(query)[0]) - - def GetWord(self, word): - return set() - - def GetWordWildcard(self, word): - return set() - - def GetQuotes(self, search_string, tmp_result): - return set() - - def GetNot(self, not_set): - return set().difference(not_set) - - -class ParserTest(SearchQueryParser): - """Tests the parser with some search queries - tests containts a dictionary with tests and expected results. - """ - tests = { - 'help': set([1, 2, 4, 5]), - 'help or hulp': set([1, 2, 3, 4, 5]), - 'help and hulp': set([2]), - 'help hulp': set([2]), - 'help and hulp or hilp': set([2, 3, 4]), - 'help or hulp and hilp': set([1, 2, 3, 4, 5]), - 'help or hulp or hilp or halp': set([1, 2, 3, 4, 5, 6]), - '(help or hulp) and (hilp or halp)': set([3, 4, 5]), - 'help and (hilp or halp)': set([4, 5]), - '(help and (hilp or halp)) or hulp': set([2, 3, 4, 5]), - 'not help': set([3, 6, 7, 8]), - 'not hulp and halp': set([5, 6]), - 'not (help and halp)': set([1, 2, 3, 4, 6, 7, 8]), - '"help me please"': set([2]), - '"help me please" or hulp': set([2, 3]), - '"help me please" or (hulp and halp)': set([2]), - 'help*': set([1, 2, 4, 5, 8]), - 'help or hulp*': set([1, 2, 3, 4, 5]), - 'help* and hulp': set([2]), - 'help and hulp* or hilp': set([2, 3, 4]), - 'help* or hulp or hilp or halp': set([1, 2, 3, 4, 5, 6, 8]), - '(help or hulp*) and (hilp* or halp)': set([3, 4, 5]), - 'help* and (hilp* or halp*)': set([4, 5]), - '(help and (hilp* or halp)) or hulp*': set([2, 3, 4, 5]), - 'not help* and halp': set([6]), - 'not (help* and helpe*)': set([1, 2, 3, 4, 5, 6, 7]), - '"help* me please"': set([2]), - '"help* me* please" or hulp*': set([2, 3]), - '"help me please*" or (hulp and halp)': set([2]), - '"help me please" not (hulp and halp)': set([2]), - '"help me please" hulp': set([2]), - 'help and hilp and not holp': set([4]), - 'help hilp not holp': set([4]), - 'help hilp and not holp': set([4]), - } - - docs = { - 1: 'help', - 2: 'help me please hulp', - 3: 'hulp hilp', - 4: 'help hilp', - 5: 'halp thinks he needs help', - 6: 'he needs halp', - 7: 'nothing', - 8: 'helper', - } - - index = { - 'help': set((1, 2, 4, 5)), - 'me': set((2,)), - 'please': set((2,)), - 'hulp': set((2, 3,)), - 'hilp': set((3, 4,)), - 'halp': set((5, 6,)), - 'thinks': set((5,)), - 'he': set((5, 6,)), - 'needs': set((5, 6,)), - 'nothing': set((7,)), - 'helper': set((8,)), - } - - def GetWord(self, word): - if (word in self.index): - return self.index[word] - else: - return set() - - def GetWordWildcard(self, word): - result = set() - for item in list(self.index.keys()): - if word == item[0:len(word)]: - result = result.union(self.index[item]) - return result - - def GetQuotes(self, search_string, tmp_result): - result = set() - for item in tmp_result: - if self.docs[item].count(search_string): - result.add(item) - return result - - def GetNot(self, not_set): - all = set(list(self.docs.keys())) - return all.difference(not_set) - - def Test(self): - all_ok = True - for item in list(self.tests.keys()): - print(item) - r = self.Parse(item) - e = self.tests[item] - print('Result: %s' % r) - print('Expect: %s' % e) - if e == r: - print('Test OK') - else: - all_ok = False - print('>>>>>>>>>>>>>>>>>>>>>>Test ERROR<<<<<<<<<<<<<<<<<<<<<') - print('') - return all_ok - -if __name__=='__main__': - if ParserTest().Test(): - print('All tests OK') - else: - print('One or more tests FAILED') diff --git a/trunk/src/examples/select_parser.py b/trunk/src/examples/select_parser.py deleted file mode 100644 index da106ac..0000000 --- a/trunk/src/examples/select_parser.py +++ /dev/null @@ -1,126 +0,0 @@ -# select_parser.py -# Copyright 2010, Paul McGuire -# -# a simple SELECT statement parser, taken from SQLite's SELECT statement -# definition at http://www.sqlite.org/lang_select.html -# -from pyparsing import * -ParserElement.enablePackrat() - -LPAR,RPAR,COMMA = map(Suppress,"(),") -select_stmt = Forward().setName("select statement") - -# keywords -(UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, - CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, - HAVING, ORDER, BY, LIMIT, OFFSET, OR) = map(CaselessKeyword, """UNION, ALL, AND, INTERSECT, - EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT, - DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY, LIMIT, OFFSET, OR""".replace(",","").split()) -(CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS, - COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE, - CURRENT_TIMESTAMP) = map(CaselessKeyword, """CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, - END, CASE, WHEN, THEN, EXISTS, COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, - CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP""".replace(",","").split()) -keyword = MatchFirst((UNION, ALL, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING, NATURAL, INNER, - CROSS, LEFT, OUTER, JOIN, AS, INDEXED, NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, - HAVING, ORDER, BY, LIMIT, OFFSET, CAST, ISNULL, NOTNULL, NULL, IS, BETWEEN, ELSE, END, CASE, WHEN, THEN, EXISTS, - COLLATE, IN, LIKE, GLOB, REGEXP, MATCH, ESCAPE, CURRENT_TIME, CURRENT_DATE, - CURRENT_TIMESTAMP)) - -identifier = ~keyword + Word(alphas, alphanums+"_") -collation_name = identifier.copy() -column_name = identifier.copy() -column_alias = identifier.copy() -table_name = identifier.copy() -table_alias = identifier.copy() -index_name = identifier.copy() -function_name = identifier.copy() -parameter_name = identifier.copy() -database_name = identifier.copy() - -# expression -expr = Forward().setName("expression") - -integer = Regex(r"[+-]?\d+") -numeric_literal = Regex(r"\d+(\.\d*)?([eE][+-]?\d+)?") -string_literal = QuotedString("'") -blob_literal = Regex(r"[xX]'[0-9A-Fa-f]+'") -literal_value = ( numeric_literal | string_literal | blob_literal | - NULL | CURRENT_TIME | CURRENT_DATE | CURRENT_TIMESTAMP ) -bind_parameter = ( - Word("?",nums) | - Combine(oneOf(": @ $") + parameter_name) - ) -type_name = oneOf("TEXT REAL INTEGER BLOB NULL") - -expr_term = ( - CAST + LPAR + expr + AS + type_name + RPAR | - EXISTS + LPAR + select_stmt + RPAR | - function_name.setName("function_name") + LPAR + Optional(delimitedList(expr)) + RPAR | - literal_value | - bind_parameter | - Combine(identifier+('.'+identifier)*(0,2)).setName("ident") - ) - -UNARY,BINARY,TERNARY=1,2,3 -expr << infixNotation(expr_term, - [ - (oneOf('- + ~') | NOT, UNARY, opAssoc.RIGHT), - (ISNULL | NOTNULL | NOT + NULL, UNARY, opAssoc.LEFT), - ('||', BINARY, opAssoc.LEFT), - (oneOf('* / %'), BINARY, opAssoc.LEFT), - (oneOf('+ -'), BINARY, opAssoc.LEFT), - (oneOf('<< >> & |'), BINARY, opAssoc.LEFT), - (oneOf('< <= > >='), BINARY, opAssoc.LEFT), - (oneOf('= == != <>') | IS | IN | LIKE | GLOB | MATCH | REGEXP, BINARY, opAssoc.LEFT), - ((BETWEEN,AND), TERNARY, opAssoc.LEFT), - (IN + LPAR + Group(select_stmt | delimitedList(expr)) + RPAR, UNARY, opAssoc.LEFT), - (AND, BINARY, opAssoc.LEFT), - (OR, BINARY, opAssoc.LEFT), - ]) - -compound_operator = (UNION + Optional(ALL) | INTERSECT | EXCEPT) - -ordering_term = Group(expr('order_key') + Optional(COLLATE + collation_name('collate')) + Optional(ASC | DESC)('direction')) - -join_constraint = Group(Optional(ON + expr | USING + LPAR + Group(delimitedList(column_name)) + RPAR)) - -join_op = COMMA | Group(Optional(NATURAL) + Optional(INNER | CROSS | LEFT + OUTER | LEFT | OUTER) + JOIN) - -join_source = Forward() -single_source = ( (Group(database_name("database") + "." + table_name("table")) | table_name("table")) + - Optional(Optional(AS) + table_alias("table_alias")) + - Optional(INDEXED + BY + index_name("name") | NOT + INDEXED)("index") | - (LPAR + select_stmt + RPAR + Optional(Optional(AS) + table_alias)) | - (LPAR + join_source + RPAR) ) - -join_source << (Group(single_source + OneOrMore(join_op + single_source + join_constraint)) | - single_source) - -result_column = "*" | table_name + "." + "*" | Group(expr + Optional(Optional(AS) + column_alias)) -select_core = (SELECT + Optional(DISTINCT | ALL) + Group(delimitedList(result_column))("columns") + - Optional(FROM + join_source("from")) + - Optional(WHERE + expr("where_expr")) + - Optional(GROUP + BY + Group(delimitedList(ordering_term)("group_by_terms")) + - Optional(HAVING + expr("having_expr")))) - -select_stmt << (select_core + ZeroOrMore(compound_operator + select_core) + - Optional(ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms")) + - Optional(LIMIT + (Group(expr + OFFSET + expr) | Group(expr + COMMA + expr) | expr)("limit"))) - -tests = """\ - select * from xyzzy where z > 100 - select * from xyzzy where z > 100 order by zz - select * from xyzzy - select z.* from xyzzy - select a, b from test_table where 1=1 and b='yes' - select a, b from test_table where 1=1 and b in (select bb from foo) - select z.a, b from test_table where 1=1 and b in (select bb from foo) - select z.a, b from test_table where 1=1 and b in (select bb from foo) order by b,c desc,d - select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo) - select a, db.table.b as BBB from db.table where 1=1 and BBB='yes' - select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' - select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' limit 50 - """ - -select_stmt.runTests(tests) diff --git a/trunk/src/examples/sexpParser.py b/trunk/src/examples/sexpParser.py deleted file mode 100644 index 963d153..0000000 --- a/trunk/src/examples/sexpParser.py +++ /dev/null @@ -1,167 +0,0 @@ -# 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 - - :: | - :: ? ; - :: | | | | - ; - :: "[" "]" ; - :: ":" ; - :: + ; - -- decimal numbers should have no unnecessary leading zeros - -- any string of bytes, of the indicated length - :: + ; - :: ? "|" ( | )* "|" ; - :: "#" ( | )* "#" ; - :: ? - :: "\"" "\"" - :: "(" ( | )* ")" ; - :: * ; - :: | | ; - :: | | ; - :: "a" | ... | "z" ; - :: "A" | ... | "Z" ; - :: "0" | ... | "9" ; - :: | "A" | ... | "F" | "a" | ... | "f" ; - :: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ; - :: " " | "\t" | "\r" | "\n" ; - :: | | "+" | "/" | "=" ; - :: "" ; -""" - -from pyparsing import * -from base64 import b64decode -import pprint - -def verifyLen(s,l,t): - t = t[0] - if t.len is not None: - t1len = len(t[1]) - if t1len != t.len: - raise ParseFatalException(s,l,\ - "invalid data of length %d, expected %s" % (t1len, t.len)) - return t[1] - -# define punctuation literals -LPAR, RPAR, LBRK, RBRK, LBRC, RBRC, VBAR = map(Suppress, "()[]{}|") - -decimal = Regex(r'0|[1-9]\d*').setParseAction(lambda t: int(t[0])) -hexadecimal = ("#" + OneOrMore(Word(hexnums)) + "#")\ - .setParseAction(lambda t: int("".join(t[1:-1]),16)) -bytes = Word(printables) -raw = Group(decimal("len") + Suppress(":") + bytes).setParseAction(verifyLen) -token = Word(alphanums + "-./_:*+=") -base64_ = Group(Optional(decimal|hexadecimal,default=None)("len") + VBAR - + OneOrMore(Word( alphanums +"+/=" )).setParseAction(lambda t: b64decode("".join(t))) - + VBAR).setParseAction(verifyLen) - -qString = Group(Optional(decimal,default=None)("len") + - dblQuotedString.setParseAction(removeQuotes)).setParseAction(verifyLen) -simpleString = base64_ | raw | decimal | token | hexadecimal | qString - -# extended definitions -decimal = Regex(r'-?0|[1-9]\d*').setParseAction(lambda t: int(t[0])) -real = Regex(r"[+-]?\d+\.\d*([eE][+-]?\d+)?").setParseAction(lambda tokens: float(tokens[0])) -token = Word(alphanums + "-./_:*+=!<>") - -simpleString = real | base64_ | raw | decimal | token | hexadecimal | qString - -display = LBRK + simpleString + RBRK -string_ = Optional(display) + simpleString - -sexp = Forward() -sexpList = Group(LPAR + ZeroOrMore(sexp) + RPAR) -sexp << ( string_ | sexpList ) - -######### Test data ########### -test00 = """(snicker "abc" (#03# |YWJj|))""" -test01 = """(certificate - (issuer - (name - (public-key - rsa-with-md5 - (e 15 |NFGq/E3wh9f4rJIQVXhS|) - (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) - aid-committee)) - (subject - (ref - (public-key - rsa-with-md5 - (e |NFGq/E3wh9f4rJIQVXhS|) - (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) - tom - mother)) - (not-before "1997-01-01_09:00:00") - (not-after "1998-01-01_09:00:00") - (tag - (spend (account "12345678") (* numeric range "1" "1000")))) -""" -test02 = """(lambda (x) (* x x))""" -test03 = """(def length - (lambda (x) - (cond - ((not x) 0) - ( t (+ 1 (length (cdr x)))) - ) - ) -) -""" -test04 = """(2:XX "abc" (#03# |YWJj|))""" -test05 = """(if (is (window_name) "XMMS") (set_workspace 2))""" -test06 = """(if - (and - (is (application_name) "Firefox") - (or - (contains (window_name) "Enter name of file to save to") - (contains (window_name) "Save As") - (contains (window_name) "Save Image") - () - ) - ) - (geometry "+140+122") -) -""" -test07 = """(defun factorial (x) - (if (zerop x) 1 - (* x (factorial (- x 1))))) - """ -test51 = """(2:XX "abc" (#30# |YWJj|))""" -test51error = """(3:XX "abc" (#30# |YWJj|))""" - -test52 = """ - (and - (or (> uid 1000) - (!= gid 20) - ) - (> quota 5.0e+03) - ) - """ - -# Run tests -t = None -alltests = [ locals()[t] for t in sorted(locals()) if t.startswith("test") ] - -for t in alltests: - print('-'*50) - print(t) - try: - sexpr = sexp.parseString(t, parseAll=True) - pprint.pprint(sexpr.asList()) - except ParseFatalException as pfe: - print("Error:", pfe.msg) - print(pfe.markInputline('^')) - print() diff --git a/trunk/src/examples/shapes.py b/trunk/src/examples/shapes.py deleted file mode 100644 index b5a0ebd..0000000 --- a/trunk/src/examples/shapes.py +++ /dev/null @@ -1,64 +0,0 @@ -# shapes.py -# -# A sample program showing how parse actions can convert parsed -# strings into a data type or object. -# -# Copyright 2012, Paul T. McGuire -# - -# define class hierarchy of Shape classes, with polymorphic area method -class Shape(object): - def __init__(self, tokens): - self.__dict__.update(tokens.asDict()) - - def area(self): - raise NotImplementedException() - - def __str__(self): - return "<%s>: %s" % (self.__class__.__name__, self.__dict__) - -class Square(Shape): - def area(self): - return self.side**2 - -class Rectangle(Shape): - def area(self): - return self.width * self.height - -class Circle(Shape): - def area(self): - return 3.14159 * self.radius**2 - - -from pyparsing import * - -number = Regex(r'-?\d+(\.\d*)?').setParseAction(lambda t:float(t[0])) - -# Shape expressions: -# square : S -# rectangle: R -# circle : C - -squareDefn = "S" + number('centerx') + number('centery') + number('side') -rectDefn = "R" + number('centerx') + number('centery') + number('width') + number('height') -circleDefn = "C" + number('centerx') + number('centery') + number('diameter') - -squareDefn.setParseAction(Square) -rectDefn.setParseAction(Rectangle) - -def computeRadius(tokens): - tokens['radius'] = tokens.diameter/2.0 -circleDefn.setParseAction(computeRadius, Circle) - -shapeExpr = squareDefn | rectDefn | circleDefn - -tests = """\ -C 0 0 100 -R 10 10 20 50 -S -1 5 10""".splitlines() - -for t in tests: - shape = shapeExpr.parseString(t)[0] - print(shape) - print("Area:", shape.area()) - print() diff --git a/trunk/src/examples/simpleArith.py b/trunk/src/examples/simpleArith.py deleted file mode 100644 index 825956b..0000000 --- a/trunk/src/examples/simpleArith.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# simpleArith.py -# -# Example of defining an arithmetic expression parser using -# the infixNotation helper method in pyparsing. -# -# Copyright 2006, by Paul McGuire -# - -from pyparsing import * - -integer = Word(nums).setParseAction(lambda t:int(t[0])) -variable = Word(alphas,exact=1) -operand = integer | variable - -expop = Literal('^') -signop = oneOf('+ -') -multop = oneOf('* /') -plusop = oneOf('+ -') -factop = Literal('!') - -# To use the infixNotation helper: -# 1. Define the "atom" operand term of the grammar. -# For this simple grammar, the smallest operand is either -# and integer or a variable. This will be the first argument -# to the infixNotation method. -# 2. Define a list of tuples for each level of operator -# precendence. Each tuple is of the form -# (opExpr, numTerms, rightLeftAssoc, parseAction), where -# - opExpr is the pyparsing expression for the operator; -# may also be a string, which will be converted to a Literal -# - numTerms is the number of terms for this operator (must -# be 1 or 2) -# - rightLeftAssoc is the indicator whether the operator is -# right or left associative, using the pyparsing-defined -# constants opAssoc.RIGHT and opAssoc.LEFT. -# - parseAction is the parse action to be associated with -# expressions matching this operator expression (the -# parse action tuple member may be omitted) -# 3. Call infixNotation passing the operand expression and -# the operator precedence list, and save the returned value -# as the generated pyparsing expression. You can then use -# this expression to parse input strings, or incorporate it -# into a larger, more complex grammar. -# -expr = infixNotation( operand, - [("!", 1, opAssoc.LEFT), - ("^", 2, opAssoc.RIGHT), - (signop, 1, opAssoc.RIGHT), - (multop, 2, opAssoc.LEFT), - (plusop, 2, opAssoc.LEFT),] - ) - -test = ["9 + 2 + 3", - "9 + 2 * 3", - "(9 + 2) * 3", - "(9 + -2) * 3", - "(9 + -2) * 3^2^2", - "(9! + -2) * 3^2^2", - "M*X + B", - "M*(X + B)", - "1+2*-3^4*5+-+-6",] -for t in test: - print(t) - print(expr.parseString(t)) - print('') - diff --git a/trunk/src/examples/simpleBool.py b/trunk/src/examples/simpleBool.py deleted file mode 100644 index 5f355b7..0000000 --- a/trunk/src/examples/simpleBool.py +++ /dev/null @@ -1,102 +0,0 @@ -# -# simpleBool.py -# -# Example of defining a boolean logic parser using -# the operatorGrammar helper method in pyparsing. -# -# In this example, parse actions associated with each -# operator expression will "compile" the expression -# into BoolXXX class instances, which can then -# later be evaluated for their boolean value. -# -# Copyright 2006, by Paul McGuire -# Updated 2013-Sep-14 - improved Python 2/3 cross-compatibility -# -from pyparsing import infixNotation, opAssoc, Keyword, Word, alphas - -# define classes to be built at parse time, as each matching -# expression type is parsed -class BoolOperand(object): - def __init__(self,t): - self.label = t[0] - self.value = eval(t[0]) - def __bool__(self): - return self.value - def __str__(self): - return self.label - __repr__ = __str__ - __nonzero__ = __bool__ - -class BoolBinOp(object): - def __init__(self,t): - self.args = t[0][0::2] - def __str__(self): - sep = " %s " % self.reprsymbol - return "(" + sep.join(map(str,self.args)) + ")" - def __bool__(self): - return self.evalop(bool(a) for a in self.args) - __nonzero__ = __bool__ - __repr__ = __str__ - -class BoolAnd(BoolBinOp): - reprsymbol = '&' - evalop = all - -class BoolOr(BoolBinOp): - reprsymbol = '|' - evalop = any - -class BoolNot(object): - def __init__(self,t): - self.arg = t[0][1] - def __bool__(self): - v = bool(self.arg) - return not v - def __str__(self): - return "~" + str(self.arg) - __repr__ = __str__ - __nonzero__ = __bool__ - -TRUE = Keyword("True") -FALSE = Keyword("False") -boolOperand = TRUE | FALSE | Word(alphas,max=1) -boolOperand.setParseAction(BoolOperand) - -# define expression, based on expression operand and -# list of operations in precedence order -boolExpr = infixNotation( boolOperand, - [ - ("not", 1, opAssoc.RIGHT, BoolNot), - ("and", 2, opAssoc.LEFT, BoolAnd), - ("or", 2, opAssoc.LEFT, BoolOr), - ]) - - -if __name__ == "__main__": - p = True - q = False - r = True - tests = [("p", True), - ("q", False), - ("p and q", False), - ("p and not q", True), - ("not not p", True), - ("not(p and q)", True), - ("q or not p and r", False), - ("q or not p or not r", False), - ("q or not (p and r)", False), - ("p or q or r", True), - ("p or q or r and False", True), - ("(p or q or r) and False", False), - ] - - print("p =", p) - print("q =", q) - print("r =", r) - print() - for t,expected in tests: - res = boolExpr.parseString(t)[0] - success = "PASS" if bool(res) == expected else "FAIL" - print (t,'\n', res, '=', bool(res),'\n', success, '\n') - - diff --git a/trunk/src/examples/simpleSQL.py b/trunk/src/examples/simpleSQL.py deleted file mode 100644 index 66dc18c..0000000 --- a/trunk/src/examples/simpleSQL.py +++ /dev/null @@ -1,72 +0,0 @@ -# simpleSQL.py -# -# simple demo of using the parsing library to do simple-minded SQL parsing -# could be extended to include where clauses etc. -# -# Copyright (c) 2003,2016, Paul McGuire -# -from pyparsing import Literal, CaselessLiteral, Word, delimitedList, Optional, \ - Combine, Group, alphas, nums, alphanums, ParseException, Forward, oneOf, quotedString, \ - ZeroOrMore, restOfLine, Keyword, upcaseTokens - -# define SQL tokens -selectStmt = Forward() -SELECT = Keyword("select", caseless=True) -FROM = Keyword("from", caseless=True) -WHERE = Keyword("where", caseless=True) - -ident = Word( alphas, alphanums + "_$" ).setName("identifier") -columnName = ( delimitedList( ident, ".", combine=True ) ).addParseAction(upcaseTokens) -columnNameList = Group( delimitedList( columnName ) ) -tableName = ( delimitedList( ident, ".", combine=True ) ).addParseAction(upcaseTokens) -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 <<= (SELECT + ('*' | columnNameList)("columns") + - FROM + tableNameList( "tables" ) + - Optional(Group(WHERE + whereExpression), "")("where")) - -simpleSQL = selectStmt - -# define Oracle comment format, and ignore them -oracleSqlComment = "--" + restOfLine -simpleSQL.ignore( oracleSqlComment ) - -if __name__ == "__main__": - simpleSQL.runTests("""\ - SELECT * from XYZZY, ABC - select * from SYS.XYZZY - Select A from Sys.dual - Select A,B,C from Sys.dual - Select A, B, C from Sys.dual - Select A, B, C from Sys.dual, Table2 - Xelect A, B, C from Sys.dual - Select A, B, C frox Sys.dual - Select - Select &&& frox Sys.dual - Select A from Sys.dual where a in ('RED','GREEN','BLUE') - Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30) - Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators""") diff --git a/trunk/src/examples/simpleWiki.py b/trunk/src/examples/simpleWiki.py deleted file mode 100644 index 7a2a0ce..0000000 --- a/trunk/src/examples/simpleWiki.py +++ /dev/null @@ -1,32 +0,0 @@ -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("","")) -bolded = QuotedString("**").setParseAction(convertToHTML("","")) -boldItalicized = QuotedString("***").setParseAction(convertToHTML("","")) -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 '%s' % (url,text) - -urlRef = QuotedString("{{",endQuoteChar="}}").setParseAction(convertToHTML_A) - -wikiMarkup = urlRef | boldItalicized | bolded | italicized - -print(wikiInput) -print() -print(wikiMarkup.transformString(wikiInput)) diff --git a/trunk/src/examples/snmp_api.h b/trunk/src/examples/snmp_api.h deleted file mode 100644 index d75cb12..0000000 --- a/trunk/src/examples/snmp_api.h +++ /dev/null @@ -1,795 +0,0 @@ -#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/trunk/src/examples/sparser.py b/trunk/src/examples/sparser.py deleted file mode 100644 index 7c416da..0000000 --- a/trunk/src/examples/sparser.py +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env python - -""" -NAME: - sparser.py - -SYNOPSIS: - sparser.py [options] filename - -DESCRIPTION: - The sparser.py script is a Specified PARSER. It is unique (as far as I can - tell) because it doesn't care about the delimiter(s). The user specifies - what is expected, and the order, for each line of text. All of the heavy - lifting is handled by pyparsing (http://pyparsing.sf.net). - -OPTIONS: - -h,--help this message - -v,--version version - -d,--debug turn on debug messages - -EXAMPLES: - 1. As standalone - sparser.py myfile - 2. As library - import sparser - ... - -#Copyright (C) 2006 Tim Cera timcera@earthlink.net -# -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 675 Mass Ave, Cambridge, MA 02139, USA. -""" - -#===imports====================== -import sys -import os -import getopt -import re -import gzip - -from pyparsing import * - - -#===globals====================== -modname = "sparser" -__version__ = "0.1" - - -#--option args-- -debug_p = 0 -#opt_b=None #string arg, default is undefined - - -#---positional args, default is empty--- -pargs = [] - - -#---other--- - - -#===utilities==================== -def msg(txt): - """Send message to stdout.""" - sys.stdout.write(txt) - sys.stdout.flush() - -def debug(ftn, txt): - """Used for debugging.""" - if debug_p: - sys.stdout.write("%s.%s:%s\n" % (modname, ftn, txt)) - sys.stdout.flush() - -def fatal(ftn, txt): - """If can't continue.""" - msg = "%s.%s:FATAL:%s\n" % (modname, ftn, txt) - raise SystemExit(msg) - -def usage(): - """Prints the docstring.""" - print(__doc__) - - - -#==================================== -class ToInteger(TokenConverter): - """Converter to make token into an integer.""" - def postParse( self, instring, loc, tokenlist ): - return int(tokenlist[0]) - -class ToFloat(TokenConverter): - """Converter to make token into a float.""" - def postParse( self, instring, loc, tokenlist ): - return float(tokenlist[0]) - -class ParseFileLineByLine: - """ - Bring data from text files into a program, optionally parsing each line - according to specifications in a parse definition file. - - ParseFileLineByLine instances can be used like normal file objects (i.e. by - calling readline(), readlines(), and write()), but can also be used as - sequences of lines in for-loops. - - ParseFileLineByLine objects also handle compression transparently. i.e. it - is possible to read lines from a compressed text file as if it were not - compressed. Compression is deduced from the file name suffixes '.Z' - (compress/uncompress), '.gz' (gzip/gunzip), and '.bz2' (bzip2). - - The parse definition file name is developed based on the input file name. - If the input file name is 'basename.ext', then the definition file is - 'basename_def.ext'. If a definition file specific to the input file is not - found, then the program searches for the file 'sparse.def' which would be - the definition file for all files in that directory without a file specific - definition file. - - Finally, ParseFileLineByLine objects accept file names that start with '~' - or '~user' to indicate a home directory, as well as URLs (for reading - only). - - Constructor: - ParseFileLineByLine(|filename|, |mode|='"r"'), where |filename| is the name - of the file (or a URL) and |mode| is one of '"r"' (read), '"w"' (write) or - '"a"' (append, not supported for .Z files). - """ - - def __init__(self, filename, mode = 'r'): - """Opens input file, and if available the definition file. If the - definition file is available __init__ will then create some pyparsing - helper variables. """ - if mode not in ['r', 'w', 'a']: - raise IOError(0, 'Illegal mode: ' + repr(mode)) - - if string.find(filename, ':/') > 1: # URL - if mode == 'w': - raise IOError("can't write to a URL") - import urllib.request, urllib.parse, urllib.error - self.file = urllib.request.urlopen(filename) - else: - filename = os.path.expanduser(filename) - if mode == 'r' or mode == 'a': - if not os.path.exists(filename): - raise IOError(2, 'No such file or directory: ' + filename) - filen, file_extension = os.path.splitext(filename) - command_dict = { - ('.Z', 'r'): - "self.file = os.popen('uncompress -c ' + filename, mode)", - ('.gz', 'r'): - "self.file = gzip.GzipFile(filename, 'rb')", - ('.bz2', 'r'): - "self.file = os.popen('bzip2 -dc ' + filename, mode)", - ('.Z', 'w'): - "self.file = os.popen('compress > ' + filename, mode)", - ('.gz', 'w'): - "self.file = gzip.GzipFile(filename, 'wb')", - ('.bz2', 'w'): - "self.file = os.popen('bzip2 > ' + filename, mode)", - ('.Z', 'a'): - "raise IOError, (0, 'Can\'t append to .Z files')", - ('.gz', 'a'): - "self.file = gzip.GzipFile(filename, 'ab')", - ('.bz2', 'a'): - "raise IOError, (0, 'Can\'t append to .bz2 files')", - } - - exec(command_dict.get((file_extension, mode), - 'self.file = open(filename, mode)')) - - self.grammar = None - - # Try to find a parse ('*_def.ext') definition file. First try to find - # a file specific parse definition file, then look for 'sparse.def' - # that would be the definition file for all files within the directory. - - # The definition file is pure Python. The one variable that needs to - # be specified is 'parse'. The 'parse' variable is a list of tuples - # defining the name, type, and because it is a list, the order of - # variables on each line in the data file. The variable name is a - # string, the type variable is defined as integer, real, and qString. - - # parse = [ - # ('year', integer), - # ('month', integer), - # ('day', integer), - # ('value', real), - # ] - - definition_file_one = filen + "_def" + file_extension - definition_file_two = os.path.dirname(filen) + os.sep + "sparse.def" - if os.path.exists(definition_file_one): - self.parsedef = definition_file_one - elif os.path.exists(definition_file_two): - self.parsedef = definition_file_two - else: - self.parsedef = None - return None - - # Create some handy pyparsing constructs. I kept 'decimal_sep' so that - # could easily change to parse if the decimal separator is a ",". - decimal_sep = "." - sign = oneOf("+ -") - # part of printables without decimal_sep, +, - - special_chars = string.replace('!"#$%&\'()*,./:;<=>?@[\\]^_`{|}~', - decimal_sep, "") - integer = ToInteger( - Combine(Optional(sign) + - Word(nums))).setName("integer") - positive_integer = ToInteger( - Combine(Optional("+") + - Word(nums))).setName("integer") - negative_integer = ToInteger( - Combine("-" + - Word(nums))).setName("integer") - real = ToFloat( - Combine(Optional(sign) + - Word(nums) + - decimal_sep + - Optional(Word(nums)) + - Optional(oneOf("E e") + - Word(nums)))).setName("real") - positive_real = ToFloat( - Combine(Optional("+") + - Word(nums) + - decimal_sep + - Optional(Word(nums)) + - Optional(oneOf("E e") + - Word(nums)))).setName("real") - negative_real = ToFloat( - Combine("-" + - Word(nums) + - decimal_sep + - Optional(Word(nums)) + - Optional(oneOf("E e") + - Word(nums)))).setName("real") - qString = ( sglQuotedString | dblQuotedString ).setName("qString") - - # add other characters we should skip over between interesting fields - integer_junk = Optional( - Suppress( - Word(alphas + - special_chars + - decimal_sep))).setName("integer_junk") - real_junk = Optional( - Suppress( - Word(alphas + - special_chars))).setName("real_junk") - qString_junk = SkipTo(qString).setName("qString_junk") - - # Now that 'integer', 'real', and 'qString' have been assigned I can - # execute the definition file. - exec(compile(open(self.parsedef).read(), self.parsedef, 'exec')) - - # Build the grammar, combination of the 'integer', 'real, 'qString', - # and '*_junk' variables assigned above in the order specified in the - # definition file. - grammar = [] - for nam, expr in parse: - grammar.append( eval(expr.name + "_junk")) - grammar.append( expr.setResultsName(nam) ) - self.grammar = And( grammar[1:] + [restOfLine] ) - - def __del__(self): - """Delete (close) the file wrapper.""" - self.close() - - def __getitem__(self, item): - """Used in 'for line in fp:' idiom.""" - line = self.readline() - if not line: - raise IndexError - return line - - def readline(self): - """Reads (and optionally parses) a single line.""" - line = self.file.readline() - if self.grammar and line: - try: - return self.grammar.parseString(line).asDict() - except ParseException: - return self.readline() - else: - return line - - def readlines(self): - """Returns a list of all lines (optionally parsed) in the file.""" - if self.grammar: - tot = [] - # Used this way instead of a 'for' loop against - # self.file.readlines() so that there wasn't two copies of the file - # in memory. - while 1: - line = self.file.readline() - if not line: - break - tot.append(line) - return tot - return self.file.readlines() - - def write(self, data): - """Write to a file.""" - self.file.write(data) - - def writelines(self, list): - """Write a list to a file. Each item in the list is a line in the - file. - """ - for line in list: - self.file.write(line) - - def close(self): - """Close the file.""" - self.file.close() - - def flush(self): - """Flush in memory contents to file.""" - self.file.flush() - - -#============================= -def main(pargs): - """This should only be used for testing. The primary mode of operation is - as an imported library. - """ - input_file = sys.argv[1] - fp = ParseFileLineByLine(input_file) - for i in fp: - print(i) - - -#------------------------- -if __name__ == '__main__': - ftn = "main" - opts, pargs = getopt.getopt(sys.argv[1:], 'hvd', - ['help', 'version', 'debug', 'bb=']) - for opt in opts: - if opt[0] == '-h' or opt[0] == '--help': - print(modname+": version="+__version__) - usage() - sys.exit(0) - elif opt[0] == '-v' or opt[0] == '--version': - print(modname+": version="+__version__) - sys.exit(0) - elif opt[0] == '-d' or opt[0] == '--debug': - debug_p = 1 - elif opt[0] == '--bb': - opt_b = opt[1] - - #---make the object and run it--- - main(pargs) - -#===Revision Log=== -#Created by mkpythonproj: -#2006-02-06 Tim Cera -# diff --git a/trunk/src/examples/sql2dot.py b/trunk/src/examples/sql2dot.py deleted file mode 100644 index 1156207..0000000 --- a/trunk/src/examples/sql2dot.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/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/trunk/src/examples/stackish.py b/trunk/src/examples/stackish.py deleted file mode 100644 index f80b4d6..0000000 --- a/trunk/src/examples/stackish.py +++ /dev/null @@ -1,81 +0,0 @@ -# stackish.py -# -# Stackish is a data representation syntax, similar to JSON or YAML. For more info on -# stackish, see http://www.savingtheinternetwithhate.com/stackish.html -# -# Copyright 2008, Paul McGuire -# - -""" -NUMBER A simple integer type that's just any series of digits. -FLOAT A simple floating point type. -STRING A string is double quotes with anything inside that's not a " or - newline character. You can include \n and \" to include these - characters. -MARK Marks a point in the stack that demarcates the boundary for a nested - group. -WORD Marks the root node of a group, with the other end being the nearest - MARK. -GROUP Acts as the root node of an anonymous group. -ATTRIBUTE Assigns an attribute name to the previously processed node. - This means that just about anything can be an attribute, unlike in XML. -BLOB A BLOB is unique to Stackish and allows you to record any content - (even binary content) inside the structure. This is done by pre- - sizing the data with the NUMBER similar to Dan Bernstein's netstrings - setup. -SPACE White space is basically ignored. This is interesting because since - Stackish is serialized consistently this means you can use \n as the - separation character and perform reasonable diffs on two structures. -""" - -from pyparsing import Suppress,Word,nums,alphas,alphanums,Combine,oneOf,\ - Optional,QuotedString,Forward,Group,ZeroOrMore,printables,srange - -MARK,UNMARK,AT,COLON,QUOTE = map(Suppress,"[]@:'") - -NUMBER = Word(nums) -NUMBER.setParseAction(lambda t:int(t[0])) -FLOAT = Combine(oneOf("+ -") + Word(nums) + "." + Optional(Word(nums))) -FLOAT.setParseAction(lambda t:float(t[0])) -STRING = QuotedString('"', multiline=True) -WORD = Word(alphas,alphanums+"_:") -ATTRIBUTE = Combine(AT + WORD) - -strBody = Forward() -def setBodyLength(tokens): - strBody << Word(srange(r'[\0x00-\0xffff]'), exact=int(tokens[0])) - return "" -BLOB = Combine(QUOTE + Word(nums).setParseAction(setBodyLength) + - COLON + strBody + QUOTE) - -item = Forward() -def assignUsing(s): - def assignPA(tokens): - if s in tokens: - tokens[tokens[s]] = tokens[0] - del tokens[s] - return assignPA -GROUP = (MARK + - Group( ZeroOrMore( - (item + - Optional(ATTRIBUTE)("attr") - ).setParseAction(assignUsing("attr")) - ) - ) + - ( WORD("name") | UNMARK ) - ).setParseAction(assignUsing("name")) -item << (NUMBER | FLOAT | STRING | BLOB | GROUP ) - -tests = """\ -[ '10:1234567890' @name 25 @age +0.45 @percentage person:zed -[ [ "hello" 1 child root -[ "child" [ 200 '4:like' "I" "hello" things root -[ [ "data" [ 2 1 ] @numbers child root -[ [ 1 2 3 ] @test 4 5 6 root -""".splitlines() - -for test in tests: - if test: - print(test) - print(item.parseString(test).dump()) - print() diff --git a/trunk/src/examples/stateMachine2.py b/trunk/src/examples/stateMachine2.py deleted file mode 100644 index eb6633d..0000000 --- a/trunk/src/examples/stateMachine2.py +++ /dev/null @@ -1,258 +0,0 @@ -# stateMachine.py -# -# module to define .pystate import handler -# -#import imputil -import sys -import os -import types -import urllib.parse - -DEBUG = False - -from pyparsing import Word, Group, ZeroOrMore, alphas, \ - alphanums, ParserElement, ParseException, ParseSyntaxException, \ - Empty, LineEnd, OneOrMore, col, Keyword, pythonStyleComment, \ - StringEnd, traceParseAction - - -ident = Word(alphas+"_", alphanums+"_$") - -pythonKeywords = """and as assert break class continue def - del elif else except exec finally for from global if import - in is lambda None not or pass print raise return try while with - yield True False""" -pythonKeywords = set(pythonKeywords.split()) -def no_keywords_allowed(s,l,t): - wd = t[0] - if wd in pythonKeywords: - errmsg = "cannot not use keyword '%s' " \ - "as an identifier" % wd - raise ParseException(s,l,errmsg) -ident.setParseAction(no_keywords_allowed) - -stateTransition = ident("fromState") + "->" + ident("toState") -stateMachine = Keyword("statemachine") + \ - ident("name") + ":" + \ - OneOrMore(Group(stateTransition))("transitions") - -namedStateTransition = (ident("fromState") + \ - "-(" + ident("transition") + ")->" + \ - ident("toState")) -namedStateMachine = Keyword("statemachine") + \ - ident("name") + ":" + \ - OneOrMore(Group(namedStateTransition))("transitions") - -def expand_state_definition(source, loc, tokens): - indent = " " * (col(loc,source)-1) - statedef = [] - - # build list of states - states = set() - fromTo = {} - for tn in tokens.transitions: - states.add(tn.fromState) - states.add(tn.toState) - fromTo[tn.fromState] = tn.toState - - # define base class for state classes - baseStateClass = tokens.name + "State" - statedef.extend([ - "class %s(object):" % baseStateClass, - " def __str__(self):", - " return self.__class__.__name__", - " def next_state(self):", - " return self._next_state_class()" ]) - - # define all state classes - statedef.extend( - "class %s(%s): pass" % (s,baseStateClass) - for s in states ) - statedef.extend( - "%s._next_state_class = %s" % (s,fromTo[s]) - for s in states if s in fromTo ) - - return indent + ("\n"+indent).join(statedef)+"\n" - -stateMachine.setParseAction(expand_state_definition) - -def expand_named_state_definition(source,loc,tokens): - indent = " " * (col(loc,source)-1) - statedef = [] - # build list of states and transitions - states = set() - transitions = set() - - baseStateClass = tokens.name + "State" - - fromTo = {} - for tn in tokens.transitions: - states.add(tn.fromState) - states.add(tn.toState) - transitions.add(tn.transition) - if tn.fromState in fromTo: - fromTo[tn.fromState][tn.transition] = tn.toState - else: - fromTo[tn.fromState] = {tn.transition:tn.toState} - - # add entries for terminal states - for s in states: - if s not in fromTo: - fromTo[s] = {} - - # define state transition class - statedef.extend([ - "class %sTransition:" % baseStateClass, - " def __str__(self):", - " return self.transitionName", - ]) - statedef.extend( - "%s = %sTransition()" % (tn,baseStateClass) - for tn in transitions) - statedef.extend("%s.transitionName = '%s'" % (tn,tn) - for tn in transitions) - - # define base class for state classes - excmsg = "'" + tokens.name + \ - '.%s does not support transition "%s"' \ - "'% (self, tn)" - statedef.extend([ - "class %s(object):" % baseStateClass, - " def __str__(self):", - " return self.__class__.__name__", - " def next_state(self,tn):", - " try:", - " return self.tnmap[tn]()", - " except KeyError:", - " raise Exception(%s)" % excmsg, - " def __getattr__(self,name):", - " raise Exception(%s)" % excmsg, - ]) - - # define all state classes - for s in states: - statedef.append("class %s(%s): pass" % - (s,baseStateClass)) - - # define state transition maps and transition methods - for s in states: - trns = list(fromTo[s].items()) - statedef.append("%s.tnmap = {%s}" % - (s, ",".join("%s:%s" % tn for tn in trns)) ) - statedef.extend([ - "%s.%s = staticmethod(lambda : %s())" % - (s,tn_,to_) - for tn_,to_ in trns - ]) - - return indent + ("\n"+indent).join(statedef) + "\n" - -namedStateMachine.setParseAction( - expand_named_state_definition) - -#====================================================================== -# NEW STUFF - Matt Anderson, 2009-11-26 -#====================================================================== -class SuffixImporter(object): - - """An importer designed using the mechanism defined in :pep:`302`. I read - the PEP, and also used Doug Hellmann's PyMOTW article `Modules and - Imports`_, as a pattern. - - .. _`Modules and Imports`: http://www.doughellmann.com/PyMOTW/sys/imports.html - - Define a subclass that specifies a :attr:`suffix` attribute, and - implements a :meth:`process_filedata` method. Then call the classmethod - :meth:`register` on your class to actually install it in the appropriate - places in :mod:`sys`. """ - - scheme = 'suffix' - suffix = None - path_entry = None - - @classmethod - def trigger_url(cls): - if cls.suffix is None: - raise ValueError('%s.suffix is not set' % cls.__name__) - return 'suffix:%s' % cls.suffix - - @classmethod - def register(cls): - sys.path_hooks.append(cls) - sys.path.append(cls.trigger_url()) - - def __init__(self, path_entry): - pr = urllib.parse.urlparse(str(path_entry)) - if pr.scheme != self.scheme or pr.path != self.suffix: - raise ImportError() - self.path_entry = path_entry - self._found = {} - - def checkpath_iter(self, fullname): - for dirpath in sys.path: - # if the value in sys.path_importer_cache is None, then this - # path *should* be imported by the builtin mechanism, and the - # entry is thus a path to a directory on the filesystem; - # if it's not None, then some other importer is in charge, and - # it probably isn't even a filesystem path - if sys.path_importer_cache.get(dirpath,False) is None: - checkpath = os.path.join( - dirpath,'%s.%s' % (fullname,self.suffix)) - yield checkpath - - def find_module(self, fullname, path=None): - for checkpath in self.checkpath_iter(fullname): - if os.path.isfile(checkpath): - self._found[fullname] = checkpath - return self - return None - - def load_module(self, fullname): - assert fullname in self._found - if fullname in sys.modules: - module = sys.modules[fullname] - else: - sys.modules[fullname] = module = types.ModuleType(fullname) - data = None - f = open(self._found[fullname]) - try: - data = f.read() - finally: - f.close() - - module.__dict__.clear() - module.__file__ = self._found[fullname] - module.__name__ = fullname - module.__loader__ = self - self.process_filedata(module, data) - return module - - def process_filedata(self, module, data): - pass - -class PystateImporter(SuffixImporter): - suffix = 'pystate' - - def process_filedata(self, module, data): - # MATT-NOTE: re-worked :func:`get_state_machine` - - # convert any statemachine expressions - stateMachineExpr = (stateMachine | - namedStateMachine).ignore( - pythonStyleComment) - generated_code = stateMachineExpr.transformString(data) - - if DEBUG: print(generated_code) - - # compile code object from generated code - # (strip trailing spaces and tabs, compile doesn't like - # dangling whitespace) - COMPILE_MODE = 'exec' - - codeobj = compile(generated_code.rstrip(" \t"), - module.__file__, - COMPILE_MODE) - - exec(codeobj, module.__dict__) - -PystateImporter.register() diff --git a/trunk/src/examples/test_bibparse.py b/trunk/src/examples/test_bibparse.py deleted file mode 100644 index 7440a66..0000000 --- a/trunk/src/examples/test_bibparse.py +++ /dev/null @@ -1,195 +0,0 @@ -""" 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/trunk/src/examples/urlExtractor.py b/trunk/src/examples/urlExtractor.py deleted file mode 100644 index 2c66d78..0000000 --- a/trunk/src/examples/urlExtractor.py +++ /dev/null @@ -1,33 +0,0 @@ -# URL extractor -# Copyright 2004, Paul McGuire -from pyparsing import makeHTMLTags, SkipTo, pyparsing_common -import urllib.request -from contextlib import closing -import pprint - -linkOpenTag, linkCloseTag = makeHTMLTags('a') - -linkBody = SkipTo(linkCloseTag) -linkBody.setParseAction(pyparsing_common.stripHTMLTags) -linkBody.addParseAction(lambda toks: ' '.join(toks[0].strip().split())) - -link = linkOpenTag + linkBody("body") + linkCloseTag.suppress() - -# Go get some HTML with some links in it. -with closing(urllib.request.urlopen("http://www.yahoo.com")) as serverListPage: - htmlText = serverListPage.read().decode("UTF-8") - -# scanString is a generator that loops through the input htmlText, and for each -# match yields the tokens and start and end locations (for this application, we are -# not interested in the start and end values). -for toks,strt,end in link.scanString(htmlText): - print(toks.asList()) - -# Create dictionary from list comprehension, assembled from each pair of tokens returned -# from a matched URL. -pprint.pprint( - dict((toks.body, toks.href) for toks,strt,end in link.scanString(htmlText)) - ) - - - diff --git a/trunk/src/examples/urlExtractorNew.py b/trunk/src/examples/urlExtractorNew.py deleted file mode 100644 index 0aac875..0000000 --- a/trunk/src/examples/urlExtractorNew.py +++ /dev/null @@ -1,35 +0,0 @@ -# URL extractor -# Copyright 2004, Paul McGuire -from pyparsing import Literal,Suppress,CharsNotIn,CaselessLiteral,\ - Word,dblQuotedString,alphanums,SkipTo,makeHTMLTags -import urllib.request, urllib.parse, urllib.error -import pprint - -# Define the pyparsing grammar for a URL, that is: -# URLlink ::= linkText -# URL ::= doubleQuotedString | alphanumericWordPath -# Note that whitespace may appear just about anywhere in the link. Note also -# that it is not necessary to explicitly show this in the pyparsing grammar; by default, -# pyparsing skips over whitespace between tokens. -linkOpenTag,linkCloseTag = makeHTMLTags("a") -link = linkOpenTag + SkipTo(linkCloseTag)("body") + linkCloseTag.suppress() - -# Go get some HTML with some links in it. -serverListPage = urllib.request.urlopen( "http://www.google.com" ) -htmlText = serverListPage.read() -serverListPage.close() - -# scanString is a generator that loops through the input htmlText, and for each -# match yields the tokens and start and end locations (for this application, we are -# not interested in the start and end values). -for toks,strt,end in link.scanString(htmlText): - print(toks.startA.href,"->",toks.body) - -# Create dictionary from list comprehension, assembled from each pair of tokens returned -# from a matched URL. -pprint.pprint( - dict( [ (toks.body,toks.startA.href) for toks,strt,end in link.scanString(htmlText) ] ) - ) - - - diff --git a/trunk/src/examples/verilogParse.py b/trunk/src/examples/verilogParse.py deleted file mode 100644 index 2b7fd35..0000000 --- a/trunk/src/examples/verilogParse.py +++ /dev/null @@ -1,720 +0,0 @@ -# -# verilogParse.py -# -# an example of using the pyparsing module to be able to process Verilog files -# uses BNF defined at http://www.verilog.com/VerilogBNF.html -# -# Copyright (c) 2004-2011 Paul T. McGuire. All rights reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# If you find this software to be useful, please make a donation to one -# of the following charities: -# - the Red Cross (http://www.redcross.org) -# - Hospice Austin (http://www.hospiceaustin.org) -# -# DISCLAIMER: -# THIS SOFTWARE IS PROVIDED BY PAUL T. McGUIRE ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -# EVENT SHALL PAUL T. McGUIRE OR CO-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OFUSE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# For questions or inquiries regarding this license, or commercial use of -# this software, contact the author via e-mail: ptmcg@users.sourceforge.net -# -# Todo: -# - add pre-process pass to implement compilerDirectives (ifdef, include, etc.) -# -# Revision History: -# -# 1.0 - Initial release -# 1.0.1 - Fixed grammar errors: -# . real declaration was incorrect -# . tolerant of '=>' for '*>' operator -# . tolerant of '?' as hex character -# . proper handling of mintypmax_expr within path delays -# 1.0.2 - Performance tuning (requires pyparsing 1.3) -# 1.0.3 - Performance updates, using Regex (requires pyparsing 1.4) -# 1.0.4 - Performance updates, enable packrat parsing (requires pyparsing 1.4.2) -# 1.0.5 - Converted keyword Literals to Keywords, added more use of Group to -# group parsed results tokens -# 1.0.6 - Added support for module header with no ports list (thanks, Thomas Dejanovic!) -# 1.0.7 - Fixed erroneous '<<' Forward definition in timCheckCond, omitting ()'s -# 1.0.8 - Re-released under MIT license -# 1.0.9 - Enhanced udpInstance to handle identifiers with leading '\' and subscripting -# 1.0.10 - Fixed change added in 1.0.9 to work for all identifiers, not just those used -# for udpInstance. -# 1.0.11 - Fixed bug in inst_args, content alternatives were reversed -# -import pdb -import time -import pprint -import sys - -__version__ = "1.0.11" - -from pyparsing import Literal, CaselessLiteral, Keyword, Word, OneOrMore, ZeroOrMore, \ - Forward, NotAny, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ - alphanums, printables, dblQuotedString, empty, ParseException, ParseResults, MatchFirst, oneOf, GoToColumn, \ - ParseResults,StringEnd, FollowedBy, ParserElement, And, Regex, cppStyleComment#,__version__ -import pyparsing -usePackrat = False -usePsyco = False - -packratOn = False -psycoOn = False - -if usePackrat: - try: - ParserElement.enablePackrat() - except: - pass - else: - packratOn = True - -# comment out this section to disable psyco function compilation -if usePsyco: - try: - import psyco - psyco.full() - except: - print("failed to import psyco Python optimizer") - else: - psycoOn = True - - -def dumpTokens(s,l,t): - import pprint - pprint.pprint( t.asList() ) - -verilogbnf = None -def Verilog_BNF(): - global verilogbnf - - if verilogbnf is None: - - # compiler directives - compilerDirective = Combine( "`" + \ - oneOf("define undef ifdef else endif default_nettype " - "include resetall timescale unconnected_drive " - "nounconnected_drive celldefine endcelldefine") + \ - restOfLine ).setName("compilerDirective") - - # primitives - SEMI,COLON,LPAR,RPAR,LBRACE,RBRACE,LBRACK,RBRACK,DOT,COMMA,EQ = map(Literal,";:(){}[].,=") - - identLead = alphas+"$_" - identBody = alphanums+"$_" - identifier1 = Regex( r"\.?["+identLead+"]["+identBody+"]*(\.["+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::= ; - x||= ; - x||= if ( ) - x||= if ( ) else - x||= case ( ) + endcase - x||= casez ( ) + endcase - x||= casex ( ) + endcase - x||= forever - x||= repeat ( ) - x||= while ( ) - x||= for ( ; ; ) - x||= - x||= wait ( ) - x||= -> ; - x||= - x||= - x||= - x||= - x||= disable ; - x||= disable ; - x||= assign ; - x||= deassign ; - x||= force ; - x||= release ; - """ - 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::= - x||= - x||= - x||= - x||= - x||= - """ - 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::= - x||= - x||= - x||= - ?||= (spec does not seem consistent for this item) - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - x||= - """ - 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") - - """ - - ::= primitive ( <,>* ) ; - + - ? - - endprimitive - """ - udp = Group( "primitive" + identifier + - LPAR + Group( delimitedList( identifier ) ) + RPAR + SEMI + - OneOrMore( udpDecl ) + - Optional( udpInitialStmt ) + - udpTableDefn + - "endprimitive" ) - - verilogbnf = OneOrMore( module | udp ) + StringEnd() - - verilogbnf.ignore( cppStyleComment ) - verilogbnf.ignore( compilerDirective ) - - return verilogbnf - - -def test( strng ): - tokens = [] - try: - tokens = Verilog_BNF().parseString( strng ) - except ParseException as err: - print(err.line) - print(" "*(err.column-1) + "^") - print(err) - return tokens - - -#~ if __name__ == "__main__": -if 0: - import pprint - toptest = """ - module TOP( in, out ); - input [7:0] in; - output [5:0] out; - COUNT_BITS8 count_bits( .IN( in ), .C( out ) ); - endmodule""" - pprint.pprint( test(toptest).asList() ) - -else: - def main(): - print("Verilog parser test (V %s)" % __version__) - print(" - using pyparsing version", pyparsing.__version__) - print(" - using Python version", sys.version) - if packratOn: print(" - using packrat parsing") - if psycoOn: print(" - using psyco runtime optimization") - print() - - import os - import gc - - failCount = 0 - Verilog_BNF() - numlines = 0 - startTime = time.clock() - fileDir = "verilog" - #~ fileDir = "verilog/new" - #~ fileDir = "verilog/new2" - #~ fileDir = "verilog/new3" - allFiles = [f for f in os.listdir(fileDir) if f.endswith(".v")] - #~ allFiles = [ "list_path_delays_test.v" ] - #~ allFiles = [ "escapedIdent.v" ] - #~ allFiles = filter( lambda f : f.startswith("a") and f.endswith(".v"), os.listdir(fileDir) ) - #~ allFiles = filter( lambda f : f.startswith("c") and f.endswith(".v"), os.listdir(fileDir) ) - #~ allFiles = [ "ff.v" ] - - pp = pprint.PrettyPrinter( indent=2 ) - totalTime = 0 - for vfile in allFiles: - gc.collect() - fnam = fileDir + "/"+vfile - infile = open(fnam) - filelines = infile.readlines() - infile.close() - print(fnam, len(filelines), end=' ') - numlines += len(filelines) - teststr = "".join(filelines) - time1 = time.clock() - tokens = test( teststr ) - time2 = time.clock() - elapsed = time2-time1 - totalTime += elapsed - if ( len( tokens ) ): - print("OK", elapsed) - #~ print "tokens=" - #~ pp.pprint( tokens.asList() ) - #~ print - - ofnam = fileDir + "/parseOutput/" + vfile + ".parsed.txt" - outfile = open(ofnam,"w") - outfile.write( teststr ) - outfile.write("\n") - outfile.write("\n") - outfile.write(pp.pformat(tokens.asList())) - outfile.write("\n") - outfile.close() - else: - print("failed", elapsed) - failCount += 1 - for i,line in enumerate(filelines,1): - print("%4d: %s" % (i,line.rstrip())) - endTime = time.clock() - print("Total parse time:", totalTime) - print("Total source lines:", numlines) - print("Average lines/sec:", ( "%.1f" % (float(numlines)/(totalTime+.05 ) ) )) - if failCount: - print("FAIL - %d files failed to parse" % failCount) - else: - print("SUCCESS - all files parsed") - - return 0 - - #~ from line_profiler import LineProfiler - #~ from pyparsing import ParseResults - #~ lp = LineProfiler(ParseResults.__init__) - - main() - - #~ lp.print_stats() - #~ import hotshot - #~ p = hotshot.Profile("vparse.prof",1,1) - #~ p.start() - #~ main() - #~ p.stop() - #~ p.close() diff --git a/trunk/src/examples/withAttribute.py b/trunk/src/examples/withAttribute.py deleted file mode 100644 index 062c9ae..0000000 --- a/trunk/src/examples/withAttribute.py +++ /dev/null @@ -1,24 +0,0 @@ -# -# withAttribute.py -# Copyright, 2007 - Paul McGuire -# -# Simple example of using withAttribute parse action helper -# to define -# -data = """\ -  49.950  -  50.950  -  51.950  - """ - -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(" ") -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/trunk/src/examples/wordsToNum.py b/trunk/src/examples/wordsToNum.py deleted file mode 100644 index 60c7c3d..0000000 --- a/trunk/src/examples/wordsToNum.py +++ /dev/null @@ -1,98 +0,0 @@ -# wordsToNum.py -# Copyright 2006, Paul McGuire -# -# Sample parser grammar to read a number given in words, and return the numeric value. -# -from pyparsing import * -from operator import mul -from functools import reduce - -def makeLit(s,val): - ret = CaselessLiteral(s).setName(s) - return ret.setParseAction( replaceWith(val) ) - -unitDefinitions = [ - ("zero", 0), - ("oh", 0), - ("zip", 0), - ("zilch", 0), - ("nada", 0), - ("bupkis", 0), - ("one", 1), - ("two", 2), - ("three", 3), - ("four", 4), - ("five", 5), - ("six", 6), - ("seven", 7), - ("eight", 8), - ("nine", 9), - ("ten", 10), - ("eleven", 11), - ("twelve", 12), - ("thirteen", 13), - ("fourteen", 14), - ("fifteen", 15), - ("sixteen", 16), - ("seventeen", 17), - ("eighteen", 18), - ("nineteen", 19), - ] -units = Or(makeLit(s,v) for s,v in unitDefinitions) - -tensDefinitions = [ - ("ten", 10), - ("twenty", 20), - ("thirty", 30), - ("forty", 40), - ("fourty", 40), # for the spelling-challenged... - ("fifty", 50), - ("sixty", 60), - ("seventy", 70), - ("eighty", 80), - ("ninety", 90), - ] -tens = Or(makeLit(s,v) for s,v in tensDefinitions) - -hundreds = makeLit("hundred", 100) - -majorDefinitions = [ - ("thousand", int(1e3)), - ("million", int(1e6)), - ("billion", int(1e9)), - ("trillion", int(1e12)), - ("quadrillion", int(1e15)), - ("quintillion", int(1e18)), - ] -mag = Or(makeLit(s,v) for s,v in majorDefinitions) - -wordprod = lambda t: reduce(mul,t) -wordsum = lambda t: sum(t) -numPart = (((( units + Optional(hundreds) ).setParseAction(wordprod) + - Optional(tens)).setParseAction(wordsum) - ^ tens ) - + Optional(units) ).setParseAction(wordsum) -numWords = OneOrMore( (numPart + Optional(mag)).setParseAction(wordprod) - ).setParseAction(wordsum) + StringEnd() -numWords.ignore(Literal("-")) -numWords.ignore(CaselessLiteral("and")) - -def test(s,expected): - print ("Expecting %s" % expected) - numWords.runTests(s) - -test("one hundred twenty hundred", None) -test("one hundred and twennty", None) -test("one hundred and twenty", 120) -test("one hundred and three", 103) -test("one hundred twenty-three", 123) -test("one hundred and twenty three", 123) -test("one hundred twenty three million", 123000000) -test("one hundred and twenty three million", 123000000) -test("one hundred twenty three million and three", 123000003) -test("fifteen hundred and sixty five", 1565) -test("seventy-seven thousand eight hundred and nineteen", 77819) -test("seven hundred seventy-seven thousand seven hundred and seventy-seven", 777777) -test("zero", 0) -test("forty two", 42) -test("fourty two", 42) \ No newline at end of file diff --git a/trunk/src/genEpydoc.bat b/trunk/src/genEpydoc.bat deleted file mode 100644 index 988954b..0000000 --- a/trunk/src/genEpydoc.bat +++ /dev/null @@ -1,2 +0,0 @@ -xcopy /y ..\sourceforge\svn\trunk\src\pyparsing.py . -c:\python27\python c:\python27\scripts\epydoc -v --name pyparsing -o htmldoc --inheritance listed --no-private pyparsing.py diff --git a/trunk/src/makeRelease.bat b/trunk/src/makeRelease.bat deleted file mode 100644 index 692e572..0000000 --- a/trunk/src/makeRelease.bat +++ /dev/null @@ -1,24 +0,0 @@ -copy ..\sourceforge\svn\trunk\src\CHANGES . -copy ..\sourceforge\svn\trunk\src\setup.py . -copy ..\sourceforge\svn\trunk\src\pyparsing.py . -copy ..\sourceforge\svn\trunk\src\MANIFEST.in_bdist . -copy ..\sourceforge\svn\trunk\src\MANIFEST.in_src . -copy ..\sourceforge\svn\trunk\src\examples\* .\examples\ - -rmdir build -rmdir dist - -copy/y MANIFEST.in_src MANIFEST.in -if exist MANIFEST del MANIFEST -python setup.py sdist --formats=gztar,zip - -copy/y MANIFEST.in_bdist MANIFEST.in -if exist MANIFEST del MANIFEST - -python setup.py bdist_wheel -python setup.py bdist_wininst --target-version=2.6 --plat-name=win32 -python setup.py bdist_wininst --target-version=2.7 --plat-name=win32 -python setup.py bdist_wininst --target-version=3.3 --plat-name=win32 -python setup.py bdist_wininst --target-version=3.4 --plat-name=win32 -python setup.py bdist_wininst --target-version=3.5 --plat-name=win32 - diff --git a/trunk/src/pyparsing.py b/trunk/src/pyparsing.py deleted file mode 100644 index 6a3f582..0000000 --- a/trunk/src/pyparsing.py +++ /dev/null @@ -1,5528 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2015 Paul T. McGuire -# -# 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. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form C{", !"}):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word( alphas ) + "," + Word( alphas ) + "!" - - hello = "Hello, World!" - print (hello, "->", greet.parseString( hello )) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The parsed results returned from L{I{ParserElement.parseString}} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments -""" - -__version__ = "2.1.6" -__versionTime__ = "07 Aug 2016 04:42 UTC" -__author__ = "Paul McGuire " - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -import collections -import pprint -import traceback -import types -from datetime import datetime - -try: - from _thread import RLock -except ImportError: - from threading import RLock - -try: - from collections import OrderedDict as _OrderedDict -except ImportError: - try: - from ordereddict import OrderedDict as _OrderedDict - except ImportError: - _OrderedDict = None - -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', -'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', -'tokenMap', 'pyparsing_common', -] - -system_version = tuple(sys.version_info)[:3] -PY_3 = system_version[0] == 3 -if PY_3: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - - # build list of single arg builtins, that can be used as parse actions - singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] - -else: - _MAX_INT = sys.maxint - range = xrange - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # Else encode it - ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') - xmlcharref = Regex('&#\d+;') - xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) - return xmlcharref.transformString(ret) - - # build list of single arg builtins, tolerant of Python version, that can be used as parse actions - singleArgBuiltins = [] - import __builtin__ - for fname in "sum len sorted reversed list tuple set any all min max".split(): - try: - singleArgBuiltins.append(getattr(__builtin__,fname)) - except AttributeError: - continue - -_generatorType = type((y for y in range(1))) - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - from_symbols = '&><"\'' - to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) - for from_,to_ in zip(from_symbols, to_symbols): - data = data.replace(from_, to_) - return data - -class _Constants(object): - pass - -alphas = string.ascii_uppercase + string.ascii_lowercase -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join(c for c in string.printable if c not in string.whitespace) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - self.args = (pstr, loc, msg) - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join((line_str[:line_column], - markerString, line_str[line_column:])) - return line_str.strip() - def __dir__(self): - return "lineno col line".split() + dir(type(self)) - -class ParseException(ParseBaseException): - """ - Exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - - Example:: - try: - Word(nums).setName("integer").parseString("ABC") - except ParseException as pe: - print(pe) - print("column: {}".format(pe.col)) - - prints:: - Expected integer (at char 0), (line:1, col:1) - column: 1 - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like C{L{ParseFatalException}}, but thrown internally when an - C{L{ErrorStop}} ('-' operator) indicates that parsing is to stop immediately because - an unbacktrackable syntax error has been found""" - def __init__(self, pe): - super(ParseSyntaxException, self).__init__( - pe.pstr, pe.loc, pe.msg, pe.parserElement) - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by C{validate()} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """ - Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.} - see L{ParserElement.setResultsName}) - - Example:: - integer = Word(nums) - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - # equivalent form: - # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString("1999/12/31") - print(list(result)) - print(result[0]) - print(result['month']) - print(result.day) - print('month' in result) - print('minutes' in result) - print(result.dump()) - prints:: - ['1999', '/', '12', '/', '31'] - 1999 - 12 - 31 - True - False - ['1999', '/', '12', '/', '31'] - - day: 31 - - month: 12 - - year: 1999 - """ - def __new__(cls, toklist=None, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - self.__asList = asList - self.__modal = modal - if toklist is None: - toklist = [] - if isinstance(toklist, list): - self.__toklist = toklist[:] - elif isinstance(toklist, _generatorType): - self.__toklist = list(toklist) - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,(int,slice)): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return ( not not self.__toklist ) - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def _iterkeys( self ): - if hasattr(self.__tokdict, "iterkeys"): - return self.__tokdict.iterkeys() - else: - return iter(self.__tokdict) - - def _itervalues( self ): - return (self[k] for k in self._iterkeys()) - - def _iteritems( self ): - return ((k, self[k]) for k in self._iterkeys()) - - if PY_3: - keys = _iterkeys - """Returns an iterator of all named result keys (Python 3.x only).""" - - values = _itervalues - """Returns an iterator of all named result values (Python 3.x only).""" - - items = _iteritems - """Returns an iterator of all named result key-value tuples (Python 3.x only).""" - - else: - iterkeys = _iterkeys - """Returns an iterator of all named result keys (Python 2.x only).""" - - itervalues = _itervalues - """Returns an iterator of all named result values (Python 2.x only).""" - - iteritems = _iteritems - """Returns an iterator of all named result key-value tuples (Python 2.x only).""" - - def keys( self ): - """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iterkeys()) - - def values( self ): - """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.itervalues()) - - def items( self ): - """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iteritems()) - - def haskeys( self ): - """Since keys() returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" - return bool(self.__tokdict) - - def pop( self, *args, **kwargs): - """ - Removes and returns item at specified index (default=C{last}). - Supports both C{list} and C{dict} semantics for C{pop()}. If passed no - argument or an integer argument, it will use C{list} semantics - and pop tokens from the list of parsed tokens. If passed a - non-integer argument (most likely a string), it will use C{dict} - semantics and pop the corresponding value from any defined - results names. A second default return value argument is - supported, just as in C{dict.pop()}. - - Example:: - def remove_first(tokens): - tokens.pop(0) - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] - - label = Word(alphas) - patt = label("LABEL") + OneOrMore(Word(nums)) - print(patt.parseString("AAB 123 321").dump()) - - # Use pop() in a parse action to remove named result (note that corresponding value is not - # removed from list form of results) - def remove_LABEL(tokens): - tokens.pop("LABEL") - return tokens - patt.addParseAction(remove_LABEL) - print(patt.parseString("AAB 123 321").dump()) - prints:: - ['AAB', '123', '321'] - - LABEL: AAB - - ['AAB', '123', '321'] - """ - if not args: - args = [-1] - for k,v in kwargs.items(): - if k == 'default': - args = (args[0], v) - else: - raise TypeError("pop() got an unexpected keyword argument '%s'" % k) - if (isinstance(args[0], int) or - len(args) == 1 or - args[0] in self): - index = args[0] - ret = self[index] - del self[index] - return ret - else: - defaultvalue = args[1] - return defaultvalue - - def get(self, key, defaultValue=None): - """ - Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified. - - Similar to C{dict.get()}. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString("1999/12/31") - print(result.get("year")) # -> '1999' - print(result.get("hour", "not specified")) # -> 'not specified' - print(result.get("hour")) # -> None - """ - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """ - Inserts new element at location index in the list of parsed tokens. - - Similar to C{list.insert()}. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to insert the parse location in the front of the parsed results - def insert_locn(locn, tokens): - tokens.insert(0, locn) - print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] - """ - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def append( self, item ): - """ - Add single element to end of ParseResults list of elements. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to compute the sum of the parsed integers, and add it to the end - def append_sum(tokens): - tokens.append(sum(map(int, tokens))) - print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] - """ - self.__toklist.append(item) - - def extend( self, itemseq ): - """ - Add sequence of elements to end of ParseResults list of elements. - - Example:: - patt = OneOrMore(Word(alphas)) - - # use a parse action to append the reverse of the matched strings, to make a palindrome - def make_palindrome(tokens): - tokens.extend(reversed([t[::-1] for t in tokens])) - return ''.join(tokens) - print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' - """ - if isinstance(itemseq, ParseResults): - self += itemseq - else: - self.__toklist.extend(itemseq) - - def clear( self ): - """ - Clear all elements and results names. - """ - del self.__toklist[:] - self.__tokdict.clear() - - def __getattr__( self, name ): - try: - return self[name] - except KeyError: - return "" - - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = lambda a: offset if a<0 else a+offset - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - # useful for merging many ParseResults using sum() builtin - return self.copy() - else: - # this may raise a TypeError - so be it - return other + self - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """ - Returns the parse results as a nested list of matching tokens, all converted to strings. - - Example:: - patt = OneOrMore(Word(alphas)) - result = patt.parseString("sldkj lsdkj sldkj") - # even though the result prints in string-like form, it is actually a pyparsing ParseResults - print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] - - # Use asList() to create an actual list - result_list = result.asList() - print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] - """ - return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] - - def asDict( self ): - """ - Returns the named parse results as a nested dictionary. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - - result_dict = result.asDict() - print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} - - # even though a ParseResults supports dict-like access, sometime you just need to have a dict - import json - print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable - print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} - """ - if PY_3: - item_fn = self.items - else: - item_fn = self.iteritems - - def toItem(obj): - if isinstance(obj, ParseResults): - if obj.haskeys(): - return obj.asDict() - else: - return [toItem(v) for v in obj] - else: - return obj - - return dict((k,toItem(v)) for k,v in item_fn()) - - def copy( self ): - """ - Returns a new copy of a C{ParseResults} object. - """ - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """ - (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. - """ - nl = "\n" - out = [] - namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - for i,res in enumerate(self.__toklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - """ - Returns the results name for this token expression. Useful when several - different expressions might match at a particular location. - - Example:: - integer = Word(nums) - ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") - house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") - | Group(ssn_expr)("ssn") - | Group(integer)("age")) - user_info = OneOrMore(user_data) - - result = user_info.parseString("22 111-22-3333 #221B") - for item in result: - print(item.getName(), ':', item[0]) - prints:: - age : 22 - ssn : 111-22-3333 - house_number : 221B - """ - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - self.__tokdict.values()[0][0][1] in (0,-1)): - return self.__tokdict.keys()[0] - else: - return None - - def dump(self, indent='', depth=0, full=True): - """ - Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(result.dump()) - prints:: - ['12', '/', '31', '/', '1999'] - - day: 1999 - - month: 31 - - year: 12 - """ - out = [] - NL = '\n' - out.append( indent+_ustr(self.asList()) ) - if full: - if self.haskeys(): - items = sorted(self.items()) - for k,v in items: - if out: - out.append(NL) - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v: - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(_ustr(v)) - elif any(isinstance(vv,ParseResults) for vv in self): - v = self - for i,vv in enumerate(v): - if isinstance(vv,ParseResults): - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) - else: - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) - - return "".join(out) - - def pprint(self, *args, **kwargs): - """ - Pretty-printer for parsed results as a list, using the C{pprint} module. - Accepts additional positional or keyword args as defined for the - C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) - - Example:: - ident = Word(alphas, alphanums) - num = Word(nums) - func = Forward() - term = ident | num | Group('(' + func + ')') - func <<= ident + Group(Optional(delimitedList(term))) - result = func.parseString("fna a,b,(fnb c,d,200),100") - result.pprint(width=40) - prints:: - ['fna', - ['a', - 'b', - ['(', 'fnb', ['c', 'd', '200'], ')'], - '100']] - """ - pprint.pprint(self.asList(), *args, **kwargs) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - (self.__tokdict, - par, - inAccumNames, - self.__name) = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __getnewargs__(self): - return self.__toklist, self.__name, self.__asList, self.__modal - - def __dir__(self): - return (dir(type(self)) + list(self.keys())) - -collections.MutableMapping.register(ParseResults) - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - s = strg - return 1 if loc} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -# Only works on Python 3.x - nonlocal is toxic to Python 2 installs -#~ 'decorator to trim function calls to match the arity of the target' -#~ def _trim_arity(func, maxargs=3): - #~ if func in singleArgBuiltins: - #~ return lambda s,l,t: func(t) - #~ limit = 0 - #~ foundArity = False - #~ def wrapper(*args): - #~ nonlocal limit,foundArity - #~ while 1: - #~ try: - #~ ret = func(*args[limit:]) - #~ foundArity = True - #~ return ret - #~ except TypeError: - #~ if limit == maxargs or foundArity: - #~ raise - #~ limit += 1 - #~ continue - #~ return wrapper - -# this version is Python 2.x-3.x cross-compatible -'decorator to trim function calls to match the arity of the target' -def _trim_arity(func, maxargs=2): - if func in singleArgBuiltins: - return lambda s,l,t: func(t) - limit = [0] - foundArity = [False] - - # traceback return data structure changed in Py3.5 - normalize back to plain tuples - if system_version[:2] >= (3,5): - def extract_stack(): - # special handling for Python 3.5.0 - extra deep call stack by 1 - offset = -3 if system_version == (3,5,0) else -2 - frame_summary = traceback.extract_stack()[offset] - return [(frame_summary.filename, frame_summary.lineno)] - def extract_tb(tb): - frames = traceback.extract_tb(tb) - frame_summary = frames[-1] - return [(frame_summary.filename, frame_summary.lineno)] - else: - extract_stack = traceback.extract_stack - extract_tb = traceback.extract_tb - - # synthesize what would be returned by traceback.extract_stack at the call to - # user's parse action 'func', so that we don't incur call penalty at parse time - - LINE_DIFF = 6 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND - # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! - this_line = extract_stack()[-1] - pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) - - def wrapper(*args): - while 1: - try: - ret = func(*args[limit[0]:]) - foundArity[0] = True - return ret - except TypeError: - # re-raise TypeErrors if they did not come from our arity testing - if foundArity[0]: - raise - else: - try: - tb = sys.exc_info()[-1] - if not extract_tb(tb)[-1][:2] == pa_call_line_synth: - raise - finally: - del tb - - if limit[0] <= maxargs: - limit[0] += 1 - continue - raise - - # copy func name to wrapper for sensible debug output - func_name = "" - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - wrapper.__name__ = func_name - - return wrapper - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - @staticmethod - def setDefaultWhitespaceChars( chars ): - r""" - Overrides the default whitespace chars - - Example:: - # default whitespace chars are space, and newline - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - - # change to just treat newline as significant - ParserElement.setDefaultWhitespaceChars(" \t") - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - - @staticmethod - def inlineLiteralsUsing(cls): - """ - Set class to be used for inclusion of string literals into a parser. - - Example:: - # default literal class used is Literal - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - - # change to Suppress - ParserElement.inlineLiteralsUsing(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] - """ - ParserElement._literalStringClass = cls - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """ - Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element. - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") - integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - - print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) - prints:: - [5120, 100, 655360, 268435456] - Equivalent form of C{expr.copy()} is just C{expr()}:: - integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - """ - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """ - Define name for this expression, makes exception messages clearer. - - Example:: - Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) - Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) - """ - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """ - Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - - Example:: - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - - # equivalent form: - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - """ - newself = self.copy() - if name.endswith("*"): - name = name[:-1] - listAllMatches=True - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def setParseAction( self, *fns, **kwargs ): - """ - Define action to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Optional keyword arguments: - - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}} for more information - on parsing strings containing C{}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - - Example:: - integer = Word(nums) - date_str = integer + '/' + integer + '/' + integer - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - # use parse action to convert to ints at parse time - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - date_str = integer + '/' + integer + '/' + integer - - # note that integer fields are now ints, not strings - date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] - """ - self.parseAction = list(map(_trim_arity, list(fns))) - self.callDuringTry = kwargs.get("callDuringTry", False) - return self - - def addParseAction( self, *fns, **kwargs ): - """ - Add parse action to expression's list of parse actions. See L{I{setParseAction}}. - - See examples in L{I{copy}}. - """ - self.parseAction += list(map(_trim_arity, list(fns))) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def addCondition(self, *fns, **kwargs): - """Add a boolean predicate function to expression's list of parse actions. See - L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, - functions passed to C{addCondition} need to return boolean success/fail of the condition. - - Optional keyword arguments: - - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - year_int = integer.copy() - year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") - date_str = year_int + '/' + integer + '/' + integer - - result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) - """ - msg = kwargs.get("message", "failed user-defined condition") - exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException - for fn in fns: - def pa(s,l,t): - if not bool(_trim_arity(fn)(s,l,t)): - raise exc_type(s,l,msg) - self.parseAction.append(pa) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{L{ParseFatalException}} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException as err: - #~ print ("Exception raised:", err) - if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or loc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - def canParseNext(self, instring, loc): - try: - self.tryParse(instring, loc) - except (ParseException, IndexError): - return False - else: - return True - - class _UnboundedCache(object): - def __init__(self): - cache = {} - self.not_in_cache = not_in_cache = object() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - - def clear(self): - cache.clear() - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - - if _OrderedDict is not None: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = _OrderedDict() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - if len(cache) > size: - cache.popitem(False) - - def clear(self): - cache.clear() - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - - else: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = {} - key_fifo = collections.deque([], size) - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - if len(cache) > size: - cache.pop(key_fifo.popleft(), None) - key_fifo.append(key) - - def clear(self): - cache.clear() - key_fifo.clear() - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail - packrat_cache_lock = RLock() - packrat_cache_stats = [0, 0] - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - HIT, MISS = 0, 1 - lookup = (self, instring, loc, callPreParse, doActions) - with ParserElement.packrat_cache_lock: - cache = ParserElement.packrat_cache - value = cache.get(lookup) - if value is cache.not_in_cache: - ParserElement.packrat_cache_stats[MISS] += 1 - try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) - except ParseBaseException as pe: - # cache a copy of the exception, without the traceback - cache.set(lookup, pe.__class__(*pe.args)) - raise - else: - cache.set(lookup, (value[0], value[1].copy())) - return value - else: - ParserElement.packrat_cache_stats[HIT] += 1 - if isinstance(value, Exception): - raise value - return (value[0], value[1].copy()) - - _parse = _parseNoCache - - @staticmethod - def resetCache(): - ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) - - _packratEnabled = False - @staticmethod - def enablePackrat(cache_size_limit=128): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - cache_size_limit - (default=C{128}) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - - Example:: - import pyparsing - pyparsing.ParserElement.enablePackrat() - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - if cache_size_limit is None: - ParserElement.packrat_cache = ParserElement._UnboundedCache() - else: - ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) - ParserElement._parse = ParserElement._parseCache - - def parseString( self, instring, parseAll=False ): - """ - Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{L{StringEnd()}}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - - Example:: - Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] - Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - loc = self.preParse( instring, loc ) - se = Empty() + StringEnd() - se._parse( instring, loc ) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): - """ - Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. If - C{overlap} is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}} for more information on parsing - strings with embedded tabs. - - Example:: - source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" - print(source) - for tokens,start,end in Word(alphas).scanString(source): - print(' '*start + '^'*(end-start)) - print(' '*start + tokens[0]) - - prints:: - - sldjf123lsdjjkf345sldkjf879lkjsfd987 - ^^^^^ - sldjf - ^^^^^^^ - lsdjjkf - ^^^^^^ - sldkjf - ^^^^^^ - lkjsfd - """ - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn( instring, loc ) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def transformString( self, instring ): - """ - Extension to C{L{scanString}}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string. - - Example:: - wd = Word(alphas) - wd.setParseAction(lambda toks: toks[0].title()) - - print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) - Prints:: - Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. - """ - out = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def searchString( self, instring, maxMatches=_MAX_INT ): - """ - Another extension to C{L{scanString}}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - - Example:: - # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters - cap_word = Word(alphas.upper(), alphas.lower()) - - print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) - prints:: - ['More', 'Iron', 'Lead', 'Gold', 'I'] - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): - """ - Generator method to split a string using the given expression as a separator. - May be called with optional C{maxsplit} argument, to limit the number of splits; - and the optional C{includeSeparators} argument (default=C{False}), if the separating - matching text should be included in the split results. - - Example:: - punc = oneOf(list(".,;:/-!?")) - print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) - prints:: - ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] - """ - splits = 0 - last = 0 - for t,s,e in self.scanString(instring, maxMatches=maxsplit): - yield instring[last:s] - if includeSeparators: - yield t[0] - last = e - yield instring[last:] - - def __add__(self, other ): - """ - Implementation of + operator - returns C{L{And}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """ - Implementation of + operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """ - Implementation of - operator, returns C{L{And}} with error stop - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, And._ErrorStop(), other ] ) - - def __rsub__(self, other ): - """ - Implementation of - operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """ - Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + L{ZeroOrMore}(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} - - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """ - Implementation of | operator - returns C{L{MatchFirst}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """ - Implementation of | operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """ - Implementation of ^ operator - returns C{L{Or}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """ - Implementation of ^ operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """ - Implementation of & operator - returns C{L{Each}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """ - Implementation of & operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """ - Implementation of ~ operator - returns C{L{NotAny}} - """ - return NotAny( self ) - - def __call__(self, name=None): - """ - Shortcut for C{L{setResultsName}}, with C{listAllMatches=default}. - - If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be - passed as C{True}. - - If C{name} is omitted, same as calling C{L{copy}}. - - Example:: - # these are equivalent - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - """ - if name is not None: - return self.setResultsName(name) - else: - return self.copy() - - def suppress( self ): - """ - Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """ - Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """ - Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """ - Overrides default behavior to expand C{}s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match C{} characters. - """ - self.keepTabs = True - return self - - def ignore( self, other ): - """ - Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - - Example:: - patt = OneOrMore(Word(alphas)) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] - - patt.ignore(cStyleComment) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] - """ - if isinstance(other, basestring): - other = Suppress(other) - - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append(other) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """ - Enable display of debugging messages while doing pattern matching. - """ - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """ - Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable. - """ - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """ - Check defined expressions for valid structure, check for infinite recursive definitions. - """ - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """ - Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - with open(file_or_filename, "r") as f: - file_contents = f.read() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or vars(self) == vars(other) - elif isinstance(other, basestring): - return self.matches(other) - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - def matches(self, testString, parseAll=True): - """ - Method for quick testing of a parser against a test string. Good for simple - inline microtests of sub expressions while building up larger parser.0 - - Parameters: - - testString - to test against this expression for a match - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - Example:: - expr = Word(nums) - assert expr.matches("100") - """ - try: - self.parseString(_ustr(testString), parseAll=parseAll) - return True - except ParseBaseException: - return False - - def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): - """ - Execute the parse expression on a series of test strings, showing each - test, the parsed results or where the parse failed. Quick and easy way to - run a parse expression against a list of sample strings. - - Parameters: - - tests - a list of separate test strings, or a multiline string of test strings - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - comment - (default=C{'#'}) - expression for indicating embedded comments in the test - string; pass None to disable comment filtering - - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; - if False, only dump nested list - - printResults - (default=C{True}) prints test output to stdout - - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing - - Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if C{failureTests} is True), and the results contain a list of lines of each - test's output - - Example:: - number_expr = pyparsing_common.number.copy() - - result = number_expr.runTests(''' - # unsigned integer - 100 - # negative integer - -100 - # float with scientific notation - 6.02e23 - # integer with scientific notation - 1e-12 - ''') - print("Success" if result[0] else "Failed!") - - result = number_expr.runTests(''' - # stray character - 100Z - # missing leading digit before '.' - -.100 - # too many '.' - 3.14.159 - ''', failureTests=True) - print("Success" if result[0] else "Failed!") - prints:: - # unsigned integer - 100 - [100] - - # negative integer - -100 - [-100] - - # float with scientific notation - 6.02e23 - [6.02e+23] - - # integer with scientific notation - 1e-12 - [1e-12] - - Success - - # stray character - 100Z - ^ - FAIL: Expected end of text (at char 3), (line:1, col:4) - - # missing leading digit before '.' - -.100 - ^ - FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) - - # too many '.' - 3.14.159 - ^ - FAIL: Expected end of text (at char 4), (line:1, col:5) - - Success - """ - if isinstance(tests, basestring): - tests = list(map(str.strip, tests.rstrip().splitlines())) - if isinstance(comment, basestring): - comment = Literal(comment) - allResults = [] - comments = [] - success = True - for t in tests: - if comment is not None and comment.matches(t, False) or comments and not t: - comments.append(t) - continue - if not t: - continue - out = ['\n'.join(comments), t] - comments = [] - try: - result = self.parseString(t, parseAll=parseAll) - out.append(result.dump(full=fullDump)) - success = success and not failureTests - except ParseBaseException as pe: - fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" - if '\n' in t: - out.append(line(pe.loc, t)) - out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) - else: - out.append(' '*pe.loc + '^' + fatal) - out.append("FAIL: " + str(pe)) - success = success and failureTests - result = pe - - if printResults: - if fullDump: - out.append('') - print('\n'.join(out)) - - allResults.append((t, result)) - - return success, allResults - - -class Token(ParserElement): - """ - Abstract C{ParserElement} subclass, for defining atomic matching patterns. - """ - def __init__( self ): - super(Token,self).__init__( savelist=False ) - - -class Empty(Token): - """ - An empty token, will always match. - """ - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """ - A token that will never match. - """ - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - - def parseImpl( self, instring, loc, doActions=True ): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """ - Token to exactly match a specified string. - - Example:: - Literal('blah').parseString('blah') # -> ['blah'] - Literal('blah').parseString('blahfooblah') # -> ['blah'] - Literal('blah').parseString('bla') # -> Exception: Expected "blah" - - For case-insensitive matching, use L{CaselessLiteral}. - - For keyword matching (force word break before and after the matched string), - use L{Keyword} or L{CaselessKeyword}. - """ - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) -_L = Literal -ParserElement._literalStringClass = Literal - -class Keyword(Token): - """ - Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{L{Literal}}: - - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. - - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} - Accepts two optional constructor arguments in addition to the keyword string: - - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$" - - C{caseless} allows case-insensitive matching, default is C{False}. - - Example:: - Keyword("start").parseString("start") # -> ['start'] - Keyword("start").parseString("starting") # -> Exception - - For case-insensitive matching, use L{CaselessKeyword}. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ): - super(Keyword,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - @staticmethod - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - -class CaselessLiteral(Literal): - """ - Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - - Example:: - OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] - - (Contrast with example for L{CaselessKeyword}.) - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - raise ParseException(instring, loc, self.errmsg, self) - -class CaselessKeyword(Keyword): - """ - Caseless version of L{Keyword}. - - Example:: - OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] - - (Contrast with example for L{CaselessLiteral}.) - """ - def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - -class Word(Token): - """ - Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. An optional - C{excludeChars} parameter can list characters that might be found in - the input C{bodyChars} string; useful to define a word of all printables - except for one or two characters, for instance. - - L{srange} is useful for defining custom character set strings for defining - C{Word} expressions, using range notation from regular expression character sets. - - A common mistake is to use C{Word} to match a specific literal string, as in - C{Word("Address")}. Remember that C{Word} uses the string argument to define - I{sets} of matchable characters. This expression would match "Add", "AAA", - "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. - To match an exact literal string, use L{Literal} or L{Keyword}. - - pyparsing includes helper strings for building Words: - - L{alphas} - - L{nums} - - L{alphanums} - - L{hexnums} - - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) - - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) - - L{printables} (any non-whitespace character) - - Example:: - # a word composed of digits - integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - - # a word with a leading capital, and zero or more lowercase - capital_word = Word(alphas.upper(), alphas.lower()) - - # hostnames are alphanumeric, with leading alpha, and '-' - hostname = Word(alphas, alphanums+'-') - - # roman numeral (not a strict parser, accepts invalid mix of characters) - roman = Word("IVXLCDM") - - # any string of non-whitespace characters, except for ',' - csv_value = Word(printables, excludeChars=",") - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): - super(Word,self).__init__() - if excludeChars: - initChars = ''.join(c for c in initChars if c not in excludeChars) - if bodyChars: - bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) - self.initCharsOrig = initChars - self.initChars = set(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.initCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc, result.group() - - if not(instring[ loc ] in self.initChars): - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - """ - Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - - Example:: - realnum = Regex(r"[+-]?\d+\.\d*") - ssn = Regex(r"\d\d\d-\d\d-\d\d\d\d") - # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression - roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if not pattern: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - r""" - Token for matching strings that are delimited by quoting characters. - - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=C{None}) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) - - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) - - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) - - Example:: - qs = QuotedString('"') - print(qs.searchString('lsjdf "This is the quote" sldjf')) - complex_qs = QuotedString('{{', endQuoteChar='}}') - print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) - sql_qs = QuotedString('"', escQuote='""') - print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) - prints:: - [['This is the quote']] - [['This is the "quote"']] - [['This is the quote with "embedded" quotes']] - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if not quoteChar: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if not endQuoteChar: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - self.convertWhitespaceEscapes = convertWhitespaceEscapes - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped whitespace - if '\\' in ret and self.convertWhitespaceEscapes: - ws_map = { - r'\t' : '\t', - r'\n' : '\n', - r'\f' : '\f', - r'\r' : '\r', - } - for wslit,wschar in ws_map.items(): - ret = ret.replace(wslit, wschar) - - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern,"\g<1>",ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """ - Token for matching words composed of characters *not* in a given set (will - include whitespace in matched characters if not listed in the provided exclusion set - see example). - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - - Example:: - # define a comma-separated-value as anything that is not a ',' - csv_value = CharsNotIn(',') - print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) - prints:: - ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """ - Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{L{Word}} class. - """ - whiteStrs = { - " " : "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) - #~ self.leaveWhitespace() - self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - raise ParseException(instring, loc, self.errmsg, self) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """ - Token to advance to a specific column of input text; useful for tabular report scraping. - """ - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - -class LineStart(_PositionToken): - """ - Matches if current position is at the beginning of a line within the parse string - """ - def __init__( self ): - super(LineStart,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected start of line" - - def preParse( self, instring, loc ): - preloc = super(LineStart,self).preParse(instring,loc) - if instring[preloc] == "\n": - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - if not( loc==0 or - (loc == self.preParse( instring, 0 )) or - (instring[loc-1] == "\n") ): #col(loc, instring) != 1: - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class LineEnd(_PositionToken): - """ - Matches if current position is at the end of a line within the parse string - """ - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): - return loc, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - -class WordStart(_PositionToken): - """ - Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class WordEnd(_PositionToken): - """ - Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - # save match among all matches, to retry longest to shortest - matches.append((loc2, e)) - - if matches: - matches.sort(key=lambda x: -x[0]) - for _,e in matches: - try: - return e._parse( instring, loc, doActions ) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """ - Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the C{'|'} operator. - - Example:: - # construct MatchFirst using '|' operator - - # watch the order of expressions to match - number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) - print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] - - # put more selective expression first - number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) - print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException as err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """ - Requires all given C{ParseExpression}s to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the C{'&'} operator. - - Example:: - color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") - shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") - integer = Word(nums) - shape_attr = "shape:" + shape_type("shape") - posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") - color_attr = "color:" + color("color") - size_attr = "size:" + integer("size") - - # use Each (using operator '&') to accept attributes in any order - # (shape and posn are required, color and size are optional) - shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) - - shape_spec.runTests(''' - shape: SQUARE color: BLACK posn: 100, 120 - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - color:GREEN size:20 shape:TRIANGLE posn:20,40 - ''' - ) - prints:: - shape: SQUARE color: BLACK posn: 100, 120 - ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - - color: BLACK - - posn: ['100', ',', '120'] - - x: 100 - - y: 120 - - shape: SQUARE - - - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - - color: BLUE - - posn: ['50', ',', '80'] - - x: 50 - - y: 80 - - shape: CIRCLE - - size: 50 - - - color: GREEN size: 20 shape: TRIANGLE posn: 20,40 - ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - - color: GREEN - - posn: ['20', ',', '40'] - - x: 20 - - y: 40 - - shape: TRIANGLE - - size: 20 - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(self.opt1map.get(id(e),e)) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join(_ustr(e) for e in tmpReqd) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = ParseResults() - for r in resultlist: - dups = {} - for k in r.keys(): - if k in finalResults: - tmp = ParseResults(finalResults[k]) - tmp += ParseResults(r[k]) - dups[k] = tmp - finalResults += ParseResults(r) - for k,v in dups.items(): - finalResults[k] = v - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """ - Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. - """ - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - expr = ParserElement._literalStringClass(expr) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """ - Lookahead matching of the given parse expression. C{FollowedBy} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list. - - Example:: - # use FollowedBy to match a label only if it is followed by a ':' - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() - prints:: - [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] - """ - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """ - Lookahead to disallow matching with the given parse expression. C{NotAny} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression does *not* match at the current - position. Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator. - - Example:: - - """ - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr.canParseNext(instring, loc): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - - -class OneOrMore(ParseElementEnhance): - """ - Repetition of one or more of the given expression. - - Parameters: - - expr - expression that must match one or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: BLACK" - OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] - - # use stopOn attribute for OneOrMore to avoid reading label string as part of the data - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - - # could also be written as - (attr_expr * (1,)).parseString(text).pprint() - """ - def __init__( self, expr, stopOn=None): - super(OneOrMore, self).__init__(expr) - ender = stopOn - if isinstance(ender, basestring): - ender = ParserElement._literalStringClass(ender) - self.not_ender = ~ender if ender is not None else None - - def parseImpl( self, instring, loc, doActions=True ): - self_expr_parse = self.expr._parse - self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: - try_not_ender = self.not_ender.tryParse - - # must be at least one (but first see if we are the stopOn sentinel; - # if so, fail) - if check_ender: - try_not_ender(instring, loc) - loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = (not not self.ignoreExprs) - while 1: - if check_ender: - try_not_ender(instring, loc) - if hasIgnoreExprs: - preloc = self_skip_ignorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self_expr_parse( instring, preloc, doActions ) - if tmptokens or tmptokens.haskeys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(OneOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - -class ZeroOrMore(OneOrMore): - """ - Optional repetition of zero or more of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example: similar to L{OneOrMore} - """ - def __init__( self, expr, stopOn=None): - super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) - except (ParseException,IndexError): - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """ - Optional matching of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - default (optional) - value to be returned if the optional expression is not found. - - Example:: - # US postal code can be a 5-digit zip, plus optional 4-digit qualifier - zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) - zip.runTests(''' - # traditional ZIP code - 12345 - - # ZIP+4 form - 12101-0001 - - # invalid ZIP - 98765- - ''') - prints:: - # traditional ZIP code - 12345 - ['12345'] - - # ZIP+4 form - 12101-0001 - ['12101-0001'] - - # invalid ZIP - 98765- - ^ - FAIL: Expected end of text (at char 5), (line:1, col:6) - """ - def __init__( self, expr, default=_optionalNotMatched ): - super(Optional,self).__init__( expr, savelist=False ) - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - -class SkipTo(ParseElementEnhance): - """ - Token for skipping over all undefined text until the matched expression is found. - - Parameters: - - expr - target expression marking the end of the data to be skipped - - include - (default=C{False}) if True, the target expression is also parsed - (the skipped text and target expression are returned as a 2-element list). - - ignore - (default=C{None}) used to define grammars (typically quoted strings and - comments) that might contain false matches to the target expression - - failOn - (default=C{None}) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, - the SkipTo is not a match - - Example:: - report = ''' - Outstanding Issues Report - 1 Jan 2000 - - # | Severity | Description | Days Open - -----+----------+-------------------------------------------+----------- - 101 | Critical | Intermittent system crash | 6 - 94 | Cosmetic | Spelling error on Login ('log|n') | 14 - 79 | Minor | System slow when running too many reports | 47 - ''' - integer = Word(nums) - SEP = Suppress('|') - # use SkipTo to simply match everything up until the next SEP - # - ignore quoted strings, so that a '|' character inside a quoted string does not match - # - parse action will call token.strip() for each matched token, i.e., the description body - string_data = SkipTo(SEP, ignore=quotedString) - string_data.setParseAction(tokenMap(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP - + integer("days_open")) - - for tkt in ticket_expr.searchString(report): - print tkt.dump() - prints:: - ['101', 'Critical', 'Intermittent system crash', '6'] - - days_open: 6 - - desc: Intermittent system crash - - issue_num: 101 - - sev: Critical - ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - - days_open: 14 - - desc: Spelling error on Login ('log|n') - - issue_num: 94 - - sev: Cosmetic - ['79', 'Minor', 'System slow when running too many reports', '47'] - - days_open: 47 - - desc: System slow when running too many reports - - issue_num: 79 - - sev: Minor - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if isinstance(failOn, basestring): - self.failOn = ParserElement._literalStringClass(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - startloc = loc - instrlen = len(instring) - expr = self.expr - expr_parse = self.expr._parse - self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None - self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - - tmploc = loc - while tmploc <= instrlen: - if self_failOn_canParseNext is not None: - # break if failOn expression matches - if self_failOn_canParseNext(instring, tmploc): - break - - if self_ignoreExpr_tryParse is not None: - # advance past ignore expressions - while 1: - try: - tmploc = self_ignoreExpr_tryParse(instring, tmploc) - except ParseBaseException: - break - - try: - expr_parse(instring, tmploc, doActions=False, callPreParse=False) - except (ParseException, IndexError): - # no match, advance loc in string - tmploc += 1 - else: - # matched skipto expr, done - break - - else: - # ran off the end of the input string without matching skipto expr, fail - raise ParseException(instring, loc, self.errmsg, self) - - # build up return values - loc = tmploc - skiptext = instring[startloc:loc] - skipresult = ParseResults(skiptext) - - if self.includeMatch: - loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) - skipresult += mat - - return loc, skipresult - -class Forward(ParseElementEnhance): - """ - Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - Converting to use the '<<=' operator instead will avoid this problem. - - See L{ParseResults.pprint} for an example of a recursive parser created using - C{Forward}. - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass(other) - self.expr = other - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return self - - def __ilshift__(self, other): - return self << other - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - return self.__class__.__name__ + ": ..." - - # stubbed out for now - creates awful memory and perf issues - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret <<= self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """ - Abstract subclass of C{ParseExpression}, for converting parsed results. - """ - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Combine(TokenConverter): - """ - Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - - Example:: - real = Word(nums) + '.' + Word(nums) - print(real.parseString('3.1416')) # -> ['3', '.', '1416'] - # will also erroneously match the following - print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] - - real = Combine(Word(nums) + '.' + Word(nums)) - print(real.parseString('3.1416')) # -> ['3.1416'] - # no match when there are internal spaces - print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and retToks.haskeys(): - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """ - Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. - - Example:: - ident = Word(alphas) - num = Word(nums) - term = ident | num - func = ident + Optional(delimitedList(term)) - print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] - - func = ident + Group(Optional(delimitedList(term))) - print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] - """ - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """ - Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - # print attributes as plain groups - print(OneOrMore(attr_expr).parseString(text).dump()) - - # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names - result = Dict(OneOrMore(Group(attr_expr))).parseString(text) - print(result.dump()) - - # access named fields as dict entries, or output as dict - print(result['shape']) - print(result.asDict()) - prints:: - ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} - See more examples at L{ParseResults} of accessing fields by results name. - """ - def __init__( self, expr ): - super(Dict,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """ - Converter for ignoring the results of a parsed expression. - - Example:: - source = "a, b, c,d" - wd = Word(alphas) - wd_list1 = wd + ZeroOrMore(',' + wd) - print(wd_list1.parseString(source)) - - # often, delimiters that are useful during parsing are just in the - # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) - print(wd_list2.parseString(source)) - prints:: - ['a', ',', 'b', ',', 'c', ',', 'd'] - ['a', 'b', 'c', 'd'] - (See also L{delimitedList}.) - """ - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """ - Wrapper for parse actions, to ensure they are only called once. - """ - def __init__(self, methodCall): - self.callable = _trim_arity(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """ - Decorator for debugging parse actions. - - Example:: - wd = Word(alphas) - - @traceParseAction - def remove_duplicate_chars(tokens): - return ''.join(sorted(set(''.join(tokens))) - - wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) - print(wds.parseString("slkdjs sld sldd sdlf sdljf")) - prints:: - >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) - <3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write( "< ['aa', 'bb', 'cc'] - delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] - """ - dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." - if combine: - return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) - else: - return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) - -def countedArray( expr, intExpr=None ): - """ - Helper to define a counted list of expressions. - This helper defines a pattern of the form:: - integer expr expr expr... - where the leading integer tells how many expr expressions follow. - The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. - - Example:: - countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] - """ - arrayExpr = Forward() - def countFieldParseAction(s,l,t): - n = t[0] - arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) - return [] - if intExpr is None: - intExpr = Word(nums).setParseAction(lambda t:int(t[0])) - else: - intExpr = intExpr.copy() - intExpr.setName("arrayLen") - intExpr.addParseAction(countFieldParseAction, callDuringTry=True) - return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') - -def _flatten(L): - ret = [] - for i in L: - if isinstance(i,list): - ret.extend(_flatten(i)) - else: - ret.append(i) - return ret - -def matchPreviousLiteral(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousLiteral(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches a - previous literal, will also match the leading C{"1:1"} in C{"1:10"}. - If this is not desired, use C{matchPreviousExpr}. - Do *not* use with packrat parsing enabled. - """ - rep = Forward() - def copyTokenToRepeater(s,l,t): - if t: - if len(t) == 1: - rep << t[0] - else: - # flatten t tokens - tflat = _flatten(t.asList()) - rep << And(Literal(tt) for tt in tflat) - else: - rep << Empty() - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def matchPreviousExpr(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousExpr(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches by - expressions, will *not* match the leading C{"1:1"} in C{"1:10"}; - the expressions are evaluated first, and then compared, so - C{"1"} is compared with C{"10"}. - Do *not* use with packrat parsing enabled. - """ - rep = Forward() - e2 = expr.copy() - rep <<= e2 - def copyTokenToRepeater(s,l,t): - matchTokens = _flatten(t.asList()) - def mustMatchTheseTokens(s,l,t): - theseTokens = _flatten(t.asList()) - if theseTokens != matchTokens: - raise ParseException("",0,"") - rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def _escapeRegexRangeChars(s): - #~ escape these chars: ^-] - for c in r"\^-]": - s = s.replace(c,_bslash+c) - s = s.replace("\n",r"\n") - s = s.replace("\t",r"\t") - return _ustr(s) - -def oneOf( strs, caseless=False, useRegex=True ): - """ - Helper to quickly define a set of alternative Literals, and makes sure to do - longest-first testing when there is a conflict, regardless of the input order, - but returns a C{L{MatchFirst}} for best performance. - - Parameters: - - strs - a string of space-delimited literals, or a list of string literals - - caseless - (default=C{False}) - treat all literals as caseless - - useRegex - (default=C{True}) - as an optimization, will generate a Regex - object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or - if creating a C{Regex} raises an exception) - - Example:: - comp_oper = oneOf("< = > <= >= !=") - var = Word(alphas) - number = Word(nums) - term = var | number - comparison_expr = term + comp_oper + term - print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) - prints:: - [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] - """ - if caseless: - isequal = ( lambda a,b: a.upper() == b.upper() ) - masks = ( lambda a,b: b.upper().startswith(a.upper()) ) - parseElementClass = CaselessLiteral - else: - isequal = ( lambda a,b: a == b ) - masks = ( lambda a,b: b.startswith(a) ) - parseElementClass = Literal - - symbols = [] - if isinstance(strs,basestring): - symbols = strs.split() - elif isinstance(strs, collections.Sequence): - symbols = list(strs[:]) - elif isinstance(strs, _generatorType): - symbols = list(strs) - else: - warnings.warn("Invalid argument to oneOf, expected string or list", - SyntaxWarning, stacklevel=2) - if not symbols: - return NoMatch() - - i = 0 - while i < len(symbols)-1: - cur = symbols[i] - for j,other in enumerate(symbols[i+1:]): - if ( isequal(other, cur) ): - del symbols[i+j+1] - break - elif ( masks(cur, other) ): - del symbols[i+j+1] - symbols.insert(i,other) - cur = other - break - else: - i += 1 - - if not caseless and useRegex: - #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) - else: - return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) - except: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) - -def dictOf( key, value ): - """ - Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - - Example:: - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - print(OneOrMore(attr_expr).parseString(text).dump()) - - attr_label = label - attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) - - # similar to Dict, but simpler call format - result = dictOf(attr_label, attr_value).parseString(text) - print(result.dump()) - print(result['shape']) - print(result.shape) # object attribute access works too - print(result.asDict()) - prints:: - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - SQUARE - {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """ - Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. By default, returns astring containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{L{ParseResults}} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{L{originalTextFor}} contains expressions with defined - results names, you must set C{asString} to C{False} if you want to preserve those - results name values. - - Example:: - src = "this is test bold text normal text " - for tag in ("b","i"): - opener,closer = makeHTMLTags(tag) - patt = originalTextFor(opener + SkipTo(closer) + closer) - print(patt.searchString(src)[0]) - prints:: - [' bold text '] - ['text'] - """ - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] - matchExpr.setParseAction(extractText) - matchExpr.ignoreExprs = expr.ignoreExprs - return matchExpr - -def ungroup(expr): - """ - Helper to undo pyparsing's default grouping of And expressions, even - if all but one are non-empty. - """ - return TokenConverter(expr).setParseAction(lambda t:t[0]) - -def locatedExpr(expr): - """ - Helper to decorate a returned token with its starting and ending locations in the input string. - This helper adds the following results names: - - locn_start = location where matched expression begins - - locn_end = location where matched expression ends - - value = the actual parsed results - - Be careful if the input text contains C{} characters, you may want to call - C{L{ParserElement.parseWithTabs}} - - Example:: - wd = Word(alphas) - for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): - print(match) - prints:: - [[0, 'ljsdf', 5]] - [[8, 'lksdjjf', 15]] - [[18, 'lkkjj', 23]] - """ - locator = Empty().setParseAction(lambda s,l,t: l) - return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) - - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(printables, excludeChars=r'\]', exact=1) | Regex(r"\w", re.UNICODE) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -def srange(s): - r""" - Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be: - - a single character - - an escaped character with a leading backslash (such as C{\-} or C{\]}) - - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) - (C{\0x##} is also supported for backwards compatibility) - - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) - - a range of any of the above, separated by a dash (C{'a-z'}, etc.) - - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) - """ - _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) - try: - return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) - except: - return "" - -def matchOnlyAtCol(n): - """ - Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """ - Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{L{transformString}()}. - - Example:: - num = Word(nums).setParseAction(lambda toks: int(toks[0])) - na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) - term = na | num - - OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] - """ - return lambda s,l,t: [replStr] - -def removeQuotes(s,l,t): - """ - Helper parse action for removing quotation marks from parsed quoted strings. - - Example:: - # by default, quotation marks are included in parsed results - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] - - # use removeQuotes to strip quotation marks from parsed results - quotedString.setParseAction(removeQuotes) - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] - """ - return t[0][1:-1] - -def tokenMap(func, *args): - """ - Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional - args are passed, they are forwarded to the given function as additional arguments after - the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the - parsed data to an integer using base 16. - - Example (compare the last to example in L{ParserElement.transformString}:: - hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) - hex_ints.runTests(''' - 00 11 22 aa FF 0a 0d 1a - ''') - - upperword = Word(alphas).setParseAction(tokenMap(str.upper)) - OneOrMore(upperword).runTests(''' - my kingdom for a horse - ''') - - wd = Word(alphas).setParseAction(tokenMap(str.title)) - OneOrMore(wd).setParseAction(' '.join).runTests(''' - now is the winter of our discontent made glorious summer by this sun of york - ''') - prints:: - 00 11 22 aa FF 0a 0d 1a - [0, 17, 34, 170, 255, 10, 13, 26] - - my kingdom for a horse - ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] - - now is the winter of our discontent made glorious summer by this sun of york - ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] - """ - def pa(s,l,t): - return [func(tokn, *args) for tokn in t] - - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - pa.__name__ = func_name - - return pa - -upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) -"""Helper parse action to convert tokens to upper case.""" - -downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) -"""Helper parse action to convert tokens to lower case.""" - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join(c for c in printables if c not in ">") - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % resname) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches - tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. - - Example:: - text = 'More info at the pyparsing wiki page' - # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple - a,a_end = makeHTMLTags("A") - link_expr = a + SkipTo(a_end)("link_text") + a_end - - for link in link_expr.searchString(text): - # attributes in the tag (like "href" shown here) are also accessible as named results - print(link.link_text, '->', link.href) - prints:: - pyparsing -> http://pyparsing.wikispaces.com - """ - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for XML, given a tag name. Matches - tags only in the given upper/lower case. - - Example: similar to L{makeHTMLTags} - """ - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """ - Helper to create a validating parse action to be used with start tags created - with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - C{} or C{
}. - - Call C{withAttribute} with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in C{(align="right")}, or - - as an explicit dict with C{**} operator, when an attribute name is also a Python - reserved word, as in C{**{"class":"Customer", "align":"right"}} - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - If just testing for C{class} (with or without a namespace), use C{L{withClass}}. - - To verify that the attribute exists, but without specifying a value, pass - C{withAttribute.ANY_VALUE} as the value. - - Example:: - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this has no type
-
- - ''' - div,div_end = makeHTMLTags("div") - - # only match div tag having a type attribute with value "grid" - div_grid = div().setParseAction(withAttribute(type="grid")) - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - # construct a match with any div tag having a type attribute, regardless of the value - div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -def withClass(classname, namespace=''): - """ - Simplified version of C{L{withAttribute}} when matching on a div class - made - difficult because C{class} is a reserved word in Python. - - Example:: - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this <div> has no class
-
- - ''' - div,div_end = makeHTMLTags("div") - div_grid = div().setParseAction(withClass("grid")) - - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - classattr = "%s:class" % namespace if namespace else "class" - return withAttribute(**{classattr : classname}) - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): - """ - Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; 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; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted) - - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) - - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) - - Example:: - # simple example of four-function arithmetic with ints and variable names - integer = pyparsing_common.signedInteger - varname = pyparsing_common.identifier - - arith_expr = infixNotation(integer | varname, - [ - ('-', 1, opAssoc.RIGHT), - (oneOf('* /'), 2, opAssoc.LEFT), - (oneOf('+ -'), 2, opAssoc.LEFT), - ]) - - arith_expr.runTests(''' - 5+3*6 - (5+3)*6 - -2--11 - ''', fullDump=False) - prints:: - 5+3*6 - [[5, '+', [3, '*', 6]]] - - (5+3)*6 - [[[5, '+', 3], '*', 6]] - - -2--11 - [[['-', 2], '-', ['-', 11]]] - """ - ret = Forward() - lastExpr = baseExpr | ( lpar + ret + rpar ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward().setName(termName) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - matchExpr.setParseAction( pa ) - thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) - lastExpr = thisExpr - ret <<= lastExpr - return ret - -operatorPrecedence = infixNotation -"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" - -dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") -sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") -quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """ - Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression - - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression - - content - expression for items within the nested lists (default=C{None}) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the C{ignoreExpr} argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. - The default is L{quotedString}, but if no expressions are to be ignored, - then pass C{None} for this argument. - - Example:: - data_type = oneOf("void int short long char float double") - decl_data_type = Combine(data_type + Optional(Word('*'))) - ident = Word(alphas+'_', alphanums+'_') - number = pyparsing_common.number - arg = Group(decl_data_type + ident) - LPAR,RPAR = map(Suppress, "()") - - code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) - - c_function = (decl_data_type("type") - + ident("name") - + LPAR + Optional(delimitedList(arg), [])("args") + RPAR - + code_body("body")) - c_function.ignore(cStyleComment) - - source_code = ''' - int is_odd(int x) { - return (x%2); - } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { - return (10+ord(hchar)-ord('A')); - } - } - ''' - for func in c_function.searchString(source_code): - print("%(name)s (%(type)s) args: %(args)s" % func) - - prints:: - is_odd (int) args: [['int', 'x']] - dec_to_hex (int) args: [['char', 'hchar']] - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - ret.setName('nested %s%s expression' % (opener,closer)) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """ - Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=C{True}) - - A valid block must contain at least one C{blockStatement}. - - Example:: - data = ''' - def A(z): - A1 - B = 100 - G = A2 - A2 - A3 - B - def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 - C - D - def spam(x,y): - def eggs(z): - pass - ''' - - - indentStack = [1] - stmt = Forward() - - identifier = Word(alphas, alphanums) - funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") - func_body = indentedBlock(stmt, indentStack) - funcDef = Group( funcDecl + func_body ) - - rvalue = Forward() - funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") - rvalue << (funcCall | identifier | Word(nums)) - assignment = Group(identifier + "=" + rvalue) - stmt << ( funcDef | assignment | identifier ) - - module_body = OneOrMore(stmt) - - parseTree = module_body.parseString(data) - parseTree.pprint() - prints:: - [['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']]]]]]] - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if 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(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') - PEER = Empty().setParseAction(checkPeerIndent).setName('') - UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr.setName('indented block') - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) -_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) -commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") -def replaceHTMLEntity(t): - """Helper parser action to replace common HTML entities with their special characters""" - return _htmlEntityMap.get(t.entity) - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") -"Comment of the form C{/* ... */}" - -htmlComment = Regex(r"").setName("HTML comment") -"Comment of the form C{}" - -restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") -dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") -"Comment of the form C{// ... (to end of line)}" - -cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") -"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" - -javaStyleComment = cppStyleComment -"Same as C{L{cppStyleComment}}" - -pythonStyleComment = Regex(r"#.*").setName("Python style comment") -"Comment of the form C{# ... (to end of line)}" - -_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + - Optional( Word(" \t") + - ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") -commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") -"""Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" - -# some other useful expressions - using lower-case class name since we are really using this as a namespace -class pyparsing_common: - """ - Here are some common low-level expressions that may be useful in jump-starting parser development: - - numeric forms (L{integers}, L{reals}, L{scientific notation}) - - common L{programming identifiers} - - network addresses (L{MAC}, L{IPv4}, L{IPv6}) - - ISO8601 L{dates} and L{datetime} - - L{UUID} - Parse actions: - - C{L{convertToInteger}} - - C{L{convertToFloat}} - - C{L{convertToDate}} - - C{L{convertToDatetime}} - - C{L{stripHTMLTags}} - - Example:: - pyparsing_common.number.runTests(''' - # any int or real number, returned as the appropriate type - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.fnumber.runTests(''' - # any int or real number, returned as float - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.hex_integer.runTests(''' - # hex numbers - 100 - FF - ''') - - pyparsing_common.fraction.runTests(''' - # fractions - 1/2 - -3/4 - ''') - - pyparsing_common.mixed_integer.runTests(''' - # mixed fractions - 1 - 1/2 - -3/4 - 1-3/4 - ''') - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(''' - # uuid - 12345678-1234-5678-1234-567812345678 - ''') - prints:: - # any int or real number, returned as the appropriate type - 100 - [100] - - -100 - [-100] - - +100 - [100] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # any int or real number, returned as float - 100 - [100.0] - - -100 - [-100.0] - - +100 - [100.0] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # hex numbers - 100 - [256] - - FF - [255] - - # fractions - 1/2 - [0.5] - - -3/4 - [-0.75] - - # mixed fractions - 1 - [1] - - 1/2 - [0.5] - - -3/4 - [-0.75] - - 1-3/4 - [1.75] - - # uuid - 12345678-1234-5678-1234-567812345678 - [UUID('12345678-1234-5678-1234-567812345678')] - """ - - convertToInteger = tokenMap(int) - """ - Parse action for converting parsed integers to Python int - """ - - convertToFloat = tokenMap(float) - """ - Parse action for converting parsed numbers to Python float - """ - - integer = Word(nums).setName("integer").setParseAction(convertToInteger) - """expression that parses an unsigned integer, returns an int""" - - hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) - """expression that parses a hexadecimal integer, returns an int""" - - signedInteger = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) - """expression that parses an integer with optional leading sign, returns an int""" - - fraction = (signedInteger().setParseAction(convertToFloat) + '/' + signedInteger().setParseAction(convertToFloat)).setName("fraction") - """fractional expression of an integer divided by an integer, returns a float""" - fraction.addParseAction(lambda t: t[0]/t[-1]) - - mixed_integer = (fraction | signedInteger + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") - """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" - mixed_integer.addParseAction(sum) - - real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) - """expression that parses a floating point number and returns a float""" - - sciReal = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) - """expression that parses a floating point number with optional scientific notation and returns a float""" - - # streamlining this expression makes the docs nicer-looking - number = (sciReal | real | signedInteger).streamline() - """any numeric expression, returns the corresponding Python type""" - - fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) - """any int or real number, returned as float""" - - identifier = Word(alphas+'_', alphanums+'_').setName("identifier") - """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") - "IPv4 address (C{0.0.0.0 - 255.255.255.255})" - - _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") - _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") - _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") - _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) - _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") - ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") - "IPv6 address (long, short, or mixed form)" - - mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") - "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" - - @staticmethod - def convertToDate(fmt="%Y-%m-%d"): - """ - Helper to create a parse action for converting parsed date string to Python datetime.date - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) - - Example:: - date_expr = pyparsing_common.iso8601_date.copy() - date_expr.setParseAction(pyparsing_common.convertToDate()) - print(date_expr.parseString("1999-12-31")) - prints:: - [datetime.date(1999, 12, 31)] - """ - return lambda s,l,t: datetime.strptime(t[0], fmt).date() - - @staticmethod - def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): - """ - Helper to create a parse action for converting parsed datetime string to Python datetime.datetime - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) - - Example:: - dt_expr = pyparsing_common.iso8601_datetime.copy() - dt_expr.setParseAction(pyparsing_common.convertToDatetime()) - print(dt_expr.parseString("1999-12-31T23:59:59.999")) - prints:: - [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] - """ - return lambda s,l,t: datetime.strptime(t[0], fmt) - - iso8601_date = Regex(r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?').setName("ISO8601 date") - "ISO8601 date (C{yyyy-mm-dd})" - - iso8601_datetime = Regex(r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") - "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" - - uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") - "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" - - _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() - @staticmethod - def stripHTMLTags(s, l, tokens): - """ - Parse action to remove HTML tags from web page HTML source - - Example:: - # strip HTML links from normal text - text = 'More info at the
pyparsing wiki page' - td,td_end = makeHTMLTags("TD") - table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - - print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' - """ - return pyparsing_common._html_stripper.transformString(tokens[0]) - -if __name__ == "__main__": - - selectToken = CaselessLiteral("select") - fromToken = CaselessLiteral("from") - - ident = Word(alphas, alphanums + "_$") - - columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - columnNameList = Group(delimitedList(columnName)).setName("columns") - columnSpec = ('*' | columnNameList) - - tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - tableNameList = Group(delimitedList(tableName)).setName("tables") - - simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") - - # demo runTests method, including embedded comments in test string - simpleSQL.runTests(""" - # '*' as column list and dotted table name - select * from SYS.XYZZY - - # caseless match on "SELECT", and casts back to "select" - SELECT * from XYZZY, ABC - - # list of column names, and mixed case SELECT keyword - Select AA,BB,CC from Sys.dual - - # multiple tables - Select A, B, C from Sys.dual, Table2 - - # invalid SELECT keyword - should fail - Xelect A, B, C from Sys.dual - - # incomplete command - should fail - Select - - # invalid column name - should fail - Select ^^^ frox Sys.dual - - """) - - pyparsing_common.number.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - # any int or real number, returned as float - pyparsing_common.fnumber.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - pyparsing_common.hex_integer.runTests(""" - 100 - FF - """) - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(""" - 12345678-1234-5678-1234-567812345678 - """) diff --git a/trunk/src/pyparsingClassDiagram.JPG b/trunk/src/pyparsingClassDiagram.JPG deleted file mode 100644 index ef10424..0000000 Binary files a/trunk/src/pyparsingClassDiagram.JPG and /dev/null differ diff --git a/trunk/src/pyparsingClassDiagram.PNG b/trunk/src/pyparsingClassDiagram.PNG deleted file mode 100644 index f59baaf..0000000 Binary files a/trunk/src/pyparsingClassDiagram.PNG and /dev/null differ diff --git a/trunk/src/setup.cfg b/trunk/src/setup.cfg deleted file mode 100644 index 981e089..0000000 --- a/trunk/src/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[bdist_wheel] -universal = 1 - -[wheel] -universal = 1 diff --git a/trunk/src/setup.py b/trunk/src/setup.py deleted file mode 100644 index 82061c6..0000000 --- a/trunk/src/setup.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -"""Setup script for the pyparsing module distribution.""" -from setuptools import setup - -import sys -import os - -from pyparsing import __version__ as pyparsing_version - -modules = ["pyparsing",] - -setup(# Distribution meta-data - name = "pyparsing", - version = pyparsing_version, - description = "Python parsing module", - author = "Paul McGuire", - author_email = "ptmcg@users.sourceforge.net", - url = "http://pyparsing.wikispaces.com/", - download_url = "http://sourceforge.net/project/showfiles.php?group_id=97203", - license = "MIT License", - py_modules = modules, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - ] - ) diff --git a/trunk/src/test/__init__.py b/trunk/src/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/trunk/src/test/jsonParserTests.py b/trunk/src/test/jsonParserTests.py deleted file mode 100644 index c8a42bb..0000000 --- a/trunk/src/test/jsonParserTests.py +++ /dev/null @@ -1,360 +0,0 @@ -# jsonParser.py -# -# Copyright (c) 2006, Paul McGuire -# - -test1 = """ -{ - "glossary": { - "title": "example glossary", - "GlossDiv": { - "title": "S", - "GlossList": [{ - "ID": "SGML", - "SortAs": "SGML", - "GlossTerm": "Standard Generalized Markup Language", - "Acronym": "SGML", - "LargestPrimeLessThan100": 97, - "AvogadroNumber": 6.02E23, - "EvenPrimesGreaterThan2": null, - "PrimesLessThan10" : [2,3,5,7], - "WMDsFound" : false, - "IraqAlQaedaConnections" : null, - "Abbrev": "ISO 8879:1986", - "GlossDef": -"A meta-markup language, used to create markup languages such as DocBook.", - "GlossSeeAlso": ["GML", "XML", "markup"], - "EmptyDict" : {}, - "EmptyList" : [] - }] - } - } -} -""" - -test2 = """ -{"menu": { - "id": "file", - "value": "File:", - "popup": { - "menuitem": [ - {"value": "New", "onclick": "CreateNewDoc()"}, - {"value": "Open", "onclick": "OpenDoc()"}, - {"value": "Close", "onclick": "CloseDoc()"} - ] - } -}} -""" -test3 = """ -{"widget": { - "debug": "on", - "window": { - "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 - }, "image": { - "src": "Images/Sun.png", - "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center" - }, "text": { - "data": "Click Here", - "size": 36, - "style": "bold", "name": "text1", "hOffset": 250, "vOffset": 100, "alignment": "center", - "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" - } -}} -""" -test4 = """ -{"web-app": { - "servlet": [ // Defines the CDSServlet - { - "servlet-name": "cofaxCDS", - "servlet-class": "org.cofax.cds.CDSServlet", -/* - Defines glossary variables that template designers - can use across the site. You can add new - variables to this set by creating a new init-param, with - the param-name prefixed with "configGlossary:". -*/ - "init-param": { - "configGlossary:installationAt": "Philadelphia, PA", - "configGlossary:adminEmail": "ksm@pobox.com", - "configGlossary:poweredBy": "Cofax", - "configGlossary:poweredByIcon": "/images/cofax.gif", - "configGlossary:staticPath": "/content/static", -/* - Defines the template loader and template processor - classes. These are implementations of org.cofax.TemplateProcessor - and org.cofax.TemplateLoader respectively. Simply create new - implementation of these classes and set them here if the default - implementations do not suit your needs. Leave these alone - for the defaults. -*/ - "templateProcessorClass": "org.cofax.WysiwygTemplate", - "templateLoaderClass": "org.cofax.FilesTemplateLoader", - "templatePath": "templates", - "templateOverridePath": "", -/* - Defines the names of the default templates to look for - when acquiring WYSIWYG templates. Leave these at their - defaults for most usage. -*/ - "defaultListTemplate": "listTemplate.htm", - "defaultFileTemplate": "articleTemplate.htm", -/* - New! useJSP switches on JSP template processing. - jspListTemplate and jspFileTemplate are the names - of the default templates to look for when aquiring JSP - templates. Cofax currently in production at KR has useJSP - set to false, since our sites currently use WYSIWYG - templating exclusively. -*/ - "useJSP": false, - "jspListTemplate": "listTemplate.jsp", - "jspFileTemplate": "articleTemplate.jsp", -/* - Defines the packageTag cache. This cache keeps - Cofax from needing to interact with the database - to look up packageTag commands. -*/ - "cachePackageTagsTrack": 200, - "cachePackageTagsStore": 200, - "cachePackageTagsRefresh": 60, -/* - Defines the template cache. Keeps Cofax from needing - to go to the file system to load a raw template from - the file system. -*/ - "cacheTemplatesTrack": 100, - "cacheTemplatesStore": 50, - "cacheTemplatesRefresh": 15, -/* - Defines the page cache. Keeps Cofax from processing - templates to deliver to users. -*/ - "cachePagesTrack": 200, - "cachePagesStore": 100, - "cachePagesRefresh": 10, - "cachePagesDirtyRead": 10, -/* - Defines the templates Cofax will use when - being browsed by a search engine identified in - searchEngineRobotsDb -*/ - "searchEngineListTemplate": "forSearchEnginesList.htm", - "searchEngineFileTemplate": "forSearchEngines.htm", - "searchEngineRobotsDb": "WEB-INF/robots.db", -/* - New! useDataStore enables/disables the Cofax database pool -*/ - "useDataStore": true, -/* - Defines the implementation of org.cofax.DataStore that Cofax - will use. If this DataStore class does not suit your needs - simply implement a new DataStore class and set here. -*/ - "dataStoreClass": "org.cofax.SqlDataStore", -/* - Defines the implementation of org.cofax.Redirection that - Cofax will use. If this Redirection class does not suit - your needs simply implenet a new Redirection class - and set here. -*/ - "redirectionClass": "org.cofax.SqlRedirection", -/* - Defines the data store name. Keep this at the default -*/ - "dataStoreName": "cofax", -/* - Defines the JDBC driver that Cofax's database pool will use -*/ - "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", -/* - Defines the JDBC connection URL to connect to the database -*/ - "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", -/* - Defines the user name to connect to the database -*/ - "dataStoreUser": "sa", -/* - Defines the password to connect to the database -*/ - "dataStorePassword": "dataStoreTestQuery", -/* - A query that will run to test the validity of the - connection in the pool. -*/ - "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", -/* - A log file to print out database information -*/ - "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", -/* - The number of connection to initialize on startup -*/ - "dataStoreInitConns": 10, -/* - The maximum number of connection to use in the pool -*/ - "dataStoreMaxConns": 100, -/* - The number of times a connection will be utilized from the - pool before disconnect -*/ - "dataStoreConnUsageLimit": 100, -/* - The level of information to print to the log -*/ - "dataStoreLogLevel": "debug", -/* - The maximum URL length allowable by the CDS Servlet - Helps to prevent hacking -*/ - "maxUrlLength": 500}}, -/* - Defines the Email Servlet -*/ - { - "servlet-name": "cofaxEmail", - "servlet-class": "org.cofax.cds.EmailServlet", - "init-param": { -/* - The mail host to be used by the mail servlet -*/ - "mailHost": "mail1", -/* - An override -*/ - "mailHostOverride": "mail2"}}, -/* - Defines the Admin Servlet - used to refresh cache on - demand and see statistics -*/ - { - "servlet-name": "cofaxAdmin", - "servlet-class": "org.cofax.cds.AdminServlet"}, -/* - Defines the File Servlet - used to display files like Apache -*/ - { - "servlet-name": "fileServlet", - "servlet-class": "org.cofax.cds.FileServlet"}, - { - "servlet-name": "cofaxTools", - "servlet-class": "org.cofax.cms.CofaxToolsServlet", - "init-param": { -/* - Path to the template folder relative to the tools tomcat installation. -*/ - "templatePath": "toolstemplates/", -/* - Logging boolean 1 = on, 0 = off -*/ - "log": 1, -/* - Location of log. If empty, log will be written System.out -*/ - "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", -/* - Max size of log in BITS. If size is empty, no limit to log. - If size is defined, log will be overwritten upon reaching defined size. -*/ - "logMaxSize": "", -/* - DataStore logging boolean 1 = on, 0 = off -*/ - "dataLog": 1, -/* - DataStore location of log. If empty, log will be written System.out -*/ - "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", -/* - Max size of log in BITS. If size is empty, no limit to log. - If size is defined, log will be overwritten upon reaching defined size. -*/ - "dataLogMaxSize": "", -/* - Http string relative to server root to call for page cache - removal to Cofax Servlet. -*/ - "removePageCache": "/content/admin/remove?cache=pages&id=", -/* - Http string relative to server root to call for template - cache removal to Cofax Servlet. -*/ - "removeTemplateCache": "/content/admin/remove?cache=templates&id=", -/* - Location of folder from root of drive that will be used for - ftp transfer from beta server or user hard drive to live servers. - Note that Edit Article will not function without this variable - set correctly. MultiPart request relies upon access to this folder. -*/ - "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", -/* - Defines whether the Server should look in another path for - config files or variables. -*/ - "lookInContext": 1, -/* - Number of the ID of the top level administration group in tblPermGroups. -*/ - "adminGroupID": 4, -/* - Is the tools app running on the 'beta server'. -*/ - "betaServer": true}}], - "servlet-mapping": { -/* - URL mapping for the CDS Servlet -*/ - "cofaxCDS": "/", -/* - URL mapping for the Email Servlet -*/ - "cofaxEmail": "/cofaxutil/aemail/*", -/* - URL mapping for the Admin servlet -*/ - "cofaxAdmin": "/admin/*", -/* - URL mapping for the Files servlet -*/ - "fileServlet": "/static/*", - "cofaxTools": "/tools/*"}, -/* - New! The cofax taglib descriptor file -*/ - "taglib": { - "taglib-uri": "cofax.tld", - "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} - -""" - -test5 = """ -{"menu": { - "header": "SVG Viewer", - "items": [ - {"id": "Open"}, - {"id": "OpenNew", "label": "Open New"}, - null, - {"id": "ZoomIn", "label": "Zoom In"}, - {"id": "ZoomOut", "label": "Zoom Out"}, - {"id": "OriginalView", "label": "Original View"}, - null, - {"id": "Quality"}, - {"id": "Pause"}, - {"id": "Mute"}, - null, - {"id": "Find", "label": "Find..."}, - {"id": "FindAgain", "label": "Find Again"}, - {"id": "Copy"}, - {"id": "CopyAgain", "label": "Copy Again"}, - {"id": "CopySVG", "label": "Copy SVG"}, - {"id": "ViewSVG", "label": "View SVG"}, - {"id": "ViewSource", "label": "View Source"}, - {"id": "SaveAs", "label": "Save As"}, - null, - {"id": "Help"}, - {"id": "About", "label": "About Adobe CVG Viewer..."} - ] -}} -""" - diff --git a/trunk/src/test/karthik.ini b/trunk/src/test/karthik.ini deleted file mode 100644 index 0a7f594..0000000 --- a/trunk/src/test/karthik.ini +++ /dev/null @@ -1,14 +0,0 @@ -[users] -source_dir = '/home/karthik/Projects/python' -data_dir = '/home/karthik/Projects/data' -result_dir = '/home/karthik/Projects/Results' -param_file = $result_dir/param_file -res_file = $result_dir/result_file -comment = 'this is a comment' -; a line starting with ';' is a comment -K = 8 -simulate_K = 0 -N = 4000 -mod_scheme = 'QPSK' - -Na = K+2 \ No newline at end of file diff --git a/trunk/src/test/parsefiletest_input_file.txt b/trunk/src/test/parsefiletest_input_file.txt deleted file mode 100644 index 022837a..0000000 --- a/trunk/src/test/parsefiletest_input_file.txt +++ /dev/null @@ -1 +0,0 @@ -123 456 789 \ No newline at end of file diff --git a/trunk/src/unitTests.py b/trunk/src/unitTests.py deleted file mode 100644 index a4c651f..0000000 --- a/trunk/src/unitTests.py +++ /dev/null @@ -1,3169 +0,0 @@ -# -*- coding: UTF-8 -*- -from unittest import TestCase, TestSuite, TextTestRunner -import unittest -import datetime - -from pyparsing import ParseException -#~ import HTMLTestRunner - -import sys -import pdb - -PY_3 = sys.version.startswith('3') -if PY_3: - import builtins - print_ = getattr(builtins, "print") - - from io import StringIO -else: - def _print(*args, **kwargs): - if 'end' in kwargs: - sys.stdout.write(' '.join(map(str,args)) + kwargs['end']) - else: - sys.stdout.write(' '.join(map(str,args)) + '\n') - print_ = _print - from cStringIO import StringIO - - -# see which Python implementation we are running -CPYTHON_ENV = (sys.platform == "win32") -IRON_PYTHON_ENV = (sys.platform == "cli") -JYTHON_ENV = sys.platform.startswith("java") - -TEST_USING_PACKRAT = True -#~ TEST_USING_PACKRAT = False - -VERBOSE = False -#~ VERBOSE = True - -# simple utility for flattening nested lists -def flatten(L): - if type(L) is not list: return [L] - if L == []: return L - return flatten(L[0]) + flatten(L[1:]) - -""" -class ParseTest(TestCase): - def setUp(self): - pass - - def runTest(self): - assert 1==1, "we've got bigger problems..." - - def tearDown(self): - pass -""" - -class ParseTestCase(TestCase): - def setUp(self): - print_(">>>> Starting test",str(self)) - - def runTest(self): - pass - - def tearDown(self): - print_("<<<< End of test",str(self)) - print_() - - def __str__(self): - return self.__class__.__name__ - -class PyparsingTestInit(ParseTestCase): - def setUp(self): - from pyparsing import __version__ as pyparsingVersion - print_("Beginning test of pyparsing, version", pyparsingVersion) - print_("Python version", sys.version) - def tearDown(self): - pass - -if 0: - class ParseASMLTest(ParseTestCase): - def runTest(self): - import parseASML - files = [ ("A52759.txt", 2150, True, True, 0.38, 25, "21:47:17", "22:07:32", 235), - ("24141506_P5107RM59_399A1457N1_PHS04", 373,True, True, 0.5, 1, "11:35:25", "11:37:05", 183), - ("24141506_P5107RM59_399A1457N1_PHS04B", 373, True, True, 0.5, 1, "01:02:54", "01:04:49", 186), - ("24157800_P5107RM74_399A1828M1_PHS04", 1141, True, False, 0.5, 13, "00:00:54", "23:59:48", 154) ] - for testFile,numToks,trkInpUsed,trkOutpUsed,maxDelta,numWafers,minProcBeg,maxProcEnd,maxLevStatsIV in files: - print_("Parsing",testFile,"...", end=' ') - #~ text = "\n".join( [ line for line in file(testFile) ] ) - #~ results = parseASML.BNF().parseString( text ) - results = parseASML.BNF().parseFile( testFile ) - #~ pprint.pprint( results.asList() ) - #~ pprint.pprint( results.batchData.asList() ) - #~ print results.batchData.keys() - - allToks = flatten( results.asList() ) - assert len(allToks) == numToks, \ - "wrong number of tokens parsed (%s), got %d, expected %d" % (testFile, len(allToks),numToks) - assert results.batchData.trackInputUsed == trkInpUsed, "error evaluating results.batchData.trackInputUsed" - assert results.batchData.trackOutputUsed == trkOutpUsed, "error evaluating results.batchData.trackOutputUsed" - assert results.batchData.maxDelta == maxDelta,"error evaluating results.batchData.maxDelta" - assert len(results.waferData) == numWafers, "did not read correct number of wafers" - assert min([wd.procBegin for wd in results.waferData]) == minProcBeg, "error reading waferData.procBegin" - assert max([results.waferData[k].procEnd for k in range(len(results.waferData))]) == maxProcEnd, "error reading waferData.procEnd" - assert sum(results.levelStatsIV['MAX']) == maxLevStatsIV, "error reading levelStatsIV" - assert sum(results.levelStatsIV.MAX) == maxLevStatsIV, "error reading levelStatsIV" - print_("OK") - print_(testFile,len(allToks)) - #~ print "results.batchData.trackInputUsed =",results.batchData.trackInputUsed - #~ print "results.batchData.trackOutputUsed =",results.batchData.trackOutputUsed - #~ print "results.batchData.maxDelta =",results.batchData.maxDelta - #~ print len(results.waferData)," wafers" - #~ print min([wd.procBegin for wd in results.waferData]) - #~ print max([results.waferData[k].procEnd for k in range(len(results.waferData))]) - #~ print sum(results.levelStatsIV['MAX.']) - - -class ParseFourFnTest(ParseTestCase): - def runTest(self): - import examples.fourFn as fourFn - def test(s,ans): - fourFn.exprStack = [] - results = fourFn.BNF().parseString( s ) - resultValue = fourFn.evaluateStack( fourFn.exprStack ) - assert resultValue == ans, "failed to evaluate %s, got %f" % ( s, resultValue ) - print_(s, "->", resultValue) - - from math import pi,exp - e = exp(1) - - test( "9", 9 ) - test( "9 + 3 + 6", 18 ) - test( "9 + 3 / 11", 9.0+3.0/11.0) - test( "(9 + 3)", 12 ) - test( "(9+3) / 11", (9.0+3.0)/11.0 ) - test( "9 - (12 - 6)", 3) - test( "2*3.14159", 6.28318) - test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535/10.0 ) - test( "PI * PI / 10", pi*pi/10.0 ) - test( "PI*PI/10", pi*pi/10.0 ) - test( "6.02E23 * 8.048", 6.02E23 * 8.048 ) - test( "e / 3", e/3.0 ) - test( "sin(PI/2)", 1.0 ) - test( "trunc(E)", 2.0 ) - test( "E^PI", e**pi ) - test( "2^3^2", 2**3**2) - test( "2^3+2", 2**3+2) - test( "2^9", 2**9 ) - test( "sgn(-2)", -1 ) - test( "sgn(0)", 0 ) - test( "sgn(0.1)", 1 ) - -class ParseSQLTest(ParseTestCase): - def runTest(self): - import examples.simpleSQL as simpleSQL - - def test(s, numToks, errloc=-1 ): - try: - sqlToks = flatten( simpleSQL.simpleSQL.parseString(s).asList() ) - print_(s,sqlToks,len(sqlToks)) - assert len(sqlToks) == numToks - except ParseException as e: - if errloc >= 0: - assert e.loc == errloc - - - test( "SELECT * from XYZZY, ABC", 6 ) - test( "select * from SYS.XYZZY", 5 ) - test( "Select A from Sys.dual", 5 ) - test( "Select A,B,C from Sys.dual", 7 ) - test( "Select A, B, C from Sys.dual", 7 ) - test( "Select A, B, C from Sys.dual, Table2 ", 8 ) - test( "Xelect A, B, C from Sys.dual", 0, 0 ) - test( "Select A, B, C frox Sys.dual", 0, 15 ) - test( "Select", 0, 6 ) - test( "Select &&& frox Sys.dual", 0, 7 ) - test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE')", 12 ) - test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)", 20 ) - test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators", 10 ) - -class ParseConfigFileTest(ParseTestCase): - def runTest(self): - from examples import configParse - - def test(fnam,numToks,resCheckList): - print_("Parsing",fnam,"...", end=' ') - iniFileLines = "\n".join(open(fnam).read().splitlines()) - iniData = configParse.inifile_BNF().parseString( iniFileLines ) - print_(len(flatten(iniData.asList()))) - #~ pprint.pprint( iniData.asList() ) - #~ pprint.pprint( repr(iniData) ) - #~ print len(iniData), len(flatten(iniData.asList())) - print_(list(iniData.keys())) - #~ print iniData.users.keys() - #~ print - assert len(flatten(iniData.asList())) == numToks, "file %s not parsed correctly" % fnam - for chk in resCheckList: - print_(chk[0], eval("iniData."+chk[0]), chk[1]) - assert eval("iniData."+chk[0]) == chk[1] - print_("OK") - - test("test/karthik.ini", 23, - [ ("users.K","8"), - ("users.mod_scheme","'QPSK'"), - ("users.Na", "K+2") ] - ) - test("examples/Setup.ini", 125, - [ ("Startup.audioinf", "M3i"), - ("Languages.key1", "0x0003"), - ("test.foo","bar") ] ) - -class ParseJSONDataTest(ParseTestCase): - def runTest(self): - from examples.jsonParser import jsonObject - from test.jsonParserTests import test1,test2,test3,test4,test5 - from test.jsonParserTests import test1,test2,test3,test4,test5 - - expected = [ - [], - [], - [], - [], - [], - ] - - import pprint - for t,exp in zip((test1,test2,test3,test4,test5),expected): - result = jsonObject.parseString(t) -## print result.dump() - result.pprint() - print_() -## if result.asList() != exp: -## print "Expected %s, parsed results as %s" % (exp, result.asList()) - -class ParseCommaSeparatedValuesTest(ParseTestCase): - def runTest(self): - from pyparsing import commaSeparatedList - import string - - 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 ", - "", - ] - testVals = [ - [ (3,'100.2'), (4,''), (5, '3') ], - [ (2, 'j k'), (3, 'm') ], - [ (0, "'Hello, World'"), (2, 'g'), (3, '') ], - [ (0,'John Doe'), (1, '123 Main St.'), (2, 'Cleveland'), (3, 'Ohio') ], - [ (0,'Jane Doe'), (1, '456 St. James St.'), (2, 'Los Angeles'), (3, 'California') ] - ] - for line,tests in zip(testData, testVals): - print_("Parsing: \""+line+"\" ->", end=' ') - results = commaSeparatedList.parseString(line) - print_(results.asList()) - for t in tests: - if not(len(results)>t[0] and results[t[0]] == t[1]): - print_("$$$", results.dump()) - print_("$$$", results[0]) - assert len(results)>t[0] and results[t[0]] == t[1],"failed on %s, item %d s/b '%s', got '%s'" % ( line, t[0], t[1], str(results.asList()) ) - -class ParseEBNFTest(ParseTestCase): - def runTest(self): - from examples import ebnf - from pyparsing import Word, quotedString, alphas, nums,ParserElement - - print_('Constructing EBNF parser with pyparsing...') - - 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['terminal_string'] = quotedString - 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'] - #~ print ",\n ".join( str(parsers.keys()).split(", ") ) - print_("-","\n- ".join( list(parsers.keys()) )) - assert len(list(parsers.keys())) == 13, "failed to construct syntax grammar" - - print_('Parsing EBNF grammar with generated EBNF parser...') - parsed_chars = ebnf_parser.parseString(grammar) - parsed_char_len = len(parsed_chars) - - print_("],\n".join(str( parsed_chars.asList() ).split("],"))) - assert len(flatten(parsed_chars.asList())) == 98, "failed to tokenize grammar correctly" - - -class ParseIDLTest(ParseTestCase): - def runTest(self): - from examples import idlParse - - def test( strng, numToks, errloc=0 ): - print_(strng) - try: - bnf = idlParse.CORBA_IDL_BNF() - tokens = bnf.parseString( strng ) - print_("tokens = ") - tokens.pprint() - tokens = flatten( tokens.asList() ) - print_(len(tokens)) - assert len(tokens) == numToks, "error matching IDL string, %s -> %s" % (strng, str(tokens) ) - except ParseException as err: - print_(err.line) - print_(" "*(err.column-1) + "^") - print_(err) - assert numToks == 0, "unexpected ParseException while parsing %s, %s" % (strng, str(err) ) - assert err.loc == errloc, "expected ParseException at %d, found exception at %d" % (errloc, err.loc) - - test( - """ - /* - * a block comment * - */ - typedef string[10] tenStrings; - typedef sequence stringSeq; - typedef sequence< sequence > stringSeqSeq; - - interface QoSAdmin { - stringSeq method1( in string arg1, inout long arg2 ); - stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3); - string method3(); - }; - """, 59 - ) - test( - """ - /* - * a block comment * - */ - typedef string[10] tenStrings; - typedef - /** ** *** **** * - * a block comment * - */ - sequence /*comment inside an And */ stringSeq; - /* */ /**/ /***/ /****/ - typedef sequence< sequence > stringSeqSeq; - - interface QoSAdmin { - stringSeq method1( in string arg1, inout long arg2 ); - stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3); - string method3(); - }; - """, 59 - ) - 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 dataStrings; - }; - - interface TestInterface - { - void method1( in string arg1, inout long arg2 ); - }; - """, 60 - ) - test( - """ - module Test1 - { - exception TestException - { - string msg; - ]; - - interface TestInterface - { - void method1( in string arg1, inout long arg2 ) - raises ( TestException ); - }; - }; - """, 0, 57 - ) - test( - """ - module Test1 - { - exception TestException - { - string msg; - }; - - }; - """, 13 - ) - -class ParseVerilogTest(ParseTestCase): - def runTest(self): - pass - -class RunExamplesTest(ParseTestCase): - def runTest(self): - pass - -class ScanStringTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, Combine, Suppress, CharsNotIn, nums, StringEnd - testdata = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameIP AddressLocation
time-a.nist.gov129.6.15.28NIST, Gaithersburg, Maryland
time-b.nist.gov129.6.15.29NIST, Gaithersburg, Maryland
time-a.timefreq.bldrdoc.gov132.163.4.101NIST, Boulder, Colorado
time-b.timefreq.bldrdoc.gov132.163.4.102NIST, Boulder, Colorado
time-c.timefreq.bldrdoc.gov132.163.4.103NIST, Boulder, Colorado
- """ - integer = Word(nums) - ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer ) - tdStart = Suppress("") - tdEnd = Suppress("") - timeServerPattern = tdStart + ipAddress.setResultsName("ipAddr") + tdEnd + \ - tdStart + CharsNotIn("<").setResultsName("loc") + tdEnd - servers = \ - [ srvr.ipAddr for srvr,startloc,endloc in timeServerPattern.scanString( testdata ) ] - - print_(servers) - assert servers == ['129.6.15.28', '129.6.15.29', '132.163.4.101', '132.163.4.102', '132.163.4.103'], \ - "failed scanString()" - - # test for stringEnd detection in scanString - foundStringEnds = [ r for r in StringEnd().scanString("xyzzy") ] - print_(foundStringEnds) - assert foundStringEnds, "Failed to find StringEnd in scanString" - -class QuotedStringsTest(ParseTestCase): - def runTest(self): - from pyparsing import sglQuotedString,dblQuotedString,quotedString,QuotedString - testData = \ - """ - 'a valid single quoted string' - 'an invalid single quoted string - because it spans lines' - "a valid double quoted string" - "an invalid double quoted string - because it spans lines" - """ - print_(testData) - sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(testData) ] - print_(sglStrings) - assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==47), \ - "single quoted string failure" - dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(testData) ] - print_(dblStrings) - assert len(dblStrings) == 1 and (dblStrings[0][1]==154 and dblStrings[0][2]==184), \ - "double quoted string failure" - allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(testData) ] - print_(allStrings) - assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==47) and \ - (allStrings[1][1]==154 and allStrings[1][2]==184), \ - "quoted string failure" - - escapedQuoteTest = \ - r""" - 'This string has an escaped (\') quote character' - "This string has an escaped (\") quote character" - """ - sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(escapedQuoteTest) ] - print_(sglStrings) - assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \ - "single quoted string escaped quote failure (%s)" % str(sglStrings[0]) - dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(escapedQuoteTest) ] - print_(dblStrings) - assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \ - "double quoted string escaped quote failure (%s)" % str(dblStrings[0]) - allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(escapedQuoteTest) ] - print_(allStrings) - assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and - allStrings[1][1]==83 and allStrings[1][2]==132), \ - "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings]) - - dblQuoteTest = \ - r""" - 'This string has an doubled ('') quote character' - "This string has an doubled ("") quote character" - """ - sglStrings = [ (t[0],b,e) for (t,b,e) in sglQuotedString.scanString(dblQuoteTest) ] - print_(sglStrings) - assert len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), \ - "single quoted string escaped quote failure (%s)" % str(sglStrings[0]) - dblStrings = [ (t[0],b,e) for (t,b,e) in dblQuotedString.scanString(dblQuoteTest) ] - print_(dblStrings) - assert len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), \ - "double quoted string escaped quote failure (%s)" % str(dblStrings[0]) - allStrings = [ (t[0],b,e) for (t,b,e) in quotedString.scanString(dblQuoteTest) ] - print_(allStrings) - assert len(allStrings) == 2 and (allStrings[0][1]==17 and allStrings[0][2]==66 and - allStrings[1][1]==83 and allStrings[1][2]==132), \ - "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings]) - - print_("testing catastrophic RE backtracking in implementation of dblQuotedString") - for expr, test_string in [ - (dblQuotedString, '"' + '\\xff' * 500), - (sglQuotedString, "'" + '\\xff' * 500), - (quotedString, '"' + '\\xff' * 500), - (quotedString, "'" + '\\xff' * 500), - (QuotedString('"'), '"' + '\\xff' * 500), - (QuotedString("'"), "'" + '\\xff' * 500), - ]: - expr.parseString(test_string+test_string[0]) - try: - expr.parseString(test_string) - except Exception: - continue - -class CaselessOneOfTest(ParseTestCase): - def runTest(self): - from pyparsing import oneOf,ZeroOrMore - - caseless1 = oneOf("d a b c aA B A C", caseless=True) - caseless1str = str( caseless1 ) - print_(caseless1str) - caseless2 = oneOf("d a b c Aa B A C", caseless=True) - caseless2str = str( caseless2 ) - print_(caseless2str) - assert caseless1str.upper() == caseless2str.upper(), "oneOf not handling caseless option properly" - assert caseless1str != caseless2str, "Caseless option properly sorted" - - res = ZeroOrMore(caseless1).parseString("AAaaAaaA") - print_(res) - assert len(res) == 4, "caseless1 oneOf failed" - assert "".join(res) == "aA"*4,"caseless1 CaselessLiteral return failed" - - res = ZeroOrMore(caseless2).parseString("AAaaAaaA") - print_(res) - assert len(res) == 4, "caseless2 oneOf failed" - assert "".join(res) == "Aa"*4,"caseless1 CaselessLiteral return failed" - - -class AsXMLTest(ParseTestCase): - def runTest(self): - - import pyparsing - # test asXML() - - aaa = pyparsing.Word("a").setResultsName("A") - bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B") - ccc = pyparsing.Combine(":" + pyparsing.Word("c")).setResultsName("C") - g1 = "XXX>&<" + pyparsing.ZeroOrMore( aaa | bbb | ccc ) - teststring = "XXX>&< b b a b b a b :c b a" - #~ print teststring - print_("test including all items") - xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=False) - assert xml=="\n".join(["", - "", - " XXX>&<", - " ", - " b", - " ", - " ", - " b", - " ", - " a", - " ", - " b", - " ", - " ", - " b", - " ", - " a", - " ", - " b", - " ", - " :c", - " ", - " b", - " ", - " a", - "", - ] ), \ - "failed to generate XML correctly showing all items: \n[" + xml + "]" - print_("test filtering unnamed items") - xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=True) - assert xml=="\n".join(["", - "", - " ", - " b", - " ", - " ", - " b", - " ", - " a", - " ", - " b", - " ", - " ", - " b", - " ", - " a", - " ", - " b", - " ", - " :c", - " ", - " b", - " ", - " a", - "", - ] ), \ - "failed to generate XML correctly, filtering unnamed items: " + xml - -class AsXMLTest2(ParseTestCase): - def runTest(self): - from pyparsing import Suppress,Optional,CharsNotIn,Combine,ZeroOrMore,Word,\ - Group,Literal,alphas,alphanums,delimitedList,OneOrMore - - EndOfLine = Word("\n").setParseAction(lambda s,l,t: [' ']) - whiteSpace=Word('\t ') - Mexpr = Suppress(Optional(whiteSpace)) + CharsNotIn('\\"\t \n') + Optional(" ") + \ - Suppress(Optional(whiteSpace)) - reducedString = Combine(Mexpr + ZeroOrMore(EndOfLine + Mexpr)) - _bslash = "\\" - _escapables = "tnrfbacdeghijklmopqsuvwxyz" + _bslash + "'" + '"' - _octDigits = "01234567" - _escapedChar = ( Word( _bslash, _escapables, exact=2 ) | - Word( _bslash, _octDigits, min=2, max=4 ) ) - _sglQuote = Literal("'") - _dblQuote = Literal('"') - QuotedReducedString = Combine( Suppress(_dblQuote) + ZeroOrMore( reducedString | - _escapedChar ) + \ - Suppress(_dblQuote )).streamline() - - Manifest_string = QuotedReducedString.setResultsName('manifest_string') - - Identifier = Word( alphas, alphanums+ '_$' ).setResultsName("identifier") - Index_string = CharsNotIn('\\";\n') - Index_string.setName('index_string') - Index_term_list = ( - Group(delimitedList(Manifest_string, delim=',')) | \ - Index_string - ).setResultsName('value') - - IndexKey = Identifier.setResultsName('key') - IndexKey.setName('key') - Index_clause = Group(IndexKey + Suppress(':') + Optional(Index_term_list)) - Index_clause.setName('index_clause') - Index_list = Index_clause.setResultsName('index') - Index_list.setName('index_list') - Index_block = Group('indexing' + Group(OneOrMore(Index_list + Suppress(';')))).setResultsName('indexes') - - -class CommentParserTest(ParseTestCase): - def runTest(self): - import pyparsing - print_("verify processing of C and HTML comments") - testdata = """ - /* */ - /** **/ - /**/ - /***/ - /****/ - /* /*/ - /** /*/ - /*** /*/ - /* - ablsjdflj - */ - """ - foundLines = [ pyparsing.lineno(s,testdata) - for t,s,e in pyparsing.cStyleComment.scanString(testdata) ] - assert foundLines == list(range(11))[2:],"only found C comments on lines "+str(foundLines) - testdata = """ - - - - - - - - - - """ - foundLines = [ pyparsing.lineno(s,testdata) - for t,s,e in pyparsing.htmlComment.scanString(testdata) ] - assert foundLines == list(range(11))[2:],"only found HTML comments on lines "+str(foundLines) - - # test C++ single line comments that have line terminated with '\' (should continue comment to following line) - testSource = r""" - // comment1 - // comment2 \ - still comment 2 - // comment 3 - """ - assert len(pyparsing.cppStyleComment.searchString(testSource)[1][0]) == 41, r"failed to match single-line comment with '\' at EOL" - -class ParseExpressionResultsTest(ParseTestCase): - def runTest(self): - from pyparsing import Word,alphas,OneOrMore,Optional,Group - - a = Word("a",alphas).setName("A") - b = Word("b",alphas).setName("B") - c = Word("c",alphas).setName("C") - ab = (a + b).setName("AB") - abc = (ab + c).setName("ABC") - word = Word(alphas).setName("word") - - #~ words = OneOrMore(word).setName("words") - words = Group(OneOrMore(~a + word)).setName("words") - - #~ phrase = words.setResultsName("Head") + \ - #~ ( abc ^ ab ^ a ).setResultsName("ABC") + \ - #~ words.setResultsName("Tail") - #~ phrase = words.setResultsName("Head") + \ - #~ ( abc | ab | a ).setResultsName("ABC") + \ - #~ words.setResultsName("Tail") - phrase = words.setResultsName("Head") + \ - Group( a + Optional(b + Optional(c)) ).setResultsName("ABC") + \ - words.setResultsName("Tail") - - results = phrase.parseString("xavier yeti alpha beta charlie will beaver") - print_(results,results.Head, results.ABC,results.Tail) - for key,ln in [("Head",2), ("ABC",3), ("Tail",2)]: - #~ assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key].asList())) - assert len(results[key]) == ln,"expected %d elements in %s, found %s" % (ln, key, str(results[key])) - - -class ParseKeywordTest(ParseTestCase): - def runTest(self): - from pyparsing import Literal,Keyword - - kw = Keyword("if") - lit = Literal("if") - - def test(s,litShouldPass,kwShouldPass): - print_("Test",s) - print_("Match Literal", end=' ') - try: - print_(lit.parseString(s)) - except: - print_("failed") - if litShouldPass: assert False, "Literal failed to match %s, should have" % s - else: - if not litShouldPass: assert False, "Literal matched %s, should not have" % s - - print_("Match Keyword", end=' ') - try: - print_(kw.parseString(s)) - except: - print_("failed") - if kwShouldPass: assert False, "Keyword failed to match %s, should have" % s - else: - if not kwShouldPass: assert False, "Keyword matched %s, should not have" % s - - test("ifOnlyIfOnly", True, False) - test("if(OnlyIfOnly)", True, True) - test("if (OnlyIf Only)", True, True) - - kw = Keyword("if",caseless=True) - - test("IFOnlyIfOnly", False, False) - test("If(OnlyIfOnly)", False, True) - test("iF (OnlyIf Only)", False, True) - - - -class ParseExpressionResultsAccumulateTest(ParseTestCase): - def runTest(self): - from pyparsing import Word,delimitedList,Combine,alphas,nums - - num=Word(nums).setName("num").setResultsName("base10", listAllMatches=True) - hexnum=Combine("0x"+ Word(nums)).setName("hexnum").setResultsName("hex", listAllMatches=True) - name = Word(alphas).setName("word").setResultsName("word", listAllMatches=True) - list_of_num=delimitedList( hexnum | num | name, "," ) - - tokens = list_of_num.parseString('1, 0x2, 3, 0x4, aaa') - for k,llen,lst in ( ("base10",2,['1','3']), - ("hex",2,['0x2','0x4']), - ("word",1,['aaa']) ): - print_(k,tokens[k]) - assert len(tokens[k]) == llen, "Wrong length for key %s, %s" % (k,str(tokens[k].asList())) - assert lst == tokens[k].asList(), "Incorrect list returned for key %s, %s" % (k,str(tokens[k].asList())) - assert tokens.base10.asList() == ['1','3'], "Incorrect list for attribute base10, %s" % str(tokens.base10.asList()) - assert tokens.hex.asList() == ['0x2','0x4'], "Incorrect list for attribute hex, %s" % str(tokens.hex.asList()) - assert tokens.word.asList() == ['aaa'], "Incorrect list for attribute word, %s" % str(tokens.word.asList()) - - from pyparsing import Literal, Word, nums, Group, Dict, alphas, \ - quotedString, oneOf, delimitedList, removeQuotes, alphanums - - lbrack = Literal("(").suppress() - rbrack = Literal(")").suppress() - integer = Word( nums ).setName("int") - variable = Word( alphas, max=1 ).setName("variable") - relation_body_item = variable | integer | quotedString.copy().setParseAction(removeQuotes) - relation_name = Word( alphas+"_", alphanums+"_" ) - relation_body = lbrack + Group(delimitedList(relation_body_item)) + rbrack - Goal = Dict(Group( relation_name + relation_body )) - Comparison_Predicate = Group(variable + oneOf("< >") + integer).setResultsName("pred",listAllMatches=True) - Query = Goal.setResultsName("head") + ":-" + delimitedList(Goal | Comparison_Predicate) - - test="""Q(x,y,z):-Bloo(x,"Mitsis",y),Foo(y,z,1243),y>28,x<12,x>3""" - - queryRes = Query.parseString(test) - print_("pred",queryRes.pred) - assert queryRes.pred.asList() == [['y', '>', '28'], ['x', '<', '12'], ['x', '>', '3']], "Incorrect list for attribute pred, %s" % str(queryRes.pred.asList()) - print_(queryRes.dump()) - -class ReStringRangeTest(ParseTestCase): - def runTest(self): - import pyparsing - testCases = ( - (r"[A-Z]"), - (r"[A-A]"), - (r"[A-Za-z]"), - (r"[A-z]"), - (r"[\ -\~]"), - (r"[\0x20-0]"), - (r"[\0x21-\0x7E]"), - (r"[\0xa1-\0xfe]"), - (r"[\040-0]"), - (r"[A-Za-z0-9]"), - (r"[A-Za-z0-9_]"), - (r"[A-Za-z0-9_$]"), - (r"[A-Za-z0-9_$\-]"), - (r"[^0-9\\]"), - (r"[a-zA-Z]"), - (r"[/\^~]"), - (r"[=\+\-!]"), - (r"[A-]"), - (r"[-A]"), - (r"[\x21]"), - #(r"[а-яА-ЯёЁA-Z$_\041α-ω]".decode('utf-8')), - (u'[\u0430-\u044f\u0410-\u042f\u0451\u0401ABCDEFGHIJKLMNOPQRSTUVWXYZ$_\041\u03b1-\u03c9]'), - ) - expectedResults = ( - "ABCDEFGHIJKLMNOPQRSTUVWXYZ", - "A", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz", - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~", - " !\"#$%&'()*+,-./0", - "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~", - #~ "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ", - u'\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe', - " !\"#$%&'()*+,-./0", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$-", - "0123456789\\", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "/^~", - "=+-!", - "A-", - "-A", - "!", - u"абвгдежзийклмнопрстуфхцчшщъыьэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯёЁABCDEFGHIJKLMNOPQRSTUVWXYZ$_!αβγδεζηθικλμνξοπρςστυφχψω", - ) - for test in zip( testCases, expectedResults ): - t,exp = test - res = pyparsing.srange(t) - #print_(t,"->",res) - assert res == exp, "srange error, srange(%r)->'%r', expected '%r'" % (t, res, exp) - -class SkipToParserTests(ParseTestCase): - def runTest(self): - - from pyparsing import Literal, SkipTo, NotAny, cStyleComment, ParseBaseException - - thingToFind = Literal('working') - testExpr = SkipTo(Literal(';'), include=True, ignore=cStyleComment) + thingToFind - - def tryToParse (someText, fail_expected=False): - try: - print_(testExpr.parseString(someText)) - assert not fail_expected, "expected failure but no exception raised" - except Exception as e: - print_("Exception %s while parsing string %s" % (e,repr(someText))) - assert fail_expected and isinstance(e,ParseBaseException), "Exception %s while parsing string %s" % (e,repr(someText)) - - # This first test works, as the SkipTo expression is immediately following the ignore expression (cStyleComment) - tryToParse('some text /* comment with ; in */; working') - # This second test previously failed, as there is text following the ignore expression, and before the SkipTo expression. - tryToParse('some text /* comment with ; in */some other stuff; working') - - # tests for optional failOn argument - testExpr = SkipTo(Literal(';'), include=True, ignore=cStyleComment, failOn='other') + thingToFind - tryToParse('some text /* comment with ; in */; working') - tryToParse('some text /* comment with ; in */some other stuff; working', fail_expected=True) - -class CustomQuotesTest(ParseTestCase): - def runTest(self): - from pyparsing import QuotedString - - testString = r""" - sdlfjs :sdf\:jls::djf: sl:kfsjf - sdlfjs -sdf\:jls::--djf: sl-kfsjf - sdlfjs -sdf\:::jls::--djf: sl:::-kfsjf - sdlfjs ^sdf\:jls^^--djf^ sl-kfsjf - sdlfjs ^^^==sdf\:j=lz::--djf: sl=^^=kfsjf - sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf^^^ - """ - colonQuotes = QuotedString(':','\\','::') - dashQuotes = QuotedString('-','\\', '--') - hatQuotes = QuotedString('^','\\') - hatQuotes1 = QuotedString('^','\\','^^') - dblEqQuotes = QuotedString('==','\\') - - def test(quoteExpr, expected): - print_(quoteExpr.pattern) - print_(quoteExpr.searchString(testString)) - print_(quoteExpr.searchString(testString)[0][0]) - print_(expected) - assert quoteExpr.searchString(testString)[0][0] == expected, \ - "failed to match %s, expected '%s', got '%s'" % \ - (quoteExpr,expected,quoteExpr.searchString(testString)[0]) - print_() - - test(colonQuotes, r"sdf:jls:djf") - test(dashQuotes, r"sdf:jls::-djf: sl") - test(hatQuotes, r"sdf:jls") - test(hatQuotes1, r"sdf:jls^--djf") - test(dblEqQuotes, r"sdf:j=ls::--djf: sl") - test( QuotedString(':::'), 'jls::--djf: sl') - test( QuotedString('==',endQuoteChar='--'), r'sdf\:j=lz::') - test( QuotedString('^^^',multiline=True), r"""==sdf\:j=lz::--djf: sl=^^=kfsjf - sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf""") - try: - bad1 = QuotedString('','\\') - except SyntaxError as se: - pass - else: - assert False,"failed to raise SyntaxError with empty quote string" - -class RepeaterTest(ParseTestCase): - def runTest(self): - from pyparsing import matchPreviousLiteral,matchPreviousExpr, Forward, Literal, Word, alphas, nums, ParserElement - - if ParserElement._packratEnabled: - print_("skipping this test, not compatible with packratting") - return - - first = Word("abcdef").setName("word1") - bridge = Word(nums).setName("number") - second = matchPreviousLiteral(first).setName("repeat(word1Literal)") - - seq = first + bridge + second - - tests = [ - ( "abc12abc", True ), - ( "abc12aabc", False ), - ( "abc12cba", True ), - ( "abc12bca", True ), - ] - - for tst,result in tests: - found = False - for tokens,start,end in seq.scanString(tst): - f,b,s = tokens - print_(f,b,s) - found = True - if not found: - print_("No literal match in", tst) - assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq)) - print_() - - # retest using matchPreviousExpr instead of matchPreviousLiteral - second = matchPreviousExpr(first).setName("repeat(word1expr)") - seq = first + bridge + second - - tests = [ - ( "abc12abc", True ), - ( "abc12cba", False ), - ( "abc12abcdef", False ), - ] - - for tst,result in tests: - found = False - for tokens,start,end in seq.scanString(tst): - print_(tokens.asList()) - found = True - if not found: - print_("No expression match in", tst) - assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq)) - - print_() - - first = Word("abcdef").setName("word1") - bridge = Word(nums).setName("number") - second = matchPreviousExpr(first).setName("repeat(word1)") - seq = first + bridge + second - csFirst = seq.setName("word-num-word") - csSecond = matchPreviousExpr(csFirst) - compoundSeq = csFirst + ":" + csSecond - compoundSeq.streamline() - print_(compoundSeq) - - tests = [ - ( "abc12abc:abc12abc", True ), - ( "abc12cba:abc12abc", False ), - ( "abc12abc:abc12abcdef", False ), - ] - - #~ for tst,result in tests: - #~ print tst, - #~ try: - #~ compoundSeq.parseString(tst) - #~ print "MATCH" - #~ assert result, "matched when shouldn't have matched" - #~ except ParseException: - #~ print "NO MATCH" - #~ assert not result, "didnt match but should have" - - #~ for tst,result in tests: - #~ print tst, - #~ if compoundSeq == tst: - #~ print "MATCH" - #~ assert result, "matched when shouldn't have matched" - #~ else: - #~ print "NO MATCH" - #~ assert not result, "didnt match but should have" - - for tst,result in tests: - found = False - for tokens,start,end in compoundSeq.scanString(tst): - print_("match:", tokens.asList()) - found = True - break - if not found: - print_("No expression match in", tst) - assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq)) - - print_() - eFirst = Word(nums) - eSecond = matchPreviousExpr(eFirst) - eSeq = eFirst + ":" + eSecond - - tests = [ - ( "1:1A", True ), - ( "1:10", False ), - ] - - for tst,result in tests: - found = False - for tokens,start,end in eSeq.scanString(tst): - #~ f,b,s = tokens - #~ print f,b,s - print_(tokens.asList()) - found = True - if not found: - print_("No match in", tst) - assert found == result, "Failed repeater for test: %s, matching %s" % (tst, str(seq)) - -class RecursiveCombineTest(ParseTestCase): - def runTest(self): - from pyparsing import Forward,Word,alphas,nums,Optional,Combine - - testInput = "myc(114)r(11)dd" - Stream=Forward() - Stream << Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream) - expected = Stream.parseString(testInput).asList() - print_(["".join(expected)]) - - Stream=Forward() - Stream << Combine(Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream)) - testVal = Stream.parseString(testInput).asList() - print_(testVal) - - assert "".join(testVal) == "".join(expected), "Failed to process Combine with recursive content" - -class InfixNotationGrammarTest1(ParseTestCase): - def runTest(self): - from pyparsing import Word,nums,alphas,Literal,oneOf,infixNotation,opAssoc - - 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('!') - - expr = infixNotation( operand, - [("!", 1, opAssoc.LEFT), - ("^", 2, opAssoc.RIGHT), - (signop, 1, opAssoc.RIGHT), - (multop, 2, opAssoc.LEFT), - (plusop, 2, opAssoc.LEFT),] - ) - - test = ["9 + 2 + 3", - "9 + 2 * 3", - "(9 + 2) * 3", - "(9 + -2) * 3", - "(9 + --2) * 3", - "(9 + -2) * 3^2^2", - "(9! + -2) * 3^2^2", - "M*X + B", - "M*(X + B)", - "1+2*-3^4*5+-+-6", - "3!!"] - expected = """[[9, '+', 2, '+', 3]] - [[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]]]]] - [[3, '!', '!']]""".split('\n') - expected = [eval(x) for x in expected] - for t,e in zip(test,expected): - print_(t,"->",e, "got", expr.parseString(t).asList()) - assert expr.parseString(t).asList() == e,"mismatched results for infixNotation: got %s, expected %s" % (expr.parseString(t).asList(),e) - -class InfixNotationGrammarTest2(ParseTestCase): - def runTest(self): - - from pyparsing import infixNotation, Word, alphas, oneOf, opAssoc - - boolVars = { "True":True, "False":False } - 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 __bool__(self): - for a in self.args: - if isinstance(a,str): - v = boolVars[a] - else: - v = bool(a) - if not v: - return False - return True - - class BoolOr(BoolOperand): - reprsymbol = '|' - def __bool__(self): - for a in self.args: - if isinstance(a,str): - v = boolVars[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 __bool__(self): - if isinstance(self.arg,str): - v = boolVars[self.arg] - else: - v = bool(self.arg) - return not v - - boolOperand = Word(alphas,max=1) | oneOf("True False") - boolExpr = infixNotation( 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", - ] - - boolVars["p"] = True - boolVars["q"] = False - boolVars["r"] = True - print_("p =", boolVars["p"]) - print_("q =", boolVars["q"]) - print_("r =", boolVars["r"]) - print_() - for t in test: - res = boolExpr.parseString(t)[0] - print_(t,'\n', res, '=', bool(res),'\n') - - -class InfixNotationGrammarTest3(ParseTestCase): - def runTest(self): - - from pyparsing import infixNotation, Word, alphas, oneOf, opAssoc, nums, Literal - - global count - count = 0 - - def evaluate_int(t): - global count - value = int(t[0]) - print_("evaluate_int", value) - count += 1 - return value - - integer = Word(nums).setParseAction(evaluate_int) - variable = Word(alphas,exact=1) - operand = integer | variable - - expop = Literal('^') - signop = oneOf('+ -') - multop = oneOf('* /') - plusop = oneOf('+ -') - factop = Literal('!') - - expr = infixNotation( operand, - [ - ("!", 1, opAssoc.LEFT), - ("^", 2, opAssoc.RIGHT), - (signop, 1, opAssoc.RIGHT), - (multop, 2, opAssoc.LEFT), - (plusop, 2, opAssoc.LEFT), - ]) - - test = ["9"] - for t in test: - count = 0 - print_("%s => %s" % (t, expr.parseString(t))) - assert count == 1, "count evaluated too many times!" - -class InfixNotationGrammarTest4(ParseTestCase): - def runTest(self): - - import pyparsing - - word = pyparsing.Word(pyparsing.alphas) - - def supLiteral(s): - """Returns the suppressed literal s""" - return pyparsing.Literal(s).suppress() - - def booleanExpr(atom): - ops = [ - (supLiteral("!"), 1, pyparsing.opAssoc.RIGHT, lambda s, l, t: ["!", t[0][0]]), - (pyparsing.oneOf("= !="), 2, pyparsing.opAssoc.LEFT, ), - (supLiteral("&"), 2, pyparsing.opAssoc.LEFT, lambda s, l, t: ["&", t[0]]), - (supLiteral("|"), 2, pyparsing.opAssoc.LEFT, lambda s, l, t: ["|", t[0]])] - return pyparsing.infixNotation(atom, ops) - - f = booleanExpr(word) + pyparsing.StringEnd() - - tests = [ - ("bar = foo", "[['bar', '=', 'foo']]"), - ("bar = foo & baz = fee", "['&', [['bar', '=', 'foo'], ['baz', '=', 'fee']]]"), - ] - for test,expected in tests: - print_(test) - results = f.parseString(test) - print_(results) - assert str(results) == expected, "failed to match expected results, got '%s'" % str(results) - print_() - - -class PickleTest_Greeting(): - def __init__(self, toks): - self.salutation = toks[0] - self.greetee = toks[1] - - def __repr__(self): - return "%s: {%s}" % (self.__class__.__name__, - ', '.join('%r: %r' % (k, getattr(self,k)) for k in sorted(self.__dict__))) - -class ParseResultsPickleTest(ParseTestCase): - def runTest(self): - from pyparsing import makeHTMLTags, ParseResults - import pickle - - # test 1 - body = makeHTMLTags("BODY")[0] - result = body.parseString("") - if VERBOSE: - print_(result.dump()) - print_() - - for protocol in range(pickle.HIGHEST_PROTOCOL+1): - print_("Test pickle dump protocol", protocol) - try: - pickleString = pickle.dumps(result, protocol) - except Exception as e: - print_("dumps exception:", e) - newresult = ParseResults() - else: - newresult = pickle.loads(pickleString) - if VERBOSE: - print_(newresult.dump()) - print_() - - assert result.dump() == newresult.dump(), "Error pickling ParseResults object (protocol=%d)" % protocol - - # test 2 - import pyparsing as pp - - word = pp.Word(pp.alphas+"'.") - salutation = pp.OneOrMore(word) - comma = pp.Literal(",") - greetee = pp.OneOrMore(word) - endpunc = pp.oneOf("! ?") - greeting = salutation + pp.Suppress(comma) + greetee + pp.Suppress(endpunc) - greeting.setParseAction(PickleTest_Greeting) - - string = 'Good morning, Miss Crabtree!' - - result = greeting.parseString(string) - - for protocol in range(pickle.HIGHEST_PROTOCOL+1): - print_("Test pickle dump protocol", protocol) - try: - pickleString = pickle.dumps(result, protocol) - except Exception as e: - print_("dumps exception:", e) - newresult = ParseResults() - else: - newresult = pickle.loads(pickleString) - print_(newresult.dump()) - assert newresult.dump() == result.dump(), "failed to pickle/unpickle ParseResults: expected %r, got %r" % (result, newresult) - - - -class ParseResultsWithNamedTupleTest(ParseTestCase): - def runTest(self): - - from pyparsing import Literal,replaceWith - - expr = Literal("A") - expr.setParseAction(replaceWith(tuple(["A","Z"]))) - expr = expr.setResultsName("Achar") - - res = expr.parseString("A") - print_(repr(res)) - print_(res.Achar) - assert res.Achar == ("A","Z"), "Failed accessing named results containing a tuple, got " + res.Achar - - -class ParseHTMLTagsTest(ParseTestCase): - def runTest(self): - import pyparsing - test = """ - - - - - - - """ - results = [ - ("startBody", False, "", ""), - ("startBody", False, "#00FFCC", ""), - ("startBody", True, "#00FFAA", ""), - ("startBody", False, "#00FFBB", "black"), - ("startBody", True, "", ""), - ("endBody", False, "", ""), - ] - - bodyStart, bodyEnd = pyparsing.makeHTMLTags("BODY") - resIter = iter(results) - for t,s,e in (bodyStart | bodyEnd).scanString( test ): - print_(test[s:e], "->", t.asList()) - (expectedType, expectedEmpty, expectedBG, expectedFG) = next(resIter) - - tType = t.getName() - #~ print tType,"==",expectedType,"?" - assert tType in "startBody endBody".split(), "parsed token of unknown type '%s'" % tType - assert tType == expectedType, "expected token of type %s, got %s" % (expectedType, tType) - if tType == "startBody": - assert bool(t.empty) == expectedEmpty, "expected %s token, got %s" % ( expectedEmpty and "empty" or "not empty", - t.empty and "empty" or "not empty" ) - assert t.bgcolor == expectedBG, "failed to match BGCOLOR, expected %s, got %s" % ( expectedBG, t.bgcolor ) - assert t.fgcolor == expectedFG, "failed to match FGCOLOR, expected %s, got %s" % ( expectedFG, t.bgcolor ) - elif tType == "endBody": - #~ print "end tag" - pass - else: - print_("BAD!!!") - -class UpcaseDowncaseUnicode(ParseTestCase): - def runTest(self): - - import pyparsing as pp - import sys - if PY_3: - unichr = chr - else: - from __builtin__ import unichr - - a = '\u00bfC\u00f3mo esta usted?' - if not JYTHON_ENV: - ualphas = "".join( unichr(i) for i in range(sys.maxunicode) - if unichr(i).isalpha() ) - else: - ualphas = "".join( unichr(i) for i in list(range(0xd800)) + list(range(0xe000,sys.maxunicode)) - if unichr(i).isalpha() ) - uword = pp.Word(ualphas).setParseAction(pp.upcaseTokens) - - print_ = lambda *args: None - print_(uword.searchString(a)) - - uword = pp.Word(ualphas).setParseAction(pp.downcaseTokens) - - print_(uword.searchString(a)) - - kw = pp.Keyword('mykey', caseless=True).setParseAction(pp.upcaseTokens).setResultsName('rname') - ret = kw.parseString('mykey') - print(ret.rname) - assert ret.rname=='MYKEY', "failed to upcase with named result" - - if not IRON_PYTHON_ENV: - #test html data - html = " \ - Производитель, модель \ - BenQ-Siemens CF61 \ - "#.decode('utf-8') - - # u'Manufacturer, model - text_manuf = 'Производитель, модель' - manufacturer = pp.Literal(text_manuf) - - td_start, td_end = pp.makeHTMLTags("td") - manuf_body = td_start.suppress() + manufacturer + pp.SkipTo(td_end)("cells*") + td_end.suppress() - - #~ manuf_body.setDebug() - - #~ for tokens in manuf_body.scanString(html): - #~ print_(tokens) - -class ParseUsingRegex(ParseTestCase): - def runTest(self): - - import re - import pyparsing - - signedInt = pyparsing.Regex(r'[-+][0-9]+') - unsignedInt = pyparsing.Regex(r'[0-9]+') - simpleString = pyparsing.Regex(r'("[^\"]*")|(\'[^\']*\')') - namedGrouping = pyparsing.Regex(r'("(?P[^\"]*)")') - compiledRE = pyparsing.Regex(re.compile(r'[A-Z]+')) - - def testMatch (expression, instring, shouldPass, expectedString=None): - if shouldPass: - try: - result = expression.parseString(instring) - print_('%s correctly matched %s' % (repr(expression), repr(instring))) - if expectedString != result[0]: - print_('\tbut failed to match the pattern as expected:') - print_('\tproduced %s instead of %s' % \ - (repr(result[0]), repr(expectedString))) - return True - except pyparsing.ParseException: - print_('%s incorrectly failed to match %s' % \ - (repr(expression), repr(instring))) - else: - try: - result = expression.parseString(instring) - print_('%s incorrectly matched %s' % (repr(expression), repr(instring))) - print_('\tproduced %s as a result' % repr(result[0])) - except pyparsing.ParseException: - print_('%s correctly failed to match %s' % \ - (repr(expression), repr(instring))) - return True - return False - - # These should fail - assert testMatch(signedInt, '1234 foo', False), "Re: (1) passed, expected fail" - assert testMatch(signedInt, ' +foo', False), "Re: (2) passed, expected fail" - assert testMatch(unsignedInt, 'abc', False), "Re: (3) passed, expected fail" - assert testMatch(unsignedInt, '+123 foo', False), "Re: (4) passed, expected fail" - assert testMatch(simpleString, 'foo', False), "Re: (5) passed, expected fail" - assert testMatch(simpleString, '"foo bar\'', False), "Re: (6) passed, expected fail" - assert testMatch(simpleString, '\'foo bar"', False), "Re: (7) passed, expected fail" - - # These should pass - assert testMatch(signedInt, ' +123', True, '+123'), "Re: (8) failed, expected pass" - assert testMatch(signedInt, '+123', True, '+123'), "Re: (9) failed, expected pass" - assert testMatch(signedInt, '+123 foo', True, '+123'), "Re: (10) failed, expected pass" - assert testMatch(signedInt, '-0 foo', True, '-0'), "Re: (11) failed, expected pass" - assert testMatch(unsignedInt, '123 foo', True, '123'), "Re: (12) failed, expected pass" - assert testMatch(unsignedInt, '0 foo', True, '0'), "Re: (13) failed, expected pass" - assert testMatch(simpleString, '"foo"', True, '"foo"'), "Re: (14) failed, expected pass" - assert testMatch(simpleString, "'foo bar' baz", True, "'foo bar'"), "Re: (15) failed, expected pass" - - assert testMatch(compiledRE, 'blah', False), "Re: (16) passed, expected fail" - assert testMatch(compiledRE, 'BLAH', True, 'BLAH'), "Re: (17) failed, expected pass" - - assert testMatch(namedGrouping, '"foo bar" baz', True, '"foo bar"'), "Re: (16) failed, expected pass" - ret = namedGrouping.parseString('"zork" blah') - print_(ret.asList()) - print_(list(ret.items())) - print_(ret.content) - assert ret.content == 'zork', "named group lookup failed" - assert ret[0] == simpleString.parseString('"zork" blah')[0], "Regex not properly returning ParseResults for named vs. unnamed groups" - - try: - #~ print "lets try an invalid RE" - invRe = pyparsing.Regex('("[^\"]*")|(\'[^\']*\'') - except Exception as e: - print_("successfully rejected an invalid RE:", end=' ') - print_(e) - else: - assert False, "failed to reject invalid RE" - - invRe = pyparsing.Regex('') - -class CountedArrayTest(ParseTestCase): - def runTest(self): - from pyparsing import Word,nums,OneOrMore,countedArray - - testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" - - integer = Word(nums).setParseAction(lambda t: int(t[0])) - countedField = countedArray(integer) - - r = OneOrMore(countedField).parseString( testString ) - print_(testString) - print_(r.asList()) - - assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \ - "Failed matching countedArray, got " + str(r.asList()) - -class CountedArrayTest2(ParseTestCase): - # addresses bug raised by Ralf Vosseler - def runTest(self): - from pyparsing import Word,nums,OneOrMore,countedArray - - testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" - - integer = Word(nums).setParseAction(lambda t: int(t[0])) - countedField = countedArray(integer) - - dummy = Word("A") - r = OneOrMore(dummy ^ countedField).parseString( testString ) - print_(testString) - print_(r.asList()) - - assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \ - "Failed matching countedArray, got " + str(r.asList()) - -class CountedArrayTest3(ParseTestCase): - # test case where counter is not a decimal integer - def runTest(self): - from pyparsing import Word,nums,OneOrMore,countedArray,alphas - int_chars = "_"+alphas - array_counter = Word(int_chars).setParseAction(lambda t: int_chars.index(t[0])) - - # 123456789012345678901234567890 - testString = "B 5 7 F 0 1 2 3 4 5 _ C 5 4 3" - - integer = Word(nums).setParseAction(lambda t: int(t[0])) - countedField = countedArray(integer, intExpr=array_counter) - - r = OneOrMore(countedField).parseString( testString ) - print_(testString) - print_(r.asList()) - - assert r.asList() == [[5,7],[0,1,2,3,4,5],[],[5,4,3]], \ - "Failed matching countedArray, got " + str(r.asList()) - -class LineAndStringEndTest(ParseTestCase): - def runTest(self): - from pyparsing import OneOrMore,lineEnd,alphanums,Word,stringEnd,delimitedList,SkipTo - - NLs = OneOrMore(lineEnd) - bnf1 = delimitedList(Word(alphanums).leaveWhitespace(), NLs) - bnf2 = Word(alphanums) + stringEnd - bnf3 = Word(alphanums) + SkipTo(stringEnd) - tests = [ - ("testA\ntestB\ntestC\n", ['testA', 'testB', 'testC']), - ("testD\ntestE\ntestF", ['testD', 'testE', 'testF']), - ("a", ['a']), - ] - - for test,expected in tests: - res1 = bnf1.parseString(test) - print_(res1,'=?',expected) - assert res1.asList() == expected, "Failed lineEnd/stringEnd test (1): "+repr(test)+ " -> "+str(res1.asList()) - - res2 = bnf2.searchString(test)[0] - print_(res2.asList(),'=?',expected[-1:]) - assert res2.asList() == expected[-1:], "Failed lineEnd/stringEnd test (2): "+repr(test)+ " -> "+str(res2.asList()) - - res3 = bnf3.parseString(test) - first = res3[0] - rest = res3[1] - #~ print res3.dump() - print_(repr(rest),'=?',repr(test[len(first)+1:])) - assert rest == test[len(first)+1:]#, "Failed lineEnd/stringEnd test (3): " +repr(test)+ " -> "+str(res3[1].asList()) - print_() - - from pyparsing import Regex - import re - - k = Regex(r'a+',flags=re.S+re.M) - k = k.parseWithTabs() - k = k.leaveWhitespace() - - tests = [ - (r'aaa',['aaa']), - (r'\naaa',None), - (r'a\naa',None), - (r'aaa\n',None), - ] - for i,(src,expected) in enumerate(tests): - print_(i, repr(src).replace('\\\\','\\'), end=' ') - try: - res = k.parseString(src, parseAll=True).asList() - except ParseException as pe: - res = None - print_(res) - assert res == expected, "Failed on parseAll=True test %d" % i - -class VariableParseActionArgsTest(ParseTestCase): - def runTest(self): - - pa3 = lambda s,l,t: t - pa2 = lambda l,t: t - pa1 = lambda t: t - pa0 = lambda : None - class Callable3(object): - def __call__(self,s,l,t): - return t - class Callable2(object): - def __call__(self,l,t): - return t - class Callable1(object): - def __call__(self,t): - return t - class Callable0(object): - def __call__(self): - return - class CallableS3(object): - #~ @staticmethod - def __call__(s,l,t): - return t - __call__=staticmethod(__call__) - class CallableS2(object): - #~ @staticmethod - def __call__(l,t): - return t - __call__=staticmethod(__call__) - class CallableS1(object): - #~ @staticmethod - def __call__(t): - return t - __call__=staticmethod(__call__) - class CallableS0(object): - #~ @staticmethod - def __call__(): - return - __call__=staticmethod(__call__) - class CallableC3(object): - #~ @classmethod - def __call__(cls,s,l,t): - return t - __call__=classmethod(__call__) - class CallableC2(object): - #~ @classmethod - def __call__(cls,l,t): - return t - __call__=classmethod(__call__) - class CallableC1(object): - #~ @classmethod - def __call__(cls,t): - return t - __call__=classmethod(__call__) - class CallableC0(object): - #~ @classmethod - def __call__(cls): - return - __call__=classmethod(__call__) - - class parseActionHolder(object): - #~ @staticmethod - def pa3(s,l,t): - return t - pa3=staticmethod(pa3) - #~ @staticmethod - def pa2(l,t): - return t - pa2=staticmethod(pa2) - #~ @staticmethod - def pa1(t): - return t - pa1=staticmethod(pa1) - #~ @staticmethod - def pa0(): - return - pa0=staticmethod(pa0) - - def paArgs(*args): - print_(args) - return args[2] - - class ClassAsPA0(object): - def __init__(self): - pass - def __str__(self): - return "A" - - class ClassAsPA1(object): - def __init__(self,t): - print_("making a ClassAsPA1") - self.t = t - def __str__(self): - return self.t[0] - - class ClassAsPA2(object): - def __init__(self,l,t): - self.t = t - def __str__(self): - return self.t[0] - - class ClassAsPA3(object): - def __init__(self,s,l,t): - self.t = t - def __str__(self): - return self.t[0] - - class ClassAsPAStarNew(tuple): - def __new__(cls, *args): - print_("make a ClassAsPAStarNew", args) - return tuple.__new__(cls, *args[2].asList()) - def __str__(self): - return ''.join(self) - - #~ def ClassAsPANew(object): - #~ def __new__(cls, t): - #~ return object.__new__(cls, t) - #~ def __init__(self,t): - #~ self.t = t - #~ def __str__(self): - #~ return self.t - - from pyparsing import Literal,OneOrMore - - A = Literal("A").setParseAction(pa0) - B = Literal("B").setParseAction(pa1) - C = Literal("C").setParseAction(pa2) - D = Literal("D").setParseAction(pa3) - E = Literal("E").setParseAction(Callable0()) - F = Literal("F").setParseAction(Callable1()) - G = Literal("G").setParseAction(Callable2()) - H = Literal("H").setParseAction(Callable3()) - I = Literal("I").setParseAction(CallableS0()) - J = Literal("J").setParseAction(CallableS1()) - K = Literal("K").setParseAction(CallableS2()) - L = Literal("L").setParseAction(CallableS3()) - M = Literal("M").setParseAction(CallableC0()) - N = Literal("N").setParseAction(CallableC1()) - O = Literal("O").setParseAction(CallableC2()) - P = Literal("P").setParseAction(CallableC3()) - Q = Literal("Q").setParseAction(paArgs) - R = Literal("R").setParseAction(parseActionHolder.pa3) - S = Literal("S").setParseAction(parseActionHolder.pa2) - T = Literal("T").setParseAction(parseActionHolder.pa1) - U = Literal("U").setParseAction(parseActionHolder.pa0) - V = Literal("V") - - gg = OneOrMore( A | C | D | E | F | G | H | - I | J | K | L | M | N | O | P | Q | R | S | U | V | B | T) - testString = "VUTSRQPONMLKJIHGFEDCBA" - res = gg.parseString(testString) - print_(res.asList()) - assert res.asList()==list(testString), "Failed to parse using variable length parse actions" - - A = Literal("A").setParseAction(ClassAsPA0) - B = Literal("B").setParseAction(ClassAsPA1) - C = Literal("C").setParseAction(ClassAsPA2) - D = Literal("D").setParseAction(ClassAsPA3) - E = Literal("E").setParseAction(ClassAsPAStarNew) - - gg = OneOrMore( A | B | C | D | E | F | G | H | - I | J | K | L | M | N | O | P | Q | R | S | T | U | V) - testString = "VUTSRQPONMLKJIHGFEDCBA" - res = gg.parseString(testString) - print_(list(map(str,res))) - assert list(map(str,res))==list(testString), "Failed to parse using variable length parse actions using class constructors as parse actions" - -class EnablePackratParsing(ParseTestCase): - def runTest(self): - from pyparsing import ParserElement - ParserElement.enablePackrat() - -class SingleArgExceptionTest(ParseTestCase): - def runTest(self): - from pyparsing import ParseBaseException,ParseFatalException - - msg = "" - raisedMsg = "" - testMessage = "just one arg" - try: - raise ParseFatalException(testMessage) - except ParseBaseException as pbe: - print_("Received expected exception:", pbe) - raisedMsg = pbe.msg - assert raisedMsg == testMessage, "Failed to get correct exception message" - - -class OriginalTextForTest(ParseTestCase): - def runTest(self): - from pyparsing import makeHTMLTags, originalTextFor - - def rfn(t): - return "%s:%d" % (t.src, len("".join(t))) - - makeHTMLStartTag = lambda tag: originalTextFor(makeHTMLTags(tag)[0], asString=False) - - # use the lambda, Luke - #~ start, imge = makeHTMLTags('IMG') - start = makeHTMLStartTag('IMG') - - # don't replace our fancy parse action with rfn, - # append rfn to the list of parse actions - #~ start.setParseAction(rfn) - start.addParseAction(rfn) - - #start.setParseAction(lambda s,l,t:t.src) - text = '''_cal image_''' - s = start.transformString(text) - if VERBOSE: - print_(s) - assert s.startswith("_images/cal.png:"), "failed to preserve input s properly" - assert s.endswith("77_"),"failed to return full original text properly" - - tag_fields = makeHTMLStartTag("IMG").searchString(text)[0] - if VERBOSE: - print_(sorted(tag_fields.keys())) - assert sorted(tag_fields.keys()) == ['alt', 'empty', 'height', 'src', 'startImg', 'tag', 'width'], 'failed to preserve results names in originalTextFor' - - -class PackratParsingCacheCopyTest(ParseTestCase): - def runTest(self): - from pyparsing import Word,nums,ParserElement,delimitedList,Literal,Optional,alphas,alphanums,ZeroOrMore,empty - - integer = Word(nums).setName("integer") - id = Word(alphas+'_',alphanums+'_') - simpleType = Literal('int'); - arrayType= simpleType+ZeroOrMore('['+delimitedList(integer)+']') - varType = arrayType | simpleType - varDec = varType + delimitedList(id + Optional('='+integer))+';' - - codeBlock = Literal('{}') - - funcDef = Optional(varType | 'void')+id+'('+(delimitedList(varType+id)|'void'|empty)+')'+codeBlock - - program = varDec | funcDef - input = 'int f(){}' - results = program.parseString(input) - print_("Parsed '%s' as %s" % (input, results.asList())) - assert results.asList() == ['int', 'f', '(', ')', '{}'], "Error in packrat parsing" - -class PackratParsingCacheCopyTest2(ParseTestCase): - def runTest(self): - from pyparsing import Keyword,Word,Suppress,Forward,Optional,delimitedList,ParserElement,Group - - DO,AA = list(map(Keyword, "DO AA".split())) - LPAR,RPAR = list(map(Suppress,"()")) - identifier = ~AA + Word("Z") - - function_name = identifier.copy() - #~ function_name = ~AA + Word("Z") #identifier.copy() - expr = Forward().setName("expr") - expr << (Group(function_name + LPAR + Optional(delimitedList(expr)) + RPAR).setName("functionCall") | - identifier.setName("ident")#.setDebug()#.setBreak() - ) - - stmt = DO + Group(delimitedList(identifier + ".*" | expr)) - result = stmt.parseString("DO Z") - print_(result.asList()) - assert len(result[1]) == 1, "packrat parsing is duplicating And term exprs" - -class ParseResultsDelTest(ParseTestCase): - def runTest(self): - from pyparsing import OneOrMore, Word, alphas, nums - - grammar = OneOrMore(Word(nums))("ints") + OneOrMore(Word(alphas))("words") - res = grammar.parseString("123 456 ABC DEF") - print_(res.dump()) - origInts = res.ints.asList() - origWords = res.words.asList() - del res[1] - del res["words"] - print_(res.dump()) - assert res[1]=='ABC',"failed to delete 0'th element correctly" - assert res.ints.asList()==origInts, "updated named attributes, should have updated list only" - assert res.words=="", "failed to update named attribute correctly" - assert res[-1]=='DEF', "updated list, should have updated named attributes only" - -class WithAttributeParseActionTest(ParseTestCase): - def runTest(self): - """ - This unit test checks withAttribute in these ways: - - * Argument forms as keywords and tuples - * Selecting matching tags by attribute - * Case-insensitive attribute matching - * Correctly matching tags having the attribute, and rejecting tags not having the attribute - - (Unit test written by voigts as part of the Google Highly Open Participation Contest) - """ - - from pyparsing import makeHTMLTags, Word, withAttribute, withClass, nums - - data = """ - 1 - 2 - 3 - 4 - 5 - 8 - """ - tagStart, tagEnd = makeHTMLTags("a") - - expr = tagStart + Word(nums).setResultsName("value") + tagEnd - - expected = ([['a', ['b', 'x'], False, '2', ''], - ['a', ['b', 'x'], False, '3', '']], - [['a', ['b', 'x'], False, '2', ''], - ['a', ['b', 'x'], False, '3', '']], - [['a', ['class', 'boo'], False, '8', '']], - ) - - for attrib, exp in zip([ - withAttribute(b="x"), - #withAttribute(B="x"), - withAttribute(("b","x")), - #withAttribute(("B","x")), - withClass("boo"), - ], expected): - - tagStart.setParseAction(attrib) - result = expr.searchString(data) - - print_(result.dump()) - assert result.asList() == exp, "Failed test, expected %s, got %s" % (expected, result.asList()) - -class NestedExpressionsTest(ParseTestCase): - def runTest(self): - """ - This unit test checks nestedExpr in these ways: - - use of default arguments - - use of non-default arguments (such as a pyparsing-defined comment - expression in place of quotedString) - - use of a custom content expression - - use of a pyparsing expression for opener and closer is *OPTIONAL* - - use of input data containing nesting delimiters - - correct grouping of parsed tokens according to nesting of opening - and closing delimiters in the input string - - (Unit test written by christoph... as part of the Google Highly Open Participation Contest) - """ - from pyparsing import nestedExpr, Literal, Regex, restOfLine, quotedString - - #All defaults. Straight out of the example script. Also, qualifies for - #the bonus: note the fact that (Z | (E^F) & D) is not parsed :-). - # Tests for bug fixed in 1.4.10 - print_("Test defaults:") - teststring = "(( ax + by)*C) (Z | (E^F) & D)" - - expr = nestedExpr() - - expected = [[['ax', '+', 'by'], '*C']] - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected, "Defaults didn't work. That's a bad sign. Expected: %s, got: %s" % (expected, result) - - #Going through non-defaults, one by one; trying to think of anything - #odd that might not be properly handled. - - #Change opener - print_("\nNon-default opener") - opener = "[" - teststring = test_string = "[[ ax + by)*C)" - expected = [[['ax', '+', 'by'], '*C']] - expr = nestedExpr("[") - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected, "Non-default opener didn't work. Expected: %s, got: %s" % (expected, result) - - #Change closer - print_("\nNon-default closer") - - teststring = test_string = "(( ax + by]*C]" - expected = [[['ax', '+', 'by'], '*C']] - expr = nestedExpr(closer="]") - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected, "Non-default closer didn't work. Expected: %s, got: %s" % (expected, result) - - # #Multicharacter opener, closer - # opener = "bar" - # closer = "baz" - print_("\nLiteral expressions for opener and closer") - - opener,closer = list(map(Literal, "bar baz".split())) - expr = nestedExpr(opener, closer, - content=Regex(r"([^b ]|b(?!a)|ba(?![rz]))+")) - - teststring = "barbar ax + bybaz*Cbaz" - expected = [[['ax', '+', 'by'], '*C']] - # expr = nestedExpr(opener, closer) - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected, "Multicharacter opener and closer didn't work. Expected: %s, got: %s" % (expected, result) - - #Lisp-ish comments - print_("\nUse ignore expression (1)") - comment = Regex(r";;.*") - teststring = \ - """ - (let ((greeting "Hello, world!")) ;;(foo bar - (display greeting)) - """ - - expected = [['let', [['greeting', '"Hello,', 'world!"']], ';;(foo bar',\ - ['display', 'greeting']]] - expr = nestedExpr(ignoreExpr=comment) - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") didn't work. Expected: %s, got: %s" % (expected, result) - - - #Lisp-ish comments, using a standard bit of pyparsing, and an Or. - print_("\nUse ignore expression (2)") - comment = ';;' + restOfLine - - teststring = \ - """ - (let ((greeting "Hello, )world!")) ;;(foo bar - (display greeting)) - """ - - expected = [['let', [['greeting', '"Hello, )world!"']], ';;', '(foo bar', - ['display', 'greeting']]] - expr = nestedExpr(ignoreExpr=(comment ^ quotedString)) - result = expr.parseString(teststring) - print_(result.dump()) - assert result.asList() == expected , "Lisp-ish comments (\";; <...> $\") and quoted strings didn't work. Expected: %s, got: %s" % (expected, result) - -class WordExcludeTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, printables - allButPunc = Word(printables, excludeChars=".,:;-_!?") - - test = "Hello, Mr. Ed, it's Wilbur!" - result = allButPunc.searchString(test).asList() - print_(result) - assert result == [['Hello'], ['Mr'], ['Ed'], ["it's"], ['Wilbur']] - -class ParseAllTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, cppStyleComment - - testExpr = Word("A") - - tests = [ - ("AAAAA", False, True), - ("AAAAA", True, True), - ("AAABB", False, True), - ("AAABB", True, False), - ] - for s,parseAllFlag,shouldSucceed in tests: - try: - print_("'%s' parseAll=%s (shouldSuceed=%s)" % (s, parseAllFlag, shouldSucceed)) - testExpr.parseString(s,parseAllFlag) - assert shouldSucceed, "successfully parsed when should have failed" - except ParseException as pe: - assert not shouldSucceed, "failed to parse when should have succeeded" - - # add test for trailing comments - testExpr.ignore(cppStyleComment) - - tests = [ - ("AAAAA //blah", False, True), - ("AAAAA //blah", True, True), - ("AAABB //blah", False, True), - ("AAABB //blah", True, False), - ] - for s,parseAllFlag,shouldSucceed in tests: - try: - print_("'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)) - testExpr.parseString(s,parseAllFlag) - assert shouldSucceed, "successfully parsed when should have failed" - except ParseException as pe: - assert not shouldSucceed, "failed to parse when should have succeeded" - -class GreedyQuotedStringsTest(ParseTestCase): - def runTest(self): - from pyparsing import QuotedString, sglQuotedString, dblQuotedString, quotedString, delimitedList - - src = """\ - "string1", "strin""g2" - 'string1', 'string2' - ^string1^, ^string2^ - , """ - - testExprs = (sglQuotedString, dblQuotedString, quotedString, - QuotedString('"', escQuote='""'), QuotedString("'", escQuote="''"), - QuotedString("^"), QuotedString("<",endQuoteChar=">")) - for expr in testExprs: - strs = delimitedList(expr).searchString(src) - print_(strs) - assert bool(strs), "no matches found for test expression '%s'" % expr - for lst in strs: - assert len(lst) == 2, "invalid match found for test expression '%s'" % expr - - from pyparsing import alphas, nums, Word - src = """'ms1',1,0,'2009-12-22','2009-12-22 10:41:22') ON DUPLICATE KEY UPDATE sent_count = sent_count + 1, mtime = '2009-12-22 10:41:22';""" - tok_sql_quoted_value = ( - QuotedString("'", "\\", "''", True, False) ^ - QuotedString('"', "\\", '""', True, False)) - tok_sql_computed_value = Word(nums) - tok_sql_identifier = Word(alphas) - - val = tok_sql_quoted_value | tok_sql_computed_value | tok_sql_identifier - vals = delimitedList(val) - print_(vals.parseString(src)) - assert len(vals.parseString(src)) == 5, "error in greedy quote escaping" - - -class WordBoundaryExpressionsTest(ParseTestCase): - def runTest(self): - from pyparsing import WordEnd, WordStart, oneOf - - ws = WordStart() - we = WordEnd() - vowel = oneOf(list("AEIOUY")) - consonant = oneOf(list("BCDFGHJKLMNPQRSTVWXZ")) - - leadingVowel = ws + vowel - trailingVowel = vowel + we - leadingConsonant = ws + consonant - trailingConsonant = consonant + we - internalVowel = ~ws + vowel + ~we - - bnf = leadingVowel | trailingVowel - - tests = """\ - ABC DEF GHI - JKL MNO PQR - STU VWX YZ """.splitlines() - tests.append( "\n".join(tests) ) - - expectedResult = [ - [['D', 'G'], ['A'], ['C', 'F'], ['I'], ['E'], ['A', 'I']], - [['J', 'M', 'P'], [], ['L', 'R'], ['O'], [], ['O']], - [['S', 'V'], ['Y'], ['X', 'Z'], ['U'], [], ['U', 'Y']], - [['D', 'G', 'J', 'M', 'P', 'S', 'V'], - ['A', 'Y'], - ['C', 'F', 'L', 'R', 'X', 'Z'], - ['I', 'O', 'U'], - ['E'], - ['A', 'I', 'O', 'U', 'Y']], - ] - - for t,expected in zip(tests, expectedResult): - print_(t) - results = [flatten(e.searchString(t).asList()) for e in [ - leadingConsonant, - leadingVowel, - trailingConsonant, - trailingVowel, - internalVowel, - bnf, - ]] - print_(results) - assert results==expected,"Failed WordBoundaryTest, expected %s, got %s" % (expected,results) - print_() - -class RequiredEachTest(ParseTestCase): - def runTest(self): - from pyparsing import Keyword - - parser = Keyword('bam') & Keyword('boo') - try: - res1 = parser.parseString('bam boo') - print_(res1.asList()) - res2 = parser.parseString('boo bam') - print_(res2.asList()) - except ParseException: - failed = True - else: - failed = False - assert not failed, "invalid logic in Each" - - assert set(res1) == set(res2), "Failed RequiredEachTest, expected " + \ - str(res1.asList()) + " and " + str(res2.asList()) + "to contain same words in any order" - -class OptionalEachTest(ParseTestCase): - def runTest1(self): - from pyparsing import Optional, Keyword - - the_input = "Major Tal Weiss" - parser1 = (Optional('Tal') + Optional('Weiss')) & Keyword('Major') - parser2 = Optional(Optional('Tal') + Optional('Weiss')) & Keyword('Major') - p1res = parser1.parseString( the_input) - p2res = parser2.parseString( the_input) - assert p1res.asList() == p2res.asList(), "Each failed to match with nested Optionals, " + \ - str(p1res.asList()) + " should match " + str(p2res.asList()) - - - def runTest2(self): - from pyparsing import Word, alphanums, Suppress, OneOrMore, Group, Regex, Optional - - word = Word(alphanums + '_').setName("word") - with_stmt = 'with' + OneOrMore(Group(word('key') + '=' + word('value')))('overrides') - using_stmt = 'using' + Regex('id-[0-9a-f]{8}')('id') - modifiers = Optional(with_stmt('with_stmt')) & Optional(using_stmt('using_stmt')) - - assert modifiers == "with foo=bar bing=baz using id-deadbeef" - assert not modifiers == "with foo=bar bing=baz using id-deadbeef using id-feedfeed" - - def runTest(self): - self.runTest1() - self.runTest2() - -class SumParseResultsTest(ParseTestCase): - def runTest(self): - - 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" - - res1 = "ID:PARI12345678 DOB:10-10-2010 INFO:" - res2 = "ID:PARI12345678 DOB:10-10-2010 INFO:" - res3 = "ID: DOB:10-10-2010 INFO:" - res4 = "ID:PARI12345678 DOB: INFO: I am cool" - - from pyparsing import Regex, Word, alphanums, restOfLine - 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 - - tests = (samplestr1,samplestr2,samplestr3,samplestr4,) - results = (res1, res2, res3, res4,) - for test,expected in zip(tests, results): - person = sum(person_data.searchString(test)) - result = "ID:%s DOB:%s INFO:%s" % (person.id, person.dob, person.info) - print_(test) - print_(expected) - print_(result) - for pd in person_data.searchString(test): - print_(pd.dump()) - print_() - assert expected == result, \ - "Failed to parse '%s' correctly, \nexpected '%s', got '%s'" % (test,expected,result) - -class MarkInputLineTest(ParseTestCase): - def runTest(self): - - samplestr1 = "DOB 100-10-2010;more garbage\nID PARI12345678;more garbage" - - from pyparsing import Regex, Word, alphanums, restOfLine - dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob") - - try: - res = dob_ref.parseString(samplestr1) - except ParseException as pe: - outstr = pe.markInputline() - print_(outstr) - assert outstr == "DOB >!<100-10-2010;more garbage", "did not properly create marked input line" - else: - assert False, "test construction failed - should have raised an exception" - -class LocatedExprTest(ParseTestCase): - def runTest(self): - - # 012345678901234567890123456789012345678901234567890 - samplestr1 = "DOB 10-10-2010;more garbage;ID PARI12345678 ;more garbage" - - from pyparsing import Regex, Word, alphanums, restOfLine, locatedExpr - id_ref = locatedExpr("ID" + Word(alphanums,exact=12)("id")) - - res = id_ref.searchString(samplestr1)[0][0] - print_(res.dump()) - assert samplestr1[res.locn_start:res.locn_end] == 'ID PARI12345678', "incorrect location calculation" - - -class PopTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, alphas, nums - - source = "AAA 123 456 789 234" - patt = Word(alphas)("name") + Word(nums)*(1,) - - result = patt.parseString(source) - tests = [ - (0, 'AAA', ['123', '456', '789', '234']), - (None, '234', ['123', '456', '789']), - ('name', 'AAA', ['123', '456', '789']), - (-1, '789', ['123', '456']), - ] - for test in tests: - idx, val, remaining = test - if idx is not None: - ret = result.pop(idx) - else: - ret = result.pop() - print_("EXP:", val, remaining) - print_("GOT:", ret, result.asList()) - print_(ret, result.asList()) - assert ret == val, "wrong value returned, got %r, expected %r" % (ret, val) - assert remaining == result.asList(), "list is in wrong state after pop, got %r, expected %r" % (result.asList(), remaining) - print_() - - prevlist = result.asList() - ret = result.pop('name', default="noname") - print_(ret) - print_(result.asList()) - assert ret == "noname", "default value not successfully returned, got %r, expected %r" % (ret, "noname") - assert result.asList() == prevlist, "list is in wrong state after pop, got %r, expected %r" % (result.asList(), remaining) - - -class AddConditionTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, alphas, nums, Suppress, ParseFatalException - - numParser = Word(nums) - numParser.addParseAction(lambda s,l,t: int(t[0])) - numParser.addCondition(lambda s,l,t: t[0] % 2) - numParser.addCondition(lambda s,l,t: t[0] >= 7) - - result = numParser.searchString("1 2 3 4 5 6 7 8 9 10") - print_(result.asList()) - assert result.asList() == [[7],[9]], "failed to properly process conditions" - - numParser = Word(nums) - numParser.addParseAction(lambda s,l,t: int(t[0])) - rangeParser = (numParser("from_") + Suppress('-') + numParser("to")) - - result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") - print_(result.asList()) - assert result.asList() == [[1, 4], [2, 4], [4, 3]], "failed to properly process conditions" - - rangeParser.addCondition(lambda t: t.to > t.from_, message="from must be <= to", fatal=False) - result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") - print_(result.asList()) - assert result.asList() == [[1, 4], [2, 4]], "failed to properly process conditions" - - rangeParser = (numParser("from_") + Suppress('-') + numParser("to")) - rangeParser.addCondition(lambda t: t.to > t.from_, message="from must be <= to", fatal=True) - try: - result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") - assert False, "failed to interrupt parsing on fatal condition failure" - except ParseFatalException: - print_("detected fatal condition") - -class PatientOrTest(ParseTestCase): - def runTest(self): - import pyparsing as pp - - # Two expressions and a input string which could - syntactically - be matched against - # both expressions. The "Literal" expression is considered invalid though, so this PE - # should always detect the "Word" expression. - def validate(token): - if token[0] == "def": - raise pp.ParseException("signalling invalid token") - return token - - a = pp.Word("de").setName("Word")#.setDebug() - b = pp.Literal("def").setName("Literal").setParseAction(validate)#.setDebug() - c = pp.Literal("d").setName("d")#.setDebug() - - # The "Literal" expressions's ParseAction is not executed directly after syntactically - # detecting the "Literal" Expression but only after the Or-decision has been made - # (which is too late)... - try: - result = (a ^ b ^ c).parseString("def") - assert result.asList() == ['de'], "failed to select longest match, chose %s" % result - except ParseException: - failed = True - else: - failed = False - assert not failed, "invalid logic in Or, fails on longest match with exception in parse action" - -class EachWithOptionalWithResultsNameTest(ParseTestCase): - def runTest(self): - from pyparsing import Optional - - result = (Optional('foo')('one') & Optional('bar')('two')).parseString('bar foo') - print_(result.dump()) - assert sorted(result.keys()) == ['one','two'] - -class UnicodeExpressionTest(ParseTestCase): - def runTest(self): - from pyparsing import Literal, ParseException - - z = 'a' | Literal(u'\u1111') - z.streamline() - try: - z.parseString('b') - except ParseException as pe: - if not PY_3: - assert pe.msg == r'''Expected {"a" | "\u1111"}''', "Invalid error message raised, got %r" % pe.msg - -class SetNameTest(ParseTestCase): - def runTest(self): - from pyparsing import (oneOf,infixNotation,Word,nums,opAssoc,delimitedList,countedArray, - nestedExpr,makeHTMLTags,anyOpenTag,anyCloseTag,commonHTMLEntity,replaceHTMLEntity) - - a = oneOf("a b c") - b = oneOf("d e f") - arith_expr = infixNotation(Word(nums), - [ - (oneOf('* /'),2,opAssoc.LEFT), - (oneOf('+ -'),2,opAssoc.LEFT), - ]) - arith_expr2 = infixNotation(Word(nums), - [ - (('?',':'),3,opAssoc.LEFT), - ]) - - tests = [ - a, - b, - (a | b), - arith_expr, - arith_expr.expr, - arith_expr2, - arith_expr2.expr, - delimitedList(Word(nums).setName("int")), - countedArray(Word(nums).setName("int")), - nestedExpr(), - makeHTMLTags('Z'), - (anyOpenTag,anyCloseTag), - commonHTMLEntity, - commonHTMLEntity.setParseAction(replaceHTMLEntity).transformString("lsdjkf <lsdjkf>&'"&xyzzy;"), - ] - - expected = map(str.strip, """\ - a | b | c - d | e | f - {a | b | c | d | e | f} - Forward: ... - + | - term - Forward: ... - ?: term - int [, int]... - (len) int... - nested () expression - (, ) - (, ) - common HTML entity - lsdjkf &'"&xyzzy;""".splitlines()) - - for t,e in zip(tests, expected): - tname = str(t) - assert tname==e, "expression name mismatch, expected {} got {}".format(e, tname) - -class TrimArityExceptionMaskingTest(ParseTestCase): - def runTest(self): - from pyparsing import Word - - invalid_message = [ - "() takes exactly 1 argument (0 given)", - "() missing 1 required positional argument: 't'" - ][PY_3] - try: - Word('a').setParseAction(lambda t: t[0]+1).parseString('aaa') - except Exception as e: - exc_msg = str(e) - assert exc_msg != invalid_message, "failed to catch TypeError thrown in _trim_arity" - -class OneOrMoreStopTest(ParseTestCase): - def runTest(self): - from pyparsing import (Word, OneOrMore, alphas, Keyword, CaselessKeyword, - nums, alphanums) - - test = "BEGIN aaa bbb ccc END" - BEGIN,END = map(Keyword, "BEGIN,END".split(',')) - body_word = Word(alphas).setName("word") - for ender in (END, "END", CaselessKeyword("END")): - expr = BEGIN + OneOrMore(body_word, stopOn=ender) + END - assert test == expr, "Did not successfully stop on ending expression %r" % ender - - number = Word(nums+',.()').setName("number with optional commas") - parser= (OneOrMore(Word(alphanums+'-/.'), stopOn=number)('id').setParseAction(' '.join) - + number('data')) - result = parser.parseString(' XXX Y/123 1,234.567890') - assert result.asList() == ['XXX Y/123', '1,234.567890'], "Did not successfully stop on ending expression %r" % number - -class ZeroOrMoreStopTest(ParseTestCase): - def runTest(self): - from pyparsing import (Word, ZeroOrMore, alphas, Keyword, CaselessKeyword) - - test = "BEGIN END" - BEGIN,END = map(Keyword, "BEGIN,END".split(',')) - body_word = Word(alphas).setName("word") - for ender in (END, "END", CaselessKeyword("END")): - expr = BEGIN + ZeroOrMore(body_word, stopOn=ender) + END - assert test == expr, "Did not successfully stop on ending expression %r" % ender - -class NestedAsDictTest(ParseTestCase): - def runTest(self): - from pyparsing import Literal, Forward, alphanums, Group, delimitedList, Dict, Word, Optional - - equals = Literal("=").suppress() - lbracket = Literal("[").suppress() - rbracket = Literal("]").suppress() - lbrace = Literal("{").suppress() - rbrace = Literal("}").suppress() - - value_dict = Forward() - value_list = Forward() - value_string = Word(alphanums + "@. ") - - value = value_list ^ value_dict ^ value_string - values = Group(delimitedList(value, ",")) - #~ values = delimitedList(value, ",").setParseAction(lambda toks: [toks.asList()]) - - value_list << lbracket + values + rbracket - - identifier = Word(alphanums + "_.") - - assignment = Group(identifier + equals + Optional(value)) - assignments = Dict(delimitedList(assignment, ';')) - value_dict << lbrace + assignments + rbrace - - response = assignments - - rsp = 'username=goat; errors={username=[already taken, too short]}; empty_field=' - result_dict = response.parseString(rsp).asDict() - print_(result_dict) - assert result_dict['username'] == 'goat', "failed to process string in ParseResults correctly" - assert result_dict['errors']['username'] == ['already taken', 'too short'], "failed to process nested ParseResults correctly" - -class TraceParseActionDecoratorTest(ParseTestCase): - def runTest(self): - from pyparsing import traceParseAction, Word, nums - - @traceParseAction - def convert_to_int(t): - return int(t[0]) - - class Z(object): - def __call__(self, other): - return other[0] * 1000 - - integer = Word(nums).addParseAction(convert_to_int) - integer.addParseAction(traceParseAction(lambda t: t[0]*10)) - integer.addParseAction(traceParseAction(Z())) - integer.parseString("132") - -class RunTestsTest(ParseTestCase): - def runTest(self): - from pyparsing import Word, nums, delimitedList - - integer = Word(nums).setParseAction(lambda t : int(t[0])) - intrange = integer("start") + '-' + integer("end") - intrange.addCondition(lambda t: t.end > t.start, message="invalid range, start must be <= end", fatal=True) - intrange.addParseAction(lambda t: list(range(t.start, t.end+1))) - - indices = delimitedList(intrange | integer) - indices.addParseAction(lambda t: sorted(set(t))) - - tests = """\ - # normal data - 1-3,2-4,6,8-10,16 - - # lone integer - 11""" - results = indices.runTests(tests, printResults=False)[1] - - expectedResults = [ - [1, 2, 3, 4, 6, 8, 9, 10, 16], - [11], - ] - for res,expected in zip(results, expectedResults): - print_(res[1].asList()) - print_(expected) - assert res[1].asList() == expected, "failed test: " + expected[0][2:] - - - tests = """\ - # invalid range - 1-2, 3-1, 4-6, 7, 12 - """ - success = indices.runTests(tests, printResults=False, failureTests=True)[0] - assert success, "failed to raise exception on improper range test" - -class CommonExpressionsTest(ParseTestCase): - def runTest(self): - from pyparsing import pyparsing_common - - success = pyparsing_common.mac_address.runTests(""" - AA:BB:CC:DD:EE:FF - AA.BB.CC.DD.EE.FF - AA-BB-CC-DD-EE-FF - """)[0] - assert success, "error in parsing valid MAC address" - - success = pyparsing_common.mac_address.runTests(""" - # mixed delimiters - AA.BB:CC:DD:EE:FF - """, failureTests=True)[0] - assert success, "error in detecting invalid mac address" - - success = pyparsing_common.ipv4_address.runTests(""" - 0.0.0.0 - 1.1.1.1 - 127.0.0.1 - 1.10.100.199 - 255.255.255.255 - """)[0] - assert success, "error in parsing valid IPv4 address" - - success = pyparsing_common.ipv4_address.runTests(""" - # out of range value - 256.255.255.255 - """, failureTests=True)[0] - assert success, "error in detecting invalid IPv4 address" - - success = pyparsing_common.ipv6_address.runTests(""" - 2001:0db8:85a3:0000:0000:8a2e:0370:7334 - 2134::1234:4567:2468:1236:2444:2106 - 0:0:0:0:0:0:A00:1 - 1080::8:800:200C:417A - ::A00:1 - - # loopback address - ::1 - - # the null address - :: - - # ipv4 compatibility form - ::ffff:192.168.0.1 - """)[0] - assert success, "error in parsing valid IPv6 address" - - success = pyparsing_common.ipv6_address.runTests(""" - # too few values - 1080:0:0:0:8:800:200C - - # too many ::'s, only 1 allowed - 2134::1234:4567::2444:2106 - """, failureTests=True)[0] - assert success, "error in detecting invalid IPv6 address" - - success = pyparsing_common.number.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """)[0] - assert success, "error in parsing valid numerics" - - # any int or real number, returned as float - success = pyparsing_common.fnumber.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """)[0] - assert success, "error in parsing valid numerics" - - success, results = pyparsing_common.iso8601_date.runTests(""" - 1997 - 1997-07 - 1997-07-16 - """) - assert success, "error in parsing valid iso8601_date" - expected = [ - ('1997', None, None), - ('1997', '07', None), - ('1997', '07', '16'), - ] - for r,exp in zip(results, expected): - assert (r[1].year,r[1].month,r[1].day,) == exp, "failed to parse date into fields" - - success, results = pyparsing_common.iso8601_date().addParseAction(pyparsing_common.convertToDate()).runTests(""" - 1997-07-16 - """) - assert success, "error in parsing valid iso8601_date with parse action" - assert results[0][1][0] == datetime.date(1997, 7, 16) - - success, results = pyparsing_common.iso8601_datetime.runTests(""" - 1997-07-16T19:20+01:00 - 1997-07-16T19:20:30+01:00 - 1997-07-16T19:20:30.45Z - 1997-07-16 19:20:30.45 - """) - assert success, "error in parsing valid iso8601_datetime" - - success, results = pyparsing_common.iso8601_datetime().addParseAction(pyparsing_common.convertToDatetime()).runTests(""" - 1997-07-16T19:20:30.45 - """) - assert success, "error in parsing valid iso8601_datetime" - assert results[0][1][0] == datetime.datetime(1997, 7, 16, 19, 20, 30, 450000) - - success = pyparsing_common.uuid.runTests(""" - 123e4567-e89b-12d3-a456-426655440000 - """)[0] - assert success, "failed to parse valid uuid" - - - success = pyparsing_common.fraction.runTests(""" - 1/2 - -15/16 - -3/-4 - """)[0] - assert success, "failed to parse valid fraction" - - - success = pyparsing_common.mixed_integer.runTests(""" - 1/2 - -15/16 - -3/-4 - 1 1/2 - 2 -15/16 - 0 -3/-4 - 12 - """)[0] - assert success, "failed to parse valid mixed integer" - - success, results = pyparsing_common.number.runTests(""" - 100 - -3 - 1.732 - -3.14159 - 6.02e23""") - assert success, "failed to parse numerics" - for test,result in results: - expected = eval(test) - assert result[0] == expected, "numeric parse failed (wrong value) (%s should be %s)" % (result[0], expected) - assert type(result[0]) == type(expected), "numeric parse failed (wrong type) (%s should be %s)" % (type(result[0]), type(expected)) - - -class TokenMapTest(ParseTestCase): - def runTest(self): - from pyparsing import tokenMap, Word, hexnums, OneOrMore - - parser = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) - success, results = parser.runTests(""" - 00 11 22 aa FF 0a 0d 1a - """, printResults=False) - assert success, "failed to parse hex integers" - print_(results) - assert results[0][-1].asList() == [0, 17, 34, 170, 255, 10, 13, 26], "tokenMap parse action failed" - - -class ParseFileTest(ParseTestCase): - def runTest(self): - from pyparsing import pyparsing_common, OneOrMore - s = """ - 123 456 789 - """ - input_file = StringIO(s) - integer = pyparsing_common.integer - - results = OneOrMore(integer).parseFile(input_file) - print_(results) - - results = OneOrMore(integer).parseFile('test/parsefiletest_input_file.txt') - print_(results) - - -class HTMLStripperTest(ParseTestCase): - def runTest(self): - from pyparsing import pyparsing_common, originalTextFor, OneOrMore, Word, printables - - sample = """ - - Here is some sample HTML text. - - """ - read_everything = originalTextFor(OneOrMore(Word(printables))) - read_everything.addParseAction(pyparsing_common.stripHTMLTags) - - result = read_everything.parseString(sample) - assert result[0].strip() == 'Here is some sample HTML text.' - -class ExprSplitterTest(ParseTestCase): - def runTest(self): - - from pyparsing import Literal, quotedString, pythonStyleComment, Empty - - expr = Literal(';') + Empty() - expr.ignore(quotedString) - expr.ignore(pythonStyleComment) - - - sample = """ - def main(): - this_semi_does_nothing(); - neither_does_this_but_there_are_spaces_afterward(); - a = "a;b"; return a # this is a comment; it has a semicolon! - - def b(): - if False: - z=1000;b("; in quotes"); c=200;return z - return ';' - - class Foo(object): - def bar(self): - '''a docstring; with a semicolon''' - a = 10; b = 11; c = 12 - - # this comment; has several; semicolons - if self.spam: - x = 12; return x # so; does; this; one - x = 15;;; y += x; return y - - def baz(self): - return self.bar - """ - expected = [ - [' this_semi_does_nothing()', ''], - [' neither_does_this_but_there_are_spaces_afterward()', ''], - [' a = "a;b"', 'return a # this is a comment; it has a semicolon!'], - [' z=1000', 'b("; in quotes")', 'c=200', 'return z'], - [" return ';'"], - [" '''a docstring; with a semicolon'''"], - [' a = 10', 'b = 11', 'c = 12'], - [' # this comment; has several; semicolons'], - [' x = 12', 'return x # so; does; this; one'], - [' x = 15', '', '', 'y += x', 'return y'], - ] - - exp_iter = iter(expected) - for line in filter(lambda ll: ';' in ll, sample.splitlines()): - print_(str(list(expr.split(line)))+',') - assert list(expr.split(line)) == next(exp_iter), "invalid split on expression" - - print_() - - expected = [ - [' this_semi_does_nothing()', ';', ''], - [' neither_does_this_but_there_are_spaces_afterward()', ';', ''], - [' a = "a;b"', ';', 'return a # this is a comment; it has a semicolon!'], - [' z=1000', ';', 'b("; in quotes")', ';', 'c=200', ';', 'return z'], - [" return ';'"], - [" '''a docstring; with a semicolon'''"], - [' a = 10', ';', 'b = 11', ';', 'c = 12'], - [' # this comment; has several; semicolons'], - [' x = 12', ';', 'return x # so; does; this; one'], - [' x = 15', ';', '', ';', '', ';', 'y += x', ';', 'return y'], - ] - exp_iter = iter(expected) - for line in filter(lambda ll: ';' in ll, sample.splitlines()): - print_(str(list(expr.split(line, includeSeparators=True)))+',') - assert list(expr.split(line, includeSeparators=True)) == next(exp_iter), "invalid split on expression" - - print_() - - - expected = [ - [' this_semi_does_nothing()', ''], - [' neither_does_this_but_there_are_spaces_afterward()', ''], - [' a = "a;b"', 'return a # this is a comment; it has a semicolon!'], - [' z=1000', 'b("; in quotes"); c=200;return z'], - [' a = 10', 'b = 11; c = 12'], - [' x = 12', 'return x # so; does; this; one'], - [' x = 15', ';; y += x; return y'], - ] - exp_iter = iter(expected) - for line in sample.splitlines(): - pieces = list(expr.split(line, maxsplit=1)) - print_(str(pieces)+',') - if len(pieces) == 2: - exp = next(exp_iter) - assert pieces == exp, "invalid split on expression with maxSplits=1" - elif len(pieces) == 1: - assert len(expr.searchString(line)) == 0, "invalid split with maxSplits=1 when expr not present" - else: - print_("\n>>> " + line) - assert False, "invalid split on expression with maxSplits=1, corner case" - - -class MiscellaneousParserTests(ParseTestCase): - def runTest(self): - import pyparsing - - runtests = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - if IRON_PYTHON_ENV: - runtests = "ABCDEGHIJKLMNOPQRSTUVWXYZ" - - # test making oneOf with duplicate symbols - if "A" in runtests: - print_("verify oneOf handles duplicate symbols") - try: - test1 = pyparsing.oneOf("a b c d a") - except RuntimeError: - assert False,"still have infinite loop in oneOf with duplicate symbols" - - # test MatchFirst bugfix - if "B" in runtests: - print_("verify MatchFirst iterates properly") - results = pyparsing.quotedString.parseString("'this is a single quoted string'") - assert len(results) > 0, "MatchFirst error - not iterating over all choices" - - # verify streamline of subexpressions - if "C" in runtests: - print_("verify proper streamline logic") - compound = pyparsing.Literal("A") + "B" + "C" + "D" - assert len(compound.exprs) == 2,"bad test setup" - print_(compound) - compound.streamline() - print_(compound) - assert len(compound.exprs) == 4,"streamline not working" - - # test for Optional with results name and no match - if "D" in runtests: - print_("verify Optional's do not cause match failure if have results name") - testGrammar = pyparsing.Literal("A") + pyparsing.Optional("B").setResultsName("gotB") + pyparsing.Literal("C") - try: - testGrammar.parseString("ABC") - testGrammar.parseString("AC") - except pyparsing.ParseException as pe: - print_(pe.pstr,"->",pe) - assert False, "error in Optional matching of string %s" % pe.pstr - - # test return of furthest exception - if "E" in runtests: - testGrammar = ( pyparsing.Literal("A") | - ( pyparsing.Optional("B") + pyparsing.Literal("C") ) | - pyparsing.Literal("D") ) - try: - testGrammar.parseString("BC") - testGrammar.parseString("BD") - except pyparsing.ParseException as pe: - print_(pe.pstr,"->",pe) - assert pe.pstr == "BD", "wrong test string failed to parse" - assert pe.loc == 1, "error in Optional matching, pe.loc="+str(pe.loc) - - # test validate - if "F" in runtests: - print_("verify behavior of validate()") - def testValidation( grmr, gnam, isValid ): - try: - grmr.streamline() - grmr.validate() - assert isValid,"validate() accepted invalid grammar " + gnam - except pyparsing.RecursiveGrammarException as e: - print_(grmr) - assert not isValid, "validate() rejected valid grammar " + gnam - - fwd = pyparsing.Forward() - g1 = pyparsing.OneOrMore( ( pyparsing.Literal("A") + "B" + "C" ) | fwd ) - g2 = pyparsing.ZeroOrMore("C" + g1) - fwd << pyparsing.Group(g2) - testValidation( fwd, "fwd", isValid=True ) - - fwd2 = pyparsing.Forward() - fwd2 << pyparsing.Group("A" | fwd2) - testValidation( fwd2, "fwd2", isValid=False ) - - fwd3 = pyparsing.Forward() - fwd3 << pyparsing.Optional("A") + fwd3 - testValidation( fwd3, "fwd3", isValid=False ) - - # test getName - if "G" in runtests: - print_("verify behavior of getName()") - aaa = pyparsing.Group(pyparsing.Word("a")).setResultsName("A") - bbb = pyparsing.Group(pyparsing.Word("b")).setResultsName("B") - ccc = pyparsing.Group(":" + pyparsing.Word("c")).setResultsName("C") - g1 = "XXX" + pyparsing.ZeroOrMore( aaa | bbb | ccc ) - teststring = "XXX b b a b b a b :c b a" - names = [] - print_(g1.parseString(teststring).dump()) - for t in g1.parseString(teststring): - print_(t, repr(t)) - try: - names.append( t[0].getName() ) - except: - try: - names.append( t.getName() ) - except: - names.append( None ) - print_(teststring) - print_(names) - assert names==[None, 'B', 'B', 'A', 'B', 'B', 'A', 'B', 'C', 'B', 'A'], \ - "failure in getting names for tokens" - - # test ParseResults.get() method - if "H" in runtests: - print_("verify behavior of ParseResults.get()") - res = g1.parseString(teststring) - print_(res.get("A","A not found")[0]) - print_(res.get("D","!D")) - assert res.get("A","A not found")[0] == "a", "get on existing key failed" - assert res.get("D","!D") == "!D", "get on missing key failed" - - if "I" in runtests: - print_("verify handling of Optional's beyond the end of string") - testGrammar = "A" + pyparsing.Optional("B") + pyparsing.Optional("C") + pyparsing.Optional("D") - testGrammar.parseString("A") - testGrammar.parseString("AB") - - # test creating Literal with empty string - if "J" in runtests: - print_('verify non-fatal usage of Literal("")') - e = pyparsing.Literal("") - try: - e.parseString("SLJFD") - except Exception as e: - assert False, "Failed to handle empty Literal" - - # test line() behavior when starting at 0 and the opening line is an \n - if "K" in runtests: - print_('verify correct line() behavior when first line is empty string') - assert pyparsing.line(0, "\nabc\ndef\n") == '', "Error in line() with empty first line in text" - txt = "\nabc\ndef\n" - results = [ pyparsing.line(i,txt) for i in range(len(txt)) ] - assert results == ['', 'abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], "Error in line() with empty first line in text" - txt = "abc\ndef\n" - results = [ pyparsing.line(i,txt) for i in range(len(txt)) ] - assert results == ['abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], "Error in line() with non-empty first line in text" - - # test bugfix with repeated tokens when packrat parsing enabled - if "L" in runtests: - a = pyparsing.Literal("a") - b = pyparsing.Literal("b") - c = pyparsing.Literal("c") - - abb = a + b + b - abc = a + b + c - aba = a + b + a - grammar = abb | abc | aba - - assert ''.join(grammar.parseString( "aba" )) == 'aba', "Packrat ABA failure!" - -def makeTestSuite(): - import inspect - suite = TestSuite() - suite.addTest( PyparsingTestInit() ) - - test_case_classes = ParseTestCase.__subclasses__() - # put classes in order as they are listed in the source code - test_case_classes.sort(key=lambda cls: inspect.getsourcelines(cls)[1]) - - test_case_classes.remove(PyparsingTestInit) - # test_case_classes.remove(ParseASMLTest) - test_case_classes.remove(EnablePackratParsing) - if IRON_PYTHON_ENV: - test_case_classes.remove(OriginalTextForTest) - - suite.addTests(T() for T in test_case_classes) - - if TEST_USING_PACKRAT: - # retest using packrat parsing (disable those tests that aren't compatible) - suite.addTest( EnablePackratParsing() ) - - unpackrattables = [ EnablePackratParsing, RepeaterTest, ] - - # add tests to test suite a second time, to run with packrat parsing - # (leaving out those that we know wont work with packrat) - packratTests = [t.__class__() for t in suite._tests - if t.__class__ not in unpackrattables] - suite.addTests( packratTests ) - - return suite - -def makeTestSuiteTemp(classes): - suite = TestSuite() - suite.addTest( PyparsingTestInit() ) - for cls in classes: - suite.addTest( cls() ) - return suite - -console = False -console = True - -#~ from line_profiler import LineProfiler -#~ from pyparsing import ParseResults -#~ lp = LineProfiler(ParseResults.__setitem__) -lp = None - -#~ if __name__ == '__main__': - #~ unittest.main() -if console: - #~ # console mode - testRunner = TextTestRunner() - - testclasses = [] - #~ testclasses.append(put_test_class_here) - #~ testclasses.append(RequiredEachTest) - if not testclasses: - testRunner.run( makeTestSuite() ) - else: - if lp is None: - testRunner.run( makeTestSuiteTemp(testclasses) ) - else: - lp.run("testRunner.run( makeTestSuite(%s) )" % testclass.__name__) -else: - # HTML mode - outfile = "testResults.html" - outstream = file(outfile,"w") - testRunner = HTMLTestRunner.HTMLTestRunner( stream=outstream ) - testRunner.run( makeTestSuite() ) - outstream.close() - - import os - os.system(r'"C:\Program Files\Internet Explorer\iexplore.exe" file://' + outfile) - -#~ lp.print_stats() diff --git a/trunk/src/update_pyparsing_timestamp.py b/trunk/src/update_pyparsing_timestamp.py deleted file mode 100644 index 80ea3d4..0000000 --- a/trunk/src/update_pyparsing_timestamp.py +++ /dev/null @@ -1,17 +0,0 @@ -from pyparsing import quotedString -from datetime import datetime - -nw = datetime.utcnow() -nowstring = '"%s"' % (nw.strftime("%d %b %Y %X")[:-3] + " UTC") -print (nowstring) - -quoted_time = quotedString() -quoted_time.setParseAction(lambda: nowstring) - -version_time = "__versionTime__ = " + quoted_time -with open('pyparsing.py') as oldpp: - new_code = version_time.transformString(oldpp.read()) - -with open('pyparsing.py','w') as newpp: - newpp.write(new_code) - -- cgit v1.2.1