1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
#include <iostream> #include <string> #include <cctype> #include <stdexcept> #include <map> using namespace std; // Token types enum class TokenType { NUMBER, PLUS, MINUS, MULTIPLY, DIVIDE, END, INVALID }; // Token structure struct Token { TokenType type; int value; // For NUMBER token }; // Lexer class class Lexer { public: Lexer(const string& text) : text(text), pos(0), currentChar(text[pos]) {} Token getNextToken() { while (currentChar != '\0') { if (isspace(currentChar)) { skipWhitespace(); continue; } if (isdigit(currentChar)) { return Token{TokenType::NUMBER, getNumber()}; } if (currentChar == '+') { advance(); return Token{TokenType::PLUS, 0}; } if (currentChar == '-') { advance(); return Token{TokenType::MINUS, 0}; } if (currentChar == '*') { advance(); return Token{TokenType::MULTIPLY, 0}; } if (currentChar == '/') { advance(); return Token{TokenType::DIVIDE, 0}; } throw runtime_error("Invalid character"); } return Token{TokenType::END, 0}; } private: string text; size_t pos; char currentChar; void advance() { ++pos; if (pos >= text.length()) { currentChar = '\0'; } else { currentChar = text[pos]; } } void skipWhitespace() { while (currentChar != '\0' && isspace(currentChar)) { advance(); } } int getNumber() { string number; while (currentChar != '\0' && isdigit(currentChar)) { number += currentChar; advance(); } return stoi(number); } }; // Parser class class Parser { public: Parser(Lexer lexer) : lexer(lexer), currentToken(lexer.getNextToken()) {} int parse() { int result = expression(); if (currentToken.type != TokenType::END) { throw runtime_error("Unexpected token after end of expression"); } return result; } private: Lexer lexer; Token currentToken; void eat(TokenType type) { if (currentToken.type == type) { currentToken = lexer.getNextToken(); } else { throw runtime_error("Unexpected token type"); } } int factor() { if (currentToken.type == TokenType::NUMBER) { int value = currentToken.value; eat(TokenType::NUMBER); return value; } throw runtime_error("Expected number"); } int term() { int result = factor(); while (currentToken.type == TokenType::MULTIPLY || currentToken.type == TokenType::DIVIDE) { TokenType op = currentToken.type; eat(op); if (op == TokenType::MULTIPLY) { result *= factor(); } else { result /= factor(); } } return result; } int expression() { int result = term(); while (currentToken.type == TokenType::PLUS || currentToken.type == TokenType::MINUS) { TokenType op = currentToken.type; eat(op); if (op == TokenType::PLUS) { result += term(); } else { result -= term(); } } return result; } }; int main() { string text; cout << "Enter an arithmetic expression: "; getline(cin, text); try { Lexer lexer(text); Parser parser(lexer); int result = parser.parse(); cout << "Result: " << result << endl; } catch (const runtime_error& e) { cerr << "Error: " << e.what() << endl; } return 0; } |
Explanation
- Token Types:
TokenType
is an enum class that defines different types of tokens:NUMBER
,PLUS
,MINUS
,MULTIPLY
,DIVIDE
,END
, andINVALID
.
- Token Structure:
Token
holds the type of token and its value (if it’s a number).
- Lexer Class:
- Purpose: Breaks the input text into tokens.
- Methods:
getNextToken()
: Reads characters from the input and generates tokens. It handles numbers and arithmetic operators.advance()
: Moves to the next character in the input.skipWhitespace()
: Skips over whitespace characters.getNumber()
: Extracts multi-digit numbers from the input.
- Parser Class:
- Purpose: Parses the tokens generated by the lexer and evaluates the arithmetic expression.
- Methods:
parse()
: Starts the parsing process and returns the result.eat(TokenType type)
: Consumes a token of the specified type.factor()
: Parses a number token.term()
: Handles multiplication and division operations.expression()
: Handles addition and subtraction operations.
- Main Function (
main
):- Reads an arithmetic expression from the user.
- Initializes the lexer and parser.
- Parses the expression and outputs the result.
- Handles errors gracefully using exception handling.