From e191173e7b0551cfc7ee1c68ce06851cc363e841 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sat, 25 Jan 2025 16:27:50 +0100 Subject: [PATCH] 2025-01-25 Latest Changes --- code_compiler/CMakeLists.txt | 8 +- code_compiler/source/ast/arithmetic.cpp | 9 - code_compiler/source/ast/arithmetic.hpp | 30 --- code_compiler/source/ast/ast.cpp | 8 + code_compiler/source/ast/ast.hpp | 83 ++---- code_compiler/source/ast/binary.cpp | 3 - code_compiler/source/ast/binary.hpp | 3 - code_compiler/source/ast/function.cpp | 29 --- code_compiler/source/ast/function.hpp | 50 ---- code_compiler/source/ast/value.cpp | 46 ---- code_compiler/source/ast/value.hpp | 85 ------ code_compiler/source/error.cpp | 15 ++ code_compiler/source/error.hpp | 2 + code_compiler/source/lexer.cpp | 326 ++---------------------- code_compiler/source/lexer.hpp | 9 + code_compiler/source/main.cpp | 8 +- code_compiler/source/parser.cpp | 177 +++++++------ code_compiler/source/parser.hpp | 50 +--- 18 files changed, 182 insertions(+), 759 deletions(-) delete mode 100644 code_compiler/source/ast/arithmetic.cpp delete mode 100644 code_compiler/source/ast/arithmetic.hpp delete mode 100644 code_compiler/source/ast/binary.cpp delete mode 100644 code_compiler/source/ast/binary.hpp delete mode 100644 code_compiler/source/ast/function.cpp delete mode 100644 code_compiler/source/ast/function.hpp delete mode 100644 code_compiler/source/ast/value.cpp delete mode 100644 code_compiler/source/ast/value.hpp diff --git a/code_compiler/CMakeLists.txt b/code_compiler/CMakeLists.txt index 0a0c2af..7da4554 100644 --- a/code_compiler/CMakeLists.txt +++ b/code_compiler/CMakeLists.txt @@ -1,7 +1,7 @@ # AUTOGENERATED COPYRIGHT HEADER START # Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks # AUTOGENERATED COPYRIGHT HEADER END -project(code_compiler +project(compiler VERSION ${PROJECT_VERSION} ) add_executable(${PROJECT_NAME}) @@ -19,12 +19,6 @@ target_sources(${PROJECT_NAME} PRIVATE "source/compiler.cpp" "source/ast/ast.hpp" "source/ast/ast.cpp" - "source/ast/arithmetic.hpp" - "source/ast/arithmetic.cpp" - "source/ast/function.hpp" - "source/ast/function.cpp" - "source/ast/value.hpp" - "source/ast/value.cpp" ) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/source" diff --git a/code_compiler/source/ast/arithmetic.cpp b/code_compiler/source/ast/arithmetic.cpp deleted file mode 100644 index aeadcbb..0000000 --- a/code_compiler/source/ast/arithmetic.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#include "arithmetic.hpp" - -blitz::ast::arithmetic_expression::arithmetic_expression(expression_operator op, std::unique_ptr left, std::unique_ptr right) - : m_operator(op), m_left(std::move(left)), m_right(std::move(right)) {} - -blitz::ast::arithmetic_expression::~arithmetic_expression() {} diff --git a/code_compiler/source/ast/arithmetic.hpp b/code_compiler/source/ast/arithmetic.hpp deleted file mode 100644 index ee249a6..0000000 --- a/code_compiler/source/ast/arithmetic.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#pragma once -#include "ast.hpp" -#include "value.hpp" - -namespace blitz { - namespace ast { - enum class expression_operator : int8_t { - Add, /*+*/ - Subtract, /*-*/ - Multiply, /***/ - Divide, /*/*/ - Invert, /*~*/ - Power, /*^*/ - Equal, /*=*/ - }; - - class arithmetic_expression : public expression { - public: - arithmetic_expression(expression_operator op, std::unique_ptr left, std::unique_ptr right); - virtual ~arithmetic_expression(); - - private: - expression_operator m_operator; - std::unique_ptr m_left, m_right; - }; - } -} \ No newline at end of file diff --git a/code_compiler/source/ast/ast.cpp b/code_compiler/source/ast/ast.cpp index 0ce4324..b3fdbde 100644 --- a/code_compiler/source/ast/ast.cpp +++ b/code_compiler/source/ast/ast.cpp @@ -4,3 +4,11 @@ #include "ast.hpp" #include +blitz::ast::variable::~variable() {} + +blitz::ast::variable::variable(blitz::token token) : _token(token), _value(nullptr) {} + +void blitz::ast::variable::set_value(std::shared_ptr value) +{ + _value = value; +} diff --git a/code_compiler/source/ast/ast.hpp b/code_compiler/source/ast/ast.hpp index 70ceb7a..ed68756 100644 --- a/code_compiler/source/ast/ast.hpp +++ b/code_compiler/source/ast/ast.hpp @@ -30,85 +30,34 @@ namespace blitz { namespace ast { - class expression { + class node { public: - virtual ~expression() = default; + virtual ~node() = default; }; - // Values - class value_expression : public expression { - protected: - blitz::token _token; + class expression : public node {}; + + class variable : public node { + blitz::token _token; + std::shared_ptr _value; public: - virtual ~value_expression() = default; - value_expression(blitz::token token); + virtual ~variable(); + variable(blitz::token token); + + void set_value(std::shared_ptr value); }; - class integer_expression : public value_expression { - protected: - int32_t _value; + class call : public node {}; + class local : public node { public: - virtual ~integer_expression() = default; - integer_expression(blitz::token token); + ~local(); + local(); }; - class real_expression : public value_expression { - protected: - float _value; + class global : public node {}; - public: - virtual ~real_expression() = default; - real_expression(blitz::token token); - }; - - class string_expression : public value_expression { - std::string _value; - - public: - virtual ~string_expression() = default; - string_expression(blitz::token token); - }; - - /** One or more constant values - * - * Const var = Value, var2 = value - */ - class const_expression : public expression { - std::list> _values; - - }; - - /** One or more local variables - * - * Local var, var2 = value, var3 - */ - class local_expression : public expression { - std::list> _values; - }; - - /** One or more global variables - * - * Local var, var2 = value, var3 - */ - class global_expression : public expression { - std::list> _values; - }; - - /** A variable definition - * - * - */ - class variable_expression : public expression { - blitz::token _assign; - std::string _name; - std::shared_ptr _value; - - public: - virtual ~variable_expression() = default; - variable_expression(blitz::token token); - }; } // namespace ast } // namespace blitz diff --git a/code_compiler/source/ast/binary.cpp b/code_compiler/source/ast/binary.cpp deleted file mode 100644 index 6dc7e3b..0000000 --- a/code_compiler/source/ast/binary.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END diff --git a/code_compiler/source/ast/binary.hpp b/code_compiler/source/ast/binary.hpp deleted file mode 100644 index 6dc7e3b..0000000 --- a/code_compiler/source/ast/binary.hpp +++ /dev/null @@ -1,3 +0,0 @@ -// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END diff --git a/code_compiler/source/ast/function.cpp b/code_compiler/source/ast/function.cpp deleted file mode 100644 index 0bc449b..0000000 --- a/code_compiler/source/ast/function.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#include "function.hpp" - -blitz::ast::ScopeExpression::ScopeExpression() {} - -blitz::ast::ScopeExpression::~ScopeExpression() {} - -void blitz::ast::ScopeExpression::AddExpression(std::unique_ptr ex) { - m_expressions.push_back(std::move(ex)); -} - -blitz::ast::FunctionExpression::FunctionExpression(ValueType returnType, - std::string& m_name, - std::list> parameters, - std::unique_ptr scope) - : m_returnType(returnType), m_name(m_name), m_parameters(std::move(parameters)), m_content(std::move(scope)) { - -} - -blitz::ast::FunctionExpression::~FunctionExpression() {} - -blitz::ast::CallExpression::CallExpression(std::string& name, std::list> arguments) - : m_name(name), m_arguments(std::move(arguments)) { - -} - -blitz::ast::CallExpression::~CallExpression() {} diff --git a/code_compiler/source/ast/function.hpp b/code_compiler/source/ast/function.hpp deleted file mode 100644 index 176c2ba..0000000 --- a/code_compiler/source/ast/function.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#pragma once -#include "ast.hpp" -#include "value.hpp" -#include -#include -#include - -namespace blitz { - namespace ast { - class ScopeExpression : public expression { - public: - ScopeExpression(); - virtual ~ScopeExpression(); - - void AddExpression(std::unique_ptr ex); - - private: - std::list> m_expressions; - }; - - class FunctionExpression : public ScopeExpression { - public: - FunctionExpression(ValueType returnType, - std::string& m_name, - std::list> parameters, - std::unique_ptr scope); - virtual ~FunctionExpression(); - - private: - ValueType m_returnType; - std::string m_name; - std::list> m_parameters; - std::unique_ptr m_content; - }; - - class CallExpression : public expression { - public: - CallExpression(std::string& name, std::list> arguments); - virtual ~CallExpression(); - - private: - std::string m_name; - std::list> m_arguments; - }; - - } -} diff --git a/code_compiler/source/ast/value.cpp b/code_compiler/source/ast/value.cpp deleted file mode 100644 index 32fb80d..0000000 --- a/code_compiler/source/ast/value.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#include "value.hpp" - -blitz::ast::VariableExpression::VariableExpression(std::string& name, ValueType type /*= ValueType::Number*/) - : m_name(name), m_type(type) {} - -blitz::ast::VariableExpression::~VariableExpression() {} - -blitz::ast::ValueType blitz::ast::VariableExpression::GetType() { - return m_type; -} - -blitz::ast::NumberExpression::NumberExpression(int32_t value) : value(value) {} - -blitz::ast::NumberExpression::~NumberExpression() {} - -blitz::ast::ValueType blitz::ast::NumberExpression::GetType() { - return ValueType::INTEGER; -} - -blitz::ast::DecimalExpression::DecimalExpression(float_t value) : value(value) {} - -blitz::ast::DecimalExpression::~DecimalExpression() {} - -blitz::ast::ValueType blitz::ast::DecimalExpression::GetType() { - return ValueType::REAL; -} - -blitz::ast::StringExpression::StringExpression(std::string value) : value(value) {} - -blitz::ast::StringExpression::~StringExpression() {} - -blitz::ast::ValueType blitz::ast::StringExpression::GetType() { - return ValueType::STRING; -} - -blitz::ast::ConstExpression::ConstExpression(std::string& name, std::unique_ptr value) - : m_name(name), m_value(std::move(value)) {} - -blitz::ast::ConstExpression::~ConstExpression() {} - -blitz::ast::ValueType blitz::ast::ConstExpression::GetType() { - return m_value->GetType(); -} diff --git a/code_compiler/source/ast/value.hpp b/code_compiler/source/ast/value.hpp deleted file mode 100644 index 974dc88..0000000 --- a/code_compiler/source/ast/value.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/// AUTOGENERATED COPYRIGHT HEADER START -// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks -// AUTOGENERATED COPYRIGHT HEADER END -#pragma once -#include "ast.hpp" -#include "lexer.hpp" -#include -#include -#include -#include -#include - -namespace blitz { - namespace ast { - enum class ValueType : int8_t { - UNKNOWN, - INTEGER, - REAL, - STRING, - TYPE, - }; - - class ValueExpression : public expression { - public: - virtual ValueType GetType() = 0; - }; - - class ConstExpression : public ValueExpression { - public: - ConstExpression(std::string& name, std::unique_ptr value); - virtual ~ConstExpression(); - - virtual ValueType GetType() override; - - private: - std::string m_name; - std::unique_ptr m_value; - }; - - class VariableExpression : public ValueExpression { - public: - VariableExpression(std::string& name, ValueType type = ValueType::INTEGER); - virtual ~VariableExpression(); - - virtual ValueType GetType() override; - - private: - std::string m_name; - ValueType m_type; - }; - - class NumberExpression : public ValueExpression { - public: - NumberExpression(int32_t value); - virtual ~NumberExpression(); - - virtual ValueType GetType() override; - - private: - int32_t value; - }; - - class DecimalExpression : public ValueExpression { - public: - DecimalExpression(float_t value); - virtual ~DecimalExpression(); - - virtual ValueType GetType() override; - - private: - float_t value; - }; - - class StringExpression : public ValueExpression { - public: - StringExpression(std::string value); - virtual ~StringExpression(); - - virtual ValueType GetType() override; - - private: - std::string value; - }; - } -} diff --git a/code_compiler/source/error.cpp b/code_compiler/source/error.cpp index 83d4d87..73148b2 100644 --- a/code_compiler/source/error.cpp +++ b/code_compiler/source/error.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks // AUTOGENERATED COPYRIGHT HEADER END #include "error.hpp" +#include blitz::error::~error() {} @@ -26,3 +27,17 @@ std::pair const& blitz::error::at() const { return _at; } + +std::string blitz::format(const char* format, ...) +{ + va_list arg1; + va_list arg2; + va_start(arg1, format); + va_copy(arg2, arg1); + int length = vsnprintf(nullptr, 0, format, arg1); + std::vector buffer(length + 1); + vsnprintf(buffer.data(), buffer.size(), format, arg2); + va_end(arg1); + va_end(arg2); + return {buffer.data(), buffer.data() + length}; +} diff --git a/code_compiler/source/error.hpp b/code_compiler/source/error.hpp index 24a7af2..86bb8ec 100644 --- a/code_compiler/source/error.hpp +++ b/code_compiler/source/error.hpp @@ -24,4 +24,6 @@ namespace blitz { std::pair const& at() const; }; + + std::string format(const char* format, ...); } // namespace blitz diff --git a/code_compiler/source/lexer.cpp b/code_compiler/source/lexer.cpp index 817c50a..0f562ee 100644 --- a/code_compiler/source/lexer.cpp +++ b/code_compiler/source/lexer.cpp @@ -6,20 +6,6 @@ #include #include -std::string format(const char* format, ...) -{ - va_list arg1; - va_list arg2; - va_start(arg1, format); - va_copy(arg2, arg1); - int length = vsnprintf(nullptr, 0, format, arg1); - std::vector buffer(length + 1); - vsnprintf(buffer.data(), buffer.size(), format, arg2); - va_end(arg1); - va_end(arg2); - return {buffer.data(), buffer.data() + length}; -} - std::string blitz::token::to_string() { std::string name; @@ -55,17 +41,27 @@ std::string blitz::token::to_string() name = "Symbol"; break; default: - name = "How the fuck?!"; + name = "Invalid"; break; } if (type == variant::NEWLINE || type == variant::CONTROL) { - return format("%s(%llu@%llu, %d)", name.c_str(), location.first, location.second, text[0]); + return blitz::format("%s(%llu@%llu, %d)", name.c_str(), location.first, location.second, text[0]); } else { - return format("%s(%llu@%llu, %s)", name.c_str(), location.first, location.second, text.c_str()); + return blitz::format("%s(%llu@%llu, %s)", name.c_str(), location.first, location.second, text.c_str()); } } +bool blitz::token::operator==(variant rhs) +{ + return type == rhs; +} + +bool blitz::token::operator==(std::string const& rhs) +{ + return text == rhs; +} + blitz::lexer::~lexer() {} blitz::lexer::lexer(std::filesystem::path file) @@ -77,7 +73,7 @@ blitz::lexer::lexer(std::filesystem::path file) _file = file; _stream = std::ifstream(_file, std::ios_base::binary); // We use binary so we can eventually support UTF-8. if (!_stream.good() || _stream.eof() || _stream.bad() || _stream.fail()) { - throw std::runtime_error(format("Reading file '%s' failed.", file.generic_string().c_str())); + throw std::runtime_error(blitz::format("Reading file '%s' failed.", file.generic_string().c_str())); } // Initialize token storage to a default token. @@ -94,6 +90,12 @@ blitz::token blitz::lexer::current() } blitz::token blitz::lexer::next() +{ + _current = peek(); + return _current; +} + +blitz::token blitz::lexer::peek() { enum class stage { DEFAULT, @@ -204,14 +206,14 @@ blitz::token blitz::lexer::next() complete = true; _stream.get(); _location.second++; - } else if (chr == ':') { + /*} else if (chr == ':') { // Allows code writers to pretend it's all one line. token.location = _location; token.type = blitz::token::variant::SEPARATOR; token.text = {1, char(chr)}; complete = true; _stream.get(); - _location.second++; + _location.second++;*/ } else if (chr == ';') { // A comment, which ends at the next new line. state = stage::COMMENT; @@ -308,14 +310,14 @@ blitz::token blitz::lexer::next() token.type = blitz::token::variant::REAL; } else { token.text = buffer.str(); - throw blitz::error(_file, token.location, _location, format("In token %s: Expected [0-9], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); + throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [0-9], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); } } } else if (issymbol(chr)) { complete = true; } else { token.text = buffer.str(); - throw blitz::error(_file, token.location, _location, format("In token %s: Expected [0-9.], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); + throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [0-9.], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); } if (complete) { @@ -331,7 +333,7 @@ blitz::token blitz::lexer::next() _location.second++; } else { token.text = buffer.str(); - throw blitz::error(_file, token.location, _location, format("In token %s: Expected [a-zA-Z0-9_], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); + throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [a-zA-Z0-9_], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str())); } if (complete) { @@ -372,281 +374,5 @@ blitz::token blitz::lexer::next() } } - _current = token; - return _current; + return token; } - -/* -std::pair blitz::lexer::current() { - return _current; -} - -std::pair blitz::lexer::next(std::istream& fs) { - std::stringstream buffer; - blitz::tokentype token; - - enum class parserState { - DEFAULT, - TEXT, - NUMBER, - STRING, - COMMENT, - } state = parserState::DEFAULT; - - while ((token == blitz::tokentype::TokenUnknown) && !fs.eof() && fs.good()) { - auto chr = fs.get(); - - - - - - } - -} - - -/* -std::pair blitz::lexer::next(std::shared_ptr fs) { - std::string buf; - token tkn = token::TokenUnknown; - bool haveResult = false; - - // Allow "overriding" the next retrieved Token. - if (m_overrideToken != token::TokenUnknown) { - buf = m_overrideText; - tkn = m_overrideToken; - m_overrideToken = token::TokenUnknown; - haveResult = true; - } - - bool m_isTextMode = false; - bool m_isNumberMode = false; - bool m_isStringMode = false; - bool m_isCommentMode = false; - bool m_numberModeHasDecimal = false; - while (((fs->eof() == false) && (fs->good())) && !haveResult) { - char chr = fs->get(); - - if (chr == '\r' || chr == '\n') { - if (tkn != token::TokenEOF) { - m_overrideToken = token::TokenNewLine; - m_overrideText = ""; - } else { - tkn = token::TokenNewLine; - buf = ""; - } - - m_isStringMode = false; - m_isNumberMode = false; - m_isTextMode = false; - m_isCommentMode = false; - break; - } else if (m_isStringMode) { - if (chr == '\"') { - m_overrideToken = token::TokenDoubleQuote; - m_overrideText = chr; - m_isStringMode = false; - tkn = token::TokenQuotedText; - break; - } else if (iscntrl(chr) || !isprint(chr)) { - fs->putback(chr); - m_isStringMode = false; - break; - } else { - buf += chr; - } - } else if (m_isTextMode) { - if (isalnum(chr) || (chr == '_')) { - buf += chr; - } else { - fs->putback(chr); - m_isTextMode = false; - break; - } - } else if (m_isNumberMode) { - if (isdigit(chr)) { - buf += chr; - } else if (chr == '.') { - if (m_numberModeHasDecimal == false) { - m_numberModeHasDecimal = true; - tkn = token::TokenDecimal; - buf += chr; - } else { - fs->putback(chr); - m_isNumberMode = false; - break; - } - } else { - fs->putback(chr); - m_isNumberMode = false; - break; - } - } else if (m_isCommentMode) { - buf += chr; - tkn = token::TokenComment; - } else { - // Whitespace - if (isspace(chr)) - continue; - - // Control Code - if (iscntrl(chr)) { - tkn = token::TokenUnknown; - buf = chr; - } - - // Special handling for + and -, due to numbers and decimals. - if (chr == '+' || chr == '-') { - char chr2 = fs->get(); - if (isdigit(chr2)) { - m_isNumberMode = true; - m_numberModeHasDecimal = false; - tkn = token::TokenNumber; - buf = chr + chr2; - break; - } else if (chr2 == '.') { - m_isNumberMode = true; - m_numberModeHasDecimal = true; - tkn = token::TokenDecimal; - buf = chr + "0" + chr2; - break; - } else { - fs->putback(chr2); - } - } - - // Symbol - for (auto v : g_symbolCharacters) { - if (v.first == chr) { - tkn = v.second; - buf = v.first; - break; - } - } - if (tkn != token::TokenEOF) { - haveResult = true; - break; - } - - // Strings, Text, Numbers - if (chr == ';') { - m_isCommentMode = true; - tkn = token::TokenSemicolon; - buf = chr; - break; - } else if (chr == '\"') { - m_isStringMode = true; - tkn = token::TokenDoubleQuote; - buf = chr; - break; - } else if (isalpha(chr)) { - m_isTextMode = true; - tkn = token::TokenText; - buf = chr; - } else if (isdigit(chr)) { - m_isNumberMode = true; - m_numberModeHasDecimal = false; - tkn = token::TokenNumber; - buf = chr; - } else if (chr == '.') { - m_isNumberMode = true; - m_numberModeHasDecimal = true; - tkn = token::TokenDecimal; - buf = "0" + chr; - } else { - tkn = token::TokenUnknown; - buf = chr; - break; - } - } - } - - // Convert from Text into native Token. - if (tkn == token::TokenText) - tkn = to_token(tkn, buf); - - return std::make_pair(tkn, buf); -} - -blitz::lexer::token blitz::lexer::to_token(token in, std::string text) { - static std::pair l_textToTokenList[] = { - // Binary - { "not", token::TokenNot }, - { "and", token::TokenAnd }, - { "or", token::TokenOr }, - { "xor", token::TokenXor }, - { "shl", token::TokenShl }, - { "shr", token::TokenShr }, - { "sal", token::TokenSal }, - { "sar", token::TokenSar }, - { "false", token::TokenFalse }, - { "true", token::TokenTrue }, - - // Conversion - { "float", token::TokenFloat }, - { "string", token::TokenString }, - { "hex", token::TokenHex }, - { "int", token::TokenInt }, - - // Control - { "if", token::TokenIf }, - { "then", token::TokenThen }, - { "elseif", token::TokenElseIf }, - { "else", token::TokenElse }, - { "endif", token::TokenEndIf }, - { "select", token::TokenSelect }, - { "case", token::TokenCase }, - { "default", token::TokenDefault }, - { "goto", token::TokenGoto }, - { "gosub", token::TokenGosub }, - { "return", token::TokenReturn }, - { "function", token::TokenFunction }, - { "end", token::TokenEnd }, - { "stop", token::TokenStop }, - - // Loop - { "for", token::TokenFor }, - { "to", token::TokenTo }, - { "next", token::TokenNext }, - { "while", token::TokenWhile }, - { "wend", token::TokenWend }, - { "repeat", token::TokenRepeat }, - { "until", token::TokenUntil }, - { "forever", token::TokenForever }, - { "exit", token::TokenExit }, - - // Math - { "abs", token::TokenAbs }, - { "sign", token::TokenSign }, - { "cos", token::TokenCos }, - { "sin", token::TokenSin }, - { "tan", token::TokenTan }, - { "acos", token::TokenACos }, - { "asin", token::TokenASin }, - { "atan", token::TokenATan }, - { "atan2", token::TokenATan2 }, - { "log", token::TokenLog }, - { "log10", token::TokenLog10 }, - { "ceil", token::TokenCeil }, - { "floor", token::TokenFloor }, - { "mod", token::TokenMod }, - { "pi", token::TokenPi }, - { "exp", token::TokenExp }, - { "sqr", token::TokenSqr }, - - // Variables - { "const", token::TokenConst }, - { "global", token::TokenGlobal }, - { "local", token::TokenLocal }, - - // Includes - { "include", token::TokenInclude }, - }; - for (auto v : l_textToTokenList) { - if (stricmp(text.c_str(), v.first)) { - return v.second; - } - } - return in; -} -*/ diff --git a/code_compiler/source/lexer.hpp b/code_compiler/source/lexer.hpp index 8466164..25990ee 100644 --- a/code_compiler/source/lexer.hpp +++ b/code_compiler/source/lexer.hpp @@ -35,6 +35,9 @@ namespace blitz { } type; std::string to_string(); + + bool operator==(blitz::token::variant rhs); + bool operator==(std::string const& rhs); }; class lexer { @@ -60,5 +63,11 @@ namespace blitz { * This will replace the current token. */ blitz::token next(); + + /** Peek at the next token in the given stream. + * + * The current token will remain in-tact. + */ + blitz::token peek(); }; } // namespace blitz diff --git a/code_compiler/source/main.cpp b/code_compiler/source/main.cpp index d9a2116..1425ba2 100644 --- a/code_compiler/source/main.cpp +++ b/code_compiler/source/main.cpp @@ -1,6 +1,7 @@ // AUTOGENERATED COPYRIGHT HEADER START // Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks // AUTOGENERATED COPYRIGHT HEADER END +#include #include #include "compiler.hpp" #include "error.hpp" @@ -8,6 +9,8 @@ int main(int argc, char** argv) { + std::setlocale(LC_ALL, "en_US.UTF-8"); + std::cout << argv[1] << std::endl; blitz::lexer lex(argv[1]); @@ -32,6 +35,7 @@ int main(int argc, char** argv) case blitz::token::variant::NEWLINE: std::cout << std::endl; break; + default: std::cout << token.to_string() << " "; break; @@ -47,7 +51,7 @@ int main(int argc, char** argv) std::cout << ex.what() << std::endl; } - std::cin.get(); + //std::cin.get(); return 0; } @@ -86,7 +90,7 @@ int main(int argc, char** argv) // Field Bla // End Type // Local myName.myName = New myName -// Print Int(myName) ; <- Prints the address of the object contained in myName. +// Print Int(myName) ; <- Prints the address of the object contained in myName. // ``` // // As this is a Basic language, there is no concept of undefined or uninitialized anything. Every behavior is well defined. diff --git a/code_compiler/source/parser.cpp b/code_compiler/source/parser.cpp index 4db758e..a3edb07 100644 --- a/code_compiler/source/parser.cpp +++ b/code_compiler/source/parser.cpp @@ -1,115 +1,112 @@ /// AUTOGENERATED COPYRIGHT HEADER START // Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks // AUTOGENERATED COPYRIGHT HEADER END -/* #include "parser.hpp" -#include "ast/function.hpp" -#include -#include -#include +#include +#include +#include +#include "error.hpp" -blitz::parser::parser(std::string file) { - // Try and load the file - std::shared_ptr instream = std::make_shared(file); - if (instream->bad() || !instream->good()) { - throw std::ios_base::failure("Failed to open file."); - } - m_files.push(std::make_pair(file, instream)); +blitz::parser::~parser() {} + +blitz::parser::parser(std::filesystem::path file) : _file(file), _lexer(), _expr() +{ + _lexer = std::make_shared(file); } -blitz::parser::~parser() { - while (m_files.size() > 0) { - std::shared_ptr file = std::dynamic_pointer_cast(m_files.top().second); - file->close(); - m_files.pop(); - } +std::shared_ptr blitz::parser::current() +{ + return _expr; } -std::unique_ptr blitz::parser::parse() { - std::unique_ptr scope = std::make_unique(); +std::shared_ptr blitz::parser::next() +{ + // This should return an entire "line" of expressions in one go, i.e.: + // 1. Local a = 1, b = a, c = b+a + // -> Local(Variable(a, Expression(Integer(1))), Variable(b, Expresssion(Variable(a))), Variable(c, Expression(Add(Variable(b), Variable(a))) + // 2. Include "HelloWorld.bb" + // -> Include(String("HelloWorld.bb")) + // 3. Function HelloWorld() + // -> Function(HelloWorld, ...)( + // Not quite sure if the above makes sense, we'd be returning many expressions outside of functions, but only one inside a function? Why even bother with the current/next crap then? + // Handling Include becomes a problem too. I guess we should actually return expressions on a line by line basis, and let the "compiler" figure out scope and stuff. - std::unique_ptr expr; - while ((expr = std::move(parse_expression())) != nullptr) { - scope->AddExpression(std::move(expr)); - } - - return std::move(scope); -} - -void blitz::parser::log(const char* msg, ...) { - std::vector buf(65535); - va_list val; - va_start(val, msg); - int rval = vsnprintf(buf.data(), buf.size(), msg, val); - va_end(val); - std::cout << buf.data() << '\n'; -} - -void blitz::parser::log_error(const char* msg, ...) { - std::vector buf(65535); - va_list val; - va_start(val, msg); - int rval = vsnprintf(buf.data(), buf.size(), msg, val); - va_end(val); - std::cerr << buf.data() << '\n'; -} - -std::pair blitz::parser::next() { - return m_lexer.next(m_files.top().second); -} - -std::unique_ptr blitz::parser::parse_expression() { + // Grab the next token to figure out what behavior we should have. while (true) { - auto tkn = next(); - log("%s", tkn.second.c_str()); - - switch (tkn.first) { - case blitz::lexer::tokentype::TokenNewLine: - case blitz::lexer::tokentype::TokenComment: - // Skip Comments, since we don't really need them for the AST. - continue; - case blitz::lexer::tokentype::TokenPlus: - case blitz::lexer::tokentype::TokenMinus: - - - default: // End Of File / Unknown - case blitz::lexer::tokentype::TokenUnknown: - case blitz::lexer::tokentype::TokenEOF: + auto token = _lexer->next(); + try { + switch (token.type) { + case blitz::token::variant::ENDOFFILE: + // End of file means there's nothing left to parse. + _expr.reset(); return nullptr; - break; + case blitz::token::variant::COMMENT: + case blitz::token::variant::NEWLINE: + case blitz::token::variant::SEPARATOR: + // Ignore some things that aren't very useful right now. + continue; + case blitz::token::variant::TEXT: + return try_parse(token); + default: + throw nullptr; + } + } catch (blitz::error const& ex) { + throw ex; + } catch (std::exception const& ex) { + throw new blitz::error(_file, token.location, token.location, ex.what()); + } catch (...) { + throw new blitz::error(_file, token.location, token.location, blitz::format("Token %s unexpected at this point.", token.to_string().c_str())); } } } -std::unique_ptr blitz::parser::parse_number(blitz::lexer::tokentype token, std::string value) { - if (token != lexer::tokentype::TokenNumber) { - log_error("Unexpected Token during parsing, expected number."); - return nullptr; +std::shared_ptr blitz::parser::try_parse(blitz::token token) +{ + // ToDo: Switch to a proper Unicode library. Maybe Boost? + std::string ltext; + std::transform(token.text.begin(), token.text.end(), ltext.begin(), [](std::string::value_type c) { return std::tolower(c); }); + + if ((ltext == "local") || (ltext == "global")) { + // Local/Global have the same parsing, but different functionality. + // Should be: + // Text Text [Symbol(=) Expression] [Symbol(,) Text [Symbol(=) Expression] [Symbol(,) ...]] + + } else if (ltext == "global") { + // Global ... + + } else if (ltext == "function") { + } else if (ltext == "select") { + } else if (ltext == "case") { + } else if (ltext == "endselect") { + } else if (ltext == "if") { + } else if (ltext == "elif") { + } else if (ltext == "endif") { + + } else if (ltext == "end") { } - char* endptr = const_cast(value.c_str() + value.size()); - int32_t parsed = strtol(value.c_str(), &endptr, 10); - if (errno == ERANGE) { - log_error("Number out of range."); - return nullptr; - } - - return std::make_unique(parsed); + return nullptr; } -std::unique_ptr blitz::parser::parse_decimal(blitz::lexer::tokentype token, std::string value) { - if (token != lexer::tokentype::TokenNumber) { - log_error("Unexpected Token during parsing, expected number."); - return nullptr; +std::shared_ptr blitz::parser::try_parse_variable() +{ + // Text [Symbol(=) Expression(...)] [Symbol(,) [Text [Symbol(=) Expression(...)]]] + + auto label = _lexer->next(); + if (label != blitz::token::variant::TEXT) { + throw new blitz::error(_file, label.location, label.location, blitz::format("Unexpected %s, expected Text.", label.to_string().c_str())); } - char* endptr = const_cast(value.c_str() + value.size()); - float_t parsed = strtof(value.c_str(), &endptr); - if (errno == ERANGE) { - log_error("Number out of range."); - return nullptr; + auto node = std::make_shared(label); + + auto operand = _lexer->next(); + if (operand == "=") { + //node->set_value(try_parse_expression()); + } else if (operand == blitz::token::variant::NEWLINE || operand == blitz::token::variant::SEPARATOR || (operand == blitz::token::variant::SYMBOL && operand == ",")) { + return node; + } else { + throw new blitz::error(_file, label.location, operand.location, blitz::format("Unexpected %s, expected Symbol(=), NewLine, Separator, or Symbol(,).", operand.to_string().c_str())); } - return std::make_unique(parsed); + return node; } -*/ diff --git a/code_compiler/source/parser.hpp b/code_compiler/source/parser.hpp index d906099..5fa66da 100644 --- a/code_compiler/source/parser.hpp +++ b/code_compiler/source/parser.hpp @@ -3,52 +3,26 @@ // AUTOGENERATED COPYRIGHT HEADER END #pragma once #include +#include #include "ast/ast.hpp" #include "lexer.hpp" namespace blitz { class parser { - std::filesystem::path _file; + std::filesystem::path _file; + std::shared_ptr _lexer; + + std::shared_ptr _expr; public: ~parser(); parser(std::filesystem::path file); + + std::shared_ptr current(); + std::shared_ptr next(); + + private: + std::shared_ptr try_parse(blitz::token token); + std::shared_ptr try_parse_variable(); }; } // namespace blitz - -/* -#include -#include -#include -#include -#include -#include "ast/value.hpp" -#include "lexer.hpp" - -namespace blitz { - class parser { - public: - parser(std::string file); - ~parser(); - - std::unique_ptr parse(); - - protected: - void log(const char* msg, ...); - void log_error(const char* msg, ...); - - private: - std::pair next(); - - private: - std::unique_ptr parse_expression(); - std::unique_ptr parse_number(blitz::lexer::tokentype token, std::string value); - std::unique_ptr parse_decimal(blitz::lexer::tokentype token, std::string value); - - private: - lexer m_lexer; - std::stack>> m_files; - - }; -} -*/