compiler.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import cPickle as pickle
  2. import os
  3. import sys
  4. from grammar_compiler_visitor import GrammarCompilerVisitor
  5. from hutnparser import Parser, Tree
  6. from meta_grammar import Grammar
  7. global parsers
  8. parsers = {}
  9. def read(filename):
  10. with open(filename, 'r') as f:
  11. return f.read()
  12. def do_parse(inputfile, grammarfile):
  13. new_grammar = True
  14. picklefile = grammarfile + ".pickle"
  15. if grammarfile not in parsers:
  16. try:
  17. if os.path.getmtime(picklefile) > os.path.getmtime(grammarfile):
  18. # Pickle is more recent than grammarfile, so use it
  19. grammar = pickle.load(open(picklefile, 'rb'))
  20. new_grammar = False
  21. else:
  22. # Will be catched immediately
  23. raise Exception("Pickle is invalid!")
  24. except:
  25. result = parser = Parser(Grammar(), hide_implicit = True).parse(read(grammarfile))
  26. if result['status'] != Parser.Constants.Success:
  27. print 'not a valid grammar!'
  28. print result
  29. tree = result['tree']
  30. visitor = GrammarCompilerVisitor()
  31. structure = visitor.visit(tree)
  32. grammar = Grammar()
  33. grammar.rules = structure['rules']
  34. grammar.tokens = structure['tokens']
  35. pickle.dump(grammar, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
  36. parsers[grammarfile] = grammar
  37. else:
  38. new_grammar = False
  39. grammar = parsers[grammarfile]
  40. picklefile = inputfile + ".pickle"
  41. try:
  42. if new_grammar:
  43. # Stop anyway, as the grammar is new
  44. raise Exception()
  45. if os.path.getmtime(picklefile) > os.path.getmtime(inputfile):
  46. # Pickle is more recent than inputfile, so use it
  47. result = pickle.load(open(picklefile, 'rb'))
  48. else:
  49. # Inputfile has changed
  50. raise Exception()
  51. except:
  52. result = Parser(grammar, line_position = True).parse(read(inputfile))
  53. if result['status'] != Parser.Constants.Success:
  54. print('not a valid input file: %s' % inputfile)
  55. print(result)
  56. pickle.dump(result, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
  57. return result
  58. def find_file(filename, include_paths):
  59. import os.path
  60. include_paths = ["."] + \
  61. [os.path.abspath(os.path.dirname(working_file))] + \
  62. [os.path.abspath("%s/../includes/" % (os.path.dirname(os.path.abspath(__file__))))] + \
  63. include_paths + \
  64. []
  65. attempts = []
  66. for include in include_paths:
  67. testfile = include + os.sep + filename
  68. if os.path.isfile(os.path.abspath(testfile)):
  69. return os.path.abspath(testfile)
  70. else:
  71. attempts.append(os.path.abspath(testfile))
  72. else:
  73. raise Exception("Could not resolve file %s. Tried: %s" % (filename, attempts))
  74. def do_compile(inputfile, grammarfile, compile_visitor = None, compile_visitor2 = None, include_paths = []):
  75. import os.path
  76. global working_file
  77. working_file = os.path.abspath(inputfile)
  78. result = do_parse(inputfile, grammarfile)
  79. error = result["status"] != Parser.Constants.Success
  80. if error:
  81. print 'not a valid input file!'
  82. print '{}:{}: error: {}'.format(result['line'], result['column'],
  83. result['text'])
  84. for r in result['partialresults']:
  85. print r
  86. if isinstance(r['tree'], Tree):
  87. print r['tree'].head, [x.head for x in r['tree'].tail if hasattr(x, 'head')]
  88. # print "-"*20+"partial-result"+"-"*20
  89. # from prettyprint_visitor import PrintVisitor
  90. # pv = PrintVisitor()
  91. # pv.visit(r['tree'])
  92. # print pv.dump()
  93. else:
  94. for child in result["tree"].tail:
  95. child.inputfile = inputfile
  96. included = set()
  97. while True:
  98. for i, v in enumerate(result["tree"].tail):
  99. if v.head == "include":
  100. # Expand this node
  101. for j in v.tail:
  102. if j.head == "STRVALUE":
  103. f = str(j.tail[0])[1:-1]
  104. if f in included:
  105. subtree = []
  106. else:
  107. # print find_file(str(j.tail[0])[1:-1], include_paths)
  108. # print do_parse(find_file(str(j.tail[0])[1:-1], include_paths), grammarfile)
  109. name = str(j.tail[0])[1:-1]
  110. subtree = do_parse(find_file(name, include_paths), grammarfile)["tree"].tail
  111. if subtree is None:
  112. if compile_visitor is None:
  113. return False
  114. else:
  115. return None
  116. for t in subtree:
  117. t.inputfile = name
  118. included.add(f)
  119. # Found the string value, so break from the inner for ("searching for element")
  120. break
  121. # Merge all nodes in
  122. before = result["tree"].tail[:i]
  123. after = result["tree"].tail[i+1:]
  124. result["tree"].tail = before + subtree + after
  125. # Found an include node, but to prevent corruption of the tree, we need to start over again, so break from the outer for loop
  126. break
  127. else:
  128. # The outer for finally finished, so there were no includes remaining, thus terminate the infinite while loop
  129. break
  130. if compile_visitor is None:
  131. return not error
  132. else:
  133. if error:
  134. return None
  135. else:
  136. try:
  137. compile_visitor.visit(result["tree"])
  138. if compile_visitor2:
  139. compile_visitor2.visit(result["tree"])
  140. except RuntimeError as e:
  141. print e.message
  142. sys.exit(1)
  143. if compile_visitor2:
  144. return compile_visitor2.dump()
  145. else:
  146. return compile_visitor.dump()
  147. def main(input_file, grammar_file, mode, args):
  148. if mode == "None":
  149. visitor = None
  150. visitor2 = None
  151. elif mode == "PP":
  152. from prettyprint_visitor import PrettyPrintVisitor
  153. visitor = PrettyPrintVisitor()
  154. visitor2 = None
  155. elif mode == "P":
  156. from prettyprint_visitor import PrintVisitor
  157. visitor = PrintVisitor()
  158. visitor2 = None
  159. elif mode == "S":
  160. from semantics_visitor import SemanticsVisitor
  161. visitor = SemanticsVisitor()
  162. visitor2 = None
  163. elif mode == "SP":
  164. from semantics_visitor import SemanticsVisitor
  165. from prettyprint_visitor import PrettyPrintVisitor
  166. visitor = SemanticsVisitor()
  167. visitor2 = PrettyPrintVisitor()
  168. elif mode == "BS":
  169. from semantics_visitor import SemanticsVisitor
  170. from bootstrap_visitor import BootstrapVisitor
  171. visitor = SemanticsVisitor()
  172. visitor2 = BootstrapVisitor(args)
  173. elif mode == "PS":
  174. from semantics_visitor import SemanticsVisitor
  175. from primitives_visitor import PrimitivesVisitor
  176. visitor = SemanticsVisitor()
  177. visitor2 = PrimitivesVisitor(args)
  178. elif mode == "PO":
  179. from semantics_visitor import SemanticsVisitor
  180. from primitives_object_visitor import PrimitivesObjectVisitor
  181. visitor = SemanticsVisitor()
  182. visitor2 = PrimitivesObjectVisitor(args)
  183. elif mode == "CS":
  184. from semantics_visitor import SemanticsVisitor
  185. from constructors_visitor import ConstructorsVisitor
  186. visitor = SemanticsVisitor()
  187. visitor2 = ConstructorsVisitor(args)
  188. elif mode == "CO":
  189. from semantics_visitor import SemanticsVisitor
  190. from constructors_object_visitor import ConstructorsObjectVisitor
  191. visitor = SemanticsVisitor()
  192. visitor2 = ConstructorsObjectVisitor(args)
  193. else:
  194. print("Visitor not understood: " + str(mode))
  195. sys.exit(1)
  196. return do_compile(input_file, grammar_file, visitor, visitor2)
  197. if __name__ == "__main__":
  198. if len(sys.argv) <= 2:
  199. print("Invocation: ")
  200. print(" %s input_file grammar_file [mode]" % sys.argv[0])
  201. sys.exit(1)
  202. else:
  203. value = main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:])
  204. if value is None:
  205. sys.exit(1)
  206. else:
  207. if isinstance(value, list):
  208. print '\n'.join([repr(x) for x in value])
  209. sys.exit(0)