#pragma once #include #include #include #include #include #include "bufio.h" 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: enum class TokenKind { E_O_F, INDENTATION, NEWLINE, COMMA, COLON_EQUALS, PLUS_EQUALS, EQUALS_PLUS, BAR_EQUALS, EXPANSION, STRING, NONE, }; struct Token { TokenKind kind; std::string str; int line; int ch; }; BXParser(bufio::IStream &stream, int line = 1, int ch = 1): line_(line), ch_(ch), buf_(stream) {} int get(); int peek(size_t count = 1) { return buf_.peek(count); } void skip(char expected); void skip() { get(); } int line() const { return line_; } int ch() const { return ch_; } Token readToken(const BXVariables &vars); Token &peekToken() { return tok_; } void parse(BXVariables &vars, bool oneLine = false); void parseLine(BXVariables &vars) { parse(vars, true); } void parseList(BXVariables &vars, std::vector &list); private: [[noreturn]] void error(std::string); [[noreturn]] void error(std::string, TokenKind); std::string readIdent(const BXVariables &vars); void skipWhitespace(); Token getToken(const BXVariables &vars); std::string readString(const BXVariables &vars); std::string readQuotedString(const BXVariables &vars); std::string readStringExpansion(const BXVariables &vars); char readEscape(); void parseList( BXVariables &vars, std::vector &var, void (*addVal)(std::vector &var, std::string val), bool oneLine); int line_; int ch_; Token tok_; bufio::IBuf<> buf_; }; class BXWriter { public: BXWriter(bufio::OStream &stream): buf_(stream) {} void write(const BXVariables &vars); private: void newline(); void escape(const std::string &str); bufio::OBuf<> buf_; };