061b7e5f358c283430a11701eb7c8602c4599ddd
2 from pathlib
import Path
4 from typing
import Iterable
6 FILENAME
= Path("openpower/power_trans_ops.mdwn")
7 NEW_FILENAME
= FILENAME
.with_suffix(".new.mdwn")
8 OLD_FILENAME
= FILENAME
.with_suffix(".old.mdwn")
10 PO_59_HEADER
= "## PO=59 XO=10--011--"
11 MNEMONIC_COLUMN_NAME
= "opcode"
12 XO_COLUMN_NAME
= "Major 59 and 63"
14 # TODO: copy PO=59 table to PO=63 table
17 def __init__(self
, lines
):
18 # type: (list[str]) -> None
19 self
.__next
_line
_index
= 0
23 if self
.__next
_line
_index
== len(self
.__lines
):
24 self
.__next
_line
_index
+= 1
25 return None, self
.__next
_line
_index
26 assert self
.__next
_line
_index
< len(self
.__lines
), \
27 "read past end-of-file"
28 line
= self
.__lines
[self
.__next
_line
_index
].rstrip()
29 self
.__next
_line
_index
+= 1
30 return line
, self
.__next
_line
_index
34 # type: (LineReader) -> Iterable[str]
36 line
, lineno
= lr
.read()
38 mnemonic_to_xo_map
= {} # type: dict[str, str]
40 def parse_table_separator_line(len_line_parts
):
41 # type: (int) -> Iterable[str]
44 assert line
is not None \
45 and line
.startswith('|') \
46 and line
.endswith('|') \
47 and len(line
.split('|')) == len_line_parts \
48 and line
.strip(" |-") == "", "invalid table separator line"
51 line
, lineno
= lr
.read()
53 assert line
is not None and line
!= "", "empty table"
55 def parse_mnemonic_to_opcode_map():
56 # type: () -> Iterable[str]
57 nonlocal line
, lineno
, mnemonic_to_xo_map
59 while line
!= PO_59_HEADER
:
60 assert line
is not None, "missing PO=59 header"
62 line
, lineno
= lr
.read()
65 line
, lineno
= lr
.read()
67 while line
is not None and not line
.startswith(("#", "|")):
69 line
, lineno
= lr
.read()
71 assert line
is not None and line
.startswith(
72 "| XO LSB half → <br/> XO MSB half ↓ |"), \
73 "can't find PO=59 table"
74 line_parts
= line
.split('|')
75 len_line_parts
= len(line_parts
)
76 assert line_parts
[-1] == "", "invalid PO=59 table top row"
77 columns
= [] # type: list[str]
78 columns_range
= range(2, len_line_parts
- 1)
79 for i
in columns_range
:
80 column
= line_parts
[i
].strip()
81 if column
.startswith('`') and column
.endswith('`'):
82 column
= column
[1:-1].strip()
83 assert column
.lstrip(" 01") == "", (f
"invalid table top row "
84 f
"contents -- must be a "
85 f
"binary string: {column}")
86 columns
.append(column
)
89 line
, lineno
= lr
.read()
91 yield from parse_table_separator_line(len_line_parts
)
93 while line
is not None and line
!= "":
94 line_parts
= line
.split('|')
95 assert line
.startswith('|') and line
.endswith('|'), \
96 "invalid table line, must start and end with |"
97 assert len(line_parts
) == len_line_parts
, (
98 f
"invalid table line, wrong part count: found "
99 f
"{len(line_parts)} expected {len_line_parts}")
100 row
= line_parts
[1].strip()
101 if row
.startswith('`') and row
.endswith('`'):
102 row
= row
[1:-1].strip()
103 assert row
.lstrip(" 01") == "", (f
"invalid table line header-cell "
104 f
"contents -- must be a "
105 f
"binary string: {row}")
106 for i
, column
in zip(columns_range
, columns
):
108 match
= re
.fullmatch(
109 r
" *<small> *` *(?P<xo>[01][01 ]*[01]) *` *</small>"
110 r
" *<br/> *(?P<mnemonic>[a-zA-Z0-9_.]+)?"
111 r
"(?(mnemonic)|(?:\([a-zA-Z0-9_.]+\)|\*\*TBD\*\*|))"
112 r
"(?: *\(draft\))? *", cell
)
113 assert match
is not None, f
"invalid table cell: {cell!r}"
114 xo
, mnemonic
= match
.group("xo", "mnemonic")
115 shrunk_xo
= xo
.replace(" ", "")
116 expected_xo
= (row
+ column
).replace(" ", "")
117 assert shrunk_xo
== expected_xo
, \
118 f
"incorrect XO: found {shrunk_xo} expected {expected_xo}"
121 assert mnemonic
.endswith('s'), \
122 f
"PO=59 fptrans mnemonic must end in `s`: {mnemonic}"
123 assert mnemonic
not in mnemonic_to_xo_map
, (
124 f
"duplicate mnemonic: {mnemonic} -- has opcode "
125 f
"{xo} and {mnemonic_to_xo_map[mnemonic]}")
127 mnemonic_to_xo_map
[mnemonic
] = xo
130 line
, lineno
= lr
.read()
133 # type: () -> Iterable[str]
134 nonlocal line
, lineno
136 assert line
is not None \
137 and line
.startswith("|") and line
.endswith('|'), \
138 "invalid table header"
139 line_parts
= line
.split("|")
140 len_line_parts
= len(line_parts
)
141 assert len_line_parts
>= 3, "invalid table header"
144 line
, lineno
= lr
.read()
146 yield from parse_table_separator_line(len_line_parts
)
147 while line
is not None and line
!= "":
148 line_parts
= line
.split('|')
149 assert line
.startswith('|') and line
.endswith('|'), \
150 "invalid table line, must start and end with |"
151 assert len(line_parts
) == len_line_parts
, (
152 f
"invalid table line, wrong part count: found "
153 f
"{len(line_parts)} expected {len_line_parts}")
156 line
, lineno
= lr
.read()
159 # type: () -> Iterable[str]
160 nonlocal line
, lineno
162 assert line
is not None \
163 and line
.startswith("|") and line
.endswith('|'), \
164 "invalid table header"
165 line_parts
= line
.split("|")
166 len_line_parts
= len(line_parts
)
167 assert len_line_parts
>= 3, "invalid table header"
168 mnemonic_index
= None
171 for i
, column
in enumerate(line_parts
):
172 column_width
= len(column
) # should use wcswidth here
173 column
= column
.strip()
174 if column
== MNEMONIC_COLUMN_NAME
:
175 assert mnemonic_index
is None, \
176 f
"two {MNEMONIC_COLUMN_NAME!r} columns in table " \
177 f
"-- can't handle that"
179 if column
== XO_COLUMN_NAME
:
180 assert xo_index
is None, \
181 f
"two {XO_COLUMN_NAME!r} columns in table " \
182 f
"-- can't handle that"
184 xo_column_width
= column_width
185 if mnemonic_index
is None and xo_index
is None:
186 # not an opcode table -- skip it
187 yield from skip_table()
190 assert mnemonic_index
is not None, \
191 f
"missing {MNEMONIC_COLUMN_NAME} column"
192 assert xo_index
is not None, f
"missing {XO_COLUMN_NAME} column"
195 line
, lineno
= lr
.read()
197 yield from parse_table_separator_line(len_line_parts
)
198 while line
is not None and line
!= "":
199 line_parts
= line
.split('|')
200 assert line
.startswith('|') and line
.endswith('|'), \
201 "invalid table line, must start and end with |"
202 assert len(line_parts
) == len_line_parts
, (
203 f
"invalid table line, wrong part count: found "
204 f
"{len(line_parts)} expected {len_line_parts}")
206 mnemonic
= line_parts
[mnemonic_index
].strip()
207 xo
= line_parts
[xo_index
].strip()
208 if mnemonic
.endswith("(s)") or mnemonic
.endswith("[s]"):
209 mnemonic
= mnemonic
[:-3] + "s"
210 if mnemonic
not in mnemonic_to_xo_map
:
211 print(f
"mnemonic not assigned an XO value: {mnemonic!r}")
213 xo
= mnemonic_to_xo_map
[mnemonic
]
214 xo_width
= len(xo
) # should use wcswidth here
215 if xo_width
< xo_column_width
:
216 # should use wc_ljust here
217 xo
= (" " + xo
).ljust(xo_column_width
)
218 line_parts
[xo_index
] = xo
220 expected_xo
= mnemonic_to_xo_map
[mnemonic
].replace(" ", "")
221 assert xo
.replace(" ", "") == expected_xo
, (
222 f
"mismatch in {XO_COLUMN_NAME} column: expected "
223 f
"{mnemonic_to_xo_map[mnemonic]} found {xo!r}")
225 yield '|'.join(line_parts
)
226 line
, lineno
= lr
.read()
229 yield from parse_mnemonic_to_opcode_map()
231 print(mnemonic_to_xo_map
)
233 while line
is not None:
234 if line
.startswith('|'):
235 yield from handle_table()
238 line
, lineno
= lr
.read()
240 except AssertionError as e
:
241 raise AssertionError(f
"\n{FILENAME}:{lineno}: error: {e}")
244 inp
= FILENAME
.read_text(encoding
="utf-8")
245 output_lines
= list(process(LineReader(inp
.splitlines())))
246 if output_lines
[-1] != "":
247 output_lines
.append("") # ensure file ends with newline
248 NEW_FILENAME
.write_text("\n".join(output_lines
), encoding
="utf-8")
249 FILENAME
.replace(OLD_FILENAME
)
250 NEW_FILENAME
.rename(FILENAME
)