diff --git a/bin/sixtypical b/bin/sixtypical index b296f94..80fc8e6 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -58,6 +58,11 @@ def process_input_files(filenames, options): analyzer = Analyzer(debug=options.debug) analyzer.analyze_program(program) + if options.dump_fallthru_map: + import json + sys.stdout.write(json.dumps(program.fallthru_map, indent=4, sort_keys=True)) + sys.stdout.write("\n") + if options.analyze_only: return @@ -121,11 +126,7 @@ if __name__ == '__main__': 'filenames', metavar='FILENAME', type=str, nargs='+', help="The SixtyPical source files to compile." ) - argparser.add_argument( - "--analyze-only", - action="store_true", - help="Only parse and analyze the program; do not compile it." - ) + argparser.add_argument( "--origin", type=str, default='0xc000', help="Location in memory where the `main` routine will be " @@ -143,16 +144,27 @@ if __name__ == '__main__': "Also sets the origin and format. " "Options are: c64, vic20, atari2600." ) + argparser.add_argument( - "--debug", + "--analyze-only", action="store_true", - help="Display debugging information when analyzing and compiling." + help="Only parse and analyze the program; do not compile it." + ) + argparser.add_argument( + "--dump-fallthru-map", + action="store_true", + help="Dump the fallthru map to stdout after analyzing the program." ) argparser.add_argument( "--parse-only", action="store_true", help="Only parse the program; do not analyze or compile it." ) + argparser.add_argument( + "--debug", + action="store_true", + help="Display debugging information when analyzing and compiling." + ) argparser.add_argument( "--traceback", action="store_true", diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index b78cf95..5418238 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -310,8 +310,13 @@ class Analyzer(object): def analyze_program(self, program): assert isinstance(program, Program) self.routines = {r.location: r for r in program.routines} + fallthru_map = {} for routine in program.routines: - self.analyze_routine(routine) + context = self.analyze_routine(routine) + if context: + for encountered_goto in context.encountered_gotos(): + fallthru_map.setdefault(encountered_goto.name, set()).add(routine.name) + program.fallthru_map = dict([(k, list(v)) for k, v in fallthru_map.iteritems()]) def analyze_routine(self, routine): assert isinstance(routine, Routine) @@ -353,6 +358,7 @@ class Analyzer(object): if ref not in type_.outputs and ref not in type_.trashes and not routine_has_static(routine, ref): raise ForbiddenWriteError(routine, ref.name) self.current_routine = None + return context def analyze_block(self, block, context): assert isinstance(block, Block)