diff --git a/CMakeLists.txt b/CMakeLists.txt index 019eb1c..3424a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,6 @@ add_executable( src/Location.cpp src/Error.h src/Error.cpp - src/StringConversion.h - src/StringConversion.cpp src/FormatString/FormatString.hpp src/FileIO.h src/FileIO.cpp @@ -42,21 +40,24 @@ add_executable( src/AST/ExprNode.h src/AST/MulNode.cpp src/AST/MulNode.h - src/AST/NumberNode.cpp - src/AST/NumberNode.h src/AST/StatementNode.cpp src/AST/StatementNode.h + src/AST/NumberNode.cpp + src/AST/NumberNode.h src/AST/SumNode.cpp src/AST/SumNode.h - src/replace.cpp - src/replace.h + src/utils.cpp + src/utils.h src/Parser.cpp src/Parser.h + src/sapphirepch.h ) target_include_directories(sapphirec PUBLIC src) target_include_directories(sapphirec PUBLIC src/tclap-1.2.5/include) +target_precompile_headers(sapphirec PUBLIC src/sapphirepch.h) + llvm_map_components_to_libnames(llvm_libs support core irreader) # Link against LLVM libraries diff --git a/core/__internal/linux/x64.sp b/core/__internal/linux/x64.sp index 9e70534..ae6db5b 100644 --- a/core/__internal/linux/x64.sp +++ b/core/__internal/linux/x64.sp @@ -1,22 +1,19 @@ -namespace linux { +let @sys_read (u32 fd, i8* buf, u64 size) in { + syscall3(0,fd,buf,size); +} - @sys_read (u32 fd, i8* buf, u64 size) { - syscall3(0,fd,buf,size); - } +let @sys_write (u32 fd, i8* buf, u64 size) in { + syscall3(1,fd,buf,size); +} - @sys_write (u32 fd, i8* buf, u64 size) { - syscall3(1,fd,buf,size); - } +let @sys_open (i8* name, i32 flags, u16 mode) in { + syscall3(2,name,flags,mode); +} - @sys_open (i8* name, i32 flags, u16 mode) { - syscall3(2,name,flags,mode); - } +let @sys_close (u32 fd) in { + syscall1(3,fd); +} - @sys_close (u32 fd) { - syscall1(3,fd); - } - - @sys_exit (i32 code) { - syscall1(60,code); - } -} \ No newline at end of file +let @sys_exit (i32 code) in { + syscall1(60,code); +} diff --git a/src/AST/NumberNode.cpp b/src/AST/NumberNode.cpp index 0e025c5..26990a8 100644 --- a/src/AST/NumberNode.cpp +++ b/src/AST/NumberNode.cpp @@ -1 +1,9 @@ #include "NumberNode.h" + +NumberNode::NumberNode() +{ +} + +NumberNode::~NumberNode() +{ +} \ No newline at end of file diff --git a/src/Arguments.h b/src/Arguments.h index 9d362bd..5b9af55 100644 --- a/src/Arguments.h +++ b/src/Arguments.h @@ -1,6 +1,6 @@ #pragma once +#include "sapphirepch.h" #include -#include struct Arguments { diff --git a/src/Error.cpp b/src/Error.cpp index 23e1f48..b65287e 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -1,25 +1,15 @@ #include "Error.h" #include "Importer.h" -#include "StringConversion.h" +#include "utils.h" #include #include -std::string Error::get_spaces(const int& num) -{ - std::string output; - for (int i = 0; i < num; i++) - { - output += " "; - } - return output; -} - void Error::show_import_line(const Location& loc, std::ostream& output_stream) { output_stream << "in file included from "; output_stream << "\033[1;1m"; - output_stream << loc.to_string(); + output_stream << loc.str(); output_stream << ": "; @@ -52,10 +42,10 @@ void Error::show_import_lines(const Location& loc, void (*import_line_printer)(c { show_import_lines(loc, show_import_line, std::cerr); - std::string linestr = int_to_string(loc.line); + std::string linestr = to_string(loc.line); std::cerr << "\033[1;1m"; - std::cerr << loc.to_string(); + std::cerr << loc.str(); std::cerr << ": "; @@ -67,11 +57,11 @@ void Error::show_import_lines(const Location& loc, void (*import_line_printer)(c std::cerr << std::endl; std::cerr << linestr; - std::cerr << get_spaces(4); + std::cerr << std::string(4, ' '); std::cerr << line_text; std::cerr << std::endl; - std::cerr << get_spaces(4 + linestr.size() + loc.column - 1); + std::cerr << std::string(4 + linestr.size() + loc.column - 1, ' '); std::cerr << "\033[31;49m"; std::cerr << "^"; @@ -99,10 +89,10 @@ void Error::throw_warning(const Location& loc, const std::string line_text, cons { show_import_lines(loc, show_import_line, std::cout); - std::string linestr = int_to_string(loc.line); + std::string linestr = to_string(loc.line); std::cout << "\033[1;1m"; - std::cout << loc.to_string(); + std::cout << loc.str(); std::cout << ": "; @@ -114,11 +104,11 @@ void Error::throw_warning(const Location& loc, const std::string line_text, cons std::cout << std::endl; std::cout << linestr; - std::cout << get_spaces(4); + std::cout << std::string(4, ' '); std::cout << line_text; std::cout << std::endl; - std::cout << get_spaces(4 + linestr.size() + loc.column - 1); + std::cout << std::string(4 + linestr.size() + loc.column - 1, ' '); std::cout << "\033[33;49m"; std::cout << "^"; diff --git a/src/Error.h b/src/Error.h index 79e334d..f6efd57 100644 --- a/src/Error.h +++ b/src/Error.h @@ -13,6 +13,4 @@ void throw_warning(const Location& loc, const std::string line_text, const std:: void show_import_lines(const Location& loc, void (*import_line_printer)(const Location&, std::ostream&), std::ostream& stream); - -std::string get_spaces(const int& num); } // namespace Error diff --git a/src/FileIO.cpp b/src/FileIO.cpp index a8c844e..8245fca 100644 --- a/src/FileIO.cpp +++ b/src/FileIO.cpp @@ -1,10 +1,10 @@ #include "FileIO.h" #include "Error.h" +#include "sapphirepch.h" #include #include #include #include -#include std::string FileIO::read_all(const std::string& filename) { @@ -19,7 +19,6 @@ std::string FileIO::read_all(const std::string& filename) catch (const std::exception& e) { Error::throw_error_without_location("unable to open file " + filename + ": " + strerror(errno)); - return ""; } file.exceptions(std::ios::goodbit); std::vector file_chars; diff --git a/src/FileIO.h b/src/FileIO.h index 18c29e0..2101b65 100644 --- a/src/FileIO.h +++ b/src/FileIO.h @@ -1,5 +1,5 @@ #pragma once -#include +#include "sapphirepch.h" /* Namespace for simple file operations. */ namespace FileIO diff --git a/src/Importer.cpp b/src/Importer.cpp index 1f6cc7f..b37e7e8 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -2,9 +2,8 @@ #include "Arguments.h" #include "Error.h" #include "FileIO.h" -#include +#include "sapphirepch.h" #include -#include #define MAX_IMPORTS 100 int Importer::import_count = 0; @@ -49,6 +48,7 @@ TokenStream Importer::evaluate(const TokenStream& original) } if (import_count > MAX_IMPORTS) + Error::throw_error(current_token.loc, current_token.line(), "maximum import depth exceeded"); std::string input_file_name = next_token.string_value + ".sp"; diff --git a/src/Lexer.cpp b/src/Lexer.cpp index c662f7a..4863114 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -1,6 +1,5 @@ #include "Lexer.h" #include "Error.h" -#include #define WHITESPACE "\t \n" #define LETTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ_" @@ -20,369 +19,369 @@ Lexer::~Lexer() int Lexer::advance() { - prev_loc = loc; - ++index; - loc.advance(); - if (index >= current_lexed_text.size()) return 0; - current_char = current_lexed_text[index]; - loc.pos_from_char(current_char); - if (current_char == '\n') - { - previous_line_text = current_line_text; - current_line_text = this->recalculate_current_line(current_lexed_text); - } - return 1; + prev_loc = loc; + ++index; + loc.advance(); + if (index >= current_lexed_text.size()) return 0; + current_char = current_lexed_text[index]; + loc.pos_from_char(current_char); + if (current_char == '\n') + { + previous_line_text = current_line_text; + current_line_text = this->recalculate_current_line(current_lexed_text); + } + return 1; } int Lexer::rewind() { - loc = prev_loc; - --index; - if (index == -1) return 0; - if (current_char == '\n') - { - current_line_text = previous_line_text; - } - current_char = current_lexed_text[index]; - return 1; + loc = prev_loc; + --index; + if (index == -1) return 0; + if (current_char == '\n') + { + current_line_text = previous_line_text; + } + current_char = current_lexed_text[index]; + return 1; } std::string Lexer::recalculate_current_line(const std::string& text) { - int idx = index; - std::string final_str; - ++idx; - while (idx != text.size() && text[idx] != '\n') - { - final_str += text[idx]; - ++idx; - } - return final_str; + int idx = index; + std::string final_str; + ++idx; + while (idx != text.size() && text[idx] != '\n') + { + final_str += text[idx]; + ++idx; + } + return final_str; } std::shared_ptr Lexer::make_lexer(const std::string& fname) { - return std::shared_ptr(new Lexer(fname)); // not using make_shared because the constructor is private + return std::shared_ptr(new Lexer(fname)); // not using make_shared because the constructor is private } void Lexer::assign_parent_location(std::shared_ptr& lexer, const std::shared_ptr& loc) { - lexer->loc.parent = loc; + lexer->loc.parent = loc; } bool Lexer::is_in_string(const std::string& string, const char& character) { - return string.find(character) != std::string::npos; + return string.find(character) != std::string::npos; } TokenStream Lexer::lex(const std::string& text) { - TokenStream result; - bool comment = false; - current_lexed_text = text; - current_line_text = this->recalculate_current_line(current_lexed_text); + TokenStream result; + bool comment = false; + current_lexed_text = text; + current_line_text = this->recalculate_current_line(current_lexed_text); - while (this->advance()) - { - if (this->current_char == '\n') comment = false; + while (this->advance()) + { + if (this->current_char == '\n') comment = false; - if (comment) continue; + if (comment) continue; - if (is_in_string(WHITESPACE, current_char)) continue; + if (is_in_string(WHITESPACE, current_char)) continue; - else if (is_in_string(LETTERS, current_char)) - { - result.push_back(create_identifier()); - } + else if (is_in_string(LETTERS, current_char)) + { + result.push_back(create_identifier()); + } - else if (is_in_string(DIGITS, current_char)) - { - result.push_back(create_number()); - } + else if (is_in_string(DIGITS, current_char)) + { + result.push_back(create_number()); + } - else if (current_char == '\'') - { - result.push_back(create_string()); - } + else if (current_char == '\'') + { + result.push_back(create_string()); + } - else - switch (current_char) - { - case '/': - if (index + 1 != current_lexed_text.size()) - { - if (current_lexed_text[index + 1] == '/') - { - comment = true; - break; - } - } - result.push_back(Token::make_with_line({TT_Div, loc}, current_line_text)); - break; - case '+': - result.push_back(Token::make_with_line({TT_Plus, loc}, current_line_text)); - break; - case '-': - result.push_back(Token::make_with_line({TT_Minus, loc}, current_line_text)); - break; - case '*': - result.push_back(Token::make_with_line({TT_Mul, loc}, current_line_text)); - break; - case '@': - result.push_back(Token::make_with_line({TT_At, loc}, current_line_text)); - break; - case '=': - result.push_back(Token::make_with_line({TT_Equal, loc}, current_line_text)); - break; - case '>': - result.push_back(Token::make_with_line({TT_GreaterThan, loc}, current_line_text)); - break; - case '<': - result.push_back(Token::make_with_line({TT_LessThan, loc}, current_line_text)); - break; - case '(': - result.push_back(Token::make_with_line({TT_LParen, loc}, current_line_text)); - break; - case ')': - result.push_back(Token::make_with_line({TT_RParen, loc}, current_line_text)); - break; - case '{': - result.push_back(Token::make_with_line({TT_RBracket, loc}, current_line_text)); - break; - case '}': - result.push_back(Token::make_with_line({TT_LBracket, loc}, current_line_text)); - break; - case ';': - result.push_back(Token::make_with_line({TT_Semicolon, loc}, current_line_text)); - break; - case '.': - result.push_back(Token::make_with_line({TT_Period, loc}, current_line_text)); - break; - case ',': - result.push_back(Token::make_with_line({TT_Comma, loc}, current_line_text)); - break; - case '!': - result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); - break; - case '[': - result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); - break; - case ']': - result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); - break; - default: - Error::throw_error(loc, current_line_text, "unknown character"); - } - } + else + switch (current_char) + { + case '/': + if (index + 1 != current_lexed_text.size()) + { + if (current_lexed_text[index + 1] == '/') + { + comment = true; + break; + } + } + result.push_back(Token::make_with_line({TT_Div, loc}, current_line_text)); + break; + case '+': + result.push_back(Token::make_with_line({TT_Plus, loc}, current_line_text)); + break; + case '-': + result.push_back(Token::make_with_line({TT_Minus, loc}, current_line_text)); + break; + case '*': + result.push_back(Token::make_with_line({TT_Mul, loc}, current_line_text)); + break; + case '@': + result.push_back(Token::make_with_line({TT_At, loc}, current_line_text)); + break; + case '=': + result.push_back(Token::make_with_line({TT_Equal, loc}, current_line_text)); + break; + case '>': + result.push_back(Token::make_with_line({TT_GreaterThan, loc}, current_line_text)); + break; + case '<': + result.push_back(Token::make_with_line({TT_LessThan, loc}, current_line_text)); + break; + case '(': + result.push_back(Token::make_with_line({TT_LParen, loc}, current_line_text)); + break; + case ')': + result.push_back(Token::make_with_line({TT_RParen, loc}, current_line_text)); + break; + case '{': + result.push_back(Token::make_with_line({TT_RBracket, loc}, current_line_text)); + break; + case '}': + result.push_back(Token::make_with_line({TT_LBracket, loc}, current_line_text)); + break; + case ';': + result.push_back(Token::make_with_line({TT_Semicolon, loc}, current_line_text)); + break; + case '.': + result.push_back(Token::make_with_line({TT_Period, loc}, current_line_text)); + break; + case ',': + result.push_back(Token::make_with_line({TT_Comma, loc}, current_line_text)); + break; + case '!': + result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); + break; + case '[': + result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); + break; + case ']': + result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); + break; + default: + Error::throw_error(loc, current_line_text, "unknown character"); + } + } - result.push_back(Token(TT_EOF, loc)); + result.push_back(Token(TT_EOF, loc)); - return result; + return result; } Token Lexer::create_identifier() { - std::vector characters; - int prev_line = loc.line; - int prev_column = loc.column; - bool is_path = false; - bool last_was_path = false; - Location saved_loc = this->loc; - Location saved_prev_loc = this->prev_loc; + std::vector characters; + int prev_line = loc.line; + int prev_column = loc.column; + bool is_path = false; + bool last_was_path = false; + Location saved_loc = this->loc; + Location saved_prev_loc = this->prev_loc; - characters.push_back(current_char); + characters.push_back(current_char); - while (this->advance()) - { - if (is_in_string(IDENTIFIERS, current_char)) - { - characters.push_back(current_char); - last_was_path = false; - } - else if (current_char == '/') - { - if (last_was_path) - { - characters.pop_back(); - this->loc = saved_loc; - this->prev_loc = saved_prev_loc; - this->rewind(); - std::string identifier(characters.begin(), characters.end()); - return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, - current_line_text); - } + while (this->advance()) + { + if (is_in_string(IDENTIFIERS, current_char)) + { + characters.push_back(current_char); + last_was_path = false; + } + else if (current_char == '/') + { + if (last_was_path) + { + characters.pop_back(); + this->loc = saved_loc; + this->prev_loc = saved_prev_loc; + this->rewind(); + std::string identifier(characters.begin(), characters.end()); + return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, + current_line_text); + } - saved_loc = this->loc; - saved_prev_loc = this->prev_loc; + saved_loc = this->loc; + saved_prev_loc = this->prev_loc; - characters.push_back(current_char); - is_path = true; - last_was_path = true; - } - else - { - this->rewind(); - std::string identifier(characters.begin(), characters.end()); - if (is_path) - return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, - current_line_text); - auto location = std::find(types.begin(), types.end(), identifier); - if (location != types.end()) - { - return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, - current_line_text); - } - if (identifier == "import") - return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall0") - return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall1") - return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall2") - return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall3") - return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall4") - return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall5") - return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "compmacro") - return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}}, - current_line_text); - return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, - current_line_text); - } - } + characters.push_back(current_char); + is_path = true; + last_was_path = true; + } + else + { + this->rewind(); + std::string identifier(characters.begin(), characters.end()); + if (is_path) + return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, + current_line_text); + auto location = std::find(types.begin(), types.end(), identifier); + if (location != types.end()) + { + return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, + current_line_text); + } + if (identifier == "import") + return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall0") + return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall1") + return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall2") + return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall3") + return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall4") + return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall5") + return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "compmacro") + return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}}, + current_line_text); + return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, + current_line_text); + } + } - std::string identifier(characters.begin(), characters.end()); - if (is_path) - return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); - auto location = std::find(types.begin(), types.end(), identifier); - if (location != types.end()) - { - return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); - } - if (identifier == "import") - return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall0") - return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall1") - return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall2") - return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall3") - return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall4") - return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "syscall5") - return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); - if (identifier == "compmacro") - return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}}, current_line_text); - return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); + std::string identifier(characters.begin(), characters.end()); + if (is_path) + return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); + auto location = std::find(types.begin(), types.end(), identifier); + if (location != types.end()) + { + return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); + } + if (identifier == "import") + return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall0") + return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall1") + return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall2") + return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall3") + return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall4") + return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "syscall5") + return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); + if (identifier == "compmacro") + return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}}, current_line_text); + return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); } Token Lexer::create_number() { - std::vector characters; - int prev_line = loc.line; - int prev_column = loc.column; - int dot_count = 0; + std::vector characters; + int prev_line = loc.line; + int prev_column = loc.column; + int dot_count = 0; - characters.push_back(current_char); + characters.push_back(current_char); - while (this->advance()) - { - if (is_in_string(DIGITS, current_char)) - { - characters.push_back(current_char); - } - else if (current_char == '.') - { - if (dot_count == 0) - { - characters.push_back(current_char); - ++dot_count; - } - else - { - Error::throw_warning(loc, current_line_text, "floats can only have one dot"); - this->rewind(); - float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); - return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, - current_line_text); - } - } - else - { - this->rewind(); - if (dot_count != 0) - { - float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); - return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, - current_line_text); - } - int tk_value = atoi(std::string(characters.begin(), characters.end()).c_str()); - return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); - } - } + while (this->advance()) + { + if (is_in_string(DIGITS, current_char)) + { + characters.push_back(current_char); + } + else if (current_char == '.') + { + if (dot_count == 0) + { + characters.push_back(current_char); + ++dot_count; + } + else + { + Error::throw_warning(loc, current_line_text, "floats can only have one dot"); + this->rewind(); + float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); + return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, + current_line_text); + } + } + else + { + this->rewind(); + if (dot_count != 0) + { + float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); + return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, + current_line_text); + } + int tk_value = atoi(std::string(characters.begin(), characters.end()).c_str()); + return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); + } + } - if (dot_count != 0) - { - float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); - return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); - } - int tk_value = atoi(std::string(characters.begin(), characters.end()).c_str()); - return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); + if (dot_count != 0) + { + float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); + return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); + } + int tk_value = atoi(std::string(characters.begin(), characters.end()).c_str()); + return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text); } Token Lexer::create_string() { - std::vector characters; - int prev_line = loc.line; - int prev_column = loc.column; + std::vector characters; + int prev_line = loc.line; + int prev_column = loc.column; - while (this->advance()) - { - if (current_char == '\n') - { - this->rewind(); - Error::throw_error(loc, current_line_text, "expected end of string but got newline"); - } - if (current_char == '\'') - { - std::string identifier(characters.begin(), characters.end()); - return Token::make_with_line({TT_String, identifier, {prev_line, prev_column, loc.fname}}, - current_line_text); - } - if (current_char == '\\') - { - if (index + 1 == current_lexed_text.size()) - { - Error::throw_error(loc, current_line_text, "unfinished escape sequence"); - } - switch (current_lexed_text[index + 1]) - { - case 'n': - characters.push_back('\n'); - break; - case '\'': - characters.push_back('\''); - break; - case '\\': - characters.push_back('\\'); - break; - default: - Error::throw_error(loc, current_line_text, "unknown escape sequence"); - } - ++index; - ++loc.column; - continue; - } + while (this->advance()) + { + if (current_char == '\n') + { + this->rewind(); + Error::throw_error(loc, current_line_text, "expected end of string but got newline"); + } + if (current_char == '\'') + { + std::string identifier(characters.begin(), characters.end()); + return Token::make_with_line({TT_String, identifier, {prev_line, prev_column, loc.fname}}, + current_line_text); + } + if (current_char == '\\') + { + if (index + 1 == current_lexed_text.size()) + { + Error::throw_error(loc, current_line_text, "unfinished escape sequence"); + } + switch (current_lexed_text[index + 1]) + { + case 'n': + characters.push_back('\n'); + break; + case '\'': + characters.push_back('\''); + break; + case '\\': + characters.push_back('\\'); + break; + default: + Error::throw_error(loc, current_line_text, "unknown escape sequence"); + } + ++index; + ++loc.column; + continue; + } - characters.push_back(current_char); - } - this->rewind(); - Error::throw_error(loc, current_line_text, "expected end of string but got EOF"); + characters.push_back(current_char); + } + this->rewind(); + Error::throw_error(loc, current_line_text, "expected end of string but got EOF"); - return Token(TT_Null, loc); // unreachable since Error::throw_error calls exit() + return Token(TT_Null, loc); // unreachable since Error::throw_error calls exit() } diff --git a/src/Lexer.h b/src/Lexer.h index 44bb0dc..0493cb4 100644 --- a/src/Lexer.h +++ b/src/Lexer.h @@ -1,9 +1,7 @@ #pragma once #include "Token.h" +#include "sapphirepch.h" #include -#include -#include -#include /* Let's redefine TokenStream, as if it wasn't already defined in Token.h*/ typedef std::vector TokenStream; @@ -15,41 +13,41 @@ typedef std::vector TokenStream; class Lexer { private: - Location loc; - Location prev_loc; + Location loc; + Location prev_loc; - int advance(); - int rewind(); - char current_char; - int index; + int advance(); + int rewind(); + char current_char; + int index; - Lexer(const std::string& fname); + Lexer(const std::string& fname); - std::string current_line_text; - std::string previous_line_text; + std::string current_line_text; + std::string previous_line_text; - std::string current_lexed_text; + std::string current_lexed_text; - std::string recalculate_current_line(const std::string& text); + std::string recalculate_current_line(const std::string& text); - Token create_string(); - Token create_number(); - Token create_identifier(); + Token create_string(); + Token create_number(); + Token create_identifier(); - bool is_in_string(const std::string& string, const char& character); + bool is_in_string(const std::string& string, const char& character); public: - /* An array containing Sapphire's current data types. */ - static const std::array types; + /* An array containing Sapphire's current data types. */ + static const std::array types; - ~Lexer(); + ~Lexer(); - /* Lex the given text, turning it into a stream of tokens. */ - TokenStream lex(const std::string& text); + /* Lex the given text, turning it into a stream of tokens. */ + TokenStream lex(const std::string& text); - /* Create a new Lexer and return a pointer to it. */ - static std::shared_ptr make_lexer(const std::string& fname); + /* Create a new Lexer and return a pointer to it. */ + static std::shared_ptr make_lexer(const std::string& fname); - /* If the Lexer is lexing an impòrted file, give it the location in the parent file at which it was imported. */ - static void assign_parent_location(std::shared_ptr& lexer, const std::shared_ptr& loc); + /* If the Lexer is lexing an impòrted file, give it the location in the parent file at which it was imported. */ + static void assign_parent_location(std::shared_ptr& lexer, const std::shared_ptr& loc); }; diff --git a/src/Location.cpp b/src/Location.cpp index ca9bb36..811931f 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -1,5 +1,4 @@ #include "Location.h" -#include "StringConversion.h" #include Location::Location(int ln, int col, std::string file) : line(ln), column(col), fname(file) @@ -10,45 +9,41 @@ Location::~Location() { } -std::string Location::to_string() const +std::string Location::str() const { - std::ostringstream ss; - ss << fname; - ss << ":"; - ss << int_to_string(line); - ss << ":"; - ss << int_to_string(column); - return ss.str(); + std::ostringstream ss; + ss << fname << ":" << line << ":" << column; + return ss.str(); } -std::string Location::to_parenthesized_string() const +std::string Location::paren_str() const { - return "(" + this->to_string() + ")"; + return "(" + this->str() + ")"; } void Location::advance() { - ++column; + ++column; } void Location::pos_from_char(const char& character) { - if (character == '\n') - { - ++line; - column = 0; - } + if (character == '\n') + { + ++line; + column = 0; + } } void Location::operator=(const Location& other) { - this->parent = other.parent; - this->line = other.line; - this->column = other.column; - this->fname.assign(other.fname.c_str()); + this->parent = other.parent; + this->line = other.line; + this->column = other.column; + this->fname = other.fname; } void Location::copy(const Location& other) { - this->operator=(other); + this->operator=(other); } diff --git a/src/Location.h b/src/Location.h index 9e722a6..7ba4589 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,35 +1,34 @@ #pragma once -#include -#include +#include "sapphirepch.h" /* Struct to represent a location in a file. */ struct Location { - int line; - int column; - std::string fname; + int line; + int column; + std::string fname; - /* The location at which this location was imported, for error traces in imported files. */ - std::shared_ptr parent = nullptr; + /* The location at which this location was imported, for error traces in imported files. */ + std::shared_ptr parent = nullptr; - /* Creates a Location with the given parameters. */ - Location(int ln, int col, std::string file); + /* Creates a Location with the given parameters. */ + Location(int ln, int col, std::string file); - ~Location(); + ~Location(); - /* Returns a string of the format FILE:LINE:COL. */ - std::string to_string() const; - /* Returns a string of the format (FILE:LINE:COL). */ - std::string to_parenthesized_string() const; + /* Returns a string of the format FILE:LINE:COL. */ + std::string str() const; + /* Returns a string of the format (FILE:LINE:COL). */ + std::string paren_str() const; - /* Advance to the next column in the file. */ - void advance(); + /* Advance to the next column in the file. */ + void advance(); - /* Advance to the next line if provided a newline. */ - void pos_from_char(const char& character); + /* Advance to the next line if provided a newline. */ + void pos_from_char(const char& character); - void operator=(const Location& other); + void operator=(const Location& other); - /* Copies the other location into this one. */ - void copy(const Location& other); + /* Copies the other location into this one. */ + void copy(const Location& other); }; diff --git a/src/Parser.h b/src/Parser.h index a8c4000..f0cad10 100644 --- a/src/Parser.h +++ b/src/Parser.h @@ -2,72 +2,71 @@ #include "AST/NumberNode.h" #include "Error.h" #include "Lexer.h" -#include -#include +#include "sapphirepch.h" /* Parser class for the Sapphire compiler. */ class Parser { - /* Struct to store a parsing result which can be either a parsing error or a success, in which case it contains a - * pointer to the result. */ - template struct ErrorOr - { - /* Return the stored pointer. */ - std::shared_ptr get() - { - assert(!m_is_error); - return m_ptr; - } + /* Struct to store a parsing result which can be either a parsing error or a success, in which case it contains a + * pointer to the result. */ + template struct ErrorOr + { + /* Return the stored pointer. */ + std::shared_ptr get() + { + assert(!m_is_error); + return m_ptr; + } - /* Call Error::throw_error() with the stored error's location, line text, and the error string provided to this - * struct instance. */ - void ethrow() - { - assert(m_is_error); - Error::throw_error(error_tok->loc, error_tok->line(), m_error); - } + /* Call Error::throw_error() with the stored error's location, line text, and the error string provided to this + * struct instance. */ + void ethrow() + { + assert(m_is_error); + Error::throw_error(error_tok->loc, error_tok->line(), m_error); + } - /* Construct a new successful ErrorOr with a heap-allocated pointer to the result class. */ - ErrorOr(T* ptr) : m_ptr(ptr), m_is_error(false) - { - } - /* Construct a new failed ErrorOr with the error details and the token where parsing failed. */ - ErrorOr(const std::string& error, const Token& error_tok) - : m_error(error), m_is_error(true), error_tok(error_tok) - { - } + /* Construct a new successful ErrorOr with a heap-allocated pointer to the result class. */ + ErrorOr(T* ptr) : m_ptr(ptr), m_is_error(false) + { + } + /* Construct a new failed ErrorOr with the error details and the token where parsing failed. */ + ErrorOr(const std::string& error, const Token& error_tok) + : m_error(error), m_is_error(true), error_tok(error_tok) + { + } - /* Is this ErrorOr instance successful or failed? */ - bool is_error() - { - return m_is_error; - } + /* Is this ErrorOr instance successful or failed? */ + bool is_error() + { + return m_is_error; + } - private: - bool m_is_error; - std::string m_error; - std::shared_ptr error_tok; - std::shared_ptr m_ptr; - }; + private: + bool m_is_error; + std::string m_error; + std::unique_ptr error_tok; + std::shared_ptr m_ptr; + }; private: - Parser(const TokenStream& tokens); - TokenStream tokens; + Parser(const TokenStream& tokens); + TokenStream tokens; - ErrorOr walk_expr(); - ErrorOr walk_number(); + ErrorOr walk_expr(); + ErrorOr walk_number(); - int m_index; - int saved_m_index; + int m_index; + int saved_m_index; - void save_current_position(); - void restore_current_position(); + void save_current_position(); + void restore_current_position(); public: - ~Parser(); + ~Parser(); - /* Construct a new Parser with the given TokenStream. */ - static std::shared_ptr new_parser(const TokenStream& tokens); - /* Parse the stored TokenStream and return the top-level node of the result Abstract Syntax Tree. */ - std::shared_ptr parse(); + /* Construct a new Parser with the given TokenStream. */ + static std::shared_ptr new_parser(const TokenStream& tokens); + /* Parse the stored TokenStream and return the top-level node of the result Abstract Syntax Tree. */ + std::shared_ptr parse(); }; diff --git a/src/StringConversion.cpp b/src/StringConversion.cpp deleted file mode 100644 index 48c3c9f..0000000 --- a/src/StringConversion.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "StringConversion.h" -#include - -std::string int_to_string(const int& value) -{ - char buffer[12]; - std::sprintf(buffer, "%d", value); - return {buffer}; -} - -std::string float_to_string(const float& value) -{ - char buffer[50]; - std::sprintf(buffer, "%f", value); - return {buffer}; -} \ No newline at end of file diff --git a/src/StringConversion.h b/src/StringConversion.h deleted file mode 100644 index 06ce891..0000000 --- a/src/StringConversion.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -/* Easy way of converting an int to a string without writing 5 lines of code every time you want to do it. */ -std::string int_to_string(const int& value); - -/* Easy way of converting a float to a string without writing 5 lines of code every time you want to do it. */ -std::string float_to_string(const float& value); \ No newline at end of file diff --git a/src/Token.cpp b/src/Token.cpp index 8a0b786..430f6bb 100644 --- a/src/Token.cpp +++ b/src/Token.cpp @@ -1,7 +1,6 @@ #include "Token.h" #include "FormatString/FormatString.hpp" -#include "StringConversion.h" -#include "replace.h" +#include "utils.h" const std::string token_strings[] = { "TT_IDENTIFIER", "TT_NUMBER", "TT_FLOAT", "TT_KEYWORD", "TT_STRING", "TT_PLUS", @@ -58,7 +57,7 @@ Token Token::copy_with_new_type(const TokenType& type) std::string Token::to_string() const { - std::string details = loc.to_parenthesized_string(); + std::string details = loc.paren_str(); if (tk_type == TT_Number) { return format_string("INT:%d %s", int_value, details); diff --git a/src/Token.h b/src/Token.h index 89e401e..a9bae23 100644 --- a/src/Token.h +++ b/src/Token.h @@ -1,7 +1,6 @@ #pragma once #include "Location.h" -#include -#include +#include "sapphirepch.h" /* All current token types. Will change in the future. */ enum TokenType diff --git a/src/replace.cpp b/src/replace.cpp deleted file mode 100644 index 3a59b0c..0000000 --- a/src/replace.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "replace.h" - -bool replace(std::string& str, const std::string& from, const std::string& to) -{ - size_t start_pos = str.find(from); - if (start_pos == std::string::npos) return false; - str.replace(start_pos, from.length(), to); - return true; -} \ No newline at end of file diff --git a/src/replace.h b/src/replace.h deleted file mode 100644 index bac4d40..0000000 --- a/src/replace.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include - -/* Simple function to replace a substring in a string. */ -bool replace(std::string& str, const std::string& from, const std::string& to); \ No newline at end of file diff --git a/src/sapphire.cpp b/src/sapphire.cpp index 3a2168a..6e592d8 100644 --- a/src/sapphire.cpp +++ b/src/sapphire.cpp @@ -3,7 +3,7 @@ #include "Importer.h" #include "Lexer.h" #include "Normalizer.h" -#include +#include "sapphirepch.h" int main(int argc, char** argv) { diff --git a/src/sapphirepch.h b/src/sapphirepch.h new file mode 100644 index 0000000..847a6db --- /dev/null +++ b/src/sapphirepch.h @@ -0,0 +1,6 @@ +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..18b5452 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,24 @@ +#include "utils.h" +#include + +bool replace(std::string& str, const std::string& from, const std::string& to) +{ + size_t start_pos = str.find(from); + if (start_pos == std::string::npos) return false; + str.replace(start_pos, from.length(), to); + return true; +} + +std::string to_string(const int& value) +{ + std::ostringstream result; + result << value; + return result.str(); +} + +std::string to_string(const float& value) +{ + std::ostringstream result; + result << value; + return result.str(); +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..c6db02a --- /dev/null +++ b/src/utils.h @@ -0,0 +1,11 @@ +#pragma once +#include "sapphirepch.h" + +/* Simple function to replace a substring in a string. */ +bool replace(std::string& str, const std::string& from, const std::string& to); + +/* Easy way of converting an int to a string without writing 5 lines of code every time you want to do it. */ +std::string to_string(const int& value); + +/* Easy way of converting a float to a string without writing 5 lines of code every time you want to do it. */ +std::string to_string(const float& value); \ No newline at end of file