1 #!/usr/bin/env python3.8
2
3 """Produce a report about the most-memoable types.
4
5 Reads a list of statistics from stdin. Each line must be two numbers,
6 being a type and a count. We then read some other files and produce a
7 list sorted by most frequent type.
8
9 There should also be something to recognize left-recursive rules.
10 """
11
12 import os
13 import re
14 import sys
15
16 from typing import Dict
17
18 reporoot = os.path.dirname(os.path.dirname(__file__))
19 parse_c = os.path.join(reporoot, "peg_extension", "parse.c")
20
21
22 class ESC[4;38;5;81mTypeMapper:
23 """State used to map types to names."""
24
25 def __init__(self, filename: str) -> None:
26 self.table: Dict[int, str] = {}
27 with open(filename) as f:
28 for line in f:
29 match = re.match(r"#define (\w+)_type (\d+)", line)
30 if match:
31 name, type = match.groups()
32 if "left" in line.lower():
33 name += " // Left-recursive"
34 self.table[int(type)] = name
35
36 def lookup(self, type: int) -> str:
37 return self.table.get(type, str(type))
38
39
40 def main() -> None:
41 mapper = TypeMapper(parse_c)
42 table = []
43 filename = sys.argv[1]
44 with open(filename) as f:
45 for lineno, line in enumerate(f, 1):
46 line = line.strip()
47 if not line or line.startswith("#"):
48 continue
49 parts = line.split()
50 # Extra fields ignored
51 if len(parts) < 2:
52 print(f"{lineno}: bad input ({line!r})")
53 continue
54 try:
55 type, count = map(int, parts[:2])
56 except ValueError as err:
57 print(f"{lineno}: non-integer input ({line!r})")
58 continue
59 table.append((type, count))
60 table.sort(key=lambda values: -values[1])
61 for type, count in table:
62 print(f"{type:4d} {count:9d} {mapper.lookup(type)}")
63
64
65 if __name__ == "__main__":
66 main()