shushus

Спринт 16. Ячейки.

Jun 20th, 2023
582
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.61 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. FindANTLR.cmake
  3. -----------------------------------------------------------------------
  4. find_package(Java QUIET COMPONENTS Runtime)
  5.  
  6. if(NOT ANTLR_EXECUTABLE)
  7.   find_program(ANTLR_EXECUTABLE
  8.                NAMES antlr.jar antlr4.jar antlr-4.jar antlr-4.12.0-complete.jar)
  9. endif()
  10.  
  11. if(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE)
  12.   execute_process(
  13.       COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}
  14.       OUTPUT_VARIABLE ANTLR_COMMAND_OUTPUT
  15.       ERROR_VARIABLE ANTLR_COMMAND_ERROR
  16.       RESULT_VARIABLE ANTLR_COMMAND_RESULT
  17.       OUTPUT_STRIP_TRAILING_WHITESPACE)
  18.  
  19.   if(ANTLR_COMMAND_RESULT EQUAL 0)
  20.     string(REGEX MATCH "Version [0-9]+(\\.[0-9]+)*" ANTLR_VERSION ${ANTLR_COMMAND_OUTPUT})
  21.     string(REPLACE "Version " "" ANTLR_VERSION ${ANTLR_VERSION})
  22.   else()
  23.     message(
  24.         SEND_ERROR
  25.         "Command '${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}' "
  26.         "failed with the output '${ANTLR_COMMAND_ERROR}'")
  27.   endif()
  28.  
  29.   macro(ANTLR_TARGET Name InputFile)
  30.     set(ANTLR_OPTIONS LEXER PARSER LISTENER VISITOR)
  31.     set(ANTLR_ONE_VALUE_ARGS PACKAGE OUTPUT_DIRECTORY DEPENDS_ANTLR)
  32.     set(ANTLR_MULTI_VALUE_ARGS COMPILE_FLAGS DEPENDS)
  33.     cmake_parse_arguments(ANTLR_TARGET
  34.                           "${ANTLR_OPTIONS}"
  35.                           "${ANTLR_ONE_VALUE_ARGS}"
  36.                           "${ANTLR_MULTI_VALUE_ARGS}"
  37.                           ${ARGN})
  38.  
  39.     set(ANTLR_${Name}_INPUT ${InputFile})
  40.  
  41.     get_filename_component(ANTLR_INPUT ${InputFile} NAME_WE)
  42.  
  43.     if(ANTLR_TARGET_OUTPUT_DIRECTORY)
  44.       set(ANTLR_${Name}_OUTPUT_DIR ${ANTLR_TARGET_OUTPUT_DIRECTORY})
  45.     else()
  46.       set(ANTLR_${Name}_OUTPUT_DIR
  47.           ${CMAKE_CURRENT_BINARY_DIR}/antlr4cpp_generated_src/${ANTLR_INPUT})
  48.     endif()
  49.  
  50.     unset(ANTLR_${Name}_CXX_OUTPUTS)
  51.  
  52.     if((ANTLR_TARGET_LEXER AND NOT ANTLR_TARGET_PARSER) OR
  53.        (ANTLR_TARGET_PARSER AND NOT ANTLR_TARGET_LEXER))
  54.       list(APPEND ANTLR_${Name}_CXX_OUTPUTS
  55.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.h
  56.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.cpp)
  57.       set(ANTLR_${Name}_OUTPUTS
  58.           ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.interp
  59.           ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.tokens)
  60.     else()
  61.       list(APPEND ANTLR_${Name}_CXX_OUTPUTS
  62.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.h
  63.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.cpp
  64.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.h
  65.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.cpp)
  66.       list(APPEND ANTLR_${Name}_OUTPUTS
  67.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.interp
  68.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.tokens)
  69.     endif()
  70.  
  71.     if(ANTLR_TARGET_LISTENER)
  72.       list(APPEND ANTLR_${Name}_CXX_OUTPUTS
  73.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.h
  74.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.cpp
  75.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.h
  76.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.cpp)
  77.       list(APPEND ANTLR_TARGET_COMPILE_FLAGS -listener)
  78.     endif()
  79.  
  80.     if(ANTLR_TARGET_VISITOR)
  81.       list(APPEND ANTLR_${Name}_CXX_OUTPUTS
  82.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.h
  83.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.cpp
  84.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.h
  85.            ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.cpp)
  86.       list(APPEND ANTLR_TARGET_COMPILE_FLAGS -visitor)
  87.     endif()
  88.  
  89.     if(ANTLR_TARGET_PACKAGE)
  90.       list(APPEND ANTLR_TARGET_COMPILE_FLAGS -package ${ANTLR_TARGET_PACKAGE})
  91.     endif()
  92.  
  93.     list(APPEND ANTLR_${Name}_OUTPUTS ${ANTLR_${Name}_CXX_OUTPUTS})
  94.  
  95.     if(ANTLR_TARGET_DEPENDS_ANTLR)
  96.       if(ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT)
  97.         list(APPEND ANTLR_TARGET_DEPENDS
  98.              ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT})
  99.         list(APPEND ANTLR_TARGET_DEPENDS
  100.              ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_OUTPUTS})
  101.       else()
  102.         message(SEND_ERROR
  103.                 "ANTLR target '${ANTLR_TARGET_DEPENDS_ANTLR}' not found")
  104.       endif()
  105.     endif()
  106.  
  107.     add_custom_command(
  108.         OUTPUT ${ANTLR_${Name}_OUTPUTS}
  109.         COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}
  110.                 ${InputFile}
  111.                 -o ${ANTLR_${Name}_OUTPUT_DIR}
  112.                 -no-listener
  113.                 -Dlanguage=Cpp
  114.                 ${ANTLR_TARGET_COMPILE_FLAGS}
  115.         DEPENDS ${InputFile}
  116.                 ${ANTLR_TARGET_DEPENDS}
  117.         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  118.         COMMENT "Building ${Name} with ANTLR ${ANTLR_VERSION}")
  119.   endmacro(ANTLR_TARGET)
  120.  
  121. endif(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE)
  122.  
  123. include(FindPackageHandleStandardArgs)
  124. find_package_handle_standard_args(
  125.     ANTLR
  126.     REQUIRED_VARS ANTLR_EXECUTABLE Java_JAVA_EXECUTABLE
  127.     VERSION_VAR ANTLR_VERSION)
  128. -----------------------------------------------------------------------
  129. CMakeLists.txt
  130. -----------------------------------------------------------------------
  131. cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
  132. project(spreadsheet)
  133.  
  134. set(CMAKE_CXX_STANDARD 17)
  135. if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
  136.     set(
  137.         CMAKE_CXX_FLAGS_DEBUG
  138.         "${CMAKE_CXX_FLAGS_DEBUG} /JMC"
  139.     )
  140. else()
  141.     set(
  142.         CMAKE_CXX_FLAGS
  143.         "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-implicit-fallthrough"
  144.     )
  145. endif()
  146.  
  147. set(ANTLR_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/antlr-4.12.0-complete.jar)
  148. include(${CMAKE_CURRENT_SOURCE_DIR}/FindANTLR.cmake)
  149.  
  150. add_definitions(
  151.     -DANTLR4CPP_STATIC
  152.     -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
  153. )
  154.  
  155. set(WITH_STATIC_CRT OFF CACHE BOOL "Visual C++ static CRT for ANTLR" FORCE)
  156. add_subdirectory(antlr4_runtime)
  157.  
  158. antlr_target(FormulaParser Formula.g4 LEXER PARSER LISTENER)
  159.  
  160. include_directories(
  161.     ${ANTLR4_INCLUDE_DIRS}
  162.     ${ANTLR_FormulaParser_OUTPUT_DIR}
  163.     ${CMAKE_CURRENT_SOURCE_DIR}/antlr4_runtime/runtime/src
  164. )
  165.  
  166. file(GLOB sources
  167.     *.cpp
  168.     *.h
  169. )
  170.  
  171. add_executable(
  172.     spreadsheet
  173.     ${ANTLR_FormulaParser_CXX_OUTPUTS}
  174.     ${sources}
  175. )
  176.  
  177. target_link_libraries(spreadsheet antlr4_static)
  178. if(MSVC)
  179.     target_compile_options(antlr4_static PRIVATE /W0)
  180. endif()
  181.  
  182. install(
  183.     TARGETS spreadsheet
  184.     DESTINATION bin
  185.     EXPORT spreadsheet
  186. )
  187.  
  188. set_directory_properties(PROPERTIES VS_STARTUP_PROJECT spreadsheet)
  189. -----------------------------------------------------------------------
  190. common.h
  191. -----------------------------------------------------------------------
  192. #pragma once
  193.  
  194. #include <iosfwd>
  195. #include <memory>
  196. #include <stdexcept>
  197. #include <string>
  198. #include <string_view>
  199. #include <variant>
  200.  
  201. class FormulaError : public std::runtime_error {
  202.     public:
  203.     using std::runtime_error::runtime_error;
  204. };
  205.  
  206. std::ostream& operator<<(std::ostream& output, FormulaError fe);
  207.  
  208. class FormulaException : public std::runtime_error {
  209.     public:
  210.     using std::runtime_error::runtime_error;
  211. };
  212.  
  213. inline constexpr char FORMULA_SIGN = '=';
  214. inline constexpr char ESCAPE_SIGN = '\'';
  215.  
  216. class CellInterface {
  217.     public:
  218.  
  219.     using Value = std::variant<std::string, double, FormulaError>;
  220.  
  221.     virtual ~CellInterface() = default;
  222.     virtual void Set(std::string text) = 0;
  223.     virtual Value GetValue() const = 0;
  224.     virtual std::string GetText() const = 0;
  225. }; 
  226. -----------------------------------------------------------------------
  227. Formula.g4
  228. -----------------------------------------------------------------------
  229. grammar Formula;
  230.  
  231. main
  232.     : expr EOF
  233.     ;
  234.  
  235. expr
  236.     : '(' expr ')'  # Parens
  237.     | (ADD | SUB) expr  # UnaryOp
  238.     | expr (MUL | DIV) expr  # BinaryOp
  239.     | expr (ADD | SUB) expr  # BinaryOp
  240.     | NUMBER  # Literal
  241.     ;
  242.  
  243. fragment INT: [-+]? UINT ;
  244. fragment UINT: [0-9]+ ;
  245. fragment EXPONENT: [eE] INT;
  246. NUMBER
  247.     : UINT EXPONENT?
  248.     | UINT? '.' UINT EXPONENT?
  249.     ;
  250.  
  251. ADD: '+' ;
  252. SUB: '-' ;
  253. MUL: '*' ;
  254. DIV: '/' ;
  255. WS: [ \t\n\r]+ -> skip ;
  256. -----------------------------------------------------------------------
  257. FormulaAST.h
  258. -----------------------------------------------------------------------
  259. #pragma once
  260.  
  261. #include "FormulaLexer.h"
  262. #include "common.h"
  263.  
  264. #include <forward_list>
  265. #include <functional>
  266. #include <stdexcept>
  267.  
  268. namespace ASTImpl {
  269. class Expr;
  270. }
  271.  
  272. class ParsingError : public std::runtime_error {
  273.     using std::runtime_error::runtime_error;
  274. };
  275.  
  276. class FormulaAST {
  277. public:
  278.     explicit FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr);
  279.     FormulaAST(FormulaAST&&) = default;
  280.     FormulaAST& operator=(FormulaAST&&) = default;
  281.     ~FormulaAST();
  282.  
  283.     double Execute() const;
  284.     void Print(std::ostream& out) const;
  285.     void PrintFormula(std::ostream& out) const;
  286.  
  287. private:
  288.     std::unique_ptr<ASTImpl::Expr> root_expr_;
  289. };
  290.  
  291. FormulaAST ParseFormulaAST(std::istream& in);
  292. FormulaAST ParseFormulaAST(const std::string& in_str);
  293. -----------------------------------------------------------------------
  294. FormulaAST.cpp
  295. -----------------------------------------------------------------------
  296. #include "FormulaAST.h"
  297.  
  298. #include "FormulaBaseListener.h"
  299. #include "FormulaLexer.h"
  300. #include "FormulaParser.h"
  301.  
  302. #include <cassert>
  303. #include <cmath>
  304. #include <memory>
  305. #include <optional>
  306. #include <sstream>
  307.  
  308. namespace ASTImpl {
  309.  
  310. enum ExprPrecedence {
  311.     EP_ADD,
  312.     EP_SUB,
  313.     EP_MUL,
  314.     EP_DIV,
  315.     EP_UNARY,
  316.     EP_ATOM,
  317.     EP_END,
  318. };
  319.  
  320. enum PrecedenceRule {
  321.     PR_NONE = 0b00,              
  322.     PR_LEFT = 0b01,              
  323.     PR_RIGHT = 0b10,              
  324.     PR_BOTH = PR_LEFT | PR_RIGHT,  
  325. };
  326.  
  327. constexpr PrecedenceRule PRECEDENCE_RULES[EP_END][EP_END] = {
  328.     /* EP_ADD */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  329.     /* EP_SUB */ {PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  330.     /* EP_MUL */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  331.     /* EP_DIV */ {PR_BOTH, PR_BOTH, PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE},
  332.     /* EP_UNARY */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  333.     /* EP_ATOM */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  334. };
  335.  
  336. class Expr {
  337. public:
  338.     virtual ~Expr() = default;
  339.     virtual void Print(std::ostream& out) const = 0;
  340.     virtual void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const = 0;
  341.     virtual double Evaluate() const = 0;
  342.  
  343.     virtual ExprPrecedence GetPrecedence() const = 0;
  344.  
  345.     void PrintFormula(std::ostream& out, ExprPrecedence parent_precedence,
  346.                       bool right_child = false) const {
  347.         auto precedence = GetPrecedence();
  348.         auto mask = right_child ? PR_RIGHT : PR_LEFT;
  349.         bool parens_needed = PRECEDENCE_RULES[parent_precedence][precedence] & mask;
  350.         if (parens_needed) {
  351.             out << '(';
  352.         }
  353.  
  354.         DoPrintFormula(out, precedence);
  355.  
  356.         if (parens_needed) {
  357.             out << ')';
  358.         }
  359.     }
  360. };
  361.  
  362. namespace {
  363. class BinaryOpExpr final : public Expr {
  364. public:
  365.     enum Type : char {
  366.         Add = '+',
  367.         Subtract = '-',
  368.         Multiply = '*',
  369.         Divide = '/',
  370.     };
  371.  
  372. public:
  373.     explicit BinaryOpExpr(Type type, std::unique_ptr<Expr> lhs, std::unique_ptr<Expr> rhs)
  374.         : type_(type)
  375.         , lhs_(std::move(lhs))
  376.         , rhs_(std::move(rhs)) {
  377.     }
  378.  
  379.     void Print(std::ostream& out) const override {
  380.         out << '(' << static_cast<char>(type_) << ' ';
  381.         lhs_->Print(out);
  382.         out << ' ';
  383.         rhs_->Print(out);
  384.         out << ')';
  385.     }
  386.  
  387.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  388.         lhs_->PrintFormula(out, precedence);
  389.         out << static_cast<char>(type_);
  390.         rhs_->PrintFormula(out, precedence, /* right_child = */ true);
  391.     }
  392.  
  393.     ExprPrecedence GetPrecedence() const override {
  394.         switch (type_) {
  395.             case Add:
  396.                 return EP_ADD;
  397.             case Subtract:
  398.                 return EP_SUB;
  399.             case Multiply:
  400.                 return EP_MUL;
  401.             case Divide:
  402.                 return EP_DIV;
  403.             default:
  404.                 assert(false);
  405.                 return static_cast<ExprPrecedence>(INT_MAX);
  406.         }
  407.     }
  408.  
  409.     double Evaluate() const override {
  410.        
  411.         switch (type_) {
  412.                
  413.             case Add:
  414.                 return lhs_->Evaluate() + rhs_->Evaluate();
  415.                
  416.             case Subtract:
  417.                 return lhs_->Evaluate() - rhs_->Evaluate();
  418.                
  419.             case Multiply:
  420.                 return lhs_->Evaluate() * rhs_->Evaluate();
  421.            
  422.             case Divide:
  423.                
  424.                 if (rhs_->Evaluate() != 0) {
  425.                     return lhs_->Evaluate() / rhs_->Evaluate();
  426.                    
  427.                 } else {
  428.                     throw FormulaError("DIV/0");
  429.                 }  
  430.            
  431.             default:
  432.                 throw FormulaError("unidentified operation type");
  433.         }
  434.     }
  435.  
  436. private:
  437.     Type type_;
  438.     std::unique_ptr<Expr> lhs_;
  439.     std::unique_ptr<Expr> rhs_;
  440. };
  441.  
  442. class UnaryOpExpr final : public Expr {
  443. public:
  444.     enum Type : char {
  445.         UnaryPlus = '+',
  446.         UnaryMinus = '-',
  447.     };
  448.  
  449. public:
  450.     explicit UnaryOpExpr(Type type, std::unique_ptr<Expr> operand)
  451.         : type_(type)
  452.         , operand_(std::move(operand)) {
  453.     }
  454.  
  455.     void Print(std::ostream& out) const override {
  456.         out << '(' << static_cast<char>(type_) << ' ';
  457.         operand_->Print(out);
  458.         out << ')';
  459.     }
  460.  
  461.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  462.         out << static_cast<char>(type_);
  463.         operand_->PrintFormula(out, precedence);
  464.     }
  465.  
  466.     ExprPrecedence GetPrecedence() const override {
  467.         return EP_UNARY;
  468.     }
  469.  
  470.     double Evaluate() const override {
  471.      
  472.         switch (type_) {
  473.                
  474.             case UnaryPlus:
  475.                 return operand_->Evaluate();
  476.                
  477.             case UnaryMinus:
  478.                 return -operand_->Evaluate();
  479.            
  480.             default:
  481.                 throw FormulaError("unidentified operation type");
  482.         }
  483.     }
  484.  
  485. private:
  486.     Type type_;
  487.     std::unique_ptr<Expr> operand_;
  488. };
  489.  
  490. class NumberExpr final : public Expr {
  491. public:
  492.     explicit NumberExpr(double value)
  493.         : value_(value) {
  494.     }
  495.  
  496.     void Print(std::ostream& out) const override {
  497.         out << value_;
  498.     }
  499.  
  500.     void DoPrintFormula(std::ostream& out, ExprPrecedence /* precedence */) const override {
  501.         out << value_;
  502.     }
  503.  
  504.     ExprPrecedence GetPrecedence() const override {
  505.         return EP_ATOM;
  506.     }
  507.  
  508.     double Evaluate() const override {
  509.         return value_;
  510.     }
  511.  
  512. private:
  513.     double value_;
  514. };
  515.  
  516. class ParseASTListener final : public FormulaBaseListener {
  517. public:
  518.     std::unique_ptr<Expr> MoveRoot() {
  519.         assert(args_.size() == 1);
  520.         auto root = std::move(args_.front());
  521.         args_.clear();
  522.  
  523.         return root;
  524.     }
  525.  
  526. public:
  527.     void exitUnaryOp(FormulaParser::UnaryOpContext* ctx) override {
  528.         assert(args_.size() >= 1);
  529.  
  530.         auto operand = std::move(args_.back());
  531.  
  532.         UnaryOpExpr::Type type;
  533.         if (ctx->SUB()) {
  534.             type = UnaryOpExpr::UnaryMinus;
  535.         } else {
  536.             assert(ctx->ADD() != nullptr);
  537.             type = UnaryOpExpr::UnaryPlus;
  538.         }
  539.  
  540.         auto node = std::make_unique<UnaryOpExpr>(type, std::move(operand));
  541.         args_.back() = std::move(node);
  542.     }
  543.  
  544.     void exitLiteral(FormulaParser::LiteralContext* ctx) override {
  545.         double value = 0;
  546.         auto valueStr = ctx->NUMBER()->getSymbol()->getText();
  547.         std::istringstream in(valueStr);
  548.         in >> value;
  549.         if (!in) {
  550.             throw ParsingError("Invalid number: " + valueStr);
  551.         }
  552.  
  553.         auto node = std::make_unique<NumberExpr>(value);
  554.         args_.push_back(std::move(node));
  555.     }
  556.  
  557.     void exitBinaryOp(FormulaParser::BinaryOpContext* ctx) override {
  558.         assert(args_.size() >= 2);
  559.  
  560.         auto rhs = std::move(args_.back());
  561.         args_.pop_back();
  562.  
  563.         auto lhs = std::move(args_.back());
  564.  
  565.         BinaryOpExpr::Type type;
  566.         if (ctx->ADD()) {
  567.             type = BinaryOpExpr::Add;
  568.         } else if (ctx->SUB()) {
  569.             type = BinaryOpExpr::Subtract;
  570.         } else if (ctx->MUL()) {
  571.             type = BinaryOpExpr::Multiply;
  572.         } else {
  573.             assert(ctx->DIV() != nullptr);
  574.             type = BinaryOpExpr::Divide;
  575.         }
  576.  
  577.         auto node = std::make_unique<BinaryOpExpr>(type, std::move(lhs), std::move(rhs));
  578.         args_.back() = std::move(node);
  579.     }
  580.  
  581.     void visitErrorNode(antlr4::tree::ErrorNode* node) override {
  582.         throw ParsingError("Error when parsing: " + node->getSymbol()->getText());
  583.     }
  584.  
  585. private:
  586.     std::vector<std::unique_ptr<Expr>> args_;
  587. };
  588.  
  589. class BailErrorListener : public antlr4::BaseErrorListener {
  590. public:
  591.     void syntaxError(antlr4::Recognizer* /* recognizer */, antlr4::Token* /* offendingSymbol */,
  592.                      size_t /* line */, size_t /* charPositionInLine */, const std::string& msg,
  593.                      std::exception_ptr /* e */
  594.                      ) override {
  595.         throw ParsingError("Error when lexing: " + msg);
  596.     }
  597. };
  598.  
  599. }//end namespace
  600. }//end namespace ASTImpl
  601.  
  602. FormulaAST ParseFormulaAST(std::istream& in) {
  603.     using namespace antlr4;
  604.  
  605.     ANTLRInputStream input(in);
  606.  
  607.     FormulaLexer lexer(&input);
  608.     ASTImpl::BailErrorListener error_listener;
  609.     lexer.removeErrorListeners();
  610.     lexer.addErrorListener(&error_listener);
  611.  
  612.     CommonTokenStream tokens(&lexer);
  613.  
  614.     FormulaParser parser(&tokens);
  615.     auto error_handler = std::make_shared<BailErrorStrategy>();
  616.     parser.setErrorHandler(error_handler);
  617.     parser.removeErrorListeners();
  618.  
  619.     tree::ParseTree* tree = parser.main();
  620.     ASTImpl::ParseASTListener listener;
  621.     tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
  622.  
  623.     return FormulaAST(listener.MoveRoot());
  624. }
  625.  
  626. FormulaAST ParseFormulaAST(const std::string& in_str) {
  627.     std::istringstream in(in_str);
  628.     try {
  629.         return ParseFormulaAST(in);
  630.     } catch (const std::exception& exc) {
  631.         std::throw_with_nested(FormulaException(exc.what()));
  632.     }
  633. }
  634.  
  635. void FormulaAST::Print(std::ostream& out) const {
  636.     root_expr_->Print(out);
  637. }
  638.  
  639. void FormulaAST::PrintFormula(std::ostream& out) const {
  640.     root_expr_->PrintFormula(out, ASTImpl::EP_ATOM);
  641. }
  642.  
  643. double FormulaAST::Execute() const {
  644.     return root_expr_->Evaluate();
  645. }
  646.  
  647. FormulaAST::FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr)
  648.     : root_expr_(std::move(root_expr)) {
  649. }
  650.  
  651. FormulaAST::~FormulaAST() = default;
  652. -----------------------------------------------------------------------
  653. main.cpp
  654. -----------------------------------------------------------------------
  655. #include "cell.h"
  656. #include "common.h"
  657. #include "formula.h"
  658. #include "test_runner_p.h"
  659.  
  660. inline std::ostream& operator<<(std::ostream& output, const CellInterface::Value& value) {
  661.     std::visit([&](const auto& x) { output << x; }, value);
  662.     return output;
  663. }
  664.  
  665. std::unique_ptr<CellInterface> CreateCell(const std::string& str) {
  666.     std::unique_ptr<CellInterface> cell = std::make_unique<Cell>();
  667.     cell->Set(str);
  668.     return cell;
  669. }
  670.  
  671. int main() {
  672.  
  673.     auto simple_text = CreateCell("simple_text");
  674.     ASSERT_EQUAL(simple_text->GetText(), "simple_text");
  675.     ASSERT_EQUAL(std::get<std::string>(simple_text->GetValue()), "simple_text");
  676.  
  677.     auto empty_apostroph = CreateCell("'");
  678.     ASSERT_EQUAL(empty_apostroph->GetText(), "'");
  679.     ASSERT_EQUAL(std::get<std::string>(empty_apostroph->GetValue()), "");
  680.  
  681.     auto apostroph = CreateCell("'apostroph");
  682.     ASSERT_EQUAL(apostroph->GetText(), "'apostroph");
  683.     ASSERT_EQUAL(std::get<std::string>(apostroph->GetValue()), "apostroph");
  684.  
  685.     auto text_formula = CreateCell("'=1+2");
  686.     ASSERT_EQUAL(text_formula->GetText(), "'=1+2");
  687.     ASSERT_EQUAL(std::get<std::string>(text_formula->GetValue()), "=1+2");
  688.  
  689.     auto empty_formula = CreateCell("=");
  690.     ASSERT_EQUAL(empty_formula->GetText(), "=");
  691.     ASSERT_EQUAL(std::get<std::string>(empty_formula->GetValue()), "=");
  692.  
  693.     auto formula = CreateCell("=1+2");
  694.     ASSERT_EQUAL(formula->GetText(), "=1+2");
  695.     ASSERT_EQUAL(std::get<double>(formula->GetValue()), 3);
  696.  
  697.     auto switch_text = CreateCell("1+2");
  698.     ASSERT_EQUAL(switch_text->GetText(), "1+2");
  699.     ASSERT_EQUAL(std::get<std::string>(switch_text->GetValue()), "1+2");
  700.  
  701.     switch_text->Set("=1+2");
  702.     ASSERT_EQUAL(switch_text->GetText(), "=1+2");
  703.     ASSERT_EQUAL(std::get<double>(switch_text->GetValue()), 3);
  704.  
  705.     switch_text->Set("=1/0");
  706.     ASSERT_EQUAL(switch_text->GetText(), "=1/0");
  707.     std::cout << std::get<FormulaError>(switch_text->GetValue()) << std::endl;
  708.  
  709.     std::cout << "All tests passed" << std::endl;
  710.     return 0;
  711. }
  712. -----------------------------------------------------------------------
  713. test_runner_p.h
  714. -----------------------------------------------------------------------
  715. #pragma once
  716.  
  717. #include <iostream>
  718. #include <map>
  719. #include <set>
  720. #include <sstream>
  721. #include <stdexcept>
  722. #include <string>
  723. #include <unordered_map>
  724. #include <vector>
  725.  
  726. namespace TestRunnerPrivate {
  727.   template <typename K, typename V, template <typename, typename> class Map>
  728.   std::ostream& PrintMap(std::ostream& os, const Map<K, V>& m) {
  729.     os << "{";
  730.     bool first = true;
  731.     for (const auto& kv : m) {
  732.       if (!first) {
  733.         os << ", ";
  734.       }
  735.       first = false;
  736.       os << kv.first << ": " << kv.second;
  737.     }
  738.     return os << "}";
  739.   }
  740. }
  741.  
  742. template <class T>
  743. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  744.   os << "{";
  745.   bool first = true;
  746.   for (const auto& x : s) {
  747.     if (!first) {
  748.       os << ", ";
  749.     }
  750.     first = false;
  751.     os << x;
  752.   }
  753.   return os << "}";
  754. }
  755.  
  756. template <class T>
  757. std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
  758.   os << "{";
  759.   bool first = true;
  760.   for (const auto& x : s) {
  761.     if (!first) {
  762.       os << ", ";
  763.     }
  764.     first = false;
  765.     os << x;
  766.   }
  767.   return os << "}";
  768. }
  769.  
  770. template <class K, class V>
  771. std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
  772.   return TestRunnerPrivate::PrintMap(os, m);
  773. }
  774.  
  775. template <class K, class V>
  776. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {
  777.   return TestRunnerPrivate::PrintMap(os, m);
  778. }
  779.  
  780. template <class T, class U>
  781. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  782.   if (!(t == u)) {
  783.     std::ostringstream os;
  784.     os << "Assertion failed: " << t << " != " << u;
  785.     if (!hint.empty()) {
  786.       os << " hint: " << hint;
  787.     }
  788.     throw std::runtime_error(os.str());
  789.   }
  790. }
  791.  
  792. inline void Assert(bool b, const std::string& hint) {
  793.   AssertEqual(b, true, hint);
  794. }
  795.  
  796. class TestRunner {
  797. public:
  798.   template <class TestFunc>
  799.   void RunTest(TestFunc func, const std::string& test_name) {
  800.     try {
  801.       func();
  802.       std::cerr << test_name << " OK" << std::endl;
  803.     } catch (std::exception& e) {
  804.       ++fail_count;
  805.       std::cerr << test_name << " fail: " << e.what() << std::endl;
  806.     } catch (...) {
  807.       ++fail_count;
  808.       std::cerr << "Unknown exception caught" << std::endl;
  809.     }
  810.   }
  811.  
  812.   ~TestRunner() {
  813.     std::cerr.flush();
  814.     if (fail_count > 0) {
  815.       std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  816.       exit(1);
  817.     }
  818.   }
  819.  
  820. private:
  821.   int fail_count = 0;
  822. };
  823.  
  824. #ifndef FILE_NAME
  825. #define FILE_NAME __FILE__
  826. #endif
  827.  
  828. #define ASSERT_EQUAL(x, y)                                               \
  829.   {                                                                      \
  830.     std::ostringstream __assert_equal_private_os;                        \
  831.     __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME \
  832.                               << ":" << __LINE__;                        \
  833.     AssertEqual(x, y, __assert_equal_private_os.str());                  \
  834.   }
  835.  
  836. #define ASSERT(x)                                                  \
  837.   {                                                                \
  838.     std::ostringstream __assert_private_os;                        \
  839.     __assert_private_os << #x << " is false, " << FILE_NAME << ":" \
  840.                         << __LINE__;                               \
  841.     Assert(x, __assert_private_os.str());                          \
  842.   }
  843.  
  844. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  845. -----------------------------------------------------------------------
  846. formula.h
  847. -----------------------------------------------------------------------
  848. #pragma once
  849.  
  850. #include "common.h"
  851.  
  852. #include "FormulaAST.h"
  853.  
  854. #include <memory>
  855. #include <variant>
  856.  
  857. class FormulaInterface {
  858. public:
  859.     using Value = std::variant<double, FormulaError>;
  860.  
  861.     virtual ~FormulaInterface() = default;
  862.     virtual Value Evaluate() const = 0;
  863.     virtual std::string GetExpression() const = 0;
  864. };
  865.  
  866. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression);
  867. -----------------------------------------------------------------------
  868. formula.cpp
  869. -----------------------------------------------------------------------
  870. #include "formula.h"
  871.  
  872. #include "FormulaAST.h"
  873.  
  874. #include <algorithm>
  875. #include <cassert>
  876. #include <cctype>
  877. #include <sstream>
  878.  
  879. using namespace std::literals;
  880.  
  881. std::ostream& operator<<(std::ostream& output, FormulaError fe) {
  882.     return output << "#DIV/0!";
  883. }
  884.  
  885. namespace {
  886. class Formula : public FormulaInterface {
  887. public:
  888.    
  889.     explicit Formula(std::string expression) try : ast_(ParseFormulaAST(expression)) {}
  890.     catch (...) {
  891.         throw FormulaException("formula is syntactically incorrect");
  892.     }
  893.    
  894.     Value Evaluate() const override {
  895.        
  896.         try {
  897.             return ast_.Execute();
  898.            
  899.         } catch (const FormulaError& evaluate_error) {
  900.             return evaluate_error;
  901.         }
  902.     }
  903.    
  904.     std::string GetExpression() const override {
  905.         std::ostringstream out;
  906.         ast_.PrintFormula(out);
  907.        
  908.         return out.str();
  909.     }
  910.  
  911. private:
  912.     FormulaAST ast_;
  913. };
  914.    
  915. }//end namespace
  916.  
  917. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression) {
  918.     return std::make_unique<Formula>(std::move(expression));
  919. }
  920. -----------------------------------------------------------------------
  921. cell.cpp
  922. -----------------------------------------------------------------------
  923. #include "cell.h"
  924.  
  925. #include <cassert>
  926. #include <iostream>
  927. #include <string>
  928. #include <optional>
  929.  
  930. Cell::Cell() : impl_(std::make_unique<EmptyImpl>()) {}
  931. Cell::~Cell() = default;
  932.  
  933. void Cell::Set(std::string text) {
  934.    
  935.     if (text.empty()) {
  936.         impl_ = std::make_unique<EmptyImpl>();
  937.         return;
  938.        
  939.     } else if (text.size() >= 2 && text.at(0) == FORMULA_SIGN) {
  940.         impl_ = std::move(std::make_unique<FormulaImpl>(std::move(text)));
  941.         return;
  942.        
  943.     } else {
  944.         impl_ = std::move(std::make_unique<TextImpl>(std::move(text)));
  945.         return;
  946.     }
  947. }
  948.  
  949. void Cell::Clear() {
  950.     impl_ = std::make_unique<EmptyImpl>();
  951. }
  952.  
  953. Cell::Value Cell::GetValue() const {return impl_->GetValue();}
  954. std::string Cell::GetText() const {return impl_->GetText();}
  955.  
  956. Cell::Value Cell::EmptyImpl::GetValue() const {return "";}
  957. std::string Cell::EmptyImpl::GetText() const {return "";}
  958.  
  959. Cell::TextImpl::TextImpl(std::string text) : text_(std::move(text)) {}
  960.  
  961. Cell::Value Cell::TextImpl::GetValue() const {
  962.     if (text_.empty()) {
  963.         throw std::logic_error("it is empty impl, not text");
  964.        
  965.     } else if (text_.at(0) == ESCAPE_SIGN) {
  966.         return text_.substr(1);
  967.        
  968.     } else {
  969.         return text_;    
  970.     }      
  971. }
  972.  
  973. std::string Cell::TextImpl::GetText() const {return text_;}
  974.  
  975. Cell::FormulaImpl::FormulaImpl(std::string text) : formula_ptr_(ParseFormula(text.substr(1))) {}
  976.  
  977. Cell::Value Cell::FormulaImpl::GetValue() const {            
  978.     auto helper = formula_ptr_->Evaluate();
  979.    
  980.     if (std::holds_alternative<double>(helper)) {
  981.         return std::get<double>(helper);
  982.     } else {
  983.         return std::get<FormulaError>(helper);  
  984.     }      
  985. }
  986.  
  987. std::string Cell::FormulaImpl::GetText() const {return FORMULA_SIGN + formula_ptr_->GetExpression();}
  988. -----------------------------------------------------------------------
  989. cell.h
  990. -----------------------------------------------------------------------
  991. #pragma once
  992.  
  993. #include "common.h"
  994. #include "formula.h"
  995.  
  996. class Cell : public CellInterface {
  997. public:
  998.     Cell();
  999.     ~Cell();
  1000.  
  1001.     void Set(std::string text);
  1002.     void Clear();
  1003.  
  1004.     Value GetValue() const override;
  1005.     std::string GetText() const override;
  1006.  
  1007. private:
  1008.    
  1009.     class Impl {
  1010.     public:
  1011.        
  1012.         virtual Value GetValue() const = 0;
  1013.         virtual std::string GetText() const = 0;
  1014.        
  1015.         virtual ~Impl() = default;
  1016.     };
  1017.    
  1018.     class EmptyImpl : public Impl {
  1019.     public:    
  1020.        
  1021.         Value GetValue() const override;
  1022.         std::string GetText() const override;      
  1023.     };
  1024.    
  1025.     class TextImpl : public Impl {
  1026.     public:
  1027.        
  1028.         explicit TextImpl(std::string text);
  1029.         Value GetValue() const override;      
  1030.         std::string GetText() const override;
  1031.        
  1032.     private:
  1033.         std::string text_;        
  1034.     };
  1035.    
  1036.     class FormulaImpl : public Impl {
  1037.     public:
  1038.        
  1039.         explicit FormulaImpl(std::string text);
  1040.         Value GetValue() const override;
  1041.         std::string GetText() const override;
  1042.        
  1043.     private:
  1044.         std::unique_ptr<FormulaInterface> formula_ptr_;        
  1045.     };
  1046.    
  1047.     std::unique_ptr<Impl> impl_;
  1048. };
Advertisement
Add Comment
Please, Sign In to add comment