/** * command line parser * @author Tobias Weber * @date 28-may-18 * @license see 'LICENSE' file */ #ifndef __CLI_PARSER_H__ #define __CLI_PARSER_H__ #include #include #include #include #include #include #undef yyFlexLexer #include #include "cliparser_types.h" #include "cliparser_impl.h" #include "../data.h" class CliAST; class CliParserContext; class Symbol; // ---------------------------------------------------------------------------- // Lexer // ---------------------------------------------------------------------------- class CliLexer : public yyFlexLexer { private: CliParserContext *m_pContext = nullptr; protected: virtual void LexerError(const char *err) override; public: CliLexer(CliParserContext *ctx = nullptr); virtual yy::CliParser::symbol_type yylex(CliParserContext &context); }; template t_real_cli str_to_real(const std::string& str); // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Parser // ---------------------------------------------------------------------------- class CliParserContext { private: CliLexer m_lex; std::vector> m_asts; std::vector m_errors; // symbol tables and update signal std::map> *m_workspace = nullptr; boost::signals2::signal m_WorkspaceUpdated; public: CliLexer& GetLexer() { return m_lex; } void PrintErrorString(const std::string &err); template void PrintError(T&&... msgs) { std::ostringstream ostr; (ostr << ... << std::forward(msgs)); PrintErrorString(ostr.str()); } const std::vector& GetErrors() const { return m_errors; } void ClearErrors() { m_errors.clear(); } void SetLexerInput(std::istream &istr); void AddAST(std::shared_ptr ast) { m_asts.push_back(ast); } void ClearASTs() { m_asts.clear(); } const std::vector>& GetASTs() const { return m_asts; } void SetWorkspace(std::map> *ws) { m_workspace = ws; } std::map> * GetWorkspace() { return m_workspace; } void EmitWorkspaceUpdated(const std::string& ident="") { m_WorkspaceUpdated(ident); } boost::signals2::signal& GetWorkspaceUpdatedSignal() { return m_WorkspaceUpdated; } }; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Symbols // ---------------------------------------------------------------------------- enum class SymbolType { REAL, // e.g. 12.3 STRING, // e.g. "abc" LIST, // e.g. 1, 2, 3 ARRAY, // e.g. [1, 2, 3] MAP, // e.g. {"key" : 1.23} DATASET }; class Symbol { public: virtual ~Symbol() {} virtual SymbolType GetType() const = 0; virtual std::shared_ptr copy() const = 0; virtual void print(std::ostream& ostr) const = 0; virtual std::string serialise() const = 0; static std::shared_ptr unserialise(const std::string &str); static std::shared_ptr uminus(const Symbol &sym2); static std::shared_ptr add(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr sub(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr mul(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr div(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr mod(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr pow(const Symbol &sym1, const Symbol &sym2); static std::shared_ptr add(std::shared_ptr sym1, std::shared_ptr sym2); static std::shared_ptr sub(std::shared_ptr sym1, std::shared_ptr sym2); static std::shared_ptr mul(std::shared_ptr sym1, std::shared_ptr sym2); static std::shared_ptr div(std::shared_ptr sym1, std::shared_ptr sym2); static const std::string& get_type_name(const Symbol &sym); }; class SymbolReal : public Symbol { private: t_real_cli m_val = 0; public: SymbolReal() = default; SymbolReal(t_real_cli val) : m_val(val) {} virtual ~SymbolReal() {} virtual SymbolType GetType() const override { return SymbolType::REAL; } t_real_cli GetValue() const { return m_val; } void SetValue(t_real_cli val) { m_val = val; } virtual std::shared_ptr copy() const override { return std::make_shared(m_val); } virtual void print(std::ostream& ostr) const override { ostr << GetValue(); } virtual std::string serialise() const override; }; class SymbolString : public Symbol { private: std::string m_val; public: SymbolString() = default; SymbolString(const std::string& val) : m_val(val) {} SymbolString(std::string&& val) : m_val(val) {} virtual ~SymbolString() {} virtual SymbolType GetType() const override { return SymbolType::STRING; } const std::string& GetValue() const { return m_val; } virtual std::shared_ptr copy() const override { return std::make_shared(m_val); } virtual void print(std::ostream& ostr) const override { ostr << GetValue(); } virtual std::string serialise() const override; }; class SymbolList : public Symbol { private: std::vector> m_val; bool m_islist = true; // list or array public: SymbolList() = default; SymbolList(const std::vector>& val, bool islist=1) : m_val(val), m_islist(islist) {} SymbolList(std::vector>&& val, bool islist=1) : m_val(val), m_islist(islist) {} SymbolList(const std::initializer_list>& lst, bool islist=1) : m_islist(islist) { for(auto iter = lst.begin(); iter !=lst.end(); ++iter) m_val.push_back(*iter); } virtual ~SymbolList() {} virtual SymbolType GetType() const override { return m_islist ? SymbolType::LIST : SymbolType::ARRAY; } const std::vector>& GetValue() const { return m_val; } virtual std::shared_ptr copy() const override { return std::make_shared(m_val, m_islist); } virtual void print(std::ostream& ostr) const override { if(!m_islist) ostr << "[ "; for(std::size_t i=0; iprint(ostr); if(i < GetValue().size()-1) ostr << ", "; } if(!m_islist) ostr << " ]"; } virtual std::string serialise() const override; }; class SymbolDataset : public Symbol { private: Dataset m_val; public: SymbolDataset() = default; SymbolDataset(const Dataset& val) : m_val(val) {} SymbolDataset(Dataset&& val) : m_val(val) {} virtual ~SymbolDataset() {} virtual SymbolType GetType() const override { return SymbolType::DATASET; } const Dataset& GetValue() const { return m_val; } virtual std::shared_ptr copy() const override { return std::make_shared(m_val); } virtual void print(std::ostream& ostr) const override { ostr << "<Dataset>"; } virtual std::string serialise() const override; }; /** * write symbol to ostream */ static inline std::ostream& operator<< (std::ostream& ostr, const Symbol& sym) { sym.print(ostr); return ostr; } // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // AST // ---------------------------------------------------------------------------- enum class CliASTType { REAL, STRING, IDENT, ASSIGN, PLUS, MINUS, MULT, DIV, MOD, POW, CALL, EXPRLIST, ARRAY, ARRAYACCESS, }; class CliAST { protected: std::shared_ptr m_left; std::shared_ptr m_right; public: CliAST(std::shared_ptr left=nullptr, std::shared_ptr right=nullptr) : m_left(left), m_right(right) {} void SetLeft(std::shared_ptr left) { m_left = left; } void SetRight(std::shared_ptr right) { m_right = right; } virtual void Print(std::ostringstream &ostr, int indent = 0) const; virtual std::shared_ptr Eval(CliParserContext& ctx) const = 0; virtual CliASTType GetType() const = 0; }; class CliASTReal : public CliAST { protected: t_real_cli m_val = t_real_cli(0); public: CliASTReal(t_real_cli val) : m_val(val) { } virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::REAL; } t_real_cli GetValue() const { return m_val; } }; class CliASTString : public CliAST { protected: std::string m_val; public: CliASTString(const std::string& val) : m_val(val) { } virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::STRING; } const std::string& GetValue() const { return m_val; } }; class CliASTIdent : public CliAST { protected: std::string m_val; public: CliASTIdent(const std::string& val) : m_val(val) { } virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::IDENT; } const std::string& GetValue() const { return m_val; } }; class CliASTAssign : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::ASSIGN; } }; class CliASTPlus : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::PLUS; } }; class CliASTMinus : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::MINUS; } }; class CliASTMult : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::MULT; } }; class CliASTDiv : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::DIV; } }; class CliASTMod : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::MOD; } }; class CliASTPow : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::POW; } }; class CliASTCall : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::CALL; } }; class CliASTExprList : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::EXPRLIST; } }; class CliASTArray : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::ARRAY; } }; class CliASTArrayAccess : public CliAST { public: using CliAST::CliAST; virtual void Print(std::ostringstream &ostr, int indent = 0) const override; virtual std::shared_ptr Eval(CliParserContext& ctx) const override; virtual CliASTType GetType() const override { return CliASTType::ARRAYACCESS; } }; // ---------------------------------------------------------------------------- #undef YY_DECL #define YY_DECL yy::CliParser::symbol_type CliLexer::yylex(CliParserContext &context) extern yy::CliParser::symbol_type yylex(CliParserContext &context); #define yyterminate() return yy::CliParser::token::yytokentype(YY_NULL); #endif