summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorJon Dufresne <jon.dufresne@gmail.com>2019-10-31 21:10:28 -0700
committerPaul McGuire <ptmcg@users.noreply.github.com>2019-10-31 23:10:28 -0500
commit53d1b4a6f48a53c4c4ec4ac7031362b691c0366d (patch)
tree088ad3cf3561b78a00af4fb2fd474f4a2b8ca70c /examples
parent41752aa52cc97c710474bb2972cceab057b52ad4 (diff)
downloadpyparsing-git-53d1b4a6f48a53c4c4ec4ac7031362b691c0366d.tar.gz
Blacken the project (#141)
Diffstat (limited to 'examples')
-rw-r--r--examples/LAparser.py674
-rw-r--r--examples/SimpleCalc.py116
-rw-r--r--examples/TAP.py128
-rw-r--r--examples/adventureEngine.py268
-rw-r--r--examples/antlr_grammar.py322
-rw-r--r--examples/antlr_grammar_tests.py41
-rw-r--r--examples/apicheck.py23
-rw-r--r--examples/bigquery_view_parser.py885
-rw-r--r--examples/booleansearchparser.py346
-rw-r--r--examples/btpyparse.py55
-rw-r--r--examples/builtin_parse_action_demo.py4
-rw-r--r--examples/cLibHeader.py16
-rw-r--r--examples/chemicalFormulas.py60
-rw-r--r--examples/commasep.py3
-rw-r--r--examples/configParse.py54
-rw-r--r--examples/cpp_enum_parser.py21
-rw-r--r--examples/datetimeParseActions.py33
-rw-r--r--examples/decaf_parser.py266
-rw-r--r--examples/delta_time.py312
-rw-r--r--examples/dfmparse.py122
-rw-r--r--examples/dhcpd_leases_parser.py50
-rw-r--r--examples/dictExample.py18
-rw-r--r--examples/dictExample2.py34
-rw-r--r--examples/ebnf.py80
-rw-r--r--examples/ebnftest.py51
-rw-r--r--examples/eval_arith.py252
-rw-r--r--examples/excelExpr.py85
-rw-r--r--examples/fourFn.py87
-rw-r--r--examples/gen_ctypes.py163
-rw-r--r--examples/getNTPserversNew.py17
-rw-r--r--examples/greeting.py8
-rw-r--r--examples/greetingInGreek.py2
-rw-r--r--examples/greetingInKorean.py2
-rw-r--r--examples/holaMundo.py37
-rw-r--r--examples/htmlStripper.py23
-rw-r--r--examples/htmlTableParser.py48
-rw-r--r--examples/httpServerLogParser.py79
-rw-r--r--examples/idlParse.py205
-rw-r--r--examples/include_preprocessor.py50
-rw-r--r--examples/indentedGrammarExample.py8
-rw-r--r--examples/invRegex.py152
-rw-r--r--examples/jsonParser.py27
-rw-r--r--examples/linenoExample.py29
-rw-r--r--examples/list1.py26
-rw-r--r--examples/listAllMatches.py12
-rw-r--r--examples/lucene_grammar.py42
-rw-r--r--examples/macroExpander.py9
-rw-r--r--examples/matchPreviousDemo.py2
-rw-r--r--examples/mozillaCalendarParser.py92
-rw-r--r--examples/nested.py4
-rw-r--r--examples/nested_markup.py21
-rw-r--r--examples/numerics.py16
-rw-r--r--examples/oc.py75
-rw-r--r--examples/parseListString.py84
-rw-r--r--examples/parsePythonValue.py53
-rw-r--r--examples/parseResultsSumExample.py10
-rw-r--r--examples/parseTabularData.py35
-rw-r--r--examples/partial_gene_match.py30
-rw-r--r--examples/pgn.py66
-rw-r--r--examples/position.py24
-rw-r--r--examples/protobuf_parser.py98
-rw-r--r--examples/pymicko.py915
-rw-r--r--examples/pythonGrammarParser.py54
-rw-r--r--examples/rangeCheck.py30
-rw-r--r--examples/readJson.py30
-rw-r--r--examples/removeLineBreaks.py7
-rw-r--r--examples/romanNumerals.py56
-rw-r--r--examples/rosettacode.py131
-rw-r--r--examples/scanExamples.py43
-rw-r--r--examples/searchParserAppDemo.py23
-rw-r--r--examples/searchparser.py203
-rw-r--r--examples/select_parser.py308
-rw-r--r--examples/sexpParser.py42
-rw-r--r--examples/shapes.py22
-rw-r--r--examples/simpleArith.py53
-rw-r--r--examples/simpleBool.py68
-rw-r--r--examples/simpleSQL.py77
-rw-r--r--examples/simpleWiki.py24
-rw-r--r--examples/sparser.py196
-rw-r--r--examples/sql2dot.py85
-rw-r--r--examples/stackish.py61
-rw-r--r--examples/statemachine/documentSignoffDemo.py18
-rw-r--r--examples/statemachine/documentsignoffstate.pystate6
-rw-r--r--examples/statemachine/libraryBookDemo.py16
-rw-r--r--examples/statemachine/statemachine.py287
-rw-r--r--examples/statemachine/vending_machine.py7
-rw-r--r--examples/statemachine/video_demo.py18
-rw-r--r--examples/test_bibparse.py221
-rw-r--r--examples/urlExtractor.py8
-rw-r--r--examples/urlExtractorNew.py2
-rw-r--r--examples/verilogParse.py1083
-rw-r--r--examples/wordsToNum.py130
92 files changed, 6316 insertions, 3863 deletions
diff --git a/examples/LAparser.py b/examples/LAparser.py
index 330b8f5..b72166f 100644
--- a/examples/LAparser.py
+++ b/examples/LAparser.py
@@ -57,41 +57,54 @@ Usage: To process LA equations embedded in source files, import this module and
"""
-import re,sys
-from pyparsing import Word, alphas, ParseException, Literal, CaselessLiteral \
-, Combine, Optional, nums, Forward, ZeroOrMore, \
- StringEnd, alphanums
+import re, sys
+from pyparsing import (
+ Word,
+ alphas,
+ ParseException,
+ Literal,
+ CaselessLiteral,
+ Combine,
+ Optional,
+ nums,
+ Forward,
+ ZeroOrMore,
+ StringEnd,
+ alphanums,
+)
# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
-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.
+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 _pushFirst(str, loc, toks):
+ if debug_flag:
+ print("pushing ", toks[0], "str is ", str)
+ exprStack.append(toks[0])
-def _assignVar( str, loc, toks ):
+
+def _assignVar(str, loc, toks):
global targetvar
- targetvar = toks[0]
+ targetvar = toks[0]
+
-#-----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
# The following statements define the grammar for the parser.
-point = Literal('.')
-e = CaselessLiteral('E')
-plusorminus = Literal('+') | Literal('-')
+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 )
- )
+integer = Combine(Optional(plusorminus) + number)
+floatnumber = Combine(
+ integer + Optional(point + Optional(number)) + Optional(e + integer)
+)
lbracket = Literal("[")
rbracket = Literal("]")
@@ -100,57 +113,66 @@ ident = Forward()
## 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
+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( "=" )
+expop = Literal("^")
+assignop = Literal("=")
expr = Forward()
-atom = ( ( e | floatnumber | integer | ident ).setParseAction(_pushFirst) |
- ( lpar + expr.suppress() + rpar )
- )
+atom = (e | floatnumber | integer | ident).setParseAction(_pushFirst) | (
+ lpar + expr.suppress() + rpar
+)
factor = Forward()
-factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( _pushFirst ) )
+factor << atom + ZeroOrMore((expop + factor).setParseAction(_pushFirst))
-term = factor + ZeroOrMore( ( multop + factor ).setParseAction( _pushFirst ) )
-expr << term + ZeroOrMore( ( addop + term ).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_'
+vprefix = "V3_"
vplen = len(vprefix)
-mprefix = 'M3_'
+mprefix = "M3_"
mplen = len(mprefix)
## We don't support unary negation for vectors and matrices
-class UnaryUnsupportedError(Exception): pass
+class UnaryUnsupportedError(Exception):
+ pass
+
def _isvec(ident):
- if ident[0] == '-' and ident[1:vplen+1] == vprefix:
- raise UnaryUnsupportedError
- else: return ident[0:vplen] == vprefix
+ 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
+ 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))
-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,
@@ -164,80 +186,121 @@ def _isscalar(ident): return not (_isvec(ident) or _ismat(ident))
## 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
+
+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 ), }
+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
+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.
@@ -248,59 +311,76 @@ def parse(input_string):
calls that implement the expression.
"""
- global exprStack
+ 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)
+ 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
- except UnaryUnsupportedError:
- print("Unary negation is not supported for vectors and matrices: '%s'"%input_string, file=sys.stderr)
+
+ # 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
- return result
- else:
- print("Empty left side in '%s'"%input_string, file=sys.stderr)
- raise TypeError
+ # 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):
- """
+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
@@ -313,106 +393,139 @@ def fprocess(infilep,outfilep):
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)
+ 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)
- 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)))")
-
- ]
-
-
- all_passed = [True]
-
- def post_test(test, parsed):
-
- # copy exprStack to evaluate and clear before running next test
- parsed_stack = exprStack[:]
- exprStack.clear()
-
- name, testcase, expected = next(tc for tc in testcases if tc[1] == test)
-
- this_test_passed = False
- try:
- try:
- result=_evaluateStack(parsed_stack)
- 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)
+ 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)))",
+ ),
+ ]
+
+ all_passed = [True]
+
+ def post_test(test, parsed):
+
+ # copy exprStack to evaluate and clear before running next test
+ parsed_stack = exprStack[:]
+ exprStack.clear()
+
+ name, testcase, expected = next(tc for tc in testcases if tc[1] == test)
+
+ this_test_passed = False
+ try:
+ try:
+ result = _evaluateStack(parsed_stack)
+ 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)
+ except UnaryUnsupportedError:
+ print(
+ "Unary negation is not supported for vectors and matrices: '%s'"
+ % input_string,
+ file=sys.stderr,
+ )
raise
- else:
- print("Empty left side in '%s'"%input_string, file=sys.stderr)
- raise TypeError
-
- parsed['result'] = result
- parsed['passed'] = this_test_passed = result == expected
+ # 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
+
+ else:
+ print("Empty left side in '%s'" % input_string, file=sys.stderr)
+ raise TypeError
+
+ parsed["result"] = result
+ parsed["passed"] = this_test_passed = result == expected
+
+ finally:
+ all_passed[0] = all_passed[0] and this_test_passed
+ print("\n" + name)
+
+ equation.runTests((t[1] for t in testcases), postParse=post_test)
+
+ ##TODO: Write testcases with invalid expressions and test that the expected
+ ## exceptions are raised.
+
+ print("Tests completed!")
+ print("PASSED" if all_passed[0] else "FAILED")
+ assert all_passed[0]
- finally:
- all_passed[0] = all_passed[0] and this_test_passed
- print('\n' + name)
-
- equation.runTests((t[1] for t in testcases), postParse=post_test)
-
-
- ##TODO: Write testcases with invalid expressions and test that the expected
- ## exceptions are raised.
-
- print("Tests completed!")
- print("PASSED" if all_passed[0] else "FAILED")
- assert all_passed[0]
##----------------------------------------------------------------------------
## The following is executed only when this module is executed as
@@ -420,43 +533,44 @@ def test():
## and then enters an interactive loop where you
## can enter expressions and see the resulting C code as output.
-if __name__ == '__main__':
+if __name__ == "__main__":
- import sys
- if not sys.flags.interactive:
- # run testcases
- test()
- sys.exit(0)
+ import sys
- # input_string
- input_string=''
+ if not sys.flags.interactive:
+ # run testcases
+ test()
+ sys.exit(0)
- # Display instructions on how to use the program interactively
- interactiveusage = """
+ # 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 Exception:
- pass
-
- # obtain new input string
+ print(interactiveusage)
input_string = input("> ")
- # if user types 'quit' then say goodbye
- print("Good bye!")
- import os
- os._exit(0)
-
+ 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 Exception:
+ pass
+
+ # obtain new input string
+ input_string = input("> ")
+
+ # if user types 'quit' then say goodbye
+ print("Good bye!")
+ import os
+
+ os._exit(0)
diff --git a/examples/SimpleCalc.py b/examples/SimpleCalc.py
index 5e1d835..7ace9ae 100644
--- a/examples/SimpleCalc.py
+++ b/examples/SimpleCalc.py
@@ -23,13 +23,12 @@
#
-
# Uncomment the line below for readline support on interactive terminal
# import readline
from pyparsing import ParseException, Word, alphas, alphanums
# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
-debug_flag=False
+debug_flag = False
variables = {}
@@ -59,64 +58,67 @@ from fourFn import BNF, exprStack, evaluate_stack
arithExpr = BNF()
ident = Word(alphas, alphanums).setName("identifier")
-assignment = ident("varname") + '=' + arithExpr
+assignment = ident("varname") + "=" + arithExpr
pattern = assignment | arithExpr
-if __name__ == '__main__':
- # input_string
- input_string=''
+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("> ")
+ # 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.strip().lower() != 'quit':
- if input_string.strip().lower() == 'debug':
- debug_flag=True
+ while input_string.strip().lower() != "quit":
+ if input_string.strip().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, (str(err), err.line, err.column)]
+
+ # 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)
+
+ for i, ob in enumerate(exprStack):
+ if isinstance(ob, str) and ob in variables:
+ exprStack[i] = str(variables[ob])
+
+ # calculate result , store a copy in ans , display the result to user
+ try:
+ result = evaluate_stack(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")
+ err_str, err_line, err_col = L[-1]
+ print(err_line)
+ print(" " * (err_col - 1) + "^")
+ print(err_str)
+
+ # obtain new input string
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, (str(err), err.line, err.column)]
-
- # 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)
-
- for i, ob in enumerate(exprStack):
- if isinstance(ob, str) and ob in variables:
- exprStack[i] = str(variables[ob])
-
- # calculate result , store a copy in ans , display the result to user
- try:
- result=evaluate_stack(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')
- err_str, err_line, err_col = L[-1]
- print(err_line)
- print(" "*(err_col-1) + "^")
- print(err_str)
-
- # obtain new input string
- input_string = input("> ")
- # if user type 'quit' then say goodbye
- print("Good bye!")
+ # if user type 'quit' then say goodbye
+ print("Good bye!")
diff --git a/examples/TAP.py b/examples/TAP.py
index cb3afff..8676e7e 100644
--- a/examples/TAP.py
+++ b/examples/TAP.py
@@ -22,11 +22,24 @@
# 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']
+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
@@ -34,51 +47,58 @@ ParserElement.setDefaultWhitespaceChars(" \t")
NL = LineEnd().suppress()
integer = Word(nums)
-plan = '1..' + integer("ubound")
+plan = "1.." + integer("ubound")
-OK,NOT_OK = map(Literal,['ok','not ok'])
-testStatus = (OK | NOT_OK)
+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]]) ))
+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"))
+ 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")
-tapOutputParser = Optional(Group(plan)("plan") + NL) & \
- Group(OneOrMore((testLine|bailLine) + NL))("tests")
class TAPTest:
- def __init__(self,results):
+ def __init__(self, results):
self.num = results.testNumber
- self.passed = (results.passed=="ok")
+ 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')
+ self.skipped = results.directive[0][0] == "SKIP"
+ self.todo = results.directive[0][0] == "TODO"
+
@classmethod
- def bailedTest(cls,num):
+ def bailedTest(cls, num):
ret = TAPTest(empty.parseString(""))
ret.num = num
ret.skipped = True
return ret
+
class TAPSummary:
- def __init__(self,results):
+ def __init__(self, results):
self.passedTests = []
self.failedTests = []
self.skippedTests = []
@@ -86,22 +106,22 @@ class TAPSummary:
self.bonusTests = []
self.bail = False
if results.plan:
- expected = list(range(1, int(results.plan.ubound)+1))
+ expected = list(range(1, int(results.plan.ubound) + 1))
else:
- expected = list(range(1,len(results.tests)+1))
+ expected = list(range(1, len(results.tests) + 1))
- for i,res in enumerate(results.tests):
+ for i, res in enumerate(results.tests):
# test for bail out
if res.BAIL:
- #~ print "Test suite aborted: " + res.reason
- #~ self.failedTests += expected[i:]
+ # ~ print "Test suite aborted: " + res.reason
+ # ~ self.failedTests += expected[i:]
self.bail = True
- self.skippedTests += [ TAPTest.bailedTest(ii) for ii in expected[i:] ]
+ self.skippedTests += [TAPTest.bailedTest(ii) for ii in expected[i:]]
self.bailReason = res.reason
break
- #~ print res.dump()
- testnum = i+1
+ # ~ print res.dump()
+ testnum = i + 1
if res.testNumber != "":
if testnum != int(res.testNumber):
print("ERROR! test %(testNumber)s out of sequence" % res)
@@ -113,31 +133,37 @@ class TAPSummary:
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)
+ 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())
+ 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) + "]"
+ testListStr = lambda tl: "[" + ",".join(str(t.num) for t in tl) + "]"
summaryText = []
if showPassed or showAll:
- summaryText.append( "PASSED: %s" % testListStr(self.passedTests) )
+ summaryText.append("PASSED: %s" % testListStr(self.passedTests))
if self.failedTests or showAll:
- summaryText.append( "FAILED: %s" % testListStr(self.failedTests) )
+ summaryText.append("FAILED: %s" % testListStr(self.failedTests))
if self.skippedTests or showAll:
- summaryText.append( "SKIPPED: %s" % testListStr(self.skippedTests) )
+ summaryText.append("SKIPPED: %s" % testListStr(self.skippedTests))
if self.todoTests or showAll:
- summaryText.append( "TODO: %s" % testListStr(self.todoTests) )
+ summaryText.append("TODO: %s" % testListStr(self.todoTests))
if self.bonusTests or showAll:
- summaryText.append( "BONUS: %s" % testListStr(self.bonusTests) )
+ summaryText.append("BONUS: %s" % testListStr(self.bonusTests))
if self.passedSuite:
- summaryText.append( "PASSED" )
+ summaryText.append("PASSED")
else:
- summaryText.append( "FAILED" )
+ summaryText.append("FAILED")
return "\n".join(summaryText)
+
# create TAPSummary objects from tapOutput parsed results, by setting
# class as parse action
tapOutputParser.setParseAction(TAPSummary)
@@ -210,7 +236,7 @@ if __name__ == "__main__":
1..7
"""
- for test in (test1,test2,test3,test4,test5,test6):
+ for test in (test1, test2, test3, test4, test5, test6):
print(test)
tapResult = tapOutputParser.parseString(test)[0]
print(tapResult.summary(showAll=True))
diff --git a/examples/adventureEngine.py b/examples/adventureEngine.py
index f4ef392..a6a44ad 100644
--- a/examples/adventureEngine.py
+++ b/examples/adventureEngine.py
@@ -8,59 +8,64 @@ from pyparsing import *
import random
import string
-def aOrAn( item ):
+
+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"
+ 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(", ".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 ""
+ if len(l) == 0:
+ return ""
out = []
if len(l) > 1:
- out.append(', '.join(l[:-1]))
+ out.append(", ".join(l[:-1]))
out.append("and")
out.append(l[-1])
return " ".join(out)
+
class Room:
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):
+ 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):
+ def removeItem(self, it):
self.inv.remove(it)
def describe(self):
print(self.desc)
- visibleItems = [ it for it in self.inv if it.isVisible ]
+ visibleItems = [it for it in self.inv if it.isVisible]
if random.random() > 0.5:
if len(visibleItems) > 1:
is_form = "are"
@@ -75,13 +80,13 @@ class Exit(Room):
def __init__(self):
super().__init__("")
- def enter(self,player):
+ def enter(self, player):
player.gameOver = True
-
class Item:
items = {}
+
def __init__(self, desc):
self.desc = desc
self.isDeadly = False
@@ -106,7 +111,7 @@ class Item:
def isUsable(self, player, target):
if self.usableConditionTest:
- return self.usableConditionTest( player, target )
+ return self.usableConditionTest(player, target)
else:
return False
@@ -114,6 +119,7 @@ class Item:
if self.useAction:
self.useAction(player, self, target)
+
class OpenableItem(Item):
def __init__(self, desc, contents=None):
super().__init__(desc)
@@ -121,7 +127,9 @@ class OpenableItem(Item):
self.isOpened = False
if contents is not None:
if isinstance(contents, Item):
- self.contents = [contents,]
+ self.contents = [
+ contents,
+ ]
else:
self.contents = contents
else:
@@ -132,7 +140,7 @@ class OpenableItem(Item):
self.isOpened = not self.isOpened
if self.contents is not None:
for item in self.contents:
- player.room.addItem( item )
+ player.room.addItem(item)
self.contents = []
self.desc = "open " + self.desc
@@ -145,6 +153,7 @@ class OpenableItem(Item):
class Command:
"Base class for commands"
+
def __init__(self, verb, verbProg):
self.verb = verb
self.verbProg = verbProg
@@ -156,8 +165,8 @@ class Command:
def _doCommand(self, player):
pass
- def __call__(self, player ):
- print(self.verbProg.capitalize()+"...")
+ def __call__(self, player):
+ print(self.verbProg.capitalize() + "...")
self._doCommand(player)
@@ -173,16 +182,9 @@ class MoveCommand(Command):
def _doCommand(self, player):
rm = player.room
- nextRoom = rm.doors[
- {
- "N":0,
- "S":1,
- "E":2,
- "W":3,
- }[self.direction]
- ]
+ nextRoom = rm.doors[{"N": 0, "S": 1, "E": 2, "W": 3,}[self.direction]]
if nextRoom:
- player.moveTo( nextRoom )
+ player.moveTo(nextRoom)
else:
print("Can't go that way.")
@@ -227,6 +229,7 @@ class DropCommand(Command):
else:
print("You don't have %s." % (aOrAn(subj)))
+
class InventoryCommand(Command):
def __init__(self, quals):
super().__init__("INV", "taking inventory")
@@ -236,7 +239,8 @@ class InventoryCommand(Command):
return "INVENTORY or INV or I - lists what items you have"
def _doCommand(self, player):
- print("You have %s." % enumerateItems( player.inv ))
+ print("You have %s." % enumerateItems(player.inv))
+
class LookCommand(Command):
def __init__(self, quals):
@@ -249,6 +253,7 @@ class LookCommand(Command):
def _doCommand(self, player):
player.room.describe()
+
class DoorsCommand(Command):
def __init__(self, quals):
super().__init__("DOORS", "looking for doors")
@@ -267,13 +272,17 @@ class DoorsCommand(Command):
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 )
+ 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().__init__("USE", "using")
@@ -291,13 +300,14 @@ class UseCommand(Command):
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 )
+ 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().__init__("OPEN", "opening")
@@ -309,11 +319,11 @@ class OpenCommand(Command):
def _doCommand(self, player):
rm = player.room
- availItems = rm.inv+player.inv
+ availItems = rm.inv + player.inv
if self.subject in availItems:
if self.subject.isOpenable:
if not self.subject.isOpened:
- self.subject.openItem( player )
+ self.subject.openItem(player)
else:
print("It's already open.")
else:
@@ -321,6 +331,7 @@ class OpenCommand(Command):
else:
print("There is no %s here to open." % self.subject)
+
class CloseCommand(Command):
def __init__(self, quals):
super().__init__("CLOSE", "closing")
@@ -332,11 +343,11 @@ class CloseCommand(Command):
def _doCommand(self, player):
rm = player.room
- availItems = rm.inv+player.inv
+ availItems = rm.inv + player.inv
if self.subject in availItems:
if self.subject.isOpenable:
if self.subject.isOpened:
- self.subject.closeItem( player )
+ self.subject.closeItem(player)
else:
print("You can't close that, it's not open.")
else:
@@ -344,6 +355,7 @@ class CloseCommand(Command):
else:
print("There is no %s here to close." % self.subject)
+
class QuitCommand(Command):
def __init__(self, quals):
super().__init__("QUIT", "quitting")
@@ -356,6 +368,7 @@ class QuitCommand(Command):
print("Ok....")
player.gameOver = True
+
class HelpCommand(Command):
def __init__(self, quals):
super().__init__("HELP", "helping")
@@ -378,13 +391,15 @@ class HelpCommand(Command):
DoorsCommand,
QuitCommand,
HelpCommand,
- ]:
+ ]:
print(" - %s" % cmd.helpDescription())
print()
+
class AppParseException(ParseException):
pass
+
class Parser:
def __init__(self):
self.bnf = self.makeBNF()
@@ -392,8 +407,9 @@ class Parser:
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") )
+ 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)
@@ -401,21 +417,24 @@ class Parser:
quitVerb = oneOf("QUIT Q", caseless=True)
lookVerb = oneOf("LOOK L", caseless=True)
doorsVerb = CaselessLiteral("DOORS")
- helpVerb = oneOf("H HELP ?",caseless=True)
+ 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"))
+ 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")
+ 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")
@@ -438,22 +457,24 @@ class Parser:
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):
+ 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)
+ raise AppParseException(s, l, "No such item '%s'." % iname)
return iname
def parseCmd(self, cmdstr):
@@ -463,11 +484,18 @@ class Parser:
except AppParseException as pe:
print(pe.msg)
except ParseException as pe:
- print(random.choice([ "Sorry, I don't understand that.",
- "Huh?",
- "Excuse me?",
- "???",
- "What?" ] ))
+ print(
+ random.choice(
+ [
+ "Sorry, I don't understand that.",
+ "Huh?",
+ "Excuse me?",
+ "???",
+ "What?",
+ ]
+ )
+ )
+
class Player:
def __init__(self, name):
@@ -485,20 +513,20 @@ class Player:
else:
rm.describe()
- def take(self,it):
+ 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):
+ def drop(self, it):
self.inv.remove(it)
if it.isFragile:
it.breakItem()
-def createRooms( rm ):
+def createRooms(rm):
"""
create rooms, using multiline string showing map layout
string contains symbols for the following:
@@ -521,8 +549,8 @@ def createRooms( rm ):
# 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):
+ for row, line in enumerate(rows):
+ for col, c in enumerate(line):
if c in string.ascii_letters:
room = ret[c]
n = None
@@ -533,46 +561,52 @@ def createRooms( rm ):
# 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]
+ 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]
+ 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]
+ 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]
+ 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]
+ room.doors = [n, s, e, w]
return ret
+
# put items in rooms
-def putItemInRoom(i,r):
- if isinstance(r,str):
+def putItemInRoom(i, r):
+ if isinstance(r, str):
r = rooms[r]
- r.addItem( Item.items[i] )
+ r.addItem(Item.items[i])
-def playGame(p,startRoom):
+
+def playGame(p, startRoom):
# create parser
parser = Parser()
- p.moveTo( startRoom )
+ p.moveTo(startRoom)
while not p.gameOver:
cmdstr = input(">> ")
cmd = parser.parseCmd(cmdstr)
if cmd is not None:
- cmd.command( p )
+ cmd.command(p)
print()
print("You ended the game with:")
for i in p.inv:
print(" -", aOrAn(i))
-#====================
+# ====================
# start game definition
roomMap = """
d-Z
@@ -583,7 +617,7 @@ roomMap = """
|
A
"""
-rooms = createRooms( roomMap )
+rooms = createRooms(roomMap)
rooms["A"].desc = "You are standing on the front porch of a wooden shack."
rooms["b"].desc = "You are in a garden."
rooms["c"].desc = "You are in a kitchen."
@@ -595,29 +629,39 @@ rooms["q"].gameOver = True
# define global variables for referencing rooms
frontPorch = rooms["A"]
-garden = rooms["b"]
-kitchen = rooms["c"]
-backPorch = rooms["d"]
-library = rooms["e"]
-patio = rooms["f"]
+garden = rooms["b"]
+kitchen = rooms["c"]
+backPorch = rooms["d"]
+library = rooms["e"]
+patio = rooms["f"]
# create items
-itemNames = """sword.diamond.apple.flower.coin.shovel.book.mirror.telescope.gold bar""".split(".")
+itemNames = """sword.diamond.apple.flower.coin.shovel.book.mirror.telescope.gold bar""".split(
+ "."
+)
for itemName in itemNames:
- Item( itemName )
+ Item(itemName)
Item.items["apple"].isDeadly = True
Item.items["mirror"].isFragile = True
Item.items["coin"].isVisible = False
-Item.items["shovel"].usableConditionTest = ( lambda p,t: p.room is garden )
-def useShovel(p,subj,target):
+Item.items["shovel"].usableConditionTest = lambda p, t: p.room is garden
+
+
+def useShovel(p, subj, target):
coin = Item.items["coin"]
if not coin.isVisible and coin in p.room.inv:
coin.isVisible = True
+
+
Item.items["shovel"].useAction = useShovel
Item.items["telescope"].isTakeable = False
-def useTelescope(p,subj,target):
+
+
+def useTelescope(p, subj, target):
print("You don't see anything.")
+
+
Item.items["telescope"].useAction = useTelescope
OpenableItem("treasure chest", Item.items["gold bar"])
@@ -642,7 +686,7 @@ putItemInRoom("treasure chest", patio)
# create player
plyr = Player("Bob")
-plyr.take( Item.items["sword"] )
+plyr.take(Item.items["sword"])
# start game
-playGame( plyr, frontPorch )
+playGame(plyr, frontPorch)
diff --git a/examples/antlr_grammar.py b/examples/antlr_grammar.py
index c131cfb..49151ee 100644
--- a/examples/antlr_grammar.py
+++ b/examples/antlr_grammar.py
@@ -1,4 +1,4 @@
-'''
+"""
antlr_grammar.py
Created on 4 sept. 2010
@@ -8,196 +8,299 @@ Created on 4 sept. 2010
Submitted by Luca DallOlio, September, 2010
(Minor updates by Paul McGuire, June, 2012)
(Code idiom updates by Paul McGuire, April, 2019)
-'''
-from pyparsing import (Word, ZeroOrMore, printables, Suppress, OneOrMore, Group,
- LineEnd, Optional, White, originalTextFor, hexnums, nums, Combine, Literal, Keyword,
- cStyleComment, Regex, Forward, MatchFirst, And, oneOf, alphas, alphanums,
- delimitedList, Char)
+"""
+from pyparsing import (
+ Word,
+ ZeroOrMore,
+ printables,
+ Suppress,
+ OneOrMore,
+ Group,
+ LineEnd,
+ Optional,
+ White,
+ originalTextFor,
+ hexnums,
+ nums,
+ Combine,
+ Literal,
+ Keyword,
+ cStyleComment,
+ Regex,
+ Forward,
+ MatchFirst,
+ And,
+ oneOf,
+ alphas,
+ alphanums,
+ delimitedList,
+ Char,
+)
# http://www.antlr.org/grammar/ANTLR/ANTLRv3.g
-QUOTE,APOS,EQ,LBRACK,RBRACK,LBRACE,RBRACE,LPAR,RPAR,ROOT,BANG,AT,TIL,SEMI,COLON,VERT = map(Suppress,
- '"\'=[]{}()^!@~;:|')
-BSLASH = Literal('\\')
-keywords = (SRC_, SCOPE_, OPTIONS_, TOKENS_, FRAGMENT, ID, LEXER, PARSER, GRAMMAR, TREE, CATCH, FINALLY,
- THROWS, PROTECTED, PUBLIC, PRIVATE, ) = map(Keyword,
- """src scope options tokens fragment id lexer parser grammar tree catch finally throws protected
- public private """.split())
+(
+ QUOTE,
+ APOS,
+ EQ,
+ LBRACK,
+ RBRACK,
+ LBRACE,
+ RBRACE,
+ LPAR,
+ RPAR,
+ ROOT,
+ BANG,
+ AT,
+ TIL,
+ SEMI,
+ COLON,
+ VERT,
+) = map(Suppress, "\"'=[]{}()^!@~;:|")
+BSLASH = Literal("\\")
+keywords = (
+ SRC_,
+ SCOPE_,
+ OPTIONS_,
+ TOKENS_,
+ FRAGMENT,
+ ID,
+ LEXER,
+ PARSER,
+ GRAMMAR,
+ TREE,
+ CATCH,
+ FINALLY,
+ THROWS,
+ PROTECTED,
+ PUBLIC,
+ PRIVATE,
+) = map(
+ Keyword,
+ """src scope options tokens fragment id lexer parser grammar tree catch finally throws protected
+ public private """.split(),
+)
KEYWORD = MatchFirst(keywords)
# Tokens
-EOL = Suppress(LineEnd()) # $
+EOL = Suppress(LineEnd()) # $
SGL_PRINTABLE = Char(printables)
-singleTextString = originalTextFor(ZeroOrMore(~EOL + (White(" \t") | Word(printables)))).leaveWhitespace()
+singleTextString = originalTextFor(
+ ZeroOrMore(~EOL + (White(" \t") | Word(printables)))
+).leaveWhitespace()
XDIGIT = hexnums
INT = Word(nums)
-ESC = BSLASH + (oneOf(list(r'nrtbf\">'+"'")) | ('u' + Word(hexnums, exact=4)) | SGL_PRINTABLE)
+ESC = BSLASH + (
+ oneOf(list(r"nrtbf\">" + "'")) | ("u" + Word(hexnums, exact=4)) | SGL_PRINTABLE
+)
LITERAL_CHAR = ESC | ~(APOS | BSLASH) + SGL_PRINTABLE
CHAR_LITERAL = APOS + LITERAL_CHAR + APOS
STRING_LITERAL = APOS + Combine(OneOrMore(LITERAL_CHAR)) + APOS
DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"'
-DOUBLE_ANGLE_STRING_LITERAL = '<<' + ZeroOrMore(SGL_PRINTABLE) + '>>'
-TOKEN_REF = Word(alphas.upper(), alphanums+'_')
-RULE_REF = Word(alphas.lower(), alphanums+'_')
-ACTION_ESC = (BSLASH.suppress() + APOS
- | BSLASH.suppress()
- | BSLASH.suppress() + (~(APOS | QUOTE) + SGL_PRINTABLE)
- )
-ACTION_CHAR_LITERAL = (APOS + (ACTION_ESC | ~(BSLASH | APOS) + SGL_PRINTABLE) + APOS)
-ACTION_STRING_LITERAL = (QUOTE + ZeroOrMore(ACTION_ESC | ~(BSLASH | QUOTE) + SGL_PRINTABLE) + QUOTE)
+DOUBLE_ANGLE_STRING_LITERAL = "<<" + ZeroOrMore(SGL_PRINTABLE) + ">>"
+TOKEN_REF = Word(alphas.upper(), alphanums + "_")
+RULE_REF = Word(alphas.lower(), alphanums + "_")
+ACTION_ESC = (
+ BSLASH.suppress() + APOS
+ | BSLASH.suppress()
+ | BSLASH.suppress() + (~(APOS | QUOTE) + SGL_PRINTABLE)
+)
+ACTION_CHAR_LITERAL = APOS + (ACTION_ESC | ~(BSLASH | APOS) + SGL_PRINTABLE) + APOS
+ACTION_STRING_LITERAL = (
+ QUOTE + ZeroOrMore(ACTION_ESC | ~(BSLASH | QUOTE) + SGL_PRINTABLE) + QUOTE
+)
SRC = SRC_.suppress() + ACTION_STRING_LITERAL("file") + INT("line")
id = TOKEN_REF | RULE_REF
-SL_COMMENT = Suppress('//') + Suppress('$ANTLR') + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL
+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 = OneOrMore(
+ Suppress(" ") | Suppress("\t") | (Optional(Suppress("\r")) + Literal("\n"))
+)
WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT)
NESTED_ARG_ACTION = Forward()
-NESTED_ARG_ACTION << (LBRACK
- + ZeroOrMore(NESTED_ARG_ACTION
- | ACTION_STRING_LITERAL
- | ACTION_CHAR_LITERAL)
- + RBRACK)
+NESTED_ARG_ACTION << (
+ LBRACK
+ + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL)
+ + RBRACK
+)
ARG_ACTION = NESTED_ARG_ACTION
NESTED_ACTION = Forward()
-NESTED_ACTION << (LBRACE
- + ZeroOrMore(NESTED_ACTION
- | SL_COMMENT
- | ML_COMMENT
- | ACTION_STRING_LITERAL
- | ACTION_CHAR_LITERAL)
- + RBRACE)
-ACTION = NESTED_ACTION + Optional('?')
+NESTED_ACTION << (
+ LBRACE
+ + ZeroOrMore(
+ NESTED_ACTION
+ | SL_COMMENT
+ | ML_COMMENT
+ | ACTION_STRING_LITERAL
+ | ACTION_CHAR_LITERAL
+ )
+ + RBRACE
+)
+ACTION = NESTED_ACTION + Optional("?")
SCOPE = SCOPE_.suppress()
-OPTIONS = OPTIONS_.suppress() + LBRACE # + WS_LOOP + Suppress('{')
-TOKENS = TOKENS_.suppress() + LBRACE # + WS_LOOP + Suppress('{')
+OPTIONS = OPTIONS_.suppress() + LBRACE # + WS_LOOP + Suppress('{')
+TOKENS = TOKENS_.suppress() + LBRACE # + WS_LOOP + Suppress('{')
TREE_BEGIN = ROOT + LPAR
-RANGE = Suppress('..')
-REWRITE = Suppress('->')
+RANGE = Suppress("..")
+REWRITE = Suppress("->")
# General Parser Definitions
# Grammar heading
-optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal('*').setName("s")
+optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal("*").setName("s")
option = Group(id("id") + EQ + optionValue("value"))("option")
optionsSpec = OPTIONS + Group(OneOrMore(option + SEMI))("options") + RBRACE
-tokenSpec = Group(TOKEN_REF("token_ref")
- + (EQ + (STRING_LITERAL | CHAR_LITERAL)("lit")))("token") + SEMI
+tokenSpec = (
+ Group(TOKEN_REF("token_ref") + (EQ + (STRING_LITERAL | CHAR_LITERAL)("lit")))(
+ "token"
+ )
+ + SEMI
+)
tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + RBRACE
attrScope = SCOPE_.suppress() + id + ACTION
grammarType = LEXER + PARSER + TREE
actionScopeName = id | LEXER("l") | PARSER("p")
-action = AT + Optional(actionScopeName + Suppress('::')) + id + ACTION
-
-grammarHeading = (Optional(ML_COMMENT("ML_COMMENT"))
- + Optional(grammarType)
- + GRAMMAR
- + id("grammarName") + SEMI
- + Optional(optionsSpec)
- + Optional(tokensSpec)
- + ZeroOrMore(attrScope)
- + ZeroOrMore(action))
+action = AT + Optional(actionScopeName + Suppress("::")) + id + ACTION
+
+grammarHeading = (
+ Optional(ML_COMMENT("ML_COMMENT"))
+ + Optional(grammarType)
+ + GRAMMAR
+ + id("grammarName")
+ + SEMI
+ + Optional(optionsSpec)
+ + Optional(tokensSpec)
+ + ZeroOrMore(attrScope)
+ + ZeroOrMore(action)
+)
modifier = PROTECTED | PUBLIC | PRIVATE | FRAGMENT
ruleAction = AT + id + ACTION
throwsSpec = THROWS.suppress() + delimitedList(id)
-ruleScopeSpec = ((SCOPE_.suppress() + ACTION)
- | (SCOPE_.suppress() + delimitedList(id) + SEMI)
- | (SCOPE_.suppress() + ACTION + SCOPE_.suppress() + delimitedList(id) + SEMI))
+ruleScopeSpec = (
+ (SCOPE_.suppress() + ACTION)
+ | (SCOPE_.suppress() + delimitedList(id) + SEMI)
+ | (SCOPE_.suppress() + ACTION + SCOPE_.suppress() + delimitedList(id) + SEMI)
+)
unary_op = oneOf("^ !")
notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL
-terminal = (CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | '.') + Optional(unary_op)
+terminal = (
+ CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | "."
+) + Optional(unary_op)
block = Forward()
notSet = TIL + (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"))
- )
+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 = ROOT + LPAR + element*(2,) + RPAR
+treeSpec = ROOT + LPAR + element * (2,) + RPAR
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 )
+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")
# Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure?
alternative = Group(Group(OneOrMore(element))("elements"))
-rewrite = Optional(Literal('TODO REWRITE RULES TODO'))
-block <<= (LPAR
- + Optional(Optional(optionsSpec("opts")) + COLON)
- + Group(alternative('a1')
- + rewrite
- + Group(ZeroOrMore(VERT
- + alternative('a2')
- + rewrite))("alternatives"))("block")
- + RPAR)
-altList = alternative('a1') + rewrite + Group(ZeroOrMore(VERT + alternative('a2') + rewrite))("alternatives")
+rewrite = Optional(Literal("TODO REWRITE RULES TODO"))
+block <<= (
+ LPAR
+ + Optional(Optional(optionsSpec("opts")) + COLON)
+ + Group(
+ alternative("a1")
+ + rewrite
+ + Group(ZeroOrMore(VERT + alternative("a2") + rewrite))("alternatives")
+ )("block")
+ + RPAR
+)
+altList = (
+ alternative("a1")
+ + rewrite
+ + Group(ZeroOrMore(VERT + alternative("a2") + rewrite))("alternatives")
+)
exceptionHandler = CATCH.suppress() + ARG_ACTION + ACTION
finallyClause = FINALLY.suppress() + 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))
+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 + COLON + altList + SEMI + 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:
+ 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))
+ alternatives.append(
+ __antlrAlternativeConverter(pyparsingRules, alternative)
+ )
rule = MatchFirst(alternatives)("anonymous_or")
- elif hasattr(antlrBlock, 'a1') and antlrBlock.a1 != '':
+ elif hasattr(antlrBlock, "a1") and antlrBlock.a1 != "":
rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)
else:
- raise Exception('Not yet implemented')
+ 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]+']')
+ 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 != '':
+ elif hasattr(element, "block") and element.block != "":
rule = __antlrAlternativesConverter(pyparsingRules, element.block)
else:
ruleRef = element.atom[0]
assert ruleRef in pyparsingRules
rule = pyparsingRules[ruleRef](ruleRef)
- if hasattr(element, 'op') and element.op != '':
- if element.op == '+':
+ if hasattr(element, "op") and element.op != "":
+ if element.op == "+":
rule = Group(OneOrMore(rule))("anonymous_one_or_more")
- elif element.op == '*':
+ elif element.op == "*":
rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more")
- elif element.op == '?':
+ elif element.op == "?":
rule = Optional(rule)
else:
- raise Exception('rule operator not yet implemented : ' + element.op)
+ raise Exception("rule operator not yet implemented : " + element.op)
rule = rule
elementList.append(rule)
if len(elementList) > 1:
@@ -207,6 +310,7 @@ def __antlrAlternativeConverter(pyparsingRules, antlrAlternative):
assert rule is not None
return rule
+
def __antlrRuleConverter(pyparsingRules, antlrRule):
rule = None
rule = __antlrAlternativesConverter(pyparsingRules, antlrRule)
@@ -214,6 +318,7 @@ def __antlrRuleConverter(pyparsingRules, antlrRule):
rule(antlrRule.ruleName)
return rule
+
def antlrConverter(antlrGrammarTree):
pyparsingRules = {}
@@ -226,7 +331,7 @@ def antlrConverter(antlrGrammarTree):
antlrRules = {}
for antlrRule in antlrGrammarTree.rules:
antlrRules[antlrRule.ruleName] = antlrRule
- pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar
+ pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar
for antlrRuleName, antlrRule in list(antlrRules.items()):
pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule)
assert pyparsingRule != None
@@ -234,6 +339,7 @@ def antlrConverter(antlrGrammarTree):
return pyparsingRules
+
if __name__ == "__main__":
text = """\
diff --git a/examples/antlr_grammar_tests.py b/examples/antlr_grammar_tests.py
index 57d6cb6..17d8fa0 100644
--- a/examples/antlr_grammar_tests.py
+++ b/examples/antlr_grammar_tests.py
@@ -1,21 +1,20 @@
-'''
+"""
Created on 4 sept. 2010
@author: luca
Submitted by Luca DallOlio, September, 2010
-'''
+"""
import unittest
from . import antlr_grammar
-class Test(unittest.TestCase):
-
+class Test(unittest.TestCase):
def testOptionsSpec(self):
text = """options {
language = Python;
}"""
- antlr_grammar.optionsSpec.parseString(text) #@UndefinedVariable
+ antlr_grammar.optionsSpec.parseString(text) # @UndefinedVariable
def testTokensSpec(self):
text = """tokens {
@@ -24,23 +23,23 @@ class Test(unittest.TestCase):
MULT = '*' ;
DIV = '/' ;
}"""
- antlr_grammar.tokensSpec.parseString(text) #@UndefinedVariable
+ antlr_grammar.tokensSpec.parseString(text) # @UndefinedVariable
def testBlock(self):
text = """( PLUS | MINUS )"""
- antlr_grammar.block.parseString(text) #@UndefinedVariable
+ antlr_grammar.block.parseString(text) # @UndefinedVariable
def testRule(self):
text = """expr : term ( ( PLUS | MINUS ) term )* ;"""
- antlr_grammar.rule.parseString(text) #@UndefinedVariable
+ antlr_grammar.rule.parseString(text) # @UndefinedVariable
def testLexerRule(self):
text = """fragment DIGIT : '0'..'9' ;"""
- antlr_grammar.rule.parseString(text) #@UndefinedVariable
+ antlr_grammar.rule.parseString(text) # @UndefinedVariable
def testLexerRule2(self):
text = """WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;"""
- #antlr_grammar.rule.parseString(text) #@UndefinedVariable
+ # antlr_grammar.rule.parseString(text) #@UndefinedVariable
def testGrammar(self):
text = """grammar SimpleCalc;
@@ -76,16 +75,28 @@ NUMBER : (DIGIT)+ ;
/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */
fragment DIGIT : '0'..'9' ;"""
- antlrGrammarTree = antlr_grammar.grammarDef.parseString(text) #@UndefinedVariable
+ antlrGrammarTree = antlr_grammar.grammarDef.parseString(
+ text
+ ) # @UndefinedVariable
pyparsingRules = antlr_grammar.antlrConverter(antlrGrammarTree)
pyparsingRule = pyparsingRules["expr"]
pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25")
pyparsingTreeList = pyparsingTree.asList()
print(pyparsingTreeList)
- self.assertEqual(pyparsingTreeList,
- [[[['2'], []], [['-', [['5'], [['*', ['4', '2']]]]], ['+', [['7'], [['/', ['2', '5']]]]]]]]
- )
+ self.assertEqual(
+ pyparsingTreeList,
+ [
+ [
+ [["2"], []],
+ [
+ ["-", [["5"], [["*", ["4", "2"]]]]],
+ ["+", [["7"], [["/", ["2", "5"]]]]],
+ ],
+ ]
+ ],
+ )
+
if __name__ == "__main__":
- #import sys;sys.argv = ['', 'Test.testOptionsSpec']
+ # import sys;sys.argv = ['', 'Test.testOptionsSpec']
unittest.main()
diff --git a/examples/apicheck.py b/examples/apicheck.py
index cd35a9a..1905d4a 100644
--- a/examples/apicheck.py
+++ b/examples/apicheck.py
@@ -9,25 +9,24 @@
from pyparsing import *
# define punctuation and simple tokens for locating API calls
-LBRACK,RBRACK,LBRACE,RBRACE = map(Suppress,"[]{}")
-ident = Word(alphas,alphanums+"_") | QuotedString("{",endQuoteChar="}")
+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
+ 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),
- ])
+apiRef = FollowedBy("[") + MatchFirst(
+ [apiProc("procname1", 2), apiProc("procname2", 1), apiProc("procname3", 2),]
+)
test = """[ procname1 $par1 $par2 ]
other code here
@@ -45,13 +44,13 @@ test = """[ procname1 $par1 $par2 ]
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)))
+ 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)
+ print(pe.lineno, ":", pe.line)
# reset api scanner to start after this exception location
- test = "\n"*(pe.lineno-1)+test[pe.loc+1:]
+ test = "\n" * (pe.lineno - 1) + test[pe.loc + 1 :]
api_scanner = apiRef.scanString(test)
except StopIteration:
break
diff --git a/examples/bigquery_view_parser.py b/examples/bigquery_view_parser.py
index 0277a17..695ca30 100644
--- a/examples/bigquery_view_parser.py
+++ b/examples/bigquery_view_parser.py
@@ -16,6 +16,7 @@ from pyparsing import infixNotation, opAssoc, OneOrMore, Regex, nums
class BigQueryViewParser:
"""Parser to extract table info from BigQuery view definitions"""
+
_parser = None
_table_identifiers = set()
_with_aliases = set()
@@ -27,7 +28,8 @@ class BigQueryViewParser:
# relevant- aliases are not case sensitive
lower_aliases = BigQueryViewParser.lowercase_set_of_tuples(with_aliases)
tables = {
- x for x in table_identifiers
+ x
+ for x in table_identifiers
if not BigQueryViewParser.lowercase_of_tuple(x) in lower_aliases
}
@@ -62,6 +64,147 @@ class BigQueryViewParser:
# keywords
(
+ UNION,
+ ALL,
+ AND,
+ INTERSECT,
+ EXCEPT,
+ COLLATE,
+ ASC,
+ DESC,
+ ON,
+ USING,
+ NATURAL,
+ INNER,
+ CROSS,
+ LEFT,
+ RIGHT,
+ OUTER,
+ FULL,
+ JOIN,
+ AS,
+ INDEXED,
+ NOT,
+ SELECT,
+ DISTINCT,
+ FROM,
+ WHERE,
+ GROUP,
+ BY,
+ HAVING,
+ ORDER,
+ BY,
+ LIMIT,
+ OFFSET,
+ OR,
+ 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,
+ WITH,
+ EXTRACT,
+ PARTITION,
+ ROWS,
+ RANGE,
+ UNBOUNDED,
+ PRECEDING,
+ CURRENT,
+ ROW,
+ FOLLOWING,
+ OVER,
+ INTERVAL,
+ DATE_ADD,
+ DATE_SUB,
+ ADDDATE,
+ SUBDATE,
+ REGEXP_EXTRACT,
+ SPLIT,
+ ORDINAL,
+ FIRST_VALUE,
+ LAST_VALUE,
+ NTH_VALUE,
+ LEAD,
+ LAG,
+ PERCENTILE_CONT,
+ PRECENTILE_DISC,
+ RANK,
+ DENSE_RANK,
+ PERCENT_RANK,
+ CUME_DIST,
+ NTILE,
+ ROW_NUMBER,
+ DATE,
+ TIME,
+ DATETIME,
+ TIMESTAMP,
+ UNNEST,
+ INT64,
+ NUMERIC,
+ FLOAT64,
+ BOOL,
+ BYTES,
+ GEOGRAPHY,
+ ARRAY,
+ STRUCT,
+ SAFE_CAST,
+ ANY_VALUE,
+ ARRAY_AGG,
+ ARRAY_CONCAT_AGG,
+ AVG,
+ BIT_AND,
+ BIT_OR,
+ BIT_XOR,
+ COUNT,
+ COUNTIF,
+ LOGICAL_AND,
+ LOGICAL_OR,
+ MAX,
+ MIN,
+ STRING_AGG,
+ SUM,
+ CORR,
+ COVAR_POP,
+ COVAR_SAMP,
+ STDDEV_POP,
+ STDDEV_SAMP,
+ STDDEV,
+ VAR_POP,
+ VAR_SAMP,
+ VARIANCE,
+ TIMESTAMP_ADD,
+ TIMESTAMP_SUB,
+ GENERATE_ARRAY,
+ GENERATE_DATE_ARRAY,
+ GENERATE_TIMESTAMP_ARRAY,
+ FOR,
+ SYSTEMTIME,
+ AS,
+ OF,
+ WINDOW,
+ RESPECT,
+ IGNORE,
+ NULLS,
+ ) = map(
+ CaselessKeyword,
+ """
UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING,
NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, JOIN, AS, INDEXED,
NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY,
@@ -81,50 +224,100 @@ class BigQueryViewParser:
VAR_SAMP, VARIANCE, TIMESTAMP_ADD, TIMESTAMP_SUB, GENERATE_ARRAY,
GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY, FOR, SYSTEMTIME, AS,
OF, WINDOW, RESPECT, IGNORE, NULLS
- ) = map(CaselessKeyword,
- """
- UNION, ALL, AND, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING,
- NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, JOIN, AS, INDEXED,
- NOT, SELECT, DISTINCT, FROM, WHERE, GROUP, BY, HAVING, ORDER, BY,
- LIMIT, OFFSET, OR, 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, WITH,
- EXTRACT, PARTITION, ROWS, RANGE, UNBOUNDED, PRECEDING, CURRENT,
- ROW, FOLLOWING, OVER, INTERVAL, DATE_ADD, DATE_SUB, ADDDATE,
- SUBDATE, REGEXP_EXTRACT, SPLIT, ORDINAL, FIRST_VALUE, LAST_VALUE,
- NTH_VALUE, LEAD, LAG, PERCENTILE_CONT, PRECENTILE_DISC, RANK,
- DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE, ROW_NUMBER, DATE, TIME,
- DATETIME, TIMESTAMP, UNNEST, INT64, NUMERIC, FLOAT64, BOOL, BYTES,
- GEOGRAPHY, ARRAY, STRUCT, SAFE_CAST, ANY_VALUE, ARRAY_AGG,
- ARRAY_CONCAT_AGG, AVG, BIT_AND, BIT_OR, BIT_XOR, COUNT, COUNTIF,
- LOGICAL_AND, LOGICAL_OR, MAX, MIN, STRING_AGG, SUM, CORR,
- COVAR_POP, COVAR_SAMP, STDDEV_POP, STDDEV_SAMP, STDDEV, VAR_POP,
- VAR_SAMP, VARIANCE, TIMESTAMP_ADD, TIMESTAMP_SUB, GENERATE_ARRAY,
- GENERATE_DATE_ARRAY, GENERATE_TIMESTAMP_ARRAY, FOR, SYSTEMTIME, AS,
- OF, WINDOW, RESPECT, IGNORE, NULLS
- """.replace(",", "").split())
+ """.replace(
+ ",", ""
+ ).split(),
+ )
- keyword_nonfunctions = MatchFirst((
- UNION, ALL, INTERSECT, EXCEPT, COLLATE, ASC, DESC, ON, USING,
- NATURAL, INNER, CROSS, LEFT, RIGHT, OUTER, FULL, 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,
- STRUCT, WINDOW))
+ keyword_nonfunctions = MatchFirst(
+ (
+ UNION,
+ ALL,
+ INTERSECT,
+ EXCEPT,
+ COLLATE,
+ ASC,
+ DESC,
+ ON,
+ USING,
+ NATURAL,
+ INNER,
+ CROSS,
+ LEFT,
+ RIGHT,
+ OUTER,
+ FULL,
+ 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,
+ STRUCT,
+ WINDOW,
+ )
+ )
- keyword = keyword_nonfunctions | MatchFirst((
- ESCAPE, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, DATE_ADD,
- DATE_SUB, ADDDATE, SUBDATE, INTERVAL, STRING_AGG, REGEXP_EXTRACT,
- SPLIT, ORDINAL, UNNEST, SAFE_CAST, PARTITION, TIMESTAMP_ADD,
- TIMESTAMP_SUB, ARRAY, GENERATE_ARRAY, GENERATE_DATE_ARRAY,
- GENERATE_TIMESTAMP_ARRAY))
+ keyword = keyword_nonfunctions | MatchFirst(
+ (
+ ESCAPE,
+ CURRENT_TIME,
+ CURRENT_DATE,
+ CURRENT_TIMESTAMP,
+ DATE_ADD,
+ DATE_SUB,
+ ADDDATE,
+ SUBDATE,
+ INTERVAL,
+ STRING_AGG,
+ REGEXP_EXTRACT,
+ SPLIT,
+ ORDINAL,
+ UNNEST,
+ SAFE_CAST,
+ PARTITION,
+ TIMESTAMP_ADD,
+ TIMESTAMP_SUB,
+ ARRAY,
+ GENERATE_ARRAY,
+ GENERATE_DATE_ARRAY,
+ GENERATE_TIMESTAMP_ARRAY,
+ )
+ )
- identifier_word = Word(alphas + '_@#', alphanums + '@$#_')
+ identifier_word = Word(alphas + "_@#", alphanums + "@$#_")
identifier = ~keyword + identifier_word.copy()
collation_name = identifier.copy()
# NOTE: Column names can be keywords. Doc says they cannot, but in practice it seems to work.
column_name = identifier_word.copy()
- qualified_column_name = Combine(column_name + ('.' + column_name) * (0, 6))
+ qualified_column_name = Combine(column_name + ("." + column_name) * (0, 6))
# NOTE: As with column names, column aliases can be keywords, e.g. functions like `current_time`. Other
# keywords, e.g. `from` make parsing pretty difficult (e.g. "SELECT a from from b" is confusing.)
column_alias = ~keyword_nonfunctions + column_name.copy()
@@ -135,15 +328,14 @@ class BigQueryViewParser:
parameter_name = identifier.copy()
# NOTE: The expression in a CASE statement can be an integer. E.g. this is valid SQL:
# select CASE 1 WHEN 1 THEN -1 ELSE -2 END from test_table
- unquoted_case_identifier = ~keyword + Word(alphanums + '$_')
+ unquoted_case_identifier = ~keyword + Word(alphanums + "$_")
quoted_case_identifier = ~keyword + (
- QuotedString('"') ^ Suppress('`')
- + CharsNotIn('`') + Suppress('`')
+ QuotedString('"') ^ Suppress("`") + CharsNotIn("`") + Suppress("`")
)
- case_identifier = (quoted_case_identifier | unquoted_case_identifier)
+ case_identifier = quoted_case_identifier | unquoted_case_identifier
case_expr = (
- Optional(case_identifier + Suppress('.'))
- + Optional(case_identifier + Suppress('.'))
+ Optional(case_identifier + Suppress("."))
+ + Optional(case_identifier + Suppress("."))
+ case_identifier
)
@@ -152,82 +344,109 @@ class BigQueryViewParser:
integer = Regex(r"[+-]?\d+")
numeric_literal = Regex(r"[+-]?\d*\.?\d+([eE][+-]?\d+)?")
- string_literal = (
- QuotedString("'")
- | QuotedString('"')
- | QuotedString('`')
- )
+ string_literal = QuotedString("'") | QuotedString('"') | QuotedString("`")
regex_literal = "r" + string_literal
blob_literal = Regex(r"[xX]'[0-9A-Fa-f]+'")
- date_or_time_literal = (
- (DATE | TIME | DATETIME | TIMESTAMP)
- + string_literal
- )
+ date_or_time_literal = (DATE | TIME | DATETIME | TIMESTAMP) + string_literal
literal_value = (
- numeric_literal | string_literal | regex_literal
- | blob_literal | date_or_time_literal | NULL
+ numeric_literal
+ | string_literal
+ | regex_literal
+ | blob_literal
+ | date_or_time_literal
+ | NULL
| CURRENT_TIME + Optional(LPAR + Optional(string_literal) + RPAR)
| CURRENT_DATE + Optional(LPAR + Optional(string_literal) + RPAR)
- | CURRENT_TIMESTAMP
- + Optional(LPAR + Optional(string_literal) + RPAR)
- )
- bind_parameter = (
- Word("?", nums)
- | Combine(oneOf(": @ $") + parameter_name)
+ | CURRENT_TIMESTAMP + Optional(LPAR + Optional(string_literal) + RPAR)
)
- type_name = oneOf("""TEXT REAL INTEGER BLOB NULL TIMESTAMP STRING DATE
+ bind_parameter = Word("?", nums) | Combine(oneOf(": @ $") + parameter_name)
+ type_name = oneOf(
+ """TEXT REAL INTEGER BLOB NULL TIMESTAMP STRING DATE
INT64 NUMERIC FLOAT64 BOOL BYTES DATETIME GEOGRAPHY TIME ARRAY
- STRUCT""", caseless=True)
- date_part = oneOf("""DAY DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND
+ STRUCT""",
+ caseless=True,
+ )
+ date_part = oneOf(
+ """DAY DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND
HOUR HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND MICROSECOND MINUTE
MINUTE_MICROSECOND MINUTE_SECOND MONTH QUARTER SECOND
- SECOND_MICROSECOND WEEK YEAR YEAR_MONTH""", caseless=True)
+ SECOND_MICROSECOND WEEK YEAR YEAR_MONTH""",
+ caseless=True,
+ )
datetime_operators = (
- DATE_ADD | DATE_SUB | ADDDATE | SUBDATE | TIMESTAMP_ADD
- | TIMESTAMP_SUB
+ DATE_ADD | DATE_SUB | ADDDATE | SUBDATE | TIMESTAMP_ADD | TIMESTAMP_SUB
)
grouping_term = expr.copy()
ordering_term = Group(
- expr('order_key')
- + Optional(COLLATE + collation_name('collate'))
- + Optional(ASC | DESC)('direction')
+ expr("order_key")
+ + Optional(COLLATE + collation_name("collate"))
+ + Optional(ASC | DESC)("direction")
)("ordering_term")
function_arg = expr.copy()("function_arg")
function_args = Optional(
"*"
- | Optional(DISTINCT) + delimitedList(function_arg) + Optional((RESPECT | IGNORE) + NULLS)
+ | Optional(DISTINCT)
+ + delimitedList(function_arg)
+ + Optional((RESPECT | IGNORE) + NULLS)
)("function_args")
function_call = (
(function_name | keyword)("function_name")
- + LPAR + Group(function_args)("function_args_group") + RPAR
+ + LPAR
+ + Group(function_args)("function_args_group")
+ + RPAR
)
navigation_function_name = (
- FIRST_VALUE | LAST_VALUE | NTH_VALUE | LEAD | LAG
- | PERCENTILE_CONT | PRECENTILE_DISC
+ FIRST_VALUE
+ | LAST_VALUE
+ | NTH_VALUE
+ | LEAD
+ | LAG
+ | PERCENTILE_CONT
+ | PRECENTILE_DISC
)
aggregate_function_name = (
- ANY_VALUE | ARRAY_AGG | ARRAY_CONCAT_AGG | AVG | BIT_AND | BIT_OR
- | BIT_XOR | COUNT | COUNTIF | LOGICAL_AND | LOGICAL_OR | MAX | MIN
- | STRING_AGG | SUM
+ ANY_VALUE
+ | ARRAY_AGG
+ | ARRAY_CONCAT_AGG
+ | AVG
+ | BIT_AND
+ | BIT_OR
+ | BIT_XOR
+ | COUNT
+ | COUNTIF
+ | LOGICAL_AND
+ | LOGICAL_OR
+ | MAX
+ | MIN
+ | STRING_AGG
+ | SUM
)
statistical_aggregate_function_name = (
- CORR | COVAR_POP | COVAR_SAMP | STDDEV_POP | STDDEV_SAMP | STDDEV
- | VAR_POP | VAR_SAMP | VARIANCE
+ CORR
+ | COVAR_POP
+ | COVAR_SAMP
+ | STDDEV_POP
+ | STDDEV_SAMP
+ | STDDEV
+ | VAR_POP
+ | VAR_SAMP
+ | VARIANCE
)
numbering_function_name = (
- RANK | DENSE_RANK | PERCENT_RANK | CUME_DIST | NTILE | ROW_NUMBER)
+ RANK | DENSE_RANK | PERCENT_RANK | CUME_DIST | NTILE | ROW_NUMBER
+ )
analytic_function_name = (
navigation_function_name
| aggregate_function_name
| statistical_aggregate_function_name
| numbering_function_name
)("analytic_function_name")
- partition_expression_list = delimitedList(
- grouping_term
- )("partition_expression_list")
+ partition_expression_list = delimitedList(grouping_term)(
+ "partition_expression_list"
+ )
window_frame_boundary_start = (
UNBOUNDED + PRECEDING
| numeric_literal + (PRECEDING | FOLLOWING)
@@ -239,15 +458,9 @@ class BigQueryViewParser:
| CURRENT + ROW
)
window_frame_clause = (ROWS | RANGE) + (
- (
- (UNBOUNDED + PRECEDING)
- | (numeric_literal + PRECEDING)
- | (CURRENT + ROW)
- ) |
- (
- BETWEEN + window_frame_boundary_start
- + AND + window_frame_boundary_end
- ))
+ ((UNBOUNDED + PRECEDING) | (numeric_literal + PRECEDING) | (CURRENT + ROW))
+ | (BETWEEN + window_frame_boundary_start + AND + window_frame_boundary_end)
+ )
window_name = identifier.copy()("window_name")
window_specification = (
Optional(window_name)
@@ -257,8 +470,11 @@ class BigQueryViewParser:
)
analytic_function = (
analytic_function_name
- + LPAR + function_args + RPAR
- + OVER + (window_name | LPAR + Optional(window_specification) + RPAR)
+ + LPAR
+ + function_args
+ + RPAR
+ + OVER
+ + (window_name | LPAR + Optional(window_specification) + RPAR)
)("analytic_function")
string_agg_term = (
@@ -268,9 +484,7 @@ class BigQueryViewParser:
+ expr
+ Optional(COMMA + string_literal)
+ Optional(
- ORDER + BY + expr
- + Optional(ASC | DESC)
- + Optional(LIMIT + integer)
+ ORDER + BY + expr + Optional(ASC | DESC) + Optional(LIMIT + integer)
)
+ RPAR
)("string_agg")
@@ -317,25 +531,22 @@ class BigQueryViewParser:
CASE
+ Optional(case_expr.copy())
+ case_clauses("case_clauses")
- + Optional(case_else) + END
+ + Optional(case_else)
+ + END
)("case")
expr_term = (
(analytic_function)("analytic_function")
| (CAST + LPAR + expr + AS + type_name + RPAR)("cast")
| (SAFE_CAST + LPAR + expr + AS + type_name + RPAR)("safe_cast")
- | (
- Optional(EXISTS)
- + LPAR + ungrouped_select_stmt + RPAR
- )("subselect")
+ | (Optional(EXISTS) + LPAR + ungrouped_select_stmt + RPAR)("subselect")
| (literal_value)("literal")
| (bind_parameter)("bind_parameter")
| (EXTRACT + LPAR + expr + FROM + expr + RPAR)("extract")
| case_stmt
- | (
- datetime_operators
- + LPAR + expr + COMMA + interval + RPAR
- )("date_operation")
+ | (datetime_operators + LPAR + expr + COMMA + interval + RPAR)(
+ "date_operation"
+ )
| string_agg_term("string_agg_term")
| array_literal("array_literal")
| array_generator("array_generator")
@@ -343,49 +554,52 @@ class BigQueryViewParser:
| explicit_struct("explicit_struct")
| function_call("function_call")
| qualified_column_name("column")
- ) + Optional(
- LBRACKET
- + (OFFSET | ORDINAL)
- + LPAR + expr + RPAR
- + RBRACKET
- )("offset_ordinal")
+ ) + Optional(LBRACKET + (OFFSET | ORDINAL) + LPAR + expr + RPAR + RBRACKET)(
+ "offset_ordinal"
+ )
- struct_term = (LPAR + delimitedList(expr_term) + RPAR)
+ struct_term = LPAR + delimitedList(expr_term) + RPAR
UNARY, BINARY, TERNARY = 1, 2, 3
- expr << infixNotation((expr_term | struct_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),
- (
- IS + Optional(NOT)
- | Optional(NOT) + IN
- | Optional(NOT) + LIKE
- | GLOB
- | MATCH
- | REGEXP, BINARY, opAssoc.LEFT
- ),
- ((BETWEEN, AND), TERNARY, opAssoc.LEFT),
- (
- Optional(NOT) + IN
- + LPAR
- + Group(ungrouped_select_stmt | delimitedList(expr))
- + RPAR,
- UNARY,
- opAssoc.LEFT
- ),
- (AND, BINARY, opAssoc.LEFT),
- (OR, BINARY, opAssoc.LEFT),
- ])
+ expr << infixNotation(
+ (expr_term | struct_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),
+ (
+ IS + Optional(NOT)
+ | Optional(NOT) + IN
+ | Optional(NOT) + LIKE
+ | GLOB
+ | MATCH
+ | REGEXP,
+ BINARY,
+ opAssoc.LEFT,
+ ),
+ ((BETWEEN, AND), TERNARY, opAssoc.LEFT),
+ (
+ Optional(NOT)
+ + IN
+ + LPAR
+ + Group(ungrouped_select_stmt | delimitedList(expr))
+ + RPAR,
+ UNARY,
+ opAssoc.LEFT,
+ ),
+ (AND, BINARY, opAssoc.LEFT),
+ (OR, BINARY, opAssoc.LEFT),
+ ],
+ )
quoted_expr = (
expr
^ Suppress('"') + expr + Suppress('"')
^ Suppress("'") + expr + Suppress("'")
- ^ Suppress('`') + expr + Suppress('`')
+ ^ Suppress("`") + expr + Suppress("`")
)("quoted_expr")
compound_operator = (
@@ -399,10 +613,9 @@ class BigQueryViewParser:
join_constraint = Group(
Optional(
ON + expr
- | USING + LPAR
- + Group(delimitedList(qualified_column_name))
- + RPAR
- ))("join_constraint")
+ | USING + LPAR + Group(delimitedList(qualified_column_name)) + RPAR
+ )
+ )("join_constraint")
join_op = (
COMMA
@@ -418,7 +631,8 @@ class BigQueryViewParser:
| FULL + OUTER
| OUTER
| FULL
- ) + JOIN
+ )
+ + JOIN
)
)("join_op")
@@ -449,8 +663,8 @@ class BigQueryViewParser:
standard_table_part = ~keyword + Word(alphanums + "_")
standard_table_identifier = (
- Optional(standard_table_part("project") + Suppress('.'))
- + Optional(standard_table_part("dataset") + Suppress('.'))
+ Optional(standard_table_part("project") + Suppress("."))
+ + Optional(standard_table_part("dataset") + Suppress("."))
+ standard_table_part("table")
).setParseAction(lambda t: record_table_identifier(t))
@@ -465,13 +679,13 @@ class BigQueryViewParser:
| Suppress("`") + CharsNotIn("`.") + Suppress("`")
)
quoted_table_parts_identifier = (
- Optional(quoted_project_part("project") + Suppress('.'))
- + Optional(quoted_table_part("dataset") + Suppress('.'))
+ Optional(quoted_project_part("project") + Suppress("."))
+ + Optional(quoted_table_part("dataset") + Suppress("."))
+ quoted_table_part("table")
).setParseAction(lambda t: record_table_identifier(t))
def record_quoted_table_identifier(t):
- identifier_list = t.asList()[0].split('.')
+ identifier_list = t.asList()[0].split(".")
first = ".".join(identifier_list[0:-2]) or None
second = identifier_list[-2]
third = identifier_list[-1]
@@ -486,19 +700,16 @@ class BigQueryViewParser:
).setParseAction(lambda t: record_quoted_table_identifier(t))
table_identifier = (
- standard_table_identifier |
- quoted_table_parts_identifier |
- quotable_table_parts_identifier
+ standard_table_identifier
+ | quoted_table_parts_identifier
+ | quotable_table_parts_identifier
)
single_source = (
table_identifier
+ Optional(Optional(AS) + table_alias("table_alias*"))
+ Optional(FOR + SYSTEMTIME + AS + OF + string_literal)
- + Optional(
- INDEXED + BY + index_name("name")
- | NOT + INDEXED
- )("index")
+ + Optional(INDEXED + BY + index_name("name") | NOT + INDEXED)("index")
| (
LPAR
+ ungrouped_select_stmt
@@ -506,23 +717,18 @@ class BigQueryViewParser:
+ Optional(Optional(AS) + table_alias)
)
| (LPAR + join_source + RPAR)
- | (UNNEST + LPAR + expr + RPAR)
- + Optional(Optional(AS) + column_alias)
+ | (UNNEST + LPAR + expr + RPAR) + Optional(Optional(AS) + column_alias)
)
join_source << (
- Group(
- single_source
- + OneOrMore(join_op + single_source + join_constraint)
- )
+ Group(single_source + OneOrMore(join_op + single_source + join_constraint))
| single_source
)
- over_partition = (
- PARTITION + BY
- + delimitedList(partition_expression_list)
- )("over_partition")
- over_order = (ORDER + BY + delimitedList(ordering_term))
+ over_partition = (PARTITION + BY + delimitedList(partition_expression_list))(
+ "over_partition"
+ )
+ over_order = ORDER + BY + delimitedList(ordering_term)
over_unsigned_value_specification = expr
over_window_frame_preceding = (
UNBOUNDED + PRECEDING
@@ -535,17 +741,15 @@ class BigQueryViewParser:
| CURRENT + ROW
)
over_window_frame_bound = (
- over_window_frame_preceding
- | over_window_frame_following
+ over_window_frame_preceding | over_window_frame_following
)
over_window_frame_between = (
BETWEEN + over_window_frame_bound + AND + over_window_frame_bound
)
over_window_frame_extent = (
- over_window_frame_preceding
- | over_window_frame_between
+ over_window_frame_preceding | over_window_frame_between
)
- over_row_or_range = ((ROWS | RANGE) + over_window_frame_extent)
+ over_row_or_range = (ROWS | RANGE) + over_window_frame_extent
over = (
OVER
+ LPAR
@@ -555,18 +759,13 @@ class BigQueryViewParser:
+ RPAR
)("over")
- result_column = (
- Optional(table_name + ".")
- + "*"
- + Optional(EXCEPT + LPAR + delimitedList(column_name) + RPAR)
- | Group(
- quoted_expr
- + Optional(over)
- + Optional(Optional(AS) + column_alias)
- )
- )
+ result_column = Optional(table_name + ".") + "*" + Optional(
+ EXCEPT + LPAR + delimitedList(column_name) + RPAR
+ ) | Group(quoted_expr + Optional(over) + Optional(Optional(AS) + column_alias))
- window_select_clause = WINDOW + identifier + AS + LPAR + window_specification + RPAR
+ window_select_clause = (
+ WINDOW + identifier + AS + LPAR + window_specification + RPAR
+ )
select_core = (
SELECT
@@ -575,17 +774,13 @@ class BigQueryViewParser:
+ Optional(FROM + join_source("from*"))
+ Optional(WHERE + expr)
+ Optional(
- GROUP + BY
- + Group(delimitedList(grouping_term))("group_by_terms")
+ GROUP + BY + Group(delimitedList(grouping_term))("group_by_terms")
)
+ Optional(HAVING + expr("having_expr"))
+ Optional(
- ORDER + BY
- + Group(delimitedList(ordering_term))("order_by_terms")
- )
- + Optional(
- delimitedList(window_select_clause)
+ ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms")
)
+ + Optional(delimitedList(window_select_clause))
)
grouped_select_core = select_core | (LPAR + select_core + RPAR)
@@ -594,17 +789,15 @@ class BigQueryViewParser:
+ ZeroOrMore(compound_operator + grouped_select_core)
+ Optional(
LIMIT
- + (
- Group(expr + OFFSET + expr)
- | Group(expr + COMMA + expr)
- | expr
- )("limit")
+ + (Group(expr + OFFSET + expr) | Group(expr + COMMA + expr) | expr)(
+ "limit"
+ )
)
)("select")
select_stmt = ungrouped_select_stmt | (LPAR + ungrouped_select_stmt + RPAR)
# define comment format, and ignore them
- sql_comment = (oneOf("-- #") + restOfLine | cStyleComment)
+ sql_comment = oneOf("-- #") + restOfLine | cStyleComment
select_stmt.ignore(sql_comment)
def record_with_alias(t):
@@ -616,16 +809,18 @@ class BigQueryViewParser:
with_clause = Group(
identifier.setParseAction(lambda t: record_with_alias(t))
+ AS
- + LPAR + (select_stmt | with_stmt) + RPAR
+ + LPAR
+ + (select_stmt | with_stmt)
+ + RPAR
)
- with_core = (WITH + delimitedList(with_clause))
+ with_core = WITH + delimitedList(with_clause)
with_stmt << (with_core + ungrouped_select_stmt)
with_stmt.ignore(sql_comment)
- select_or_with = (select_stmt | with_stmt)
+ select_or_with = select_stmt | with_stmt
select_or_with_parens = LPAR + select_or_with + RPAR
- cls._parser = (select_or_with | select_or_with_parens)
+ cls._parser = select_or_with | select_or_with_parens
return cls._parser
TEST_CASES = [
@@ -633,86 +828,61 @@ class BigQueryViewParser:
"""
SELECT x FROM y.a, b
""",
- [
- (None, "y", "a"),
- (None, None, "b",),
- ]
+ [(None, "y", "a"), (None, None, "b",),],
],
[
"""
SELECT x FROM y.a JOIN b
""",
- [
- (None, "y", "a"),
- (None, None, "b"),
- ]
+ [(None, "y", "a"), (None, None, "b"),],
],
[
"""
select * from xyzzy where z > 100
""",
- [
- (None, None, "xyzzy"),
- ]
+ [(None, None, "xyzzy"),],
],
[
"""
select * from xyzzy where z > 100 order by zz
""",
- [
- (None, None, "xyzzy"),
- ]
+ [(None, None, "xyzzy"),],
],
[
"""
select * from xyzzy
""",
- [
- (None, None, "xyzzy",),
- ]
+ [(None, None, "xyzzy",),],
],
[
"""
select z.* from xyzzy
""",
- [
- (None, None, "xyzzy",),
- ]
+ [(None, None, "xyzzy",),],
],
[
"""
select a, b from test_table where 1=1 and b='yes'
""",
- [
- (None, None, "test_table"),
- ]
+ [(None, None, "test_table"),],
],
[
"""
select a, b from test_table where 1=1 and b in (select bb from foo)
""",
- [
- (None, None, "test_table"),
- (None, None, "foo"),
- ]
+ [(None, None, "test_table"), (None, None, "foo"),],
],
[
"""
select z.a, b from test_table where 1=1 and b in (select bb from foo)
""",
- [
- (None, None, "test_table"),
- (None, None, "foo"),
- ]
+ [(None, None, "test_table"), (None, None, "foo"),],
],
[
"""
select z.a, b from test_table where 1=1 and b in (select bb from foo) order by b,c desc,d
""",
- [
- (None, None, "test_table"),
- (None, None, "foo"),
- ]
+ [(None, None, "test_table"), (None, None, "foo"),],
],
[
"""
@@ -722,41 +892,31 @@ class BigQueryViewParser:
(None, None, "test_table"),
(None, None, "test2_table"),
(None, None, "foo"),
- ]
+ ],
],
[
"""
select a, db.table.b as BBB from db.table where 1=1 and BBB='yes'
""",
- [
- (None, "db", "table"),
- ]
+ [(None, "db", "table"),],
],
[
"""
select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes'
""",
- [
- (None, None, "test_table"),
- (None, "db", "table"),
- ]
+ [(None, None, "test_table"), (None, "db", "table"),],
],
[
"""
select a, db.table.b as BBB from test_table,db.table where 1=1 and BBB='yes' limit 50
""",
- [
- (None, None, "test_table"),
- (None, "db", "table"),
- ]
+ [(None, None, "test_table"), (None, "db", "table"),],
],
[
"""
select a, b from test_table where (1=1 or 2=3) and b='yes' group by zx having b=2 order by 1
""",
- [
- (None, None, "test_table"),
- ]
+ [(None, None, "test_table"),],
],
[
"""
@@ -771,44 +931,31 @@ class BigQueryViewParser:
#yup, a comment
group by zx having b=2 order by 1
""",
- [
- (None, None, "test_table"),
- ]
+ [(None, None, "test_table"),],
],
[
"""
SELECT COUNT(DISTINCT foo) FROM bar JOIN baz ON bar.baz_id = baz.id
""",
- [
- (None, None, "bar"),
- (None, None, "baz"),
- ]
+ [(None, None, "bar"), (None, None, "baz"),],
],
[
"""
SELECT COUNT(DISTINCT foo) FROM bar, baz WHERE bar.baz_id = baz.id
""",
- [
- (None, None, "bar"),
- (None, None, "baz"),
- ]
+ [(None, None, "bar"), (None, None, "baz"),],
],
[
"""
WITH one AS (SELECT id FROM foo) SELECT one.id
""",
- [
- (None, None, "foo"),
- ]
+ [(None, None, "foo"),],
],
[
"""
WITH one AS (SELECT id FROM foo), two AS (select id FROM bar) SELECT one.id, two.id
""",
- [
- (None, None, "foo"),
- (None, None, "bar"),
- ]
+ [(None, None, "foo"), (None, None, "bar"),],
],
[
"""
@@ -818,9 +965,7 @@ class BigQueryViewParser:
ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) AS row_num
FROM a
""",
- [
- (None, None, "a",),
- ]
+ [(None, None, "a",),],
],
[
"""
@@ -828,9 +973,7 @@ class BigQueryViewParser:
RANGE BETWEEN 2 PRECEDING AND 2 FOLLOWING ) AS count_x
FROM T
""",
- [
- (None, None, "T",),
- ]
+ [(None, None, "T",),],
],
[
"""
@@ -838,11 +981,8 @@ class BigQueryViewParser:
RANK() OVER ( PARTITION BY department ORDER BY startdate ) AS rank
FROM Employees
""",
- [
- (None, None, "Employees"),
- ]
+ [(None, None, "Employees"),],
],
-
# A fragment from https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -859,10 +999,8 @@ class BigQueryViewParser:
UNION ALL SELECT 'Carly Forte', TIMESTAMP '2016-10-18 3:08:58', 'F25-29'
UNION ALL SELECT 'Lauren Reasoner', TIMESTAMP '2016-10-18 3:10:14', 'F30-34'
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -893,10 +1031,8 @@ class BigQueryViewParser:
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS fastest_time
FROM finishers)
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -927,10 +1063,8 @@ class BigQueryViewParser:
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS slowest_time
FROM finishers)
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -965,10 +1099,8 @@ class BigQueryViewParser:
PARTITION BY division ORDER BY finish_time ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING))
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -992,10 +1124,8 @@ class BigQueryViewParser:
OVER (PARTITION BY division ORDER BY finish_time ASC) AS followed_by
FROM finishers
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -1019,10 +1149,8 @@ class BigQueryViewParser:
OVER (PARTITION BY division ORDER BY finish_time ASC) AS two_runners_back
FROM finishers
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -1046,10 +1174,8 @@ class BigQueryViewParser:
OVER (PARTITION BY division ORDER BY finish_time ASC) AS preceding_runner
FROM finishers
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -1061,10 +1187,8 @@ class BigQueryViewParser:
PERCENTILE_CONT(x, 1) OVER() AS max
FROM UNNEST([0, 3, NULL, 1, 2]) AS x LIMIT 1
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions
[
"""
@@ -1075,10 +1199,8 @@ class BigQueryViewParser:
PERCENTILE_DISC(x, 1) OVER() AS max
FROM UNNEST(['c', NULL, 'b', 'a']) AS x
""",
- [
- ]
+ [],
],
-
# From https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions
[
"""
@@ -1086,10 +1208,8 @@ class BigQueryViewParser:
TIMESTAMP "2008-12-25 15:30:00 UTC" as original,
TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00 UTC", INTERVAL 10 MINUTE) AS later
""",
- [
- ]
+ [],
],
-
# Previously hosted on https://cloud.google.com/bigquery/docs/reference/standard-sql/timestamp_functions, but
# appears to no longer be there
[
@@ -1178,7 +1298,7 @@ class BigQueryViewParser:
[
(None, "date_hour_slots", "full_timestamps"),
(None, "full_timestamps", "dt_range"),
- ]
+ ],
],
[
"""
@@ -1198,17 +1318,14 @@ class BigQueryViewParser:
FROM
bar
""",
- [
- (None, None, "bar"),
- ]
+ [(None, None, "bar"),],
],
[
"""
SELECT GENERATE_ARRAY(start, 5) AS example_array
FROM UNNEST([3, 4, 5]) AS start
""",
- [
- ]
+ [],
],
[
"""
@@ -1221,8 +1338,7 @@ class BigQueryViewParser:
SELECT GENERATE_DATE_ARRAY(date_start, date_end, INTERVAL 1 WEEK) AS date_range
FROM StartsAndEnds
""",
- [
- ]
+ [],
],
[
"""
@@ -1241,15 +1357,13 @@ class BigQueryViewParser:
TIMESTAMP '2016-10-05 23:59:00' AS start_timestamp,
TIMESTAMP '2016-10-06 01:59:00' AS end_timestamp)
""",
- [
- ]
+ [],
],
[
"""
SELECT DATE_SUB(current_date("-08:00")), INTERVAL 2 DAY)
""",
- [
- ]
+ [],
],
[
"""
@@ -1257,9 +1371,7 @@ class BigQueryViewParser:
case when (a) then b else c end
FROM d
""",
- [
- (None, None, "d",),
- ]
+ [(None, None, "d",),],
],
[
"""
@@ -1268,9 +1380,7 @@ class BigQueryViewParser:
case when (f) then g else h end
FROM i
""",
- [
- (None, None, "i",),
- ]
+ [(None, None, "i",),],
],
[
"""
@@ -1278,9 +1388,7 @@ class BigQueryViewParser:
case when j then k else l end
FROM m
""",
- [
- (None, None, "m",),
- ]
+ [(None, None, "m",),],
],
[
"""
@@ -1289,9 +1397,7 @@ class BigQueryViewParser:
case when o then p else q end
FROM r
""",
- [
- (None, None, "r",),
- ]
+ [(None, None, "r",),],
],
[
"""
@@ -1299,9 +1405,7 @@ class BigQueryViewParser:
case s when (t) then u else v end
FROM w
""",
- [
- (None, None, "w",),
- ]
+ [(None, None, "w",),],
],
[
"""
@@ -1310,18 +1414,15 @@ class BigQueryViewParser:
case y when (z) then aa else ab end
FROM ac
""",
- [
- (None, None, "ac",),
- ]
+ [(None, None, "ac",),],
],
[
"""
SELECT
case ad when ae then af else ag end
FROM ah
- """, [
- (None, None, "ah",),
- ]
+ """,
+ [(None, None, "ah",),],
],
[
"""
@@ -1330,9 +1431,7 @@ class BigQueryViewParser:
case aj when ak then al else am end
FROM an
""",
- [
- (None, None, "an",),
- ]
+ [(None, None, "an",),],
],
[
"""
@@ -1341,10 +1440,7 @@ class BigQueryViewParser:
TWO AS (select a FROM b)
SELECT y FROM onE JOIN TWo
""",
- [
- (None, None, "y",),
- (None, None, "b",),
- ]
+ [(None, None, "y",), (None, None, "b",),],
],
[
"""
@@ -1353,89 +1449,67 @@ class BigQueryViewParser:
(SELECT b FROM oNE)
FROM OnE
""",
- [
- (None, None, "oNE",),
- (None, None, "OnE",),
- ]
+ [(None, None, "oNE",), (None, None, "OnE",),],
],
[
"""
SELECT * FROM `a.b.c`
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM `b.c`
""",
- [
- (None, "b", "c"),
- ]
+ [(None, "b", "c"),],
],
[
"""
SELECT * FROM `c`
""",
- [
- (None, None, "c"),
- ]
- ], [
+ [(None, None, "c"),],
+ ],
+ [
"""
SELECT * FROM a.b.c
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM "a"."b"."c"
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM 'a'.'b'.'c'
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM `a`.`b`.`c`
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM "a.b.c"
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM 'a.b.c'
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
SELECT * FROM `a.b.c`
""",
- [
- ("a", "b", "c"),
- ]
+ [("a", "b", "c"),],
],
[
"""
@@ -1444,21 +1518,14 @@ class BigQueryViewParser:
WHERE t1.a IN (SELECT t2.a
FROM t2 ) FOR SYSTEM_TIME AS OF t1.timestamp_column)
""",
- [
- (None, None, "t1"),
- (None, None, "t2"),
- ]
+ [(None, None, "t1"), (None, None, "t2"),],
],
[
"""
WITH a AS (SELECT b FROM c)
SELECT d FROM A JOIN e ON f = g JOIN E ON h = i
""",
- [
- (None, None, "c"),
- (None, None, "e"),
- (None, None, "E"),
- ]
+ [(None, None, "c"), (None, None, "e"), (None, None, "E"),],
],
[
"""
@@ -1478,11 +1545,7 @@ class BigQueryViewParser:
select g from h
""",
- [
- (None, None, 'd'),
- (None, None, 'f'),
- (None, None, 'h'),
- ]
+ [(None, None, "d"), (None, None, "f"), (None, None, "h"),],
],
[
"""
@@ -1494,9 +1557,7 @@ class BigQueryViewParser:
e AS DATE_ADD
FROM x
""",
- [
- (None, None, 'x'),
- ]
+ [(None, None, "x"),],
],
[
"""
@@ -1507,22 +1568,16 @@ class BigQueryViewParser:
)
SELECT y FROM z
""",
- [
- (None, None, 'b'),
- (None, None, 'z')
- ]
+ [(None, None, "b"), (None, None, "z")],
],
-
[
"""
SELECT DISTINCT
FIRST_VALUE(x IGNORE NULLS) OVER (PARTITION BY y)
FROM z
""",
- [
- (None, None, 'z')
- ]
- ]
+ [(None, None, "z")],
+ ],
]
def test(self):
@@ -1533,8 +1588,10 @@ class BigQueryViewParser:
expected_tables_set = set(expected_tables)
if expected_tables_set != found_tables:
- raise Exception(f"Test {test_index} failed- expected {expected_tables_set} but got {found_tables}")
+ raise Exception(
+ f"Test {test_index} failed- expected {expected_tables_set} but got {found_tables}"
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
BigQueryViewParser().test()
diff --git a/examples/booleansearchparser.py b/examples/booleansearchparser.py
index d970e98..7ac502c 100644
--- a/examples/booleansearchparser.py
+++ b/examples/booleansearchparser.py
@@ -64,8 +64,8 @@ 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
+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:
@@ -81,46 +81,56 @@ TODO:
- add more kinds of wildcards ('*' at the beginning and '*' inside a word)?
"""
-from pyparsing import Word, alphanums, Keyword, Group, Forward, Suppress, OneOrMore, oneOf
+from pyparsing import (
+ Word,
+ alphanums,
+ Keyword,
+ Group,
+ Forward,
+ Suppress,
+ OneOrMore,
+ oneOf,
+)
import re
alphabet_ranges = [
##CYRILIC: https://en.wikipedia.org/wiki/Cyrillic_(Unicode_block)
- [int("0400",16), int("04FF",16)],
+ [int("0400", 16), int("04FF", 16)],
##THAI: https://en.wikipedia.org/wiki/Thai_(Unicode_block)
- [int("0E00",16), int("0E7F",16)],
+ [int("0E00", 16), int("0E7F", 16)],
##ARABIC: https://en.wikipedia.org/wiki/Arabic_(Unicode_block) (Arabic (0600–06FF)+ Syriac (0700–074F)+ Arabic Supplement (0750–077F) )
- [int("0600",16), int("07FF",16)],
+ [int("0600", 16), int("07FF", 16)],
##CHINESE: https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
- [int("0400",16), int("09FF",16)],
- #JAPANESE : https://en.wikipedia.org/wiki/Japanese_writing_system
- [int("3040",16), int("30FF",16)],
- #KOREAN : https://en.wikipedia.org/wiki/Hangul
- [int("AC00",16), int("D7AF",16)],
- [int("1100",16), int("11FF",16)],
- [int("3130",16), int("318F",16)],
- [int("3200",16), int("32FF",16)],
- [int("A960",16), int("A97F",16)],
- [int("D7B0",16), int("D7FF",16)],
- [int("FF00",16), int("FFEF",16)],
+ [int("0400", 16), int("09FF", 16)],
+ # JAPANESE : https://en.wikipedia.org/wiki/Japanese_writing_system
+ [int("3040", 16), int("30FF", 16)],
+ # KOREAN : https://en.wikipedia.org/wiki/Hangul
+ [int("AC00", 16), int("D7AF", 16)],
+ [int("1100", 16), int("11FF", 16)],
+ [int("3130", 16), int("318F", 16)],
+ [int("3200", 16), int("32FF", 16)],
+ [int("A960", 16), int("A97F", 16)],
+ [int("D7B0", 16), int("D7FF", 16)],
+ [int("FF00", 16), int("FFEF", 16)],
]
-class BooleanSearchParser:
- def __init__(self,only_parse=False):
+
+class BooleanSearchParser:
+ def __init__(self, only_parse=False):
self._methods = {
- 'and': self.evaluateAnd,
- 'or': self.evaluateOr,
- 'not': self.evaluateNot,
- 'parenthesis': self.evaluateParenthesis,
- 'quotes': self.evaluateQuotes,
- 'word': self.evaluateWord,
- 'wordwildcardprefix': self.evaluateWordWildcardPrefix,
- 'wordwildcardsufix': self.evaluateWordWildcardSufix,
+ "and": self.evaluateAnd,
+ "or": self.evaluateOr,
+ "not": self.evaluateNot,
+ "parenthesis": self.evaluateParenthesis,
+ "quotes": self.evaluateQuotes,
+ "word": self.evaluateWord,
+ "wordwildcardprefix": self.evaluateWordWildcardPrefix,
+ "wordwildcardsufix": self.evaluateWordWildcardSufix,
}
- self._parser = self.parser()
- self.text = ''
- self.words = []
+ self._parser = self.parser()
+ self.text = ""
+ self.words = []
def parser(self):
"""
@@ -141,47 +151,54 @@ class BooleanSearchParser:
alphabet = alphanums
- #suport for non-western alphabets
+ # suport for non-western alphabets
for r in alphabet_ranges:
- alphabet += ''.join(chr(c) for c in range(*r) if not chr(c).isspace())
-
- operatorWord = Group(
- Word(alphabet + '*')
- ).setResultsName('word*')
+ alphabet += "".join(chr(c) for c in range(*r) if not chr(c).isspace())
+ operatorWord = Group(Word(alphabet + "*")).setResultsName("word*")
operatorQuotesContent = Forward()
- operatorQuotesContent << (
- (operatorWord + operatorQuotesContent) | operatorWord
- )
+ operatorQuotesContent << ((operatorWord + operatorQuotesContent) | operatorWord)
- operatorQuotes = Group(
- Suppress('"') + operatorQuotesContent + Suppress('"')
- ).setResultsName("quotes") | operatorWord
+ operatorQuotes = (
+ Group(Suppress('"') + operatorQuotesContent + Suppress('"')).setResultsName(
+ "quotes"
+ )
+ | operatorWord
+ )
- operatorParenthesis = Group(
- Suppress("(") + operatorOr + Suppress(")")
- ).setResultsName("parenthesis") | operatorQuotes
+ operatorParenthesis = (
+ Group(Suppress("(") + operatorOr + Suppress(")")).setResultsName(
+ "parenthesis"
+ )
+ | operatorQuotes
+ )
operatorNot = Forward()
- operatorNot << (Group(
- Suppress(Keyword("not", caseless=True)) + operatorNot
- ).setResultsName("not") | operatorParenthesis)
+ 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(
+ ).setResultsName("and")
+ | Group(
operatorNot + OneOrMore(~oneOf("and or") + operatorAnd)
- ).setResultsName("and") |
- operatorNot
+ ).setResultsName("and")
+ | operatorNot
)
- operatorOr << (Group(
- operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr
- ).setResultsName("or") | operatorAnd)
+ operatorOr << (
+ Group(
+ operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr
+ ).setResultsName("or")
+ | operatorAnd
+ )
return operatorOr.parseString
@@ -204,26 +221,26 @@ class BooleanSearchParser:
function GetQuoted to only return the subset of ID's that contain the
literal string.
"""
- #r = set()
+ # r = set()
r = False
search_terms = []
for item in argument:
search_terms.append(item[0])
r = r and self.evaluate(item)
- return self.GetQuotes(' '.join(search_terms), r)
+ return self.GetQuotes(" ".join(search_terms), r)
def evaluateWord(self, argument):
wildcard_count = argument[0].count("*")
if wildcard_count > 0:
if wildcard_count == 1 and argument[0].startswith("*"):
- return self.GetWordWildcard(argument[0][1:], method = "endswith")
+ return self.GetWordWildcard(argument[0][1:], method="endswith")
if wildcard_count == 1 and argument[0].endswith("*"):
- return self.GetWordWildcard(argument[0][:-1], method = "startswith")
+ return self.GetWordWildcard(argument[0][:-1], method="startswith")
else:
- _regex = argument[0].replace("*",".+")
+ _regex = argument[0].replace("*", ".+")
matched = False
for w in self.words:
- matched = bool(re.search(_regex,w))
+ matched = bool(re.search(_regex, w))
if matched:
break
return matched
@@ -231,10 +248,10 @@ class BooleanSearchParser:
return self.GetWord(argument[0])
def evaluateWordWildcardPrefix(self, argument):
- return self.GetWordWildcard(argument[0], method = "endswith")
+ return self.GetWordWildcard(argument[0], method="endswith")
def evaluateWordWildcardSufix(self, argument):
- return self.GetWordWildcard(argument[0], method = "startswith")
+ return self.GetWordWildcard(argument[0], method="startswith")
def evaluate(self, argument):
return self._methods[argument.getName()](argument)
@@ -245,10 +262,10 @@ class BooleanSearchParser:
def GetWord(self, word):
return word in self.words
- def GetWordWildcard(self, word, method = "startswith"):
+ def GetWordWildcard(self, word, method="startswith"):
matched = False
for w in self.words:
- matched = getattr(w,method)(word)
+ matched = getattr(w, method)(word)
if matched:
break
return matched
@@ -265,24 +282,22 @@ class BooleanSearchParser:
def GetQuotes(self, search_string, tmp_result):
return search_string in self.text
-
def GetNot(self, not_set):
return not not_set
-
- def _split_words(self,text):
+ def _split_words(self, text):
words = []
"""
>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
"""
- #it will keep @, # and
- #usernames and hashtags can contain dots, so a double check is done
- r = re.compile(r'[\s{}]+'.format(re.escape('!"$%&\'()*+,-/:;<=>?[\\]^`{|}~')))
- _words = r.split(text)
+ # it will keep @, # and
+ # usernames and hashtags can contain dots, so a double check is done
+ r = re.compile(r"[\s{}]+".format(re.escape("!\"$%&'()*+,-/:;<=>?[\\]^`{|}~")))
+ _words = r.split(text)
for _w in _words:
- if '.' in _w and not _w.startswith("#") and not _w.startswith("@"):
+ if "." in _w and not _w.startswith("#") and not _w.startswith("@"):
for __w in _w.split("."):
words.append(__w)
continue
@@ -291,9 +306,9 @@ class BooleanSearchParser:
return words
- def match(self,text,expr):
- self.text = text
- self.words = self._split_words(text)
+ def match(self, text, expr):
+ self.text = text
+ self.words = self._split_words(text)
return self.Parse(expr)
@@ -305,72 +320,132 @@ class ParserTest(BooleanSearchParser):
def Test(self):
exprs = {
- '0' : 'help',
- '1' : 'help or hulp',
- '2' : 'help and hulp',
- '3' : 'help hulp',
- '4' : 'help and hulp or hilp',
- '5' : 'help or hulp and hilp',
- '6' : 'help or hulp or hilp or halp',
- '7' : '(help or hulp) and (hilp or halp)',
- '8' : 'help and (hilp or halp)',
- '9' : '(help and (hilp or halp)) or hulp',
- '10': 'not help',
- '11': 'not hulp and halp',
- '12': 'not (help and halp)',
- '13': '"help me please"',
- '14': '"help me please" or hulp',
- '15': '"help me please" or (hulp and halp)',
- '16': 'help*',
- '17': 'help or hulp*',
- '18': 'help* and hulp',
- '19': 'help and hulp* or hilp',
- '20': 'help* or hulp or hilp or halp',
- '21': '(help or hulp*) and (hilp* or halp)',
- '22': 'help* and (hilp* or halp*)',
- '23': '(help and (hilp* or halp)) or hulp*',
- '24': 'not help* and halp',
- '25': 'not (help* and helpe*)',
- '26': '"help* me please"',
- '27': '"help* me* please" or hulp*',
- '28': '"help me please*" or (hulp and halp)',
- '29': '"help me please" not (hulp and halp)',
- '30': '"help me please" hulp',
- '31': 'help and hilp and not holp',
- '32': 'help hilp not holp',
- '33': 'help hilp and not holp',
- '34': '*lp and halp',
- '35': '*신은 and 어떠세요',
+ "0": "help",
+ "1": "help or hulp",
+ "2": "help and hulp",
+ "3": "help hulp",
+ "4": "help and hulp or hilp",
+ "5": "help or hulp and hilp",
+ "6": "help or hulp or hilp or halp",
+ "7": "(help or hulp) and (hilp or halp)",
+ "8": "help and (hilp or halp)",
+ "9": "(help and (hilp or halp)) or hulp",
+ "10": "not help",
+ "11": "not hulp and halp",
+ "12": "not (help and halp)",
+ "13": '"help me please"',
+ "14": '"help me please" or hulp',
+ "15": '"help me please" or (hulp and halp)',
+ "16": "help*",
+ "17": "help or hulp*",
+ "18": "help* and hulp",
+ "19": "help and hulp* or hilp",
+ "20": "help* or hulp or hilp or halp",
+ "21": "(help or hulp*) and (hilp* or halp)",
+ "22": "help* and (hilp* or halp*)",
+ "23": "(help and (hilp* or halp)) or hulp*",
+ "24": "not help* and halp",
+ "25": "not (help* and helpe*)",
+ "26": '"help* me please"',
+ "27": '"help* me* please" or hulp*',
+ "28": '"help me please*" or (hulp and halp)',
+ "29": '"help me please" not (hulp and halp)',
+ "30": '"help me please" hulp',
+ "31": "help and hilp and not holp",
+ "32": "help hilp not holp",
+ "33": "help hilp and not holp",
+ "34": "*lp and halp",
+ "35": "*신은 and 어떠세요",
}
texts_matcheswith = {
"halp thinks he needs help": [
- "25", "22", "20", "21", "11", "17", "16", "23", "34", "1", "0", "5", "7", "6", "9", "8"
- ],
- "he needs halp": [
- "24", "25", "20", "11", "10", "12", "34", "6"
- ],
- "help": [
- "25", "20", "12", "17", "16", "1", "0", "5", "6"
+ "25",
+ "22",
+ "20",
+ "21",
+ "11",
+ "17",
+ "16",
+ "23",
+ "34",
+ "1",
+ "0",
+ "5",
+ "7",
+ "6",
+ "9",
+ "8",
],
+ "he needs halp": ["24", "25", "20", "11", "10", "12", "34", "6"],
+ "help": ["25", "20", "12", "17", "16", "1", "0", "5", "6"],
"help hilp": [
- "25", "22", "20", "32", "21", "12", "17", "16", "19", "31", "23", "1", "0", "5", "4", "7", "6", "9", "8", "33"
+ "25",
+ "22",
+ "20",
+ "32",
+ "21",
+ "12",
+ "17",
+ "16",
+ "19",
+ "31",
+ "23",
+ "1",
+ "0",
+ "5",
+ "4",
+ "7",
+ "6",
+ "9",
+ "8",
+ "33",
],
"help me please hulp": [
- "30", "25", "27", "20", "13", "12", "15", "14", "17", "16", "19", "18", "23", "29", "1", "0", "3", "2", "5", "4", "6", "9"
- ],
- "helper": [
- "20", "10", "12", "16"
+ "30",
+ "25",
+ "27",
+ "20",
+ "13",
+ "12",
+ "15",
+ "14",
+ "17",
+ "16",
+ "19",
+ "18",
+ "23",
+ "29",
+ "1",
+ "0",
+ "3",
+ "2",
+ "5",
+ "4",
+ "6",
+ "9",
],
+ "helper": ["20", "10", "12", "16"],
"hulp hilp": [
- "25", "27", "20", "21", "10", "12", "14", "17", "19", "23", "1", "5", "4", "7", "6", "9"
+ "25",
+ "27",
+ "20",
+ "21",
+ "10",
+ "12",
+ "14",
+ "17",
+ "19",
+ "23",
+ "1",
+ "5",
+ "4",
+ "7",
+ "6",
+ "9",
],
- "nothing": [
- "25", "10", "12"
- ],
- "안녕하세요, 당신은 어떠세요?": [
- "10", "12", "25", "35"
- ]
+ "nothing": ["25", "10", "12"],
+ "안녕하세요, 당신은 어떠세요?": ["10", "12", "25", "35"],
}
all_ok = True
@@ -382,16 +457,17 @@ class ParserTest(BooleanSearchParser):
test_passed = sorted(matches) == sorted(_matches)
if not test_passed:
- print('Failed', repr(text), 'expected', matches, 'matched', _matches)
+ print("Failed", repr(text), "expected", matches, "matched", _matches)
all_ok = all_ok and test_passed
return all_ok
-if __name__=='__main__':
+
+if __name__ == "__main__":
if ParserTest().Test():
- print ('All tests OK')
+ print("All tests OK")
exit(0)
else:
- print ('One or more tests FAILED')
+ print("One or more tests FAILED")
exit(1)
diff --git a/examples/btpyparse.py b/examples/btpyparse.py
index 39e5261..81ca4b0 100644
--- a/examples/btpyparse.py
+++ b/examples/btpyparse.py
@@ -10,22 +10,36 @@ Submitted by Matthew Brett, 2010
Simplified BSD license
"""
-from pyparsing import (Regex, Suppress, ZeroOrMore, Group, Optional, Forward,
- SkipTo, CaselessLiteral, Dict)
+from pyparsing import (
+ Regex,
+ Suppress,
+ ZeroOrMore,
+ Group,
+ Optional,
+ Forward,
+ SkipTo,
+ CaselessLiteral,
+ Dict,
+)
class Macro:
""" 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
# Character literals
-LCURLY,RCURLY,LPAREN,RPAREN,QUOTE,COMMA,AT,EQUALS,HASH = map(Suppress,'{}()",@=#')
+LCURLY, RCURLY, LPAREN, RPAREN, QUOTE, COMMA, AT, EQUALS, HASH = map(
+ Suppress, '{}()",@=#'
+)
def bracketed(expr):
@@ -48,31 +62,30 @@ 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]+')
+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"#%\'(),={}]+')
+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"#%\'(),={}]*')
+not_digname = Regex("[^\\d\\s\"#%'(),={}][^\\s\"#%'(),={}]*")
# Comment comments out to end of line
-comment = (AT + CaselessLiteral('comment') +
- Regex(r"[\s{(].*").leaveWhitespace())
+comment = AT + CaselessLiteral("comment") + Regex(r"[\s{(].*").leaveWhitespace()
# The name types with their digiteyness
not_dig_lower = not_digname.copy().setParseAction(lambda t: t[0].lower())
macro_def = not_dig_lower.copy()
-macro_ref = not_dig_lower.copy().setParseAction(lambda t : Macro(t[0].lower()))
+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')
+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)
+string = number | macro_ref | quoted_string | curly_string
# There can be hash concatenation
field_value = string + ZeroOrMore(HASH + string)
@@ -80,25 +93,21 @@ 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))
+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)
+preamble = AT + CaselessLiteral("preamble") + bracketed(field_value)
# Macros (aka strings)
macro_contents = macro_def + EQUALS + field_value
-macro = AT + CaselessLiteral('string') + bracketed(macro_contents)
+macro = AT + CaselessLiteral("string") + bracketed(macro_contents)
# Implicit comments
-icomment = SkipTo('@').setParseAction(lambda t : t.insert(0, 'icomment'))
+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)
+definitions = Group(comment | preamble | macro | entry | icomment)
# Start symbol
bibfile = ZeroOrMore(definitions)
@@ -108,7 +117,7 @@ def parse_str(str):
return bibfile.parseString(str)
-if __name__ == '__main__':
+if __name__ == "__main__":
# Run basic test
txt = """
Some introductory text
@@ -124,4 +133,4 @@ Some introductory text
number = {2}
}
"""
- print('\n\n'.join(defn.dump() for defn in parse_str(txt)))
+ print("\n\n".join(defn.dump() for defn in parse_str(txt)))
diff --git a/examples/builtin_parse_action_demo.py b/examples/builtin_parse_action_demo.py
index 3ec6af8..36b3a98 100644
--- a/examples/builtin_parse_action_demo.py
+++ b/examples/builtin_parse_action_demo.py
@@ -7,7 +7,7 @@
from pyparsing import *
-integer = Word(nums).setParseAction(lambda t : int(t[0]))
+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
@@ -23,7 +23,7 @@ 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))
+ fn = lambda x: list(reversed(x))
# show how each builtin works as a free-standing parse action
print(fn_name, nums.setParseAction(fn).parseString(test))
diff --git a/examples/cLibHeader.py b/examples/cLibHeader.py
index 6bb1c25..10a0c77 100644
--- a/examples/cLibHeader.py
+++ b/examples/cLibHeader.py
@@ -6,7 +6,17 @@
# Copyright, 2012 - Paul McGuire
#
-from pyparsing import Word, alphas, alphanums, Combine, oneOf, Optional, delimitedList, Group, Keyword
+from pyparsing import (
+ Word,
+ alphas,
+ alphanums,
+ Combine,
+ oneOf,
+ Optional,
+ delimitedList,
+ Group,
+ Keyword,
+)
testdata = """
int func1(float *vec, int len, double arg1);
@@ -14,12 +24,12 @@ testdata = """
"""
ident = Word(alphas, alphanums + "_")
-vartype = Combine( oneOf("float double int char") + Optional(Word("*")), adjacent = False)
+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):
+for fn, s, e in functionCall.scanString(testdata):
print(fn.name)
for a in fn.args:
print(" - %(name)s (%(type)s)" % a)
diff --git a/examples/chemicalFormulas.py b/examples/chemicalFormulas.py
index 1b41871..f4725ed 100644
--- a/examples/chemicalFormulas.py
+++ b/examples/chemicalFormulas.py
@@ -7,12 +7,12 @@
import pyparsing as pp
atomicWeight = {
- "O" : 15.9994,
- "H" : 1.00794,
- "Na" : 22.9897,
- "Cl" : 35.4527,
- "C" : 12.0107,
- }
+ "O": 15.9994,
+ "H": 1.00794,
+ "Na": 22.9897,
+ "Cl": 35.4527,
+ "C": 12.0107,
+}
digits = "0123456789"
@@ -26,58 +26,78 @@ element = pp.Word(pp.alphas.upper(), pp.alphas.lower(), max=2)
elementRef = pp.Group(element + pp.Optional(pp.Word(digits), default="1"))
formula = elementRef[...]
-fn = lambda elemList : sum(atomicWeight[elem]*int(qty) for elem,qty in elemList)
-formula.runTests("""\
+fn = lambda elemList: sum(atomicWeight[elem] * int(qty) for elem, qty in elemList)
+formula.runTests(
+ """\
H2O
C6H5OH
NaCl
""",
- fullDump=False, postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)))
+ fullDump=False,
+ postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)),
+)
print()
# Version 2 - access parsed items by results name
-elementRef = pp.Group(element("symbol") + pp.Optional(pp.Word(digits), default="1")("qty"))
+elementRef = pp.Group(
+ element("symbol") + pp.Optional(pp.Word(digits), default="1")("qty")
+)
formula = elementRef[...]
-fn = lambda elemList : sum(atomicWeight[elem.symbol]*int(elem.qty) for elem in elemList)
-formula.runTests("""\
+fn = lambda elemList: sum(
+ atomicWeight[elem.symbol] * int(elem.qty) for elem in elemList
+)
+formula.runTests(
+ """\
H2O
C6H5OH
NaCl
""",
- fullDump=False, postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)))
+ fullDump=False,
+ postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)),
+)
print()
# Version 3 - convert integers during parsing process
-integer = pp.Word(digits).setParseAction(lambda t:int(t[0]))
+integer = pp.Word(digits).setParseAction(lambda t: int(t[0]))
elementRef = pp.Group(element("symbol") + pp.Optional(integer, default=1)("qty"))
formula = elementRef[...]
-fn = lambda elemList : sum(atomicWeight[elem.symbol]*elem.qty for elem in elemList)
-formula.runTests("""\
+fn = lambda elemList: sum(atomicWeight[elem.symbol] * elem.qty for elem in elemList)
+formula.runTests(
+ """\
H2O
C6H5OH
NaCl
""",
- fullDump=False, postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)))
+ fullDump=False,
+ postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)),
+)
print()
# Version 4 - parse and convert integers as subscript digits
subscript_digits = "₀₁₂₃₄₅₆₇₈₉"
subscript_int_map = {e[1]: e[0] for e in enumerate(subscript_digits)}
+
+
def cvt_subscript_int(s):
ret = 0
for c in s[0]:
- ret = ret*10 + subscript_int_map[c]
+ ret = ret * 10 + subscript_int_map[c]
return ret
+
+
subscript_int = pp.Word(subscript_digits).addParseAction(cvt_subscript_int)
elementRef = pp.Group(element("symbol") + pp.Optional(subscript_int, default=1)("qty"))
formula = elementRef[...]
-formula.runTests("""\
+formula.runTests(
+ """\
H₂O
C₆H₅OH
NaCl
""",
- fullDump=False, postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)))
+ fullDump=False,
+ postParse=lambda _, tokens: "Molecular weight: {}".format(fn(tokens)),
+)
print()
diff --git a/examples/commasep.py b/examples/commasep.py
index 067647d..c3557b6 100644
--- a/examples/commasep.py
+++ b/examples/commasep.py
@@ -10,6 +10,7 @@
#
import pyparsing as pp
+
ppc = pp.pyparsing_common
testData = [
@@ -19,6 +20,6 @@ testData = [
"John Doe, 123 Main St., Cleveland, Ohio",
"Jane Doe, 456 St. James St., Los Angeles , California ",
"",
- ]
+]
ppc.comma_separated_list.runTests(testData)
diff --git a/examples/configParse.py b/examples/configParse.py
index db7b6c7..02727e9 100644
--- a/examples/configParse.py
+++ b/examples/configParse.py
@@ -6,13 +6,24 @@
# Copyright (c) 2003, Paul McGuire
#
-from pyparsing import \
- Literal, Word, ZeroOrMore, Group, Dict, Optional, \
- printables, ParseException, restOfLine, empty
+from pyparsing import (
+ Literal,
+ Word,
+ ZeroOrMore,
+ Group,
+ Dict,
+ Optional,
+ printables,
+ ParseException,
+ restOfLine,
+ empty,
+)
import pprint
inibnf = None
+
+
def inifile_BNF():
global inibnf
@@ -22,50 +33,53 @@ def inifile_BNF():
lbrack = Literal("[").suppress()
rbrack = Literal("]").suppress()
equals = Literal("=").suppress()
- semi = Literal(";")
+ semi = Literal(";")
- comment = semi + Optional( restOfLine )
+ comment = semi + Optional(restOfLine)
- nonrbrack = "".join( [ c for c in printables if c != "]" ] ) + " \t"
- nonequals = "".join( [ c for c in printables if c != "=" ] ) + " \t"
+ 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
+ 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 = Dict(ZeroOrMore(Group(sectionDef + Dict(ZeroOrMore(Group(keyDef))))))
- inibnf.ignore( comment )
+ inibnf.ignore(comment)
return inibnf
pp = pprint.PrettyPrinter(2)
-def test( strng ):
+
+def test(strng):
print(strng)
try:
iniFile = open(strng)
- iniData = "".join( iniFile.readlines() )
+ iniData = "".join(iniFile.readlines())
bnf = inifile_BNF()
- tokens = bnf.parseString( iniData )
- pp.pprint( tokens.asList() )
+ tokens = bnf.parseString(iniData)
+ pp.pprint(tokens.asList())
except ParseException as err:
print(err.line)
- print(" "*(err.column-1) + "^")
+ 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)
+ ini = test("setup.ini")
+ print("ini['Startup']['modemid'] =", ini["Startup"]["modemid"])
+ print("ini.Startup =", ini.Startup)
+ print("ini.Startup.modemid =", ini.Startup.modemid)
diff --git a/examples/cpp_enum_parser.py b/examples/cpp_enum_parser.py
index ca2c04b..26dde7c 100644
--- a/examples/cpp_enum_parser.py
+++ b/examples/cpp_enum_parser.py
@@ -10,8 +10,9 @@
#
from pyparsing import *
+
# sample string with enums and other stuff
-sample = '''
+sample = """
stuff before
enum hello {
Zero,
@@ -31,22 +32,22 @@ sample = '''
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+'_')
+LBRACE, RBRACE, EQ, COMMA = map(Suppress, "{}=,")
+_enum = Suppress("enum")
+identifier = Word(alphas, alphanums + "_")
integer = Word(nums)
-enumValue = Group(identifier('name') + Optional(EQ + integer('value')))
+enumValue = Group(identifier("name") + Optional(EQ + integer("value")))
enumList = Group(enumValue + ZeroOrMore(COMMA + enumValue))
-enum = _enum + identifier('enum') + LBRACE + enumList('names') + RBRACE
+enum = _enum + identifier("enum") + LBRACE + enumList("names") + RBRACE
# find instances of enums ignoring other syntax
-for item,start,stop in enum.scanString(sample):
+for item, start, stop in enum.scanString(sample):
id = 0
for entry in item.names:
- if entry.value != '':
+ if entry.value != "":
id = int(entry.value)
- print('%s_%s = %d' % (item.enum.upper(),entry.name.upper(),id))
+ print("%s_%s = %d" % (item.enum.upper(), entry.name.upper(), id))
id += 1
diff --git a/examples/datetimeParseActions.py b/examples/datetimeParseActions.py
index e5ae2b9..f7c4fc9 100644
--- a/examples/datetimeParseActions.py
+++ b/examples/datetimeParseActions.py
@@ -12,32 +12,44 @@ from pyparsing import pyparsing_common as ppc
# define an integer string, and a parse action to convert it
# to an integer at parse time
integer = pp.Word(pp.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]))
+# integer = Word(nums).setParseAction(lambda t: int(t[0]))
# define a pattern for a year/month/day date
-date_expr = integer('year') + '/' + integer('month') + '/' + integer('day')
+date_expr = integer("year") + "/" + integer("month") + "/" + integer("day")
date_expr.ignore(pp.pythonStyleComment)
-def convertToDatetime(s,loc,tokens):
+
+def convertToDatetime(s, loc, tokens):
try:
# note that the year, month, and day fields were already
# converted to ints from strings by the parse action defined
# on the integer expression above
return datetime(tokens.year, tokens.month, tokens.day).date()
except Exception as ve:
- errmsg = "'%s/%s/%s' is not a valid date, %s" % \
- (tokens.year, tokens.month, tokens.day, ve)
+ errmsg = "'%s/%s/%s' is not a valid date, %s" % (
+ tokens.year,
+ tokens.month,
+ tokens.day,
+ ve,
+ )
raise pp.ParseException(s, loc, errmsg)
+
+
date_expr.setParseAction(convertToDatetime)
-date_expr.runTests("""\
+date_expr.runTests(
+ """\
2000/1/1
# invalid month
@@ -48,14 +60,16 @@ date_expr.runTests("""\
# but 2000 was
2000/2/29
- """)
+ """
+)
# if dates conform to ISO8601, use definitions in pyparsing_common
date_expr = ppc.iso8601_date.setParseAction(ppc.convertToDate())
date_expr.ignore(pp.pythonStyleComment)
-date_expr.runTests("""\
+date_expr.runTests(
+ """\
2000-01-01
# invalid month
@@ -66,4 +80,5 @@ date_expr.runTests("""\
# but 2000 was
2000-02-29
- """)
+ """
+)
diff --git a/examples/decaf_parser.py b/examples/decaf_parser.py
index e6b1abb..be3a1e9 100644
--- a/examples/decaf_parser.py
+++ b/examples/decaf_parser.py
@@ -12,46 +12,75 @@
"""
Program ::= Decl+
Decl ::= VariableDecl | FunctionDecl | ClassDecl | InterfaceDecl
- VariableDecl ::= Variable ;
- Variable ::= Type ident
- Type ::= int | double | bool | string | ident | Type []
- FunctionDecl ::= Type ident ( Formals ) StmtBlock | void ident ( Formals ) StmtBlock
- Formals ::= Variable+, | e
- ClassDecl ::= class ident <extends ident> <implements ident + ,> { Field* }
- Field ::= VariableDecl | FunctionDecl
- InterfaceDecl ::= interface ident { Prototype* }
- Prototype ::= Type ident ( Formals ) ; | void ident ( Formals ) ;
- StmtBlock ::= { VariableDecl* Stmt* }
- Stmt ::= <Expr> ; | IfStmt | WhileStmt | ForStmt | BreakStmt | ReturnStmt | PrintStmt | StmtBlock
- IfStmt ::= if ( Expr ) Stmt <else Stmt>
- WhileStmt ::= while ( Expr ) Stmt
- ForStmt ::= for ( <Expr> ; Expr ; <Expr> ) Stmt
- ReturnStmt ::= return <Expr> ;
- BreakStmt ::= break ;
- PrintStmt ::= Print ( Expr+, ) ;
+ VariableDecl ::= Variable ;
+ Variable ::= Type ident
+ Type ::= int | double | bool | string | ident | Type []
+ FunctionDecl ::= Type ident ( Formals ) StmtBlock | void ident ( Formals ) StmtBlock
+ Formals ::= Variable+, | e
+ ClassDecl ::= class ident <extends ident> <implements ident + ,> { Field* }
+ Field ::= VariableDecl | FunctionDecl
+ InterfaceDecl ::= interface ident { Prototype* }
+ Prototype ::= Type ident ( Formals ) ; | void ident ( Formals ) ;
+ StmtBlock ::= { VariableDecl* Stmt* }
+ Stmt ::= <Expr> ; | IfStmt | WhileStmt | ForStmt | BreakStmt | ReturnStmt | PrintStmt | StmtBlock
+ IfStmt ::= if ( Expr ) Stmt <else Stmt>
+ WhileStmt ::= while ( Expr ) Stmt
+ ForStmt ::= for ( <Expr> ; Expr ; <Expr> ) Stmt
+ ReturnStmt ::= return <Expr> ;
+ BreakStmt ::= break ;
+ PrintStmt ::= Print ( Expr+, ) ;
Expr ::= LValue = Expr | Constant | LValue | this | Call
- | ( Expr )
- | Expr + Expr | Expr - Expr | Expr * Expr | Expr / Expr | Expr % Expr | - Expr
- | Expr < Expr | Expr <= Expr | Expr > Expr | Expr >= Expr | Expr == Expr | Expr != Expr
- | Expr && Expr | Expr || Expr | ! Expr
- | ReadInteger ( ) | ReadLine ( ) | new ident | NewArray ( Expr , Typev)
- LValue ::= ident | Expr . ident | Expr [ Expr ]
- Call ::= ident ( Actuals ) | Expr . ident ( Actuals )
- Actuals ::= Expr+, | e
+ | ( Expr )
+ | Expr + Expr | Expr - Expr | Expr * Expr | Expr / Expr | Expr % Expr | - Expr
+ | Expr < Expr | Expr <= Expr | Expr > Expr | Expr >= Expr | Expr == Expr | Expr != Expr
+ | Expr && Expr | Expr || Expr | ! Expr
+ | ReadInteger ( ) | ReadLine ( ) | new ident | NewArray ( Expr , Typev)
+ LValue ::= ident | Expr . ident | Expr [ Expr ]
+ Call ::= ident ( Actuals ) | Expr . ident ( Actuals )
+ Actuals ::= Expr+, | e
Constant ::= intConstant | doubleConstant | boolConstant | stringConstant | null
"""
import pyparsing as pp
from pyparsing import pyparsing_common as ppc
+
pp.ParserElement.enablePackrat()
# keywords
-keywords = (VOID, INT, DOUBLE, BOOL, STRING, CLASS, INTERFACE, NULL, THIS, EXTENDS, IMPLEMENTS, FOR, WHILE,
- IF, ELSE, RETURN, BREAK, NEW, NEWARRAY, PRINT, READINTEGER, READLINE, TRUE, FALSE) = map(pp.Keyword,
- """void int double bool string class interface null this extends implements or while
- if else return break new NewArray Print ReadInteger ReadLine true false""".split())
+keywords = (
+ VOID,
+ INT,
+ DOUBLE,
+ BOOL,
+ STRING,
+ CLASS,
+ INTERFACE,
+ NULL,
+ THIS,
+ EXTENDS,
+ IMPLEMENTS,
+ FOR,
+ WHILE,
+ IF,
+ ELSE,
+ RETURN,
+ BREAK,
+ NEW,
+ NEWARRAY,
+ PRINT,
+ READINTEGER,
+ READLINE,
+ TRUE,
+ FALSE,
+) = map(
+ pp.Keyword,
+ """void int double bool string class interface null this extends implements or while
+ if else return break new NewArray Print ReadInteger ReadLine true false""".split(),
+)
keywords = pp.MatchFirst(list(keywords))
-LPAR, RPAR, LBRACE, RBRACE, LBRACK, RBRACK, DOT, EQ, COMMA, SEMI = map(pp.Suppress, "(){}[].=,;")
+LPAR, RPAR, LBRACE, RBRACE, LBRACK, RBRACK, DOT, EQ, COMMA, SEMI = map(
+ pp.Suppress, "(){}[].=,;"
+)
hexConstant = pp.Regex(r"0[xX][0-9a-fA-F]+").addParseAction(lambda t: int(t[0][2:], 16))
intConstant = hexConstant | ppc.integer
doubleConstant = ppc.real
@@ -59,7 +88,7 @@ boolConstant = TRUE | FALSE
stringConstant = pp.dblQuotedString
null = NULL
constant = doubleConstant | boolConstant | intConstant | stringConstant | null
-ident = ~keywords + pp.Word(pp.alphas, pp.alphanums+'_')
+ident = ~keywords + pp.Word(pp.alphas, pp.alphanums + "_")
type_ = pp.Group((INT | DOUBLE | BOOL | STRING | ident) + pp.ZeroOrMore("[]"))
variable = type_ + ident
@@ -68,86 +97,142 @@ variable_decl = variable + SEMI
expr = pp.Forward()
expr_parens = pp.Group(LPAR + expr + RPAR)
actuals = pp.Optional(pp.delimitedList(expr))
-call = pp.Group(ident("call_ident") + LPAR + actuals("call_args") + RPAR
- | (expr_parens + pp.ZeroOrMore(DOT + ident))("call_ident_expr") + LPAR + actuals("call_args") + RPAR)
-lvalue = ((ident | expr_parens)
- + pp.ZeroOrMore(DOT + (ident | expr_parens))
- + pp.ZeroOrMore(LBRACK + expr + RBRACK))
+call = pp.Group(
+ ident("call_ident") + LPAR + actuals("call_args") + RPAR
+ | (expr_parens + pp.ZeroOrMore(DOT + ident))("call_ident_expr")
+ + LPAR
+ + actuals("call_args")
+ + RPAR
+)
+lvalue = (
+ (ident | expr_parens)
+ + pp.ZeroOrMore(DOT + (ident | expr_parens))
+ + pp.ZeroOrMore(LBRACK + expr + RBRACK)
+)
assignment = pp.Group(lvalue("lhs") + EQ + expr("rhs"))
read_integer = pp.Group(READINTEGER + LPAR + RPAR)
read_line = pp.Group(READLINE + LPAR + RPAR)
new_statement = pp.Group(NEW + ident)
new_array = pp.Group(NEWARRAY + LPAR + expr + COMMA + type_ + RPAR)
rvalue = constant | call | read_integer | read_line | new_statement | new_array | ident
-arith_expr = pp.infixNotation(rvalue,
+arith_expr = pp.infixNotation(
+ rvalue,
[
- ('-', 1, pp.opAssoc.RIGHT,),
- (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
- ])
-comparison_expr = pp.infixNotation(arith_expr,
+ ("-", 1, pp.opAssoc.RIGHT,),
+ (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
+ ],
+)
+comparison_expr = pp.infixNotation(
+ arith_expr,
[
- ('!', 1, pp.opAssoc.RIGHT,),
- (pp.oneOf("< > <= >="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
- ])
-expr <<= (assignment
- | call
- | THIS
- | comparison_expr
- | arith_expr
- | lvalue
- | constant
- | read_integer
- | read_line
- | new_statement
- | new_array
- )
+ ("!", 1, pp.opAssoc.RIGHT,),
+ (pp.oneOf("< > <= >="), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
+ ],
+)
+expr <<= (
+ assignment
+ | call
+ | THIS
+ | comparison_expr
+ | arith_expr
+ | lvalue
+ | constant
+ | read_integer
+ | read_line
+ | new_statement
+ | new_array
+)
stmt = pp.Forward()
-print_stmt = pp.Group(PRINT("statement") + LPAR + pp.Group(pp.Optional(pp.delimitedList(expr)))("args") + RPAR + SEMI)
+print_stmt = pp.Group(
+ PRINT("statement")
+ + LPAR
+ + pp.Group(pp.Optional(pp.delimitedList(expr)))("args")
+ + RPAR
+ + SEMI
+)
break_stmt = pp.Group(BREAK("statement") + SEMI)
return_stmt = pp.Group(RETURN("statement") + expr + SEMI)
-for_stmt = pp.Group(FOR("statement") + LPAR + pp.Optional(expr) + SEMI + expr + SEMI + pp.Optional(expr) + RPAR + stmt)
+for_stmt = pp.Group(
+ FOR("statement")
+ + LPAR
+ + pp.Optional(expr)
+ + SEMI
+ + expr
+ + SEMI
+ + pp.Optional(expr)
+ + RPAR
+ + stmt
+)
while_stmt = pp.Group(WHILE("statement") + LPAR + expr + RPAR + stmt)
-if_stmt = pp.Group(IF("statement")
- + LPAR + pp.Group(expr)("condition") + RPAR
- + pp.Group(stmt)("then_statement")
- + pp.Group(pp.Optional(ELSE + stmt))("else_statement"))
-stmt_block = pp.Group(LBRACE + pp.ZeroOrMore(variable_decl) + pp.ZeroOrMore(stmt) + RBRACE)
-stmt <<= (if_stmt
- | while_stmt
- | for_stmt
- | break_stmt
- | return_stmt
- | print_stmt
- | stmt_block
- | pp.Group(expr + SEMI)
- )
+if_stmt = pp.Group(
+ IF("statement")
+ + LPAR
+ + pp.Group(expr)("condition")
+ + RPAR
+ + pp.Group(stmt)("then_statement")
+ + pp.Group(pp.Optional(ELSE + stmt))("else_statement")
+)
+stmt_block = pp.Group(
+ LBRACE + pp.ZeroOrMore(variable_decl) + pp.ZeroOrMore(stmt) + RBRACE
+)
+stmt <<= (
+ if_stmt
+ | while_stmt
+ | for_stmt
+ | break_stmt
+ | return_stmt
+ | print_stmt
+ | stmt_block
+ | pp.Group(expr + SEMI)
+)
formals = pp.Optional(pp.delimitedList(variable))
-prototype = pp.Group((type_ | VOID)("return_type")
- + ident("function_name")
- + LPAR + formals("args") + RPAR + SEMI)("prototype")
-function_decl = pp.Group((type_ | VOID)("return_type") + ident("function_name")
- + LPAR + formals("args") + RPAR
- + stmt_block("body"))("function_decl")
+prototype = pp.Group(
+ (type_ | VOID)("return_type")
+ + ident("function_name")
+ + LPAR
+ + formals("args")
+ + RPAR
+ + SEMI
+)("prototype")
+function_decl = pp.Group(
+ (type_ | VOID)("return_type")
+ + ident("function_name")
+ + LPAR
+ + formals("args")
+ + RPAR
+ + stmt_block("body")
+)("function_decl")
-interface_decl = pp.Group(INTERFACE + ident("interface_name")
- + LBRACE + pp.ZeroOrMore(prototype)("prototypes") + RBRACE)("interface")
+interface_decl = pp.Group(
+ INTERFACE
+ + ident("interface_name")
+ + LBRACE
+ + pp.ZeroOrMore(prototype)("prototypes")
+ + RBRACE
+)("interface")
field = variable_decl | function_decl
-class_decl = pp.Group(CLASS + ident("class_name")
- + pp.Optional(EXTENDS + ident)("extends")
- + pp.Optional(IMPLEMENTS + pp.delimitedList(ident))("implements")
- + LBRACE + pp.ZeroOrMore(field)("fields") + RBRACE)("class_decl")
+class_decl = pp.Group(
+ CLASS
+ + ident("class_name")
+ + pp.Optional(EXTENDS + ident)("extends")
+ + pp.Optional(IMPLEMENTS + pp.delimitedList(ident))("implements")
+ + LBRACE
+ + pp.ZeroOrMore(field)("fields")
+ + RBRACE
+)("class_decl")
decl = variable_decl | function_decl | class_decl | interface_decl | prototype
program = pp.OneOrMore(pp.Group(decl))
decaf_parser = program
-stmt.runTests("""\
+stmt.runTests(
+ """\
sin(30);
a = 1;
b = 1 + 1;
@@ -158,7 +243,8 @@ stmt.runTests("""\
a[100] = b;
a[0][0] = 2;
a = 0x1234;
-""")
+"""
+)
test_program = """
void getenv(string var);
diff --git a/examples/delta_time.py b/examples/delta_time.py
index e079094..237414f 100644
--- a/examples/delta_time.py
+++ b/examples/delta_time.py
@@ -39,22 +39,34 @@ __all__ = ["time_expression"]
# basic grammar definitions
def make_integer_word_expr(int_name, int_value):
return pp.CaselessKeyword(int_name).addParseAction(pp.replaceWith(int_value))
-integer_word = pp.MatchFirst(make_integer_word_expr(int_str, int_value)
- for int_value, int_str
- in enumerate("one two three four five six seven eight nine ten"
- " eleven twelve thirteen fourteen fifteen sixteen"
- " seventeen eighteen nineteen twenty".split(), start=1))
+
+
+integer_word = pp.MatchFirst(
+ make_integer_word_expr(int_str, int_value)
+ for int_value, int_str in enumerate(
+ "one two three four five six seven eight nine ten"
+ " eleven twelve thirteen fourteen fifteen sixteen"
+ " seventeen eighteen nineteen twenty".split(),
+ start=1,
+ )
+)
integer = pp.pyparsing_common.integer | integer_word
CK = pp.CaselessKeyword
CL = pp.CaselessLiteral
-today, tomorrow, yesterday, noon, midnight, now = map(CK, "today tomorrow yesterday noon midnight now".split())
+today, tomorrow, yesterday, noon, midnight, now = map(
+ CK, "today tomorrow yesterday noon midnight now".split()
+)
+
+
def plural(s):
- return CK(s) | CK(s + 's').addParseAction(pp.replaceWith(s))
+ return CK(s) | CK(s + "s").addParseAction(pp.replaceWith(s))
+
+
week, day, hour, minute, second = map(plural, "week day hour minute second".split())
am = CL("am")
pm = CL("pm")
-COLON = pp.Suppress(':')
+COLON = pp.Suppress(":")
in_ = CK("in").setParseAction(pp.replaceWith(1))
from_ = CK("from").setParseAction(pp.replaceWith(1))
@@ -66,51 +78,59 @@ last_ = CK("last").setParseAction(pp.replaceWith(-1))
at_ = CK("at")
on_ = CK("on")
-couple = (pp.Optional(CK("a")) + CK("couple") + pp.Optional(CK("of"))).setParseAction(pp.replaceWith(2))
+couple = (pp.Optional(CK("a")) + CK("couple") + pp.Optional(CK("of"))).setParseAction(
+ pp.replaceWith(2)
+)
a_qty = (CK("a") | CK("an")).setParseAction(pp.replaceWith(1))
the_qty = CK("the").setParseAction(pp.replaceWith(1))
qty = pp.ungroup(integer | couple | a_qty | the_qty)
-time_ref_present = pp.Empty().addParseAction(pp.replaceWith(True))('time_ref_present')
+time_ref_present = pp.Empty().addParseAction(pp.replaceWith(True))("time_ref_present")
+
def fill_24hr_time_fields(t):
- t['HH'] = t[0]
- t['MM'] = t[1]
- t['SS'] = 0
- t['ampm'] = ('am','pm')[t.HH >= 12]
+ t["HH"] = t[0]
+ t["MM"] = t[1]
+ t["SS"] = 0
+ t["ampm"] = ("am", "pm")[t.HH >= 12]
+
def fill_default_time_fields(t):
- for fld in 'HH MM SS'.split():
+ for fld in "HH MM SS".split():
if fld not in t:
t[fld] = 0
+
weekday_name_list = list(calendar.day_name)
weekday_name = pp.oneOf(weekday_name_list)
-_24hour_time = pp.Word(pp.nums, exact=4).addParseAction(lambda t: [int(t[0][:2]),int(t[0][2:])],
- fill_24hr_time_fields)
+_24hour_time = pp.Word(pp.nums, exact=4).addParseAction(
+ lambda t: [int(t[0][:2]), int(t[0][2:])], fill_24hr_time_fields
+)
_24hour_time.setName("0000 time")
ampm = am | pm
-timespec = (integer("HH")
- + pp.Optional(CK("o'clock")
- |
- COLON + integer("MM")
- + pp.Optional(COLON + integer("SS"))
- )
- + (am | pm)("ampm")
- ).addParseAction(fill_default_time_fields)
+timespec = (
+ integer("HH")
+ + pp.Optional(
+ CK("o'clock") | COLON + integer("MM") + pp.Optional(COLON + integer("SS"))
+ )
+ + (am | pm)("ampm")
+).addParseAction(fill_default_time_fields)
absolute_time = _24hour_time | timespec
absolute_time_of_day = noon | midnight | now | absolute_time
+
def add_computed_time(t):
- if t[0] in 'now noon midnight'.split():
- t['computed_time'] = {'now': datetime.now().time().replace(microsecond=0),
- 'noon': time(hour=12),
- 'midnight': time()}[t[0]]
+ if t[0] in "now noon midnight".split():
+ t["computed_time"] = {
+ "now": datetime.now().time().replace(microsecond=0),
+ "noon": time(hour=12),
+ "midnight": time(),
+ }[t[0]]
else:
- t['HH'] = {'am': int(t['HH']) % 12,
- 'pm': int(t['HH']) % 12 + 12}[t.ampm]
- t['computed_time'] = time(hour=t.HH, minute=t.MM, second=t.SS)
+ t["HH"] = {"am": int(t["HH"]) % 12, "pm": int(t["HH"]) % 12 + 12}[t.ampm]
+ t["computed_time"] = time(hour=t.HH, minute=t.MM, second=t.SS)
+
absolute_time_of_day.addParseAction(add_computed_time)
@@ -119,42 +139,49 @@ absolute_time_of_day.addParseAction(add_computed_time)
# | qty time_units 'ago'
# | 'in' qty time_units
time_units = hour | minute | second
-relative_time_reference = (qty('qty') + time_units('units') + ago('dir')
- | qty('qty') + time_units('units')
- + (from_ | before | after)('dir')
- + pp.Group(absolute_time_of_day)('ref_time')
- | in_('dir') + qty('qty') + time_units('units')
- )
+relative_time_reference = (
+ qty("qty") + time_units("units") + ago("dir")
+ | qty("qty")
+ + time_units("units")
+ + (from_ | before | after)("dir")
+ + pp.Group(absolute_time_of_day)("ref_time")
+ | in_("dir") + qty("qty") + time_units("units")
+)
+
def compute_relative_time(t):
- if 'ref_time' not in t:
- t['ref_time'] = datetime.now().time().replace(microsecond=0)
+ if "ref_time" not in t:
+ t["ref_time"] = datetime.now().time().replace(microsecond=0)
else:
- t['ref_time'] = t.ref_time.computed_time
- delta_seconds = {'hour': 3600,
- 'minute': 60,
- 'second': 1}[t.units] * t.qty
- t['time_delta'] = timedelta(seconds=t.dir * delta_seconds)
+ t["ref_time"] = t.ref_time.computed_time
+ delta_seconds = {"hour": 3600, "minute": 60, "second": 1}[t.units] * t.qty
+ t["time_delta"] = timedelta(seconds=t.dir * delta_seconds)
+
relative_time_reference.addParseAction(compute_relative_time)
time_reference = absolute_time_of_day | relative_time_reference
+
+
def add_default_time_ref_fields(t):
- if 'time_delta' not in t:
- t['time_delta'] = timedelta()
+ if "time_delta" not in t:
+ t["time_delta"] = timedelta()
+
+
time_reference.addParseAction(add_default_time_ref_fields)
# absolute_day_reference ::= 'today' | 'tomorrow' | 'yesterday' | ('next' | 'last') weekday_name
# day_units ::= 'days' | 'weeks'
day_units = day | week
-weekday_reference = pp.Optional(next_ | last_, 1)('dir') + weekday_name('day_name')
+weekday_reference = pp.Optional(next_ | last_, 1)("dir") + weekday_name("day_name")
+
def convert_abs_day_reference_to_date(t):
now = datetime.now().replace(microsecond=0)
# handle day reference by weekday name
- if 'day_name' in t:
+ if "day_name" in t:
todaynum = now.weekday()
daynames = [n.lower() for n in weekday_name_list]
nameddaynum = daynames.index(t.day_name.lower())
@@ -168,84 +195,111 @@ def convert_abs_day_reference_to_date(t):
else:
name = t[0]
t["abs_date"] = {
- "now" : now,
- "today" : datetime(now.year, now.month, now.day),
- "yesterday" : datetime(now.year, now.month, now.day) + timedelta(days=-1),
- "tomorrow" : datetime(now.year, now.month, now.day) + timedelta(days=+1),
- }[name]
+ "now": now,
+ "today": datetime(now.year, now.month, now.day),
+ "yesterday": datetime(now.year, now.month, now.day) + timedelta(days=-1),
+ "tomorrow": datetime(now.year, now.month, now.day) + timedelta(days=+1),
+ }[name]
-absolute_day_reference = today | tomorrow | yesterday | now + time_ref_present | weekday_reference
+
+absolute_day_reference = (
+ today | tomorrow | yesterday | now + time_ref_present | weekday_reference
+)
absolute_day_reference.addParseAction(convert_abs_day_reference_to_date)
# relative_day_reference ::= 'in' qty day_units
# | qty day_units 'ago'
# | 'qty day_units ('from' | 'before' | 'after') absolute_day_reference
-relative_day_reference = (in_('dir') + qty('qty') + day_units('units')
- | qty('qty') + day_units('units') + ago('dir')
- | qty('qty') + day_units('units') + (from_ | before | after)('dir')
- + absolute_day_reference('ref_day')
- )
+relative_day_reference = (
+ in_("dir") + qty("qty") + day_units("units")
+ | qty("qty") + day_units("units") + ago("dir")
+ | qty("qty")
+ + day_units("units")
+ + (from_ | before | after)("dir")
+ + absolute_day_reference("ref_day")
+)
+
def compute_relative_date(t):
now = datetime.now().replace(microsecond=0)
- if 'ref_day' in t:
- t['computed_date'] = t.ref_day
+ if "ref_day" in t:
+ t["computed_date"] = t.ref_day
else:
- t['computed_date'] = now.date()
- day_diff = t.dir * t.qty * {'week': 7, 'day': 1}[t.units]
- t['date_delta'] = timedelta(days=day_diff)
+ t["computed_date"] = now.date()
+ day_diff = t.dir * t.qty * {"week": 7, "day": 1}[t.units]
+ t["date_delta"] = timedelta(days=day_diff)
+
+
relative_day_reference.addParseAction(compute_relative_date)
# combine expressions for absolute and relative day references
day_reference = relative_day_reference | absolute_day_reference
+
+
def add_default_date_fields(t):
- if 'date_delta' not in t:
- t['date_delta'] = timedelta()
+ if "date_delta" not in t:
+ t["date_delta"] = timedelta()
+
+
day_reference.addParseAction(add_default_date_fields)
# combine date and time expressions into single overall parser
-time_and_day = (time_reference + time_ref_present + pp.Optional(pp.Optional(on_) + day_reference)
- | day_reference + pp.Optional(at_ + absolute_time_of_day + time_ref_present))
+time_and_day = time_reference + time_ref_present + pp.Optional(
+ pp.Optional(on_) + day_reference
+) | day_reference + pp.Optional(at_ + absolute_time_of_day + time_ref_present)
# parse actions for total time_and_day expression
def save_original_string(s, l, t):
# save original input string and reference time
- t['original'] = ' '.join(s.strip().split())
- t['relative_to'] = datetime.now().replace(microsecond=0)
+ t["original"] = " ".join(s.strip().split())
+ t["relative_to"] = datetime.now().replace(microsecond=0)
+
def compute_timestamp(t):
# accumulate values from parsed time and day subexpressions - fill in defaults for omitted parts
now = datetime.now().replace(microsecond=0)
- if 'computed_time' not in t:
- t['computed_time'] = t.ref_time or now.time()
- if 'abs_date' not in t:
- t['abs_date'] = now
+ if "computed_time" not in t:
+ t["computed_time"] = t.ref_time or now.time()
+ if "abs_date" not in t:
+ t["abs_date"] = now
# roll up all fields and apply any time or day deltas
- t['computed_dt'] = (
- t.abs_date.replace(hour=t.computed_time.hour, minute=t.computed_time.minute, second=t.computed_time.second)
+ t["computed_dt"] = (
+ t.abs_date.replace(
+ hour=t.computed_time.hour,
+ minute=t.computed_time.minute,
+ second=t.computed_time.second,
+ )
+ (t.time_delta or timedelta(0))
+ (t.date_delta or timedelta(0))
)
# if time just given in terms of day expressions, zero out time fields
if not t.time_ref_present:
- t['computed_dt'] = t.computed_dt.replace(hour=0, minute=0, second=0)
+ t["computed_dt"] = t.computed_dt.replace(hour=0, minute=0, second=0)
# add results name compatible with previous version
- t['calculatedTime'] = t.computed_dt
+ t["calculatedTime"] = t.computed_dt
# add time_offset fields
- t['time_offset'] = t.computed_dt - t.relative_to
+ t["time_offset"] = t.computed_dt - t.relative_to
+
def remove_temp_keys(t):
# strip out keys that are just used internally
all_keys = list(t.keys())
for k in all_keys:
- if k not in ('computed_dt', 'original', 'relative_to', 'time_offset', 'calculatedTime'):
+ if k not in (
+ "computed_dt",
+ "original",
+ "relative_to",
+ "time_offset",
+ "calculatedTime",
+ ):
del t[k]
+
time_and_day.addParseAction(save_original_string, compute_timestamp, remove_temp_keys)
@@ -304,50 +358,56 @@ if __name__ == "__main__":
last Sunday at 2pm
"""
- time_of_day = timedelta(hours=current_time.hour,
- minutes=current_time.minute,
- seconds=current_time.second)
+ time_of_day = timedelta(
+ hours=current_time.hour,
+ minutes=current_time.minute,
+ seconds=current_time.second,
+ )
expected = {
- 'now' : timedelta(0),
- '10 minutes ago': timedelta(minutes=-10),
- '10 minutes from now': timedelta(minutes=10),
- 'in 10 minutes': timedelta(minutes=10),
- 'in a minute': timedelta(minutes=1),
- 'in a couple of minutes': timedelta(minutes=2),
- '20 seconds ago': timedelta(seconds=-20),
- 'in 30 seconds': timedelta(seconds=30),
- 'in an hour': timedelta(hours=1),
- 'in a couple hours': timedelta(hours=2),
- 'a week from now': timedelta(days=7),
- '3 days from now': timedelta(days=3),
- 'a couple of days from now': timedelta(days=2),
- 'an hour ago': timedelta(hours=-1),
- 'in a couple days': timedelta(days=2) - time_of_day,
- 'a week from today': timedelta(days=7) - time_of_day,
- 'three weeks ago': timedelta(days=-21) - time_of_day,
- 'a day ago': timedelta(days=-1) - time_of_day,
- 'in a couple of days': timedelta(days=2) - time_of_day,
- 'a couple of days from today': timedelta(days=2) - time_of_day,
- '2 weeks after today': timedelta(days=14) - time_of_day,
- 'in 2 weeks': timedelta(days=14) - time_of_day,
- 'the day after tomorrow': timedelta(days=2) - time_of_day,
- 'tomorrow': timedelta(days=1) - time_of_day,
- 'the day before yesterday': timedelta(days=-2) - time_of_day,
- 'yesterday': timedelta(days=-1) - time_of_day,
- 'today': -time_of_day,
- 'midnight': -time_of_day,
- 'in a day': timedelta(days=1) - time_of_day,
- '3 days ago': timedelta(days=-3) - time_of_day,
- 'noon tomorrow': timedelta(days=1) - time_of_day + timedelta(hours=12),
- '6am tomorrow': timedelta(days=1) - time_of_day + timedelta(hours=6),
- '0800 yesterday': timedelta(days=-1) - time_of_day + timedelta(hours=8),
- '1700 tomorrow': timedelta(days=1) - time_of_day + timedelta(hours=17),
- '12:15 AM today': -time_of_day + timedelta(minutes=15),
- '3pm 2 days from today': timedelta(days=2) - time_of_day + timedelta(hours=15),
- 'ten seconds before noon tomorrow': timedelta(days=1) - time_of_day
- + timedelta(hours=12) + timedelta(seconds=-10),
- '20 seconds before noon': -time_of_day + timedelta(hours=12) + timedelta(seconds=-20),
- 'in 3 days at 5pm': timedelta(days=3) - time_of_day + timedelta(hours=17),
+ "now": timedelta(0),
+ "10 minutes ago": timedelta(minutes=-10),
+ "10 minutes from now": timedelta(minutes=10),
+ "in 10 minutes": timedelta(minutes=10),
+ "in a minute": timedelta(minutes=1),
+ "in a couple of minutes": timedelta(minutes=2),
+ "20 seconds ago": timedelta(seconds=-20),
+ "in 30 seconds": timedelta(seconds=30),
+ "in an hour": timedelta(hours=1),
+ "in a couple hours": timedelta(hours=2),
+ "a week from now": timedelta(days=7),
+ "3 days from now": timedelta(days=3),
+ "a couple of days from now": timedelta(days=2),
+ "an hour ago": timedelta(hours=-1),
+ "in a couple days": timedelta(days=2) - time_of_day,
+ "a week from today": timedelta(days=7) - time_of_day,
+ "three weeks ago": timedelta(days=-21) - time_of_day,
+ "a day ago": timedelta(days=-1) - time_of_day,
+ "in a couple of days": timedelta(days=2) - time_of_day,
+ "a couple of days from today": timedelta(days=2) - time_of_day,
+ "2 weeks after today": timedelta(days=14) - time_of_day,
+ "in 2 weeks": timedelta(days=14) - time_of_day,
+ "the day after tomorrow": timedelta(days=2) - time_of_day,
+ "tomorrow": timedelta(days=1) - time_of_day,
+ "the day before yesterday": timedelta(days=-2) - time_of_day,
+ "yesterday": timedelta(days=-1) - time_of_day,
+ "today": -time_of_day,
+ "midnight": -time_of_day,
+ "in a day": timedelta(days=1) - time_of_day,
+ "3 days ago": timedelta(days=-3) - time_of_day,
+ "noon tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=12),
+ "6am tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=6),
+ "0800 yesterday": timedelta(days=-1) - time_of_day + timedelta(hours=8),
+ "1700 tomorrow": timedelta(days=1) - time_of_day + timedelta(hours=17),
+ "12:15 AM today": -time_of_day + timedelta(minutes=15),
+ "3pm 2 days from today": timedelta(days=2) - time_of_day + timedelta(hours=15),
+ "ten seconds before noon tomorrow": timedelta(days=1)
+ - time_of_day
+ + timedelta(hours=12)
+ + timedelta(seconds=-10),
+ "20 seconds before noon": -time_of_day
+ + timedelta(hours=12)
+ + timedelta(seconds=-20),
+ "in 3 days at 5pm": timedelta(days=3) - time_of_day + timedelta(hours=17),
}
def verify_offset(instring, parsed):
@@ -355,9 +415,9 @@ if __name__ == "__main__":
if instring in expected:
# allow up to a second time discrepancy due to test processing time
if (parsed.time_offset - expected[instring]) <= time_epsilon:
- parsed['verify_offset'] = 'PASS'
+ parsed["verify_offset"] = "PASS"
else:
- parsed['verify_offset'] = 'FAIL'
+ parsed["verify_offset"] = "FAIL"
print("(relative to %s)" % datetime.now())
time_expression.runTests(tests, postParse=verify_offset)
diff --git a/examples/dfmparse.py b/examples/dfmparse.py
index 5a1d2a0..5d9b1b1 100644
--- a/examples/dfmparse.py
+++ b/examples/dfmparse.py
@@ -8,21 +8,36 @@ __version__ = "1.0"
__author__ = "Daniel 'Dang' Griffith <pythondev - dang at lazytwinacres . net>"
-from pyparsing import Literal, CaselessLiteral, Word, delimitedList \
- , Optional, Combine, Group, alphas, nums, alphanums, Forward \
- , oneOf, OneOrMore, ZeroOrMore, CharsNotIn
+from pyparsing import (
+ Literal,
+ CaselessLiteral,
+ Word,
+ delimitedList,
+ Optional,
+ Combine,
+ Group,
+ alphas,
+ nums,
+ alphanums,
+ Forward,
+ oneOf,
+ 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 )
+ return 0 < x < 128 and chr(x) or eval("u'\\u%d'" % x)
+
#################
# BEGIN GRAMMAR
#################
-COLON = Literal(":").suppress()
+COLON = Literal(":").suppress()
CONCAT = Literal("+").suppress()
EQUALS = Literal("=").suppress()
LANGLE = Literal("<").suppress()
@@ -33,66 +48,100 @@ 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()
+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
+attribute_value_pair = Forward() # this is recursed in item_list_entry
simple_identifier = Word(alphas, alphanums + "_")
-identifier = Combine( simple_identifier + ZeroOrMore( Literal(".") + simple_identifier ))
+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]) ] )
+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)
+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() )
+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]) ))))
+ 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])
+ 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
+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
+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)
+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)
+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
@@ -101,31 +150,36 @@ 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
+ 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
+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=' ')
+ print(tok, end=" ")
return tok
+
def get_filename_list(tf):
import sys, glob
+
if tf == None:
if len(sys.argv) > 1:
tf = sys.argv[1:]
@@ -138,6 +192,7 @@ def get_filename_list(tf):
testfiles.extend(glob.glob(arg))
return testfiles
+
def main(testfiles=None, action=printer):
"""testfiles can be None, in which case the command line arguments are used as filenames.
testfiles can be a string, in which case that file is parsed.
@@ -165,8 +220,8 @@ def main(testfiles=None, action=printer):
failures.append(f)
if failures:
- print('\nfailed while processing %s' % ', '.join(failures))
- print('\nsucceeded on %d of %d files' %(success, len(testfiles)))
+ 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
@@ -175,5 +230,6 @@ def main(testfiles=None, action=printer):
# else, return a dictionary of parseResults
return retval
+
if __name__ == "__main__":
main()
diff --git a/examples/dhcpd_leases_parser.py b/examples/dhcpd_leases_parser.py
index a885051..e9f64bd 100644
--- a/examples/dhcpd_leases_parser.py
+++ b/examples/dhcpd_leases_parser.py
@@ -44,28 +44,32 @@ lease 192.168.0.239 {
"""
from pyparsing import *
-import datetime,time
+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)
+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")
+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()
+ 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
@@ -76,12 +80,18 @@ 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
+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(lease.ipaddress, "->", lease.hardware.mac)
print()
diff --git a/examples/dictExample.py b/examples/dictExample.py
index 7d3d45d..ebc437f 100644
--- a/examples/dictExample.py
+++ b/examples/dictExample.py
@@ -19,15 +19,19 @@ testData = """
"""
# define grammar for datatable
-heading = (pp.Literal(
-"+-------+------+------+------+------+------+------+------+------+") +
-"| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |" +
-"+=======+======+======+======+======+======+======+======+======+").suppress()
+heading = (
+ pp.Literal("+-------+------+------+------+------+------+------+------+------+")
+ + "| | A1 | B1 | C1 | D1 | A2 | B2 | C2 | D2 |"
+ + "+=======+======+======+======+======+======+======+======+======+"
+).suppress()
vert = pp.Literal("|").suppress()
number = pp.Word(pp.nums)
-rowData = pp.Group( vert + pp.Word(pp.alphas) + vert + pp.delimitedList(number,"|") + vert )
+rowData = pp.Group(
+ vert + pp.Word(pp.alphas) + vert + pp.delimitedList(number, "|") + vert
+)
trailing = pp.Literal(
-"+-------+------+------+------+------+------+------+------+------+").suppress()
+ "+-------+------+------+------+------+------+------+------+------+"
+).suppress()
datatable = heading + pp.Dict(pp.ZeroOrMore(rowData)) + trailing
@@ -42,7 +46,7 @@ data.pprint()
print("data keys=", list(data.keys()))
# use dict-style access to values
-print("data['min']=", data['min'])
+print("data['min']=", data["min"])
# use attribute-style access to values (if key is a valid Python identifier)
print("data.max", data.max)
diff --git a/examples/dictExample2.py b/examples/dictExample2.py
index fa1b866..16590a3 100644
--- a/examples/dictExample2.py
+++ b/examples/dictExample2.py
@@ -6,7 +6,17 @@
#
# Copyright (c) 2004, Paul McGuire
#
-from pyparsing import Literal, Word, Group, Dict, ZeroOrMore, alphas, nums, delimitedList, pyparsing_common as ppc
+from pyparsing import (
+ Literal,
+ Word,
+ Group,
+ Dict,
+ ZeroOrMore,
+ alphas,
+ nums,
+ delimitedList,
+ pyparsing_common as ppc,
+)
testData = """
+-------+------+------+------+------+------+------+------+------+
@@ -25,34 +35,34 @@ number = ppc.integer
vert = Literal("|").suppress()
-rowDelim = ("+" + ZeroOrMore( underline + "+" ) ).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 )
+rowData = Group(vert + Word(alphas) + vert + delimitedList(number, "|") + vert)
trailing = rowDelim
-datatable = heading + Dict( ZeroOrMore(rowData) ) + trailing
+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['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(" " * 5, end=" ")
+for i in range(1, len(data)):
+ print("|%5s" % data[i][0], end=" ")
print()
-print(("-" * 6) + ("+------" * (len(data)-1)))
+print(("-" * 6) + ("+------" * (len(data) - 1)))
for i in range(len(data.columns)):
- print("%5s" % data.columns[i], end=' ')
+ print("%5s" % data.columns[i], end=" ")
for j in range(len(data) - 1):
- print('|%5s' % data[j + 1][i + 1], end=' ')
+ print("|%5s" % data[j + 1][i + 1], end=" ")
print()
diff --git a/examples/ebnf.py b/examples/ebnf.py
index bb19155..4843d40 100644
--- a/examples/ebnf.py
+++ b/examples/ebnf.py
@@ -11,7 +11,7 @@
from pyparsing import *
-all_names = '''
+all_names = """
integer
meta_identifier
terminal_string
@@ -25,29 +25,36 @@ single_definition
definitions_list
syntax_rule
syntax
-'''.split()
+""".split()
integer = Word(nums)
-meta_identifier = Word(alphas, alphanums + '_')
-terminal_string = Suppress("'") + CharsNotIn("'") + Suppress("'") ^ \
- Suppress('"') + CharsNotIn('"') + Suppress('"')
+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")
+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)
@@ -56,6 +63,7 @@ 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]]
@@ -64,28 +72,35 @@ def do_meta_identifier(str, loc, toks):
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] ]
+ return [toks[0]]
+
def do_syntactic_term(str, loc, toks):
if len(toks) == 2:
@@ -93,7 +108,8 @@ def do_syntactic_term(str, loc, toks):
return NotAny(toks[1]) + toks[0]
else:
# syntactic_factor
- return [ toks[0] ]
+ return [toks[0]]
+
def do_single_definition(str, loc, toks):
toks = toks.asList()
@@ -102,7 +118,8 @@ def do_single_definition(str, loc, toks):
return And(toks)
else:
# syntactic_term
- return [ toks[0] ]
+ return [toks[0]]
+
def do_definitions_list(str, loc, toks):
toks = toks.asList()
@@ -111,31 +128,36 @@ def do_definitions_list(str, loc, toks):
return Or(toks)
else:
# single_definition
- return [ toks[0] ]
+ 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] ]
+ 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]
+ action = vars()["do_" + name]
expr.setName(name)
expr.setParseAction(action)
- #~ expr.setDebug()
+ # ~ expr.setDebug()
def parse(ebnf, given_table={}):
@@ -147,5 +169,5 @@ def parse(ebnf, given_table={}):
for name in table:
expr = table[name]
expr.setName(name)
- #~ expr.setDebug()
+ # ~ expr.setDebug()
return table
diff --git a/examples/ebnftest.py b/examples/ebnftest.py
index 40772ee..7b1ff75 100644
--- a/examples/ebnftest.py
+++ b/examples/ebnftest.py
@@ -5,14 +5,14 @@
#
# Submitted 2004 by Seo Sanghyeon
#
-print('Importing pyparsing...')
+print("Importing pyparsing...")
from pyparsing import *
-print('Constructing EBNF parser with pyparsing...')
+print("Constructing EBNF parser with pyparsing...")
import ebnf
-grammar = '''
+grammar = """
syntax = (syntax_rule), {(syntax_rule)};
syntax_rule = meta_identifier, '=', definitions_list, ';';
definitions_list = single_definition, {'|', single_definition};
@@ -30,43 +30,46 @@ terminal_string = "'", 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)
+# ~ 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...')
+print("Parsing EBNF grammar with EBNF parser...")
parsers = ebnf.parse(grammar, table)
-ebnf_parser = parsers['syntax']
+ebnf_parser = parsers["syntax"]
commentcharcount = 0
commentlocs = set()
-def tallyCommentChars(s,l,t):
- global commentcharcount,commentlocs
+
+
+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]))) )
+ charCount = len(t[0]) - len(list(filter(str.isspace, t[0])))
commentcharcount += charCount
commentlocs.add(l)
- return l,t
+ 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 )
+# 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')
+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("],")))
+print("],\n".join(str(parsed_chars.asList()).split("],")))
-#~ grammar_length = len(grammar) - len(filter(str.isspace, grammar))-commentcharcount
+# ~ grammar_length = len(grammar) - len(filter(str.isspace, grammar))-commentcharcount
-#~ assert parsed_char_len == grammar_length
+# ~ assert parsed_char_len == grammar_length
-print('Ok!')
+print("Ok!")
diff --git a/examples/eval_arith.py b/examples/eval_arith.py
index 8f3e996..bfd0ce0 100644
--- a/examples/eval_arith.py
+++ b/examples/eval_arith.py
@@ -8,28 +8,43 @@
# Added support for exponentiation, using right-to-left evaluation of
# operands
#
-from pyparsing import Word, nums, alphas, Combine, oneOf, \
- opAssoc, infixNotation, Literal
+from pyparsing import (
+ Word,
+ nums,
+ alphas,
+ Combine,
+ oneOf,
+ opAssoc,
+ infixNotation,
+ Literal,
+)
+
class EvalConstant:
"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:
"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]
+ mult = {"+": 1, "-": -1}[self.sign]
return mult * self.value.eval()
+
def operatorOperands(tokenlist):
"generator to extract operators and operands in pairs"
it = iter(tokenlist)
@@ -39,67 +54,79 @@ def operatorOperands(tokenlist):
except StopIteration:
break
+
class EvalPowerOp:
"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
+ res = val.eval() ** res
return res
+
class EvalMultOp:
"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 == '*':
+ for op, val in operatorOperands(self.value[1:]):
+ if op == "*":
prod *= val.eval()
- if op == '/':
+ if op == "/":
prod /= val.eval()
return prod
+
class EvalAddOp:
"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 == '+':
+ for op, val in operatorOperands(self.value[1:]):
+ if op == "+":
sum += val.eval()
- if op == '-':
+ if op == "-":
sum -= val.eval()
return sum
+
class EvalComparisonOp:
"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,
- }
+ "<": 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:]):
+ for op, val in operatorOperands(self.value[1:]):
fn = EvalComparisonOp.opMap[op]
val2 = val.eval()
- if not fn(val1,val2):
+ if not fn(val1, val2):
break
val1 = val2
else:
@@ -110,104 +137,116 @@ class EvalComparisonOp:
# define the parser
integer = Word(nums)
real = Combine(Word(nums) + "." + Word(nums))
-variable = Word(alphas,exact=1)
+variable = Word(alphas, exact=1)
operand = real | integer | variable
-signop = oneOf('+ -')
-multop = oneOf('* /')
-plusop = oneOf('+ -')
-expop = Literal('**')
+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,
+arith_expr = infixNotation(
+ operand,
[
- (signop, 1, opAssoc.RIGHT, EvalSignOp),
- (expop, 2, opAssoc.LEFT, EvalPowerOp),
- (multop, 2, opAssoc.LEFT, EvalMultOp),
- (plusop, 2, opAssoc.LEFT, EvalAddOp),
- ])
+ (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),
- ])
+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}
+ 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_)) )
+ 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:
+ for test, expected in tests:
ret = comp_expr.parseString(test)[0]
parsedvalue = ret.eval()
print(test, expected, parsedvalue)
@@ -215,9 +254,9 @@ def main():
print("<<< FAIL")
failed += 1
else:
- print('')
+ print("")
- print('')
+ print("")
if failed:
print(failed, "tests FAILED")
return 1
@@ -225,5 +264,6 @@ def main():
print("all tests PASSED")
return 0
-if __name__=='__main__':
+
+if __name__ == "__main__":
exit(main())
diff --git a/examples/excelExpr.py b/examples/excelExpr.py
index 86237ef..cea2eea 100644
--- a/examples/excelExpr.py
+++ b/examples/excelExpr.py
@@ -4,36 +4,64 @@
#
# A partial implementation of a parser of Excel formula expressions.
#
-from pyparsing import (CaselessKeyword, Suppress, Word, alphas,
- alphanums, nums, Optional, Group, oneOf, Forward,
- infixNotation, opAssoc, dblQuotedString, delimitedList,
- Combine, Literal, QuotedString, ParserElement, pyparsing_common as ppc)
+from pyparsing import (
+ CaselessKeyword,
+ Suppress,
+ Word,
+ alphas,
+ alphanums,
+ nums,
+ Optional,
+ Group,
+ oneOf,
+ Forward,
+ infixNotation,
+ opAssoc,
+ dblQuotedString,
+ delimitedList,
+ Combine,
+ Literal,
+ QuotedString,
+ ParserElement,
+ pyparsing_common as ppc,
+)
+
ParserElement.enablePackrat()
-EQ,LPAR,RPAR,COLON,COMMA = map(Suppress, '=():,')
-EXCL, DOLLAR = map(Literal,"!$")
-sheetRef = Word(alphas, alphanums) | QuotedString("'",escQuote="''")
-colRef = Optional(DOLLAR) + Word(alphas,max=2)
+EQ, LPAR, RPAR, COLON, COMMA = map(Suppress, "=():,")
+EXCL, DOLLAR = map(Literal, "!$")
+sheetRef = Word(alphas, alphanums) | QuotedString("'", escQuote="''")
+colRef = Optional(DOLLAR) + Word(alphas, max=2)
rowRef = Optional(DOLLAR) + Word(nums)
-cellRef = Combine(Group(Optional(sheetRef + EXCL)("sheet") + colRef("col") +
- rowRef("row")))
+cellRef = Combine(
+ Group(Optional(sheetRef + EXCL)("sheet") + colRef("col") + rowRef("row"))
+)
-cellRange = (Group(cellRef("start") + COLON + cellRef("end"))("range")
- | cellRef | Word(alphas,alphanums))
+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)
+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))
+statFunc = lambda name: Group(
+ CaselessKeyword(name) + Group(LPAR + delimitedList(expr) + RPAR)
+)
sumFunc = statFunc("sum")
minFunc = statFunc("min")
maxFunc = statFunc("max")
@@ -44,22 +72,18 @@ multOp = oneOf("* /")
addOp = oneOf("+ -")
numericLiteral = ppc.number
operand = numericLiteral | funcCall | cellRange | cellRef
-arithExpr = infixNotation(operand,
- [
- (multOp, 2, opAssoc.LEFT),
- (addOp, 2, opAssoc.LEFT),
- ])
+arithExpr = infixNotation(
+ operand, [(multOp, 2, opAssoc.LEFT), (addOp, 2, opAssoc.LEFT),]
+)
textOperand = dblQuotedString | cellRef
-textExpr = infixNotation(textOperand,
- [
- ('&', 2, opAssoc.LEFT),
- ])
+textExpr = infixNotation(textOperand, [("&", 2, opAssoc.LEFT),])
expr << (arithExpr | textExpr)
-(EQ + expr).runTests("""\
+(EQ + expr).runTests(
+ """\
=3*A7+5
=3*Sheet1!$A$7+5
=3*'Sheet 1'!$A$7+5"
@@ -67,4 +91,5 @@ expr << (arithExpr | textExpr)
=if(Sum(A1:A25)>42,Min(B1:B25),if(Sum(C1:C25)>3.14, (Min(C1:C25)+3)*18,Max(B1:B25)))
=sum(a1:a25,10,min(b1,c2,d3))
=if("T"&a2="TTime", "Ready", "Not ready")
-""")
+"""
+)
diff --git a/examples/fourFn.py b/examples/fourFn.py
index e5be215..68441b8 100644
--- a/examples/fourFn.py
+++ b/examples/fourFn.py
@@ -10,24 +10,40 @@
#
# Copyright 2003-2019 by Paul McGuire
#
-from pyparsing import (Literal, Word, Group, Forward, alphas, alphanums, Regex, ParseException,
- CaselessKeyword, Suppress, delimitedList)
+from pyparsing import (
+ Literal,
+ Word,
+ Group,
+ Forward,
+ alphas,
+ alphanums,
+ Regex,
+ ParseException,
+ CaselessKeyword,
+ Suppress,
+ delimitedList,
+)
import math
import operator
exprStack = []
+
def push_first(toks):
exprStack.append(toks[0])
+
def push_unary_minus(toks):
for t in toks:
- if t == '-':
- exprStack.append('unary -')
+ if t == "-":
+ exprStack.append("unary -")
else:
break
+
bnf = None
+
+
def BNF():
"""
expop :: '^'
@@ -52,7 +68,7 @@ def BNF():
# or use provided pyparsing_common.number, but convert back to str:
# fnumber = ppc.number().addParseAction(lambda t: str(t[0]))
fnumber = Regex(r"[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?")
- ident = Word(alphas, alphanums+"_$")
+ ident = Word(alphas, alphanums + "_$")
plus, minus, mult, div = map(Literal, "+-*/")
lpar, rpar = map(Suppress, "()")
@@ -63,11 +79,16 @@ def BNF():
expr = Forward()
expr_list = delimitedList(Group(expr))
# add parse action that replaces the function identifier with a (name, number of args) tuple
- fn_call = (ident + lpar - Group(expr_list) + rpar).setParseAction(lambda t: t.insert(0, (t.pop(0), len(t[0]))))
- atom = (addop[...] +
- ((fn_call | pi | e | fnumber | ident).setParseAction(push_first)
- | Group(lpar + expr + rpar))
- ).setParseAction(push_unary_minus)
+ fn_call = (ident + lpar - Group(expr_list) + rpar).setParseAction(
+ lambda t: t.insert(0, (t.pop(0), len(t[0])))
+ )
+ atom = (
+ addop[...]
+ + (
+ (fn_call | pi | e | fnumber | ident).setParseAction(push_first)
+ | Group(lpar + expr + rpar)
+ )
+ ).setParseAction(push_unary_minus)
# by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left
# exponents, instead of left-to-right that is, 2^3^2 = 2^(3^2), not (2^3)^2.
@@ -78,6 +99,7 @@ def BNF():
bnf = expr
return bnf
+
# map operator symbols to corresponding arithmetic operations
epsilon = 1e-12
opn = {
@@ -85,8 +107,8 @@ opn = {
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
- "^": operator.pow
- }
+ "^": operator.pow,
+}
fn = {
"sin": math.sin,
@@ -96,14 +118,15 @@ fn = {
"abs": abs,
"trunc": lambda a: int(a),
"round": round,
- "sgn": lambda a: -1 if a < -epsilon else 1 if a > epsilon else 0
- }
+ "sgn": lambda a: -1 if a < -epsilon else 1 if a > epsilon else 0,
+}
+
def evaluate_stack(s):
op, num_args = s.pop(), 0
if isinstance(op, tuple):
op, num_args = op
- if op == 'unary -':
+ if op == "unary -":
return -evaluate_stack(s)
if op in "+-*/^":
# note: operands are pushed onto the stack in reverse order
@@ -113,7 +136,7 @@ def evaluate_stack(s):
elif op == "PI":
return math.pi # 3.1415926535
elif op == "E":
- return math.e # 2.718281828
+ return math.e # 2.718281828
elif op in fn:
# note: args are pushed onto the stack in reverse order
args = reversed([evaluate_stack(s) for _ in range(num_args)])
@@ -152,37 +175,37 @@ if __name__ == "__main__":
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+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("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("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("10+sin(PI/4)^2", 10 + math.sin(math.pi/4)**2)
+ test("sin(PI/2)", math.sin(math.pi / 2))
+ test("10+sin(PI/4)^2", 10 + math.sin(math.pi / 4) ** 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("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+2", 2**3+2)
- test("2^3+5", 2**3+5)
- test("2^9", 2**9)
+ test("2^3^2", 2 ** 3 ** 2)
+ 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("sgn(0.1)", 1)
test("foo(0.1)", None)
test("round(E, 3)", round(math.e, 3))
- test("round(PI^2, 3)", round(math.pi**2, 3))
+ test("round(PI^2, 3)", round(math.pi ** 2, 3))
test("sgn(cos(PI/4))", 1)
test("sgn(cos(PI/2))", 0)
test("sgn(cos(PI*3/4))", -1)
diff --git a/examples/gen_ctypes.py b/examples/gen_ctypes.py
index 325aa28..176644f 100644
--- a/examples/gen_ctypes.py
+++ b/examples/gen_ctypes.py
@@ -8,43 +8,43 @@
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,"(){},;")
+ "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]+")
@@ -52,32 +52,50 @@ 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")))
+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
+ 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)
+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
+ 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)
+enum_def = (
+ Keyword("enum")
+ + LBRACE
+ + delimitedList(Group(ident("name") + "=" + (hexinteger | integer)("value")))(
+ "evalues"
+ )
+ + Optional(COMMA)
+ + RBRACE
+)
c_header = open("snmp_api.h").read()
@@ -91,19 +109,23 @@ functions = []
enum_constants = []
# add structures commonly included from std lib headers
-def addStdType(t,namespace=""):
- fullname = namespace+'_'+t if namespace else t
+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] = "{}_{}".format(module, key)
+
def typeAsCtypes(typestr):
if typestr in typemap:
return typemap[typestr]
@@ -111,9 +133,10 @@ def typeAsCtypes(typestr):
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) )
+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
@@ -124,8 +147,11 @@ 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
+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 != "...":
@@ -135,26 +161,29 @@ for fn,_,_ in (cStyleComment.suppress() | fn_typedef.suppress() | func_def).scan
# scan input header text for enums
enum_def.ignore(cppStyleComment)
-for en_,_,_ in enum_def.scanString(c_header):
+for en_, _, _ in enum_def.scanString(c_header):
for ev in en_.evalues:
- enum_constants.append( (ev.name, ev.value) )
+ enum_constants.append((ev.name, ev.value))
print("from ctypes import *")
print("{} = CDLL('{}.dll')".format(module, module))
print()
print("# user defined types")
-for tdname,tdtyp in typedefs:
+for tdname, tdtyp in typedefs:
print("{} = {}".format(tdname, typemap[tdtyp]))
for fntd in fn_typedefs:
- print("{} = CFUNCTYPE({})".format(fntd.fn_name,
- ',\n '.join(typeAsCtypes(a.argtype) for a in fntd.fn_args)))
+ print(
+ "{} = CFUNCTYPE({})".format(
+ 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("{} = {}".format(en,ev))
+for en, ev in enum_constants:
+ print("{} = {}".format(en, ev))
print()
print("# functions")
@@ -166,7 +195,11 @@ for fn in functions:
print("# warning - %s takes variable argument list" % prefix)
del fn.fn_args[-1]
- if fn.fn_args.asList() != [['void']]:
- print("{}.argtypes = ({},)".format(prefix, ','.join(typeAsCtypes(a.argtype) for a in fn.fn_args)))
+ if fn.fn_args.asList() != [["void"]]:
+ print(
+ "{}.argtypes = ({},)".format(
+ prefix, ",".join(typeAsCtypes(a.argtype) for a in fn.fn_args)
+ )
+ )
else:
print("%s.argtypes = ()" % (prefix))
diff --git a/examples/getNTPserversNew.py b/examples/getNTPserversNew.py
index 3ee5e06..5fcd9d1 100644
--- a/examples/getNTPserversNew.py
+++ b/examples/getNTPserversNew.py
@@ -7,16 +7,25 @@
# September, 2010 - updated to more current use of setResultsName, new NIST URL
#
import pyparsing as pp
+
ppc = pp.pyparsing_common
from urllib.request import urlopen
integer = pp.Word(pp.nums)
ipAddress = ppc.ipv4_address()
-hostname = pp.delimitedList(pp.Word(pp.alphas, pp.alphanums+"-_"), ".", combine=True)
+hostname = pp.delimitedList(pp.Word(pp.alphas, pp.alphanums + "-_"), ".", combine=True)
tdStart, tdEnd = pp.makeHTMLTags("td")
-timeServerPattern = (tdStart + hostname("hostname") + tdEnd
- + tdStart + ipAddress("ipAddr") + tdEnd
- + tdStart + tdStart.tag_body("loc") + tdEnd)
+timeServerPattern = (
+ tdStart
+ + hostname("hostname")
+ + tdEnd
+ + tdStart
+ + ipAddress("ipAddr")
+ + tdEnd
+ + tdStart
+ + tdStart.tag_body("loc")
+ + tdEnd
+)
# get list of time servers
nistTimeServerURL = "https://tf.nist.gov/tf-cgi/servers.cgi#"
diff --git a/examples/greeting.py b/examples/greeting.py
index 6b1cfe3..28a534a 100644
--- a/examples/greeting.py
+++ b/examples/greeting.py
@@ -14,12 +14,14 @@ greet = pp.Word(pp.alphas) + "," + pp.Word(pp.alphas) + pp.oneOf("! ? .")
hello = "Hello, World!"
# parse input string
-print(hello, "->", greet.parseString( hello ))
+print(hello, "->", greet.parseString(hello))
# parse a bunch of input strings
-greet.runTests("""\
+greet.runTests(
+ """\
Hello, World!
Ahoy, Matey!
Howdy, Pardner!
Morning, Neighbor!
- """) \ No newline at end of file
+ """
+)
diff --git a/examples/greetingInGreek.py b/examples/greetingInGreek.py
index 56117d2..ed98e9a 100644
--- a/examples/greetingInGreek.py
+++ b/examples/greetingInGreek.py
@@ -9,7 +9,7 @@ from pyparsing import Word, pyparsing_unicode as ppu
# define grammar
alphas = ppu.Greek.alphas
-greet = Word(alphas) + ',' + Word(alphas) + '!'
+greet = Word(alphas) + "," + Word(alphas) + "!"
# input string
hello = "Καλημέρα, κόσμε!"
diff --git a/examples/greetingInKorean.py b/examples/greetingInKorean.py
index 9e881ac..00ea9bc 100644
--- a/examples/greetingInKorean.py
+++ b/examples/greetingInKorean.py
@@ -14,7 +14,7 @@ koreanWord = Word(koreanChars, min=2)
greet = koreanWord + "," + koreanWord + "!"
# input string
-hello = '안녕, 여러분!' #"Hello, World!" in Korean
+hello = "안녕, 여러분!" # "Hello, World!" in Korean
# parse input string
print(greet.parseString(hello))
diff --git a/examples/holaMundo.py b/examples/holaMundo.py
index 02be601..0589a0d 100644
--- a/examples/holaMundo.py
+++ b/examples/holaMundo.py
@@ -1,7 +1,15 @@
# escrito por Marco Alfonso, 2004 Noviembre
# importamos los símbolos requeridos desde el módulo
-from pyparsing import Word, alphas, oneOf, nums, Group, OneOrMore, pyparsing_unicode as ppu
+from pyparsing import (
+ Word,
+ alphas,
+ oneOf,
+ nums,
+ Group,
+ OneOrMore,
+ pyparsing_unicode as ppu,
+)
# usamos las letras en latin1, que incluye las como 'ñ', 'á', 'é', etc.
alphas = ppu.Latin1.alphas
@@ -10,42 +18,45 @@ alphas = ppu.Latin1.alphas
# una palabra compuesta de caracteres alfanumericos
# (Word(alphas)) mas una ',' mas otra palabra alfanumerica,
# mas '!' y esos seian nuestros tokens
-saludo = Word(alphas) + ',' + Word(alphas) + oneOf('! . ?')
+saludo = Word(alphas) + "," + Word(alphas) + oneOf("! . ?")
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, token in enumerate(tokens):
- print ("Token %d -> %s" % (i,token))
+ print("Token %d -> %s" % (i, token))
-#imprimimos cada uno de los tokens Y listooo!!, he aquí a salida
+# imprimimos cada uno de los tokens Y listooo!!, he aquí a salida
# Token 0 -> Hola
# Token 1 -> ,
# Token 2-> Mundo
# Token 3 -> !
# ahora cambia el parseador, aceptando saludos con mas que una sola palabra antes que ','
-saludo = Group(OneOrMore(Word(alphas))) + ',' + Word(alphas) + oneOf('! . ?')
+saludo = Group(OneOrMore(Word(alphas))) + "," + Word(alphas) + oneOf("! . ?")
tokens = saludo.parseString("Hasta mañana, Mundo !")
for i, token in enumerate(tokens):
- print ("Token %d -> %s" % (i,token))
+ print("Token %d -> %s" % (i, token))
# Ahora parseamos algunas cadenas, usando el metodo runTests
-saludo.runTests("""\
+saludo.runTests(
+ """\
Hola, Mundo!
Hasta mañana, Mundo !
-""", fullDump=False)
+""",
+ fullDump=False,
+)
# Por supuesto, se pueden "reutilizar" gramáticas, por ejemplo:
-numimag = Word(nums) + 'i'
+numimag = Word(nums) + "i"
numreal = Word(nums)
-numcomplex = numreal + '+' + numimag
-print (numcomplex.parseString("3+5i"))
+numcomplex = numreal + "+" + numimag
+print(numcomplex.parseString("3+5i"))
# Cambiar a complejo numero durante parsear:
-numcomplex.setParseAction(lambda t: complex(''.join(t).replace('i','j')))
-print (numcomplex.parseString("3+5i"))
+numcomplex.setParseAction(lambda t: complex("".join(t).replace("i", "j")))
+print(numcomplex.parseString("3+5i"))
# Excelente!!, bueno, los dejo, me voy a seguir tirando código...
diff --git a/examples/htmlStripper.py b/examples/htmlStripper.py
index bd99b77..6a209fa 100644
--- a/examples/htmlStripper.py
+++ b/examples/htmlStripper.py
@@ -7,8 +7,16 @@
# Copyright (c) 2006, 2016, Paul McGuire
#
from urllib.request import urlopen
-from pyparsing import (makeHTMLTags, commonHTMLEntity, replaceHTMLEntity,
- htmlComment, anyOpenTag, anyCloseTag, LineEnd, replaceWith)
+from pyparsing import (
+ makeHTMLTags,
+ commonHTMLEntity,
+ replaceHTMLEntity,
+ htmlComment,
+ anyOpenTag,
+ anyCloseTag,
+ LineEnd,
+ replaceWith,
+)
scriptOpen, scriptClose = makeHTMLTags("script")
scriptBody = scriptOpen + scriptOpen.tag_body + scriptClose
@@ -16,15 +24,18 @@ commonHTMLEntity.setParseAction(replaceHTMLEntity)
# get some HTML
targetURL = "https://wiki.python.org/moin/PythonDecoratorLibrary"
-with urlopen( targetURL ) as targetPage:
+with urlopen(targetURL) as targetPage:
targetHTML = targetPage.read().decode("UTF-8")
# first pass, strip out tags and translate entities
-firstPass = (htmlComment | scriptBody | commonHTMLEntity |
- anyOpenTag | anyCloseTag ).suppress().transformString(targetHTML)
+firstPass = (
+ (htmlComment | scriptBody | commonHTMLEntity | anyOpenTag | anyCloseTag)
+ .suppress()
+ .transformString(targetHTML)
+)
# first pass leaves many blank lines, collapse these down
-repeatedNewlines = LineEnd()*(2,)
+repeatedNewlines = LineEnd() * (2,)
repeatedNewlines.setParseAction(replaceWith("\n\n"))
secondPass = repeatedNewlines.transformString(firstPass)
diff --git a/examples/htmlTableParser.py b/examples/htmlTableParser.py
index 35cdd03..e96a913 100644
--- a/examples/htmlTableParser.py
+++ b/examples/htmlTableParser.py
@@ -11,42 +11,51 @@ import urllib.request
# define basic HTML tags, and compose into a Table
-table, table_end = pp.makeHTMLTags('table')
-thead, thead_end = pp.makeHTMLTags('thead')
-tbody, tbody_end = pp.makeHTMLTags('tbody')
-tr, tr_end = pp.makeHTMLTags('tr')
-th, th_end = pp.makeHTMLTags('th')
-td, td_end = pp.makeHTMLTags('td')
-a, a_end = pp.makeHTMLTags('a')
+table, table_end = pp.makeHTMLTags("table")
+thead, thead_end = pp.makeHTMLTags("thead")
+tbody, tbody_end = pp.makeHTMLTags("tbody")
+tr, tr_end = pp.makeHTMLTags("tr")
+th, th_end = pp.makeHTMLTags("th")
+td, td_end = pp.makeHTMLTags("td")
+a, a_end = pp.makeHTMLTags("a")
# method to strip HTML tags from a string - will be used to clean up content of table cells
strip_html = (pp.anyOpenTag | pp.anyCloseTag).suppress().transformString
# expression for parsing <a href="url">text</a> links, returning a (text, url) tuple
-link = pp.Group(a + a.tag_body('text') + a_end.suppress())
+link = pp.Group(a + a.tag_body("text") + a_end.suppress())
link.addParseAction(lambda t: (t[0].text, t[0].href))
# method to create table rows of header and data tags
def table_row(start_tag, end_tag):
body = start_tag.tag_body
- body.addParseAction(pp.tokenMap(str.strip),
- pp.tokenMap(strip_html))
- row = pp.Group(tr.suppress()
- + pp.ZeroOrMore(start_tag.suppress()
- + body
- + end_tag.suppress())
- + tr_end.suppress())
+ body.addParseAction(pp.tokenMap(str.strip), pp.tokenMap(strip_html))
+ row = pp.Group(
+ tr.suppress()
+ + pp.ZeroOrMore(start_tag.suppress() + body + end_tag.suppress())
+ + tr_end.suppress()
+ )
return row
+
th_row = table_row(th, th_end)
td_row = table_row(td, td_end)
# define expression for overall table - may vary slightly for different pages
-html_table = table + tbody + pp.Optional(th_row('headers')) + pp.ZeroOrMore(td_row)('rows') + tbody_end + table_end
+html_table = (
+ table
+ + tbody
+ + pp.Optional(th_row("headers"))
+ + pp.ZeroOrMore(td_row)("rows")
+ + tbody_end
+ + table_end
+)
# read in a web page containing an interesting HTML table
-with urllib.request.urlopen("https://en.wikipedia.org/wiki/List_of_tz_database_time_zones") as page:
+with urllib.request.urlopen(
+ "https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"
+) as page:
page_html = page.read().decode()
tz_table = html_table.searchString(page_html)[0]
@@ -55,7 +64,8 @@ tz_table = html_table.searchString(page_html)[0]
rows = [dict(zip(tz_table.headers, row)) for row in tz_table.rows]
# make a dict keyed by TZ database name
-tz_db = {row['TZ database name']: row for row in rows}
+tz_db = {row["TZ database name"]: row for row in rows}
from pprint import pprint
-pprint(tz_db['America/Chicago'])
+
+pprint(tz_db["America/Chicago"])
diff --git a/examples/httpServerLogParser.py b/examples/httpServerLogParser.py
index b10678b..c84337f 100644
--- a/examples/httpServerLogParser.py
+++ b/examples/httpServerLogParser.py
@@ -23,39 +23,69 @@ Referer
Client Software
"""
-from pyparsing import alphas,nums, dblQuotedString, Combine, Word, Group, delimitedList, Suppress, removeQuotes
+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()
+
+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 )
+ integer = Word(nums)
+ ipAddress = delimitedList(integer, ".", combine=True)
- timeZoneOffset = Word("+-",nums)
+ timeZoneOffset = Word("+-", nums)
month = Word(string.ascii_uppercase, string.ascii_lowercase, exact=3)
- serverDateTime = Group( Suppress("[") +
- Combine( integer + "/" + month + "/" + integer +
- ":" + integer + ":" + integer + ":" + integer ) +
- timeZoneOffset +
- Suppress("]") )
+ 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) )
+ 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)"
@@ -63,10 +93,11 @@ testdata = """
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
+ 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 repr(fields)
+ # ~ for k in fields.keys():
+ # ~ print "fields." + k + " =", fields[k]
print()
diff --git a/examples/idlParse.py b/examples/idlParse.py
index 1daaf24..52ed3c3 100644
--- a/examples/idlParse.py
+++ b/examples/idlParse.py
@@ -6,85 +6,200 @@
# Copyright (c) 2003, Paul McGuire
#
-from pyparsing import Literal, Word, OneOrMore, ZeroOrMore, \
- Forward, delimitedList, Group, Optional, alphas, restOfLine, cStyleComment, \
- alphanums, quotedString, ParseException, Keyword, Regex
+from pyparsing import (
+ Literal,
+ Word,
+ OneOrMore,
+ ZeroOrMore,
+ Forward,
+ delimitedList,
+ Group,
+ Optional,
+ alphas,
+ restOfLine,
+ cStyleComment,
+ alphanums,
+ quotedString,
+ ParseException,
+ Keyword,
+ Regex,
+)
import pprint
-#~ import tree2image
+
+# ~ import tree2image
bnf = None
+
+
def CORBA_IDL_BNF():
global bnf
if not bnf:
# punctuation
- (colon,lbrace,rbrace,lbrack,rbrack,lparen,rparen,
- equals,comma,dot,slash,bslash,star,semi,langle,rangle) = map(Literal, r":{}[]()=,./\*;<>")
+ (
+ colon,
+ lbrace,
+ rbrace,
+ lbrack,
+ rbrack,
+ lparen,
+ rparen,
+ equals,
+ comma,
+ dot,
+ slash,
+ bslash,
+ star,
+ semi,
+ langle,
+ rangle,
+ ) = map(Literal, r":{}[]()=,./\*;<>")
# keywords
- (any_, attribute_, boolean_, case_, char_, const_, context_, default_, double_, enum_, exception_,
- FALSE_, fixed_, float_, inout_, interface_, in_, long_, module_, Object_, octet_, oneway_, out_, raises_,
- readonly_, sequence_, short_, string_, struct_, switch_, TRUE_, typedef_, unsigned_, union_, void_,
- wchar_, wstring_) = map(Keyword, """any attribute boolean case char const context
+ (
+ any_,
+ attribute_,
+ boolean_,
+ case_,
+ char_,
+ const_,
+ context_,
+ default_,
+ double_,
+ enum_,
+ exception_,
+ FALSE_,
+ fixed_,
+ float_,
+ inout_,
+ interface_,
+ in_,
+ long_,
+ module_,
+ Object_,
+ octet_,
+ oneway_,
+ out_,
+ raises_,
+ readonly_,
+ sequence_,
+ short_,
+ string_,
+ struct_,
+ switch_,
+ TRUE_,
+ typedef_,
+ unsigned_,
+ union_,
+ void_,
+ wchar_,
+ wstring_,
+ ) = map(
+ Keyword,
+ """any attribute boolean case char const context
default double enum exception FALSE fixed float inout interface in long module
Object octet oneway out raises readonly sequence short string struct switch
- TRUE typedef unsigned union void wchar wstring""".split())
+ TRUE typedef unsigned union void wchar wstring""".split(),
+ )
- identifier = Word( alphas, alphanums + "_" ).setName("identifier")
+ identifier = Word(alphas, alphanums + "_").setName("identifier")
real = Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?").setName("real")
integer = Regex(r"0x[0-9a-fA-F]+|[+-]?\d+").setName("int")
- udTypeName = delimitedList( identifier, "::", combine=True ).setName("udType")
- typeName = ( any_ | boolean_ | char_ | double_ | fixed_ |
- float_ | long_ | octet_ | short_ | string_ |
- wchar_ | wstring_ | udTypeName ).setName("type")
+ udTypeName = delimitedList(identifier, "::", combine=True).setName("udType")
+ typeName = (
+ any_
+ | boolean_
+ | char_
+ | double_
+ | fixed_
+ | float_
+ | long_
+ | octet_
+ | short_
+ | string_
+ | wchar_
+ | wstring_
+ | udTypeName
+ ).setName("type")
sequenceDef = Forward().setName("seq")
- sequenceDef << Group( sequence_ + langle + ( sequenceDef | typeName ) + rangle )
- typeDef = sequenceDef | ( typeName + Optional( lbrack + integer + rbrack ) )
- typedefDef = Group( typedef_ + typeDef + identifier + semi ).setName("typedef")
+ 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 ) )
+ 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 )
+ bnf.ignore(singleLineComment)
+ bnf.ignore(cStyleComment)
return bnf
+
testnum = 1
-def test( strng ):
+
+
+def test(strng):
global testnum
print(strng)
try:
bnf = CORBA_IDL_BNF()
- tokens = bnf.parseString( strng )
+ tokens = bnf.parseString(strng)
print("tokens = ")
- pprint.pprint( tokens.asList() )
+ pprint.pprint(tokens.asList())
imgname = "idlParse%02d.bmp" % testnum
testnum += 1
- #~ tree2image.str2image( str(tokens.asList()), imgname )
+ # ~ tree2image.str2image( str(tokens.asList()), imgname )
except ParseException as err:
print(err.line)
- print(" "*(err.column-1) + "^")
+ print(" " * (err.column - 1) + "^")
print(err)
print()
+
if __name__ == "__main__":
test(
"""
@@ -101,7 +216,7 @@ if __name__ == "__main__":
string method3();
};
"""
- )
+ )
test(
"""
/*
@@ -122,7 +237,7 @@ if __name__ == "__main__":
string method3();
};
"""
- )
+ )
test(
r"""
const string test="Test String\n";
@@ -141,7 +256,7 @@ if __name__ == "__main__":
void method1( in string arg1, inout long arg2 );
};
"""
- )
+ )
test(
"""
module Test1
@@ -158,7 +273,7 @@ if __name__ == "__main__":
};
};
"""
- )
+ )
test(
"""
module Test1
@@ -170,4 +285,4 @@ if __name__ == "__main__":
};
"""
- )
+ )
diff --git a/examples/include_preprocessor.py b/examples/include_preprocessor.py
index 0b0d742..294d658 100644
--- a/examples/include_preprocessor.py
+++ b/examples/include_preprocessor.py
@@ -9,19 +9,20 @@ import pyparsing as pp
from pathlib import Path
# parser elements to be used to assemble into #include parser
-SEMI = pp.Suppress(';')
+SEMI = pp.Suppress(";")
INCLUDE = pp.Keyword("#include")
quoted_string = pp.quotedString.addParseAction(pp.removeQuotes)
-file_ref = (quoted_string
- | pp.Word(pp.printables, excludeChars=';'))
+file_ref = quoted_string | pp.Word(pp.printables, excludeChars=";")
# parser for parsing "#include xyz.dat;" directives
-include_directive = (INCLUDE + file_ref("include_file_name") + SEMI)
+include_directive = INCLUDE + file_ref("include_file_name") + SEMI
# add parse action that will recursively pull in included files - when
# using transformString, the value returned from the parse action will replace
# the text matched by the attached expression
seen = set()
+
+
def read_include_contents(s, l, t):
include_file_ref = t.include_file_name
include_echo = "/* {} */".format(pp.line(l, s).strip())
@@ -30,18 +31,22 @@ def read_include_contents(s, l, t):
if include_file_ref not in seen:
seen.add(include_file_ref)
included_file_contents = Path(include_file_ref).read_text()
- return (include_echo + '\n'
- + include_directive.transformString(included_file_contents))
+ return (
+ include_echo
+ + "\n"
+ + include_directive.transformString(included_file_contents)
+ )
else:
- lead = ' '*(pp.col(l, s) - 1)
+ lead = " " * (pp.col(l, s) - 1)
return "/* recursive include! */\n{}{}".format(lead, include_echo)
+
# attach include processing method as parse action (parse-time callback)
# to include_directive expression
include_directive.addParseAction(read_include_contents)
-if __name__ == '__main__':
+if __name__ == "__main__":
# demo
@@ -49,35 +54,40 @@ if __name__ == '__main__':
# - a.txt includes b.txt
# - b.txt includes c.txt
# - c.txt includes b.txt (must catch infinite recursion)
- Path('a.txt').write_text("""\
+ Path("a.txt").write_text(
+ """\
/* a.txt */
int i;
-
- /* sometimes included files aren't in quotes */
+
+ /* sometimes included files aren't in quotes */
#include b.txt;
- """)
+ """
+ )
- Path('b.txt').write_text("""\
+ Path("b.txt").write_text(
+ """\
i = 100;
#include 'c.txt';
- """)
+ """
+ )
- Path('c.txt').write_text("""\
+ Path("c.txt").write_text(
+ """\
i += 1;
-
+
/* watch out! this might be recursive if this file included by b.txt */
#include b.txt;
- """)
-
+ """
+ )
# use include_directive.transformString to perform includes
# read contents of original file
- initial_file = Path('a.txt').read_text()
+ initial_file = Path("a.txt").read_text()
# print original file
print(initial_file)
- print('-----------------')
+ print("-----------------")
# expand includes in source file (and any included files) and print the result
expanded_source = include_directive.transformString(initial_file)
diff --git a/examples/indentedGrammarExample.py b/examples/indentedGrammarExample.py
index 0133a9e..c761393 100644
--- a/examples/indentedGrammarExample.py
+++ b/examples/indentedGrammarExample.py
@@ -37,14 +37,16 @@ stmt = Forward()
suite = indentedBlock(stmt, indentStack)
identifier = Word(alphas, alphanums)
-funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")
-funcDef = Group( funcDecl + suite )
+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 )
+stmt << (funcDef | assignment | identifier)
module_body = OneOrMore(stmt)
diff --git a/examples/invRegex.py b/examples/invRegex.py
index 1777635..f0bfe31 100644
--- a/examples/invRegex.py
+++ b/examples/invRegex.py
@@ -11,85 +11,122 @@
# - () grouping
# - | alternation
#
-__all__ = ["count","invert"]
+__all__ = ["count", "invert"]
+
+from pyparsing import (
+ Literal,
+ oneOf,
+ printables,
+ ParserElement,
+ Combine,
+ SkipTo,
+ infixNotation,
+ ParseFatalException,
+ Word,
+ nums,
+ opAssoc,
+ Suppress,
+ ParseResults,
+ srange,
+)
-from pyparsing import (Literal, oneOf, printables, ParserElement, Combine,
- SkipTo, infixNotation, ParseFatalException, Word, nums, opAssoc,
- Suppress, ParseResults, srange)
class CharacterRangeEmitter:
- def __init__(self,chars):
+ 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 )
+ self.charset = "".join(seen.add(c) or c for c in chars if c not in seen)
+
def __str__(self):
- return '['+self.charset+']'
+ return "[" + self.charset + "]"
+
def __repr__(self):
- return '['+self.charset+']'
+ return "[" + self.charset + "]"
+
def makeGenerator(self):
def genChars():
- yield from self.charset
+ yield from self.charset
+
return genChars
+
class OptionalEmitter:
- def __init__(self,expr):
+ def __init__(self, expr):
self.expr = expr
+
def makeGenerator(self):
def optionalGen():
yield ""
- yield from self.expr.makeGenerator()()
+ yield from self.expr.makeGenerator()()
+
return optionalGen
+
class DotEmitter:
def makeGenerator(self):
def dotGen():
- yield from printables
+ yield from printables
+
return dotGen
+
class GroupEmitter:
- def __init__(self,exprs):
+ def __init__(self, exprs):
self.exprs = ParseResults(exprs)
+
def makeGenerator(self):
def groupGen():
def recurseList(elist):
- if len(elist)==1:
- yield from elist[0].makeGenerator()()
+ if len(elist) == 1:
+ yield from elist[0].makeGenerator()()
else:
for s in elist[0].makeGenerator()():
for s2 in recurseList(elist[1:]):
yield s + s2
+
if self.exprs:
- yield from recurseList(self.exprs)
+ yield from recurseList(self.exprs)
+
return groupGen
+
class AlternativeEmitter:
- def __init__(self,exprs):
+ def __init__(self, exprs):
self.exprs = exprs
+
def makeGenerator(self):
def altGen():
for e in self.exprs:
- yield from e.makeGenerator()()
+ yield from e.makeGenerator()()
+
return altGen
+
class LiteralEmitter:
- def __init__(self,lit):
+ def __init__(self, lit):
self.lit = lit
+
def __str__(self):
- return "Lit:"+self.lit
+ return "Lit:" + self.lit
+
def __repr__(self):
- return "Lit:"+self.lit
+ 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]
+ toks = toks[0]
if toks[1] in "*+":
- raise ParseFatalException("",0,"unbounded repetition operators not supported")
+ raise ParseFatalException("", 0, "unbounded repetition operators not supported")
if toks[1] == "?":
return OptionalEmitter(toks[0])
if "count" in toks:
@@ -100,24 +137,26 @@ def handleRepetition(toks):
optcount = maxcount - mincount
if optcount:
opt = OptionalEmitter(toks[0])
- for i in range(1,optcount):
- opt = OptionalEmitter(GroupEmitter([toks[0],opt]))
+ 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'
+ lit += "\t"
else:
lit += t[1]
else:
lit += t
return LiteralEmitter(lit)
+
def handleMacro(toks):
macroChar = toks[0][1]
if macroChar == "d":
@@ -127,60 +166,74 @@ def handleMacro(toks):
elif macroChar == "s":
return LiteralEmitter(" ")
else:
- raise ParseFatalException("",0,"unsupported macro character (" + macroChar + ")")
+ 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,"[]{}():?")
+ 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"
+ 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)) )
+ 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("*+?"))
- )
+ (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,
+ reTerm = reLiteral | reRange | reMacro | reDot | reNonCaptureGroup
+ reExpr = infixNotation(
+ reTerm,
[
- (repetition, 1, opAssoc.LEFT, handleRepetition),
- (None, 2, opAssoc.LEFT, handleSequence),
- (Suppress('|'), 2, opAssoc.LEFT, handleAlternative),
- ]
- )
+ (repetition, 1, opAssoc.LEFT, handleRepetition),
+ (None, 2, opAssoc.LEFT, handleSequence),
+ (Suppress("|"), 2, opAssoc.LEFT, handleAlternative),
+ ],
+ )
_parser = reExpr
return _parser
+
def count(gen):
"""Simple function to count the number of elements returned by a generator."""
return sum(1 for _ in gen)
+
def invert(regex):
r"""Call this routine as a generator to return all the strings that
match the input regular expression.
@@ -190,6 +243,7 @@ def invert(regex):
invReGenerator = GroupEmitter(parser().parseString(regex)).makeGenerator()
return invReGenerator()
+
def main():
tests = r"""
[A-EA]
@@ -225,12 +279,15 @@ def main():
[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')
+ """.split(
+ "\n"
+ )
for t in tests:
t = t.strip()
- if not t: continue
- print('-'*50)
+ if not t:
+ continue
+ print("-" * 50)
print(t)
try:
num = count(invert(t))
@@ -243,9 +300,10 @@ def main():
break
except ParseFatalException as pfe:
print(pfe.msg)
- print('')
+ print("")
continue
- print('')
+ print("")
+
if __name__ == "__main__":
main()
diff --git a/examples/jsonParser.py b/examples/jsonParser.py
index fbf76b4..3dd9b69 100644
--- a/examples/jsonParser.py
+++ b/examples/jsonParser.py
@@ -36,11 +36,14 @@ value
import pyparsing as pp
from pyparsing import pyparsing_common as ppc
+
def make_keyword(kwd_str, kwd_value):
return pp.Keyword(kwd_str).setParseAction(pp.replaceWith(kwd_value))
-TRUE = make_keyword("true", True)
+
+
+TRUE = make_keyword("true", True)
FALSE = make_keyword("false", False)
-NULL = make_keyword("null", None)
+NULL = make_keyword("null", None)
LBRACK, RBRACK, LBRACE, RBRACE, COLON = map(pp.Suppress, "[]{}:")
@@ -49,9 +52,11 @@ jsonNumber = ppc.number()
jsonObject = pp.Forward()
jsonValue = pp.Forward()
-jsonElements = pp.delimitedList( jsonValue )
+jsonElements = pp.delimitedList(jsonValue)
jsonArray = pp.Group(LBRACK + pp.Optional(jsonElements, []) + RBRACK)
-jsonValue << (jsonString | jsonNumber | pp.Group(jsonObject) | jsonArray | TRUE | FALSE | NULL)
+jsonValue << (
+ jsonString | jsonNumber | pp.Group(jsonObject) | jsonArray | TRUE | FALSE | NULL
+)
memberDef = pp.Group(jsonString + COLON + jsonValue)
jsonMembers = pp.delimitedList(memberDef)
jsonObject << pp.Dict(LBRACE + pp.Optional(jsonMembers) + RBRACE)
@@ -94,12 +99,14 @@ if __name__ == "__main__":
results = jsonObject.parseString(testdata)
results.pprint()
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 )
+ testPrint(results.glossary.title)
+ testPrint(results.glossary.GlossDiv.GlossList.ID)
+ testPrint(results.glossary.GlossDiv.GlossList.FalseValue)
+ testPrint(results.glossary.GlossDiv.GlossList.Acronym)
+ testPrint(results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2)
+ testPrint(results.glossary.GlossDiv.GlossList.PrimesLessThan10)
diff --git a/examples/linenoExample.py b/examples/linenoExample.py
index f343869..d21e502 100644
--- a/examples/linenoExample.py
+++ b/examples/linenoExample.py
@@ -15,16 +15,20 @@ to come to the aid
of their country."""
# demonstrate use of lineno, line, and col in a parse action
-def reportLongWords(st,locn,toks):
+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(
+ "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("'%s'" % line(locn, st))
+ print((" " * col(locn, st)) + " ^")
print()
-wd = Word(alphas).setParseAction( reportLongWords )
+
+wd = Word(alphas).setParseAction(reportLongWords)
OneOrMore(wd).parseString(data)
@@ -34,16 +38,19 @@ class Token:
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)
+ 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 )
+def createTokenObject(st, locn, toks):
+ return Token(st, locn, toks[0])
+
+
+wd = Word(alphas).setParseAction(createTokenObject)
for tokenObj in OneOrMore(wd).parseString(data):
print(tokenObj)
diff --git a/examples/list1.py b/examples/list1.py
index 49a0bff..53673db 100644
--- a/examples/list1.py
+++ b/examples/list1.py
@@ -11,8 +11,9 @@ from pyparsing import *
lbrack = Literal("[")
rbrack = Literal("]")
integer = Word(nums).setName("integer")
-real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
- Optional(Word(nums))).setName("real")
+real = Combine(
+ Optional(oneOf("+ -")) + Word(nums) + "." + Optional(Word(nums))
+).setName("real")
listItem = real | integer | quotedString
@@ -26,12 +27,15 @@ print(listStr.parseString(test))
# second pass, cleanup and add converters
lbrack = Literal("[").suppress()
rbrack = Literal("]").suppress()
-cvtInt = lambda s,l,toks: int(toks[0])
-cvtReal = lambda s,l,toks: float(toks[0])
-integer = Word(nums).setName("integer").setParseAction( cvtInt )
-real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
- Optional(Word(nums))).setName("real").setParseAction( cvtReal )
-listItem = real | integer | quotedString.setParseAction( removeQuotes )
+cvtInt = lambda s, l, toks: int(toks[0])
+cvtReal = lambda s, l, toks: float(toks[0])
+integer = Word(nums).setName("integer").setParseAction(cvtInt)
+real = (
+ Combine(Optional(oneOf("+ -")) + Word(nums) + "." + Optional(Word(nums)))
+ .setName("real")
+ .setParseAction(cvtReal)
+)
+listItem = real | integer | quotedString.setParseAction(removeQuotes)
listStr = lbrack + delimitedList(listItem) + rbrack
@@ -45,12 +49,12 @@ lbrack, rbrack = map(Suppress, "[]")
cvtInt = tokenMap(int)
cvtReal = tokenMap(float)
-integer = Word(nums).setName("integer").setParseAction( cvtInt )
-real = Regex(r"[+-]?\d+\.\d*").setName("real").setParseAction( cvtReal )
+integer = Word(nums).setName("integer").setParseAction(cvtInt)
+real = Regex(r"[+-]?\d+\.\d*").setName("real").setParseAction(cvtReal)
listStr = Forward()
listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listStr)
listStr << lbrack + delimitedList(listItem) + rbrack
test = "['a', 100, 3.14, [ +2.718, 'xyzzy', -1.414] ]"
-print(listStr.parseString(test)) \ No newline at end of file
+print(listStr.parseString(test))
diff --git a/examples/listAllMatches.py b/examples/listAllMatches.py
index 7301c84..02ef481 100644
--- a/examples/listAllMatches.py
+++ b/examples/listAllMatches.py
@@ -8,11 +8,11 @@
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() ]
+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("")
print("Define grammar using normal results names")
print("(only last matching symbol is saved)")
@@ -26,7 +26,7 @@ print(results)
print(results.vowels)
print(results.cons)
print(results.others)
-print('')
+print("")
print("Define grammar using results names, with listAllMatches=True")
@@ -40,12 +40,12 @@ letters = OneOrMore(cons | vowels | other)
results = letters.parseString(test, parseAll=True)
print(results)
print(sorted(set(results)))
-print('')
+print("")
print(results.vowels)
print(sorted(set(results.vowels)))
-print('')
+print("")
print(results.cons)
print(sorted(set(results.cons)))
-print('')
+print("")
print(results.others)
print(sorted(set(results.others)))
diff --git a/examples/lucene_grammar.py b/examples/lucene_grammar.py
index bf92509..ee4633c 100644
--- a/examples/lucene_grammar.py
+++ b/examples/lucene_grammar.py
@@ -9,19 +9,22 @@
import pyparsing as pp
from pyparsing import pyparsing_common as ppc
+
pp.ParserElement.enablePackrat()
-COLON,LBRACK,RBRACK,LBRACE,RBRACE,TILDE,CARAT = map(pp.Literal,":[]{}~^")
-LPAR,RPAR = map(pp.Suppress,"()")
+COLON, LBRACK, RBRACK, LBRACE, RBRACE, TILDE, CARAT = map(pp.Literal, ":[]{}~^")
+LPAR, RPAR = map(pp.Suppress, "()")
and_, or_, not_, to_ = map(pp.CaselessKeyword, "AND OR NOT TO".split())
keyword = and_ | or_ | not_ | to_
expression = pp.Forward()
-valid_word = pp.Regex(r'([a-zA-Z0-9*_+.-]|\\\\|\\([+\-!(){}\[\]^"~*?:]|\|\||&&))+').setName("word")
+valid_word = pp.Regex(
+ r'([a-zA-Z0-9*_+.-]|\\\\|\\([+\-!(){}\[\]^"~*?:]|\|\||&&))+'
+).setName("word")
valid_word.setParseAction(
- lambda t : t[0].replace('\\\\',chr(127)).replace('\\','').replace(chr(127),'\\')
- )
+ lambda t: t[0].replace("\\\\", chr(127)).replace("\\", "").replace(chr(127), "\\")
+)
string = pp.QuotedString('"')
@@ -37,24 +40,28 @@ field_name = valid_word().setName("fieldname")
incl_range_search = pp.Group(LBRACK - term("lower") + to_ + term("upper") + RBRACK)
excl_range_search = pp.Group(LBRACE - term("lower") + to_ + term("upper") + RBRACE)
range_search = incl_range_search("incl_range") | excl_range_search("excl_range")
-boost = (CARAT - number("boost"))
+boost = CARAT - number("boost")
string_expr = pp.Group(string + proximity_modifier) | string
word_expr = pp.Group(valid_word + fuzzy_modifier) | valid_word
-term << (pp.Optional(field_name("field") + COLON)
- + (word_expr | string_expr | range_search | pp.Group(LPAR + expression + RPAR))
- + pp.Optional(boost))
-term.setParseAction(lambda t:[t] if 'field' in t or 'boost' in t else None)
+term << (
+ pp.Optional(field_name("field") + COLON)
+ + (word_expr | string_expr | range_search | pp.Group(LPAR + expression + RPAR))
+ + pp.Optional(boost)
+)
+term.setParseAction(lambda t: [t] if "field" in t or "boost" in t else None)
-expression << pp.infixNotation(term,
+expression << pp.infixNotation(
+ term,
[
- (required_modifier | prohibit_modifier, 1, pp.opAssoc.RIGHT),
- ((not_ | '!').setParseAction(lambda: "NOT"), 1, pp.opAssoc.RIGHT),
- ((and_ | '&&').setParseAction(lambda: "AND"), 2, pp.opAssoc.LEFT),
- (pp.Optional(or_ | '||').setParseAction(lambda: "OR"), 2, pp.opAssoc.LEFT),
- ])
+ (required_modifier | prohibit_modifier, 1, pp.opAssoc.RIGHT),
+ ((not_ | "!").setParseAction(lambda: "NOT"), 1, pp.opAssoc.RIGHT),
+ ((and_ | "&&").setParseAction(lambda: "AND"), 2, pp.opAssoc.LEFT),
+ (pp.Optional(or_ | "||").setParseAction(lambda: "OR"), 2, pp.opAssoc.LEFT),
+ ],
+)
-if __name__ == '__main__':
+if __name__ == "__main__":
# test strings taken from grammar description doc, and TestQueryParser.java
tests = r"""
@@ -329,4 +336,5 @@ if __name__ == '__main__':
if not (success1 and success2):
import sys
+
sys.exit(1)
diff --git a/examples/macroExpander.py b/examples/macroExpander.py
index c6b7034..3b06250 100644
--- a/examples/macroExpander.py
+++ b/examples/macroExpander.py
@@ -16,7 +16,7 @@ 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+"_")
+identifier = Word(alphas + "_", alphanums + "_")
macroDef = "#def" + identifier("macro") + empty + restOfLine("value")
# define a placeholder for defined macros - initially nothing
@@ -27,16 +27,18 @@ macroExpr << NoMatch()
macros = {}
# parse action for macro definitions
-def processMacroDefn(s,l,t):
+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):
+def processMacroRef(s, l, t):
return macros[t[0]]
+
# attach parse actions to expressions
macroExpr.setParseAction(processMacroRef)
macroDef.setParseAction(processMacroDefn)
@@ -45,7 +47,6 @@ macroDef.setParseAction(processMacroDefn)
macroExpander = macroExpr | macroDef
-
# test macro substitution using transformString
testString = """
#def A 100
diff --git a/examples/matchPreviousDemo.py b/examples/matchPreviousDemo.py
index 34991f8..caa76e1 100644
--- a/examples/matchPreviousDemo.py
+++ b/examples/matchPreviousDemo.py
@@ -23,7 +23,7 @@ identifier = Word(alphas)
classIdent = identifier("classname") # note that this also makes a copy of identifier
classHead = "class" + classIdent
classBody = "..."
-classEnd = "end" + matchPreviousLiteral(classIdent) + ';'
+classEnd = "end" + matchPreviousLiteral(classIdent) + ";"
classDefn = classHead + classBody + classEnd
# use this form to catch syntax error
diff --git a/examples/mozillaCalendarParser.py b/examples/mozillaCalendarParser.py
index 2633eb8..5000cfe 100644
--- a/examples/mozillaCalendarParser.py
+++ b/examples/mozillaCalendarParser.py
@@ -1,4 +1,13 @@
-from pyparsing import Optional, oneOf, Literal, Word, printables, Group, OneOrMore, ZeroOrMore
+from pyparsing import (
+ Optional,
+ oneOf,
+ Literal,
+ Word,
+ printables,
+ Group,
+ OneOrMore,
+ ZeroOrMore,
+)
"""
A simple parser for calendar (*.ics) files,
@@ -14,68 +23,73 @@ License: Free for any use
# TERMINALS
-BEGIN = Literal("BEGIN:").suppress()
-END = Literal("END:").suppress()
-valstr = printables + "\xe4\xf6\xe5\xd6\xc4\xc5 "
+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()
+EQ = Literal("=").suppress()
+SEMI = Literal(";").suppress()
+COLON = Literal(":").suppress()
-EVENT = Literal("VEVENT").suppress()
-CALENDAR = Literal("VCALENDAR").suppress()
-ALARM = Literal("VALARM").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 \
+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")
+ UID DTSTAMP LAST-MODIFIED X RRULE EXDATE"
+)
-propval = Word(valstr)
-typeval = Word(valstr)
-typename = oneOf("VALUE MEMBER FREQ UNTIL INTERVAL")
+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") \
-
+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)
+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())
+
+def gotEvent(s, loc, toks):
+ for event in toks:
+ print(event.dump())
+
event.setParseAction(gotEvent)
# MAIN PROGRAM
-if __name__=="__main__":
+if __name__ == "__main__":
- calendars.parseFile("mozilla.ics")
+ calendars.parseFile("mozilla.ics")
diff --git a/examples/nested.py b/examples/nested.py
index 218c10b..c696b48 100644
--- a/examples/nested.py
+++ b/examples/nested.py
@@ -21,8 +21,8 @@ data = """
# use {}'s for nested lists
nestedItems = nestedExpr("{", "}")
-print( (nestedItems+stringEnd).parseString(data).asList() )
+print((nestedItems + stringEnd).parseString(data).asList())
# use default delimiters of ()'s
mathExpr = nestedExpr()
-print( mathExpr.parseString( "((( ax + by)*C) *(Z | (E^F) & D))") )
+print(mathExpr.parseString("((( ax + by)*C) *(Z | (E^F) & D))"))
diff --git a/examples/nested_markup.py b/examples/nested_markup.py
index 6d83636..3e3aafa 100644
--- a/examples/nested_markup.py
+++ b/examples/nested_markup.py
@@ -12,27 +12,34 @@ wiki_markup = pp.Forward()
# a method that will construct and return a parse action that will
# do the proper wrapping in opening and closing HTML, and recursively call
# wiki_markup.transformString on the markup body text
-def convert_markup_to_html(opening,closing):
+def convert_markup_to_html(opening, closing):
def conversionParseAction(s, l, t):
return opening + wiki_markup.transformString(t[1][1:-1]) + closing
+
return conversionParseAction
+
# use a nestedExpr with originalTextFor to parse nested braces, but return the
# parsed text as a single string containing the outermost nested braces instead
# of a nested list of parsed tokens
-markup_body = pp.originalTextFor(pp.nestedExpr('{', '}'))
-italicized = ('ital' + markup_body).setParseAction(convert_markup_to_html("<I>", "</I>"))
-bolded = ('bold' + markup_body).setParseAction(convert_markup_to_html("<B>", "</B>"))
+markup_body = pp.originalTextFor(pp.nestedExpr("{", "}"))
+italicized = ("ital" + markup_body).setParseAction(
+ convert_markup_to_html("<I>", "</I>")
+)
+bolded = ("bold" + markup_body).setParseAction(convert_markup_to_html("<B>", "</B>"))
# another markup and parse action to parse links - again using transform string
# to recursively parse any markup in the link text
def convert_link_to_html(s, l, t):
link_text, url = t._skipped
- t['link_text'] = wiki_markup.transformString(link_text)
- t['url'] = url
+ t["link_text"] = wiki_markup.transformString(link_text)
+ t["url"] = url
return '<A href="{url}">{link_text}</A>'.format_map(t)
-urlRef = (pp.Keyword('link') + '{' + ... + '->' + ... + '}').setParseAction(convert_link_to_html)
+
+urlRef = (pp.Keyword("link") + "{" + ... + "->" + ... + "}").setParseAction(
+ convert_link_to_html
+)
# now inject all the markup bits as possible markup expressions
wiki_markup <<= urlRef | italicized | bolded
diff --git a/examples/numerics.py b/examples/numerics.py
index 0af3cae..3a1f9e9 100644
--- a/examples/numerics.py
+++ b/examples/numerics.py
@@ -48,15 +48,19 @@ tests = """\
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(',','.')))
+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(',','')))
+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 = Regex(r"\d{1,2}(([ .,])\d\d\d(\2\d\d\d)*)?")
+grouped_integer.setParseAction(
+ lambda t: int(t[0].replace(" ", "").replace(",", "").replace(".", ""))
+)
grouped_integer.runTests(tests, parseAll=False)
diff --git a/examples/oc.py b/examples/oc.py
index c8b95b1..f19a2b0 100644
--- a/examples/oc.py
+++ b/examples/oc.py
@@ -71,13 +71,15 @@ The following is a description of the OC grammar:
"""
from pyparsing import *
+
ParserElement.enablePackrat()
-LPAR,RPAR,LBRACK,RBRACK,LBRACE,RBRACE,SEMI,COMMA = map(Suppress, "()[]{};,")
-INT, CHAR, WHILE, DO, IF, ELSE, RETURN = map(Keyword,
- "int char while do if else return".split())
+LPAR, RPAR, LBRACK, RBRACK, LBRACE, RBRACE, SEMI, COMMA = map(Suppress, "()[]{};,")
+INT, CHAR, WHILE, DO, IF, ELSE, RETURN = map(
+ Keyword, "int char while do if else return".split()
+)
-NAME = Word(alphas+"_", alphanums+"_")
+NAME = Word(alphas + "_", alphanums + "_")
integer = Regex(r"[+-]?\d+")
char = Regex(r"'.'")
string_ = dblQuotedString
@@ -86,19 +88,20 @@ TYPE = Group((INT | CHAR) + ZeroOrMore("*"))
expr = Forward()
func_call = Group(NAME + LPAR + Group(Optional(delimitedList(expr))) + RPAR)
operand = func_call | NAME | integer | char | string_
-expr <<= (infixNotation(operand,
+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 )
- )
+ (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()
@@ -107,34 +110,46 @@ 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)
+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)
+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()):
+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()
+# ~ for vname in "fundecl stmt".split():
+# ~ v = vars()[vname]
+# ~ v.setDebug()
test = r"""
/* A factorial program */
diff --git a/examples/parseListString.py b/examples/parseListString.py
index d5723b0..f34f614 100644
--- a/examples/parseListString.py
+++ b/examples/parseListString.py
@@ -9,8 +9,9 @@ from pyparsing import *
lbrack = Literal("[")
rbrack = Literal("]")
integer = Word(nums).setName("integer")
-real = Combine(Optional(oneOf("+ -")) + Word(nums) + "." +
- Optional(Word(nums))).setName("real")
+real = Combine(
+ Optional(oneOf("+ -")) + Word(nums) + "." + Optional(Word(nums))
+).setName("real")
listItem = real | integer | quotedString
@@ -24,11 +25,11 @@ 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 )
+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
@@ -37,46 +38,75 @@ 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])
+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 )
+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()) )
+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])
+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 )
+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)
+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: {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,],}]'
+dictStr <<= (
+ lbrace
+ + Optional(delimitedList(Group(dictKeyStr + colon + listItem)))
+ + Optional(Suppress(","))
+ + rbrace
+)
+dictStr.setParseAction(
+ lambda t: {
+ k_v[0]: (k_v[1].asList() if isinstance(k_v[1], ParseResults) else k_v[1])
+ for k_v in t
+ }
+)
+
+test = "[{0: [2], 1: []}, {0: [], 1: [], 2: [,]}, {0: [1, 2,],}]"
print(listStr.parseString(test))
diff --git a/examples/parsePythonValue.py b/examples/parsePythonValue.py
index 259473f..6a75d48 100644
--- a/examples/parsePythonValue.py
+++ b/examples/parsePythonValue.py
@@ -5,52 +5,55 @@
import pyparsing as pp
-cvtBool = lambda t:t[0]=='True'
+cvtBool = lambda t: t[0] == "True"
cvtInt = lambda toks: int(toks[0])
cvtReal = lambda toks: float(toks[0])
-cvtTuple = lambda toks : tuple(toks.asList())
+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, comma = map(pp.Suppress,"()[]{}:,")
+lparen, rparen, lbrack, rbrack, lbrace, rbrace, colon, comma = map(
+ pp.Suppress, "()[]{}:,"
+)
-integer = pp.Regex(r"[+-]?\d+").setName("integer").setParseAction(cvtInt )
+integer = pp.Regex(r"[+-]?\d+").setName("integer").setParseAction(cvtInt)
real = pp.Regex(r"[+-]?\d+\.\d*([Ee][+-]?\d+)?").setName("real").setParseAction(cvtReal)
tupleStr = pp.Forward()
listStr = pp.Forward()
dictStr = pp.Forward()
-pp.unicodeString.setParseAction(lambda t:t[0][2:-1])
-pp.quotedString.setParseAction(lambda t:t[0][1:-1])
+pp.unicodeString.setParseAction(lambda t: t[0][2:-1])
+pp.quotedString.setParseAction(lambda t: t[0][1:-1])
boolLiteral = pp.oneOf("True False").setParseAction(cvtBool)
noneLiteral = pp.Literal("None").setParseAction(pp.replaceWith(None))
-listItem = (real
- | integer
- | pp.quotedString
- | pp.unicodeString
- | boolLiteral
- | noneLiteral
- | pp.Group(listStr)
- | tupleStr
- | dictStr)
+listItem = (
+ real
+ | integer
+ | pp.quotedString
+ | pp.unicodeString
+ | boolLiteral
+ | noneLiteral
+ | pp.Group(listStr)
+ | tupleStr
+ | dictStr
+)
-tupleStr << (lparen
- + pp.Optional(pp.delimitedList(listItem))
- + pp.Optional(comma)
- + rparen)
+tupleStr << (
+ lparen + pp.Optional(pp.delimitedList(listItem)) + pp.Optional(comma) + rparen
+)
tupleStr.setParseAction(cvtTuple)
-listStr << (lbrack
- + pp.Optional(pp.delimitedList(listItem) + pp.Optional(comma))
- + rbrack)
+listStr << (
+ lbrack + pp.Optional(pp.delimitedList(listItem) + pp.Optional(comma)) + rbrack
+)
listStr.setParseAction(cvtList, lambda t: t[0])
dictEntry = pp.Group(listItem + colon + listItem)
-dictStr << (lbrace
- + pp.Optional(pp.delimitedList(dictEntry) + pp.Optional(comma))
- + rbrace)
+dictStr << (
+ lbrace + pp.Optional(pp.delimitedList(dictEntry) + pp.Optional(comma)) + rbrace
+)
dictStr.setParseAction(cvtDict)
tests = """['a', 100, ('A', [101,102]), 3.14, [ +2.718, 'xyzzy', -1.414] ]
diff --git a/examples/parseResultsSumExample.py b/examples/parseResultsSumExample.py
index 2c0f9fc..2341b7c 100644
--- a/examples/parseResultsSumExample.py
+++ b/examples/parseResultsSumExample.py
@@ -10,13 +10,19 @@ 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")
+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,):
+for test in (
+ samplestr1,
+ samplestr2,
+ samplestr3,
+ samplestr4,
+):
person = sum(person_data.searchString(test))
print(person.id)
print(person.dump())
diff --git a/examples/parseTabularData.py b/examples/parseTabularData.py
index da19033..3c898e0 100644
--- a/examples/parseTabularData.py
+++ b/examples/parseTabularData.py
@@ -7,7 +7,7 @@
#
# Copyright 2015, Paul McGuire
#
-from pyparsing import col,Word,Optional,alphas,nums
+from pyparsing import col, Word, Optional, alphas, nums
table = """\
1 2
@@ -19,32 +19,41 @@ 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
+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)
+ 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"))
+ 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"))
+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('')
+ print("")
diff --git a/examples/partial_gene_match.py b/examples/partial_gene_match.py
index e4c59af..fe62e77 100644
--- a/examples/partial_gene_match.py
+++ b/examples/partial_gene_match.py
@@ -17,12 +17,19 @@ Sample header:
>NC_001799-6-2978-2778 | organism=Toxoplasma_gondii_RH | location=NC_001799:2778-2978(-) | length=201
"""
integer = pp.pyparsing_common.integer
-genebit = pp.Group(">" + pp.Word(pp.alphanums.upper() + "-_")("gene_id")
- + "|" + pp.Word(pp.printables)("organism")
- + "|" + pp.Word(pp.printables)("location")
- + "|" + "length=" + integer("gene_len")
- + pp.LineEnd()
- + pp.Word("ACGTN")[1, ...].addParseAction(''.join)("gene"))
+genebit = pp.Group(
+ ">"
+ + pp.Word(pp.alphanums.upper() + "-_")("gene_id")
+ + "|"
+ + pp.Word(pp.printables)("organism")
+ + "|"
+ + pp.Word(pp.printables)("location")
+ + "|"
+ + "length="
+ + integer("gene_len")
+ + pp.LineEnd()
+ + pp.Word("ACGTN")[1, ...].addParseAction("".join)("gene")
+)
# read gene data from .fasta file - takes just a few seconds
# An important aspect of this parsing process is the reassembly of all the separate lines of the
@@ -45,12 +52,17 @@ for g in genedata:
show_header = False
matched = t[0]
- mismatches = t['mismatches']
+ mismatches = t["mismatches"]
print("MATCH:", searchseq.match_string)
print("FOUND:", matched)
if mismatches:
- print(" ", ''.join('*' if i in mismatches else ' '
- for i, c in enumerate(searchseq.match_string)))
+ print(
+ " ",
+ "".join(
+ "*" if i in mismatches else " "
+ for i, c in enumerate(searchseq.match_string)
+ ),
+ )
else:
print("<exact match>")
print("at location", startLoc)
diff --git a/examples/pgn.py b/examples/pgn.py
index fc19c98..d9889d6 100644
--- a/examples/pgn.py
+++ b/examples/pgn.py
@@ -10,7 +10,18 @@
# 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, Word
+from pyparsing import (
+ Combine,
+ Forward,
+ Group,
+ Literal,
+ oneOf,
+ OneOrMore,
+ Optional,
+ Suppress,
+ ZeroOrMore,
+ Word,
+)
from pyparsing import ParseException
#
@@ -30,14 +41,14 @@ 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
+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("#")
@@ -46,8 +57,11 @@ 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)
+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...
@@ -56,19 +70,23 @@ 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))
+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)
-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 = """
+ # input string
+ pgn = """
[Event "ICC 5 0 u"]
[Site "Internet Chess Club"]
[Date "2004.01.25"]
@@ -89,6 +107,6 @@ 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())
+ # parse input string
+ tokens = parsePGN(pgn, pgnGrammar)
+ print(tokens.dump())
diff --git a/examples/position.py b/examples/position.py
index d88c14a..a6f03b9 100644
--- a/examples/position.py
+++ b/examples/position.py
@@ -11,7 +11,7 @@ mollit anim id est laborum"""
# find all words beginning with a vowel
vowels = "aeiouAEIOU"
-initialVowelWord = Word(vowels,alphas)
+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
@@ -20,34 +20,38 @@ initialVowelWord = Word(vowels,alphas)
# 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)
+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):
+for t, start, end in (initialConsWord | initialVowelWord).scanString(text):
if t:
- print(start,':', t[0])
+ 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]
+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)
+ 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))
+ 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)
+ print(ivowelInfo.locn, ":", ivowelInfo.word)
diff --git a/examples/protobuf_parser.py b/examples/protobuf_parser.py
index ae5b5d3..afc8296 100644
--- a/examples/protobuf_parser.py
+++ b/examples/protobuf_parser.py
@@ -5,14 +5,27 @@
# Copyright 2010, Paul McGuire
#
-from pyparsing import (Word, alphas, alphanums, Regex, Suppress, Forward,
- Group, oneOf, ZeroOrMore, Optional, delimitedList,
- restOfLine, quotedString, Dict)
-
-ident = Word(alphas+"_",alphanums+"_").setName("identifier")
+from pyparsing import (
+ Word,
+ alphas,
+ alphanums,
+ Regex,
+ Suppress,
+ Forward,
+ Group,
+ oneOf,
+ ZeroOrMore,
+ Optional,
+ delimitedList,
+ restOfLine,
+ quotedString,
+ Dict,
+)
+
+ident = Word(alphas + "_", alphanums + "_").setName("identifier")
integer = Regex(r"[+-]?\d+")
-LBRACE,RBRACE,LBRACK,RBRACK,LPAR,RPAR,EQ,SEMI = map(Suppress,"{}[]()=;")
+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 syntax"""
@@ -23,15 +36,34 @@ 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
+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
-fieldDefnPrefix = REQUIRED_ | OPTIONAL_ | REPEATED_
-fieldDefn = (Optional(fieldDefnPrefix) + typespec("typespec") + ident("ident") + EQ + integer("fieldint") + ZeroOrMore(fieldDirective) + SEMI)
+fieldDefnPrefix = REQUIRED_ | OPTIONAL_ | REPEATED_
+fieldDefn = (
+ Optional(fieldDefnPrefix)
+ + 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
+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
@@ -40,28 +72,52 @@ extensionsDefn = EXTENSIONS_ - integer + TO_ + integer + SEMI
messageExtension = EXTEND_ - ident + LBRACE + messageBody + RBRACE
# messageBody ::= { fieldDefn | enumDefn | messageDefn | extensionsDefn | messageExtension }*
-messageBody << Group(ZeroOrMore( Group(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)
+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
+serviceDefn = (
+ SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(methodDefn)) + RBRACE
+)
syntaxDefn = SYNTAX_ + EQ - quotedString("syntaxString") + SEMI
# packageDirective ::= 'package' ident [ '.' ident]* ';'
-packageDirective = Group(PACKAGE_ - delimitedList(ident, '.', combine=True) + SEMI)
+packageDirective = Group(PACKAGE_ - delimitedList(ident, ".", combine=True) + SEMI)
-comment = '//' + restOfLine
+comment = "//" + restOfLine
importDirective = IMPORT_ - quotedString("importFileSpec") + SEMI
-optionDirective = OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI
-
-topLevelStatement = Group(messageDefn | messageExtension | enumDefn | serviceDefn | importDirective | optionDirective | syntaxDefn)
+optionDirective = (
+ OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI
+)
+
+topLevelStatement = Group(
+ messageDefn
+ | messageExtension
+ | enumDefn
+ | serviceDefn
+ | importDirective
+ | optionDirective
+ | syntaxDefn
+)
parser = Optional(packageDirective) + ZeroOrMore(topLevelStatement)
diff --git a/examples/pymicko.py b/examples/pymicko.py
index eddfdd3..a5512ea 100644
--- a/examples/pymicko.py
+++ b/examples/pymicko.py
@@ -20,7 +20,7 @@
from pyparsing import *
from sys import stdin, argv, exit
-#defines debug level
+# defines debug level
# 0 - no debug
# 1 - print parsing results
# 2 - print parsing results and symbol table
@@ -204,56 +204,63 @@ DEBUG = 0
##########################################################################################
##########################################################################################
+
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:
"""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
+ # 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
+ # bit size of variables
TYPE_BIT_SIZE = 16
- #min/max values of constants
- MIN_INT = -2 ** (TYPE_BIT_SIZE - 1)
+ # 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!)
+ # 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
+ # register for function's return value
FUNCTION_REGISTER = len(REGISTERS) - 1
- #the index of last working register
+ # the index of last working register
LAST_WORKING_REGISTER = len(REGISTERS) - 2
- #list of relational operators
+ # list of relational operators
RELATIONAL_OPERATORS = "< > <= >= == !=".split()
def __init__(self):
- #index of the currently parsed function
+ # index of the currently parsed function
self.functon_index = 0
- #name of the currently parsed function
+ # name of the currently parsed function
self.functon_name = 0
- #number of parameters of the currently parsed function
+ # number of parameters of the currently parsed function
self.function_params = 0
- #number of local variables of the currently parsed function
+ # number of local variables of the currently parsed function
self.function_vars = 0
+
##########################################################################################
##########################################################################################
+
class ExceptionSharedData:
"""Class for exception handling data"""
def __init__(self):
- #position in currently parsed text
+ # position in currently parsed text
self.location = 0
- #currently parsed text
+ # currently parsed text
self.text = ""
def setpos(self, location, text):
@@ -261,8 +268,10 @@ class ExceptionSharedData:
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
@@ -283,8 +292,10 @@ class SemanticException(Exception):
def _get_message(self):
return self._message
+
def _set_message(self, message):
self._message = message
+
message = property(_get_message, _set_message)
def __str__(self):
@@ -297,13 +308,15 @@ class SemanticException(Exception):
msg += "\n%s" % self.text
return msg
+
##########################################################################################
##########################################################################################
+
class SymbolTableEntry:
"""Class which represents one symbol table entry."""
- def __init__(self, sname = "", skind = 0, stype = 0, sattr = None, sattr_name = "None"):
+ def __init__(self, sname="", skind=0, stype=0, sattr=None, sattr_name="None"):
"""Initialization of symbol table entry.
sname - symbol name
skind - symbol kind
@@ -325,7 +338,12 @@ class SymbolTableEntry:
def attribute_str(self):
"""Returns attribute string (used only for table display)"""
- return "{}={}".format(self.attribute_name, self.attribute) if self.attribute != None else "None"
+ return (
+ "{}={}".format(self.attribute_name, self.attribute)
+ if self.attribute != None
+ else "None"
+ )
+
class SymbolTable:
"""Class for symbol table of microC program"""
@@ -334,10 +352,14 @@ class SymbolTable:
"""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
+ # 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=""):
@@ -351,27 +373,60 @@ class SymbolTable:
def display(self):
"""Displays the symbol table content"""
- #Finding the maximum length for each column
+ # 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))
+ 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))
+ 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))
+ 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):
+ 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 = "{}".format(SharedData.TYPES[p])
else:
parameters += ", {}".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))
+ 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.
@@ -382,7 +437,7 @@ class SymbolTable:
"""
self.table.append(SymbolTableEntry(sname, skind, stype))
self.table_len = len(self.table)
- return self.table_len-1
+ return self.table_len - 1
def clear_symbols(self, index):
"""Clears all symbols begining with the index to the end of table"""
@@ -392,7 +447,12 @@ class SymbolTable:
self.error()
self.table_len = len(self.table)
- def lookup_symbol(self, sname, skind=list(SharedData.KINDS.keys()), stype=list(SharedData.TYPES.keys())):
+ 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
@@ -401,7 +461,10 @@ class SymbolTable:
"""
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)]:
+ 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
@@ -423,26 +486,43 @@ class SymbolTable:
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)
+ 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)
+ 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
+ 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
+ # 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)
+ 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):
@@ -454,17 +534,25 @@ class SymbolTable:
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)
+ 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)
+ 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
+ same = (
+ self.table[index1].type
+ == self.table[index2].type
+ != SharedData.TYPES.NO_TYPE
+ )
except Exception:
self.error()
return same
@@ -476,7 +564,10 @@ class SymbolTable:
argument_number - # of function's argument
"""
try:
- same = self.table[function_index].param_types[argument_number] == self.table[index].type
+ same = (
+ self.table[function_index].param_types[argument_number]
+ == self.table[index].type
+ )
except Exception:
self.error()
return same
@@ -517,45 +608,75 @@ class SymbolTable:
except Exception:
self.error()
+
##########################################################################################
##########################################################################################
+
class CodeGenerator:
"""Class for code generation methods."""
- #dictionary of relational operators
- RELATIONAL_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
+ # dictionary of relational operators
+ RELATIONAL_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
+ # text at start of code segment
CODE_START_TEXT = "#CODE"
def __init__(self, shared, symtab):
- #generated code
+ # generated code
self.code = ""
- #prefix for internal labels
+ # prefix for internal labels
self.internal = "@"
- #suffix for label definition
+ # suffix for label definition
self.definition = ":"
- #list of free working registers
+ # list of free working registers
self.free_registers = list(range(SharedData.FUNCTION_REGISTER, -1, -1))
- #list of used working registers
+ # list of used working registers
self.used_registers = []
- #list of used registers needed when function call is inside of a function call
+ # list of used registers needed when function call is inside of a function call
self.used_registers_stack = []
- #shared data
+ # shared data
self.shared = shared
- #symbol table
+ # symbol table
self.symtab = symtab
def error(self, text):
@@ -564,7 +685,7 @@ class CodeGenerator:
"""
raise Exception("Compiler error: %s" % text)
- def take_register(self, rtype = SharedData.TYPES.NO_TYPE):
+ 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")
@@ -573,7 +694,7 @@ class CodeGenerator:
self.symtab.set_type(reg, rtype)
return reg
- def take_function_register(self, rtype = SharedData.TYPES.NO_TYPE):
+ 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:
@@ -589,7 +710,7 @@ class CodeGenerator:
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)
+ 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)"""
@@ -604,20 +725,24 @@ class CodeGenerator:
internal - boolean value, adds "@" prefix to label
definition - boolean value, adds ":" suffix to label
"""
- return "{}{}{}".format(self.internal if internal else "", name, self.definition if definition else "")
+ return "{}{}{}".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 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
+ # local variables are located at negative offset from frame pointer register
if sym.kind == SharedData.KINDS.LOCAL_VAR:
return "-{}(1:%14)".format(sym.attribute * 4 + 4)
- #parameters are located at positive offset from frame pointer register
+ # parameters are located at positive offset from frame pointer register
elif sym.kind == SharedData.KINDS.PARAMETER:
return "{}(1:%14)".format(8 + sym.attribute * 4)
elif sym.kind == SharedData.KINDS.CONSTANT:
@@ -634,13 +759,13 @@ class CodeGenerator:
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)
+ 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)
+ used.sort(reverse=True)
for reg in used:
self.newline_text("POP \t%s" % SharedData.REGISTERS[reg], True)
self.free_registers.remove(reg)
@@ -663,7 +788,7 @@ class CodeGenerator:
if indent:
self.text("\t\t\t")
- def newline_text(self, text, indent = False):
+ def newline_text(self, text, indent=False):
"""Inserts a newline and text, optionally with indentation (helper function)"""
self.newline(indent)
self.text(text)
@@ -674,7 +799,13 @@ class CodeGenerator:
internal - boolean value, adds "@" prefix to label
definition - boolean value, adds ":" suffix to label
"""
- self.newline_text(self.label("{}{}{}".format("@" if internal else "", name, ":" if definition else "")))
+ self.newline_text(
+ self.label(
+ "{}{}{}".format(
+ "@" if internal else "", name, ":" if definition else ""
+ )
+ )
+ )
def global_var(self, name):
"""Inserts a new static (global) variable definition"""
@@ -685,7 +816,7 @@ class CodeGenerator:
"""Generates an arithmetic instruction mnemonic"""
return self.OPERATIONS[op_name] + self.OPSIGNS[op_type]
- def arithmetic(self, operation, operand1, operand2, operand3 = None):
+ 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
@@ -697,14 +828,26 @@ class CodeGenerator:
else:
output_type = None
if isinstance(operand2, int):
- output_type = self.symtab.get_type(operand2) if output_type == None else output_type
+ 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_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("{}\t{},{},{}".format(mnemonic, self.symbol(operand1), self.symbol(operand2), self.symbol(output)), True)
+ self.newline_text(
+ "{}\t{},{},{}".format(
+ mnemonic,
+ self.symbol(operand1),
+ self.symbol(operand2),
+ self.symbol(output),
+ ),
+ True,
+ )
return output
def relop_code(self, relop, operands_type):
@@ -713,7 +856,11 @@ class CodeGenerator:
operands_type - int or unsigned
"""
code = self.RELATIONAL_DICT[relop]
- offset = 0 if operands_type == SharedData.TYPES.INT else len(SharedData.RELATIONAL_OPERATORS)
+ offset = (
+ 0
+ if operands_type == SharedData.TYPES.INT
+ else len(SharedData.RELATIONAL_OPERATORS)
+ )
return code + offset
def jump(self, relcode, opposite, label):
@@ -722,7 +869,11 @@ class CodeGenerator:
opposite - generate normal or opposite jump
label - jump label
"""
- jump = self.OPPOSITE_JUMPS[relcode] if opposite else self.CONDITIONAL_JUMPS[relcode]
+ jump = (
+ self.OPPOSITE_JUMPS[relcode]
+ if opposite
+ else self.CONDITIONAL_JUMPS[relcode]
+ )
self.newline_text("{}\t{}".format(jump, label), True)
def unconditional_jump(self, label):
@@ -731,7 +882,7 @@ class CodeGenerator:
"""
self.newline_text("JMP \t{}".format(label), True)
- def move(self,operand1, operand2):
+ 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
@@ -741,7 +892,9 @@ class CodeGenerator:
self.free_if_register(operand1)
else:
output_type = SharedData.TYPES.NO_TYPE
- self.newline_text("MOV \t{},{}".format(self.symbol(operand1), self.symbol(operand2)), True)
+ self.newline_text(
+ "MOV \t{},{}".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)
@@ -761,7 +914,12 @@ class CodeGenerator:
typ = self.symtab.get_type(operand1)
self.free_if_register(operand1)
self.free_if_register(operand2)
- self.newline_text("CMP{}\t{},{}".format(self.OPSIGNS[typ], self.symbol(operand1), self.symbol(operand2)), True)
+ self.newline_text(
+ "CMP{}\t{},{}".format(
+ self.OPSIGNS[typ], self.symbol(operand1), self.symbol(operand2)
+ ),
+ True,
+ )
def function_begin(self):
"""Inserts function name label and function frame initialization"""
@@ -772,7 +930,9 @@ class CodeGenerator:
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)
+ 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)
@@ -788,128 +948,204 @@ class CodeGenerator:
function - function index in symbol table
arguments - list of arguments (indexes in symbol table)
"""
- #push each argument to stack
+ # 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)
+ self.newline_text("CALL\t" + self.symtab.get_name(function), True)
args = self.symtab.get_attribute(function)
- #generates stack cleanup if function has arguments
+ # generates stack cleanup if function has arguments
if args > 0:
- args_space = self.symtab.insert_constant("{}".format(args * 4), SharedData.TYPES.UNSIGNED)
+ args_space = self.symtab.insert_constant(
+ "{}".format(args * 4), SharedData.TYPES.UNSIGNED
+ )
self.arithmetic("+", "%15", args_space, "%15")
+
##########################################################################################
##########################################################################################
+
class MicroC:
"""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)
+ # 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)
+ # 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
+ # 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.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.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.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.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.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.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.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.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
+ # symbol table
self.symtab = SymbolTable(self.shared)
- #code generator
+ # code generator
self.codegen = CodeGenerator(self.shared, self.symtab)
- #index of the current function call
+ # index of the current function call
self.function_call_index = -1
- #stack for the nested function calls
+ # stack for the nested function calls
self.function_call_stack = []
- #arguments of the current function call
+ # arguments of the current function call
self.function_arguments = []
- #stack for arguments of the nested function calls
+ # stack for arguments of the nested function calls
self.function_arguments_stack = []
- #number of arguments for the curent function call
+ # number of arguments for the curent function call
self.function_arguments_number = -1
- #stack for the number of arguments for the nested function calls
+ # stack for the number of arguments for the nested function calls
self.function_arguments_number_stack = []
- #last relational expression
+ # last relational expression
self.relexp_code = None
- #last and expression
+ # last and expression
self.andexp_code = None
- #label number for "false" internal labels
+ # label number for "false" internal labels
self.false_label_number = -1
- #label number for all other internal labels
+ # label number for all other internal labels
self.label_number = None
- #label stack for nested statements
+ # label stack for nested statements
self.label_stack = []
def warning(self, message, print_location=True):
@@ -925,7 +1161,6 @@ class MicroC:
msg += "\n%s" % wtext
print(msg)
-
def data_begin_action(self):
"""Inserts text at start of data segment"""
self.codegen.prepare_data_segment()
@@ -938,9 +1173,11 @@ class MicroC:
"""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
+ 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
@@ -949,10 +1186,14 @@ class MicroC:
"""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)
+ 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
@@ -960,9 +1201,11 @@ class MicroC:
"""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
+ 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
@@ -971,42 +1214,52 @@ class MicroC:
"""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
+ 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
+ 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();
+ 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
+ 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)
+ 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()
@@ -1014,27 +1267,40 @@ class MicroC:
"""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
+ 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
+ # 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
+ # 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))
+ # 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])
+ 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
@@ -1043,10 +1309,19 @@ class MicroC:
"""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])
+ 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]):
@@ -1057,16 +1332,18 @@ class MicroC:
"""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
+ 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
+ # replace first calculation with it's result
m[0:3] = [reg]
return m[0]
@@ -1074,16 +1351,18 @@ class MicroC:
"""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
+ 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
+ # replace first calculation with it's result
n[0:3] = [reg]
return n[0]
@@ -1091,13 +1370,15 @@ class MicroC:
"""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
+ 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)
+ # 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[:])
@@ -1108,49 +1389,64 @@ class MicroC:
"""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
+ 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)))
+ # 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
+ 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
+ # 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
+ # 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
+ 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 '{}'".format(arg[1]))
self.codegen.compare(arg[0], arg[2])
- #return relational operator's code
+ # return relational operator's code
self.relexp_code = self.codegen.relop_code(arg[1], self.symtab.get_type(arg[0]))
return self.relexp_code
@@ -1158,10 +1454,14 @@ class MicroC:
"""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{}".format(self.false_label_number), True, False)
+ print("AND+EXP:", arg)
+ if DEBUG == 2:
+ self.symtab.display()
+ if DEBUG > 2:
+ return
+ label = self.codegen.label(
+ "false{}".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
@@ -1170,21 +1470,27 @@ class MicroC:
"""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
+ print("LOG_EXP:", arg)
+ if DEBUG == 2:
+ self.symtab.display()
+ if DEBUG > 2:
+ return
label = self.codegen.label("true{}".format(self.label_number), True, False)
self.codegen.jump(self.relexp_code, False, label)
- self.codegen.newline_label("false{}".format(self.false_label_number), True, True)
+ self.codegen.newline_label(
+ "false{}".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
+ 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{}".format(self.label_number), True, True)
@@ -1193,15 +1499,19 @@ class MicroC:
"""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{}".format(self.false_label_number), True, False)
+ 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{}".format(self.false_label_number), True, False
+ )
self.codegen.jump(self.relexp_code, True, label)
- #generate 'true' label (executes if condition is satisfied)
+ # generate 'true' label (executes if condition is satisfied)
self.codegen.newline_label("true{}".format(self.label_number), True, True)
- #save label numbers (needed for nested if/while statements)
+ # save label numbers (needed for nested if/while statements)
self.label_stack.append(self.false_label_number)
self.label_stack.append(self.label_number)
@@ -1209,14 +1519,16 @@ class MicroC:
"""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
+ 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{}".format(self.label_number), True, False)
self.codegen.unconditional_jump(label)
- #generate final 'false' label (executes if condition isn't satisfied)
+ # generate final 'false' label (executes if condition isn't satisfied)
self.codegen.newline_label("false{}".format(self.label_stack.pop()), True, True)
self.label_stack.append(self.label_number)
@@ -1224,18 +1536,22 @@ class MicroC:
"""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
+ print("IF_END:", arg)
+ if DEBUG == 2:
+ self.symtab.display()
+ if DEBUG > 2:
+ return
self.codegen.newline_label("exit{}".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
+ 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{}".format(self.label_number), True, True)
@@ -1244,13 +1560,17 @@ class MicroC:
"""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{}".format(self.false_label_number), True, False)
+ 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{}".format(self.false_label_number), True, False
+ )
self.codegen.jump(self.relexp_code, True, label)
- #generate 'true' label (executes if condition is satisfied)
+ # generate 'true' label (executes if condition is satisfied)
self.codegen.newline_label("true{}".format(self.label_number), True, True)
self.label_stack.append(self.false_label_number)
self.label_stack.append(self.label_number)
@@ -1259,14 +1579,16 @@ class MicroC:
"""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
+ 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{}".format(self.label_number), True, False)
self.codegen.unconditional_jump(label)
- #generate final 'false' label and exit label
+ # generate final 'false' label and exit label
self.codegen.newline_label("false{}".format(self.label_stack.pop()), True, True)
self.codegen.newline_label("exit{}".format(self.label_number), True, True)
@@ -1274,16 +1596,18 @@ class MicroC:
"""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)
+ 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):
+ def parse_text(self, text):
"""Parse string (helper function)"""
try:
return self.rProgram.ignore(cStyleComment).parseString(text, parseAll=True)
@@ -1294,10 +1618,12 @@ class MicroC:
print(err)
exit(3)
- def parse_file(self,filename):
+ def parse_file(self, filename):
"""Parse file (helper function)"""
try:
- return self.rProgram.ignore(cStyleComment).parseFile(filename, parseAll=True)
+ return self.rProgram.ignore(cStyleComment).parseFile(
+ filename, parseAll=True
+ )
except SemanticException as err:
print(err)
exit(3)
@@ -1305,10 +1631,11 @@ class MicroC:
print(err)
exit(3)
+
##########################################################################################
##########################################################################################
if 0:
- #main program
+ # main program
mc = MicroC()
output_file = "output.asm"
@@ -1322,19 +1649,21 @@ if 0:
else:
usage = """Usage: {} [input_file [output_file]]
If output file is omitted, output.asm is used
- If input file is omitted, stdin is used""".format(argv[0])
+ 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')
+ 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()
+ # if you want to see the final symbol table, uncomment next line
+ # mc.symtab.display()
try:
- out = open(output_file, 'w')
+ out = open(output_file, "w")
out.write(mc.codegen.code)
out.close
except Exception:
diff --git a/examples/pythonGrammarParser.py b/examples/pythonGrammarParser.py
index e3685a1..e9d7d94 100644
--- a/examples/pythonGrammarParser.py
+++ b/examples/pythonGrammarParser.py
@@ -130,35 +130,42 @@ testlist1: test (',' test)*
encoding_decl: NAME
"""
+
class SemanticGroup:
- def __init__(self,contents):
+ 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 "{}({})".format(self.label,
- " ".join([isinstance(c,str) and c or str(c) for c in self.contents]) )
+ return "{}({})".format(
+ 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):
+ def __init__(self, contents):
if len(contents) > 1:
self.rep = contents[1]
else:
self.rep = ""
- if isinstance(contents,str):
+ if isinstance(contents, str):
self.contents = contents
else:
self.contents = contents[0]
@@ -166,12 +173,14 @@ class Atom(SemanticGroup):
def __str__(self):
return "{}{}".format(self.rep, self.contents)
+
def makeGroupObject(cls):
- def groupAction(s,l,t):
+ def groupAction(s, l, t):
try:
return cls(t[0].asList())
except Exception:
return cls(t)
+
return groupAction
@@ -180,20 +189,27 @@ LPAREN = Suppress("(")
RPAREN = Suppress(")")
LBRACK = Suppress("[")
RBRACK = Suppress("]")
-COLON = Suppress(":")
+COLON = Suppress(":")
ALT_OP = Suppress("|")
# bnf grammar
-ident = Word(alphanums+"_")
-bnfToken = Word(alphanums+"_") + ~FollowedBy(":")
+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))
+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 )
+orList = Group(bnfFactor + OneOrMore(ALT_OP + bnfFactor)).setParseAction(
+ makeGroupObject(OrList)
+)
+bnfExpr << (orList | bnfFactor)
bnfLine = ident + COLON + bnfExpr
bnfComment = "#" + restOfLine
@@ -207,14 +223,16 @@ bnfDefs = bnf.parseString(grammar)
# correct answer is 78
expected = 78
-assert len(bnfDefs) == expected, \
- "Error, found %d BNF defns, expected %d" % (len(bnfDefs), expected)
+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)
+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])
+ print(k, "=", bnfDefs[k])
diff --git a/examples/rangeCheck.py b/examples/rangeCheck.py
index 66af545..2d1d2c8 100644
--- a/examples/rangeCheck.py
+++ b/examples/rangeCheck.py
@@ -11,6 +11,7 @@
from pyparsing import Word, nums, Suppress, 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:
@@ -19,27 +20,28 @@ def ranged_value(expr, minval=None, maxval=None):
# 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]
+ (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 ({} to {})".format(minval,maxval),
- }[minval is None, maxval is None]
+ (True, False): "value is greater than %s" % maxval,
+ (False, True): "value is less than %s" % minval,
+ (False, False): "value is not in the range ({} to {})".format(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]))
+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('/')
+SLASH = Suppress("/")
dateExpr = year("year") + SLASH + month("month") + Optional(SLASH + day("day"))
dateExpr.setName("date")
@@ -47,14 +49,16 @@ dateExpr.setName("date")
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()
+mindate = datetime(2002, 1, 1).date()
maxdate = datetime.now().date()
dateExpr = ranged_value(dateExpr, mindate, maxdate)
-dateExpr.runTests("""
+dateExpr.runTests(
+ """
2011/5/8
2001/1/1
2004/2/29
2004/2
- 1999/12/31""")
+ 1999/12/31"""
+)
diff --git a/examples/readJson.py b/examples/readJson.py
index f691ea5..f3b6a6f 100644
--- a/examples/readJson.py
+++ b/examples/readJson.py
@@ -1,14 +1,14 @@
-#~ 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()
+# ~ 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
+# ~ print s
s = """
{"phedex":{"request":[{"last_update":"1188037561", "numofapproved":"1",
@@ -1903,14 +1903,14 @@ from jsonParser import jsonObject
data = jsonObject.parseString(s)
-#~ from pprint import pprint
-#~ pprint( data[0].asList() )
-#~ print
-#~ print data.dump()
+# ~ 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.dump()
print("-", req.id, req.last_update)
diff --git a/examples/removeLineBreaks.py b/examples/removeLineBreaks.py
index 1a77231..03315be 100644
--- a/examples/removeLineBreaks.py
+++ b/examples/removeLineBreaks.py
@@ -18,11 +18,14 @@ line_end = pp.LineEnd()
# define an expression for the body of a line of text - use a predicate condition to
# accept only lines with some content.
def mustBeNonBlank(t):
- return t[0] != ''
+ return t[0] != ""
# could also be written as
# return bool(t[0])
-lineBody = pp.SkipTo(line_end).addCondition(mustBeNonBlank, message="line body can't be empty")
+
+lineBody = pp.SkipTo(line_end).addCondition(
+ mustBeNonBlank, message="line body can't be empty"
+)
# now define a line with a trailing lineEnd, to be replaced with a space character
textLine = lineBody + line_end().setParseAction(pp.replaceWith(" "))
diff --git a/examples/romanNumerals.py b/examples/romanNumerals.py
index 757a925..932daa6 100644
--- a/examples/romanNumerals.py
+++ b/examples/romanNumerals.py
@@ -5,26 +5,40 @@
import pyparsing as pp
+
def romanNumeralLiteral(numeralString, value):
return pp.Literal(numeralString).setParseAction(pp.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)
+
+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()
+numeral = (
+ onethousand
+ | ninehundred
+ | fivehundred
+ | fourhundred
+ | onehundred
+ | ninety
+ | fifty
+ | forty
+ | ten
+ | nine
+ | five
+ | four
+ | one
+).leaveWhitespace()
romanNumeral = numeral[1, ...].setParseAction(sum)
@@ -52,8 +66,9 @@ def makeRomanNumeral(n):
n, ret = addDigits(n, 1, "I", ret)
return ret
+
# make a string of all roman numerals from I to MMMMM
-tests = " ".join(makeRomanNumeral(i) for i in range(1, 5000+1))
+tests = " ".join(makeRomanNumeral(i) for i in range(1, 5000 + 1))
# parse each roman numeral, and populate map for validation below
roman_int_map = {}
@@ -63,17 +78,24 @@ for expected, (t, s, e) in enumerate(romanNumeral.scanString(tests), start=1):
print("{} {} {}".format("==>", t, orig))
roman_int_map[orig] = t[0]
+
def verify_value(s, tokens):
expected = roman_int_map[s]
if tokens[0] != expected:
- raise Exception("incorrect value for {} ({}), expected {}".format(s, tokens[0], expected ))
+ raise Exception(
+ "incorrect value for {} ({}), expected {}".format(s, tokens[0], expected)
+ )
+
-romanNumeral.runTests("""\
+romanNumeral.runTests(
+ """\
XVI
XXXIX
XIV
XIX
MCMLXXX
MMVI
- """, fullDump=False,
- postParse=verify_value)
+ """,
+ fullDump=False,
+ postParse=verify_value,
+)
diff --git a/examples/rosettacode.py b/examples/rosettacode.py
index 8a8d5c9..5cbf203 100644
--- a/examples/rosettacode.py
+++ b/examples/rosettacode.py
@@ -7,7 +7,7 @@
#
BNF = """
stmt_list = {stmt} ;
-
+
stmt = ';'
| Identifier '=' expr ';'
| 'while' paren_expr stmt
@@ -16,11 +16,11 @@ BNF = """
| 'putc' paren_expr ';'
| '{' stmt_list '}'
;
-
+
paren_expr = '(' expr ')' ;
-
+
prt_list = string | expr {',' String | expr} ;
-
+
expr = and_expr {'||' and_expr} ;
and_expr = equality_expr {'&&' equality_expr} ;
equality_expr = relational_expr [('==' | '!=') relational_expr] ;
@@ -35,28 +35,33 @@ BNF = """
"""
import pyparsing as pp
+
pp.ParserElement.enablePackrat()
LBRACE, RBRACE, LPAR, RPAR, SEMI = map(pp.Suppress, "{}();")
-EQ = pp.Literal('=')
+EQ = pp.Literal("=")
-keywords = (WHILE, IF, PRINT, PUTC, ELSE) = map(pp.Keyword, "while if print putc else".split())
+keywords = (WHILE, IF, PRINT, PUTC, ELSE) = map(
+ pp.Keyword, "while if print putc else".split()
+)
any_keyword = pp.MatchFirst(keywords)
identifier = ~any_keyword + pp.pyparsing_common.identifier
integer = pp.pyparsing_common.integer
-string = pp.QuotedString('"', convertWhitespaceEscapes=False).setName("quoted string")
+string = pp.QuotedString('"', convertWhitespaceEscapes=False).setName("quoted string")
char = pp.Regex(r"'\\?.'")
-expr = pp.infixNotation(identifier | integer | char,
- [
- (pp.oneOf("+ - !"), 1, pp.opAssoc.RIGHT,),
- (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT, ),
- (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("< <= > >="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
- (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
- ])
+expr = pp.infixNotation(
+ identifier | integer | char,
+ [
+ (pp.oneOf("+ - !"), 1, pp.opAssoc.RIGHT,),
+ (pp.oneOf("* / %"), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("+ -"), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("< <= > >="), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("== !="), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("&&"), 2, pp.opAssoc.LEFT,),
+ (pp.oneOf("||"), 2, pp.opAssoc.LEFT,),
+ ],
+)
prt_list = pp.Group(pp.delimitedList(string | expr))
paren_expr = pp.Group(LPAR + expr + RPAR)
@@ -68,28 +73,29 @@ if_stmt = pp.Group(IF - paren_expr + stmt + pp.Optional(ELSE + stmt))
print_stmt = pp.Group(PRINT - pp.Group(LPAR + prt_list + RPAR) + SEMI)
putc_stmt = pp.Group(PUTC - paren_expr + SEMI)
stmt_list = pp.Group(LBRACE + stmt[...] + RBRACE)
-stmt <<= (pp.Group(SEMI)
- | assignment_stmt
- | while_stmt
- | if_stmt
- | print_stmt
- | putc_stmt
- | stmt_list
- ).setName("statement")
+stmt <<= (
+ pp.Group(SEMI)
+ | assignment_stmt
+ | while_stmt
+ | if_stmt
+ | print_stmt
+ | putc_stmt
+ | stmt_list
+).setName("statement")
code = stmt[...]
code.ignore(pp.cppStyleComment)
tests = [
- r'''
+ r"""
count = 1;
while (count < 10) {
print("count is: ", count, "\n");
count = count + 1;
}
- ''',
- r'''
+ """,
+ r"""
/*
Simple prime number generator
*/
@@ -110,64 +116,64 @@ tests = [
}
}
print("Total primes found: ", count, "\n");
- ''',
- r'''
+ """,
+ r"""
/*
Hello world
*/
- print("Hello, World!\n");
- ''',
- r'''
+ print("Hello, World!\n");
+ """,
+ r"""
/*
Show Ident and Integers
*/
phoenix_number = 142857;
print(phoenix_number, "\n");
- ''',
- r'''
+ """,
+ r"""
/*** test printing, embedded \n and comments with lots of '*' ***/
print(42);
print("\nHello World\nGood Bye\nok\n");
print("Print a slash n - \\n.\n");
- ''',
- r'''
+ """,
+ r"""
/* 100 Doors */
i = 1;
while (i * i <= 100) {
print("door ", i * i, " is open\n");
i = i + 1;
}
- ''',
- r'''
+ """,
+ r"""
a = (-1 * ((-1 * (5 * 15)) / 10));
print(a, "\n");
b = -a;
print(b, "\n");
print(-b, "\n");
print(-(1), "\n");
- ''',
- r'''
+ """,
+ r"""
print(---------------------------------+++5, "\n");
print(((((((((3 + 2) * ((((((2))))))))))))), "\n");
-
+
if (1) { if (1) { if (1) { if (1) { if (1) { print(15, "\n"); } } } } }
- ''',
- r'''
+ """,
+ r"""
/* Compute the gcd of 1071, 1029: 21 */
-
+
a = 1071;
b = 1029;
-
+
while (b != 0) {
new_a = b;
b = a % b;
a = new_a;
}
print(a);
- ''',
- r'''
+ """,
+ r"""
/* 12 factorial is 479001600 */
-
+
n = 12;
result = 1;
i = 1;
@@ -176,10 +182,10 @@ tests = [
i = i + 1;
}
print(result);
- ''',
- r'''
+ """,
+ r"""
/* fibonacci of 44 is 701408733 */
-
+
n = 44;
i = 1;
a = 0;
@@ -191,8 +197,8 @@ tests = [
i = i + 1;
}
print(w, "\n");
- ''',
- r'''
+ """,
+ r"""
/* FizzBuzz */
i = 1;
while (i <= 100) {
@@ -204,12 +210,12 @@ tests = [
print("Buzz");
else
print(i);
-
+
print("\n");
i = i + 1;
}
- ''',
- r'''
+ """,
+ r"""
/* 99 bottles */
bottles = 99;
while (bottles > 0) {
@@ -219,8 +225,8 @@ tests = [
bottles = bottles - 1;
print(bottles, " bottles of beer on the wall\n\n");
}
- ''',
- r'''
+ """,
+ r"""
{
/*
This is an integer ascii Mandelbrot generator
@@ -231,9 +237,9 @@ tests = [
bottom_edge = -300;
x_step = 7;
y_step = 15;
-
+
max_iter = 200;
-
+
y0 = top_edge;
while (y0 > bottom_edge) {
x0 = left_edge;
@@ -263,10 +269,11 @@ tests = [
y0 = y0 - y_step;
}
}
- ''',
+ """,
]
import sys
+
sys.setrecursionlimit(2000)
for test in tests:
diff --git a/examples/scanExamples.py b/examples/scanExamples.py
index 4ee62a1..91d0739 100644
--- a/examples/scanExamples.py
+++ b/examples/scanExamples.py
@@ -5,8 +5,17 @@
#
# Copyright (c) 2004, 2006 Paul McGuire
#
-from pyparsing import Word, alphas, alphanums, Literal, restOfLine, OneOrMore, \
- empty, Suppress, replaceWith
+from pyparsing import (
+ Word,
+ alphas,
+ alphanums,
+ Literal,
+ restOfLine,
+ OneOrMore,
+ empty,
+ Suppress,
+ replaceWith,
+)
# simulate some C++ code
testData = """
@@ -24,10 +33,15 @@ 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)
+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)
@@ -43,23 +57,24 @@ print("Examples of a transformer")
print("----------------------")
# convert C++ namespaces to mangled C-compatible names
-scopedIdent = ident + OneOrMore( Literal("::").suppress() + ident )
+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 ))
+print(scopedIdent.transformString(testData))
# or a crude pre-processor (use parse actions to replace matching text)
-def substituteMacro(s,l,t):
+def substituteMacro(s, l, t):
if t[0] in macros:
return macros[t[0]]
-ident.setParseAction( substituteMacro )
+
+
+ident.setParseAction(substituteMacro)
ident.ignore(macroDef)
print("(simulate #define pre-processor)")
-print(ident.transformString( testData ))
-
+print(ident.transformString(testData))
#################
@@ -70,6 +85,6 @@ 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("") )
+stringMacroDef.setParseAction(replaceWith(""))
-print(stringMacroDef.transformString( testData ))
+print(stringMacroDef.transformString(testData))
diff --git a/examples/searchParserAppDemo.py b/examples/searchParserAppDemo.py
index d1bf8ba..c608132 100644
--- a/examples/searchParserAppDemo.py
+++ b/examples/searchParserAppDemo.py
@@ -1,15 +1,24 @@
from searchparser import SearchQueryParser
-products = [ "grape juice", "grape jelly", "orange juice", "orange jujubees",
- "strawberry jam", "prune juice", "prune butter", "orange marmalade",
- "grapefruit juice" ]
+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 { p for p in products if p.startswith(word + " ") }
+ return {p for p in products if p.startswith(word + " ")}
def GetWordWildcard(self, word):
- return { p for p in products if p.startswith(word[:-1]) }
+ return {p for p in products if p.startswith(word[:-1])}
def GetQuotes(self, search_string, tmp_result):
result = set()
@@ -17,7 +26,7 @@ class FruitSearchParser(SearchQueryParser):
return result
def GetNot(self, not_set):
- return set( products ) - not_set
+ return set(products) - not_set
parser = FruitSearchParser()
@@ -31,4 +40,4 @@ tests = """\
for t in tests:
print(t.strip())
print(parser.Parse(t))
- print('')
+ print("")
diff --git a/examples/searchparser.py b/examples/searchparser.py
index 30231b0..4284cc3 100644
--- a/examples/searchparser.py
+++ b/examples/searchparser.py
@@ -57,19 +57,29 @@ TODO:
- 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, OneOrMore, oneOf
+from pyparsing import (
+ Word,
+ alphanums,
+ Keyword,
+ Group,
+ Combine,
+ Forward,
+ Suppress,
+ OneOrMore,
+ oneOf,
+)
-class SearchQueryParser:
+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,
+ "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()
@@ -90,37 +100,52 @@ class SearchQueryParser:
"""
operatorOr = Forward()
- operatorWord = Group(Combine(Word(alphanums) + Suppress('*'))).setResultsName('wordwildcard') | \
- Group(Word(alphanums)).setResultsName('word')
+ operatorWord = Group(Combine(Word(alphanums) + Suppress("*"))).setResultsName(
+ "wordwildcard"
+ ) | Group(Word(alphanums)).setResultsName("word")
operatorQuotesContent = Forward()
- operatorQuotesContent << (
- (operatorWord + operatorQuotesContent) | operatorWord
- )
+ operatorQuotesContent << ((operatorWord + operatorQuotesContent) | operatorWord)
- operatorQuotes = Group(
- Suppress('"') + operatorQuotesContent + Suppress('"')
- ).setResultsName("quotes") | operatorWord
+ operatorQuotes = (
+ Group(Suppress('"') + operatorQuotesContent + Suppress('"')).setResultsName(
+ "quotes"
+ )
+ | operatorWord
+ )
- operatorParenthesis = Group(
- Suppress("(") + operatorOr + Suppress(")")
- ).setResultsName("parenthesis") | operatorQuotes
+ operatorParenthesis = (
+ Group(Suppress("(") + operatorOr + Suppress(")")).setResultsName(
+ "parenthesis"
+ )
+ | operatorQuotes
+ )
operatorNot = Forward()
- operatorNot << (Group(
- Suppress(Keyword("not", caseless=True)) + operatorNot
- ).setResultsName("not") | operatorParenthesis)
+ 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)
+ 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)
+ operatorOr << (
+ Group(
+ operatorAnd + Suppress(Keyword("or", caseless=True)) + operatorOr
+ ).setResultsName("or")
+ | operatorAnd
+ )
return operatorOr.parseString
@@ -151,7 +176,7 @@ class SearchQueryParser:
r = self.evaluate(item)
else:
r = r.intersection(self.evaluate(item))
- return self.GetQuotes(' '.join(search_terms), r)
+ return self.GetQuotes(" ".join(search_terms), r)
def evaluateWord(self, argument):
return self.GetWord(argument[0])
@@ -163,7 +188,7 @@ class SearchQueryParser:
return self._methods[argument.getName()](argument)
def Parse(self, query):
- #print self._parser(query)[0]
+ # print self._parser(query)[0]
return self.evaluate(self._parser(query)[0])
def GetWord(self, word):
@@ -183,70 +208,71 @@ class ParserTest(SearchQueryParser):
"""Tests the parser with some search queries
tests containts a dictionary with tests and expected results.
"""
+
tests = {
- 'help': {1, 2, 4, 5},
- 'help or hulp': {1, 2, 3, 4, 5},
- 'help and hulp': {2},
- 'help hulp': {2},
- 'help and hulp or hilp': {2, 3, 4},
- 'help or hulp and hilp': {1, 2, 3, 4, 5},
- 'help or hulp or hilp or halp': {1, 2, 3, 4, 5, 6},
- '(help or hulp) and (hilp or halp)': {3, 4, 5},
- 'help and (hilp or halp)': {4, 5},
- '(help and (hilp or halp)) or hulp': {2, 3, 4, 5},
- 'not help': {3, 6, 7, 8},
- 'not hulp and halp': {5, 6},
- 'not (help and halp)': {1, 2, 3, 4, 6, 7, 8},
+ "help": {1, 2, 4, 5},
+ "help or hulp": {1, 2, 3, 4, 5},
+ "help and hulp": {2},
+ "help hulp": {2},
+ "help and hulp or hilp": {2, 3, 4},
+ "help or hulp and hilp": {1, 2, 3, 4, 5},
+ "help or hulp or hilp or halp": {1, 2, 3, 4, 5, 6},
+ "(help or hulp) and (hilp or halp)": {3, 4, 5},
+ "help and (hilp or halp)": {4, 5},
+ "(help and (hilp or halp)) or hulp": {2, 3, 4, 5},
+ "not help": {3, 6, 7, 8},
+ "not hulp and halp": {5, 6},
+ "not (help and halp)": {1, 2, 3, 4, 6, 7, 8},
'"help me please"': {2},
'"help me please" or hulp': {2, 3},
'"help me please" or (hulp and halp)': {2},
- 'help*': {1, 2, 4, 5, 8},
- 'help or hulp*': {1, 2, 3, 4, 5},
- 'help* and hulp': {2},
- 'help and hulp* or hilp': {2, 3, 4},
- 'help* or hulp or hilp or halp': {1, 2, 3, 4, 5, 6, 8},
- '(help or hulp*) and (hilp* or halp)': {3, 4, 5},
- 'help* and (hilp* or halp*)': {4, 5},
- '(help and (hilp* or halp)) or hulp*': {2, 3, 4, 5},
- 'not help* and halp': {6},
- 'not (help* and helpe*)': {1, 2, 3, 4, 5, 6, 7},
+ "help*": {1, 2, 4, 5, 8},
+ "help or hulp*": {1, 2, 3, 4, 5},
+ "help* and hulp": {2},
+ "help and hulp* or hilp": {2, 3, 4},
+ "help* or hulp or hilp or halp": {1, 2, 3, 4, 5, 6, 8},
+ "(help or hulp*) and (hilp* or halp)": {3, 4, 5},
+ "help* and (hilp* or halp*)": {4, 5},
+ "(help and (hilp* or halp)) or hulp*": {2, 3, 4, 5},
+ "not help* and halp": {6},
+ "not (help* and helpe*)": {1, 2, 3, 4, 5, 6, 7},
'"help* me please"': {2},
'"help* me* please" or hulp*': {2, 3},
'"help me please*" or (hulp and halp)': {2},
'"help me please" not (hulp and halp)': {2},
'"help me please" hulp': {2},
- 'help and hilp and not holp': {4},
- 'help hilp not holp': {4},
- 'help hilp and not holp': {4},
+ "help and hilp and not holp": {4},
+ "help hilp not holp": {4},
+ "help hilp and not holp": {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',
+ 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': {1, 2, 4, 5},
- 'me': {2},
- 'please': {2},
- 'hulp': {2, 3},
- 'hilp': {3, 4},
- 'halp': {5, 6},
- 'thinks': {5},
- 'he': {5, 6},
- 'needs': {5, 6},
- 'nothing': {7},
- 'helper': {8},
+ "help": {1, 2, 4, 5},
+ "me": {2},
+ "please": {2},
+ "hulp": {2, 3},
+ "hilp": {3, 4},
+ "halp": {5, 6},
+ "thinks": {5},
+ "he": {5, 6},
+ "needs": {5, 6},
+ "nothing": {7},
+ "helper": {8},
}
def GetWord(self, word):
- if (word in self.index):
+ if word in self.index:
return self.index[word]
else:
return set()
@@ -254,7 +280,7 @@ class ParserTest(SearchQueryParser):
def GetWordWildcard(self, word):
result = set()
for item in list(self.index.keys()):
- if word == item[0:len(word)]:
+ if word == item[0 : len(word)]:
result = result.union(self.index[item])
return result
@@ -275,18 +301,19 @@ class ParserTest(SearchQueryParser):
print(item)
r = self.Parse(item)
e = self.tests[item]
- print('Result: %s' % r)
- print('Expect: %s' % e)
+ print("Result: %s" % r)
+ print("Expect: %s" % e)
if e == r:
- print('Test OK')
+ print("Test OK")
else:
all_ok = False
- print('>>>>>>>>>>>>>>>>>>>>>>Test ERROR<<<<<<<<<<<<<<<<<<<<<')
- print('')
+ print(">>>>>>>>>>>>>>>>>>>>>>Test ERROR<<<<<<<<<<<<<<<<<<<<<")
+ print("")
return all_ok
-if __name__=='__main__':
+
+if __name__ == "__main__":
if ParserTest().Test():
- print('All tests OK')
+ print("All tests OK")
else:
- print('One or more tests FAILED')
+ print("One or more tests FAILED")
diff --git a/examples/select_parser.py b/examples/select_parser.py
index 7f9273c..723f8b2 100644
--- a/examples/select_parser.py
+++ b/examples/select_parser.py
@@ -5,29 +5,140 @@
# definition at https://www.sqlite.org/lang_select.html
#
from pyparsing import *
+
ParserElement.enablePackrat()
-LPAR,RPAR,COMMA = map(Suppress,"(),")
-DOT,STAR = map(Literal, ".*")
+LPAR, RPAR, COMMA = map(Suppress, "(),")
+DOT, STAR = map(Literal, ".*")
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,
+(
+ 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, 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, 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+"_")
+ 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,
+ 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, 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()
@@ -46,87 +157,120 @@ 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)
- )
+ 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(STAR | delimitedList(expr)) + RPAR
+ | function_name.setName("function_name")
+ + LPAR
+ + Optional(STAR | delimitedList(expr))
+ + RPAR
| literal_value
| bind_parameter
- | Group(identifier('col_db') + DOT + identifier('col_tab') + DOT + identifier('col'))
- | Group(identifier('col_tab') + DOT + identifier('col'))
- | Group(identifier('col'))
+ | Group(
+ identifier("col_db") + DOT + identifier("col_tab") + DOT + identifier("col")
)
+ | Group(identifier("col_tab") + DOT + identifier("col"))
+ | Group(identifier("col"))
+)
-UNARY,BINARY,TERNARY=1,2,3
-expr << infixNotation(expr_term,
+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)
+ (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") + DOT + 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)
- )
+ Group(database_name("database") + DOT + 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)
+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))
-result_column = Group(STAR('col')
- | table_name('col_table') + DOT + STAR('col')
- | expr('col') + Optional(Optional(AS) + column_alias('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"))
- )
+result_column = Group(
+ STAR("col")
+ | table_name("col_table") + DOT + STAR("col")
+ | expr("col") + Optional(Optional(AS) + column_alias("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
diff --git a/examples/sexpParser.py b/examples/sexpParser.py
index 5c4f14d..2a0f2c7 100644
--- a/examples/sexpParser.py
+++ b/examples/sexpParser.py
@@ -52,28 +52,40 @@ def verify_length(s, l, t):
if t.len is not None:
t1len = len(t[1])
if t1len != t.len:
- raise pp.ParseFatalException(s, l, "invalid data of length {}, expected {}".format(t1len, t.len))
+ raise pp.ParseFatalException(
+ s, l, "invalid data of length {}, expected {}".format(t1len, t.len)
+ )
return t[1]
# define punctuation literals
-LPAR, RPAR, LBRK, RBRK, LBRC, RBRC, VBAR, COLON = (pp.Suppress(c).setName(c) for c in "()[]{}|:")
+LPAR, RPAR, LBRK, RBRK, LBRC, RBRC, VBAR, COLON = (
+ pp.Suppress(c).setName(c) for c in "()[]{}|:"
+)
-decimal = pp.Regex(r'-?0|[1-9]\d*').setParseAction(lambda t: int(t[0]))
-hexadecimal = ("#" + pp.Word(pp.hexnums)[1, ...] + "#").setParseAction(lambda t: int("".join(t[1:-1]), 16))
+decimal = pp.Regex(r"-?0|[1-9]\d*").setParseAction(lambda t: int(t[0]))
+hexadecimal = ("#" + pp.Word(pp.hexnums)[1, ...] + "#").setParseAction(
+ lambda t: int("".join(t[1:-1]), 16)
+)
bytes = pp.Word(pp.printables)
raw = pp.Group(decimal("len") + COLON + bytes).setParseAction(verify_length)
-base64_ = pp.Group(pp.Optional(decimal | hexadecimal, default=None)("len")
- + VBAR
- + pp.Word(pp.alphanums + "+/=")[1, ...].setParseAction(lambda t: b64decode("".join(t)))
- + VBAR
- ).setParseAction(verify_length)
+base64_ = pp.Group(
+ pp.Optional(decimal | hexadecimal, default=None)("len")
+ + VBAR
+ + pp.Word(pp.alphanums + "+/=")[1, ...].setParseAction(
+ lambda t: b64decode("".join(t))
+ )
+ + VBAR
+).setParseAction(verify_length)
-real = pp.Regex(r"[+-]?\d+\.\d*([eE][+-]?\d+)?").setParseAction(lambda tokens: float(tokens[0]))
+real = pp.Regex(r"[+-]?\d+\.\d*([eE][+-]?\d+)?").setParseAction(
+ lambda tokens: float(tokens[0])
+)
token = pp.Word(pp.alphanums + "-./_:*+=!<>")
-qString = pp.Group(pp.Optional(decimal, default=None)("len")
- + pp.dblQuotedString.setParseAction(pp.removeQuotes)
- ).setParseAction(verify_length)
+qString = pp.Group(
+ pp.Optional(decimal, default=None)("len")
+ + pp.dblQuotedString.setParseAction(pp.removeQuotes)
+).setParseAction(verify_length)
simpleString = real | base64_ | raw | decimal | token | hexadecimal | qString
@@ -151,6 +163,8 @@ test52 = """
"""
# Run tests
-alltests = [globals()[testname] for testname in sorted(locals()) if testname.startswith("test")]
+alltests = [
+ globals()[testname] for testname in sorted(locals()) if testname.startswith("test")
+]
sexp.runTests(alltests, fullDump=False)
diff --git a/examples/shapes.py b/examples/shapes.py
index b0fe979..5f621b1 100644
--- a/examples/shapes.py
+++ b/examples/shapes.py
@@ -17,37 +17,45 @@ class Shape:
def __str__(self):
return "<{}>: {}".format(self.__class__.__name__, vars(self))
+
class Square(Shape):
def area(self):
- return self.side**2
+ 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
+ return 3.14159 * self.radius ** 2
import pyparsing as pp
-number = pp.Regex(r'-?\d+(\.\d*)?').setParseAction(lambda t: float(t[0]))
+number = pp.Regex(r"-?\d+(\.\d*)?").setParseAction(lambda t: float(t[0]))
# Shape expressions:
# square : S <centerx> <centery> <side>
# rectangle: R <centerx> <centery> <width> <height>
# circle : C <centerx> <centery> <diameter>
-squareDefn = "S" + number('centerx') + number('centery') + number('side')
-rectDefn = "R" + number('centerx') + number('centery') + number('width') + number('height')
-circleDefn = "C" + number('centerx') + number('centery') + number('diameter')
+squareDefn = "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
+ tokens["radius"] = tokens.diameter / 2.0
+
+
circleDefn.setParseAction(computeRadius, Circle)
shapeExpr = squareDefn | rectDefn | circleDefn
diff --git a/examples/simpleArith.py b/examples/simpleArith.py
index af05373..af3f904 100644
--- a/examples/simpleArith.py
+++ b/examples/simpleArith.py
@@ -9,15 +9,15 @@
from pyparsing import *
-integer = Word(nums).setParseAction(lambda t:int(t[0]))
-variable = Word(alphas,exact=1)
+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('!')
+expop = Literal("^")
+signop = oneOf("+ -")
+multop = oneOf("* /")
+plusop = oneOf("+ -")
+factop = Literal("!")
# To use the infixNotation helper:
# 1. Define the "atom" operand term of the grammar.
@@ -43,24 +43,29 @@ factop = Literal('!')
# 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),]
- )
+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",]
+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('')
+ print("")
diff --git a/examples/simpleBool.py b/examples/simpleBool.py
index 81f5049..f47e090 100644
--- a/examples/simpleBool.py
+++ b/examples/simpleBool.py
@@ -17,84 +17,98 @@ 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:
- def __init__(self,t):
+ 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__
class BoolBinOp:
- def __init__(self,t):
+ def __init__(self, t):
self.args = t[0][0::2]
+
def __str__(self):
sep = " %s " % self.reprsymbol
- return "(" + sep.join(map(str,self.args)) + ")"
+ return "(" + sep.join(map(str, self.args)) + ")"
+
def __bool__(self):
return self.evalop(bool(a) for a in self.args)
+
__nonzero__ = __bool__
class BoolAnd(BoolBinOp):
- reprsymbol = '&'
+ reprsymbol = "&"
evalop = all
+
class BoolOr(BoolBinOp):
- reprsymbol = '|'
+ reprsymbol = "|"
evalop = any
+
class BoolNot:
- def __init__(self,t):
+ 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__
TRUE = Keyword("True")
FALSE = Keyword("False")
-boolOperand = TRUE | FALSE | Word(alphas,max=1)
+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,
+boolExpr = infixNotation(
+ boolOperand,
[
- ("not", 1, opAssoc.RIGHT, BoolNot),
- ("and", 2, opAssoc.LEFT, BoolAnd),
- ("or", 2, opAssoc.LEFT, BoolOr),
- ])
+ ("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),
- ]
+ 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:
+ 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')
+ print(t, "\n", res, "=", bool(res), "\n", success, "\n")
diff --git a/examples/simpleSQL.py b/examples/simpleSQL.py
index 60582cd..a806ad6 100644
--- a/examples/simpleSQL.py
+++ b/examples/simpleSQL.py
@@ -5,57 +5,75 @@
#
# Copyright (c) 2003,2016, Paul McGuire
#
-from pyparsing import Word, delimitedList, Optional, \
- Group, alphas, alphanums, Forward, oneOf, quotedString, \
- infixNotation, opAssoc, \
- restOfLine, CaselessKeyword, pyparsing_common as ppc
+from pyparsing import (
+ Word,
+ delimitedList,
+ Optional,
+ Group,
+ alphas,
+ alphanums,
+ Forward,
+ oneOf,
+ quotedString,
+ infixNotation,
+ opAssoc,
+ restOfLine,
+ CaselessKeyword,
+ pyparsing_common as ppc,
+)
# define SQL tokens
selectStmt = Forward()
-SELECT, FROM, WHERE, AND, OR, IN, IS, NOT, NULL = map(CaselessKeyword,
- "select from where and or in is not null".split())
+SELECT, FROM, WHERE, AND, OR, IN, IS, NOT, NULL = map(
+ CaselessKeyword, "select from where and or in is not null".split()
+)
NOT_NULL = NOT + NULL
-ident = Word( alphas, alphanums + "_$" ).setName("identifier")
-columnName = delimitedList(ident, ".", combine=True).setName("column name")
+ident = Word(alphas, alphanums + "_$").setName("identifier")
+columnName = delimitedList(ident, ".", combine=True).setName("column name")
columnName.addParseAction(ppc.upcaseTokens)
-columnNameList = Group( delimitedList(columnName))
-tableName = delimitedList(ident, ".", combine=True).setName("table name")
+columnNameList = Group(delimitedList(columnName))
+tableName = delimitedList(ident, ".", combine=True).setName("table name")
tableName.addParseAction(ppc.upcaseTokens)
-tableNameList = Group(delimitedList(tableName))
+tableNameList = Group(delimitedList(tableName))
binop = oneOf("= != < > >= <= eq ne lt le gt ge", caseless=True)
realNum = ppc.real()
intNum = ppc.signed_integer()
-columnRval = realNum | intNum | quotedString | columnName # need to add support for alg expressions
+columnRval = (
+ realNum | intNum | quotedString | columnName
+) # need to add support for alg expressions
whereCondition = Group(
- ( columnName + binop + columnRval ) |
- ( columnName + IN + Group("(" + delimitedList( columnRval ) + ")" )) |
- ( columnName + IN + Group("(" + selectStmt + ")" )) |
- ( columnName + IS + (NULL | NOT_NULL))
- )
+ (columnName + binop + columnRval)
+ | (columnName + IN + Group("(" + delimitedList(columnRval) + ")"))
+ | (columnName + IN + Group("(" + selectStmt + ")"))
+ | (columnName + IS + (NULL | NOT_NULL))
+)
-whereExpression = infixNotation(whereCondition,
- [
- (NOT, 1, opAssoc.RIGHT),
- (AND, 2, opAssoc.LEFT),
- (OR, 2, opAssoc.LEFT),
- ])
+whereExpression = infixNotation(
+ whereCondition,
+ [(NOT, 1, opAssoc.RIGHT), (AND, 2, opAssoc.LEFT), (OR, 2, opAssoc.LEFT),],
+)
# define the grammar
-selectStmt <<= (SELECT + ('*' | columnNameList)("columns") +
- FROM + tableNameList( "tables" ) +
- Optional(Group(WHERE + whereExpression), "")("where"))
+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 )
+simpleSQL.ignore(oracleSqlComment)
if __name__ == "__main__":
- simpleSQL.runTests("""\
+ simpleSQL.runTests(
+ """\
# multiple tables
SELECT * from XYZZY, ABC
@@ -92,4 +110,5 @@ if __name__ == "__main__":
# where clause with comparison operator
Select A,b from table1,table2 where table1.id eq table2.id
- """)
+ """
+ )
diff --git a/examples/simpleWiki.py b/examples/simpleWiki.py
index ca660c5..73c8116 100644
--- a/examples/simpleWiki.py
+++ b/examples/simpleWiki.py
@@ -8,22 +8,28 @@ Here is a simple Wiki input:
Here's a URL to {{Pyparsing's Wiki Page->https://site-closed.wikispaces.com}}
"""
-def convertToHTML(opening,closing):
- def conversionParseAction(s,l,t):
+
+def convertToHTML(opening, closing):
+ def conversionParseAction(s, l, t):
return opening + t[0] + closing
+
return conversionParseAction
-italicized = QuotedString("*").setParseAction(convertToHTML("<I>","</I>"))
-bolded = QuotedString("**").setParseAction(convertToHTML("<B>","</B>"))
-boldItalicized = QuotedString("***").setParseAction(convertToHTML("<B><I>","</I></B>"))
-def convertToHTML_A(s,l,t):
+
+italicized = QuotedString("*").setParseAction(convertToHTML("<I>", "</I>"))
+bolded = QuotedString("**").setParseAction(convertToHTML("<B>", "</B>"))
+boldItalicized = QuotedString("***").setParseAction(convertToHTML("<B><I>", "</I></B>"))
+
+
+def convertToHTML_A(s, l, t):
try:
- text,url=t[0].split("->")
+ text, url = t[0].split("->")
except ValueError:
- raise ParseFatalException(s,l,"invalid URL link reference: " + t[0])
+ raise ParseFatalException(s, l, "invalid URL link reference: " + t[0])
return '<A href="{}">{}</A>'.format(url, text)
-urlRef = QuotedString("{{",endQuoteChar="}}").setParseAction(convertToHTML_A)
+
+urlRef = QuotedString("{{", endQuoteChar="}}").setParseAction(convertToHTML_A)
wikiMarkup = urlRef | boldItalicized | bolded | italicized
diff --git a/examples/sparser.py b/examples/sparser.py
index 39758d6..49617ff 100644
--- a/examples/sparser.py
+++ b/examples/sparser.py
@@ -43,7 +43,7 @@ EXAMPLES:
# 675 Mass Ave, Cambridge, MA 02139, USA.
"""
-#===imports======================
+# ===imports======================
import sys
import os
import getopt
@@ -51,57 +51,63 @@ import getopt
from pyparsing import *
-#===globals======================
+# ===globals======================
modname = "sparser"
__version__ = "0.1"
-#--option args--
+# --option args--
debug_p = 0
-#opt_b=None #string arg, default is undefined
+# opt_b=None #string arg, default is undefined
-#---positional args, default is empty---
+# ---positional args, default is empty---
pargs = []
-#---other---
+# ---other---
-#===utilities====================
+# ===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("{}.{}:{}\n".format(modname, ftn, txt))
sys.stdout.flush()
+
def fatal(ftn, txt):
"""If can't continue."""
msg = "{}.{}:FATAL:{}\n".format(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 ):
+
+ 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 ):
+
+ def postParse(self, instring, loc, tokenlist):
return float(tokenlist[0])
+
class ParseFileLineByLine:
"""
Bring data from text files into a program, optionally parsing each line
@@ -133,47 +139,42 @@ class ParseFileLineByLine:
'"a"' (append, not supported for .Z files).
"""
- def __init__(self, filename, mode = 'r'):
+ 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 OSError(0, 'Illegal mode: ' + repr(mode))
+ if mode not in ["r", "w", "a"]:
+ raise OSError(0, "Illegal mode: " + repr(mode))
- if string.find(filename, ':/') > 1: # URL
- if mode == 'w':
+ if string.find(filename, ":/") > 1: # URL
+ if mode == "w":
raise OSError("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 mode == "r" or mode == "a":
if not os.path.exists(filename):
- raise OSError(2, 'No such file or directory: ' + filename)
+ raise OSError(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)'))
+ (".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
@@ -209,64 +210,64 @@ class ParseFileLineByLine:
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")
+ 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")
+ 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")
+ 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")
+ 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")
+ 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'))
+ 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] )
+ 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."""
@@ -325,7 +326,7 @@ class ParseFileLineByLine:
self.file.flush()
-#=============================
+# =============================
def main(pargs):
"""This should only be used for testing. The primary mode of operation is
as an imported library.
@@ -336,28 +337,29 @@ def main(pargs):
print(i)
-#-------------------------
-if __name__ == '__main__':
+# -------------------------
+if __name__ == "__main__":
ftn = "main"
- opts, pargs = getopt.getopt(sys.argv[1:], 'hvd',
- ['help', 'version', 'debug', 'bb='])
+ 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__)
+ 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__)
+ elif opt[0] == "-v" or opt[0] == "--version":
+ print(modname + ": version=" + __version__)
sys.exit(0)
- elif opt[0] == '-d' or opt[0] == '--debug':
+ elif opt[0] == "-d" or opt[0] == "--debug":
debug_p = 1
- elif opt[0] == '--bb':
+ elif opt[0] == "--bb":
opt_b = opt[1]
- #---make the object and run it---
+ # ---make the object and run it---
main(pargs)
-#===Revision Log===
-#Created by mkpythonproj:
-#2006-02-06 Tim Cera
+# ===Revision Log===
+# Created by mkpythonproj:
+# 2006-02-06 Tim Cera
#
diff --git a/examples/sql2dot.py b/examples/sql2dot.py
index cd6717c..ca22ed8 100644
--- a/examples/sql2dot.py
+++ b/examples/sql2dot.py
@@ -47,50 +47,95 @@ alter table only student_registrations
(class_id) references classes(class_id);
""".upper()
-from pyparsing import Literal, Word, delimitedList \
- , alphas, alphanums \
- , OneOrMore, ZeroOrMore, CharsNotIn \
- , replaceWith
+from pyparsing import (
+ Literal,
+ Word,
+ delimitedList,
+ alphas,
+ alphanums,
+ OneOrMore,
+ ZeroOrMore,
+ CharsNotIn,
+ replaceWith,
+)
skobki = "(" + ZeroOrMore(CharsNotIn(")")) + ")"
-field_def = OneOrMore(Word(alphas,alphanums+"_\"':-") | skobki)
+field_def = OneOrMore(Word(alphas, alphanums + "_\"':-") | skobki)
+
+
+def field_act(s, loc, tok):
+ return ("<" + tok[0] + "> " + " ".join(tok)).replace('"', '\\"')
-def field_act(s,loc,tok):
- return ("<"+tok[0]+"> " + " ".join(tok)).replace("\"","\\\"")
field_def.setParseAction(field_act)
-field_list_def = delimitedList( field_def )
+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")+")"+ ";"
+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
+ 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")+")"+";"
+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("") )
+other_statement_def = OneOrMore(CharsNotIn(";")) + ";"
+other_statement_def.setParseAction(replaceWith(""))
comment_def = "--" + ZeroOrMore(CharsNotIn("\n"))
-comment_def.setParseAction( replaceWith("") )
+comment_def.setParseAction(replaceWith(""))
-statement_def = comment_def | create_table_def | add_fkey_def | other_statement_def
-defs = OneOrMore(statement_def)
+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!="":
+ if i != "":
print(i)
print("}")
diff --git a/examples/stackish.py b/examples/stackish.py
index d33d4de..f02baf3 100644
--- a/examples/stackish.py
+++ b/examples/stackish.py
@@ -28,43 +28,66 @@ SPACE White space is basically ignored. This is interesting because since
separation character and perform reasonable diffs on two structures.
"""
-from pyparsing import Suppress,Word,nums,alphas,alphanums,Combine,oneOf,\
- Optional,QuotedString,Forward,Group,ZeroOrMore,srange
+from pyparsing import (
+ Suppress,
+ Word,
+ nums,
+ alphas,
+ alphanums,
+ Combine,
+ oneOf,
+ Optional,
+ QuotedString,
+ Forward,
+ Group,
+ ZeroOrMore,
+ srange,
+)
-MARK,UNMARK,AT,COLON,QUOTE = map(Suppress,"[]@:'")
+MARK, UNMARK, AT, COLON, QUOTE = map(Suppress, "[]@:'")
NUMBER = Word(nums)
-NUMBER.setParseAction(lambda t:int(t[0]))
+NUMBER.setParseAction(lambda t: int(t[0]))
FLOAT = Combine(oneOf("+ -") + Word(nums) + "." + Optional(Word(nums)))
-FLOAT.setParseAction(lambda t:float(t[0]))
+FLOAT.setParseAction(lambda t: float(t[0]))
STRING = QuotedString('"', multiline=True)
-WORD = Word(alphas,alphanums+"_:")
+WORD = Word(alphas, alphanums + "_:")
ATTRIBUTE = Combine(AT + WORD)
strBody = Forward()
+
+
def setBodyLength(tokens):
- strBody << Word(srange(r'[\0x00-\0xffff]'), exact=int(tokens[0]))
+ strBody << Word(srange(r"[\0x00-\0xffff]"), exact=int(tokens[0]))
return ""
-BLOB = Combine(QUOTE + Word(nums).setParseAction(setBodyLength) +
- COLON + strBody + QUOTE)
+
+
+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 )
+
+
+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
diff --git a/examples/statemachine/documentSignoffDemo.py b/examples/statemachine/documentSignoffDemo.py
index 2ca38c8..23c902d 100644
--- a/examples/statemachine/documentSignoffDemo.py
+++ b/examples/statemachine/documentSignoffDemo.py
@@ -7,7 +7,12 @@
import statemachine
import documentsignoffstate
-print('\n'.join(t.__name__ for t in documentsignoffstate.DocumentRevisionState.transitions()))
+print(
+ "\n".join(
+ t.__name__ for t in documentsignoffstate.DocumentRevisionState.transitions()
+ )
+)
+
class Document(documentsignoffstate.DocumentRevisionStateMixin):
def __init__(self):
@@ -27,16 +32,16 @@ def run_demo():
while not isinstance(doc._state, documentsignoffstate.Approved):
- print('...submit')
+ print("...submit")
doc.submit()
print(doc)
print(doc.state.description)
- if random.randint(1,10) > 3:
- print('...reject')
+ if random.randint(1, 10) > 3:
+ print("...reject")
doc.reject()
else:
- print('...approve')
+ print("...approve")
doc.approve()
print(doc)
@@ -46,5 +51,6 @@ def run_demo():
print(doc)
print(doc.state.description)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
run_demo()
diff --git a/examples/statemachine/documentsignoffstate.pystate b/examples/statemachine/documentsignoffstate.pystate
index 04df274..0c8fc61 100644
--- a/examples/statemachine/documentsignoffstate.pystate
+++ b/examples/statemachine/documentsignoffstate.pystate
@@ -7,7 +7,7 @@
# example using named state transitions
# This implements a state model for submitting,
-# approving, activating, and purging document
+# approving, activating, and purging document
# revisions in a document management system.
#
# The state model looks like:
@@ -16,7 +16,7 @@
# |
# | (create)
# |
-# v
+# v
# Editing ----------------------------------------------+
# | ^ |
# | | |
@@ -50,7 +50,7 @@
# just an example of a state machine with named transitions.
#
-
+
statemachine DocumentRevisionState:
New -( create )-> Editing
Editing -( cancel )-> Deleted
diff --git a/examples/statemachine/libraryBookDemo.py b/examples/statemachine/libraryBookDemo.py
index 98f0b2b..61bdd6d 100644
--- a/examples/statemachine/libraryBookDemo.py
+++ b/examples/statemachine/libraryBookDemo.py
@@ -26,7 +26,11 @@ class RestrictedBook(Book):
if user in self._authorized_users:
super().checkout()
else:
- raise Exception("{} could not check out restricted book".format(user if user is not None else "anonymous"))
+ raise Exception(
+ "{} could not check out restricted book".format(
+ user if user is not None else "anonymous"
+ )
+ )
def run_demo():
@@ -41,9 +45,9 @@ def run_demo():
print(book)
try:
book.checkout()
- except Exception as e: # statemachine.InvalidTransitionException:
+ except Exception as e: # statemachine.InvalidTransitionException:
print(e)
- print('..cannot check out reserved book')
+ print("..cannot check out reserved book")
book.release()
print(book)
book.checkout()
@@ -58,13 +62,13 @@ def run_demo():
try:
restricted_book.checkout(name)
except Exception as e:
- print('..' + str(e))
+ print(".." + str(e))
else:
- print('checkout to', name)
+ print("checkout to", name)
print(restricted_book)
restricted_book.checkin()
print(restricted_book)
-if __name__ == '__main__':
+if __name__ == "__main__":
run_demo()
diff --git a/examples/statemachine/statemachine.py b/examples/statemachine/statemachine.py
index 4c8ee1d..a5f144e 100644
--- a/examples/statemachine/statemachine.py
+++ b/examples/statemachine/statemachine.py
@@ -18,7 +18,8 @@ import pyparsing as pp
# define basic exception for invalid state transitions - state machine classes will subclass to
# define their own specific exception type
-class InvalidTransitionException(Exception): pass
+class InvalidTransitionException(Exception):
+ pass
ident = pp.Word(pp.alphas + "_", pp.alphanums + "_$")
@@ -28,17 +29,30 @@ ident = pp.Word(pp.alphas + "_", pp.alphanums + "_$")
def no_keywords_allowed(s, l, t):
wd = t[0]
return not keyword.iskeyword(wd)
-ident.addCondition(no_keywords_allowed, message="cannot use a Python keyword for state or transition identifier")
-stateTransition = ident("from_state") + "->" + ident("to_state")
-stateMachine = (pp.Keyword("statemachine") + ident("name") + ":"
- + pp.OneOrMore(pp.Group(stateTransition))("transitions"))
-namedStateTransition = (ident("from_state")
- + "-(" + ident("transition") + ")->"
- + ident("to_state"))
-namedStateMachine = (pp.Keyword("statemachine") + ident("name") + ":"
- + pp.OneOrMore(pp.Group(namedStateTransition))("transitions"))
+ident.addCondition(
+ no_keywords_allowed,
+ message="cannot use a Python keyword for state or transition identifier",
+)
+
+stateTransition = ident("from_state") + "->" + ident("to_state")
+stateMachine = (
+ pp.Keyword("statemachine")
+ + ident("name")
+ + ":"
+ + pp.OneOrMore(pp.Group(stateTransition))("transitions")
+)
+
+namedStateTransition = (
+ ident("from_state") + "-(" + ident("transition") + ")->" + ident("to_state")
+)
+namedStateMachine = (
+ pp.Keyword("statemachine")
+ + ident("name")
+ + ":"
+ + pp.OneOrMore(pp.Group(namedStateTransition))("transitions")
+)
def expand_state_definition(source, loc, tokens):
@@ -58,50 +72,53 @@ def expand_state_definition(source, loc, tokens):
# define base class for state classes
baseStateClass = tokens.name
- statedef.extend([
- "class %s(object):" % baseStateClass,
- " def __str__(self):",
- " return self.__class__.__name__",
-
- " @classmethod",
- " def states(cls):",
- " return list(cls.__subclasses__())",
-
- " def next_state(self):",
- " return self._next_state_class()",
- ])
+ statedef.extend(
+ [
+ "class %s(object):" % baseStateClass,
+ " def __str__(self):",
+ " return self.__class__.__name__",
+ " @classmethod",
+ " def states(cls):",
+ " return list(cls.__subclasses__())",
+ " def next_state(self):",
+ " return self._next_state_class()",
+ ]
+ )
# define all state classes
statedef.extend("class {}({}): pass".format(s, baseStateClass) for s in states)
# define state->state transitions
- statedef.extend("{}._next_state_class = {}".format(s, fromTo[s]) for s in states if s in fromTo)
-
- statedef.extend([
- "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass),
- " def __init__(self):",
- " self._state = None",
-
- " def initialize_state(self, init_state):",
- " if issubclass(init_state, {baseStateClass}):".format(baseStateClass=baseStateClass),
- " init_state = init_state()",
- " self._state = init_state",
-
- " @property",
- " def state(self):",
- " return self._state",
-
- " # get behavior/properties from current state",
- " def __getattr__(self, attrname):",
- " attr = getattr(self._state, attrname)",
- " return attr",
+ statedef.extend(
+ "{}._next_state_class = {}".format(s, fromTo[s]) for s in states if s in fromTo
+ )
- " def __str__(self):",
- " return '{0}: {1}'.format(self.__class__.__name__, self._state)",
- ])
+ statedef.extend(
+ [
+ "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass),
+ " def __init__(self):",
+ " self._state = None",
+ " def initialize_state(self, init_state):",
+ " if issubclass(init_state, {baseStateClass}):".format(
+ baseStateClass=baseStateClass
+ ),
+ " init_state = init_state()",
+ " self._state = init_state",
+ " @property",
+ " def state(self):",
+ " return self._state",
+ " # get behavior/properties from current state",
+ " def __getattr__(self, attrname):",
+ " attr = getattr(self._state, attrname)",
+ " return attr",
+ " def __str__(self):",
+ " return '{0}: {1}'.format(self.__class__.__name__, self._state)",
+ ]
+ )
return ("\n" + indent).join(statedef) + "\n"
+
stateMachine.setParseAction(expand_state_definition)
@@ -134,102 +151,115 @@ def expand_named_state_definition(source, loc, tokens):
fromTo[s] = {}
# define state transition class
- statedef.extend([
- "class {baseStateClass}Transition:".format(baseStateClass=baseStateClass),
- " def __str__(self):",
- " return self.transitionName",
- ])
statedef.extend(
- "{tn_name} = {baseStateClass}Transition()".format(tn_name=tn,
- baseStateClass=baseStateClass)
- for tn in transitions)
- statedef.extend("{tn_name}.transitionName = '{tn_name}'".format(tn_name=tn)
- for tn in transitions)
+ [
+ "class {baseStateClass}Transition:".format(baseStateClass=baseStateClass),
+ " def __str__(self):",
+ " return self.transitionName",
+ ]
+ )
+ statedef.extend(
+ "{tn_name} = {baseStateClass}Transition()".format(
+ tn_name=tn, baseStateClass=baseStateClass
+ )
+ for tn in transitions
+ )
+ statedef.extend(
+ "{tn_name}.transitionName = '{tn_name}'".format(tn_name=tn)
+ for tn in transitions
+ )
# define base class for state classes
- statedef.extend([
- "class %s(object):" % baseStateClass,
- " from statemachine import InvalidTransitionException as BaseTransitionException",
- " class InvalidTransitionException(BaseTransitionException): pass",
- " def __str__(self):",
- " return self.__class__.__name__",
-
- " @classmethod",
- " def states(cls):",
- " return list(cls.__subclasses__())",
-
- " @classmethod",
- " def next_state(cls, name):",
- " try:",
- " return cls.tnmap[name]()",
- " except KeyError:",
- " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))",
-
- " def __bad_tn(name):",
- " def _fn(cls):",
- " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))",
- " _fn.__name__ = name",
- " return _fn",
- ])
+ statedef.extend(
+ [
+ "class %s(object):" % baseStateClass,
+ " from statemachine import InvalidTransitionException as BaseTransitionException",
+ " class InvalidTransitionException(BaseTransitionException): pass",
+ " def __str__(self):",
+ " return self.__class__.__name__",
+ " @classmethod",
+ " def states(cls):",
+ " return list(cls.__subclasses__())",
+ " @classmethod",
+ " def next_state(cls, name):",
+ " try:",
+ " return cls.tnmap[name]()",
+ " except KeyError:",
+ " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))",
+ " def __bad_tn(name):",
+ " def _fn(cls):",
+ " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))",
+ " _fn.__name__ = name",
+ " return _fn",
+ ]
+ )
# define default 'invalid transition' methods in base class, valid transitions will be implemented in subclasses
statedef.extend(
" {tn_name} = classmethod(__bad_tn({tn_name!r}))".format(tn_name=tn)
- for tn in transitions)
+ for tn in transitions
+ )
# define all state classes
- statedef.extend("class {}({}): pass".format(s, baseStateClass)
- for s in states)
+ statedef.extend("class {}({}): pass".format(s, baseStateClass) for s in states)
# define state transition methods for valid transitions from each state
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("{}.{} = classmethod(lambda cls: {}())".format(s, tn_, to_)
- for tn_, to_ in trns)
-
- statedef.extend([
- "{baseStateClass}.transitions = classmethod(lambda cls: [{transition_class_list}])".format(
- baseStateClass=baseStateClass,
- transition_class_list = ', '.join("cls.{}".format(tn) for tn in transitions)
- ),
- "{baseStateClass}.transition_names = [tn.__name__ for tn in {baseStateClass}.transitions()]".format(
- baseStateClass=baseStateClass
+ statedef.extend(
+ "{}.{} = classmethod(lambda cls: {}())".format(s, tn_, to_)
+ for tn_, to_ in trns
)
- ])
-
- # define <state>Mixin class for application classes that delegate to the state
- statedef.extend([
- "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass),
- " def __init__(self):",
- " self._state = None",
-
- " def initialize_state(self, init_state):",
- " if issubclass(init_state, {baseStateClass}):".format(baseStateClass=baseStateClass),
- " init_state = init_state()",
- " self._state = init_state",
- " @property",
- " def state(self):",
- " return self._state",
-
- " # get behavior/properties from current state",
- " def __getattr__(self, attrname):",
- " attr = getattr(self._state, attrname)",
- " return attr",
-
- " def __str__(self):",
- " return '{0}: {1}'.format(self.__class__.__name__, self._state)",
+ statedef.extend(
+ [
+ "{baseStateClass}.transitions = classmethod(lambda cls: [{transition_class_list}])".format(
+ baseStateClass=baseStateClass,
+ transition_class_list=", ".join(
+ "cls.{}".format(tn) for tn in transitions
+ ),
+ ),
+ "{baseStateClass}.transition_names = [tn.__name__ for tn in {baseStateClass}.transitions()]".format(
+ baseStateClass=baseStateClass
+ ),
+ ]
+ )
- ])
+ # define <state>Mixin class for application classes that delegate to the state
+ statedef.extend(
+ [
+ "class {baseStateClass}Mixin:".format(baseStateClass=baseStateClass),
+ " def __init__(self):",
+ " self._state = None",
+ " def initialize_state(self, init_state):",
+ " if issubclass(init_state, {baseStateClass}):".format(
+ baseStateClass=baseStateClass
+ ),
+ " init_state = init_state()",
+ " self._state = init_state",
+ " @property",
+ " def state(self):",
+ " return self._state",
+ " # get behavior/properties from current state",
+ " def __getattr__(self, attrname):",
+ " attr = getattr(self._state, attrname)",
+ " return attr",
+ " def __str__(self):",
+ " return '{0}: {1}'.format(self.__class__.__name__, self._state)",
+ ]
+ )
# define transition methods to be delegated to the _state instance variable
statedef.extend(
- " def {tn_name}(self): self._state = self._state.{tn_name}()".format(tn_name=tn)
+ " def {tn_name}(self): self._state = self._state.{tn_name}()".format(
+ tn_name=tn
+ )
for tn in transitions
)
return ("\n" + indent).join(statedef) + "\n"
+
namedStateMachine.setParseAction(expand_named_state_definition)
@@ -248,15 +278,15 @@ class SuffixImporter:
:meth:`register` on your class to actually install it in the appropriate
places in :mod:`sys`. """
- scheme = 'suffix'
+ 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
+ raise ValueError("%s.suffix is not set" % cls.__name__)
+ return "suffix:%s" % cls.suffix
@classmethod
def register(cls):
@@ -279,7 +309,7 @@ class SuffixImporter:
# it probably isn't even a filesystem path
finder = sys.path_importer_cache.get(dirpath)
if isinstance(finder, (type(None), importlib.machinery.FileFinder)):
- checkpath = os.path.join(dirpath, '{}.{}'.format(fullname, self.suffix))
+ checkpath = os.path.join(dirpath, "{}.{}".format(fullname, self.suffix))
yield checkpath
def find_module(self, fullname, path=None):
@@ -311,25 +341,26 @@ class SuffixImporter:
class PystateImporter(SuffixImporter):
- suffix = 'pystate'
+ suffix = "pystate"
def process_filedata(self, module, data):
# MATT-NOTE: re-worked :func:`get_state_machine`
# convert any statemachine expressions
- stateMachineExpr = (stateMachine | namedStateMachine).ignore(pp.pythonStyleComment)
+ stateMachineExpr = (stateMachine | namedStateMachine).ignore(
+ pp.pythonStyleComment
+ )
generated_code = stateMachineExpr.transformString(data)
- if DEBUG: print(generated_code)
+ 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'
+ COMPILE_MODE = "exec"
- codeobj = compile(generated_code.rstrip(" \t"),
- module.__file__,
- COMPILE_MODE)
+ codeobj = compile(generated_code.rstrip(" \t"), module.__file__, COMPILE_MODE)
exec(codeobj, module.__dict__)
diff --git a/examples/statemachine/vending_machine.py b/examples/statemachine/vending_machine.py
index d218608..b5fe524 100644
--- a/examples/statemachine/vending_machine.py
+++ b/examples/statemachine/vending_machine.py
@@ -22,11 +22,14 @@ statemachine VendingMachineState:
"""
# convert state machine text to state classes
-generated = statemachine.namedStateMachine.transformString(vending_machine_state_description)
+generated = statemachine.namedStateMachine.transformString(
+ vending_machine_state_description
+)
# print(generated)
# exec generated code to define state classes and state mixin
exec(generated)
+
class VendingMachine(VendingMachineStateMixin):
def __init__(self):
self.initialize_state(Idle)
@@ -42,7 +45,7 @@ class VendingMachine(VendingMachineStateMixin):
self._pressed = button
self.press_digit_button()
else:
- print('Did not recognize button {!r}'.format(str(button)))
+ print("Did not recognize button {!r}".format(str(button)))
def press_alpha_button(self):
try:
diff --git a/examples/statemachine/video_demo.py b/examples/statemachine/video_demo.py
index fadfb9d..f6dbc8f 100644
--- a/examples/statemachine/video_demo.py
+++ b/examples/statemachine/video_demo.py
@@ -20,25 +20,29 @@ v = Video("Die Hard.mp4")
while True:
print(v.state)
- cmd = input("Command ({})> ".format('/'.join(videostate.VideoState.transition_names))).lower().strip()
+ cmd = (
+ input("Command ({})> ".format("/".join(videostate.VideoState.transition_names)))
+ .lower()
+ .strip()
+ )
if not cmd:
continue
- if cmd in ('?', 'h', 'help'):
- print('enter a transition {!r}'.format(videostate.VideoState.transition_names))
- print(' q - quit')
- print(' ?, h, help - this message')
+ if cmd in ("?", "h", "help"):
+ print("enter a transition {!r}".format(videostate.VideoState.transition_names))
+ print(" q - quit")
+ print(" ?, h, help - this message")
continue
# quitting out
- if cmd.startswith('q'):
+ if cmd.startswith("q"):
break
# get transition function for given command
state_transition_fn = getattr(v, cmd, None)
if state_transition_fn is None:
- print('???')
+ print("???")
continue
# invoke the input transition, handle invalid commands
diff --git a/examples/test_bibparse.py b/examples/test_bibparse.py
index 12e416e..339fd7c 100644
--- a/examples/test_bibparse.py
+++ b/examples/test_bibparse.py
@@ -5,158 +5,199 @@ from pyparsing import ParseException
from .btpyparse import Macro
from . import btpyparse as bp
+
class TestBibparse(unittest.TestCase):
def test_names(self):
# 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
- self.assertEqual(name_type.parseString('2t')[0], '2t')
+ 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
+ self.assertEqual(name_type.parseString("2t")[0], "2t")
else:
- self.assertRaises(ParseException, name_type.parseString, '2t')
+ self.assertRaises(ParseException, name_type.parseString, "2t")
# All of the names cannot contain some characters
for char in bad_chars:
self.assertRaises(ParseException, name_type.parseString, char)
# standard strings all OK
- self.assertEqual(name_type.parseString('simple_test')[0], 'simple_test')
+ self.assertEqual(name_type.parseString("simple_test")[0], "simple_test")
# Test macro ref
mr = bp.macro_ref
# can't start with digit
- self.assertRaises(ParseException, mr.parseString, '2t')
+ self.assertRaises(ParseException, mr.parseString, "2t")
for char in bad_chars:
self.assertRaises(ParseException, mr.parseString, char)
- self.assertEqual(mr.parseString('simple_test')[0].name, 'simple_test')
+ self.assertEqual(mr.parseString("simple_test")[0].name, "simple_test")
def test_numbers(self):
- self.assertEqual(bp.number.parseString('1066')[0], '1066')
- self.assertEqual(bp.number.parseString('0')[0], '0')
- self.assertRaises(ParseException, bp.number.parseString, '-4')
- self.assertRaises(ParseException, bp.number.parseString, '+4')
- self.assertRaises(ParseException, bp.number.parseString, '.4')
+ self.assertEqual(bp.number.parseString("1066")[0], "1066")
+ self.assertEqual(bp.number.parseString("0")[0], "0")
+ self.assertRaises(ParseException, bp.number.parseString, "-4")
+ self.assertRaises(ParseException, bp.number.parseString, "+4")
+ self.assertRaises(ParseException, bp.number.parseString, ".4")
# something point something leaves a trailing .4 unmatched
- self.assertEqual(bp.number.parseString('0.4')[0], '0')
-
+ self.assertEqual(bp.number.parseString("0.4")[0], "0")
def test_parse_string(self):
# test string building blocks
- self.assertEqual(bp.chars_no_quotecurly.parseString('x')[0], 'x')
- self.assertEqual(bp.chars_no_quotecurly.parseString("a string")[0], 'a string')
- self.assertEqual(bp.chars_no_quotecurly.parseString('a "string')[0], 'a ')
- self.assertEqual(bp.chars_no_curly.parseString('x')[0], 'x')
- self.assertEqual(bp.chars_no_curly.parseString("a string")[0], 'a string')
- self.assertEqual(bp.chars_no_curly.parseString('a {string')[0], 'a ')
- self.assertEqual(bp.chars_no_curly.parseString('a }string')[0], 'a ')
+ self.assertEqual(bp.chars_no_quotecurly.parseString("x")[0], "x")
+ self.assertEqual(bp.chars_no_quotecurly.parseString("a string")[0], "a string")
+ self.assertEqual(bp.chars_no_quotecurly.parseString('a "string')[0], "a ")
+ self.assertEqual(bp.chars_no_curly.parseString("x")[0], "x")
+ self.assertEqual(bp.chars_no_curly.parseString("a string")[0], "a string")
+ self.assertEqual(bp.chars_no_curly.parseString("a {string")[0], "a ")
+ self.assertEqual(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):
- self.assertEqual(obj.parseString('{}').asList(), [])
+ self.assertEqual(obj.parseString("{}").asList(), [])
self.assertEqual(obj.parseString('{a "string}')[0], 'a "string')
- self.assertEqual(obj.parseString('{a {nested} string}').asList(),
- ['a ', ['nested'], ' string'])
- self.assertEqual(obj.parseString('{a {double {nested}} string}').asList(),
- ['a ', ['double ', ['nested']], ' string'])
+ self.assertEqual(
+ obj.parseString("{a {nested} string}").asList(),
+ ["a ", ["nested"], " string"],
+ )
+ self.assertEqual(
+ obj.parseString("{a {double {nested}} string}").asList(),
+ ["a ", ["double ", ["nested"]], " string"],
+ )
for obj in (bp.quoted_string, bp.string, bp.field_value):
self.assertEqual(obj.parseString('""').asList(), [])
- self.assertEqual(obj.parseString('"a string"')[0], 'a string')
- self.assertEqual(obj.parseString('"a {nested} string"').asList(),
- ['a ', ['nested'], ' string'])
- self.assertEqual(obj.parseString('"a {double {nested}} string"').asList(),
- ['a ', ['double ', ['nested']], ' string'])
+ self.assertEqual(obj.parseString('"a string"')[0], "a string")
+ self.assertEqual(
+ obj.parseString('"a {nested} string"').asList(),
+ ["a ", ["nested"], " string"],
+ )
+ self.assertEqual(
+ obj.parseString('"a {double {nested}} string"').asList(),
+ ["a ", ["double ", ["nested"]], " string"],
+ )
# check macro def in string
- self.assertEqual(bp.string.parseString('someascii')[0], Macro('someascii'))
- self.assertRaises(ParseException, bp.string.parseString, '%#= validstring')
+ self.assertEqual(bp.string.parseString("someascii")[0], Macro("someascii"))
+ self.assertRaises(ParseException, bp.string.parseString, "%#= validstring")
# check number in string
- self.assertEqual(bp.string.parseString('1994')[0], '1994')
-
+ self.assertEqual(bp.string.parseString("1994")[0], "1994")
def test_parse_field(self):
# test field value - hashes included
fv = bp.field_value
# Macro
- self.assertEqual(fv.parseString('aname')[0], Macro('aname'))
- self.assertEqual(fv.parseString('ANAME')[0], Macro('aname'))
+ self.assertEqual(fv.parseString("aname")[0], Macro("aname"))
+ self.assertEqual(fv.parseString("ANAME")[0], Macro("aname"))
# String and macro
- self.assertEqual(fv.parseString('aname # "some string"').asList(),
- [Macro('aname'), 'some string'])
+ self.assertEqual(
+ fv.parseString('aname # "some string"').asList(),
+ [Macro("aname"), "some string"],
+ )
# Nested string
- self.assertEqual(fv.parseString('aname # {some {string}}').asList(),
- [Macro('aname'), 'some ', ['string']])
+ self.assertEqual(
+ fv.parseString("aname # {some {string}}").asList(),
+ [Macro("aname"), "some ", ["string"]],
+ )
# String and number
- self.assertEqual(fv.parseString('"a string" # 1994').asList(),
- ['a string', '1994'])
+ self.assertEqual(
+ fv.parseString('"a string" # 1994').asList(), ["a string", "1994"]
+ )
# String and number and macro
- self.assertEqual(fv.parseString('"a string" # 1994 # a_macro').asList(),
- ['a string', '1994', Macro('a_macro')])
-
+ self.assertEqual(
+ fv.parseString('"a string" # 1994 # a_macro').asList(),
+ ["a string", "1994", Macro("a_macro")],
+ )
def test_comments(self):
- res = bp.comment.parseString('@Comment{about something}')
- self.assertEqual(res.asList(), ['comment', '{about something}'])
+ res = bp.comment.parseString("@Comment{about something}")
+ self.assertEqual(res.asList(), ["comment", "{about something}"])
self.assertEqual(
- bp.comment.parseString('@COMMENT{about something').asList(),
- ['comment', '{about something'])
+ bp.comment.parseString("@COMMENT{about something").asList(),
+ ["comment", "{about something"],
+ )
self.assertEqual(
- bp.comment.parseString('@comment(about something').asList(),
- ['comment', '(about something'])
+ bp.comment.parseString("@comment(about something").asList(),
+ ["comment", "(about something"],
+ )
self.assertEqual(
- bp.comment.parseString('@COMment about something').asList(),
- ['comment', ' about something'])
- self.assertRaises(ParseException, bp.comment.parseString,
- '@commentabout something')
- self.assertRaises(ParseException, bp.comment.parseString,
- '@comment+about something')
- self.assertRaises(ParseException, bp.comment.parseString,
- '@comment"about something')
-
+ bp.comment.parseString("@COMment about something").asList(),
+ ["comment", " about something"],
+ )
+ self.assertRaises(
+ ParseException, bp.comment.parseString, "@commentabout something"
+ )
+ self.assertRaises(
+ ParseException, bp.comment.parseString, "@comment+about something"
+ )
+ self.assertRaises(
+ ParseException, bp.comment.parseString, '@comment"about something'
+ )
def test_preamble(self):
res = bp.preamble.parseString('@preamble{"about something"}')
- self.assertEqual(res.asList(), ['preamble', 'about something'])
- self.assertEqual(bp.preamble.parseString(
- '@PREamble{{about something}}').asList(),
- ['preamble', 'about something'])
- self.assertEqual(bp.preamble.parseString("""@PREamble{
+ self.assertEqual(res.asList(), ["preamble", "about something"])
+ self.assertEqual(
+ bp.preamble.parseString("@PREamble{{about something}}").asList(),
+ ["preamble", "about something"],
+ )
+ self.assertEqual(
+ bp.preamble.parseString(
+ """@PREamble{
{about something}
- }""").asList(),
- ['preamble', 'about something'])
-
+ }"""
+ ).asList(),
+ ["preamble", "about something"],
+ )
def test_macro(self):
res = bp.macro.parseString('@string{ANAME = "about something"}')
- self.assertEqual(res.asList(), ['string', 'aname', 'about something'])
+ self.assertEqual(res.asList(), ["string", "aname", "about something"])
self.assertEqual(
- bp.macro.parseString('@string{aname = {about something}}').asList(),
- ['string', 'aname', 'about something'])
-
+ bp.macro.parseString("@string{aname = {about something}}").asList(),
+ ["string", "aname", "about something"],
+ )
def test_entry(self):
txt = """@some_entry{akey, aname = "about something",
another={something else}}"""
res = bp.entry.parseString(txt)
- self.assertEqual(res.asList(),
- ['some_entry', 'akey',
- ['aname', 'about something'], ['another', 'something else']])
+ self.assertEqual(
+ 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)
- self.assertEqual(res.asList(),
- ['some_entry', 'akey',
- ['aname', 'about something'], ['another', 'something else']])
-
+ self.assertEqual(
+ res.asList(),
+ [
+ "some_entry",
+ "akey",
+ ["aname", "about something"],
+ ["another", "something else"],
+ ],
+ )
def test_bibfile(self):
txt = """@some_entry{akey, aname = "about something",
another={something else}}"""
res = bp.bibfile.parseString(txt)
- self.assertEqual(res.asList(),
- [['some_entry', 'akey',
- ['aname', 'about something'],
- ['another', 'something else']]])
-
+ self.assertEqual(
+ res.asList(),
+ [
+ [
+ "some_entry",
+ "akey",
+ ["aname", "about something"],
+ ["another", "something else"],
+ ]
+ ],
+ )
def test_bib1(self):
# First pass whole bib-like tests
@@ -186,5 +227,5 @@ class TestBibparse(unittest.TestCase):
self.assertEqual(res.asList(), res3)
-if __name__ == '__main__':
+if __name__ == "__main__":
unittest.main()
diff --git a/examples/urlExtractor.py b/examples/urlExtractor.py
index 70835da..2d29200 100644
--- a/examples/urlExtractor.py
+++ b/examples/urlExtractor.py
@@ -4,11 +4,11 @@ from pyparsing import makeHTMLTags, pyparsing_common as ppc
from urllib.request import urlopen
import pprint
-linkOpenTag, linkCloseTag = makeHTMLTags('a')
+linkOpenTag, linkCloseTag = makeHTMLTags("a")
linkBody = linkOpenTag.tag_body
linkBody.setParseAction(ppc.stripHTMLTags)
-linkBody.addParseAction(lambda toks: ' '.join(toks[0].strip().split()))
+linkBody.addParseAction(lambda toks: " ".join(toks[0].strip().split()))
link = linkOpenTag + linkBody("body") + linkCloseTag.suppress()
@@ -24,6 +24,4 @@ for toks, strt, end in link.scanString(htmlText):
# Create dictionary from list comprehension, assembled from each pair of tokens returned
# from a matched URL.
-pprint.pprint(
- {toks.body: toks.href for toks, strt, end in link.scanString(htmlText)}
- )
+pprint.pprint({toks.body: toks.href for toks, strt, end in link.scanString(htmlText)})
diff --git a/examples/urlExtractorNew.py b/examples/urlExtractorNew.py
index 14f6eb1..7a6e54a 100644
--- a/examples/urlExtractorNew.py
+++ b/examples/urlExtractorNew.py
@@ -27,4 +27,4 @@ for toks, strt, end in link.scanString(htmlText):
# from a matched URL.
pprint.pprint(
{toks.body: toks.startA.href for toks, strt, end in link.scanString(htmlText)}
- )
+)
diff --git a/examples/verilogParse.py b/examples/verilogParse.py
index 2d060e6..8a809d1 100644
--- a/examples/verilogParse.py
+++ b/examples/verilogParse.py
@@ -67,11 +67,33 @@ import sys
__version__ = "1.0.11"
-from pyparsing import Literal, Keyword, Word, OneOrMore, ZeroOrMore, \
- Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, \
- alphanums, dblQuotedString, empty, ParseException, oneOf, \
- StringEnd, FollowedBy, ParserElement, Regex, cppStyleComment
+from pyparsing import (
+ Literal,
+ Keyword,
+ Word,
+ OneOrMore,
+ ZeroOrMore,
+ Forward,
+ delimitedList,
+ Group,
+ Optional,
+ Combine,
+ alphas,
+ nums,
+ restOfLine,
+ alphanums,
+ dblQuotedString,
+ empty,
+ ParseException,
+ oneOf,
+ StringEnd,
+ FollowedBy,
+ ParserElement,
+ Regex,
+ cppStyleComment,
+)
import pyparsing
+
usePackrat = False
packratOn = False
@@ -84,184 +106,269 @@ if usePackrat:
else:
packratOn = True
-def dumpTokens(s,l,t):
+
+def dumpTokens(s, l, t):
import pprint
- pprint.pprint( t.asList() )
+
+ 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")
+ compilerDirective = Combine(
+ "`"
+ + oneOf(
+ "define undef ifdef else endif default_nettype "
+ "include resetall timescale unconnected_drive "
+ "nounconnected_drive celldefine endcelldefine"
+ )
+ + restOfLine
+ ).setName("compilerDirective")
# primitives
- SEMI,COLON,LPAR,RPAR,LBRACE,RBRACE,LBRACK,RBRACK,DOT,COMMA,EQ = map(Literal,";:(){}[].,=")
-
- identLead = alphas+"$_"
- identBody = alphanums+"$_"
- identifier1 = Regex( r"\.?["+identLead+"]["+identBody+r"]*(\.["+identLead+"]["+identBody+"]*)*"
- ).setName("baseIdent")
- identifier2 = Regex(r"\\\S+").setParseAction(lambda t:t[0][1:]).setName("escapedIdent")#.setDebug()
+ SEMI, COLON, LPAR, RPAR, LBRACE, RBRACE, LBRACK, RBRACK, DOT, COMMA, EQ = map(
+ Literal, ";:(){}[].,="
+ )
+
+ identLead = alphas + "$_"
+ identBody = alphanums + "$_"
+ identifier1 = Regex(
+ r"\.?["
+ + identLead
+ + "]["
+ + identBody
+ + r"]*(\.["
+ + identLead
+ + "]["
+ + identBody
+ + "]*)*"
+ ).setName("baseIdent")
+ identifier2 = (
+ Regex(r"\\\S+").setParseAction(lambda t: t[0][1:]).setName("escapedIdent")
+ ) # .setDebug()
identifier = identifier1 | identifier2
- assert(identifier2 == r'\abc')
+ 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" + "_"
+ 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 )
+ concat = Group(LBRACE + delimitedList(expr) + RBRACE)
multiConcat = Group("{" + expr + concat + "}").setName("multiConcat")
- funcCall = Group(identifier + LPAR + Optional( delimitedList( expr ) ) + RPAR).setName("funcCall")
+ 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") ))
+ 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")
+ 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")
+ 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 ) )
- )
+ (unop + expr)
+ | (primary + "?" + expr + COLON + expr) # must be first!
+ | (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")
+ 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")
+ 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()
+ 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 + "$_")
+ | (LPAR + Group(delimitedList(mintypmaxExpr | expr)) + RPAR) # identifier |
+ ).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" )
+ 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 )
+ 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 )
+ 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
- )
+ parameterDecl | regDecl | integerDecl | realDecl | timeDecl | eventDecl
+ )
- stmt = Forward().setName("stmt")#.setDebug()
+ stmt = Forward().setName("stmt") # .setDebug()
stmtOrNull = stmt | SEMI
- caseItem = ( delimitedList( expr ) + COLON + stmtOrNull ) | \
- ( default + Optional(":") + stmtOrNull )
+ 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") |
+ (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")
+ (assgnmt + SEMI)
+ | (nbAssgnmt + SEMI)
+ | (
+ Combine(Optional("$") + identifier)
+ + Optional(LPAR + delimitedList(expr | empty) + RPAR)
+ + SEMI
+ )
+ ).setName("stmtBody")
"""
x::=<blocking_assignment> ;
x||= <non_blocking_assignment> ;
@@ -288,199 +395,359 @@ def Verilog_BNF():
x||= force <assignment> ;
x||= release <lvalue> ;
"""
- alwaysStmt = Group( "always" + Optional(eventControl) + stmt ).setName("alwaysStmt")
- initialStmt = Group( "initial" + stmt ).setName("initialStmt")
+ alwaysStmt = Group("always" + Optional(eventControl) + stmt).setName(
+ "alwaysStmt"
+ )
+ initialStmt = Group("initial" + stmt).setName("initialStmt")
- chargeStrength = Group( LPAR + oneOf( "small medium large" ) + RPAR ).setName("chargeStrength")
+ chargeStrength = Group(LPAR + oneOf("small medium large") + RPAR).setName(
+ "chargeStrength"
+ )
continuousAssign = Group(
- assign + Optional( driveStrength ) + Optional( delay ) + delimitedList( assgnmt ) + SEMI
- ).setName("continuousAssign")
-
+ assign
+ + Optional(driveStrength)
+ + Optional(delay)
+ + delimitedList(assgnmt)
+ + SEMI
+ ).setName("continuousAssign")
tfDecl = (
- parameterDecl |
- inputDecl |
- outputDecl |
- inoutDecl |
- regDecl |
- timeDecl |
- integerDecl |
- realDecl
- )
+ parameterDecl
+ | inputDecl
+ | outputDecl
+ | inoutDecl
+ | regDecl
+ | timeDecl
+ | integerDecl
+ | realDecl
+ )
functionDecl = Group(
- "function" + Optional( range | "integer" | "real" ) + identifier + SEMI +
- Group( OneOrMore( tfDecl ) ) +
- Group( ZeroOrMore( stmt ) ) +
- "endfunction"
- )
+ "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 ) ) )
+ 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)
+ 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")
+ # ~ 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 )
+ portConditionExpr << portConditionTerm + Optional(binop + portConditionExpr)
polarityOp = oneOf("+ -")
levelSensitivePathDecl1 = Group(
- if_ + Group(LPAR + portConditionExpr + RPAR) +
- subscrIdentifier + Optional( polarityOp ) + "=>" + subscrIdentifier + EQ +
- pathDelayValue +
- SEMI )
+ 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 )
+ 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 )
+ 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 )
+ 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 ))
+ 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 ) )
+ 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 ) )
+ 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
+ systemTimingCheck1 = Group(
+ "$setup"
+ + LPAR
+ + timCheckEvent
+ + COMMA
+ + timCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck2 = Group(
+ "$hold"
+ + LPAR
+ + timCheckEvent
+ + COMMA
+ + timCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck3 = Group(
+ "$period"
+ + LPAR
+ + controlledTimingCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck4 = Group(
+ "$width"
+ + LPAR
+ + controlledTimingCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + expr + COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck5 = Group(
+ "$skew"
+ + LPAR
+ + timCheckEvent
+ + COMMA
+ + timCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck6 = Group(
+ "$recovery"
+ + LPAR
+ + controlledTimingCheckEvent
+ + COMMA
+ + timCheckEvent
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck7 = Group(
+ "$setuphold"
+ + LPAR
+ + timCheckEvent
+ + COMMA
+ + timCheckEvent
+ + COMMA
+ + timCheckLimit
+ + COMMA
+ + timCheckLimit
+ + Optional(COMMA + notifyRegister)
+ + RPAR
+ + SEMI
+ )
+ systemTimingCheck = (
+ FollowedBy("$")
+ + (
+ systemTimingCheck1
+ | systemTimingCheck2
+ | systemTimingCheck3
+ | systemTimingCheck4
+ | systemTimingCheck5
+ | systemTimingCheck6
+ | systemTimingCheck7
)
+ ).setName("systemTimingCheck")
+ sdpd = (
+ if_
+ + Group(LPAR + expr + RPAR)
+ + (pathDescr1 | pathDescr2)
+ + EQ
+ + pathDelayValue
+ + SEMI
+ )
+
+ specifyItem = ~Keyword("endspecify") + (
+ specparamDecl
+ | pathDecl
+ | levelSensitivePathDecl
+ | edgeSensitivePathDecl
+ | systemTimingCheck
+ | sdpd
+ )
"""
x::= <specparam_declaration>
x||= <path_declaration>
@@ -489,33 +756,36 @@ def Verilog_BNF():
x||= <system_timing_check>
x||= <sdpd>
"""
- specifyBlock = Group( "specify" + ZeroOrMore( specifyItem ) + "endspecify" ).setName("specifyBlock")
+ 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 |
+ 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
- )
+ moduleInstantiation
+ | udpInstantiation
+ )
""" All possible moduleItems, from Verilog grammar spec
x::= <parameter_declaration>
x||= <input_declaration>
@@ -539,39 +809,55 @@ def Verilog_BNF():
x||= <function>
"""
portRef = subscrIdentifier
- portExpr = portRef | Group( LBRACE + delimitedList( portRef ) + RBRACE )
- port = portExpr | Group( DOT + identifier + LPAR + portExpr + RPAR )
-
- moduleHdr = Group ( oneOf("module macromodule") + identifier +
- Optional( LPAR + Group( Optional( delimitedList(
- Group(oneOf("input output") +
- (netDecl1Arg | netDecl2Arg | netDecl3Arg) ) |
- port ) ) ) +
- RPAR ) + SEMI ).setName("moduleHdr")
+ 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()
+ 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 = 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")
+ udpInitialStmt = Group("initial" + identifier + EQ + udpInitVal + SEMI).setName(
+ "udpInitialStmt"
+ )
levelSymbol = oneOf("0 1 x X ? b B")
- levelInputList = Group( OneOrMore( levelSymbol ).setName("levelInpList") )
+ levelInputList = Group(OneOrMore(levelSymbol).setName("levelInpList"))
outputSymbol = oneOf("0 1 x X")
- combEntry = Group( levelInputList + COLON + outputSymbol + SEMI )
+ 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 ) )
+ 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")
+ seqEntry = Group(
+ inputList + COLON + levelSymbol + COLON + (outputSymbol | "-") + SEMI
+ ).setName("seqEntry")
+ udpTableDefn = Group(
+ "table" + OneOrMore(combEntry | seqEntry) + "endtable"
+ ).setName("table")
"""
<UDP>
@@ -581,49 +867,58 @@ def Verilog_BNF():
<table_definition>
endprimitive
"""
- udp = Group( "primitive" + identifier +
- LPAR + Group( delimitedList( identifier ) ) + RPAR + SEMI +
- OneOrMore( udpDecl ) +
- Optional( udpInitialStmt ) +
- udpTableDefn +
- "endprimitive" )
-
- verilogbnf = OneOrMore( module | udp ) + StringEnd()
-
- verilogbnf.ignore( cppStyleComment )
- verilogbnf.ignore( compilerDirective )
+ 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 ):
+def test(strng):
tokens = []
try:
- tokens = Verilog_BNF().parseString( strng )
+ tokens = Verilog_BNF().parseString(strng)
except ParseException as err:
print(err.line)
- print(" "*(err.column-1) + "^")
+ print(" " * (err.column - 1) + "^")
print(err)
return tokens
-#~ if __name__ == "__main__":
+# ~ 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() )
+ 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 packratOn:
+ print(" - using packrat parsing")
print()
import os
@@ -634,41 +929,41 @@ else:
numlines = 0
startTime = time.clock()
fileDir = "verilog"
- #~ fileDir = "verilog/new"
- #~ fileDir = "verilog/new2"
- #~ fileDir = "verilog/new3"
+ # ~ 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" ]
+ # ~ 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 )
+ pp = pprint.PrettyPrinter(indent=2)
totalTime = 0
for vfile in allFiles:
gc.collect()
- fnam = fileDir + "/"+vfile
+ fnam = fileDir + "/" + vfile
infile = open(fnam)
filelines = infile.readlines()
infile.close()
- print(fnam, len(filelines), end=' ')
+ print(fnam, len(filelines), end=" ")
numlines += len(filelines)
teststr = "".join(filelines)
time1 = time.clock()
- tokens = test( teststr )
+ tokens = test(teststr)
time2 = time.clock()
- elapsed = time2-time1
+ elapsed = time2 - time1
totalTime += elapsed
- if ( len( tokens ) ):
+ if len(tokens):
print("OK", elapsed)
- #~ print "tokens="
- #~ pp.pprint( tokens.asList() )
- #~ print
+ # ~ print "tokens="
+ # ~ pp.pprint( tokens.asList() )
+ # ~ print
ofnam = fileDir + "/parseOutput/" + vfile + ".parsed.txt"
- outfile = open(ofnam,"w")
- outfile.write( teststr )
+ outfile = open(ofnam, "w")
+ outfile.write(teststr)
outfile.write("\n")
outfile.write("\n")
outfile.write(pp.pformat(tokens.asList()))
@@ -677,12 +972,12 @@ else:
else:
print("failed", elapsed)
failCount += 1
- for i,line in enumerate(filelines,1):
- print("%4d: %s" % (i,line.rstrip()))
+ 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 ) ) ))
+ print("Average lines/sec:", ("%.1f" % (float(numlines) / (totalTime + 0.05))))
if failCount:
print("FAIL - %d files failed to parse" % failCount)
else:
@@ -690,16 +985,16 @@ else:
return 0
- #~ from line_profiler import LineProfiler
- #~ from pyparsing import ParseResults
- #~ lp = LineProfiler(ParseResults.__init__)
+ # ~ 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()
+ # ~ lp.print_stats()
+ # ~ import hotshot
+ # ~ p = hotshot.Profile("vparse.prof",1,1)
+ # ~ p.start()
+ # ~ main()
+ # ~ p.stop()
+ # ~ p.close()
diff --git a/examples/wordsToNum.py b/examples/wordsToNum.py
index 71538ba..99eddab 100644
--- a/examples/wordsToNum.py
+++ b/examples/wordsToNum.py
@@ -7,73 +7,82 @@ import pyparsing as pp
from operator import mul
from functools import reduce
+
def makeLit(s, val):
ret = pp.CaselessLiteral(s)
return ret.setParseAction(pp.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),
+ ("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 = pp.MatchFirst(makeLit(s,v) for s,v in sorted(unitDefinitions, key=lambda d: -len(d[0])))
+ ("eighteen", 18),
+ ("nineteen", 19),
+]
+units = pp.MatchFirst(
+ makeLit(s, v) for s, v in sorted(unitDefinitions, key=lambda d: -len(d[0]))
+)
tensDefinitions = [
- ("ten", 10),
- ("twenty", 20),
- ("thirty", 30),
- ("forty", 40),
- ("fourty", 40), # for the spelling-challenged...
- ("fifty", 50),
- ("sixty", 60),
+ ("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 = pp.MatchFirst(makeLit(s,v) for s,v in tensDefinitions)
+ ("eighty", 80),
+ ("ninety", 90),
+]
+tens = pp.MatchFirst(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)),
+ ("thousand", int(1e3)),
+ ("million", int(1e6)),
+ ("billion", int(1e9)),
+ ("trillion", int(1e12)),
("quadrillion", int(1e15)),
("quintillion", int(1e18)),
- ]
-mag = pp.MatchFirst(makeLit(s,v) for s,v in majorDefinitions)
-
-wordprod = lambda t: reduce(mul,t)
-numPart = ((((units + pp.Optional(hundreds)).setParseAction(wordprod)
- + pp.Optional(tens)
- ).setParseAction(sum)
- ^ tens)
- + pp.Optional(units)
- ).setParseAction(sum)
-numWords = ((numPart + pp.Optional(mag)).setParseAction(wordprod)[1, ...]).setParseAction(sum)
+]
+mag = pp.MatchFirst(makeLit(s, v) for s, v in majorDefinitions)
+
+wordprod = lambda t: reduce(mul, t)
+numPart = (
+ (
+ (
+ (units + pp.Optional(hundreds)).setParseAction(wordprod) + pp.Optional(tens)
+ ).setParseAction(sum)
+ ^ tens
+ )
+ + pp.Optional(units)
+).setParseAction(sum)
+numWords = (
+ (numPart + pp.Optional(mag)).setParseAction(wordprod)[1, ...]
+).setParseAction(sum)
numWords.setName("num word parser")
numWords.ignore(pp.Literal("-"))
@@ -98,13 +107,20 @@ tests = """
"""
# use '| ...' to indicate "if omitted, skip to next" logic
-test_expr = (numWords('result') | ...) + ',' + (pp.pyparsing_common.integer('expected') | 'None')
+test_expr = (
+ (numWords("result") | ...)
+ + ","
+ + (pp.pyparsing_common.integer("expected") | "None")
+)
+
def verify_result(t):
- if '_skipped' in t:
- t['pass'] = False
- elif 'expected' in t:
- t['pass'] = t.result == t.expected
+ if "_skipped" in t:
+ t["pass"] = False
+ elif "expected" in t:
+ t["pass"] = t.result == t.expected
+
+
test_expr.addParseAction(verify_result)
test_expr.runTests(tests)