19[[nodiscard]] std::size_t skip_balanced_braces(
const std::vector<Token> &tokens, std::size_t
start)
25 std::size_t pos =
start + 1;
28 while (pos < tokens.size() && depth > 0) {
48[[nodiscard]] std::vector<Token> collect_brace_contents(
const std::vector<Token> &tokens, std::size_t
start)
50 std::vector<Token> contents;
56 std::size_t pos =
start + 1;
59 while (pos < tokens.size() && depth > 0) {
69 contents.push_back(tokens[pos]);
82[[nodiscard]] std::vector<std::string> extract_identifier_elements(
const std::vector<Token> &brace_contents)
84 std::vector<std::string> elements;
86 for (
const auto &token : brace_contents) {
88 elements.push_back(token.text());
103[[nodiscard]] std::size_t skip_balanced_parens(
const std::vector<Token> &tokens, std::size_t
start)
109 std::size_t pos =
start + 1;
112 while (pos < tokens.size() && depth > 0) {
127FormattableError Parser::make_error(SourcePosition pos, std::string message)
const
129 if (context_ !=
nullptr) {
130 return context_->
make_error(pos, std::move(message));
132 return FormattableError{format_->
format(
"{}:{}: {}", pos.line, pos.column, message)};
137 std::vector<DefineStatement> defines;
139 while (!is_at_end()) {
146 auto result = parse_define();
147 if (!result.has_value()) {
150 defines.push_back(std::move(result).value());
168 std::vector<EnumDeclaration> enums;
173 while (!is_at_end()) {
175 auto result = parse_enum();
176 if (!result.has_value()) {
179 enums.push_back(std::move(result).value());
195 std::optional<std::string> enum_name;
197 enum_name = peek().
text();
208 return make_error(peek().position(),
"expected '{' after 'enum'");
213 std::vector<EnumMember> members;
214 std::int64_t counter = 0;
226 auto member_result = parse_enum_member(counter);
227 if (!member_result.has_value()) {
228 return ChainableResult<EnumDeclaration>{member_result};
230 members.push_back(std::move(member_result).value());
245 return make_error(peek().position(),
"expected '}' to close enum");
254 if (enum_name.has_value()) {
255 return EnumDeclaration{std::move(enum_name).value(), std::move(members), enum_pos};
257 return EnumDeclaration{std::move(members), enum_pos};
260ChainableResult<EnumMember> Parser::parse_enum_member(std::int64_t &counter)
264 return make_error(peek().position(),
"expected identifier for enum member");
267 std::string name = peek().
text();
268 SourcePosition member_pos = peek().
position();
272 bool has_explicit =
false;
278 std::vector<Token> expr_tokens = collect_enum_value_tokens();
280 if (expr_tokens.empty()) {
283 format_->
format(
"expected expression after '=' for enum member '{}'", FormatParam{name, Style::bold}));
286 auto eval_result = evaluate_expression(expr_tokens);
287 if (!eval_result.has_value()) {
288 return ChainableResult<EnumMember>{
292 "failed to evaluate expression for enum member '{}'", FormatParam{name, Style::bold})),
296 counter = eval_result.value();
299 EnumMember member{std::move(name), counter, has_explicit, member_pos};
304std::vector<Token> Parser::collect_enum_value_tokens()
306 std::vector<Token> expr_tokens;
309 expr_tokens.push_back(peek());
316const Token &Parser::peek()
const
319 return tokens_.back();
321 return tokens_[current_];
324const Token &Parser::peek_next()
const
326 if (current_ + 1 >= tokens_.size()) {
327 return tokens_.back();
329 return tokens_[current_ + 1];
332const Token &Parser::advance()
337 return tokens_[current_ - 1];
340bool Parser::is_at_end()
const
350 return peek().
is(type);
362void Parser::skip_to_next_line()
372bool Parser::is_at_line_end()
const
377ChainableResult<DefineStatement> Parser::parse_define()
379 SourcePosition define_pos = peek().
position();
386 return make_error(peek().position(),
"expected identifier after '#define'");
389 std::string name = peek().
text();
390 SourcePosition name_pos = peek().
position();
391 std::size_t name_end_column = name_pos.
column + name.size();
398 SourcePosition paren_pos = peek().
position();
400 if (paren_pos.line == name_pos.line && paren_pos.column == name_end_column) {
403 return DefineStatement{std::move(name), define_pos};
409 if (is_at_line_end()) {
413 return DefineStatement{std::move(name), define_pos};
418 std::string value = peek().
text();
421 return DefineStatement{std::move(name), std::move(value), define_pos};
425 std::vector<Token> expr_tokens = collect_expression_tokens();
427 if (expr_tokens.empty()) {
429 return DefineStatement{std::move(name), define_pos};
432 auto result = evaluate_expression(expr_tokens);
433 if (!result.has_value()) {
434 return ChainableResult<DefineStatement>{
437 format_->
format(
"failed to evaluate expression for #define '{}'", FormatParam{name, Style::bold})),
441 std::int64_t value = result.value();
444 defined_values_[name] = value;
446 return DefineStatement{std::move(name), value, define_pos};
449std::vector<Token> Parser::collect_expression_tokens()
451 std::vector<Token> expr_tokens;
453 while (!is_at_line_end()) {
454 expr_tokens.push_back(peek());
466ChainableResult<std::int64_t> Parser::evaluate_expression(
const std::vector<Token> &expr_tokens)
468 if (expr_tokens.empty()) {
469 return make_error(SourcePosition{},
"empty expression");
473 std::vector<Token> postfix = to_postfix(expr_tokens);
476 return evaluate_postfix(postfix);
479std::vector<Token> Parser::to_postfix(
const std::vector<Token> &expr_tokens)
481 std::vector<Token> output;
482 std::stack<Token> operators;
484 bool expect_operand =
true;
486 for (std::size_t i = 0; i < expr_tokens.size(); ++i) {
487 const Token &token = expr_tokens[i];
490 output.push_back(token);
491 expect_operand =
false;
494 operators.push(token);
495 expect_operand =
true;
499 output.push_back(operators.top());
505 expect_operand =
false;
507 else if (is_operator(token.type())) {
509 if (expect_operand && is_unary_operator(token.type())) {
512 Token unary_token{token.type(),
"u" + token.text(), token.position()};
513 operators.push(unary_token);
518 is_operator(operators.top().type())) {
519 int top_prec = operator_precedence(operators.top().type());
520 int curr_prec = operator_precedence(token.type());
522 if (top_prec < curr_prec || (top_prec == curr_prec && is_left_associative(token.type()))) {
523 output.push_back(operators.top());
530 operators.push(token);
531 expect_operand =
true;
538 while (!operators.empty()) {
540 output.push_back(operators.top());
548ChainableResult<std::int64_t> Parser::evaluate_postfix(
const std::vector<Token> &postfix)
550 std::stack<std::int64_t> values;
552 for (
const Token &token : postfix) {
554 values.push(token.int_value());
558 auto it = defined_values_.find(token.text());
559 if (it != defined_values_.end()) {
560 values.push(it->second);
566 format_->
format(
"unknown identifier '{}'", FormatParam{token.text(), Style::bold}));
569 else if (is_operator(token.type())) {
571 if (token.text().size() > 1 && token.text()[0] ==
'u') {
572 if (values.empty()) {
576 "unary operator '{}' missing operand", FormatParam{token.text().substr(1), Style::bold}));
578 std::int64_t operand = values.top();
581 std::int64_t result = 0;
582 switch (token.type()) {
590 result = operand == 0 ? 1 : 0;
595 format_->
format(
"unknown unary operator '{}'", FormatParam{token.text(), Style::bold}));
601 if (values.size() < 2) {
605 "binary operator '{}' missing operands", FormatParam{token.text(), Style::bold}));
607 std::int64_t right = values.top();
609 std::int64_t left = values.top();
612 std::int64_t result = 0;
613 switch (token.type()) {
615 result = left + right;
618 result = left - right;
621 result = left * right;
625 return make_error(token.position(),
"division by zero");
627 result = left / right;
631 return make_error(token.position(),
"modulo by zero");
633 result = left % right;
636 result = left & right;
639 result = left | right;
642 result = left ^ right;
645 result = left << right;
648 result = left >> right;
653 format_->
format(
"unknown binary operator '{}'", FormatParam{token.text(), Style::bold}));
660 if (values.empty()) {
661 return make_error(SourcePosition{},
"expression evaluated to no value");
667int Parser::operator_precedence(
TokenType type)
const
705bool Parser::is_left_associative(
TokenType type)
const
711bool Parser::is_operator(
TokenType type)
const
740bool Parser::is_unary_operator(
TokenType type)
const
755 std::vector<ArrayDeclaration> arrays;
760 while (!is_at_end()) {
774 std::size_t scan_start = current_;
792 if (current_ == scan_start) {
814 std::string array_name = peek().
text();
846 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
847 std::vector<std::string> elements = extract_identifier_elements(brace_contents);
850 current_ = skip_balanced_braces(tokens_, current_);
857 arrays.emplace_back(std::move(array_name), std::move(elements), name_pos);
865 std::vector<FunctionDefinition> functions;
870 while (!is_at_end()) {
881 std::size_t scan_start = current_;
894 if (current_ == scan_start) {
905 std::string func_name = peek().
text();
915 current_ = skip_balanced_parens(tokens_, current_);
928 std::vector<Token> body_tokens = collect_brace_contents(tokens_, current_);
931 current_ = skip_balanced_braces(tokens_, current_);
933 functions.emplace_back(std::move(func_name), std::move(body_tokens), name_pos);
941 std::vector<StructVariableDeclaration> structs;
946 while (!is_at_end()) {
957 std::size_t scan_start = current_;
967 if (current_ == scan_start) {
978 std::string struct_type = peek().
text();
985 std::string variable_name = peek().
text();
1006 current_ = skip_balanced_braces(tokens_, current_);
1013 structs.emplace_back(std::move(struct_type), std::move(variable_name), name_pos);
1021 std::vector<StructInitializerDeclaration> structs;
1026 while (!is_at_end()) {
1037 std::size_t scan_start = current_;
1047 if (current_ == scan_start) {
1058 std::string struct_type = peek().
text();
1065 std::string variable_name = peek().
text();
1086 std::vector<DesignatedInitializerField> fields;
1087 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
1090 std::size_t brace_pos = 0;
1091 while (brace_pos < brace_contents.size()) {
1093 while (brace_pos < brace_contents.size() && (brace_contents[brace_pos].is(
TokenType::newline) ||
1098 if (brace_pos >= brace_contents.size()) {
1105 while (brace_pos < brace_contents.size() && !brace_contents[brace_pos].is(
TokenType::comma)) {
1116 std::string field_name = brace_contents[brace_pos].text();
1121 if (brace_pos >= brace_contents.size() || !brace_contents[brace_pos].is(
TokenType::equal)) {
1127 while (brace_pos < brace_contents.size() && brace_contents[brace_pos].is(
TokenType::newline)) {
1132 if (brace_pos >= brace_contents.size()) {
1138 value = brace_contents[brace_pos].text();
1142 value = brace_contents[brace_pos].text();
1147 while (brace_pos < brace_contents.size() && !brace_contents[brace_pos].is(
TokenType::comma) &&
1154 fields.emplace_back(std::move(field_name), std::move(value), field_pos);
1158 current_ = skip_balanced_braces(tokens_, current_);
1165 structs.emplace_back(std::move(struct_type), std::move(variable_name), std::move(fields), name_pos);
1173 std::vector<IncbinDeclaration> incbins;
1178 while (!is_at_end()) {
1190 std::size_t scan_start = current_;
1204 if (current_ == scan_start) {
1230 std::string variable_name = peek().
text();
1251 bool is_multi_dimensional =
false;
1253 is_multi_dimensional =
true;
1275 if (is_multi_dimensional) {
1281 std::vector<Token> brace_contents = collect_brace_contents(tokens_, current_);
1282 current_ = skip_balanced_braces(tokens_, current_);
1284 std::vector<std::string> paths;
1285 std::string macro_name;
1286 std::size_t brace_pos = 0;
1288 while (brace_pos < brace_contents.size()) {
1290 while (brace_pos < brace_contents.size() && (brace_contents[brace_pos].is(
TokenType::newline) ||
1295 if (brace_pos >= brace_contents.size()) {
1305 std::string token_text = brace_contents[brace_pos].text();
1306 if (token_text.find(
"INCBIN_") != 0) {
1311 if (macro_name.empty()) {
1312 macro_name = token_text;
1326 paths.push_back(brace_contents[brace_pos].text());
1333 if (brace_pos < brace_contents.size()) {
1338 if (!paths.empty()) {
1339 incbins.emplace_back(std::move(variable_name), std::move(macro_name), std::move(paths), name_pos);
1348 std::string token_text = peek().
text();
1349 if (token_text.find(
"INCBIN_") != 0) {
1352 std::string macro_name = token_text;
1365 std::string path = peek().
text();
1376 incbins.emplace_back(std::move(variable_name), std::move(macro_name), std::move(path), name_pos);
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.
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.
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.
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.
const std::string & text() const
Returns the raw text of the token.
TokenType
Enumeration of token types recognized by the C parser lexer.
Represents a position within source content.
std::size_t column
1-based column number