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 + sys.path[:] 51 52 # Determine the options and arguments. 53 54 verbose = False 55 reset = False 56 debug = False 57 make = True 58 make_verbose = True 59 60 filenames = [] 61 outputs = [] 62 63 # Obtain program filenames by default. 64 65 l = filenames 66 67 for arg in args: 68 if arg == "-v": verbose = True 69 elif arg == "-r": reset = True 70 elif arg == "-g": debug = True 71 elif arg == "-c": make = False 72 elif arg == "-q": make_verbose = False 73 elif arg == "-o": l = outputs 74 else: 75 l.append(arg) 76 77 # Revert to collecting program filenames after obtaining the output 78 # executable filename. 79 80 if l is outputs: l = filenames 81 82 # Obtain the program filename. 83 84 if len(filenames) > 1: 85 print >>sys.stderr, "Only one main program file can be specified." 86 sys.exit(1) 87 88 filename = abspath(filenames[0]) 89 path.append(split(filename)[0]) 90 91 # Obtain the output filename. 92 93 output = outputs and outputs[0] or "_main" 94 95 # Define the output data directories. 96 97 datadir = "_lplc" 98 cache_dir = join(datadir, "_cache") 99 deduced_dir = join(datadir, "_deduced") 100 output_dir = join(datadir, "_output") 101 generated_dir = join(datadir, "_generated") 102 103 # Load the program. 104 105 try: 106 start = now = time() 107 108 i = importer.Importer(path, cache_dir, verbose) 109 m = i.initialise(filename, reset) 110 success = i.finalise() 111 112 now = stopwatch("Inspection", now) 113 114 # Check for success, indicating missing references otherwise. 115 116 if not success: 117 show_missing(i.missing) 118 sys.exit(1) 119 120 d = deducer.Deducer(i, deduced_dir) 121 d.to_output() 122 123 now = stopwatch("Deduction", now) 124 125 o = optimiser.Optimiser(i, d, output_dir) 126 o.to_output() 127 128 now = stopwatch("Optimisation", now) 129 130 g = generator.Generator(i, o, generated_dir) 131 g.to_output(debug) 132 133 now = stopwatch("Generation", now) 134 135 t = translator.Translator(i, d, o, generated_dir) 136 t.to_output() 137 138 now = stopwatch("Translation", now) 139 140 # Compile the program unless otherwise indicated. 141 142 if make: 143 make_clean_cmd = ["make", "-C", generated_dir, "clean"] 144 make_cmd = make_clean_cmd[:-1] 145 146 retval = call(make_clean_cmd, make_verbose) 147 if not retval: 148 retval = call(make_cmd, make_verbose) 149 150 if not retval: 151 stopwatch("Compilation", now) 152 else: 153 sys.exit(retval) 154 155 # Move the executable into the current directory. 156 157 rename(join(generated_dir, "main"), output) 158 159 # Report any errors. 160 161 except error.SyntaxError, exc: 162 show_syntax_error(exc) 163 if "-tb" in args: 164 raise 165 sys.exit(1) 166 167 except ProcessingError, exc: 168 print exc 169 if "-tb" in args: 170 raise 171 sys.exit(1) 172 173 else: 174 sys.exit(0) 175 176 # vim: tabstop=4 expandtab shiftwidth=4