Porytiles
Loading...
Searching...
No Matches
parser.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <optional>
5#include <string>
6#include <unordered_map>
7#include <unordered_set>
8#include <utility>
9#include <vector>
10
11#include "gsl/pointers"
12
26
27namespace porytiles {
28
29class CParserContext;
30
58class Parser {
59 public:
68 Parser(gsl::not_null<const TextFormatter *> format, std::vector<Token> tokens)
69 : format_{format}, tokens_{std::move(tokens)}
70 {
71 }
72
82 Parser(gsl::not_null<const TextFormatter *> format, std::vector<Token> tokens, const CParserContext *context)
83 : format_{format}, tokens_{std::move(tokens)}, context_{context}
84 {
85 }
86
107
127
148
168
190
217
238
266
283
294
305
314 [[nodiscard]] const std::vector<std::string> &scan_warnings() const
315 {
316 return scan_warnings_;
317 }
318
327 [[nodiscard]] const std::unordered_set<std::string> &ambiguous_defines() const
328 {
329 return ambiguous_defines_;
330 }
331
339 [[nodiscard]] const std::unordered_set<std::string> &defined_names() const
340 {
341 return defined_names_;
342 }
343
352 void seed_symbols(const std::unordered_map<std::string, std::int64_t> &symbols)
353 {
354 for (const auto &[name, value] : symbols) {
355 defined_values_[name] = value;
356 defined_names_.insert(name);
357 }
358 }
359
368 void seed_values(const std::unordered_map<std::string, std::int64_t> &symbols)
369 {
370 for (const auto &[name, value] : symbols) {
371 defined_values_[name] = value;
372 }
373 }
374
375 private:
381 enum class CondState : std::uint8_t { active, skipping, both };
382
389 struct ConditionalFrame {
390 CondState state;
391 bool decidable;
392 bool branch_taken;
393 };
394
395 [[nodiscard]] const Token &peek() const;
396 [[nodiscard]] const Token &peek_next() const;
397 const Token &advance();
398 [[nodiscard]] bool is_at_end() const;
399 [[nodiscard]] bool check(TokenType type) const;
400 bool match(TokenType type);
401
402 void skip_to_next_line();
403 [[nodiscard]] bool is_at_line_end() const;
404
405 // Preprocessor conditional handling. try_handle_conditional consumes a conditional directive (returning true) or
406 // reports that the directive at the current '#' is not conditional (returning false). effective_cond_state folds
407 // the frame stack into a single state that gates whether scanned constructs are recorded.
408 [[nodiscard]] CondState effective_cond_state() const;
409 bool try_handle_conditional();
410 [[nodiscard]] std::pair<CondState, bool> classify_ifdef(bool negated);
411 [[nodiscard]] std::pair<CondState, bool> classify_if_expression();
412 [[nodiscard]] std::optional<std::vector<Token>> substitute_defined_operators(const std::vector<Token> &expr) const;
413
414 [[nodiscard]] ChainableResult<DefineStatement> parse_define();
415 void record_define(DefineStatement statement, std::vector<DefineStatement> &out);
416 [[nodiscard]] ChainableResult<EnumDeclaration> parse_enum();
417 [[nodiscard]] ChainableResult<EnumMember> parse_enum_member(std::int64_t &counter);
418
419 // Tolerant variants used by the tolerant scans. The outcome carries either a resolved statement or a skip record;
420 // both leave the parser positioned at the start of the next line.
421 struct DefineParseOutcome {
422 std::optional<DefineStatement> statement;
423 std::optional<SkippedConstruct> skipped;
424 };
425 [[nodiscard]] DefineParseOutcome parse_define_tolerant();
426 [[nodiscard]] std::optional<TolerantEnum> parse_enum_tolerant();
427 [[nodiscard]] TolerantEnumMember parse_enum_member_tolerant(std::int64_t &counter, bool &counter_valid);
428 [[nodiscard]] std::vector<IndexedArrayEntry> parse_indexed_entries(const std::vector<Token> &brace_contents);
429 [[nodiscard]] std::vector<Token> collect_expression_tokens();
430 [[nodiscard]] std::vector<Token> collect_enum_value_tokens();
431 [[nodiscard]] ChainableResult<std::int64_t> evaluate_expression(const std::vector<Token> &expr_tokens);
432
433 // Shunting Yard algorithm helpers
434 [[nodiscard]] std::vector<Token> to_postfix(const std::vector<Token> &expr_tokens);
435 [[nodiscard]] ChainableResult<std::int64_t> evaluate_postfix(const std::vector<Token> &postfix);
436 [[nodiscard]] int operator_precedence(TokenType type) const;
437 [[nodiscard]] bool is_left_associative(TokenType type) const;
438 [[nodiscard]] bool is_operator(TokenType type) const;
439 [[nodiscard]] bool is_unary_operator(TokenType type) const;
440
441 [[nodiscard]] FormattableError make_error(SourcePosition pos, std::string message) const;
442
443 const TextFormatter *format_;
444 std::vector<Token> tokens_;
445 std::size_t current_{0};
446 std::unordered_map<std::string, std::int64_t> defined_values_{{"UCHAR_MAX", 255}}; // Symbol table for macro values
447 std::unordered_set<std::string> defined_names_; // All names seen as defined
448 std::vector<ConditionalFrame> cond_stack_; // Active preprocessor conditionals
449 std::vector<std::string> scan_warnings_; // Recoverable scan diagnostics
450 std::unordered_set<std::string> ambiguous_defines_;
451 const CParserContext *context_{nullptr};
452};
453
454} // namespace porytiles
Context object providing rich error formatting for C/C++ parsing.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
Parser for C preprocessor constructs.
Definition parser.hpp:58
const std::unordered_set< std::string > & ambiguous_defines() const
Returns names whose definitions conflicted in an undecidable conditional branch.
Definition parser.hpp:327
Parser(gsl::not_null< const TextFormatter * > format, std::vector< Token > tokens, const CParserContext *context)
Constructs a parser with a context for rich error formatting.
Definition parser.hpp:82
ChainableResult< std::vector< ArrayDeclaration > > parse_pointer_arrays()
Parses all pointer array declarations from the token stream.
Definition parser.cpp:1234
ChainableResult< std::vector< EnumDeclaration > > parse_enums()
Parses all enum declarations from the token stream.
Definition parser.cpp:590
ChainableResult< std::vector< DefineStatement > > parse_defines()
Parses all #define statements from the token stream.
Definition parser.cpp:303
void seed_symbols(const std::unordered_map< std::string, std::int64_t > &symbols)
Seeds the symbol table with externally known macro values before scanning.
Definition parser.hpp:352
ChainableResult< std::vector< IncbinDeclaration > > parse_incbin_arrays()
Parses INCBIN array declarations from the token stream.
Definition parser.cpp:1796
const std::unordered_set< std::string > & defined_names() const
Returns the set of macro names seen as defined so far.
Definition parser.hpp:339
ChainableResult< std::vector< StructVariableDeclaration > > parse_struct_variables()
Parses struct variable declarations from the token stream.
Definition parser.cpp:1420
ChainableResult< std::vector< StructInitializerDeclaration > > parse_struct_initializers()
Parses struct variable declarations with their designated initializer fields.
Definition parser.cpp:1500
const std::vector< std::string > & scan_warnings() const
Returns warnings accumulated while scanning conditionals and defines.
Definition parser.hpp:314
TolerantEnumScan parse_enums_tolerant()
Parses all enum declarations, tolerating individual member evaluation failures.
Definition parser.cpp:562
Parser(gsl::not_null< const TextFormatter * > format, std::vector< Token > tokens)
Constructs a parser for the given token stream.
Definition parser.hpp:68
ChainableResult< std::vector< StructDefinition > > parse_struct_definitions()
Parses struct type definitions from the token stream.
Definition parser.cpp:1652
ChainableResult< std::vector< IndexedArrayDeclaration > > parse_indexed_arrays()
Parses array declarations that use designated (indexed) initializers.
Definition parser.cpp:2097
void seed_values(const std::unordered_map< std::string, std::int64_t > &symbols)
Seeds only expression values without marking their names as preprocessor-defined.
Definition parser.hpp:368
TolerantDefineScan parse_defines_tolerant()
Parses all #define statements, tolerating individual evaluation failures.
Definition parser.cpp:413
ChainableResult< std::vector< FunctionDefinition > > parse_functions()
Parses function definitions from the token stream.
Definition parser.cpp:1344
std::string name
TokenType
Enumeration of token types recognized by the C parser lexer.
Definition token.hpp:17
The result of a tolerant #define scan.
The result of a tolerant enum scan.