| | |
| | | |
| | | #include <algorithm> |
| | | #include <memory> |
| | | #include <sstream> // Hibaüzenetekhez |
| | | #include <stack> |
| | | #include <stdexcept> |
| | | #include <string> |
| | | #include <vector> |
| | | |
| | | // Szükséges header-ök a Lexer és Symbol komponensekből |
| | | #include "Interpreter/ExpressionBuilder.hpp" |
| | | #include "Interpreter/OperationsFactory.hpp" |
| | | #include "Lexer/Token.hpp" |
| | | #include "Lexer/TokenType.hpp" // Enum és TypeToString |
| | | #include "Lexer/TokenType.hpp" |
| | | #include "Parser/ParsedExpression.hpp" |
| | | #include "Symbols/ParameterContainer.hpp" |
| | | #include "Symbols/SymbolContainer.hpp" |
| | | #include "Symbols/SymbolFactory.hpp" |
| | | #include "Symbols/Value.hpp" // Symbols::Value miatt |
| | | #include "Symbols/Value.hpp" |
| | | |
| | | namespace Parser { |
| | | |
| | |
| | | public: |
| | | Parser() {} |
| | | |
| | | void parseProgram(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string) { |
| | | void parseScript(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string, |
| | | const std::string & filename) { |
| | | tokens_ = tokens; |
| | | input_str_view_ = input_string; |
| | | current_token_index_ = 0; |
| | | symbol_container_ = std::make_unique<Symbols::SymbolContainer>(); |
| | | current_filename_ = filename; |
| | | |
| | | try { |
| | | while (!isAtEnd() && currentToken().type != Lexer::Tokens::Type::END_OF_FILE) { |
| | | parseStatement(); |
| | |
| | | } |
| | | } |
| | | |
| | | const std::shared_ptr<Symbols::SymbolContainer> & getSymbolContainer() const { |
| | | if (!symbol_container_) { |
| | | throw std::runtime_error("Symbol container is not initialized."); |
| | | } |
| | | return symbol_container_; |
| | | } |
| | | |
| | | static const std::unordered_map<std::string, Lexer::Tokens::Type> keywords; |
| | | static const std::unordered_map<Lexer::Tokens::Type, Symbols::Variables::Type> variable_types; |
| | | |
| | | private: |
| | | std::vector<Lexer::Tokens::Token> tokens_; |
| | | std::string_view input_str_view_; |
| | | size_t current_token_index_; |
| | | std::shared_ptr<Symbols::SymbolContainer> symbol_container_; |
| | | std::vector<Lexer::Tokens::Token> tokens_; |
| | | std::string_view input_str_view_; |
| | | size_t current_token_index_; |
| | | std::string current_filename_; |
| | | |
| | | // Token Stream Kezelő és Hibakezelő segédfüggvények (változatlanok) |
| | | const Lexer::Tokens::Token & currentToken() const { |
| | |
| | | void parseStatement() { |
| | | const auto & token_type = currentToken().type; |
| | | |
| | | if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION) { |
| | | if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION) { |
| | | parseFunctionDefinition(); |
| | | return; |
| | | } |
| | |
| | | reportError("Unexpected token at beginning of statement"); |
| | | } |
| | | |
| | | // parseVariableDefinition (SymbolFactory használata már korrekt volt) |
| | | void parseVariableDefinition() { |
| | | Symbols::Variables::Type var_type_enum = parseType(); |
| | | // A típus stringjének tárolása csak a debug kiíráshoz kell |
| | | //std::string var_type_str = tokens_[current_token_index_ - 1].value; |
| | | std::cout << "var_name: " << currentToken().lexeme << std::endl; |
| | | Symbols::Variables::Type var_type = parseType(); |
| | | |
| | | Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER); |
| | | std::string var_name = id_token.value; |
| | | // Levágjuk a '$' jelet, ha a lexer mégis benne hagyta |
| | | |
| | | if (!var_name.empty() && var_name[0] == '$') { |
| | | var_name = var_name.substr(1); |
| | | } |
| | | const auto ns = Symbols::SymbolContainer::instance()->currentScopeName(); |
| | | |
| | | expect(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "="); |
| | | Symbols::Value initial_value = parseValue(var_type_enum); |
| | | /* |
| | | Symbols::Value initial_value = parseValue(var_type); |
| | | |
| | | Interpreter::OperationsFactory::defineSimpleVariable(var_name, initial_value, ns, this->current_filename_, |
| | | id_token.line_number, id_token.column_number); |
| | | */ |
| | | |
| | | auto expr = parseParsedExpression(var_type); |
| | | Interpreter::OperationsFactory::defineVariableWithExpression( |
| | | var_name, var_type, std::move(expr), ns, current_filename_, id_token.line_number, id_token.column_number); |
| | | expect(Lexer::Tokens::Type::PUNCTUATION, ";"); |
| | | |
| | | std::string context = "global"; // Globális változó |
| | | // SymbolFactory használata a létrehozáshoz |
| | | auto variable_symbol = Symbols::SymbolFactory::createVariable(var_name, initial_value, context, var_type_enum); |
| | | |
| | | // Ellenőrzés és definíció az *aktuális* scope-ban (ami itt a globális) |
| | | if (symbol_container_->exists("variables", var_name)) { |
| | | reportError("Variable '" + var_name + "' already defined in this scope"); |
| | | } |
| | | symbol_container_->define("variables", variable_symbol); |
| | | |
| | | // Debugging kiírás (változatlan) |
| | | // std::cout << "Parsed variable: " << var_type_str << " " << id_token.value << " = ... ;\n"; |
| | | } |
| | | |
| | | // *** MÓDOSÍTOTT parseFunctionDefinition *** |
| | | void parseFunctionDefinition() { |
| | | expect(Lexer::Tokens::Type::KEYWORD_FUNCTION); |
| | | expect(Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION); |
| | | Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::IDENTIFIER); |
| | | std::string func_name = id_token.value; |
| | | Symbols::Variables::Type func_return_type = Symbols::Variables::Type::NULL_TYPE; |
| | |
| | | if (currentToken().type != Lexer::Tokens::Type::PUNCTUATION || currentToken().value != ")") { |
| | | while (true) { |
| | | // Paraméter típusa |
| | | //size_t type_token_index = current_token_index_; // Elmentjük a típus token indexét |
| | | Symbols::Variables::Type param_type = parseType(); // Ez elfogyasztja a type tokent |
| | | |
| | | // Paraméter név ($variable) |
| | |
| | | } |
| | | } |
| | | |
| | | auto function_symbol = |
| | | Symbols::SymbolFactory::createFunction(func_name, "global", param_infos, "", func_return_type); |
| | | if (symbol_container_->exists("functions", func_name)) { |
| | | reportError("Function '" + func_name + "' already defined in this scope"); |
| | | } |
| | | |
| | | Lexer::Tokens::Token opening_brace = expect(Lexer::Tokens::Type::PUNCTUATION, "{"); |
| | | |
| | | symbol_container_->define("functions", function_symbol); |
| | | |
| | | // only parse the body if we checked out if not exists the function and created the symbol |
| | | Symbols::SymbolContainer func_symbols = |
| | | parseFunctionBody(opening_brace, func_return_type != Symbols::Variables::Type::NULL_TYPE); |
| | | |
| | | // create new container for the function |
| | | |
| | | std::cout << "Defined function symbol: " << func_name << " in global scope.\n"; |
| | | |
| | | // 3. Új scope nyitása a függvény paraméterei (és később lokális változói) számára |
| | | symbol_container_->enterScope(); |
| | | //std::cout << "Entered scope for function: " << func_name << "\n"; |
| | | |
| | | // 4. Paraméterek definiálása mint változók az *új* (függvény) scope-ban |
| | | const std::string & param_context = func_name; // Paraméter kontextusa a függvény neve |
| | | for (const auto & p_info : param_infos) { |
| | | auto param_symbol = Symbols::SymbolFactory::createVariable(p_info.name, // Név '$' nélkül |
| | | Symbols::Value(), // Alapértelmezett/üres érték |
| | | param_context, // Kontextus |
| | | p_info.type // Típus |
| | | ); |
| | | |
| | | if (symbol_container_->exists("variables", p_info.name)) { |
| | | reportError("Parameter name '" + p_info.name + "' conflicts with another symbol in function '" + |
| | | func_name + "'"); |
| | | } |
| | | symbol_container_->define("variables", param_symbol); |
| | | } |
| | | |
| | | // 5. Függvény scope elhagyása |
| | | symbol_container_->leaveScope(); |
| | | //std::cout << "Left scope for function: " << func_name << "\n"; |
| | | |
| | | // Debugging kiírás (változatlan) |
| | | // std::cout << "Parsed function: " << func_name << " (...) { ... } scope handled.\n"; |
| | | parseFunctionBody(opening_brace, func_name, func_return_type, param_infos); |
| | | } |
| | | |
| | | // --- Elemzési Segédfüggvények --- |
| | |
| | | reportError("Expected type keyword (string, int, double, float)"); |
| | | } |
| | | |
| | | // value : STRING_LITERAL | NUMBER |
| | | // Feldolgozza az értéket a várt típus alapján. |
| | | Symbols::Value parseValue(Symbols::Variables::Type expected_var_type) { |
| | | Lexer::Tokens::Token token = currentToken(); |
| | | Lexer::Tokens::Token token = currentToken(); |
| | | bool is_negative = false; |
| | | |
| | | /// find if this is a function call |
| | | if (token.type == Lexer::Tokens::Type::IDENTIFIER && peekToken().lexeme == "(") { |
| | | for (const auto & symbol_ptr : this->symbol_container_->listNamespace("functions")) { |
| | | if (auto func_symbol = std::dynamic_pointer_cast<Symbols::FunctionSymbol>(symbol_ptr)) { |
| | | // TODO: A függvény hívását kellene feldolgozni, a func_symbol-ból kellene lekérni a paramétereket, func_symbol->plainBody() tartalmazza a függvény törzsét |
| | | // A függvény hívásának feldolgozása |
| | | std::cout << "Function call: " << token.value << "\n"; |
| | | while (consumeToken().lexeme != ")") { |
| | | // Feltételezzük, hogy a függvény hívását a lexer már feldolgozta |
| | | } |
| | | return Symbols::Value(""); // TODO: Implementálni a függvény hívását |
| | | } |
| | | } |
| | | } |
| | | |
| | | bool is_negative = false; |
| | | std::cout << "Peek: " << peekToken().lexeme << "\n"; |
| | | if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC && peekToken().type == Lexer::Tokens::Type::NUMBER) { |
| | | is_negative = true; |
| | | // Előjel kezelése |
| | | if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC && (token.lexeme == "-" || token.lexeme == "+") && |
| | | peekToken().type == Lexer::Tokens::Type::NUMBER) { |
| | | is_negative = (token.lexeme == "-"); |
| | | token = peekToken(); |
| | | consumeToken(); |
| | | consumeToken(); // előjelet elfogyasztottuk |
| | | } |
| | | |
| | | // STRING típus |
| | | if (expected_var_type == Symbols::Variables::Type::STRING) { |
| | | if (token.type == Lexer::Tokens::Type::STRING_LITERAL) { |
| | | consumeToken(); |
| | | return Symbols::Value(token.value); // A lexer value-ja már a feldolgozott string |
| | | return Symbols::Value(token.value); |
| | | } |
| | | reportError("Expected string literal value"); |
| | | } else if (expected_var_type == Symbols::Variables::Type::INTEGER) { |
| | | if (token.type == Lexer::Tokens::Type::NUMBER) { |
| | | // Konvertálás int-re, hibakezeléssel |
| | | try { |
| | | // TODO: Ellenőrizni, hogy a szám valóban egész-e (nincs benne '.') |
| | | // Most egyszerűen std::stoi-t használunk. |
| | | int int_value = std::stoi(token.value); |
| | | if (is_negative) { |
| | | int_value = -int_value; |
| | | } |
| | | consumeToken(); |
| | | return Symbols::Value(int_value); |
| | | } catch (const std::invalid_argument & e) { |
| | | reportError("Invalid integer literal: " + token.value); |
| | | } catch (const std::out_of_range & e) { |
| | | reportError("Integer literal out of range: " + token.value); |
| | | } |
| | | } |
| | | reportError("Expected integer literal value"); |
| | | } else if (expected_var_type == Symbols::Variables::Type::DOUBLE) { |
| | | if (token.type == Lexer::Tokens::Type::NUMBER) { |
| | | // Konvertálás double-re, hibakezeléssel |
| | | try { |
| | | double double_value = std::stod(token.value); |
| | | if (is_negative) { |
| | | double_value = -double_value; |
| | | } |
| | | consumeToken(); |
| | | return Symbols::Value(double_value); |
| | | } catch (const std::invalid_argument & e) { |
| | | reportError("Invalid double literal: " + token.value); |
| | | } catch (const std::out_of_range & e) { |
| | | reportError("Double literal out of range: " + token.value); |
| | | } |
| | | } |
| | | reportError("Expected numeric literal value for double"); |
| | | } else if (expected_var_type == Symbols::Variables::Type::FLOAT) { |
| | | if (token.type == Lexer::Tokens::Type::NUMBER) { |
| | | // Konvertálás double-re, hibakezeléssel |
| | | try { |
| | | |
| | | float float_value = std::atof(token.value.data()); |
| | | if (is_negative) { |
| | | float_value = -float_value; |
| | | } |
| | | consumeToken(); |
| | | return Symbols::Value(float_value); |
| | | } catch (const std::invalid_argument & e) { |
| | | reportError("Invalid float literal: " + token.value); |
| | | } catch (const std::out_of_range & e) { |
| | | reportError("Float literal out of range: " + token.value); |
| | | } |
| | | } |
| | | reportError("Expected numeric literal value for double"); |
| | | } else if (expected_var_type == Symbols::Variables::Type::BOOLEAN) { |
| | | if (token.type == Lexer::Tokens::Type::KEYWORD) { |
| | | consumeToken(); |
| | | return Symbols::Value(token.value == "true"); // A lexer value-ja már a feldolgozott string |
| | | } |
| | | reportError("Expected boolean literal value"); |
| | | } else { |
| | | // Más típusok (pl. boolean) itt kezelendők, ha lennének |
| | | reportError("Unsupported variable type encountered during value parsing"); |
| | | } |
| | | // Should not reach here due to reportError throwing |
| | | return Symbols::Value(); // Default return to satisfy compiler |
| | | |
| | | // BOOLEAN típus |
| | | if (expected_var_type == Symbols::Variables::Type::BOOLEAN) { |
| | | if (token.type == Lexer::Tokens::Type::KEYWORD && (token.value == "true" || token.value == "false")) { |
| | | consumeToken(); |
| | | return Symbols::Value(token.value == "true"); |
| | | } |
| | | reportError("Expected boolean literal value (true or false)"); |
| | | } |
| | | |
| | | // NUMERIC típusok |
| | | if (expected_var_type == Symbols::Variables::Type::INTEGER || |
| | | expected_var_type == Symbols::Variables::Type::DOUBLE || |
| | | expected_var_type == Symbols::Variables::Type::FLOAT) { |
| | | if (token.type == Lexer::Tokens::Type::NUMBER) { |
| | | Symbols::Value val = parseNumericLiteral(token.value, is_negative, expected_var_type); |
| | | consumeToken(); |
| | | return val; |
| | | } |
| | | |
| | | reportError("Expected numeric literal value"); |
| | | } |
| | | |
| | | reportError("Unsupported variable type encountered during value parsing"); |
| | | return Symbols::Value(); // compiler happy |
| | | } |
| | | |
| | | Symbols::SymbolContainer parseFunctionBody(const Lexer::Tokens::Token & opening_brace, |
| | | bool return_required = false) { |
| | | Symbols::Value parseNumericLiteral(const std::string & value, bool is_negative, Symbols::Variables::Type type) { |
| | | try { |
| | | switch (type) { |
| | | case Symbols::Variables::Type::INTEGER: |
| | | { |
| | | if (value.find('.') != std::string::npos) { |
| | | throw std::invalid_argument("Floating point value in integer context: " + value); |
| | | } |
| | | int v = std::stoi(value); |
| | | return Symbols::Value(is_negative ? -v : v); |
| | | } |
| | | case Symbols::Variables::Type::DOUBLE: |
| | | { |
| | | double v = std::stod(value); |
| | | return Symbols::Value(is_negative ? -v : v); |
| | | } |
| | | case Symbols::Variables::Type::FLOAT: |
| | | { |
| | | float v = std::stof(value); |
| | | return Symbols::Value(is_negative ? -v : v); |
| | | } |
| | | default: |
| | | throw std::invalid_argument("Unsupported numeric type"); |
| | | } |
| | | } catch (const std::invalid_argument & e) { |
| | | reportError("Invalid numeric literal: " + value + " (" + e.what() + ")"); |
| | | } catch (const std::out_of_range & e) { |
| | | reportError("Numeric literal out of range: " + value + " (" + e.what() + ")"); |
| | | } |
| | | |
| | | return Symbols::Value(); // unreachable |
| | | } |
| | | |
| | | void parseFunctionBody(const Lexer::Tokens::Token & opening_brace, const std::string & function_name, |
| | | Symbols::Variables::Type return_type, const Symbols::FunctionParameterInfo & params) { |
| | | size_t braceDepth = 0; |
| | | int peek = 0; |
| | | int tokenIndex = current_token_index_; |
| | | Lexer::Tokens::Token currentToken_; |
| | | Lexer::Tokens::Token closing_brace; |
| | | |
| | | while (tokenIndex < tokens_.size()) { |
| | | currentToken_ = peekToken(); |
| | | |
| | | currentToken_ = peekToken(peek); |
| | | if (currentToken_.type == Lexer::Tokens::Type::PUNCTUATION) { |
| | | if (currentToken_.value == "{") { |
| | | ++braceDepth; |
| | |
| | | --braceDepth; |
| | | } |
| | | } |
| | | tokenIndex++; |
| | | peek++; |
| | | } |
| | | if (braceDepth != 0) { |
| | | reportError("Unmatched braces in function body"); |
| | |
| | | auto startIt = std::find(tokens_.begin(), tokens_.end(), opening_brace); |
| | | auto endIt = std::find(tokens_.begin(), tokens_.end(), closing_brace); |
| | | |
| | | // Ellenőrzés: mindkét token megtalálva és start_token megelőzi az end_token-t |
| | | if (startIt != tokens_.end() && endIt != tokens_.end() && startIt < endIt) { |
| | | filtered_tokens = std::vector<Lexer::Tokens::Token>(startIt + 1, endIt); |
| | | } |
| | | std::string_view input_string = input_str_view_.substr(opening_brace.end_pos, closing_brace.end_pos); |
| | | auto parser = Parser(); |
| | | parser.parseProgram(filtered_tokens, input_string); |
| | | |
| | | return *parser.getSymbolContainer(); |
| | | current_token_index_ = tokenIndex; |
| | | expect(Lexer::Tokens::Type::PUNCTUATION, "}"); |
| | | const std::string newns = Symbols::SymbolContainer::instance()->currentScopeName() + "." + function_name; |
| | | Symbols::SymbolContainer::instance()->create(newns); |
| | | std::shared_ptr<Parser> parser = std::make_shared<Parser>(); |
| | | parser->parseScript(filtered_tokens, input_string, this->current_filename_); |
| | | Symbols::SymbolContainer::instance()->enterPreviousScope(); |
| | | // create function |
| | | Interpreter::OperationsFactory::defineFunction( |
| | | function_name, params, return_type, Symbols::SymbolContainer::instance()->currentScopeName(), |
| | | this->current_filename_, currentToken_.line_number, currentToken_.column_number); |
| | | } |
| | | |
| | | std::string parseFunctionBodyOld(size_t body_start_pos, bool return_required = false) { |
| | | std::stringstream body_ss; |
| | | int brace_level = 1; |
| | | size_t last_token_end_pos = body_start_pos; |
| | | bool has_return = false; |
| | | ParsedExpressionPtr parseParsedExpression(const Symbols::Variables::Type & expected_var_type) { |
| | | std::stack<std::string> operator_stack; |
| | | std::vector<ParsedExpressionPtr> output_queue; |
| | | |
| | | auto getPrecedence = [](const std::string & op) -> int { |
| | | if (op == "+" || op == "-") { |
| | | return 1; |
| | | } |
| | | if (op == "*" || op == "/") { |
| | | return 2; |
| | | } |
| | | if (op == "u-" || op == "u+") { |
| | | return 3; |
| | | } |
| | | return 0; |
| | | }; |
| | | |
| | | auto isLeftAssociative = [](const std::string & op) -> bool { |
| | | return !(op == "u-" || op == "u+"); |
| | | }; |
| | | |
| | | auto applyOperator = [](const std::string & op, ParsedExpressionPtr rhs, ParsedExpressionPtr lhs = nullptr) { |
| | | if (op == "u-" || op == "u+") { |
| | | std::string real_op = (op == "u-") ? "-" : "+"; |
| | | return ParsedExpression::makeUnary(real_op, std::move(rhs)); |
| | | } else { |
| | | return ParsedExpression::makeBinary(op, std::move(lhs), std::move(rhs)); |
| | | } |
| | | }; |
| | | |
| | | auto pushOperand = [&](const Lexer::Tokens::Token & token) { |
| | | if (token.type == Lexer::Tokens::Type::NUMBER || token.type == Lexer::Tokens::Type::STRING_LITERAL || |
| | | token.type == Lexer::Tokens::Type::KEYWORD) { |
| | | output_queue.push_back( |
| | | ParsedExpression::makeLiteral(Symbols::Value::fromString(token.value, expected_var_type))); |
| | | } else if (token.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) { |
| | | std::string name = token.value; |
| | | if (!name.empty() && name[0] == '$') { |
| | | name = name.substr(1); |
| | | } |
| | | output_queue.push_back(ParsedExpression::makeVariable(name)); |
| | | } else { |
| | | reportError("Expected literal or variable"); |
| | | } |
| | | }; |
| | | |
| | | bool expect_unary = true; |
| | | |
| | | while (true) { |
| | | if (isAtEnd()) { |
| | | reportError("Unexpected end of file inside function body (missing '}')"); |
| | | } |
| | | const auto & token = currentToken(); |
| | | auto token = currentToken(); |
| | | |
| | | // Whitespace visszaállítása (ha volt) az 'input_str_view_' alapján |
| | | if (token.start_pos > last_token_end_pos) { |
| | | if (last_token_end_pos < input_str_view_.length() && token.start_pos <= input_str_view_.length()) { |
| | | body_ss << input_str_view_.substr(last_token_end_pos, token.start_pos - last_token_end_pos); |
| | | } else { |
| | | reportError("Invalid position range in body reconstruction"); |
| | | if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.lexeme == "(") { |
| | | operator_stack.push("("); |
| | | consumeToken(); |
| | | expect_unary = true; |
| | | } else if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.lexeme == ")") { |
| | | consumeToken(); |
| | | while (!operator_stack.empty() && operator_stack.top() != "(") { |
| | | std::string op = operator_stack.top(); |
| | | operator_stack.pop(); |
| | | |
| | | if (op == "u-" || op == "u+") { |
| | | if (output_queue.empty()) { |
| | | reportError("Missing operand for unary operator"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(op, std::move(rhs))); |
| | | } else { |
| | | if (output_queue.size() < 2) { |
| | | reportError("Malformed expression"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | auto lhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(op, std::move(rhs), std::move(lhs))); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (token.type == Lexer::Tokens::Type::KEYWORD_RETURN) { |
| | | has_return = true; |
| | | } |
| | | |
| | | if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "{") { |
| | | brace_level++; |
| | | body_ss << token.lexeme; |
| | | } else if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "}") { |
| | | brace_level--; |
| | | if (brace_level == 0) { |
| | | consumeToken(); // Záró '}' elfogyasztása |
| | | break; |
| | | if (operator_stack.empty() || operator_stack.top() != "(") { |
| | | reportError("Mismatched parentheses"); |
| | | } |
| | | body_ss << token.lexeme; |
| | | operator_stack.pop(); // remove "(" |
| | | expect_unary = false; |
| | | } else if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC) { |
| | | std::string op = std::string(token.lexeme); |
| | | if (expect_unary && (op == "-" || op == "+")) { |
| | | op = "u" + op; // pl. u- |
| | | } |
| | | |
| | | while (!operator_stack.empty()) { |
| | | const std::string & top = operator_stack.top(); |
| | | if ((isLeftAssociative(op) && getPrecedence(op) <= getPrecedence(top)) || |
| | | (!isLeftAssociative(op) && getPrecedence(op) < getPrecedence(top))) { |
| | | operator_stack.pop(); |
| | | |
| | | if (top == "u-" || top == "u+") { |
| | | if (output_queue.empty()) { |
| | | reportError("Missing operand for unary operator"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(top, std::move(rhs))); |
| | | } else { |
| | | if (output_queue.size() < 2) { |
| | | reportError("Malformed expression"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | auto lhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(top, std::move(rhs), std::move(lhs))); |
| | | } |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | operator_stack.push(op); |
| | | consumeToken(); |
| | | expect_unary = true; |
| | | } else if (token.type == Lexer::Tokens::Type::NUMBER || token.type == Lexer::Tokens::Type::STRING_LITERAL || |
| | | token.type == Lexer::Tokens::Type::KEYWORD || |
| | | token.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) { |
| | | pushOperand(token); |
| | | consumeToken(); |
| | | expect_unary = false; |
| | | } else { |
| | | body_ss << token.lexeme; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // Kiürítjük az operator stack-et |
| | | while (!operator_stack.empty()) { |
| | | std::string op = operator_stack.top(); |
| | | operator_stack.pop(); |
| | | |
| | | if (op == "(" || op == ")") { |
| | | reportError("Mismatched parentheses"); |
| | | } |
| | | |
| | | last_token_end_pos = token.end_pos; |
| | | consumeToken(); |
| | | if (op == "u-" || op == "u+") { |
| | | if (output_queue.empty()) { |
| | | reportError("Missing operand for unary operator"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(op, std::move(rhs))); |
| | | } else { |
| | | if (output_queue.size() < 2) { |
| | | reportError("Malformed expression"); |
| | | } |
| | | auto rhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | auto lhs = std::move(output_queue.back()); |
| | | output_queue.pop_back(); |
| | | output_queue.push_back(applyOperator(op, std::move(rhs), std::move(lhs))); |
| | | } |
| | | } |
| | | |
| | | if (return_required && !has_return) { |
| | | return ""; |
| | | if (output_queue.size() != 1) { |
| | | reportError("Expression could not be parsed cleanly"); |
| | | } |
| | | |
| | | return body_ss.str(); |
| | | return std::move(output_queue.back()); |
| | | } |
| | | |
| | | }; // class Parser |