From 92cd4e542a1b42bd10e2bdf9fe403d8316108a94 Mon Sep 17 00:00:00 2001 From: Bobby Lucero Date: Sat, 27 May 2023 20:12:30 -0400 Subject: [PATCH] Binary and hex notation --- headers/Interpreter.h | 2 + headers/Lexer.h | 5 +- headers/helperFunctions/HelperFunctions.h | 15 ++++ source.bob | 4 +- source/Interpreter.cpp | 66 ++++++++++++++-- source/Lexer.cpp | 92 +++++++++++++++++++---- source/bob.cpp | 7 +- 7 files changed, 165 insertions(+), 26 deletions(-) diff --git a/headers/Interpreter.h b/headers/Interpreter.h index 83e0c4f..6ecd5e0 100644 --- a/headers/Interpreter.h +++ b/headers/Interpreter.h @@ -20,4 +20,6 @@ private: bool isEqual(sptr(Object) a, sptr(Object) b); std::string stringify(sptr(Object) object); + + bool isWholeNumer(double num); }; diff --git a/headers/Lexer.h b/headers/Lexer.h index 290c6e0..a582c7e 100644 --- a/headers/Lexer.h +++ b/headers/Lexer.h @@ -58,5 +58,8 @@ private: std::vector src; private: bool matchOn(char expected); - void advance(); + + char peekNext(); + + void advance(int by = 1); }; diff --git a/headers/helperFunctions/HelperFunctions.h b/headers/helperFunctions/HelperFunctions.h index 7738f09..92fb5cb 100644 --- a/headers/helperFunctions/HelperFunctions.h +++ b/headers/helperFunctions/HelperFunctions.h @@ -2,6 +2,7 @@ #include #include +#include std::vector splitString(const std::string& input, std::string delimiter) { std::vector tokens; @@ -48,5 +49,19 @@ std::string replaceSubstring(const std::string& str, const std::string& findSubs startPos = result.find(findSubstring, startPos + replacement.length()); } + return result; +} + +bool isHexDigit(char c) { + return (std::isdigit(c) || (std::isxdigit(c) && std::islower(c))); +} + +u_long binaryStringToLong(const std::string& binaryString) { + std::string binaryDigits = binaryString.substr(2); // Remove the '0b' prefix + u_long result = 0; + for (char ch : binaryDigits) { + result <<= 1; + result += (ch - '0'); + } return result; } \ No newline at end of file diff --git a/source.bob b/source.bob index f737e90..261aba8 100644 --- a/source.bob +++ b/source.bob @@ -1 +1,3 @@ -10 + 10 \ No newline at end of file +//10 + 10 +//0xFF + 0xFF +0xFF + 0xFF00 == 0xFFFF \ No newline at end of file diff --git a/source/Interpreter.cpp b/source/Interpreter.cpp index 696c0a7..f77dbbb 100644 --- a/source/Interpreter.cpp +++ b/source/Interpreter.cpp @@ -7,11 +7,23 @@ #include #include #include "../headers/Interpreter.h" +#include "../headers/helperFunctions/HelperFunctions.h" sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) { if(expr->isNull) return msptr(None)(); - if(expr->isNumber) return msptr(Number)(std::stod(expr->value)); + if(expr->isNumber){ + double num; + if(expr->value[1] == 'b') + { + num = binaryStringToLong(expr->value); + } + else + { + num = std::stod(expr->value); + } + return msptr(Number)(num); + } return msptr(String)(expr->value); } @@ -86,9 +98,37 @@ sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) } else if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) { - std::string left_string = std::dynamic_pointer_cast(left)->value; - std::string right_string = std::dynamic_pointer_cast(right)->value; - return msptr(String)(left_string + right_string); + switch (expression->oper.type) { + case PLUS: + std::string left_string = std::dynamic_pointer_cast(left)->value; + std::string right_string = std::dynamic_pointer_cast(right)->value; + return msptr(String)(left_string + right_string); + } + throw std::runtime_error("Cannot use '" + expression->oper.lexeme + "' on two strings"); + + } + else if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) + { + switch (expression->oper.type) { + case STAR: + std::string left_string = std::dynamic_pointer_cast(left)->value; + double right_number = std::dynamic_pointer_cast(right)->value; + if(isWholeNumer(right_number)) + { + std::stringstream ss; + for (int i = 0; i < (int)right_number; ++i) { + ss << left_string; + } + return msptr(String)(ss.str()); + + } + else + { + throw std::runtime_error("String multiplier must be whole number"); + } + } + throw std::runtime_error("Cannot use '" + expression->oper.lexeme + "' on a string and a number"); + } else { @@ -158,7 +198,7 @@ bool Interpreter::isEqual(sptr(Object) a, sptr(Object) b) { void Interpreter::interpret(std::shared_ptr expr) { sptr(Object) value = evaluate(std::move(expr)); - std::cout << stringify(value) << std::endl; + std::cout << "\033[0;32m" << stringify(value) << std::endl; } @@ -181,7 +221,7 @@ std::string Interpreter::stringify(std::shared_ptr object) { } else { - ss << std::fixed << std::setprecision(std::numeric_limits::digits10) << num->value;\ + ss << std::fixed << std::setprecision(std::numeric_limits::digits10 - 1) << num->value; std::string str = ss.str(); str.erase(str.find_last_not_of('0') + 1, std::string::npos); if (str.back() == '.') { @@ -201,6 +241,20 @@ std::string Interpreter::stringify(std::shared_ptr object) { } } +bool Interpreter::isWholeNumer(double num) { + double integral = num; + double fractional = std::modf(num, &integral); + + if(std::abs(fractional) < std::numeric_limits::epsilon()) + { + return true; + } + else + { + return false; + } +} + diff --git a/source/Lexer.cpp b/source/Lexer.cpp index 5dd40ea..6e36bfb 100644 --- a/source/Lexer.cpp +++ b/source/Lexer.cpp @@ -124,6 +124,7 @@ std::vector Lexer::Tokenize(std::string source){ advance(); while(!src.empty() && src[0] != '"') { + if(src[0] == '\n') line++; str += src[0]; advance(); @@ -148,33 +149,80 @@ std::vector Lexer::Tokenize(std::string source){ } else { + bool isNotation = false; + bool notationInvalidated = false; + char notationChar; //Multi char tokens if(std::isdigit(t)) { std::string num; - while(!src.empty() && std::isdigit(src[0])) - { - num += src[0]; - advance(); - } - if(!src.empty() && src[0] == '.') + if(src[0] != '0') notationInvalidated = true; + + while(!src.empty()) { - advance(); - if(!src.empty() && std::isdigit(src[0])) + if(std::isdigit(src[0])) { - num += '.'; - while(!src.empty() && std::isdigit(src[0])) + if(src[0] == '0' && !notationInvalidated) { - num += src[0]; - advance(); + if(peekNext() == 'b' || peekNext() == 'x') { + num += "0"; + num += peekNext(); + notationChar = peekNext(); + advance(2); + isNotation = true; + break; + } + } + + num += src[0]; + advance(); + + } + else + { + break; + } + + } + if(!isNotation) { + if (!src.empty() && src[0] == '.') { + advance(); + if (!src.empty() && std::isdigit(src[0])) { + num += '.'; + while (!src.empty() && std::isdigit(src[0])) { + num += src[0]; + advance(); + } + } else { + throw std::runtime_error("LEXER: malformed number at: " + std::to_string(this->line)); + } + + } + } + else + { + if(!src.empty() && ishexnumber(src[0])) + { + if(notationChar == 'b') { + while (!src.empty() && (src[0] == '0' || src[0] == '1')) { + num += src[0]; + advance(); + } + } + else if(notationChar == 'x') + { + while (!src.empty() && ishexnumber(src[0])) { + + num += src[0]; + advance(); + } } } else { - throw std::runtime_error("LEXER: malformed number at: " + std::to_string(this->line)); + throw std::runtime_error("LEXER: malformed notation at: " + std::to_string(this->line)); } - } tokens.push_back(Token{NUMBER, num, line}); @@ -224,7 +272,19 @@ bool Lexer::matchOn(char expected) return true; } -void Lexer::advance() +void Lexer::advance(int by) { - src.erase(src.begin()); + for (int i = 0; i < by; ++i) { + src.erase(src.begin()); + } } + +char Lexer::peekNext() +{ + if(src.size() > 1) + { + return src[1]; + } +} + + diff --git a/source/bob.cpp b/source/bob.cpp index 25a5b98..247b20b 100644 --- a/source/bob.cpp +++ b/source/bob.cpp @@ -27,7 +27,7 @@ void Bob::runPrompt() for(;;) { string line; - cout << "-> "; + cout << "\033[0;36m" << "-> " << "\033[0;37m"; std::getline(std::cin, line); if(std::cin.eof()) @@ -52,10 +52,13 @@ void Bob::run(string source) Parser p(tokens); shared_ptr expr = p.parse(); interpreter.interpret(expr); + //cout << "=========================" << endl; + ASTPrinter printer; + //cout << dynamic_pointer_cast(printer.print(expr))->value << endl; for(Token t : tokens){ - cout << "{type: " << t.type << ", value: " << t.lexeme << "}" << endl; + //cout << "{type: " << t.type << ", value: " << t.lexeme << "}" << endl; }