compiler.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. from cached_exception import CachedException
  8. global parsers
  9. parsers = {}
  10. sys.setrecursionlimit(2000)
  11. def read(filename):
  12. with open(filename, 'r') as f:
  13. return f.read()
  14. def do_parse(inputfile, grammarfile):
  15. new_grammar = True
  16. picklefile = grammarfile + ".pickle"
  17. if grammarfile not in parsers:
  18. try:
  19. if os.path.getmtime(picklefile) > os.path.getmtime(grammarfile):
  20. # Pickle is more recent than grammarfile, so use it
  21. grammar = pickle.load(open(picklefile, 'rb'))
  22. new_grammar = False
  23. else:
  24. # Will be catched immediately
  25. raise Exception()
  26. except:
  27. result = parser = Parser(Grammar(), hide_implicit = True).parse(read(grammarfile))
  28. if result['status'] != Parser.Constants.Success:
  29. print 'not a valid grammar!'
  30. print result
  31. tree = result['tree']
  32. visitor = GrammarCompilerVisitor()
  33. structure = visitor.visit(tree)
  34. grammar = Grammar()
  35. grammar.rules = structure['rules']
  36. grammar.tokens = structure['tokens']
  37. pickle.dump(grammar, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
  38. parsers[grammarfile] = grammar
  39. else:
  40. new_grammar = False
  41. grammar = parsers[grammarfile]
  42. picklefile = inputfile + ".pickle"
  43. try:
  44. if os.path.getmtime(picklefile) > os.path.getmtime(inputfile):
  45. # Pickle is more recent than inputfile, so use it
  46. result = pickle.load(open(picklefile, 'rb'))
  47. else:
  48. # Inputfile has changed
  49. raise Exception()
  50. except:
  51. result = Parser(grammar, line_position = True).parse(read(inputfile))
  52. if result['status'] != Parser.Constants.Success:
  53. msg = "%s:%s:%s: %s" % (inputfile, result["line"], result["column"], result["text"])
  54. raise Exception(msg)
  55. pickle.dump(result, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
  56. return result
  57. def find_file(filename, include_paths):
  58. import os.path
  59. include_paths = ["."] + \
  60. [os.path.abspath(os.path.dirname(working_file))] + \
  61. [os.path.abspath("%s/../includes/" % (os.path.dirname(os.path.abspath(__file__))))] + \
  62. include_paths + \
  63. []
  64. attempts = []
  65. for include in include_paths:
  66. testfile = include + os.sep + filename
  67. if os.path.isfile(os.path.abspath(testfile)):
  68. return os.path.abspath(testfile)
  69. else:
  70. attempts.append(os.path.abspath(testfile))
  71. else:
  72. raise Exception("Could not resolve file %s. Tried: %s" % (filename, attempts))
  73. def do_compile(inputfile, grammarfile, visitors=[], include_paths = []):
  74. import os.path
  75. global working_file
  76. working_file = os.path.abspath(inputfile)
  77. result = do_parse(inputfile, grammarfile)
  78. error = result["status"] != Parser.Constants.Success
  79. if error:
  80. msg = "%s:%s:%s: %s" % (inputfile, result["line"], result["column"], result["text"])
  81. raise Exception(msg)
  82. else:
  83. for child in result["tree"].tail:
  84. child.inputfile = inputfile
  85. included = set()
  86. while True:
  87. for i, v in enumerate(result["tree"].tail):
  88. if v.head == "include":
  89. # Expand this node
  90. for j in v.tail:
  91. if j.head == "STRVALUE":
  92. f = str(j.tail[0])[1:-1]
  93. if f in included:
  94. subtree = []
  95. else:
  96. name = str(j.tail[0])[1:-1]
  97. subtree = do_parse(find_file(name, include_paths), grammarfile)["tree"].tail
  98. if subtree is None:
  99. raise Exception("Parsing error for included file %s" % find_file(name, include_paths))
  100. for t in subtree:
  101. t.inputfile = name
  102. included.add(f)
  103. # Found the string value, so break from the inner for ("searching for element")
  104. break
  105. # Merge all nodes in
  106. before = result["tree"].tail[:i]
  107. after = result["tree"].tail[i+1:]
  108. result["tree"].tail = before + subtree + after
  109. # Found an include node, but to prevent corruption of the tree, we need to start over again, so break from the outer for loop
  110. break
  111. else:
  112. # The outer for finally finished, so there were no includes remaining, thus terminate the infinite while loop
  113. break
  114. result["tree"].fix_tracability(inputfile)
  115. for visitor in visitors:
  116. visitor.visit(result["tree"])
  117. if visitors:
  118. return visitors[-1].dump()
  119. def main(input_file, grammar_file, mode, args=[], symbols=None):
  120. from prettyprint_visitor import PrettyPrintVisitor
  121. from prettyprint_visitor import PrintVisitor
  122. from semantics_visitor import SemanticsVisitor
  123. from bootstrap_visitor import BootstrapVisitor
  124. from primitives_visitor import PrimitivesVisitor
  125. from primitives_object_visitor import PrimitivesObjectVisitor
  126. from constructors_visitor import ConstructorsVisitor
  127. from constructors_object_visitor import ConstructorsObjectVisitor
  128. from model_visitor import ModelVisitor
  129. from model_bootstrap_visitor import ModelBootstrapVisitor
  130. from model_object_visitor import ModelObjectVisitor
  131. modes = {
  132. "N" : [],
  133. "P" : [PrintVisitor],
  134. "PP" : [PrettyPrintVisitor],
  135. "S" : [SemanticsVisitor],
  136. "PS" : [SemanticsVisitor, PrimitivesVisitor],
  137. "PO" : [SemanticsVisitor, PrimitivesObjectVisitor],
  138. "BS" : [SemanticsVisitor, BootstrapVisitor],
  139. "CS" : [SemanticsVisitor, ConstructorsVisitor],
  140. "CO" : [SemanticsVisitor, ConstructorsObjectVisitor],
  141. "M" : [ModelVisitor],
  142. "MB" : [ModelBootstrapVisitor],
  143. "MO" : [ModelObjectVisitor],
  144. }
  145. try:
  146. visitors = [v(args) for v in modes[mode]]
  147. result = do_compile(input_file, grammar_file, visitors)
  148. if symbols is not None and mode == "BS":
  149. symbols.update(visitors[-1].object_symbols)
  150. except CachedException:
  151. return True
  152. return result
  153. if __name__ == "__main__":
  154. if len(sys.argv) <= 2:
  155. print("Invocation: ")
  156. print(" %s input_file grammar_file mode [mode_params]*" % sys.argv[0])
  157. sys.exit(1)
  158. else:
  159. value = main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:])
  160. if value is not None:
  161. print(value)