Path: blob/main/Tools/peg_generator/pegen/__main__.py
12 views
#!/usr/bin/env python3.812"""pegen -- PEG Generator.34Search the web for PEG Parsers for reference.5"""67import argparse8import sys9import time10import token11import traceback12from typing import Tuple1314from pegen.build import Grammar, Parser, ParserGenerator, Tokenizer15from pegen.validator import validate_grammar161718def generate_c_code(19args: argparse.Namespace,20) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]:21from pegen.build import build_c_parser_and_generator2223verbose = args.verbose24verbose_tokenizer = verbose >= 325verbose_parser = verbose == 2 or verbose >= 426try:27grammar, parser, tokenizer, gen = build_c_parser_and_generator(28args.grammar_filename,29args.tokens_filename,30args.output,31args.compile_extension,32verbose_tokenizer,33verbose_parser,34args.verbose,35keep_asserts_in_extension=False if args.optimized else True,36skip_actions=args.skip_actions,37)38return grammar, parser, tokenizer, gen39except Exception as err:40if args.verbose:41raise # Show traceback42traceback.print_exception(err.__class__, err, None)43sys.stderr.write("For full traceback, use -v\n")44sys.exit(1)454647def generate_python_code(48args: argparse.Namespace,49) -> Tuple[Grammar, Parser, Tokenizer, ParserGenerator]:50from pegen.build import build_python_parser_and_generator5152verbose = args.verbose53verbose_tokenizer = verbose >= 354verbose_parser = verbose == 2 or verbose >= 455try:56grammar, parser, tokenizer, gen = build_python_parser_and_generator(57args.grammar_filename,58args.output,59verbose_tokenizer,60verbose_parser,61skip_actions=args.skip_actions,62)63return grammar, parser, tokenizer, gen64except Exception as err:65if args.verbose:66raise # Show traceback67traceback.print_exception(err.__class__, err, None)68sys.stderr.write("For full traceback, use -v\n")69sys.exit(1)707172argparser = argparse.ArgumentParser(73prog="pegen", description="Experimental PEG-like parser generator"74)75argparser.add_argument("-q", "--quiet", action="store_true", help="Don't print the parsed grammar")76argparser.add_argument(77"-v",78"--verbose",79action="count",80default=0,81help="Print timing stats; repeat for more debug output",82)83subparsers = argparser.add_subparsers(help="target language for the generated code")8485c_parser = subparsers.add_parser("c", help="Generate C code for inclusion into CPython")86c_parser.set_defaults(func=generate_c_code)87c_parser.add_argument("grammar_filename", help="Grammar description")88c_parser.add_argument("tokens_filename", help="Tokens description")89c_parser.add_argument(90"-o", "--output", metavar="OUT", default="parse.c", help="Where to write the generated parser"91)92c_parser.add_argument(93"--compile-extension",94action="store_true",95help="Compile generated C code into an extension module",96)97c_parser.add_argument(98"--optimized", action="store_true", help="Compile the extension in optimized mode"99)100c_parser.add_argument(101"--skip-actions",102action="store_true",103help="Suppress code emission for rule actions",104)105106python_parser = subparsers.add_parser("python", help="Generate Python code")107python_parser.set_defaults(func=generate_python_code)108python_parser.add_argument("grammar_filename", help="Grammar description")109python_parser.add_argument(110"-o",111"--output",112metavar="OUT",113default="parse.py",114help="Where to write the generated parser",115)116python_parser.add_argument(117"--skip-actions",118action="store_true",119help="Suppress code emission for rule actions",120)121122123def main() -> None:124from pegen.testutil import print_memstats125126args = argparser.parse_args()127if "func" not in args:128argparser.error("Must specify the target language mode ('c' or 'python')")129130t0 = time.time()131grammar, parser, tokenizer, gen = args.func(args)132t1 = time.time()133134validate_grammar(grammar)135136if not args.quiet:137if args.verbose:138print("Raw Grammar:")139for line in repr(grammar).splitlines():140print(" ", line)141142print("Clean Grammar:")143for line in str(grammar).splitlines():144print(" ", line)145146if args.verbose:147print("First Graph:")148for src, dsts in gen.first_graph.items():149print(f" {src} -> {', '.join(dsts)}")150print("First SCCS:")151for scc in gen.first_sccs:152print(" ", scc, end="")153if len(scc) > 1:154print(155" # Indirectly left-recursive; leaders:",156{name for name in scc if grammar.rules[name].leader},157)158else:159name = next(iter(scc))160if name in gen.first_graph[name]:161print(" # Left-recursive")162else:163print()164165if args.verbose:166dt = t1 - t0167diag = tokenizer.diagnose()168nlines = diag.end[0]169if diag.type == token.ENDMARKER:170nlines -= 1171print(f"Total time: {dt:.3f} sec; {nlines} lines", end="")172if dt:173print(f"; {nlines / dt:.0f} lines/sec")174else:175print()176print("Caches sizes:")177print(f" token array : {len(tokenizer._tokens):10}")178print(f" cache : {len(parser._cache):10}")179if not print_memstats():180print("(Can't find psutil; install it for memory stats.)")181182183if __name__ == "__main__":184if sys.version_info < (3, 8):185print("ERROR: using pegen requires at least Python 3.8!", file=sys.stderr)186sys.exit(1)187main()188189190