1 #!/usr/bin/env python 2 3 from errors import * 4 from os import rename 5 from os.path import abspath, exists, join, split 6 from pyparser import error 7 from subprocess import Popen, PIPE 8 from time import time 9 import importer, deducer, optimiser, generator, translator 10 import sys 11 12 libdirs = [ 13 join(split(__file__)[0], "lib"), 14 "/usr/share/lichen/lib" 15 ] 16 17 def load_module(filename, module_name): 18 for libdir in libdirs: 19 path = join(libdir, filename) 20 if exists(path): 21 return i.load_from_file(path, module_name) 22 return None 23 24 def show_missing(missing): 25 missing = list(missing) 26 missing.sort() 27 for module_name, name in missing: 28 print >>sys.stderr, "Module %s references an unknown object: %s" % (module_name, name) 29 30 def show_syntax_error(exc): 31 print >>sys.stderr, "Syntax error at column %d on line %d in file %s:" % (exc.offset, exc.lineno, exc.filename) 32 print >>sys.stderr 33 print >>sys.stderr, exc.text.rstrip() 34 print >>sys.stderr, " " * exc.offset + "^" 35 36 def stopwatch(activity, now): 37 print >>sys.stderr, "%s took %.2f seconds" % (activity, time() - now) 38 return time() 39 40 def call(tokens, verbose=False): 41 out = not verbose and PIPE or None 42 cmd = Popen(tokens, stdout=out, stderr=out) 43 stdout, stderr = cmd.communicate() 44 return cmd.wait() 45 46 # Main program. 47 48 if __name__ == "__main__": 49 args = sys.argv[1:] 50 path = libdirs 51 52 # Determine the options and arguments. 53 54 debug = False 55 make = True 56 make_verbose = True 57 reset = False 58 traceback = False 59 verbose = False 60 61 filenames = [] 62 outputs = [] 63 64 # Obtain program filenames by default. 65 66 l = filenames 67 68 for arg in args: 69 if arg == "-c": make = False 70 elif arg == "-g": debug = True 71 elif arg == "-q": make_verbose = False 72 elif arg == "-r": reset = True 73 elif arg == "-tb": traceback = True 74 elif arg == "-o": l = outputs 75 elif arg == "-v": verbose = True 76 else: 77 l.append(arg) 78 79 # Revert to collecting program filenames after obtaining the output 80 # executable filename. 81 82 if l is outputs: l = filenames 83 84 # Obtain the program filename. 85 86 if len(filenames) > 1: 87 print >>sys.stderr, "Only one main program file can be specified." 88 sys.exit(1) 89 90 filename = abspath(filenames[0]) 91 path.append(split(filename)[0]) 92 93 # Obtain the output filename. 94 95 output = outputs and outputs[0] or "_main" 96 97 # Define the output data directories. 98 99 datadir = "_lplc" 100 cache_dir = join(datadir, "_cache") 101 deduced_dir = join(datadir, "_deduced") 102 output_dir = join(datadir, "_output") 103 generated_dir = join(datadir, "_generated") 104 105 # Load the program. 106 107 try: 108 start = now = time() 109 110 i = importer.Importer(path, cache_dir, verbose) 111 m = i.initialise(filename, reset) 112 success = i.finalise() 113 114 now = stopwatch("Inspection", now) 115 116 # Check for success, indicating missing references otherwise. 117 118 if not success: 119 show_missing(i.missing) 120 sys.exit(1) 121 122 d = deducer.Deducer(i, deduced_dir) 123 d.to_output() 124 125 now = stopwatch("Deduction", now) 126 127 o = optimiser.Optimiser(i, d, output_dir) 128 o.to_output() 129 130 now = stopwatch("Optimisation", now) 131 132 g = generator.Generator(i, o, generated_dir) 133 g.to_output(debug) 134 135 now = stopwatch("Generation", now) 136 137 t = translator.Translator(i, d, o, generated_dir) 138 t.to_output() 139 140 now = stopwatch("Translation", now) 141 142 # Compile the program unless otherwise indicated. 143 144 if make: 145 make_clean_cmd = ["make", "-C", generated_dir, "clean"] 146 make_cmd = make_clean_cmd[:-1] 147 148 retval = call(make_clean_cmd, make_verbose) 149 if not retval: 150 retval = call(make_cmd, make_verbose) 151 152 if not retval: 153 stopwatch("Compilation", now) 154 else: 155 sys.exit(retval) 156 157 # Move the executable into the current directory. 158 159 rename(join(generated_dir, "main"), output) 160 161 # Report any errors. 162 163 except error.SyntaxError, exc: 164 show_syntax_error(exc) 165 if traceback: 166 raise 167 sys.exit(1) 168 169 except ProcessingError, exc: 170 print exc 171 if traceback: 172 raise 173 sys.exit(1) 174 175 else: 176 sys.exit(0) 177 178 # vim: tabstop=4 expandtab shiftwidth=4