-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpmtools_parser.py
executable file
·132 lines (107 loc) · 4.31 KB
/
cpmtools_parser.py
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/python3
import sys
from lark.lark import Lark
from lark import UnexpectedToken, UnexpectedCharacters, UnexpectedEOF
from cpmtools_grammar import CPMTOOLS, build_callbacks
from cpmtools_transform import CPMToolsTransformer
from cpmtools import SkewSkewtabError
from exceptions import DuplicateParmError, DuplicateDefError, MissingParmError, UnknownKeywordError
import re
# A Transformer is a 'data handler' that absorbs input from parser and
# builds a Cpmtools object to represent each definition in the file.
xfm = CPMToolsTransformer(False)
# Instantiate the parser and connect data handlers
parser = Lark(CPMTOOLS,
lexer = 'contextual',
lexer_callbacks = build_callbacks(xfm),
start = 'diskdef',
parser = 'lalr',
transformer = xfm)
defdict = {}
def do_parse(data, linenum):
global parser, xfm
xfm.set_start(linenum)
try:
# Process the input
parser.parse(data)
# If we made it here, the parse succeeded.
defn = xfm.get_definition()
if defn.defname in defdict:
print("WARNING: Duplicate definition '%s' at line %d." % (defn.defname, linenum))
print("WARNING: Only the first instance will be used")
else:
defdict[defn.defname] = defn
except MissingParmError as d:
print("ERROR: Required parameter(s) missing from definition '%s' (line: %d)" % (d.defname, linenum))
for parm in d.missing:
print("%s " % parm, end="")
print("\n")
print("ERROR: Skipping this definition")
except SkewSkewtabError as d:
print("ERROR: Skew and skewtab both found in definition '%s' (line: %d)" % (d.defname, linenum))
print("ERROR: Skipping this definition")
except DuplicateParmError as d:
print("WARNING: Duplicate parameter '%s' in definition '%s' (line: %d)" % (d.parm, d.defname, linenum))
print("WARNING: Only the first instance will be used")
# We will only see this if strict checking is enabled
except UnknownKeywordError as u:
print("WARNING: Unknown keyword in definition '%s' (line: %d)" % (u.defname, linenum))
ctxt = u.get_context(data)
print(ctxt)
except UnexpectedToken as u:
print("Unxpected token at line: %d, column: %d" % (u.line, u.column))
ctxt = u.get_context(data)
print(ctxt)
if u.expected is not None:
if len(u.expected) > 1:
print("Expected one of:")
else:
print("Expected: ", end="")
for tok in u.expected:
name = str(parser.get_terminal(tok).pattern)
print(name.replace('\\',''))
except UnexpectedCharacters as u:
print(u)
except UnexpectedEOF as u:
print("Unexpected EOF at line: %d, column: %d\n" % (u.line, u.column))
ctxt = u.get_context(data)
print(ctxt)
dd_rx = re.compile('^diskdef\s+(\S+)')
end_rx = re.compile('^end(\s+|#)?')
try:
infile = sys.argv[1]
except IndexError:
raise SystemExit(f"Usage: {sys.argv[0]} <diskdef_file>")
state = 'SCAN'
with open(infile, "r") as f:
data = ""
defname = None
linenum = 0
def_linenum = 0
for line in f:
linenum += 1
dd_m = dd_rx.match(line)
if dd_m:
if state == 'DEF':
print("WARNING: Definition '%s' (line: %d) is missing the end keyword" % (defname, def_linenum))
print("WARNING: Will fake it, but results may not be correct")
data += "end\n"
do_parse(data, def_linenum)
data = ""
state = 'DEF'
defname = dd_m.group(1)
def_linenum = linenum
elif end_rx.match(line):
state = 'SCAN'
data += line
do_parse(data, def_linenum)
data = ""
continue
data += line
if state == 'DEF':
print("WARNING: Definition '%s' (line: %d) is missing the end keyword" % (defname, def_linenum))
print("WARNING: Will fake it, but results may not be correct")
data += "end\n"
do_parse(data, def_linenum)
for defname in sorted(defdict.keys()):
print(defdict[defname])