#pragma once #include #include #include #include #include struct BXParseError: std::exception { BXParseError(std::string msg): message(msg) {} std::string message; const char *what() const noexcept override { return message.c_str(); } }; using BXVariables = std::unordered_map>; class BXParser { public: static const int FLAG_NONE = 0; static const int FLAG_ONE_LINE = 1 << 0; BXParser(std::istream &stream, int flags, int line = 1, int ch = 1): flags_(flags), line_(line), ch_(ch), stream_(stream) {} void parse(BXVariables &vars); void parseList(const BXVariables &vars, std::vector &values); int peek() { return stream_.peek(); } int peek2() { stream_.get(); int ch = peek(); stream_.unget(); return ch; } int get(); void skip(char); void skip() { get(); } int line() const { return line_; } int ch() const { return ch_; } private: enum class Operator { COLON_EQUALS, PLUS_EQUALS, EQUALS_PLUS, NONE, }; [[noreturn]] void error(std::string); Operator readOperator(); void skipWhitespaceLine(); void skipWhitespace(); char parseEscape(); void parseExpansion(const BXVariables &vars, std::vector &values); void parseQuotedExpansion(const BXVariables &vars, std::string &content); void parseQuotedString(const BXVariables &vars, std::string &content); bool parseString(const BXVariables &vars, std::string &content, int sep = -1); bool parseIdentifier(std::string &content); int flags_; int line_; int ch_; std::istream &stream_; }; class BXWriter { public: BXWriter(std::ostream &stream, int line = 1, int ch = 1): line_(line), ch_(ch), stream_(stream) {} void write(const BXVariables &vars); private: void put(char ch); void put(const std::string &str); void newline(); void escape(const std::string &str); int line_; int ch_; std::ostream &stream_; };