#!/usr/bin/env python ######################################################################## # # File Name: BisonGen.py # # Documentation: http://docs.4suite.com/BisonGen/BisonGen.py.html # """ A Bison input file generator WWW: http://4suite.org/BisonGen e-mail: support@4suite.org Copyright (c) 2001 Fourthought Inc., USA. All Rights Reserved. See http://4suite.org/COPYRIGHT for license and copyright information """ import os, sys, stat, getopt ### Main Function ### def Generate(filename, options): from Reader import BisonGenReader import Grammar, Lexer, Python, C, Ebnf reader = BisonGenReader() parser = reader.parse(filename) # Command-line takes precedence over those specified in source file parser.options.update(options) bison = Grammar.Generate(parser) lexer = Lexer.Generate(parser) generated = [] # 2005-03-20: disabled until it catches up with the C version # Pure Python parser #if parser.options.get('mode', 'python') == 'python': # file = '%s.py' % parser.name # filename = Newer(parser, file) # if filename: # generated.append(filename) # if not options['quiet']: # print "Generate parser %s" % filename # Python.Generate(parser, bison, lexer, filename) # C based parser if parser.options.get('mode', 'c') == 'c': file = '%s.c' % parser.name filename = Newer(parser, file) if filename: generated.append(filename) if not options['quiet']: print "Generate parser %s" % filename C.Generate(parser, bison, lexer, filename) if options.get('ebnf'): file = '%s.ebnf' % parser.name filename = Newer(parser, file) if filename: generated.append(filename) if not options['quiet']: print "Generate EBNF %s" % filename Ebnf.Generate(parser, filename) return generated def Newer(parser, dest): base_dir = os.path.dirname(parser.options['input']) output_dir = parser.options.get('output', base_dir) filename = os.path.join(output_dir, dest) if not os.path.exists(filename): return filename if parser.last_modified > os.stat(filename)[stat.ST_MTIME]: return filename if parser.options.get('force'): return filename if not parser.options['quiet']: print 'Skipping %s (up-to-date)' % filename return None def Run(argv): prog_name = os.path.split(argv[0])[1] short_opts = 'hmto:efdvq' long_opts = ['help', 'mapping', 'tuples', 'output-dir=', 'ebnf', 'force', 'debug', 'verbose', 'quiet', 'mode=', ] usage = """Usage: %s [options] Options: -h, --help Print this message and exit -q, --quiet Do not display generated filenames -o, --output-dir Directory for output files -e, --ebnf Write an extra output file containing the EBNF structure of the grammar -f, --force Force creation of parser (ignore timestamps) -v, --verbose Write an extra output file describing parser states and what is done at each -d, --debug Generate parser with debugging enabled -m, --mapping Use mapping for parse tree -t, --tuples Use tuples for parse tree --mode Only generate parser for given mode """ % (prog_name) command_line_error = 0 bad_options = [] options = {'quiet' : 0} finished = 0 args = argv[1:] while not finished: try: optlist, args = getopt.getopt(args, short_opts, long_opts) except getopt.error, data: bad = str(data).split()[1] bad_options.append(bad) del args[0] command_line_error = 1 else: finished = 1 display_usage = 0 for opt,value in optlist: if opt == '-e' or opt == '--ebnf': options['ebnf'] = 1 elif opt == '-h' or opt == '--help': display_usage = 1 elif opt == '-m' or opt == '--mapping': options['mapping'] = 1 elif opt == '-t' or opt == '--tuples': options['tuple'] = 1 elif opt == '-o' or opt == '--output-dir': options['output'] = value elif opt in ['-v', '--verbose']: options['verbose'] = 1 elif opt in ['-d', '--debug']: options['debug'] = 1 elif opt in ['-f', '--force']: options['force'] = 1 elif opt in ['-q', '--quiet']: options['quiet'] = 1 elif opt == '--mode': options['mode'] = value.strip().lower() spec_file = '' if args: spec_file = args[0] if not os.path.exists(spec_file): import errno print "%s: %s '%s'" %(prog_name, os.strerror(errno.ENOENT), spec_file) spec_file = '' command_line_error = 1 else: command_line_error = 1 if command_line_error or display_usage: for op in bad_options: print "%s: Unrecognized option '%s'" %(prog_name,op) if not spec_file: print "%s: No input files" %(prog_name) display_usage = 1 if display_usage: print usage sys.exit(command_line_error) if not options.has_key('output'): options['output'] = os.path.dirname(spec_file) options['input'] = spec_file return Generate(spec_file, options) if __name__ == '__main__': Run(sys.argv)