diff options
Diffstat (limited to 'examples/apicheck.py')
-rw-r--r-- | examples/apicheck.py | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/examples/apicheck.py b/examples/apicheck.py new file mode 100644 index 0000000..7bca41a --- /dev/null +++ b/examples/apicheck.py @@ -0,0 +1,58 @@ +# apicheck.py
+# A simple source code scanner for finding patterns of the form
+# [ procname1 $arg1 $arg2 ]
+# and verifying the number of arguments
+#
+# Copyright (c) 2004-2016, Paul McGuire
+#
+
+from pyparsing import *
+
+# define punctuation and simple tokens for locating API calls
+LBRACK,RBRACK,LBRACE,RBRACE = map(Suppress,"[]{}")
+ident = Word(alphas,alphanums+"_") | QuotedString("{",endQuoteChar="}")
+arg = "$" + ident
+
+# define an API call with a specific number of arguments - using '-'
+# will ensure that after matching procname, an incorrect number of args will
+# raise a ParseSyntaxException, which will interrupt the scanString
+def apiProc(name, numargs):
+ return LBRACK + Keyword(name)("procname") - arg*numargs + RBRACK
+
+# create an apiReference, listing all API functions to be scanned for, and
+# their respective number of arguments. Beginning the overall expression
+# with FollowedBy allows us to quickly rule out non-api calls while scanning,
+# since all of the api calls begin with a "["
+apiRef = FollowedBy("[") + MatchFirst([
+ apiProc("procname1", 2),
+ apiProc("procname2", 1),
+ apiProc("procname3", 2),
+ ])
+
+test = """[ procname1 $par1 $par2 ]
+ other code here
+ [ procname1 $par1 $par2 $par3 ]
+ more code here
+ [ procname1 $par1 ]
+ [ procname3 ${arg with spaces} $par2 ]"""
+
+
+# now explicitly iterate through the scanner using next(), so that
+# we can trap ParseSyntaxException's that would be raised due to
+# an incorrect number of arguments. If an exception does occur,
+# then see how we reset the input text and scanner to advance to the
+# next line of source code
+api_scanner = apiRef.scanString(test)
+while 1:
+ try:
+ t,s,e = next(api_scanner)
+ print("found %s on line %d" % (t.procname, lineno(s,test)))
+ except ParseSyntaxException as pe:
+ print("invalid arg count on line", pe.lineno)
+ print(pe.lineno,':',pe.line)
+ # reset api scanner to start after this exception location
+ test = "\n"*(pe.lineno-1)+test[pe.loc+1:]
+ api_scanner = apiRef.scanString(test)
+ except StopIteration:
+ break
+
|