136 absl::string_view label) {
137 const size_t comment = line.
text.find(
';');
138 const size_t code_end =
139 comment == absl::string_view::npos ? line.
text.size() : comment;
141 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
144 if (cursor + 2 > code_end ||
145 std::tolower(
static_cast<unsigned char>(line.
text[cursor])) !=
'd' ||
146 std::tolower(
static_cast<unsigned char>(line.
text[cursor + 1])) !=
'w' ||
147 cursor + 2 == code_end || !
IsSpace(line.
text[cursor + 2])) {
148 return absl::InvalidArgumentError(absl::StrFormat(
153 std::vector<ParsedToken> tokens;
154 bool requires_token =
true;
156 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
159 if (cursor == code_end) {
160 if (requires_token) {
161 return absl::InvalidArgumentError(
162 absl::StrFormat(
"Empty operand in %s", label));
167 const size_t token_start = cursor;
168 if (line.
text[cursor] !=
'$' || cursor + 5 > code_end ||
170 line.
text.begin() +
static_cast<std::ptrdiff_t
>(cursor + 1),
171 line.
text.begin() +
static_cast<std::ptrdiff_t
>(cursor + 5),
173 return absl::InvalidArgumentError(
174 absl::StrFormat(
"%s values must use exact 16-bit $hhhh operands: %s",
179 return absl::InvalidArgumentError(
180 absl::StrFormat(
"%s contains an over-wide 16-bit operand: %s", label,
185 for (
size_t digit = token_start + 1; digit < token_start + 5; ++digit) {
186 const char hex = line.
text[digit];
188 if (hex >=
'0' && hex <=
'9') {
191 value += 10 + std::tolower(
static_cast<unsigned char>(hex)) -
'a';
194 tokens.push_back({value, {line.
offset + token_start, 5}});
195 requires_token =
false;
197 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
200 if (cursor == code_end) {
203 if (line.
text[cursor] !=
',') {
204 return absl::InvalidArgumentError(
205 absl::StrFormat(
"Unexpected operand separator in %s: %s", label,
209 requires_token =
true;
211 if (tokens.empty()) {
212 return absl::InvalidArgumentError(
213 absl::StrFormat(
"Empty dw statement in %s", label));
218absl::StatusOr<ParsedSection>
ParseSection(
const std::vector<SourceLine>& lines,
219 size_t first_line,
size_t end_line,
222 enum class GuardState { kPrefix, kEnabled,
kDisabled, kComplete };
223 enum class TrailerState {
kNone, kEndLabel, kAssertion };
224 GuardState state = GuardState::kPrefix;
225 TrailerState trailer = TrailerState::kNone;
226 bool saw_guard =
false;
227 bool saw_else =
false;
228 bool saw_endif =
false;
229 std::vector<ParsedToken> prefix;
230 std::vector<ParsedToken> enabled;
231 std::vector<ParsedToken> disabled;
233 for (
size_t line_index = first_line + 1; line_index < end_line;
235 const absl::string_view code =
CodeForLine(lines[line_index].text);
239 if (trailer != TrailerState::kNone) {
240 if (trailer == TrailerState::kEndLabel &&
242 trailer = TrailerState::kAssertion;
245 return absl::InvalidArgumentError(absl::StrFormat(
246 "Unexpected content after %s table end: %s", label, code));
249 if ((saw_guard && state != GuardState::kComplete) ||
251 return absl::InvalidArgumentError(absl::StrFormat(
252 "Size assertion follows an incomplete %s table", label));
254 trailer = TrailerState::kEndLabel;
258 if (state != GuardState::kPrefix || saw_guard) {
259 return absl::InvalidArgumentError(
260 absl::StrFormat(
"Nested or repeated guard in %s", label));
263 state = GuardState::kEnabled;
266 if (code ==
"else") {
267 if (!saw_guard || state != GuardState::kEnabled || saw_else) {
268 return absl::InvalidArgumentError(
269 absl::StrFormat(
"Unexpected else in %s", label));
272 state = GuardState::kDisabled;
275 if (code ==
"endif") {
276 if (!saw_else || state != GuardState::kDisabled || saw_endif) {
277 return absl::InvalidArgumentError(
278 absl::StrFormat(
"Unexpected endif in %s", label));
281 state = GuardState::kComplete;
284 if (state == GuardState::kComplete) {
285 return absl::InvalidArgumentError(absl::StrFormat(
286 "Unexpected content after guarded table in %s: %s", label, code));
289 auto tokens_or =
ParseDwLine(lines[line_index], label);
290 if (!tokens_or.ok()) {
291 return tokens_or.status();
294 if (state == GuardState::kEnabled) {
296 }
else if (state == GuardState::kDisabled) {
303 if (trailer == TrailerState::kEndLabel) {
304 return absl::InvalidArgumentError(
305 absl::StrFormat(
"Missing size assertion after %s table end", label));
309 std::vector<ParsedToken> active;
312 return absl::InvalidArgumentError(
313 absl::StrFormat(
"%s must contain exactly %zu values; found %zu",
316 active = std::move(prefix);
318 if (!saw_else || !saw_endif) {
319 return absl::InvalidArgumentError(
320 absl::StrFormat(
"Incomplete planned-track guard in %s", label));
322 if (prefix.size() != 4 || enabled.size() != 28 || disabled.size() != 28) {
323 return absl::InvalidArgumentError(absl::StrFormat(
324 "%s guarded layout requires exactly 4 prefix, 28 enabled, and 28 "
325 "disabled values; found %zu, %zu, and %zu",
326 label, prefix.size(), enabled.size(), disabled.size()));
328 active = std::move(prefix);
329 active.insert(active.end(), enabled.begin(), enabled.end());
334 result.
values[index] = active[index].value;