template.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python
  2. """
  3. Template of a pyBison parser file
  4. This is actually a working parser, but so
  5. minimal as to be totally useless. Refer to the
  6. '.on_someTarget()' rule handler in the class
  7. 'Parser' below for more info.
  8. You can do much worse than to copy this file
  9. somewhere, and tinker away to your heart's content.
  10. """
  11. import sys, traceback
  12. from bison import BisonParser, BisonNode
  13. # -------------------------------------------
  14. # Our own custom base class for all objects
  15. # which get inserted into the parse tree
  16. # -------------------------------------------
  17. class ParseNode(BisonNode):
  18. """
  19. This is the base class from which all your
  20. parse nodes are derived.
  21. Add methods to this class as you need them
  22. """
  23. def __init__(self, **kw):
  24. BisonNode.__init__(self, **kw)
  25. def __str__(self):
  26. """Customise as needed"""
  27. return "<%s instance at 0x%x>" % (self.__class__.__name__, hash(self))
  28. def __repr__(self):
  29. """Customise as needed"""
  30. return str(self)
  31. def dump(self, indent=0):
  32. """
  33. Dump out human-readable, indented parse tree
  34. Customise as needed - here, or in the node-specific subclasses
  35. """
  36. BisonNode.dump(self, indent) # alter as needed
  37. # ----------------------------------------------------
  38. # Now, we need to define a node class for each parse
  39. # target. (This is completely optional, but it can
  40. # turn out to be a PITA if you don't).
  41. # ----------------------------------------------------
  42. class someTarget_Node(ParseNode):
  43. """
  44. Holds a "someTarget" parse target and its components.
  45. """
  46. def __init__(self, **kw):
  47. ParseNode.__init__(self, **kw)
  48. def dump(self, indent=0):
  49. ParseNode.dump(self, indent)
  50. # ----------------------------------------------------
  51. # Now, at last, we get to the main Parser class itself
  52. # ----------------------------------------------------
  53. class Parser(BisonParser):
  54. """
  55. Describe your parser here
  56. """
  57. # basename of binary parser engine dynamic lib
  58. bisonEngineLibName = "template-engine"
  59. # ----------------------------------------------------------------
  60. # lexer tokens - these must match those in your lex script (below)
  61. # ----------------------------------------------------------------
  62. tokens = [ 'WORD' ]
  63. # ------------------------------
  64. # precedences
  65. # ------------------------------
  66. precedences = (
  67. #('left', ('aTarget1', 'aTarget2',..., 'aTargetn')),
  68. #('right', ('another_target1', 'another_target2',..., 'another_targetn')),
  69. )
  70. # ---------------------------------------------------------------
  71. # These methods are the python handlers for the bison targets.
  72. # (which get called by the bison code each time the corresponding
  73. # parse target is unambiguously reached)
  74. #
  75. # WARNING - don't touch the method docstrings unless you know what
  76. # you are doing - they are in bison rule syntax, and are passed
  77. # verbatim to bison to build the parser engine library.
  78. # ---------------------------------------------------------------
  79. # Declare the start target here (by name)
  80. start = "someTarget"
  81. def on_someTarget(self, target, option, names, values):
  82. """
  83. someTarget
  84. :
  85. | someTarget WORD
  86. """
  87. print "on_someTarget: %s %s" % (option, repr(values))
  88. node = someTarget_Node(target=target,
  89. option=option,
  90. names=names,
  91. values=values)
  92. return node
  93. # -----------------------------------------
  94. # raw lex script, verbatim here
  95. #
  96. # the script used here in this template is one which
  97. # breaks up the input stream into strings of
  98. # alphanumeric 'words' and discards everything else
  99. # -----------------------------------------
  100. lexscript = r"""
  101. %{
  102. #include <stdio.h>
  103. #include <string.h>
  104. #include "Python.h"
  105. #define YYSTYPE void *
  106. #include "tokens.h"
  107. int yylineno = 0;
  108. int yywrap() { return(1); }
  109. extern void *py_parser;
  110. extern void (*py_input)(PyObject *parser, char *buf, int *result, int max_size);
  111. #define returntoken(tok) yylval = PyString_FromString(strdup(yytext)); return (tok);
  112. #define YY_INPUT(buf,result,max_size) { (*py_input)(py_parser, buf, &result, max_size); }
  113. %}
  114. %%
  115. [a-zA-Z0-9\.]+ { returntoken(WORD); }
  116. [ \t\n] { /* ignore spaces/tabs/newlines */ }
  117. . { printf("unknown char %c ignored\n", yytext[0]); /* ignore bad chars */}
  118. %%
  119. //yywrap() { return(1); }
  120. """
  121. # -----------------------------------------
  122. # end raw lex script
  123. # -----------------------------------------
  124. # --------------------------------------------------
  125. # global functions to add in unit-testing our parser
  126. # (same as what gets generated by bison2py)
  127. # --------------------------------------------------
  128. def usage():
  129. print "%s: PyBison template parser" % sys.argv[0]
  130. print "Usage: %s [-k] [-v] [-d] [filename]" % sys.argv[0]
  131. print " -k Keep temporary files used in building parse engine lib"
  132. print " -v Enable verbose messages while parser is running"
  133. print " -d Enable garrulous debug messages from parser engine"
  134. print " filename path of a file to parse, defaults to stdin"
  135. def main(*args):
  136. """
  137. Unit-testing func
  138. """
  139. keepfiles = 0
  140. verbose = 0
  141. debug = 0
  142. filename = None
  143. for s in ["-h", "-help", "--h", "--help", "-?"]:
  144. if s in args:
  145. usage()
  146. sys.exit(0)
  147. if len(args) > 0:
  148. if "-k" in args:
  149. keepfiles = 1
  150. args.remove("-k")
  151. if "-v" in args:
  152. verbose = 1
  153. args.remove("-v")
  154. if "-d" in args:
  155. debug = 1
  156. args.remove("-d")
  157. if len(args) > 0:
  158. filename = args[0]
  159. p = Parser(verbose=verbose, keepfiles=keepfiles)
  160. if filename == None:
  161. print "(Reading from standard input - please type stuff)"
  162. tree = p.run(file=filename, debug=debug)
  163. return tree
  164. if __name__ == "__main__":
  165. main(*(sys.argv[1:]))