17[[nodiscard]] std::size_t skip_balanced_braces(
const std::vector<Token> &tokens, std::size_t
start)
23 std::size_t pos =
start + 1;
26 while (pos < tokens.size() && depth > 0) {
44[[nodiscard]] std::vector<Token> collect_brace_contents(
const std::vector<Token> &tokens, std::size_t
start)
46 std::vector<Token> contents;
52 std::size_t pos =
start + 1;
55 while (pos < tokens.size() && depth > 0) {
65 contents.push_back(tokens[pos]);
76[[nodiscard]] std::vector<std::string> extract_identifier_elements(
const std::vector<Token> &brace_contents)
78 std::vector<std::string> elements;
80 for (
const auto &token : brace_contents) {
82 elements.push_back(token.text());
95[[nodiscard]] std::size_t skip_balanced_parens(
const std::vector<Token> &tokens, std::size_t
start)
101 std::size_t pos =
start + 1;
104 while (pos < tokens.size() && depth > 0) {
126[[nodiscard]]
bool is_gfx_inclusion_macro(
const std::string &token)
128 return token.starts_with(
"INCBIN_") || token.starts_with(
"INCGFX_");
133FormattableError Parser::make_error(SourcePosition pos, std::string message)
const
135 if (context_ !=
nullptr) {
136 return context_->
make_error(pos, std::move(message));
138 return FormattableError{format_->
format(
"{}:{}: {}", pos.line, pos.column, message)};
141Parser::CondState Parser::effective_cond_state()
const
143 bool any_both =
false;
144 for (
const auto &frame : cond_stack_) {
145 if (frame.state == CondState::skipping) {
146 return CondState::skipping;
148 if (frame.state == CondState::both) {
152 return any_both ? CondState::both : CondState::active;
155std::pair<Parser::CondState, bool> Parser::classify_ifdef(
bool negated)
164 if (
name.empty() || !defined_names_.contains(
name)) {
166 return {CondState::both,
false};
168 const bool condition = negated ? false :
true;
169 return {condition ? CondState::active : CondState::skipping,
true};
172std::optional<std::vector<Token>> Parser::substitute_defined_operators(
const std::vector<Token> &expr)
const
174 std::vector<Token> out;
176 while (i < expr.size()) {
178 out.push_back(expr[i]);
185 SourcePosition pos = expr[i].position();
186 std::size_t next = i + 1;
189 name = expr[next + 1].text();
191 std::size_t close = next + 1;
195 i = (close < expr.size()) ? close + 1 : expr.size();
198 name = expr[next].text();
205 if (
name.empty() || !defined_names_.contains(
name)) {
209 out.push_back(Token{
"1",
static_cast<std::int64_t
>(1), pos});
214std::pair<Parser::CondState, bool> Parser::classify_if_expression()
217 std::vector<Token> expr = collect_expression_tokens();
219 auto substituted = substitute_defined_operators(expr);
220 if (!substituted.has_value() || substituted->empty()) {
221 return {CondState::both,
false};
224 auto eval = evaluate_expression(substituted.value());
225 if (!eval.has_value()) {
227 return {CondState::both,
false};
229 return {eval.value() != 0 ? CondState::active : CondState::skipping,
true};
232bool Parser::try_handle_conditional()
243 auto [state, decidable] = classify_ifdef(negated);
244 cond_stack_.push_back(ConditionalFrame{state, decidable, state == CondState::active});
250 auto [state, decidable] = classify_if_expression();
251 cond_stack_.push_back(ConditionalFrame{state, decidable, state == CondState::active});
257 auto [state, decidable] = classify_if_expression();
258 if (!cond_stack_.empty()) {
259 ConditionalFrame &frame = cond_stack_.back();
260 if (!frame.decidable || !decidable) {
262 frame.state = CondState::both;
263 frame.decidable =
false;
265 else if (frame.branch_taken) {
266 frame.state = CondState::skipping;
270 frame.branch_taken = state == CondState::active;
279 if (!cond_stack_.empty()) {
280 ConditionalFrame &frame = cond_stack_.back();
281 if (frame.decidable) {
282 frame.state = frame.branch_taken ? CondState::skipping : CondState::active;
283 frame.branch_taken =
true;
293 if (!cond_stack_.empty()) {
294 cond_stack_.pop_back();
305 std::vector<DefineStatement> defines;
308 while (!is_at_end()) {
311 if (try_handle_conditional()) {
318 auto result = parse_define();
319 if (!result.has_value()) {
322 record_define(std::move(result).value(), defines);
338void Parser::record_define(
DefineStatement statement, std::vector<DefineStatement> &out)
340 const CondState eff = effective_cond_state();
341 if (eff == CondState::skipping) {
347 auto it = defined_values_.find(statement.
name());
348 if (eff == CondState::both && it != defined_values_.end() && it->second != statement.
int_value()) {
349 ambiguous_defines_.insert(statement.
name());
350 scan_warnings_.push_back(format_->
format(
351 "conflicting redefinition of '{}' inside an undecidable conditional; using the last value",
352 FormatParam{statement.name(), Style::bold}));
356 defined_names_.insert(statement.
name());
357 out.push_back(std::move(statement));
360Parser::DefineParseOutcome Parser::parse_define_tolerant()
362 SourcePosition define_pos = peek().
position();
367 return {std::nullopt, SkippedConstruct{
"", define_pos,
"expected identifier after #define"}};
371 SourcePosition name_pos = peek().
position();
372 std::size_t name_end_column = name_pos.
column +
name.size();
377 SourcePosition paren_pos = peek().
position();
378 if (paren_pos.line == name_pos.line && paren_pos.column == name_end_column) {
380 return {DefineStatement{std::move(
name), define_pos}, std::nullopt};
385 if (is_at_line_end()) {
389 return {DefineStatement{std::move(
name), define_pos}, std::nullopt};
394 std::string value = peek().
text();
397 return {DefineStatement{std::move(
name), std::move(value), define_pos}, std::nullopt};
401 std::vector<Token> expr_tokens = collect_expression_tokens();
402 if (expr_tokens.empty()) {
403 return {DefineStatement{std::move(
name), define_pos}, std::nullopt};
406 auto result = evaluate_expression(expr_tokens);
407 if (!result.has_value()) {
408 return {std::nullopt, SkippedConstruct{std::move(
name), define_pos,
"unevaluable value expression"}};
410 return {DefineStatement{std::move(
name), result.value(), define_pos}, std::nullopt};
419 while (!is_at_end()) {
421 if (try_handle_conditional()) {
427 auto outcome = parse_define_tolerant();
428 if (effective_cond_state() == CondState::skipping) {
432 if (outcome.statement.has_value()) {
433 record_define(std::move(outcome.statement).value(), scan.
defines);
435 else if (outcome.skipped.has_value()) {
436 if (!outcome.skipped->name.empty()) {
437 defined_names_.insert(outcome.skipped->name);
439 scan.
skipped.push_back(std::move(outcome.skipped).value());
454TolerantEnumMember Parser::parse_enum_member_tolerant(std::int64_t &counter,
bool &counter_valid)
462 std::vector<Token> expr_tokens = collect_enum_value_tokens();
463 if (!expr_tokens.empty()) {
464 auto eval = evaluate_expression(expr_tokens);
465 if (eval.has_value()) {
466 counter = eval.value();
467 counter_valid =
true;
470 defined_values_[member.name] = member.value.value();
475 counter_valid =
false;
476 return TolerantEnumMember{std::move(
name), std::nullopt, member_pos};
480 std::optional<std::int64_t> value = counter_valid ? std::optional<std::int64_t>{counter} : std::nullopt;
481 TolerantEnumMember member{std::move(
name), value, member_pos};
483 if (member.value.has_value()) {
484 defined_values_[member.name] = member.value.value();
489std::optional<TolerantEnum> Parser::parse_enum_tolerant()
491 SourcePosition enum_pos = peek().
position();
494 std::optional<std::string> enum_name;
496 enum_name = peek().
text();
510 std::vector<TolerantEnumMember> members;
511 std::int64_t counter = 0;
512 bool counter_valid =
true;
513 bool directive_seen =
false;
527 directive_seen =
true;
528 counter_valid =
false;
537 members.push_back(parse_enum_member_tolerant(counter, counter_valid));
538 if (directive_seen) {
540 members.back().value = std::nullopt;
541 counter_valid =
false;
559 return TolerantEnum{std::move(enum_name), std::move(members), enum_pos};
568 while (!is_at_end()) {
570 if (try_handle_conditional()) {
577 auto parsed = parse_enum_tolerant();
578 if (parsed.has_value() && effective_cond_state() != CondState::skipping) {
579 scan.
enums.push_back(std::move(parsed).value());
592 std::vector<EnumDeclaration> enums;
598 while (!is_at_end()) {
600 if (try_handle_conditional()) {
608 auto result = parse_enum();
609 if (!result.has_value()) {
612 if (effective_cond_state() != CondState::skipping) {
613 enums.push_back(std::move(result).value());
630 std::optional<std::string> enum_name;
632 enum_name = peek().
text();
643 return make_error(peek().position(),
"expected '{' after 'enum'");
648 std::vector<EnumMember> members;
649 std::int64_t counter = 0;
661 auto member_result = parse_enum_member(counter);
662 if (!member_result.has_value()) {
663 return ChainableResult<EnumDeclaration>{member_result};
665 members.push_back(std::move(member_result).value());
680 return make_error(peek().position(),
"expected '}' to close enum");
689 if (enum_name.has_value()) {
690 return EnumDeclaration{std::move(enum_name).value(), std::move(members), enum_pos};
692 return EnumDeclaration{std::move(members), enum_pos};
695ChainableResult<EnumMember> Parser::parse_enum_member(std::int64_t &counter)
699 return make_error(peek().position(),
"expected identifier for enum member");
703 SourcePosition member_pos = peek().
position();
707 bool has_explicit =
false;
713 std::vector<Token> expr_tokens = collect_enum_value_tokens();
715 if (expr_tokens.empty()) {
718 format_->
format(
"expected expression after '=' for enum member '{}'", FormatParam{name, Style::bold}));
721 auto eval_result = evaluate_expression(expr_tokens);
722 if (!eval_result.has_value()) {
723 return ChainableResult<EnumMember>{
727 "failed to evaluate expression for enum member '{}'", FormatParam{name, Style::bold})),
731 counter = eval_result.value();
734 EnumMember member{std::move(
name), counter, has_explicit, member_pos};
736 defined_values_[member.name()] = member.int_value();
740std::vector<Token> Parser::collect_enum_value_tokens()
742 std::vector<Token> expr_tokens;
745 expr_tokens.push_back(peek());
752const Token &Parser::peek()
const
755 return tokens_.back();
757 return tokens_[current_];
760const Token &Parser::peek_next()
const
762 if (current_ + 1 >= tokens_.size()) {
763 return tokens_.back();
765 return tokens_[current_ + 1];
768const Token &Parser::advance()
773 return tokens_[current_ - 1];
776bool Parser::is_at_end()
const
786 return peek().
is(type);
798void Parser::skip_to_next_line()
808bool Parser::is_at_line_end()
const
813ChainableResult<DefineStatement> Parser::parse_define()
815 SourcePosition define_pos = peek().
position();
822 return make_error(peek().position(),
"expected identifier after '#define'");
826 SourcePosition name_pos = peek().
position();
827 std::size_t name_end_column = name_pos.
column +
name.size();
834 SourcePosition paren_pos = peek().
position();
836 if (paren_pos.line == name_pos.line && paren_pos.column == name_end_column) {
839 return DefineStatement{std::move(
name), define_pos};
845 if (is_at_line_end()) {
849 return DefineStatement{std::move(
name), define_pos};
854 std::string value = peek().
text();
857 return DefineStatement{std::move(
name), std::move(value), define_pos};
861 std::vector<Token> expr_tokens = collect_expression_tokens();
863 if (expr_tokens.empty()) {
865 return DefineStatement{std::move(
name), define_pos};
868 auto result = evaluate_expression(expr_tokens);
869 if (!result.has_value()) {
870 return ChainableResult<DefineStatement>{
873 format_->
format(
"failed to evaluate expression for #define '{}'", FormatParam{name, Style::bold})),
877 std::int64_t value = result.value();
880 return DefineStatement{std::move(
name), value, define_pos};
883std::vector<Token> Parser::collect_expression_tokens()
885 std::vector<Token> expr_tokens;
887 while (!is_at_line_end()) {
888 expr_tokens.push_back(peek());
900ChainableResult<std::int64_t> Parser::evaluate_expression(
const std::vector<Token> &expr_tokens)
902 if (expr_tokens.empty()) {
903 return make_error(SourcePosition{},
"empty expression");
908 for (
const Token &token : expr_tokens) {
911 is_operator(token.type());
915 format_->
format(
"unsupported token '{}' in expression", FormatParam{token.text(), Style::bold}));
920 std::vector<Token> postfix = to_postfix(expr_tokens);
923 return evaluate_postfix(postfix);
926std::vector<Token> Parser::to_postfix(
const std::vector<Token> &expr_tokens)
928 std::vector<Token> output;
929 std::stack<Token> operators;
931 bool expect_operand =
true;
933 for (std::size_t i = 0; i < expr_tokens.size(); ++i) {
934 const Token &token = expr_tokens[i];
937 output.push_back(token);
938 expect_operand =
false;
941 operators.push(token);
942 expect_operand =
true;
946 output.push_back(operators.top());
952 expect_operand =
false;
954 else if (is_operator(token.type())) {
956 if (expect_operand && is_unary_operator(token.type())) {
959 Token unary_token{token.type(),
"u" + token.text(), token.position()};
960 operators.push(unary_token);
965 is_operator(operators.top().type())) {
966 int top_prec = operator_precedence(operators.top().type());
967 int curr_prec = operator_precedence(token.type());
969 if (top_prec < curr_prec || (top_prec == curr_prec && is_left_associative(token.type()))) {
970 output.push_back(operators.top());
977 operators.push(token);
978 expect_operand =
true;
985 while (!operators.empty()) {
987 output.push_back(operators.top());
995ChainableResult<std::int64_t> Parser::evaluate_postfix(
const std::vector<Token> &postfix)
997 std::stack<std::int64_t> values;
999 for (
const Token &token : postfix) {
1001 values.push(token.int_value());
1005 auto it = defined_values_.find(token.text());
1006 if (it != defined_values_.end()) {
1007 values.push(it->second);
1013 format_->
format(
"unknown identifier '{}'", FormatParam{token.text(), Style::bold}));
1016 else if (is_operator(token.type())) {
1018 if (token.text().size() > 1 && token.text()[0] ==
'u') {
1019 if (values.empty()) {
1023 "unary operator '{}' missing operand", FormatParam{token.text().substr(1), Style::bold}));
1025 std::int64_t operand = values.top();
1028 std::int64_t result = 0;
1029 switch (token.type()) {
1037 result = operand == 0 ? 1 : 0;
1042 format_->
format(
"unknown unary operator '{}'", FormatParam{token.text(), Style::bold}));
1044 values.push(result);
1048 if (values.size() < 2) {
1052 "binary operator '{}' missing operands", FormatParam{token.text(), Style::bold}));
1054 std::int64_t right = values.top();
1056 std::int64_t left = values.top();
1059 std::int64_t result = 0;
1060 switch (token.type()) {
1062 result = left + right;
1065 result = left - right;
1068 result = left * right;
1072 return make_error(token.position(),
"division by zero");
1074 result = left / right;
1078 return make_error(token.position(),
"modulo by zero");
1080 result = left % right;
1083 result = left & right;
1086 result = left | right;
1089 result = left ^ right;
1092 result = left << right;
1095 result = left >> right;
1098 result = left < right ? 1 : 0;
1101 result = left > right ? 1 : 0;
1104 result = left <= right ? 1 : 0;
1107 result = left >= right ? 1 : 0;
1110 result = left == right ? 1 : 0;
1113 result = left != right ? 1 : 0;
1116 result = (left != 0 && right != 0) ? 1 : 0;
1119 result = (left != 0 || right != 0) ? 1 : 0;
1124 format_->
format(
"unknown binary operator '{}'", FormatParam{token.text(), Style::bold}));
1126 values.push(result);
1131 if (values.empty()) {
1132 return make_error(SourcePosition{},
"expression evaluated to no value");
1134 if (values.size() != 1) {
1137 return make_error(SourcePosition{},
"expression did not reduce to a single value");
1140 return values.top();
1143int Parser::operator_precedence(
TokenType type)
const
1186bool Parser::is_left_associative(
TokenType type)
const
1192bool Parser::is_operator(
TokenType type)
const
1221bool Parser::is_unary_operator(
TokenType type)
const
1236 std::vector<ArrayDeclaration> arrays;
1241 while (!is_at_end()) {
1255 std::size_t scan_start = current_;
1273 if (current_ == scan_start) {
1295 std::string array_name = peek().
text();
1327 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
1328 std::vector<std::string> elements = extract_identifier_elements(brace_contents);
1331 current_ = skip_balanced_braces(tokens_, current_);
1338 arrays.emplace_back(std::move(array_name), std::move(elements), name_pos);
1346 std::vector<FunctionDefinition> functions;
1351 while (!is_at_end()) {
1362 std::size_t scan_start = current_;
1375 if (current_ == scan_start) {
1386 std::string func_name = peek().
text();
1396 current_ = skip_balanced_parens(tokens_, current_);
1409 std::vector<Token> body_tokens = collect_brace_contents(tokens_, current_);
1412 current_ = skip_balanced_braces(tokens_, current_);
1414 functions.emplace_back(std::move(func_name), std::move(body_tokens), name_pos);
1422 std::vector<StructVariableDeclaration> structs;
1427 while (!is_at_end()) {
1438 std::size_t scan_start = current_;
1448 if (current_ == scan_start) {
1459 std::string struct_type = peek().
text();
1466 std::string variable_name = peek().
text();
1487 current_ = skip_balanced_braces(tokens_, current_);
1494 structs.emplace_back(std::move(struct_type), std::move(variable_name), name_pos);
1502 std::vector<StructInitializerDeclaration> structs;
1507 while (!is_at_end()) {
1518 std::size_t scan_start = current_;
1528 if (current_ == scan_start) {
1539 std::string struct_type = peek().
text();
1546 std::string variable_name = peek().
text();
1567 std::vector<DesignatedInitializerField> fields;
1568 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
1571 std::size_t brace_pos = 0;
1572 while (brace_pos < brace_contents.size()) {
1574 while (brace_pos < brace_contents.size() && (brace_contents[brace_pos].is(
TokenType::newline) ||
1579 if (brace_pos >= brace_contents.size()) {
1586 while (brace_pos < brace_contents.size() && !brace_contents[brace_pos].is(
TokenType::comma)) {
1597 std::string field_name = brace_contents[brace_pos].text();
1602 if (brace_pos >= brace_contents.size() || !brace_contents[brace_pos].is(
TokenType::equal)) {
1608 while (brace_pos < brace_contents.size() && brace_contents[brace_pos].is(
TokenType::newline)) {
1613 if (brace_pos >= brace_contents.size()) {
1619 value = brace_contents[brace_pos].text();
1623 value = brace_contents[brace_pos].text();
1628 while (brace_pos < brace_contents.size() && !brace_contents[brace_pos].is(
TokenType::comma) &&
1635 fields.emplace_back(std::move(field_name), std::move(value), field_pos);
1639 current_ = skip_balanced_braces(tokens_, current_);
1646 structs.emplace_back(std::move(struct_type), std::move(variable_name), std::move(fields), name_pos);
1654 std::vector<StructDefinition> definitions;
1659 while (!is_at_end()) {
1670 std::size_t scan_start = current_;
1673 if (current_ == scan_start) {
1684 std::string struct_name = peek().
text();
1699 std::vector<Token> body_tokens = collect_brace_contents(tokens_, current_);
1700 current_ = skip_balanced_braces(tokens_, current_);
1707 std::vector<std::vector<Token>> member_runs;
1708 std::vector<Token> run;
1709 int nesting_depth = 0;
1710 for (std::size_t i = 0; i < body_tokens.size(); ++i) {
1711 const Token &tok = body_tokens[i];
1729 member_runs.push_back(std::move(run));
1738 std::vector<StructMemberDeclaration> members;
1739 for (
const auto &member_tokens : member_runs) {
1740 std::size_t pos = 0;
1741 bool is_const =
false;
1744 member_tokens[pos].text() ==
"const") {
1750 member_tokens[pos].text() ==
"struct") {
1756 std::string type_name = member_tokens[pos].
text();
1760 member_tokens[pos].text() ==
"const") {
1764 std::size_t pointer_depth = 0;
1765 while (pos < member_tokens.size() && member_tokens[pos].is(
TokenType::star)) {
1772 std::string member_name = member_tokens[pos].text();
1776 if (pos + 1 < member_tokens.size() && member_tokens[pos].is(
TokenType::colon) &&
1781 if (pos != member_tokens.size()) {
1787 std::move(type_name), pointer_depth, std::move(member_name), is_const, member_pos});
1790 definitions.push_back(
StructDefinition{std::move(struct_name), std::move(members), name_pos});
1798 std::vector<IncbinDeclaration> incbins;
1803 while (!is_at_end()) {
1815 std::size_t scan_start = current_;
1829 if (current_ == scan_start) {
1855 std::string variable_name = peek().
text();
1876 bool is_multi_dimensional =
false;
1878 is_multi_dimensional =
true;
1900 if (is_multi_dimensional) {
1906 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
1907 current_ = skip_balanced_braces(tokens_, current_);
1909 std::vector<std::string> paths;
1910 std::string macro_name;
1911 std::size_t brace_pos = 0;
1913 while (brace_pos < brace_contents.size()) {
1915 while (brace_pos < brace_contents.size() && (brace_contents[brace_pos].is(
TokenType::newline) ||
1920 if (brace_pos >= brace_contents.size()) {
1930 std::string token_text = brace_contents[brace_pos].text();
1931 if (!is_gfx_inclusion_macro(token_text)) {
1936 if (macro_name.empty()) {
1937 macro_name = token_text;
1951 paths.push_back(brace_contents[brace_pos].text());
1958 if (brace_pos < brace_contents.size()) {
1963 if (!paths.empty()) {
1964 incbins.emplace_back(std::move(variable_name), std::move(macro_name), std::move(paths), name_pos);
1973 std::string token_text = peek().
text();
1974 if (!is_gfx_inclusion_macro(token_text)) {
1977 std::string macro_name = token_text;
1990 std::string path = peek().
text();
2001 incbins.emplace_back(std::move(variable_name), std::move(macro_name), std::move(path), name_pos);
2008std::vector<IndexedArrayEntry> Parser::parse_indexed_entries(
const std::vector<Token> &brace_contents)
2010 std::vector<IndexedArrayEntry> entries;
2011 std::size_t pos = 0;
2013 while (pos < brace_contents.size()) {
2015 while (pos < brace_contents.size() &&
2019 if (pos >= brace_contents.size()) {
2025 while (pos < brace_contents.size() && !brace_contents[pos].is(
TokenType::comma)) {
2033 std::string index_name;
2034 SourcePosition entry_pos{};
2035 if (pos < brace_contents.size() &&
2037 index_name = brace_contents[pos].text();
2038 entry_pos = brace_contents[pos].position();
2044 if (pos < brace_contents.size()) {
2052 if (pos >= brace_contents.size() || !brace_contents[pos].is(
TokenType::equal)) {
2054 while (pos < brace_contents.size() && !brace_contents[pos].is(
TokenType::comma)) {
2062 std::vector<Token> value_tokens;
2064 while (pos < brace_contents.size()) {
2065 const Token &token = brace_contents[pos];
2076 value_tokens.push_back(token);
2081 std::optional<std::int64_t> value;
2082 if (!value_tokens.empty()) {
2083 auto eval = evaluate_expression(value_tokens);
2084 if (eval.has_value()) {
2085 value = eval.value();
2089 if (!index_name.empty()) {
2090 entries.push_back(IndexedArrayEntry{std::move(index_name), value, std::move(value_tokens), entry_pos});
2099 std::vector<IndexedArrayDeclaration> arrays;
2102 cond_stack_.clear();
2104 while (!is_at_end()) {
2113 if (try_handle_conditional()) {
2116 skip_to_next_line();
2121 std::size_t scan_start = current_;
2132 if (current_ == scan_start) {
2143 std::string array_name = peek().
text();
2152 int bracket_depth = 1;
2153 while (!is_at_end() && bracket_depth > 0) {
2178 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
2179 current_ = skip_balanced_braces(tokens_, current_);
2184 std::vector<IndexedArrayEntry> entries = parse_indexed_entries(brace_contents);
2185 if (effective_cond_state() != CondState::skipping) {
FormattableError make_error(SourcePosition pos, const std::string &message) const
Creates a FormattableError with source context.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
Represents a parsed #define preprocessor statement.
const std::string & name() const
Returns the macro name.
bool has_int_value() const
Checks if this define has an integer value.
std::int64_t int_value() const
Returns the integer value.
ChainableResult< std::vector< ArrayDeclaration > > parse_pointer_arrays()
Parses all pointer array declarations from the token stream.
ChainableResult< std::vector< EnumDeclaration > > parse_enums()
Parses all enum declarations from the token stream.
ChainableResult< std::vector< DefineStatement > > parse_defines()
Parses all #define statements from the token stream.
ChainableResult< std::vector< IncbinDeclaration > > parse_incbin_arrays()
Parses INCBIN array declarations from the token stream.
ChainableResult< std::vector< StructVariableDeclaration > > parse_struct_variables()
Parses struct variable declarations from the token stream.
ChainableResult< std::vector< StructInitializerDeclaration > > parse_struct_initializers()
Parses struct variable declarations with their designated initializer fields.
TolerantEnumScan parse_enums_tolerant()
Parses all enum declarations, tolerating individual member evaluation failures.
ChainableResult< std::vector< StructDefinition > > parse_struct_definitions()
Parses struct type definitions from the token stream.
ChainableResult< std::vector< IndexedArrayDeclaration > > parse_indexed_arrays()
Parses array declarations that use designated (indexed) initializers.
TolerantDefineScan parse_defines_tolerant()
Parses all #define statements, tolerating individual evaluation failures.
ChainableResult< std::vector< FunctionDefinition > > parse_functions()
Parses function definitions from the token stream.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.
Represents a lexical token from C source code.
bool is(TokenType type) const
Checks if this token is of the specified type.
const SourcePosition & position() const
Returns the source position where the token starts.
TokenType type() const
Returns the token type.
const std::string & text() const
Returns the raw text of the token.
TokenType
Enumeration of token types recognized by the C parser lexer.
A parsed C array declaration that uses designated initializers.
Represents a position within source content.
std::size_t column
1-based column number
A parsed C struct type definition.
One member declaration inside a C struct definition.
The result of a tolerant #define scan.
std::vector< DefineStatement > defines
std::vector< SkippedConstruct > skipped
One enum member from a tolerant enum scan.
The result of a tolerant enum scan.
std::vector< TolerantEnum > enums