shushus

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

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