shushus

Спринт 16. Дерево для вычисления формул. Задание 2.

Jun 20th, 2023
694
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 24.86 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 <stdexcept>
  195.  
  196. class FormulaError : public std::runtime_error {
  197. public:
  198.     using std::runtime_error::runtime_error;
  199. };
  200.  
  201. std::ostream& operator<<(std::ostream& output, FormulaError fe);
  202.  
  203. class FormulaException : public std::runtime_error {
  204. public:
  205.     using std::runtime_error::runtime_error;
  206. };
  207. -----------------------------------------------------------------------
  208. Formula.g4
  209. -----------------------------------------------------------------------
  210. grammar Formula;
  211.  
  212. main
  213.     : expr EOF
  214.     ;
  215.  
  216. expr
  217.     : '(' expr ')'  # Parens
  218.     | (ADD | SUB) expr  # UnaryOp
  219.     | expr (MUL | DIV) expr  # BinaryOp
  220.     | expr (ADD | SUB) expr  # BinaryOp
  221.     | NUMBER  # Literal
  222.     ;
  223.  
  224. fragment INT: [-+]? UINT ;
  225. fragment UINT: [0-9]+ ;
  226. fragment EXPONENT: [eE] INT;
  227. NUMBER
  228.     : UINT EXPONENT?
  229.     | UINT? '.' UINT EXPONENT?
  230.     ;
  231.  
  232. ADD: '+' ;
  233. SUB: '-' ;
  234. MUL: '*' ;
  235. DIV: '/' ;
  236. WS: [ \t\n\r]+ -> skip ;
  237. -----------------------------------------------------------------------
  238. FormulaAST.h
  239. -----------------------------------------------------------------------
  240. #pragma once
  241.  
  242. #include "FormulaLexer.h"
  243. #include "common.h"
  244.  
  245. #include <forward_list>
  246. #include <functional>
  247. #include <stdexcept>
  248.  
  249. namespace ASTImpl {
  250. class Expr;
  251. }
  252.  
  253. class ParsingError : public std::runtime_error {
  254.     using std::runtime_error::runtime_error;
  255. };
  256.  
  257. class FormulaAST {
  258. public:
  259.     explicit FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr);
  260.     FormulaAST(FormulaAST&&) = default;
  261.     FormulaAST& operator=(FormulaAST&&) = default;
  262.     ~FormulaAST();
  263.  
  264.     double Execute() const;
  265.     void Print(std::ostream& out) const;
  266.     void PrintFormula(std::ostream& out) const;
  267.  
  268. private:
  269.     std::unique_ptr<ASTImpl::Expr> root_expr_;
  270. };
  271.  
  272. FormulaAST ParseFormulaAST(std::istream& in);
  273. FormulaAST ParseFormulaAST(const std::string& in_str);
  274. -----------------------------------------------------------------------
  275. FormulaAST.cpp
  276. -----------------------------------------------------------------------
  277. #include "FormulaAST.h"
  278.  
  279. #include "FormulaBaseListener.h"
  280. #include "FormulaLexer.h"
  281. #include "FormulaParser.h"
  282.  
  283. #include <cassert>
  284. #include <cmath>
  285. #include <memory>
  286. #include <optional>
  287. #include <sstream>
  288.  
  289. namespace ASTImpl {
  290.  
  291. enum ExprPrecedence {
  292.     EP_ADD,
  293.     EP_SUB,
  294.     EP_MUL,
  295.     EP_DIV,
  296.     EP_UNARY,
  297.     EP_ATOM,
  298.     EP_END,
  299. };
  300.  
  301. enum PrecedenceRule {
  302.     PR_NONE = 0b00,              
  303.     PR_LEFT = 0b01,              
  304.     PR_RIGHT = 0b10,              
  305.     PR_BOTH = PR_LEFT | PR_RIGHT,  
  306. };
  307.  
  308. constexpr PrecedenceRule PRECEDENCE_RULES[EP_END][EP_END] = {
  309.     /* EP_ADD */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  310.     /* EP_SUB */ {PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  311.     /* EP_MUL */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  312.     /* EP_DIV */ {PR_BOTH, PR_BOTH, PR_RIGHT, PR_RIGHT, PR_NONE, PR_NONE},
  313.     /* EP_UNARY */ {PR_BOTH, PR_BOTH, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  314.     /* EP_ATOM */ {PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE},
  315. };
  316.  
  317. class Expr {
  318. public:
  319.     virtual ~Expr() = default;
  320.     virtual void Print(std::ostream& out) const = 0;
  321.     virtual void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const = 0;
  322.     virtual double Evaluate() const = 0;
  323.  
  324.     virtual ExprPrecedence GetPrecedence() const = 0;
  325.  
  326.     void PrintFormula(std::ostream& out, ExprPrecedence parent_precedence,
  327.                       bool right_child = false) const {
  328.         auto precedence = GetPrecedence();
  329.         auto mask = right_child ? PR_RIGHT : PR_LEFT;
  330.         bool parens_needed = PRECEDENCE_RULES[parent_precedence][precedence] & mask;
  331.         if (parens_needed) {
  332.             out << '(';
  333.         }
  334.  
  335.         DoPrintFormula(out, precedence);
  336.  
  337.         if (parens_needed) {
  338.             out << ')';
  339.         }
  340.     }
  341. };
  342.  
  343. namespace {
  344. class BinaryOpExpr final : public Expr {
  345. public:
  346.     enum Type : char {
  347.         Add = '+',
  348.         Subtract = '-',
  349.         Multiply = '*',
  350.         Divide = '/',
  351.     };
  352.  
  353. public:
  354.     explicit BinaryOpExpr(Type type, std::unique_ptr<Expr> lhs, std::unique_ptr<Expr> rhs)
  355.         : type_(type)
  356.         , lhs_(std::move(lhs))
  357.         , rhs_(std::move(rhs)) {
  358.     }
  359.  
  360.     void Print(std::ostream& out) const override {
  361.         out << '(' << static_cast<char>(type_) << ' ';
  362.         lhs_->Print(out);
  363.         out << ' ';
  364.         rhs_->Print(out);
  365.         out << ')';
  366.     }
  367.  
  368.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  369.         lhs_->PrintFormula(out, precedence);
  370.         out << static_cast<char>(type_);
  371.         rhs_->PrintFormula(out, precedence, /* right_child = */ true);
  372.     }
  373.  
  374.     ExprPrecedence GetPrecedence() const override {
  375.         switch (type_) {
  376.             case Add:
  377.                 return EP_ADD;
  378.             case Subtract:
  379.                 return EP_SUB;
  380.             case Multiply:
  381.                 return EP_MUL;
  382.             case Divide:
  383.                 return EP_DIV;
  384.             default:
  385.                 assert(false);
  386.                 return static_cast<ExprPrecedence>(INT_MAX);
  387.         }
  388.     }
  389.  
  390.     double Evaluate() const override {
  391.        
  392.         switch (type_) {
  393.                
  394.             case Add:
  395.                 return lhs_->Evaluate() + rhs_->Evaluate();
  396.                
  397.             case Subtract:
  398.                 return lhs_->Evaluate() - rhs_->Evaluate();
  399.                
  400.             case Multiply:
  401.                 return lhs_->Evaluate() * rhs_->Evaluate();
  402.            
  403.             case Divide:
  404.                
  405.                 if (rhs_->Evaluate() != 0) {
  406.                     return lhs_->Evaluate() / rhs_->Evaluate();
  407.                    
  408.                 } else {
  409.                     throw FormulaError("DIV/0");
  410.                 }  
  411.            
  412.             default:
  413.                 throw FormulaError("unidentified operation type");
  414.         }
  415.     }
  416.  
  417. private:
  418.     Type type_;
  419.     std::unique_ptr<Expr> lhs_;
  420.     std::unique_ptr<Expr> rhs_;
  421. };
  422.  
  423. class UnaryOpExpr final : public Expr {
  424. public:
  425.     enum Type : char {
  426.         UnaryPlus = '+',
  427.         UnaryMinus = '-',
  428.     };
  429.  
  430. public:
  431.     explicit UnaryOpExpr(Type type, std::unique_ptr<Expr> operand)
  432.         : type_(type)
  433.         , operand_(std::move(operand)) {
  434.     }
  435.  
  436.     void Print(std::ostream& out) const override {
  437.         out << '(' << static_cast<char>(type_) << ' ';
  438.         operand_->Print(out);
  439.         out << ')';
  440.     }
  441.  
  442.     void DoPrintFormula(std::ostream& out, ExprPrecedence precedence) const override {
  443.         out << static_cast<char>(type_);
  444.         operand_->PrintFormula(out, precedence);
  445.     }
  446.  
  447.     ExprPrecedence GetPrecedence() const override {
  448.         return EP_UNARY;
  449.     }
  450.  
  451.     double Evaluate() const override {
  452.      
  453.         switch (type_) {
  454.                
  455.             case UnaryPlus:
  456.                 return operand_->Evaluate();
  457.                
  458.             case UnaryMinus:
  459.                 return -operand_->Evaluate();
  460.            
  461.             default:
  462.                 throw FormulaError("unidentified operation type");
  463.         }
  464.     }
  465.  
  466. private:
  467.     Type type_;
  468.     std::unique_ptr<Expr> operand_;
  469. };
  470.  
  471. class NumberExpr final : public Expr {
  472. public:
  473.     explicit NumberExpr(double value)
  474.         : value_(value) {
  475.     }
  476.  
  477.     void Print(std::ostream& out) const override {
  478.         out << value_;
  479.     }
  480.  
  481.     void DoPrintFormula(std::ostream& out, ExprPrecedence /* precedence */) const override {
  482.         out << value_;
  483.     }
  484.  
  485.     ExprPrecedence GetPrecedence() const override {
  486.         return EP_ATOM;
  487.     }
  488.  
  489.     double Evaluate() const override {
  490.         return value_;
  491.     }
  492.  
  493. private:
  494.     double value_;
  495. };
  496.  
  497. class ParseASTListener final : public FormulaBaseListener {
  498. public:
  499.     std::unique_ptr<Expr> MoveRoot() {
  500.         assert(args_.size() == 1);
  501.         auto root = std::move(args_.front());
  502.         args_.clear();
  503.  
  504.         return root;
  505.     }
  506.  
  507. public:
  508.     void exitUnaryOp(FormulaParser::UnaryOpContext* ctx) override {
  509.         assert(args_.size() >= 1);
  510.  
  511.         auto operand = std::move(args_.back());
  512.  
  513.         UnaryOpExpr::Type type;
  514.         if (ctx->SUB()) {
  515.             type = UnaryOpExpr::UnaryMinus;
  516.         } else {
  517.             assert(ctx->ADD() != nullptr);
  518.             type = UnaryOpExpr::UnaryPlus;
  519.         }
  520.  
  521.         auto node = std::make_unique<UnaryOpExpr>(type, std::move(operand));
  522.         args_.back() = std::move(node);
  523.     }
  524.  
  525.     void exitLiteral(FormulaParser::LiteralContext* ctx) override {
  526.         double value = 0;
  527.         auto valueStr = ctx->NUMBER()->getSymbol()->getText();
  528.         std::istringstream in(valueStr);
  529.         in >> value;
  530.         if (!in) {
  531.             throw ParsingError("Invalid number: " + valueStr);
  532.         }
  533.  
  534.         auto node = std::make_unique<NumberExpr>(value);
  535.         args_.push_back(std::move(node));
  536.     }
  537.  
  538.     void exitBinaryOp(FormulaParser::BinaryOpContext* ctx) override {
  539.         assert(args_.size() >= 2);
  540.  
  541.         auto rhs = std::move(args_.back());
  542.         args_.pop_back();
  543.  
  544.         auto lhs = std::move(args_.back());
  545.  
  546.         BinaryOpExpr::Type type;
  547.         if (ctx->ADD()) {
  548.             type = BinaryOpExpr::Add;
  549.         } else if (ctx->SUB()) {
  550.             type = BinaryOpExpr::Subtract;
  551.         } else if (ctx->MUL()) {
  552.             type = BinaryOpExpr::Multiply;
  553.         } else {
  554.             assert(ctx->DIV() != nullptr);
  555.             type = BinaryOpExpr::Divide;
  556.         }
  557.  
  558.         auto node = std::make_unique<BinaryOpExpr>(type, std::move(lhs), std::move(rhs));
  559.         args_.back() = std::move(node);
  560.     }
  561.  
  562.     void visitErrorNode(antlr4::tree::ErrorNode* node) override {
  563.         throw ParsingError("Error when parsing: " + node->getSymbol()->getText());
  564.     }
  565.  
  566. private:
  567.     std::vector<std::unique_ptr<Expr>> args_;
  568. };
  569.  
  570. class BailErrorListener : public antlr4::BaseErrorListener {
  571. public:
  572.     void syntaxError(antlr4::Recognizer* /* recognizer */, antlr4::Token* /* offendingSymbol */,
  573.                      size_t /* line */, size_t /* charPositionInLine */, const std::string& msg,
  574.                      std::exception_ptr /* e */
  575.                      ) override {
  576.         throw ParsingError("Error when lexing: " + msg);
  577.     }
  578. };
  579.  
  580. }//end namespace
  581. }//end namespace ASTImpl
  582.  
  583. FormulaAST ParseFormulaAST(std::istream& in) {
  584.     using namespace antlr4;
  585.  
  586.     ANTLRInputStream input(in);
  587.  
  588.     FormulaLexer lexer(&input);
  589.     ASTImpl::BailErrorListener error_listener;
  590.     lexer.removeErrorListeners();
  591.     lexer.addErrorListener(&error_listener);
  592.  
  593.     CommonTokenStream tokens(&lexer);
  594.  
  595.     FormulaParser parser(&tokens);
  596.     auto error_handler = std::make_shared<BailErrorStrategy>();
  597.     parser.setErrorHandler(error_handler);
  598.     parser.removeErrorListeners();
  599.  
  600.     tree::ParseTree* tree = parser.main();
  601.     ASTImpl::ParseASTListener listener;
  602.     tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
  603.  
  604.     return FormulaAST(listener.MoveRoot());
  605. }
  606.  
  607. FormulaAST ParseFormulaAST(const std::string& in_str) {
  608.     std::istringstream in(in_str);
  609.     try {
  610.         return ParseFormulaAST(in);
  611.     } catch (const std::exception& exc) {
  612.         std::throw_with_nested(FormulaException(exc.what()));
  613.     }
  614. }
  615.  
  616. void FormulaAST::Print(std::ostream& out) const {
  617.     root_expr_->Print(out);
  618. }
  619.  
  620. void FormulaAST::PrintFormula(std::ostream& out) const {
  621.     root_expr_->PrintFormula(out, ASTImpl::EP_ATOM);
  622. }
  623.  
  624. double FormulaAST::Execute() const {
  625.     return root_expr_->Evaluate();
  626. }
  627.  
  628. FormulaAST::FormulaAST(std::unique_ptr<ASTImpl::Expr> root_expr)
  629.     : root_expr_(std::move(root_expr)) {
  630. }
  631.  
  632. FormulaAST::~FormulaAST() = default;
  633. -----------------------------------------------------------------------
  634. main.cpp
  635. -----------------------------------------------------------------------
  636. #include "FormulaAST.h"
  637. #include "common.h"
  638. #include "formula.h"
  639. #include "test_runner_p.h"
  640.  
  641. using Value = FormulaInterface::Value;
  642.  
  643. namespace {
  644.    
  645.     Value ExecuteFormula(const std::string& expression) {
  646.         return ParseFormula(expression)->Evaluate();
  647.     }
  648.    
  649. }//end namespace
  650.  
  651. int main() {
  652.    
  653.     try {
  654.         auto empty_formula = ParseFormula("");
  655.     } catch (const FormulaException& exc) {
  656.         std::cout << exc.what() << std::endl;
  657.     }
  658.  
  659.     try {
  660.         auto wrong_formula = ParseFormula("A1");
  661.     } catch (const FormulaException& exc) {
  662.         std::cout << exc.what() << std::endl;
  663.     }
  664.  
  665.     try {
  666.         auto wrong_formula = ParseFormula("22/(22)+++++");
  667.     } catch (const FormulaException& exc) {
  668.         std::cout << exc.what() << std::endl;
  669.     }
  670.  
  671.     ASSERT_EQUAL(std::get<double>(ExecuteFormula("1")), 1.0);
  672.     ASSERT_EQUAL(std::get<double>(ExecuteFormula("1+2*3-4/5")), 6.2);
  673.  
  674.     std::cout << std::get<FormulaError>(ExecuteFormula("1/0")) << std::endl;
  675.  
  676.     auto complex_formula = ParseFormula("((22/(22+3))-(8*5))");
  677.     ASSERT_EQUAL(complex_formula->GetExpression(), "22/(22+3)-8*5");
  678.  
  679.     std::cout << "Tests Passed" << std::endl;
  680.     return 0;
  681. }
  682. -----------------------------------------------------------------------
  683. test_runner_p.h
  684. -----------------------------------------------------------------------
  685. #pragma once
  686.  
  687. #include <iostream>
  688. #include <map>
  689. #include <set>
  690. #include <sstream>
  691. #include <stdexcept>
  692. #include <string>
  693. #include <unordered_map>
  694. #include <vector>
  695.  
  696. namespace TestRunnerPrivate {
  697.   template <typename K, typename V, template <typename, typename> class Map>
  698.   std::ostream& PrintMap(std::ostream& os, const Map<K, V>& m) {
  699.     os << "{";
  700.     bool first = true;
  701.     for (const auto& kv : m) {
  702.       if (!first) {
  703.         os << ", ";
  704.       }
  705.       first = false;
  706.       os << kv.first << ": " << kv.second;
  707.     }
  708.     return os << "}";
  709.   }
  710. }
  711.  
  712. template <class T>
  713. std::ostream& operator<<(std::ostream& os, const std::vector<T>& s) {
  714.   os << "{";
  715.   bool first = true;
  716.   for (const auto& x : s) {
  717.     if (!first) {
  718.       os << ", ";
  719.     }
  720.     first = false;
  721.     os << x;
  722.   }
  723.   return os << "}";
  724. }
  725.  
  726. template <class T>
  727. std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
  728.   os << "{";
  729.   bool first = true;
  730.   for (const auto& x : s) {
  731.     if (!first) {
  732.       os << ", ";
  733.     }
  734.     first = false;
  735.     os << x;
  736.   }
  737.   return os << "}";
  738. }
  739.  
  740. template <class K, class V>
  741. std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
  742.   return TestRunnerPrivate::PrintMap(os, m);
  743. }
  744.  
  745. template <class K, class V>
  746. std::ostream& operator<<(std::ostream& os, const std::unordered_map<K, V>& m) {
  747.   return TestRunnerPrivate::PrintMap(os, m);
  748. }
  749.  
  750. template <class T, class U>
  751. void AssertEqual(const T& t, const U& u, const std::string& hint = {}) {
  752.   if (!(t == u)) {
  753.     std::ostringstream os;
  754.     os << "Assertion failed: " << t << " != " << u;
  755.     if (!hint.empty()) {
  756.       os << " hint: " << hint;
  757.     }
  758.     throw std::runtime_error(os.str());
  759.   }
  760. }
  761.  
  762. inline void Assert(bool b, const std::string& hint) {
  763.   AssertEqual(b, true, hint);
  764. }
  765.  
  766. class TestRunner {
  767. public:
  768.   template <class TestFunc>
  769.   void RunTest(TestFunc func, const std::string& test_name) {
  770.     try {
  771.       func();
  772.       std::cerr << test_name << " OK" << std::endl;
  773.     } catch (std::exception& e) {
  774.       ++fail_count;
  775.       std::cerr << test_name << " fail: " << e.what() << std::endl;
  776.     } catch (...) {
  777.       ++fail_count;
  778.       std::cerr << "Unknown exception caught" << std::endl;
  779.     }
  780.   }
  781.  
  782.   ~TestRunner() {
  783.     std::cerr.flush();
  784.     if (fail_count > 0) {
  785.       std::cerr << fail_count << " unit tests failed. Terminate" << std::endl;
  786.       exit(1);
  787.     }
  788.   }
  789.  
  790. private:
  791.   int fail_count = 0;
  792. };
  793.  
  794. #ifndef FILE_NAME
  795. #define FILE_NAME __FILE__
  796. #endif
  797.  
  798. #define ASSERT_EQUAL(x, y)                                               \
  799.   {                                                                      \
  800.     std::ostringstream __assert_equal_private_os;                        \
  801.     __assert_equal_private_os << #x << " != " << #y << ", " << FILE_NAME \
  802.                               << ":" << __LINE__;                        \
  803.     AssertEqual(x, y, __assert_equal_private_os.str());                  \
  804.   }
  805.  
  806. #define ASSERT(x)                                                  \
  807.   {                                                                \
  808.     std::ostringstream __assert_private_os;                        \
  809.     __assert_private_os << #x << " is false, " << FILE_NAME << ":" \
  810.                         << __LINE__;                               \
  811.     Assert(x, __assert_private_os.str());                          \
  812.   }
  813.  
  814. #define RUN_TEST(tr, func) tr.RunTest(func, #func)
  815. -----------------------------------------------------------------------
  816. formula.h
  817. -----------------------------------------------------------------------
  818. #pragma once
  819.  
  820. #include "common.h"
  821.  
  822. #include "FormulaAST.h"
  823.  
  824. #include <memory>
  825. #include <variant>
  826.  
  827. class FormulaInterface {
  828. public:
  829.     using Value = std::variant<double, FormulaError>;
  830.  
  831.     virtual ~FormulaInterface() = default;
  832.     virtual Value Evaluate() const = 0;
  833.     virtual std::string GetExpression() const = 0;
  834. };
  835.  
  836. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression);
  837. -----------------------------------------------------------------------
  838. formula.cpp
  839. -----------------------------------------------------------------------
  840. #include "formula.h"
  841.  
  842. #include "FormulaAST.h"
  843.  
  844. #include <algorithm>
  845. #include <cassert>
  846. #include <cctype>
  847. #include <sstream>
  848.  
  849. using namespace std::literals;
  850.  
  851. std::ostream& operator<<(std::ostream& output, FormulaError fe) {
  852.     return output << "#DIV/0!";
  853. }
  854.  
  855. namespace {
  856. class Formula : public FormulaInterface {
  857. public:
  858.    
  859.     explicit Formula(std::string expression) : ast_(ParseFormulaAST(expression)) {}
  860.    
  861.     Value Evaluate() const override {
  862.        
  863.         try {
  864.             return ast_.Execute();
  865.            
  866.         } catch (const FormulaError& evaluate_error) {
  867.             return evaluate_error;
  868.         }
  869.     }
  870.    
  871.     std::string GetExpression() const override {
  872.         std::ostringstream out;
  873.         ast_.PrintFormula(out);
  874.        
  875.         return out.str();
  876.     }
  877.  
  878. private:
  879.     FormulaAST ast_;
  880. };
  881.    
  882. }//end namespace
  883.  
  884. std::unique_ptr<FormulaInterface> ParseFormula(std::string expression) {
  885.     return std::make_unique<Formula>(std::move(expression));
  886. }
Advertisement
Add Comment
Please, Sign In to add comment