| #!/usr/bin/env python3.8 | |
| """Produce a report about the most-memoable types. | |
| Reads a list of statistics from stdin. Each line must be two numbers, | |
| being a type and a count. We then read some other files and produce a | |
| list sorted by most frequent type. | |
| There should also be something to recognize left-recursive rules. | |
| """ | |
| import os | |
| import re | |
| import sys | |
| from typing import Dict | |
| reporoot = os.path.dirname(os.path.dirname(__file__)) | |
| parse_c = os.path.join(reporoot, "peg_extension", "parse.c") | |
| class TypeMapper: | |
| """State used to map types to names.""" | |
| def __init__(self, filename: str) -> None: | |
| self.table: Dict[int, str] = {} | |
| with open(filename) as f: | |
| for line in f: | |
| match = re.match(r"#define (\w+)_type (\d+)", line) | |
| if match: | |
| name, type = match.groups() | |
| if "left" in line.lower(): | |
| name += " // Left-recursive" | |
| self.table[int(type)] = name | |
| def lookup(self, type: int) -> str: | |
| return self.table.get(type, str(type)) | |
| def main() -> None: | |
| mapper = TypeMapper(parse_c) | |
| table = [] | |
| filename = sys.argv[1] | |
| with open(filename) as f: | |
| for lineno, line in enumerate(f, 1): | |
| line = line.strip() | |
| if not line or line.startswith("#"): | |
| continue | |
| parts = line.split() | |
| # Extra fields ignored | |
| if len(parts) < 2: | |
| print(f"{lineno}: bad input ({line!r})") | |
| continue | |
| try: | |
| type, count = map(int, parts[:2]) | |
| except ValueError as err: | |
| print(f"{lineno}: non-integer input ({line!r})") | |
| continue | |
| table.append((type, count)) | |
| table.sort(key=lambda values: -values[1]) | |
| for type, count in table: | |
| print(f"{type:4d} {count:9d} {mapper.lookup(type)}") | |
| if __name__ == "__main__": | |
| main() |