shushus

Спринт 16. Реализация таблицы целиком.

Jun 20th, 2023
1,870
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 57.10 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. #include <vector>
  201.  
  202. struct Position {
  203.     int row = 0;
  204.     int col = 0;
  205.  
  206.     bool operator==(Position rhs) const;
  207.     bool operator<(Position rhs) const;
  208.  
  209.     bool IsValid() const;
  210.     std::string ToString() const;
  211.  
  212.     static Position FromString(std::string_view str);
  213.  
  214.     static const int MAX_ROWS = 16384;
  215.     static const int MAX_COLS = 16384;
  216.     static const Position NONE;
  217. };
  218.  
  219. struct Size {
  220.     int rows = 0;
  221.     int cols = 0;
  222.  
  223.     bool operator==(Size rhs) const;
  224. };
  225.  
  226. class FormulaError {
  227. public:
  228.     enum class Category {
  229.         Ref,    
  230.         Value,  
  231.         Div0,  
  232.     };
  233.  
  234.     FormulaError(Category category) {category_ = category;}
  235.     Category GetCategory() const {return category_;}
  236.     bool operator==(FormulaError rhs) const{return category_ == rhs.category_;}
  237.  
  238.     std::string_view ToString() const {
  239.        
  240.         switch (category_) {
  241.                
  242.             case Category::Ref:
  243.                 return "#REF!";
  244.                
  245.             case Category::Value:
  246.                 return "#VALUE!";
  247.                
  248.             case Category::Div0:
  249.                 return "#DIV/0!";
  250.         }
  251.         return "";
  252.     }
  253.  
  254. private:
  255.     Category category_;
  256. };
  257.  
  258. std::ostream& operator<<(std::ostream& output, FormulaError fe);
  259.  
  260. class InvalidPositionException : public std::out_of_range {
  261. public:
  262.     using std::out_of_range::out_of_range;
  263. };
  264.  
  265. class FormulaException : public std::runtime_error {
  266. public:
  267.     using std::runtime_error::runtime_error;
  268. };
  269.  
  270. class CircularDependencyException : public std::runtime_error {
  271. public:
  272.     using std::runtime_error::runtime_error;
  273. };
  274.  
  275. class CellInterface {
  276. public:
  277.  
  278.     using Value = std::variant<std::string, double, FormulaError>;
  279.  
  280.     virtual ~CellInterface() = default;
  281.     virtual Value GetValue() const = 0;
  282.     virtual std::string GetText() const = 0;
  283.     virtual std::vector<Position> GetReferencedCells() const = 0;
  284. };
  285.  
  286. inline constexpr char FORMULA_SIGN = '=';
  287. inline constexpr char ESCAPE_SIGN = '\'';
  288.  
  289. class SheetInterface {
  290. public:
  291.    
  292.     virtual ~SheetInterface() = default;
  293.  
  294.     virtual void SetCell(Position pos, std::string text) = 0;
  295.     virtual const CellInterface* GetCell(Position pos) const = 0;
  296.     virtual CellInterface* GetCell(Position pos) = 0;
  297.     virtual void ClearCell(Position pos) = 0;
  298.     virtual Size GetPrintableSize() const = 0;
  299.     virtual void PrintValues(std::ostream& output) const = 0;
  300.     virtual void PrintTexts(std::ostream& output) const = 0;
  301. };
  302.  
  303. std::unique_ptr<SheetInterface> CreateSheet();
  304. -----------------------------------------------------------------------
  305. Formula.g4
  306. -----------------------------------------------------------------------
  307. grammar Formula;
  308.  
  309. main
  310.     : expr EOF
  311.     ;
  312.  
  313. expr
  314.     : '(' expr ')'  # Parens
  315.     | (ADD | SUB) expr  # UnaryOp
  316.     | expr (MUL | DIV) expr  # BinaryOp
  317.     | expr (ADD | SUB) expr  # BinaryOp
  318.     | CELL  # Cell
  319.     | NUMBER  # Literal
  320.     ;
  321.  
  322. fragment INT: [-+]? UINT ;
  323. fragment UINT: [0-9]+ ;
  324. fragment EXPONENT: [eE] INT;
  325. NUMBER
  326.     : UINT EXPONENT?
  327.     | UINT? '.' UINT EXPONENT?
  328.     ;
  329.  
  330. ADD: '+' ;
  331. SUB: '-' ;
  332. MUL: '*' ;
  333. DIV: '/' ;
  334. CELL: [A-Z]+[0-9]+ ;
  335. WS: [ \t\n\r]+ -> skip ;
  336. -----------------------------------------------------------------------
  337. FormulaAST.h
  338. -----------------------------------------------------------------------
  339. #pragma once
  340.  
  341. #include "FormulaLexer.h"
  342. #include "common.h"
  343.  
  344. #include <forward_list>
  345. #include <functional>
  346. #include <stdexcept>
  347.  
  348. namespace ASTImpl {
  349. class Expr;
  350. }
  351.  
  352. class ParsingError : public std::runtime_error {
  353.     using std::runtime_error::runtime_error;
  354. };
  355.  
  356. class FormulaAST {
  357. public:
  358.    
  359.     explicit FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr,
  360.                         std::forward_list<Position> cells);
  361.    
  362.     FormulaAST(FormulaAST&&) = default;
  363.     FormulaAST& operator=(FormulaAST&&) = default;
  364.     ~FormulaAST();
  365.  
  366.     double Execute(std::function<double(Position)>& args) const;
  367.     void PrintCells(std::ostream& out) const;
  368.     void Print(std::ostream& out) const;
  369.     void PrintFormula(std::ostream& out) const;
  370.  
  371.     std::forward_list<Position>& GetCells() {return cells_;}
  372.     const std::forward_list<Position>& GetCells() const {return cells_;}
  373.  
  374. private:
  375.     std::unique_ptr<ASTImpl::Expr> root_expr_;
  376.     std::forward_list<Position> cells_;
  377. };
  378.  
  379. FormulaAST ParseFormulaAST(std::istream& in);
  380. FormulaAST ParseFormulaAST(const std::string& in_str);
  381. -----------------------------------------------------------------------
  382. FormulaAST.cpp
  383. -----------------------------------------------------------------------
  384. #include "FormulaAST.h"
  385.  
  386. #include "FormulaBaseListener.h"
  387. #include "FormulaLexer.h"
  388. #include "FormulaParser.h"
  389.  
  390. #include <cassert>
  391. #include <cmath>
  392. #include <memory>
  393. #include <optional>
  394. #include <sstream>
  395.  
  396. namespace ASTImpl {
  397.  
  398. enum ExprPrecedence {
  399.     EP_ADD,
  400.     EP_SUB,
  401.     EP_MUL,
  402.     EP_DIV,
  403.     EP_UNARY,
  404.     EP_ATOM,
  405.     EP_END,
  406. };
  407.  
  408. enum PrecedenceRule {
  409.     PR_NONE = 0b00,                // never needed
  410.     PR_LEFT = 0b01,                // needed for a left child
  411.     PR_RIGHT = 0b10,               // needed for a right child
  412.     PR_BOTH = PR_LEFT | PR_RIGHT,  // needed for both children
  413. };
  414.  
  415. constexpr PrecedenceRule PRECEDENCE_RULES[EP_END][EP_END] = {
  416.     /* EP_ADD */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  417.     /* EP_SUB */ {PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  418.     /* EP_MUL */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  419.     /* EP_DIV */ {PR_BOTH, PR_BOTH, PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE},
  420.     /* EP_UNARY */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  421.     /* EP_ATOM */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  422. };
  423.  
  424. class Expr {
  425. public:
  426.    
  427.     virtual ~Expr() = default;
  428.     virtual void Print(std::ostream& out) const = 0;
  429.     virtual void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const = 0;
  430.     virtual double Evaluate(std::function<double(Position)>& args) const = 0;
  431.  
  432.     virtual ExprPrecedence GetPrecedence() const = 0;
  433.  
  434.     void PrintFormula(std::ostream& out, ExprPrecedence parent_precedence,
  435.                       bool right_child = false) const {
  436.         auto precedence = GetPrecedence();
  437.         auto mask = right_child ? PR_RIGHT : PR_LEFT;
  438.         bool parens_needed = PRECEDENCE_RULES[parent_precedence][precedence] & mask;
  439.        
  440.         if (parens_needed) {out << '(';}
  441.         DoPrintFormula(out, precedence);
  442.         if (parens_needed) {out << ')';}
  443.     }
  444. };
  445.  
  446. namespace {
  447. class BinaryOpExpr final : public Expr {
  448. public:
  449.     enum Type : char {
  450.         Add = '+',
  451.         Subtract = '-',
  452.         Multiply = '*',
  453.         Divide = '/',
  454.     };
  455.  
  456. public:
  457.    
  458.     explicit BinaryOpExpr(Type type, std::unique_ptr<Expr> lhs, std::unique_ptr<Expr> rhs) : type_(type)
  459.                                                                                            , lhs_(std::move(lhs))
  460.                                                                                            , rhs_(std::move(rhs)) {}
  461.  
  462.     void Print(std::ostream& out) const override {
  463.         out << '(' << static_cast<char>(type_) << ' ';
  464.         lhs_->Print(out);
  465.         out << ' ';
  466.         rhs_->Print(out);
  467.         out << ')';
  468.     }
  469.  
  470.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  471.         lhs_->PrintFormula(out, precedence);
  472.         out << static_cast<char>(type_);
  473.         rhs_->PrintFormula(out, precedence, true);
  474.     }
  475.  
  476.     ExprPrecedence GetPrecedence() const override {
  477.        
  478.         switch (type_) {
  479.                
  480.             case Add:
  481.                 return EP_ADD;
  482.                
  483.             case Subtract:
  484.                 return EP_SUB;
  485.                
  486.             case Multiply:
  487.                 return EP_MUL;
  488.                
  489.             case Divide:
  490.                 return EP_DIV;
  491.                
  492.             default:
  493.                 assert(false);
  494.                 return static_cast<ExprPrecedence>(INT_MAX);
  495.         }
  496.     }
  497.  
  498.     double Evaluate(std::function<double(Position)>& args) const override {
  499.        
  500.         switch (type_) {
  501.                
  502.             case Add:
  503.                 return lhs_->Evaluate(args) + rhs_->Evaluate(args);
  504.                
  505.             case Subtract:
  506.                 return lhs_->Evaluate(args) - rhs_->Evaluate(args);
  507.                
  508.             case Multiply:
  509.                 return lhs_->Evaluate(args) * rhs_->Evaluate(args);
  510.            
  511.             case Divide:
  512.                
  513.                 if (rhs_->Evaluate(args) != 0) {
  514.                     return lhs_->Evaluate(args) / rhs_->Evaluate(args);
  515.                    
  516.                 } else {
  517.                     throw FormulaError(FormulaError::Category::Div0);
  518.                 }  
  519.            
  520.             default:
  521.                 throw std::invalid_argument("unidentified operation type");
  522.         }
  523.     }
  524.  
  525. private:
  526.     Type type_;
  527.     std::unique_ptr<Expr> lhs_;
  528.     std::unique_ptr<Expr> rhs_;
  529. };
  530.  
  531. class UnaryOpExpr final : public Expr {
  532. public:
  533.     enum Type : char {
  534.         UnaryPlus = '+',
  535.         UnaryMinus = '-',
  536.     };
  537.  
  538. public:
  539.    
  540.     explicit UnaryOpExpr(Type type, std::unique_ptr<Expr> operand) : type_(type)
  541.                                                                    , operand_(std::move(operand)) {}
  542.  
  543.     void Print(std::ostream& out) const override {
  544.         out << '(' << static_cast<char>(type_) << ' ';
  545.         operand_->Print(out);
  546.         out << ')';
  547.     }
  548.  
  549.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  550.         out << static_cast<char>(type_);
  551.         operand_->PrintFormula(out, precedence);
  552.     }
  553.  
  554.     ExprPrecedence GetPrecedence() const override {return EP_UNARY;}
  555.  
  556.     double Evaluate(std::function<double(Position)>& args) const override {
  557.        
  558.         switch (type_) {
  559.  
  560.             case UnaryPlus:
  561.                 return operand_->Evaluate(args);
  562.  
  563.             case UnaryMinus:
  564.                 return -operand_->Evaluate(args);
  565.  
  566.             default:
  567.                 throw std::invalid_argument("unidentified operation type");
  568.         }
  569.     }
  570.  
  571. private:
  572.     Type type_;
  573.     std::unique_ptr<Expr> operand_;
  574. };
  575.  
  576. class CellExpr final : public Expr {
  577. public:
  578.    
  579.     explicit CellExpr(const Position* cell) : cell_(cell) {}
  580.  
  581.     void Print(std::ostream& out) const override {
  582.         if (!cell_->IsValid()) {
  583.             out << FormulaError::Category::Ref;
  584.         } else {
  585.             out << cell_->ToString();
  586.         }
  587.     }
  588.  
  589.     void DoPrintFormula(std::ostream& out, ExprPrecedence) const override {Print(out);}
  590.     ExprPrecedence GetPrecedence() const override {return EP_ATOM;}
  591.  
  592.     double Evaluate(std::function<double(Position)>& args) const override {return args(*cell_);}
  593.  
  594. private:
  595.     const Position* cell_;
  596. };
  597.  
  598. class NumberExpr final : public Expr {
  599. public:
  600.    
  601.     explicit NumberExpr(double value) : value_(value) {}
  602.  
  603.     void Print(std::ostream& out) const override {out << value_;}
  604.     void DoPrintFormula(std::ostream& out, ExprPrecedence) const override {out << value_;}
  605.     ExprPrecedence GetPrecedence() const override {return EP_ATOM;}
  606.     double Evaluate(std::function<double(Position)>& args) const override {return value_;}
  607.  
  608. private:
  609.     double value_;
  610. };
  611.  
  612. class ParseASTListener final : public FormulaBaseListener {
  613. public:
  614.     std::unique_ptr<Expr> MoveRoot() {
  615.         assert(args_.size() == 1);
  616.         auto root = std::move(args_.front());
  617.         args_.clear();
  618.  
  619.         return root;
  620.     }
  621.  
  622.     std::forward_list<Position> MoveCells() {return std::move(cells_);}
  623.  
  624. public:
  625.     void exitUnaryOp(FormulaParser::UnaryOpContext* ctx) override {
  626.         assert(args_.size() >= 1);
  627.  
  628.         auto operand = std::move(args_.back());
  629.  
  630.         UnaryOpExpr::Type type;
  631.         if (ctx->SUB()) {
  632.             type = UnaryOpExpr::UnaryMinus;
  633.         } else {
  634.             assert(ctx->ADD() != nullptr);
  635.             type = UnaryOpExpr::UnaryPlus;
  636.         }
  637.  
  638.         auto node = std::make_unique<UnaryOpExpr>(type, std::move(operand));
  639.         args_.back() = std::move(node);
  640.     }
  641.  
  642.     void exitLiteral(FormulaParser::LiteralContext* ctx) override {
  643.         double value = 0;
  644.         auto valueStr = ctx->NUMBER()->getSymbol()->getText();
  645.         std::istringstream in(valueStr);
  646.         in >> value;
  647.         if (!in) {
  648.             throw ParsingError("Invalid number: " + valueStr);
  649.         }
  650.  
  651.         auto node = std::make_unique<NumberExpr>(value);
  652.         args_.push_back(std::move(node));
  653.     }
  654.  
  655.     void exitCell(FormulaParser::CellContext* ctx) override {
  656.         auto value_str = ctx->CELL()->getSymbol()->getText();
  657.         auto value = Position::FromString(value_str);
  658.         if (!value.IsValid()) {
  659.             throw FormulaException("Invalid position: " + value_str);
  660.         }
  661.  
  662.         cells_.push_front(value);
  663.         auto node = std::make_unique<CellExpr>(&cells_.front());
  664.         args_.push_back(std::move(node));
  665.     }
  666.  
  667.     void exitBinaryOp(FormulaParser::BinaryOpContext* ctx) override {
  668.         assert(args_.size() >= 2);
  669.  
  670.         auto rhs = std::move(args_.back());
  671.         args_.pop_back();
  672.  
  673.         auto lhs = std::move(args_.back());
  674.  
  675.         BinaryOpExpr::Type type;
  676.         if (ctx->ADD()) {
  677.             type = BinaryOpExpr::Add;
  678.         } else if (ctx->SUB()) {
  679.             type = BinaryOpExpr::Subtract;
  680.         } else if (ctx->MUL()) {
  681.             type = BinaryOpExpr::Multiply;
  682.         } else {
  683.             assert(ctx->DIV() != nullptr);
  684.             type = BinaryOpExpr::Divide;
  685.         }
  686.  
  687.         auto node = std::make_unique<BinaryOpExpr>(type, std::move(lhs), std::move(rhs));
  688.         args_.back() = std::move(node);
  689.     }
  690.  
  691.     void visitErrorNode(antlr4::tree::ErrorNode* node) override {
  692.         throw ParsingError("Error when parsing: " + node->getSymbol()->getText());
  693.     }
  694.  
  695. private:
  696.     std::vector<std::unique_ptr<Expr>> args_;
  697.     std::forward_list<Position> cells_;
  698. };
  699.  
  700. class BailErrorListener : public antlr4::BaseErrorListener {
  701. public:
  702.     void syntaxError(antlr4::Recognizer*, antlr4::Token*, size_t, size_t, const std::string& msg, std::exception_ptr) override {
  703.         throw ParsingError("Error when lexing: " + msg);
  704.     }
  705. };
  706.  
  707. }//end namespace
  708. }//end namespace ASTImpl
  709.  
  710. FormulaAST ParseFormulaAST(std::istream& in) {
  711.     using namespace antlr4;
  712.  
  713.     ANTLRInputStream input(in);
  714.  
  715.     FormulaLexer lexer(&input);
  716.     ASTImpl::BailErrorListener error_listener;
  717.     lexer.removeErrorListeners();
  718.     lexer.addErrorListener(&error_listener);
  719.  
  720.     CommonTokenStream tokens(&lexer);
  721.  
  722.     FormulaParser parser(&tokens);
  723.     auto error_handler = std::make_shared<BailErrorStrategy>();
  724.     parser.setErrorHandler(error_handler);
  725.     parser.removeErrorListeners();
  726.  
  727.     tree::ParseTree* tree = parser.main();
  728.     ASTImpl::ParseASTListener listener;
  729.     tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
  730.  
  731.     return FormulaAST(listener.MoveRoot(), listener.MoveCells());
  732. }
  733.  
  734. FormulaAST ParseFormulaAST(const std::string& in_str) {
  735.     std::istringstream in(in_str);
  736.     return ParseFormulaAST(in);
  737. }
  738.  
  739. void FormulaAST::PrintCells(std::ostream& out) const {
  740.     for (auto cell : cells_) {
  741.         out << cell.ToString() << ' ';
  742.     }
  743. }
  744.  
  745. void FormulaAST::Print(std::ostream& out) const {root_expr_->Print(out);}
  746. void FormulaAST::PrintFormula(std::ostream& out) const {root_expr_->PrintFormula(out, ASTImpl::EP_ATOM);}
  747. double FormulaAST::Execute(std::function<double(Position)>& args) const {return root_expr_->Evaluate(args);}
  748.  
  749. FormulaAST::FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr, std::forward_list<Position> cells) : root_expr_(std::move(root_expr))
  750.                                                                                                     , cells_(std::move(cells)) {cells_.sort();}
  751.  
  752. FormulaAST::~FormulaAST() = default;
  753. -----------------------------------------------------------------------
  754. main.cpp
  755. -----------------------------------------------------------------------
  756. #include <limits>
  757. #include "common.h"
  758. #include "formula.h"
  759. #include "test_runner_p.h"
  760.  
  761. inline std::ostream& operator<<(std::ostream& output, Position pos) {
  762.     return output << "(" << pos.row << ", " << pos.col << ")";
  763. }
  764.  
  765. inline Position operator"" _pos(const char* str, std::size_t) {
  766.     return Position::FromString(str);
  767. }
  768.  
  769. inline std::ostream& operator<<(std::ostream& output, Size size) {
  770.     return output << "(" << size.rows << ", " << size.cols << ")";
  771. }
  772.  
  773. inline std::ostream& operator<<(std::ostream& output, const CellInterface::Value& value) {
  774.     std::visit(
  775.         [&](const auto& x) {
  776.             output << x;
  777.         },
  778.         value);
  779.     return output;
  780. }
  781.  
  782. namespace {
  783.  
  784. void TestPositionAndStringConversion() {
  785.     auto testSingle = [](Position pos, std::string_view str) {
  786.         ASSERT_EQUAL(pos.ToString(), str);
  787.         ASSERT_EQUAL(Position::FromString(str), pos);
  788.     };
  789.  
  790.     for (int i = 0; i < 25; ++i) {
  791.         testSingle(Position{i, i}, char('A' + i) + std::to_string(i + 1));
  792.     }
  793.  
  794.     testSingle(Position{0, 0}, "A1");
  795.     testSingle(Position{0, 1}, "B1");
  796.     testSingle(Position{0, 25}, "Z1");
  797.     testSingle(Position{0, 26}, "AA1");
  798.     testSingle(Position{0, 27}, "AB1");
  799.     testSingle(Position{0, 51}, "AZ1");
  800.     testSingle(Position{0, 52}, "BA1");
  801.     testSingle(Position{0, 53}, "BB1");
  802.     testSingle(Position{0, 77}, "BZ1");
  803.     testSingle(Position{0, 78}, "CA1");
  804.     testSingle(Position{0, 701}, "ZZ1");
  805.     testSingle(Position{0, 702}, "AAA1");
  806.     testSingle(Position{136, 2}, "C137");
  807.     testSingle(Position{Position::MAX_ROWS - 1, Position::MAX_COLS - 1}, "XFD16384");
  808. }
  809.  
  810. void TestPositionToStringInvalid() {
  811.     ASSERT_EQUAL((Position{-1, -1}).ToString(), "");
  812.     ASSERT_EQUAL((Position{-10, 0}).ToString(), "");
  813.     ASSERT_EQUAL((Position{1, -3}).ToString(), "");
  814. }
  815.  
  816. void TestStringToPositionInvalid() {
  817.     ASSERT(!Position::FromString("").IsValid());
  818.     ASSERT(!Position::FromString("A").IsValid());
  819.     ASSERT(!Position::FromString("1").IsValid());
  820.     ASSERT(!Position::FromString("e2").IsValid());
  821.     ASSERT(!Position::FromString("A0").IsValid());
  822.     ASSERT(!Position::FromString("A-1").IsValid());
  823.     ASSERT(!Position::FromString("A+1").IsValid());
  824.     ASSERT(!Position::FromString("R2D2").IsValid());
  825.     ASSERT(!Position::FromString("C3PO").IsValid());
  826.     ASSERT(!Position::FromString("XFD16385").IsValid());
  827.     ASSERT(!Position::FromString("XFE16384").IsValid());
  828.     ASSERT(!Position::FromString("A1234567890123456789").IsValid());
  829.     ASSERT(!Position::FromString("ABCDEFGHIJKLMNOPQRS8").IsValid());
  830. }
  831.  
  832. void TestEmpty() {
  833.     auto sheet = CreateSheet();
  834.     ASSERT_EQUAL(sheet->GetPrintableSize(), (Size{0, 0}));
  835. }
  836.  
  837. void TestInvalidPosition() {
  838.     auto sheet = CreateSheet();
  839.     try {
  840.         sheet->SetCell(Position{-1, 0}, "");
  841.     } catch (const InvalidPositionException&) {
  842.     }
  843.     try {
  844.         sheet->GetCell(Position{0, -2});
  845.     } catch (const InvalidPositionException&) {
  846.     }
  847.     try {
  848.         sheet->ClearCell(Position{Position::MAX_ROWS, 0});
  849.     } catch (const InvalidPositionException&) {
  850.     }
  851. }
  852.  
  853. void TestSetCellPlainText() {
  854.     auto sheet = CreateSheet();
  855.  
  856.     auto checkCell = [&](Position pos, std::string text) {
  857.         sheet->SetCell(pos, text);
  858.         CellInterface* cell = sheet->GetCell(pos);
  859.         ASSERT(cell != nullptr);
  860.         ASSERT_EQUAL(cell->GetText(), text);
  861.         ASSERT_EQUAL(std::get<std::string>(cell->GetValue()), text);
  862.     };
  863.  
  864.     checkCell("A1"_pos, "Hello");
  865.     checkCell("A1"_pos, "World");
  866.     checkCell("B2"_pos, "Purr");
  867.     checkCell("A3"_pos, "Meow");
  868.  
  869.     const SheetInterface& constSheet = *sheet;
  870.     ASSERT_EQUAL(constSheet.GetCell("B2"_pos)->GetText(), "Purr");
  871.  
  872.     sheet->SetCell("A3"_pos, "'=escaped");
  873.     CellInterface* cell = sheet->GetCell("A3"_pos);
  874.     ASSERT_EQUAL(cell->GetText(), "'=escaped");
  875.     ASSERT_EQUAL(std::get<std::string>(cell->GetValue()), "=escaped");
  876. }
  877.  
  878. void TestClearCell() {
  879.     auto sheet = CreateSheet();
  880.  
  881.     sheet->SetCell("C2"_pos, "Me gusta");
  882.     sheet->ClearCell("C2"_pos);
  883.     ASSERT(sheet->GetCell("C2"_pos) == nullptr);
  884.  
  885.     sheet->ClearCell("A1"_pos);
  886.     sheet->ClearCell("J10"_pos);
  887. }
  888.  
  889. void TestFormulaArithmetic() {
  890.     auto sheet = CreateSheet();
  891.     auto evaluate = [&](std::string expr) {
  892.         return std::get<double>(ParseFormula(std::move(expr))->Evaluate(*sheet));
  893.     };
  894.  
  895.     ASSERT_EQUAL(evaluate("1"), 1);
  896.     ASSERT_EQUAL(evaluate("42"), 42);
  897.     ASSERT_EQUAL(evaluate("2 + 2"), 4);
  898.     ASSERT_EQUAL(evaluate("2 + 2*2"), 6);
  899.     ASSERT_EQUAL(evaluate("4/2 + 6/3"), 4);
  900.     ASSERT_EQUAL(evaluate("(2+3)*4 + (3-4)*5"), 15);
  901.     ASSERT_EQUAL(evaluate("(12+13) * (14+(13-24/(1+1))*55-46)"), 575);
  902. }
  903.  
  904. void TestFormulaReferences() {
  905.     auto sheet = CreateSheet();
  906.     auto evaluate = [&](std::string expr) {
  907.         return std::get<double>(ParseFormula(std::move(expr))->Evaluate(*sheet));
  908.     };
  909.  
  910.     sheet->SetCell("A1"_pos, "1");
  911.     ASSERT_EQUAL(evaluate("A1"), 1);
  912.     sheet->SetCell("A2"_pos, "2");
  913.     ASSERT_EQUAL(evaluate("A1+A2"), 3);
  914.  
  915.     sheet->SetCell("B3"_pos, "");
  916.     ASSERT_EQUAL(evaluate("A1+B3"), 1);
  917.     ASSERT_EQUAL(evaluate("A1+B1"), 1);  
  918.     ASSERT_EQUAL(evaluate("A1+E4"), 1);  
  919. }
  920.  
  921. void TestFormulaExpressionFormatting() {
  922.     auto reformat = [](std::string expr) {
  923.         return ParseFormula(std::move(expr))->GetExpression();
  924.     };
  925.  
  926.     ASSERT_EQUAL(reformat("  1  "), "1");
  927.     ASSERT_EQUAL(reformat("  -1  "), "-1");
  928.     ASSERT_EQUAL(reformat("2 + 2"), "2+2");
  929.     ASSERT_EQUAL(reformat("(2*3)+4"), "2*3+4");
  930.     ASSERT_EQUAL(reformat("(2*3)-4"), "2*3-4");
  931.     ASSERT_EQUAL(reformat("( ( (  1) ) )"), "1");
  932. }
  933.  
  934. void TestFormulaReferencedCells() {
  935.     ASSERT(ParseFormula("1")->GetReferencedCells().empty());
  936.  
  937.     auto a1 = ParseFormula("A1");
  938.     ASSERT_EQUAL(a1->GetReferencedCells(), (std::vector{"A1"_pos}));
  939.  
  940.     auto b2c3 = ParseFormula("B2+C3");
  941.     ASSERT_EQUAL(b2c3->GetReferencedCells(), (std::vector{"B2"_pos, "C3"_pos}));
  942.  
  943.     auto tricky = ParseFormula("A1 + A2 + A1 + A3 + A1 + A2 + A1");
  944.     ASSERT_EQUAL(tricky->GetExpression(), "A1+A2+A1+A3+A1+A2+A1");
  945.     ASSERT_EQUAL(tricky->GetReferencedCells(), (std::vector{"A1"_pos, "A2"_pos, "A3"_pos}));
  946. }
  947.  
  948. void TestErrorValue() {
  949.     auto sheet = CreateSheet();
  950.     sheet->SetCell("E2"_pos, "A1");
  951.     sheet->SetCell("E4"_pos, "=E2");
  952.     ASSERT_EQUAL(sheet->GetCell("E4"_pos)->GetValue(),
  953.                  CellInterface::Value(FormulaError::Category::Value));
  954.  
  955.     sheet->SetCell("E2"_pos, "3D");
  956.     ASSERT_EQUAL(sheet->GetCell("E4"_pos)->GetValue(),
  957.                  CellInterface::Value(FormulaError::Category::Value));
  958. }
  959.  
  960. void TestErrorDiv0() {
  961.     auto sheet = CreateSheet();
  962.  
  963.     constexpr double max = std::numeric_limits<double>::max();
  964.  
  965.     sheet->SetCell("A1"_pos, "=1/0");
  966.     ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  967.                  CellInterface::Value(FormulaError::Category::Div0));
  968.  
  969.     sheet->SetCell("A1"_pos, "=1e+200/1e-200");
  970.     ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  971.                  CellInterface::Value(FormulaError::Category::Div0));
  972.  
  973.     sheet->SetCell("A1"_pos, "=0/0");
  974.     ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  975.                  CellInterface::Value(FormulaError::Category::Div0));
  976.  
  977.     {
  978.         std::ostringstream formula;
  979.         formula << '=' << max << '+' << max;
  980.         sheet->SetCell("A1"_pos, formula.str());
  981.         ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  982.                      CellInterface::Value(FormulaError::Category::Div0));
  983.     }
  984.  
  985.     {
  986.         std::ostringstream formula;
  987.         formula << '=' << -max << '-' << max;
  988.         sheet->SetCell("A1"_pos, formula.str());
  989.         ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  990.                      CellInterface::Value(FormulaError::Category::Div0));
  991.     }
  992.  
  993.     {
  994.         std::ostringstream formula;
  995.         formula << '=' << max << '*' << max;
  996.         sheet->SetCell("A1"_pos, formula.str());
  997.         ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(),
  998.                      CellInterface::Value(FormulaError::Category::Div0));
  999.     }
  1000. }
  1001.  
  1002. void TestEmptyCellTreatedAsZero() {
  1003.     auto sheet = CreateSheet();
  1004.     sheet->SetCell("A1"_pos, "=B2");
  1005.     ASSERT_EQUAL(sheet->GetCell("A1"_pos)->GetValue(), CellInterface::Value(0.0));
  1006. }
  1007.  
  1008. void TestFormulaInvalidPosition() {
  1009.     auto sheet = CreateSheet();
  1010.     auto try_formula = [&](const std::string& formula) {
  1011.         try {
  1012.             sheet->SetCell("A1"_pos, formula);
  1013.             ASSERT(false);
  1014.         } catch (const FormulaException&) {
  1015.             // we expect this one
  1016.         }
  1017.     };
  1018.  
  1019.     try_formula("=X0");
  1020.     try_formula("=ABCD1");
  1021.     try_formula("=A123456");
  1022.     try_formula("=ABCDEFGHIJKLMNOPQRS1234567890");
  1023.     try_formula("=XFD16385");
  1024.     try_formula("=XFE16384");
  1025.     try_formula("=R2D2");
  1026. }
  1027.  
  1028. void TestPrint() {
  1029.     auto sheet = CreateSheet();
  1030.     sheet->SetCell("A2"_pos, "meow");
  1031.     sheet->SetCell("B2"_pos, "=35");
  1032.  
  1033.     ASSERT_EQUAL(sheet->GetPrintableSize(), (Size{2, 2}));
  1034.  
  1035.     std::ostringstream texts;
  1036.     sheet->PrintTexts(texts);
  1037.     ASSERT_EQUAL(texts.str(), "\t\nmeow\t=35\n");
  1038.  
  1039.     std::ostringstream values;
  1040.     sheet->PrintValues(values);
  1041.     ASSERT_EQUAL(values.str(), "\t\nmeow\t35\n");
  1042. }
  1043.  
  1044. void TestCellReferences() {
  1045.     auto sheet = CreateSheet();
  1046.     sheet->SetCell("A1"_pos, "1");
  1047.     sheet->SetCell("A2"_pos, "=A1");
  1048.     sheet->SetCell("B2"_pos, "=A1");
  1049.  
  1050.     ASSERT(sheet->GetCell("A1"_pos)->GetReferencedCells().empty());
  1051.     ASSERT_EQUAL(sheet->GetCell("A2"_pos)->GetReferencedCells(), std::vector{"A1"_pos});
  1052.     ASSERT_EQUAL(sheet->GetCell("B2"_pos)->GetReferencedCells(), std::vector{"A1"_pos});
  1053.  
  1054.     sheet->SetCell("B2"_pos, "=B1");
  1055.     ASSERT(sheet->GetCell("B1"_pos)->GetReferencedCells().empty());
  1056.     ASSERT_EQUAL(sheet->GetCell("B2"_pos)->GetReferencedCells(), std::vector{"B1"_pos});
  1057.  
  1058.     sheet->SetCell("A2"_pos, "");
  1059.     ASSERT(sheet->GetCell("A1"_pos)->GetReferencedCells().empty());
  1060.     ASSERT(sheet->GetCell("A2"_pos)->GetReferencedCells().empty());
  1061.  
  1062.     sheet->SetCell("B1"_pos, "=C3");
  1063.     ASSERT_EQUAL(sheet->GetCell("B1"_pos)->GetReferencedCells(), std::vector{"C3"_pos});
  1064. }
  1065.  
  1066. void TestFormulaIncorrect() {
  1067.     auto isIncorrect = [](std::string expression) {
  1068.         try {
  1069.             ParseFormula(std::move(expression));
  1070.         } catch (const FormulaException&) {
  1071.             return true;
  1072.         }
  1073.         return false;
  1074.     };
  1075.  
  1076.     ASSERT(isIncorrect("A2B"));
  1077.     ASSERT(isIncorrect("3X"));
  1078.     ASSERT(isIncorrect("A0++"));
  1079.     ASSERT(isIncorrect("((1)"));
  1080.     ASSERT(isIncorrect("2+4-"));
  1081. }
  1082.  
  1083. void TestCellCircularReferences() {
  1084.     auto sheet = CreateSheet();
  1085.     sheet->SetCell("E2"_pos, "=E4");
  1086.     sheet->SetCell("E4"_pos, "=X9");
  1087.     sheet->SetCell("X9"_pos, "=M6");
  1088.     sheet->SetCell("M6"_pos, "Ready");
  1089.  
  1090.     bool caught = false;
  1091.     try {
  1092.         sheet->SetCell("M6"_pos, "=E2");
  1093.     } catch (const CircularDependencyException&) {
  1094.         caught = true;
  1095.     }
  1096.  
  1097.     ASSERT(caught);
  1098.     ASSERT_EQUAL(sheet->GetCell("M6"_pos)->GetText(), "Ready");
  1099. }
  1100.    
  1101. }//end namespace
  1102.  
  1103. int main() {
  1104.     TestRunner tr;
  1105.     RUN_TEST(tr, TestPositionAndStringConversion);
  1106.     RUN_TEST(tr, TestPositionToStringInvalid);
  1107.     RUN_TEST(tr, TestStringToPositionInvalid);
  1108.     RUN_TEST(tr, TestEmpty);
  1109.     RUN_TEST(tr, TestInvalidPosition);
  1110.     RUN_TEST(tr, TestSetCellPlainText);
  1111.     RUN_TEST(tr, TestClearCell);
  1112.     RUN_TEST(tr, TestFormulaArithmetic);
  1113.     RUN_TEST(tr, TestFormulaReferences);
  1114.     RUN_TEST(tr, TestFormulaExpressionFormatting);
  1115.     RUN_TEST(tr, TestFormulaReferencedCells);
  1116.     RUN_TEST(tr, TestErrorValue);
  1117.     RUN_TEST(tr, TestErrorDiv0);
  1118.     RUN_TEST(tr, TestEmptyCellTreatedAsZero);
  1119.     RUN_TEST(tr, TestFormulaInvalidPosition);
  1120.     RUN_TEST(tr, TestPrint);
  1121.     RUN_TEST(tr, TestCellReferences);
  1122.     RUN_TEST(tr, TestFormulaIncorrect);
  1123.     RUN_TEST(tr, TestCellCircularReferences);
  1124.     return 0;
  1125. }
  1126. -----------------------------------------------------------------------
  1127. test_runner_p.h
  1128. -----------------------------------------------------------------------
  1129. #pragma once
  1130.  
  1131. #include <iostream>
  1132. #include <map>
  1133. #include <set>
  1134. #include <sstream>
  1135. #include <stdexcept>
  1136. #include <string>
  1137. #include <unordered_map>
  1138. #include <vector>
  1139.  
  1140. namespace TestRunnerPrivate {
  1141.   template <typename K, typename V, template <typename, typename> class Map>
  1142.   std::ostream& PrintMap(std::ostream& os, const Map<K, V>& m) {
  1143.     os << "{";
  1144.     bool first = true;
  1145.     for (const auto& kv : m) {
  1146.       if (!first) {
  1147.         os << ", ";
  1148.       }
  1149.       first = false;
  1150.       os << kv.first << ": " << kv.second;
  1151.     }
  1152.     return os << "}";
  1153.   }
  1154. }
  1155.  
  1156. template <class T>
  1157. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  1158.   os << "{";
  1159.   bool first = true;
  1160.   for (const auto& x : s) {
  1161.     if (!first) {
  1162.       os << ", ";
  1163.     }
  1164.     first = false;
  1165.     os << x;
  1166.   }
  1167.   return os << "}";
  1168. }
  1169.  
  1170. template <class T>
  1171. std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
  1172.   os << "{";
  1173.   bool first = true;
  1174.   for (const auto& x : s) {
  1175.     if (!first) {
  1176.       os << ", ";
  1177.     }
  1178.     first = false;
  1179.     os << x;
  1180.   }
  1181.   return os << "}";
  1182. }
  1183.  
  1184. template <class K, class V>
  1185. std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
  1186.   return TestRunnerPrivate::PrintMap(os, m);
  1187. }
  1188.  
  1189. template <class K, class V>
  1190. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {
  1191.   return TestRunnerPrivate::PrintMap(os, m);
  1192. }
  1193.  
  1194. template <class T, class U>
  1195. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  1196.   if (!(t == u)) {
  1197.     std::ostringstream os;
  1198.     os << "Assertion failed: " << t << " != " << u;
  1199.     if (!hint.empty()) {
  1200.       os << " hint: " << hint;
  1201.     }
  1202.     throw std::runtime_error(os.str());
  1203.   }
  1204. }
  1205.  
  1206. inline void Assert(bool b, const std::string& hint) {
  1207.   AssertEqual(b, true, hint);
  1208. }
  1209.  
  1210. class TestRunner {
  1211. public:
  1212.   template <class TestFunc>
  1213.   void RunTest(TestFunc func, const std::string& test_name) {
  1214.     try {
  1215.       func();
  1216.       std::cerr << test_name << " OK" << std::endl;
  1217.     } catch (std::exception& e) {
  1218.       ++fail_count;
  1219.       std::cerr << test_name << " fail: " << e.what() << std::endl;
  1220.     } catch (...) {
  1221.       ++fail_count;
  1222.       std::cerr << "Unknown exception caught" << std::endl;
  1223.     }
  1224.   }
  1225.  
  1226.   ~TestRunner() {
  1227.     std::cerr.flush();
  1228.     if (fail_count > 0) {
  1229.       std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  1230.       exit(1);
  1231.     }
  1232.   }
  1233.  
  1234. private:
  1235.   int fail_count = 0;
  1236. };
  1237.  
  1238. #ifndef FILE_NAME
  1239. #define FILE_NAME __FILE__
  1240. #endif
  1241.  
  1242. #define ASSERT_EQUAL(x, y)                                               \
  1243.   {                                                                      \
  1244.     std::ostringstream __assert_equal_private_os;                        \
  1245.     __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME \
  1246.                               << ":" << __LINE__;                        \
  1247.     AssertEqual(x, y, __assert_equal_private_os.str());                  \
  1248.   }
  1249.  
  1250. #define ASSERT(x)                                                  \
  1251.   {                                                                \
  1252.     std::ostringstream __assert_private_os;                        \
  1253.     __assert_private_os << #x << " is false, " << FILE_NAME << ":" \
  1254.                         << __LINE__;                               \
  1255.     Assert(x, __assert_private_os.str());                          \
  1256.   }
  1257.  
  1258. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  1259. -----------------------------------------------------------------------
  1260. formula.h
  1261. -----------------------------------------------------------------------
  1262. #pragma once
  1263.  
  1264. #include "common.h"
  1265.  
  1266. #include <memory>
  1267. #include <vector>
  1268.  
  1269. class FormulaInterface {
  1270. public:
  1271.     using Value = std::variant<double, FormulaError>;
  1272.  
  1273.     virtual ~FormulaInterface() = default;
  1274.     virtual Value Evaluate(const SheetInterface& sheet) const = 0;
  1275.     virtual std::string GetExpression() const = 0;
  1276.     virtual std::vector<Position> GetReferencedCells() const = 0;
  1277. };
  1278.  
  1279. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression);
  1280. -----------------------------------------------------------------------
  1281. formula.cpp
  1282. -----------------------------------------------------------------------
  1283. #include "formula.h"
  1284.  
  1285. #include "FormulaAST.h"
  1286.  
  1287. #include <algorithm>
  1288. #include <cassert>
  1289. #include <cctype>
  1290. #include <sstream>
  1291.  
  1292. using namespace std::literals;
  1293.  
  1294. std::ostream& operator<<(std::ostream& output, FormulaError fe) {
  1295.     return output << "#DIV/0!";
  1296. }
  1297.  
  1298. namespace {
  1299. class Formula : public FormulaInterface {
  1300. public:
  1301.    
  1302.     explicit Formula(std::string expression) try : ast_(ParseFormulaAST(expression)) {}
  1303.     catch (...) {
  1304.         throw FormulaException("formula is syntactically incorrect");
  1305.     }
  1306.    
  1307.     Value Evaluate(const SheetInterface& sheet) const override {
  1308.  
  1309.         try {
  1310.            
  1311.             std::function<double(Position)> args = [&sheet](const Position pos)->double {
  1312.            
  1313.                 if (pos.IsValid()) {
  1314.                
  1315.                     const auto* cell = sheet.GetCell(pos);
  1316.                     if (cell) {
  1317.                        
  1318.                         if (std::holds_alternative<double>(cell->GetValue())) {
  1319.                             return std::get<double>(cell->GetValue());
  1320.                            
  1321.                         } else if (std::holds_alternative<std::string>(cell->GetValue())) {
  1322.                            
  1323.                             auto str_value = std::get<std::string>(cell->GetValue());
  1324.                             if (str_value != "") {
  1325.                                 std::istringstream input(str_value);
  1326.                                 double num = 0.0;
  1327.  
  1328.                                 if (input.eof() && input >> num) {
  1329.                                     return num;
  1330.                                 } else {
  1331.                                     throw FormulaError(FormulaError::Category::Value);
  1332.                                 }
  1333.  
  1334.                             } else {
  1335.                                 return 0.0;
  1336.                             }
  1337.                            
  1338.                         } else {
  1339.                             throw FormulaError(std::get<FormulaError>(cell->GetValue()));
  1340.                         }
  1341.  
  1342.                     } else {
  1343.                         return 0.0;
  1344.                     }
  1345.                    
  1346.                 } else {
  1347.                     throw FormulaError(FormulaError::Category::Ref);
  1348.                 }
  1349.             };
  1350.            
  1351.             return ast_.Execute(args);
  1352.            
  1353.         } catch (const FormulaError& evaluate_error) {
  1354.             return evaluate_error;
  1355.         }
  1356.     }
  1357.    
  1358.     std::string GetExpression() const override {
  1359.         std::ostringstream out;
  1360.         ast_.PrintFormula(out);
  1361.        
  1362.         return out.str();
  1363.     }
  1364.    
  1365.     std::vector<Position> GetReferencedCells() const override {
  1366.         std::vector<Position> cells;
  1367.         for (const auto& cell : ast_.GetCells()) {
  1368.            
  1369.             if (cell.IsValid()) {
  1370.                 cells.push_back(cell);
  1371.             } else {
  1372.                 continue;
  1373.             }
  1374.         }
  1375.         return cells;
  1376.     }
  1377.  
  1378. private:
  1379.     FormulaAST ast_;
  1380. };
  1381.    
  1382. }//end namespace
  1383.  
  1384. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression) {
  1385.     return std::make_unique<Formula>(std::move(expression));
  1386. }
  1387. -----------------------------------------------------------------------
  1388. cell.cpp
  1389. -----------------------------------------------------------------------
  1390. #include "cell.h"
  1391. #include "sheet.h"
  1392.  
  1393. #include <cassert>
  1394. #include <iostream>
  1395. #include <string>
  1396. #include <optional>
  1397.  
  1398. Cell::Cell(Sheet& sheet) : impl_(std::make_unique<EmptyImpl>()),
  1399.                            sheet_(sheet) {}
  1400. Cell::~Cell() = default;
  1401.  
  1402. void Cell::Set(std::string text) {
  1403.    
  1404.     std::unique_ptr<Impl> temp_impl;
  1405.    
  1406.     if (text.empty()) {
  1407.         temp_impl = std::make_unique<EmptyImpl>();
  1408.        
  1409.     } else if (text.size() >= 2 && text.at(0) == FORMULA_SIGN) {
  1410.         temp_impl = std::make_unique<FormulaImpl>(std::move(text), sheet_);
  1411.        
  1412.     } else {
  1413.         temp_impl = std::make_unique<TextImpl>(std::move(text));
  1414.     }
  1415.    
  1416.     //начали искать циклические зависимости
  1417.     const Impl& temp_impl_ = *temp_impl;
  1418.     const auto temp_ref_cells = temp_impl_.GetReferencedCells();
  1419.    
  1420.     if (!temp_ref_cells.empty()) {
  1421.        
  1422.         std::set<const Cell*> ref_collection;
  1423.         std::set<const Cell*> enter_collection;
  1424.         std::vector<const Cell*> to_enter_collection;
  1425.        
  1426.         for (auto position : temp_ref_cells) {
  1427.             ref_collection.insert(sheet_.Get_Cell(position));
  1428.         }
  1429.  
  1430.         to_enter_collection.push_back(this);
  1431.        
  1432.         while (!to_enter_collection.empty()) {
  1433.            
  1434.             const Cell* ongoing = to_enter_collection.back();
  1435.            
  1436.             to_enter_collection.pop_back();
  1437.             enter_collection.insert(ongoing);
  1438.            
  1439.             if (ref_collection.find(ongoing) == ref_collection.end()) {
  1440.                
  1441.                 for (const Cell* dependent : ongoing->dependent_cells_) {
  1442.  
  1443.                     if (enter_collection.find(dependent) == enter_collection.end()) {
  1444.                         to_enter_collection.push_back(dependent);
  1445.                     }
  1446.                 }
  1447.                
  1448.             } else {
  1449.                 throw CircularDependencyException("circular dependency detected");
  1450.             }
  1451.         }
  1452.        
  1453.         impl_ = std::move(temp_impl);
  1454.        
  1455.     } else {
  1456.         impl_ = std::move(temp_impl);
  1457.     }
  1458.     //закончили искать циклические зависимости
  1459.    
  1460.     //обновляем зависимости
  1461.     for (Cell* refrenced : referenced_cells_) {
  1462.         refrenced->dependent_cells_.erase(this);
  1463.     }
  1464.    
  1465.     referenced_cells_.clear();
  1466.    
  1467.     for (const auto& position : impl_->GetReferencedCells()) {
  1468.        
  1469.         Cell* refrenced = sheet_.Get_Cell(position);
  1470.        
  1471.         if (!refrenced) {
  1472.             sheet_.SetCell(position, "");
  1473.             refrenced = sheet_.Get_Cell(position);
  1474.         }
  1475.        
  1476.         referenced_cells_.insert(refrenced);
  1477.         refrenced->dependent_cells_.insert(this);
  1478.     }
  1479.     //обновили зависимости
  1480.    
  1481.     //инвалидация кеша
  1482.     InvalidateAllCache(true);
  1483. }
  1484.  
  1485. void Cell::Clear() {
  1486.     impl_ = std::make_unique<EmptyImpl>();
  1487. }
  1488.  
  1489. Cell::Value Cell::GetValue() const {return impl_->GetValue();}
  1490. std::string Cell::GetText() const {return impl_->GetText();}
  1491. std::vector<Position> Cell::GetReferencedCells() const {return impl_->GetReferencedCells();}
  1492. bool Cell::IsReferenced() const {return !dependent_cells_.empty();}
  1493.  
  1494. void Cell::InvalidateAllCache(bool flag = false) {
  1495.     if (impl_->HasCache() || flag) {
  1496.         impl_->InvalidateCache();
  1497.        
  1498.         for (Cell* dependent : dependent_cells_) {
  1499.             dependent->InvalidateAllCache();
  1500.         }
  1501.     }
  1502. }
  1503.  
  1504. std::vector<Position> Cell::Impl::GetReferencedCells() const {return {};}
  1505. bool Cell::Impl::HasCache() {return true;}
  1506. void Cell::Impl::InvalidateCache() {}
  1507.  
  1508. Cell::Value Cell::EmptyImpl::GetValue() const {return "";}
  1509. std::string Cell::EmptyImpl::GetText() const {return "";}
  1510.  
  1511. Cell::TextImpl::TextImpl(std::string text) : text_(std::move(text)) {}
  1512.  
  1513. Cell::Value Cell::TextImpl::GetValue() const {
  1514.    
  1515.     if (text_.empty()) {
  1516.         throw FormulaException("it is empty impl, not text");
  1517.        
  1518.     } else if (text_.at(0) == ESCAPE_SIGN) {
  1519.         return text_.substr(1);
  1520.        
  1521.     } else {
  1522.         return text_;    
  1523.     }      
  1524. }
  1525.  
  1526. std::string Cell::TextImpl::GetText() const {return text_;}
  1527.  
  1528. Cell::FormulaImpl::FormulaImpl(std::string text, SheetInterface& sheet) : formula_ptr_(ParseFormula(text.substr(1)))
  1529.                                                                         , sheet_(sheet) {}
  1530.  
  1531. Cell::Value Cell::FormulaImpl::GetValue() const {            
  1532.    
  1533.     if (!cache_) {cache_ = formula_ptr_->Evaluate(sheet_);}    
  1534.     return std::visit([](auto& helper){return Value(helper);}, *cache_);        
  1535. }
  1536.  
  1537. std::string Cell::FormulaImpl::GetText() const {return FORMULA_SIGN + formula_ptr_->GetExpression();}
  1538. std::vector<Position> Cell::FormulaImpl::GetReferencedCells() const {return formula_ptr_->GetReferencedCells();}
  1539. bool Cell::FormulaImpl::HasCache() {return cache_.has_value();}
  1540. void Cell::FormulaImpl::InvalidateCache() {cache_.reset();}
  1541. -----------------------------------------------------------------------
  1542. cell.h
  1543. -----------------------------------------------------------------------
  1544. #pragma once
  1545.  
  1546. #include "common.h"
  1547. #include "formula.h"
  1548.  
  1549. #include <functional>
  1550. #include <unordered_set>
  1551. #include <stack>
  1552. #include <set>
  1553.  
  1554. class Sheet;
  1555.  
  1556. class Cell : public CellInterface {
  1557. public:
  1558.     Cell(Sheet& sheet);
  1559.     ~Cell();
  1560.  
  1561.     void Set(std::string text);
  1562.     void Clear();
  1563.  
  1564.     Value GetValue() const override;
  1565.     std::string GetText() const override;
  1566.     std::vector<Position> GetReferencedCells() const override;
  1567.    
  1568.     bool IsReferenced() const;
  1569.     void InvalidateAllCache(bool flag);
  1570.    
  1571. private:
  1572.    
  1573.     class Impl {
  1574.     public:
  1575.         virtual Value GetValue() const = 0;
  1576.         virtual std::string GetText() const = 0;
  1577.         virtual std::vector<Position> GetReferencedCells() const;
  1578.  
  1579.         virtual bool HasCache();
  1580.         virtual void InvalidateCache();
  1581.        
  1582.         virtual ~Impl() = default;
  1583.     };
  1584.    
  1585.     class EmptyImpl : public Impl {
  1586.     public:    
  1587.        
  1588.         Value GetValue() const override;
  1589.         std::string GetText() const override;      
  1590.     };
  1591.    
  1592.     class TextImpl : public Impl {
  1593.     public:
  1594.        
  1595.         explicit TextImpl(std::string text);
  1596.         Value GetValue() const override;      
  1597.         std::string GetText() const override;
  1598.        
  1599.     private:
  1600.         std::string text_;        
  1601.     };
  1602.    
  1603.     class FormulaImpl : public Impl {
  1604.     public:
  1605.        
  1606.         explicit FormulaImpl(std::string text, SheetInterface& sheet);
  1607.        
  1608.         Value GetValue() const override;
  1609.         std::string GetText() const override;
  1610.         std::vector<Position> GetReferencedCells() const override;
  1611.        
  1612.         bool HasCache() override;
  1613.         void InvalidateCache() override;
  1614.        
  1615.     private:
  1616.         mutable std::optional<FormulaInterface::Value> cache_;
  1617.         std::unique_ptr<FormulaInterface> formula_ptr_;
  1618.         SheetInterface& sheet_;
  1619.     };
  1620.    
  1621.     std::unique_ptr<Impl> impl_;
  1622.     Sheet& sheet_;
  1623.    
  1624.     std::set<Cell*> dependent_cells_;
  1625.     std::set<Cell*> referenced_cells_;
  1626. };
  1627. -----------------------------------------------------------------------
  1628. sheet.h
  1629. -----------------------------------------------------------------------
  1630. #pragma once
  1631.  
  1632. #include "cell.h"
  1633. #include "common.h"
  1634.  
  1635. #include <functional>
  1636. #include <vector>
  1637.  
  1638. using Table = std::vector<std::vector<std::unique_ptr<Cell>>>;
  1639.  
  1640. class Sheet : public SheetInterface {
  1641. public:
  1642.     ~Sheet();
  1643.  
  1644.     void SetCell(Position pos, std::string text) override;
  1645.    
  1646.     CellInterface* GetCell(Position pos) override;
  1647.     const CellInterface* GetCell(Position pos) const override;
  1648.     Cell* Get_Cell(Position pos);
  1649.     const Cell* Get_Cell(Position pos) const;
  1650.  
  1651.     void ClearCell(Position pos) override;
  1652.  
  1653.     Size GetPrintableSize() const override;
  1654.  
  1655.     void PrintValues(std::ostream& output) const override;
  1656.     void PrintTexts(std::ostream& output) const override;
  1657.  
  1658. private:
  1659.     Table cells_;
  1660. };
  1661. -----------------------------------------------------------------------
  1662. sheet.cpp
  1663. -----------------------------------------------------------------------
  1664. #include "sheet.h"
  1665.  
  1666. #include "cell.h"
  1667. #include "common.h"
  1668.  
  1669. #include <algorithm>
  1670. #include <functional>
  1671. #include <iostream>
  1672. #include <optional>
  1673.  
  1674. using namespace std::literals;
  1675.  
  1676. Sheet::~Sheet() {}
  1677.  
  1678. void Sheet::SetCell(Position pos, std::string text) {
  1679.    
  1680.     if (pos.IsValid()) {
  1681.        
  1682.         cells_.resize(std::max(pos.row + 1, int(std::size(cells_))));
  1683.         cells_[pos.row].resize(std::max(pos.col + 1, int(std::size(cells_[pos.row]))));
  1684.  
  1685.         if (!cells_[pos.row][pos.col]) {cells_[pos.row][pos.col] = std::make_unique<Cell>(*this);}
  1686.         cells_[pos.row][pos.col]->Set(std::move(text));
  1687.        
  1688.     } else {
  1689.         throw InvalidPositionException("invalid cell position. setsell");
  1690.     }    
  1691. }
  1692.  
  1693. CellInterface* Sheet::GetCell(Position pos) {
  1694.    
  1695.     if (pos.IsValid()) {
  1696.        
  1697.         if (pos.row < int(std::size(cells_)) && pos.col < int(std::size(cells_[pos.row]))) {
  1698.            
  1699.             if (cells_[pos.row][pos.col].get()->GetText() == "") {
  1700.                 return nullptr;
  1701.                
  1702.             } else {
  1703.                 return cells_[pos.row][pos.col].get();
  1704.             }
  1705.  
  1706.         } else {
  1707.             return nullptr;
  1708.         }
  1709.        
  1710.     } else {
  1711.         throw InvalidPositionException("invalid cell position. getcell");
  1712.     }
  1713. }
  1714.  
  1715. const CellInterface* Sheet::GetCell(Position pos) const {
  1716.     if (pos.IsValid()) {
  1717.        
  1718.         if (pos.row < int(std::size(cells_)) && pos.col < int(std::size(cells_[pos.row]))) {
  1719.            
  1720.             if (cells_[pos.row][pos.col].get()->GetText() == "") {
  1721.                 return nullptr;
  1722.                
  1723.             } else {
  1724.                 return cells_[pos.row][pos.col].get();
  1725.             }
  1726.  
  1727.         } else {
  1728.             return nullptr;
  1729.         }
  1730.        
  1731.     } else {
  1732.         throw InvalidPositionException("invalid cell position. getcell");
  1733.     }
  1734. }
  1735.  
  1736. Cell* Sheet::Get_Cell(Position pos) {
  1737.    
  1738.     if (pos.IsValid()) {
  1739.        
  1740.         if (pos.row < int(std::size(cells_)) && pos.col < int(std::size(cells_[pos.row]))) {
  1741.             return cells_[pos.row][pos.col].get();
  1742.            
  1743.         } else {
  1744.             return nullptr;
  1745.         }
  1746.          
  1747.     } else {
  1748.         throw InvalidPositionException("invalid cell position. get_cell");
  1749.     }
  1750.    
  1751. }
  1752.  
  1753. const Cell* Sheet::Get_Cell(Position pos) const {
  1754.     const Cell* const_result = Get_Cell(pos);
  1755.     return const_result;
  1756. }
  1757.  
  1758. void Sheet::ClearCell(Position pos) {
  1759.    
  1760.     if (pos.IsValid()) {
  1761.        
  1762.         if (pos.row < int(std::size(cells_)) && pos.col < int(std::size(cells_[pos.row]))) {
  1763.            
  1764.             if (cells_[pos.row][pos.col]) {
  1765.                 cells_[pos.row][pos.col]->Clear();
  1766.                
  1767.                 if (!cells_[pos.row][pos.col]->IsReferenced()) {
  1768.                     cells_[pos.row][pos.col].reset();
  1769.                 }
  1770.             }
  1771.         }
  1772.        
  1773.     } else {    
  1774.         throw InvalidPositionException("invalid cell position. clearcell");
  1775.     }
  1776. }
  1777.  
  1778. Size Sheet::GetPrintableSize() const {
  1779.    
  1780.     Size size;
  1781.    
  1782.     for (int row = 0; row < int(std::size(cells_)); ++row) {
  1783.        
  1784.         for (int col = (int(std::size(cells_[row])) - 1); col >= 0; --col) {
  1785.  
  1786.             if (cells_[row][col]) {
  1787.                
  1788.                 if (cells_[row][col]->GetText().empty()) {
  1789.                     continue;
  1790.                    
  1791.                 } else {
  1792.                     size.rows = std::max(size.rows, row + 1);
  1793.                     size.cols = std::max(size.cols, col + 1);
  1794.                     break;
  1795.                 }
  1796.             }
  1797.         }
  1798.     }
  1799.    
  1800.     return size;
  1801. }
  1802.  
  1803. void Sheet::PrintValues(std::ostream& output) const {
  1804.    
  1805.     for (int row = 0; row < GetPrintableSize().rows; ++row) {    
  1806.        
  1807.         for (int col = 0; col < GetPrintableSize().cols; ++col) {
  1808.            
  1809.             if (col > 0) {output << '\t';}
  1810.            
  1811.             if (col < int(std::size(cells_[row]))) {  
  1812.                
  1813.                 if (cells_[row][col]) {std::visit([&output](const auto& value) {output << value;},
  1814.                                        cells_[row][col]->GetValue());}
  1815.             }
  1816.         }
  1817.        
  1818.         output << '\n';
  1819.     }
  1820. }
  1821.            
  1822. void Sheet::PrintTexts(std::ostream& output) const {
  1823.    
  1824.     for (int row = 0; row < GetPrintableSize().rows; ++row) {  
  1825.        
  1826.         for (int col = 0; col < GetPrintableSize().cols; ++col) {
  1827.            
  1828.             if (col) {output << '\t';}
  1829.            
  1830.             if (col < int(std::size(cells_[row]))) {  
  1831.                
  1832.                 if (cells_[row][col]) {output << cells_[row][col]->GetText();}
  1833.             }
  1834.         }
  1835.        
  1836.         output << '\n';
  1837.     }
  1838. }
  1839.  
  1840. std::unique_ptr<SheetInterface> CreateSheet() {return std::make_unique<Sheet>();}
  1841. -----------------------------------------------------------------------
  1842. structures.cpp
  1843. -----------------------------------------------------------------------
  1844. #include "common.h"
  1845.  
  1846. #include <cctype>
  1847. #include <sstream>
  1848. #include <algorithm>
  1849.  
  1850. const int LETTERS = 26;
  1851. const int MAX_POSITION_LENGTH = 17;
  1852. const int MAX_POS_LETTER_COUNT = 3;
  1853.  
  1854. const Position Position::NONE = {-1, -1};
  1855.  
  1856. bool Position::operator==(const Position rhs) const {return row == rhs.row && col == rhs.col;}
  1857. bool Position::operator<(const Position rhs) const {return std::tie(row, col) < std::tie(rhs.row, rhs.col);}
  1858.  
  1859. bool Position::IsValid() const {return row >= 0 && col >= 0 && row < MAX_ROWS && col < MAX_COLS;}
  1860.  
  1861. std::string Position::ToString() const {
  1862.    
  1863.     if (!IsValid()) {return "";}
  1864.  
  1865.     std::string result;
  1866.     result.reserve(MAX_POSITION_LENGTH);
  1867.     int c = col;
  1868.    
  1869.     while (c >= 0) {
  1870.         result.insert(result.begin(), 'A' + c % LETTERS);
  1871.         c = c / LETTERS - 1;
  1872.     }
  1873.  
  1874.     result += std::to_string(row + 1);
  1875.     return result;
  1876. }
  1877.  
  1878. Position Position::FromString(std::string_view str) {
  1879.    
  1880.     auto it = std::find_if(str.begin(), str.end(), [](const char c) {
  1881.         return !(std::isalpha(c) && std::isupper(c));
  1882.     });
  1883.    
  1884.     auto letters = str.substr(0, it - str.begin());
  1885.     auto digits = str.substr(it - str.begin());
  1886.  
  1887.     if (letters.empty() || digits.empty()) {return Position::NONE;}
  1888.     if (letters.size() > MAX_POS_LETTER_COUNT) {return Position::NONE;}
  1889.     if (!std::isdigit(digits[0])) {return Position::NONE;}
  1890.  
  1891.     int row;
  1892.     std::istringstream row_in{std::string{digits}};
  1893.    
  1894.     if (!(row_in >> row) || !row_in.eof()) {return Position::NONE;}
  1895.  
  1896.     int col = 0;
  1897.    
  1898.     for (char ch : letters) {
  1899.         col *= LETTERS;
  1900.         col += ch - 'A' + 1;
  1901.     }
  1902.  
  1903.     return {row - 1, col - 1};
  1904. }
  1905.  
  1906. bool Size::operator==(Size rhs) const {return cols == rhs.cols && rows == rhs.rows;}
Advertisement
Add Comment
Please, Sign In to add comment