62std::vector<SourceLine>
SplitLines(absl::string_view source) {
63 std::vector<SourceLine> lines;
65 while (offset < source.size()) {
66 const size_t newline = source.find(
'\n', offset);
68 newline == absl::string_view::npos ? source.size() : newline;
69 lines.push_back({offset, source.substr(offset, end - offset)});
70 if (newline == absl::string_view::npos) {
79 absl::string_view label) {
80 const size_t comment = line.
text.find(
';');
81 const size_t code_end =
82 comment == absl::string_view::npos ? line.
text.size() : comment;
84 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
87 if (cursor + 2 > code_end ||
88 std::tolower(
static_cast<unsigned char>(line.
text[cursor])) !=
'd' ||
89 std::tolower(
static_cast<unsigned char>(line.
text[cursor + 1])) !=
'w' ||
90 cursor + 2 == code_end || !
IsSpace(line.
text[cursor + 2])) {
91 return absl::InvalidArgumentError(absl::StrFormat(
96 std::vector<ParsedToken> tokens;
97 bool requires_token =
true;
99 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
102 if (cursor == code_end) {
103 if (requires_token) {
104 return absl::InvalidArgumentError(
105 absl::StrFormat(
"Empty operand in %s", label));
110 const size_t token_start = cursor;
111 if (line.
text[cursor] !=
'$' || cursor + 5 > code_end ||
113 line.
text.begin() +
static_cast<std::ptrdiff_t
>(cursor + 1),
114 line.
text.begin() +
static_cast<std::ptrdiff_t
>(cursor + 5),
116 return absl::InvalidArgumentError(
117 absl::StrFormat(
"%s values must use exact 16-bit $hhhh operands: %s",
122 return absl::InvalidArgumentError(
123 absl::StrFormat(
"%s contains an over-wide 16-bit operand: %s", label,
128 for (
size_t digit = token_start + 1; digit < token_start + 5; ++digit) {
129 const char hex = line.
text[digit];
131 if (hex >=
'0' && hex <=
'9') {
134 value += 10 + std::tolower(
static_cast<unsigned char>(hex)) -
'a';
137 tokens.push_back({value, {line.
offset + token_start, 5}});
138 requires_token =
false;
140 while (cursor < code_end &&
IsSpace(line.
text[cursor])) {
143 if (cursor == code_end) {
146 if (line.
text[cursor] !=
',') {
147 return absl::InvalidArgumentError(
148 absl::StrFormat(
"Unexpected operand separator in %s: %s", label,
152 requires_token =
true;
154 if (tokens.empty()) {
155 return absl::InvalidArgumentError(
156 absl::StrFormat(
"Empty dw statement in %s", label));
161absl::StatusOr<ParsedSection>
ParseSection(
const std::vector<SourceLine>& lines,
162 size_t first_line,
size_t end_line,
163 absl::string_view label) {
164 enum class GuardState { kPrefix, kEnabled,
kDisabled, kComplete };
165 GuardState state = GuardState::kPrefix;
166 bool saw_guard =
false;
167 bool saw_else =
false;
168 bool saw_endif =
false;
169 std::vector<ParsedToken> prefix;
170 std::vector<ParsedToken> enabled;
171 std::vector<ParsedToken> disabled;
173 for (
size_t line_index = first_line + 1; line_index < end_line;
175 const absl::string_view code =
CodeForLine(lines[line_index].text);
180 if (state != GuardState::kPrefix || saw_guard) {
181 return absl::InvalidArgumentError(
182 absl::StrFormat(
"Nested or repeated guard in %s", label));
185 state = GuardState::kEnabled;
188 if (code ==
"else") {
189 if (!saw_guard || state != GuardState::kEnabled || saw_else) {
190 return absl::InvalidArgumentError(
191 absl::StrFormat(
"Unexpected else in %s", label));
194 state = GuardState::kDisabled;
197 if (code ==
"endif") {
198 if (!saw_else || state != GuardState::kDisabled || saw_endif) {
199 return absl::InvalidArgumentError(
200 absl::StrFormat(
"Unexpected endif in %s", label));
203 state = GuardState::kComplete;
206 if (state == GuardState::kComplete) {
207 return absl::InvalidArgumentError(absl::StrFormat(
208 "Unexpected content after guarded table in %s: %s", label, code));
211 auto tokens_or =
ParseDwLine(lines[line_index], label);
212 if (!tokens_or.ok()) {
213 return tokens_or.status();
216 if (state == GuardState::kEnabled) {
218 }
else if (state == GuardState::kDisabled) {
226 std::vector<ParsedToken> active;
229 return absl::InvalidArgumentError(
230 absl::StrFormat(
"%s must contain exactly %zu values; found %zu",
233 active = std::move(prefix);
235 if (!saw_else || !saw_endif) {
236 return absl::InvalidArgumentError(
237 absl::StrFormat(
"Incomplete planned-track guard in %s", label));
239 if (prefix.size() != 4 || enabled.size() != 28 || disabled.size() != 28) {
240 return absl::InvalidArgumentError(absl::StrFormat(
241 "%s guarded layout requires exactly 4 prefix, 28 enabled, and 28 "
242 "disabled values; found %zu, %zu, and %zu",
243 label, prefix.size(), enabled.size(), disabled.size()));
245 active = std::move(prefix);
246 active.insert(active.end(), enabled.begin(), enabled.end());
251 result.
values[index] = active[index].value;