1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
#!/usr/bin/python3
#
# Yapps 2 - yet another python parser system
# Copyright 1999-2003 by Amit J. Patel <amitp@cs.stanford.edu>
#
# This version of Yapps 2 can be distributed under the
# terms of the MIT open source license, either found in the LICENSE file
# included with the Yapps distribution
# <http://theory.stanford.edu/~amitp/yapps/> or at
# <http://www.opensource.org/licenses/mit-license.php>
#
import os, sys, re, types
#from six import string_types
PY2 = sys.version_info[0] == 2
if PY2:
string_types = (basestring,)
else:
string_types = (str,)
try: from yapps import runtime, parsetree, grammar
except ImportError:
# For running binary from a checkout-path directly
if os.path.isfile('yapps/__init__.py'):
sys.path.append('.')
from yapps import runtime, parsetree, grammar
else: raise
def generate(inputfile, outputfile=None, dump=0, **flags):
"""Generate a grammar, given an input filename (X.g)
and an output filename (defaulting to X.py)."""
inputfilename = inputfile if isinstance(
inputfile, string_types ) else inputfile.name
if not outputfile:
if inputfilename.endswith('.g'):
outputfile = inputfilename[:-2] + '.py'
else:
raise Exception('Must specify output filename if input filename is not *.g')
DIVIDER = '\n%%\n' # This pattern separates the pre/post parsers
preparser, postparser = None, None # Code before and after the parser desc
# Read the entire file
if isinstance(inputfile, string_types):
inputfile = open(inputfilename)
s = inputfile.read()
# See if there's a separation between the pre-parser and parser
f = s.find(DIVIDER)
if f >= 0: preparser, s = s[:f]+'\n\n', s[f+len(DIVIDER):]
# See if there's a separation between the parser and post-parser
f = s.find(DIVIDER)
if f >= 0: s, postparser = s[:f], '\n\n'+s[f+len(DIVIDER):]
# Create the parser and scanner and parse the text
scanner = grammar.ParserDescriptionScanner(s, filename=inputfilename)
if preparser: scanner.del_line += preparser.count('\n')
parser = grammar.ParserDescription(scanner)
t = runtime.wrap_error_reporter(parser, 'Parser')
if t is None: return 1 # Failure
if preparser is not None: t.preparser = preparser
if postparser is not None: t.postparser = postparser
# Add command line options to the set
t.options.update(flags)
# Generate the output
if dump:
t.dump_information()
else:
if isinstance(outputfile, string_types):
outputfile = open(outputfile, 'w')
t.output = outputfile
t.generate_output()
return 0
def main(argv=None):
import doctest
doctest.testmod(sys.modules['__main__'])
doctest.testmod(parsetree)
import argparse
parser = argparse.ArgumentParser(
description='Generate python parser code from grammar description file.')
parser.add_argument('grammar_path', help='Path to grammar description file (input).')
parser.add_argument('parser_path', nargs='?',
help='Path to output file to be generated.'
' Input path, but with .py will be used, if omitted.'
' "-" or "/dev/stdout" (on some systems) can be used to output generated code to stdout.')
parser.add_argument('-i', '--context-insensitive-scanner',
action='store_true', help='Scan all tokens (see docs).')
parser.add_argument('-t', '--indent-with-tabs', action='store_true',
help='Use tabs instead of four spaces for indentation in generated code.')
parser.add_argument('--dump', action='store_true', help='Dump out grammar information.')
optz = parser.parse_args(argv if argv is not None else sys.argv[1:])
parser_flags = dict()
for k in 'dump', 'context_insensitive_scanner':
if getattr(optz, k, False): parser_flags[k] = True
if optz.indent_with_tabs: parsetree.INDENT = '\t' # not the cleanest way
outputfile = optz.parser_path
if outputfile == '-': outputfile = sys.stdout
sys.exit(generate(optz.grammar_path, outputfile, **parser_flags))
if __name__ == '__main__': main()
|