Precompiled Header :)

This commit is contained in:
apio 2022-06-16 15:56:10 +02:00
parent 4f6a1235a0
commit 8b1bb00d75
24 changed files with 512 additions and 528 deletions

View File

@ -23,8 +23,6 @@ add_executable(
src/Location.cpp src/Location.cpp
src/Error.h src/Error.h
src/Error.cpp src/Error.cpp
src/StringConversion.h
src/StringConversion.cpp
src/FormatString/FormatString.hpp src/FormatString/FormatString.hpp
src/FileIO.h src/FileIO.h
src/FileIO.cpp src/FileIO.cpp
@ -42,21 +40,24 @@ add_executable(
src/AST/ExprNode.h src/AST/ExprNode.h
src/AST/MulNode.cpp src/AST/MulNode.cpp
src/AST/MulNode.h src/AST/MulNode.h
src/AST/NumberNode.cpp
src/AST/NumberNode.h
src/AST/StatementNode.cpp src/AST/StatementNode.cpp
src/AST/StatementNode.h src/AST/StatementNode.h
src/AST/NumberNode.cpp
src/AST/NumberNode.h
src/AST/SumNode.cpp src/AST/SumNode.cpp
src/AST/SumNode.h src/AST/SumNode.h
src/replace.cpp src/utils.cpp
src/replace.h src/utils.h
src/Parser.cpp src/Parser.cpp
src/Parser.h src/Parser.h
src/sapphirepch.h
) )
target_include_directories(sapphirec PUBLIC src) target_include_directories(sapphirec PUBLIC src)
target_include_directories(sapphirec PUBLIC src/tclap-1.2.5/include) 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) llvm_map_components_to_libnames(llvm_libs support core irreader)
# Link against LLVM libraries # Link against LLVM libraries

View File

@ -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);
} let @sys_exit (i32 code) in {
syscall1(60,code);
@sys_exit (i32 code) {
syscall1(60,code);
}
} }

View File

@ -1 +1,9 @@
#include "NumberNode.h" #include "NumberNode.h"
NumberNode::NumberNode()
{
}
NumberNode::~NumberNode()
{
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "sapphirepch.h"
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
#include <string>
struct Arguments struct Arguments
{ {

View File

@ -1,25 +1,15 @@
#include "Error.h" #include "Error.h"
#include "Importer.h" #include "Importer.h"
#include "StringConversion.h" #include "utils.h"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
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) void Error::show_import_line(const Location& loc, std::ostream& output_stream)
{ {
output_stream << "in file included from "; output_stream << "in file included from ";
output_stream << "\033[1;1m"; output_stream << "\033[1;1m";
output_stream << loc.to_string(); output_stream << loc.str();
output_stream << ": "; 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); 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 << "\033[1;1m";
std::cerr << loc.to_string(); std::cerr << loc.str();
std::cerr << ": "; 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 << std::endl;
std::cerr << linestr; std::cerr << linestr;
std::cerr << get_spaces(4); std::cerr << std::string(4, ' ');
std::cerr << line_text; std::cerr << line_text;
std::cerr << std::endl; 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 << "\033[31;49m";
std::cerr << "^"; 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); 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 << "\033[1;1m";
std::cout << loc.to_string(); std::cout << loc.str();
std::cout << ": "; 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 << std::endl;
std::cout << linestr; std::cout << linestr;
std::cout << get_spaces(4); std::cout << std::string(4, ' ');
std::cout << line_text; std::cout << line_text;
std::cout << std::endl; 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 << "\033[33;49m";
std::cout << "^"; std::cout << "^";

View File

@ -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&), void show_import_lines(const Location& loc, void (*import_line_printer)(const Location&, std::ostream&),
std::ostream& stream); std::ostream& stream);
std::string get_spaces(const int& num);
} // namespace Error } // namespace Error

View File

@ -1,10 +1,10 @@
#include "FileIO.h" #include "FileIO.h"
#include "Error.h" #include "Error.h"
#include "sapphirepch.h"
#include <cstring> #include <cstring>
#include <errno.h> #include <errno.h>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <vector>
std::string FileIO::read_all(const std::string& filename) 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) catch (const std::exception& e)
{ {
Error::throw_error_without_location("unable to open file " + filename + ": " + strerror(errno)); Error::throw_error_without_location("unable to open file " + filename + ": " + strerror(errno));
return "";
} }
file.exceptions(std::ios::goodbit); file.exceptions(std::ios::goodbit);
std::vector<char> file_chars; std::vector<char> file_chars;

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <string> #include "sapphirepch.h"
/* Namespace for simple file operations. */ /* Namespace for simple file operations. */
namespace FileIO namespace FileIO

View File

@ -2,9 +2,8 @@
#include "Arguments.h" #include "Arguments.h"
#include "Error.h" #include "Error.h"
#include "FileIO.h" #include "FileIO.h"
#include <algorithm> #include "sapphirepch.h"
#include <fstream> #include <fstream>
#include <iostream>
#define MAX_IMPORTS 100 #define MAX_IMPORTS 100
int Importer::import_count = 0; int Importer::import_count = 0;
@ -49,6 +48,7 @@ TokenStream Importer::evaluate(const TokenStream& original)
} }
if (import_count > MAX_IMPORTS) if (import_count > MAX_IMPORTS)
Error::throw_error(current_token.loc, current_token.line(), "maximum import depth exceeded"); Error::throw_error(current_token.loc, current_token.line(), "maximum import depth exceeded");
std::string input_file_name = next_token.string_value + ".sp"; std::string input_file_name = next_token.string_value + ".sp";

View File

@ -1,6 +1,5 @@
#include "Lexer.h" #include "Lexer.h"
#include "Error.h" #include "Error.h"
#include <algorithm>
#define WHITESPACE "\t \n" #define WHITESPACE "\t \n"
#define LETTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ_" #define LETTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ_"
@ -20,369 +19,369 @@ Lexer::~Lexer()
int Lexer::advance() int Lexer::advance()
{ {
prev_loc = loc; prev_loc = loc;
++index; ++index;
loc.advance(); loc.advance();
if (index >= current_lexed_text.size()) return 0; if (index >= current_lexed_text.size()) return 0;
current_char = current_lexed_text[index]; current_char = current_lexed_text[index];
loc.pos_from_char(current_char); loc.pos_from_char(current_char);
if (current_char == '\n') if (current_char == '\n')
{ {
previous_line_text = current_line_text; previous_line_text = current_line_text;
current_line_text = this->recalculate_current_line(current_lexed_text); current_line_text = this->recalculate_current_line(current_lexed_text);
} }
return 1; return 1;
} }
int Lexer::rewind() int Lexer::rewind()
{ {
loc = prev_loc; loc = prev_loc;
--index; --index;
if (index == -1) return 0; if (index == -1) return 0;
if (current_char == '\n') if (current_char == '\n')
{ {
current_line_text = previous_line_text; current_line_text = previous_line_text;
} }
current_char = current_lexed_text[index]; current_char = current_lexed_text[index];
return 1; return 1;
} }
std::string Lexer::recalculate_current_line(const std::string& text) std::string Lexer::recalculate_current_line(const std::string& text)
{ {
int idx = index; int idx = index;
std::string final_str; std::string final_str;
++idx; ++idx;
while (idx != text.size() && text[idx] != '\n') while (idx != text.size() && text[idx] != '\n')
{ {
final_str += text[idx]; final_str += text[idx];
++idx; ++idx;
} }
return final_str; return final_str;
} }
std::shared_ptr<Lexer> Lexer::make_lexer(const std::string& fname) std::shared_ptr<Lexer> Lexer::make_lexer(const std::string& fname)
{ {
return std::shared_ptr<Lexer>(new Lexer(fname)); // not using make_shared because the constructor is private return std::shared_ptr<Lexer>(new Lexer(fname)); // not using make_shared because the constructor is private
} }
void Lexer::assign_parent_location(std::shared_ptr<Lexer>& lexer, const std::shared_ptr<Location>& loc) void Lexer::assign_parent_location(std::shared_ptr<Lexer>& lexer, const std::shared_ptr<Location>& loc)
{ {
lexer->loc.parent = loc; lexer->loc.parent = loc;
} }
bool Lexer::is_in_string(const std::string& string, const char& character) 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 Lexer::lex(const std::string& text)
{ {
TokenStream result; TokenStream result;
bool comment = false; bool comment = false;
current_lexed_text = text; current_lexed_text = text;
current_line_text = this->recalculate_current_line(current_lexed_text); current_line_text = this->recalculate_current_line(current_lexed_text);
while (this->advance()) while (this->advance())
{ {
if (this->current_char == '\n') comment = false; 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)) else if (is_in_string(LETTERS, current_char))
{ {
result.push_back(create_identifier()); result.push_back(create_identifier());
} }
else if (is_in_string(DIGITS, current_char)) else if (is_in_string(DIGITS, current_char))
{ {
result.push_back(create_number()); result.push_back(create_number());
} }
else if (current_char == '\'') else if (current_char == '\'')
{ {
result.push_back(create_string()); result.push_back(create_string());
} }
else else
switch (current_char) switch (current_char)
{ {
case '/': case '/':
if (index + 1 != current_lexed_text.size()) if (index + 1 != current_lexed_text.size())
{ {
if (current_lexed_text[index + 1] == '/') if (current_lexed_text[index + 1] == '/')
{ {
comment = true; comment = true;
break; break;
} }
} }
result.push_back(Token::make_with_line({TT_Div, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Div, loc}, current_line_text));
break; break;
case '+': case '+':
result.push_back(Token::make_with_line({TT_Plus, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Plus, loc}, current_line_text));
break; break;
case '-': case '-':
result.push_back(Token::make_with_line({TT_Minus, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Minus, loc}, current_line_text));
break; break;
case '*': case '*':
result.push_back(Token::make_with_line({TT_Mul, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Mul, loc}, current_line_text));
break; break;
case '@': case '@':
result.push_back(Token::make_with_line({TT_At, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_At, loc}, current_line_text));
break; break;
case '=': case '=':
result.push_back(Token::make_with_line({TT_Equal, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Equal, loc}, current_line_text));
break; break;
case '>': case '>':
result.push_back(Token::make_with_line({TT_GreaterThan, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_GreaterThan, loc}, current_line_text));
break; break;
case '<': case '<':
result.push_back(Token::make_with_line({TT_LessThan, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_LessThan, loc}, current_line_text));
break; break;
case '(': case '(':
result.push_back(Token::make_with_line({TT_LParen, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_LParen, loc}, current_line_text));
break; break;
case ')': case ')':
result.push_back(Token::make_with_line({TT_RParen, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_RParen, loc}, current_line_text));
break; break;
case '{': case '{':
result.push_back(Token::make_with_line({TT_RBracket, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_RBracket, loc}, current_line_text));
break; break;
case '}': case '}':
result.push_back(Token::make_with_line({TT_LBracket, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_LBracket, loc}, current_line_text));
break; break;
case ';': case ';':
result.push_back(Token::make_with_line({TT_Semicolon, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Semicolon, loc}, current_line_text));
break; break;
case '.': case '.':
result.push_back(Token::make_with_line({TT_Period, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Period, loc}, current_line_text));
break; break;
case ',': case ',':
result.push_back(Token::make_with_line({TT_Comma, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Comma, loc}, current_line_text));
break; break;
case '!': case '!':
result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text));
break; break;
case '[': case '[':
result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text));
break; break;
case ']': case ']':
result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text));
break; break;
default: default:
Error::throw_error(loc, current_line_text, "unknown character"); 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() Token Lexer::create_identifier()
{ {
std::vector<char> characters; std::vector<char> characters;
int prev_line = loc.line; int prev_line = loc.line;
int prev_column = loc.column; int prev_column = loc.column;
bool is_path = false; bool is_path = false;
bool last_was_path = false; bool last_was_path = false;
Location saved_loc = this->loc; Location saved_loc = this->loc;
Location saved_prev_loc = this->prev_loc; Location saved_prev_loc = this->prev_loc;
characters.push_back(current_char); characters.push_back(current_char);
while (this->advance()) while (this->advance())
{ {
if (is_in_string(IDENTIFIERS, current_char)) if (is_in_string(IDENTIFIERS, current_char))
{ {
characters.push_back(current_char); characters.push_back(current_char);
last_was_path = false; last_was_path = false;
} }
else if (current_char == '/') else if (current_char == '/')
{ {
if (last_was_path) if (last_was_path)
{ {
characters.pop_back(); characters.pop_back();
this->loc = saved_loc; this->loc = saved_loc;
this->prev_loc = saved_prev_loc; this->prev_loc = saved_prev_loc;
this->rewind(); this->rewind();
std::string identifier(characters.begin(), characters.end()); std::string identifier(characters.begin(), characters.end());
return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
saved_loc = this->loc; saved_loc = this->loc;
saved_prev_loc = this->prev_loc; saved_prev_loc = this->prev_loc;
characters.push_back(current_char); characters.push_back(current_char);
is_path = true; is_path = true;
last_was_path = true; last_was_path = true;
} }
else else
{ {
this->rewind(); this->rewind();
std::string identifier(characters.begin(), characters.end()); std::string identifier(characters.begin(), characters.end());
if (is_path) if (is_path)
return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
auto location = std::find(types.begin(), types.end(), identifier); auto location = std::find(types.begin(), types.end(), identifier);
if (location != types.end()) if (location != types.end())
{ {
return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
if (identifier == "import") if (identifier == "import")
return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall0") if (identifier == "syscall0")
return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall1") if (identifier == "syscall1")
return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall2") if (identifier == "syscall2")
return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall3") if (identifier == "syscall3")
return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall4") if (identifier == "syscall4")
return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall5") if (identifier == "syscall5")
return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "compmacro") if (identifier == "compmacro")
return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_CompilerMacro, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
} }
std::string identifier(characters.begin(), characters.end()); std::string identifier(characters.begin(), characters.end());
if (is_path) if (is_path)
return Token::make_with_line({TT_Path, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); 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); auto location = std::find(types.begin(), types.end(), identifier);
if (location != types.end()) if (location != types.end())
{ {
return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Type, identifier, {prev_line, prev_column, loc.fname}}, current_line_text);
} }
if (identifier == "import") if (identifier == "import")
return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Import, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall0") if (identifier == "syscall0")
return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall0, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall1") if (identifier == "syscall1")
return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall1, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall2") if (identifier == "syscall2")
return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall2, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall3") if (identifier == "syscall3")
return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall3, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall4") if (identifier == "syscall4")
return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall4, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "syscall5") if (identifier == "syscall5")
return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text); return Token::make_with_line({TT_Syscall5, {prev_line, prev_column, loc.fname}}, current_line_text);
if (identifier == "compmacro") 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_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); return Token::make_with_line({TT_Identifier, identifier, {prev_line, prev_column, loc.fname}}, current_line_text);
} }
Token Lexer::create_number() Token Lexer::create_number()
{ {
std::vector<char> characters; std::vector<char> characters;
int prev_line = loc.line; int prev_line = loc.line;
int prev_column = loc.column; int prev_column = loc.column;
int dot_count = 0; int dot_count = 0;
characters.push_back(current_char); characters.push_back(current_char);
while (this->advance()) while (this->advance())
{ {
if (is_in_string(DIGITS, current_char)) if (is_in_string(DIGITS, current_char))
{ {
characters.push_back(current_char); characters.push_back(current_char);
} }
else if (current_char == '.') else if (current_char == '.')
{ {
if (dot_count == 0) if (dot_count == 0)
{ {
characters.push_back(current_char); characters.push_back(current_char);
++dot_count; ++dot_count;
} }
else else
{ {
Error::throw_warning(loc, current_line_text, "floats can only have one dot"); Error::throw_warning(loc, current_line_text, "floats can only have one dot");
this->rewind(); this->rewind();
float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); 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}}, return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
} }
else else
{ {
this->rewind(); this->rewind();
if (dot_count != 0) if (dot_count != 0)
{ {
float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); 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}}, return Token::make_with_line({TT_Float, tk_value, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
int tk_value = atoi(std::string(characters.begin(), characters.end()).c_str()); 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); return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text);
} }
} }
if (dot_count != 0) if (dot_count != 0)
{ {
float tk_value = std::stof(std::string(characters.begin(), characters.end()).c_str()); 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); 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()); 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); return Token::make_with_line({TT_Number, tk_value, {prev_line, prev_column, loc.fname}}, current_line_text);
} }
Token Lexer::create_string() Token Lexer::create_string()
{ {
std::vector<char> characters; std::vector<char> characters;
int prev_line = loc.line; int prev_line = loc.line;
int prev_column = loc.column; int prev_column = loc.column;
while (this->advance()) while (this->advance())
{ {
if (current_char == '\n') if (current_char == '\n')
{ {
this->rewind(); this->rewind();
Error::throw_error(loc, current_line_text, "expected end of string but got newline"); Error::throw_error(loc, current_line_text, "expected end of string but got newline");
} }
if (current_char == '\'') if (current_char == '\'')
{ {
std::string identifier(characters.begin(), characters.end()); std::string identifier(characters.begin(), characters.end());
return Token::make_with_line({TT_String, identifier, {prev_line, prev_column, loc.fname}}, return Token::make_with_line({TT_String, identifier, {prev_line, prev_column, loc.fname}},
current_line_text); current_line_text);
} }
if (current_char == '\\') if (current_char == '\\')
{ {
if (index + 1 == current_lexed_text.size()) if (index + 1 == current_lexed_text.size())
{ {
Error::throw_error(loc, current_line_text, "unfinished escape sequence"); Error::throw_error(loc, current_line_text, "unfinished escape sequence");
} }
switch (current_lexed_text[index + 1]) switch (current_lexed_text[index + 1])
{ {
case 'n': case 'n':
characters.push_back('\n'); characters.push_back('\n');
break; break;
case '\'': case '\'':
characters.push_back('\''); characters.push_back('\'');
break; break;
case '\\': case '\\':
characters.push_back('\\'); characters.push_back('\\');
break; break;
default: default:
Error::throw_error(loc, current_line_text, "unknown escape sequence"); Error::throw_error(loc, current_line_text, "unknown escape sequence");
} }
++index; ++index;
++loc.column; ++loc.column;
continue; continue;
} }
characters.push_back(current_char); characters.push_back(current_char);
} }
this->rewind(); this->rewind();
Error::throw_error(loc, current_line_text, "expected end of string but got EOF"); 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()
} }

View File

@ -1,9 +1,7 @@
#pragma once #pragma once
#include "Token.h" #include "Token.h"
#include "sapphirepch.h"
#include <array> #include <array>
#include <memory>
#include <string>
#include <vector>
/* Let's redefine TokenStream, as if it wasn't already defined in Token.h*/ /* Let's redefine TokenStream, as if it wasn't already defined in Token.h*/
typedef std::vector<Token> TokenStream; typedef std::vector<Token> TokenStream;
@ -15,41 +13,41 @@ typedef std::vector<Token> TokenStream;
class Lexer class Lexer
{ {
private: private:
Location loc; Location loc;
Location prev_loc; Location prev_loc;
int advance(); int advance();
int rewind(); int rewind();
char current_char; char current_char;
int index; int index;
Lexer(const std::string& fname); Lexer(const std::string& fname);
std::string current_line_text; std::string current_line_text;
std::string previous_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_string();
Token create_number(); Token create_number();
Token create_identifier(); 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: public:
/* An array containing Sapphire's current data types. */ /* An array containing Sapphire's current data types. */
static const std::array<std::string, TYPE_COUNT> types; static const std::array<std::string, TYPE_COUNT> types;
~Lexer(); ~Lexer();
/* Lex the given text, turning it into a stream of tokens. */ /* Lex the given text, turning it into a stream of tokens. */
TokenStream lex(const std::string& text); TokenStream lex(const std::string& text);
/* Create a new Lexer and return a pointer to it. */ /* Create a new Lexer and return a pointer to it. */
static std::shared_ptr<Lexer> make_lexer(const std::string& fname); static std::shared_ptr<Lexer> 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. */ /* 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>& lexer, const std::shared_ptr<Location>& loc); static void assign_parent_location(std::shared_ptr<Lexer>& lexer, const std::shared_ptr<Location>& loc);
}; };

View File

@ -1,5 +1,4 @@
#include "Location.h" #include "Location.h"
#include "StringConversion.h"
#include <sstream> #include <sstream>
Location::Location(int ln, int col, std::string file) : line(ln), column(col), fname(file) 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; std::ostringstream ss;
ss << fname; ss << fname << ":" << line << ":" << column;
ss << ":"; return ss.str();
ss << int_to_string(line);
ss << ":";
ss << int_to_string(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() void Location::advance()
{ {
++column; ++column;
} }
void Location::pos_from_char(const char& character) void Location::pos_from_char(const char& character)
{ {
if (character == '\n') if (character == '\n')
{ {
++line; ++line;
column = 0; column = 0;
} }
} }
void Location::operator=(const Location& other) void Location::operator=(const Location& other)
{ {
this->parent = other.parent; this->parent = other.parent;
this->line = other.line; this->line = other.line;
this->column = other.column; this->column = other.column;
this->fname.assign(other.fname.c_str()); this->fname = other.fname;
} }
void Location::copy(const Location& other) void Location::copy(const Location& other)
{ {
this->operator=(other); this->operator=(other);
} }

View File

@ -1,35 +1,34 @@
#pragma once #pragma once
#include <memory> #include "sapphirepch.h"
#include <string>
/* Struct to represent a location in a file. */ /* Struct to represent a location in a file. */
struct Location struct Location
{ {
int line; int line;
int column; int column;
std::string fname; std::string fname;
/* The location at which this location was imported, for error traces in imported files. */ /* The location at which this location was imported, for error traces in imported files. */
std::shared_ptr<Location> parent = nullptr; std::shared_ptr<Location> parent = nullptr;
/* Creates a Location with the given parameters. */ /* Creates a Location with the given parameters. */
Location(int ln, int col, std::string file); Location(int ln, int col, std::string file);
~Location(); ~Location();
/* Returns a string of the format FILE:LINE:COL. */ /* Returns a string of the format FILE:LINE:COL. */
std::string to_string() const; std::string str() const;
/* Returns a string of the format (FILE:LINE:COL). */ /* Returns a string of the format (FILE:LINE:COL). */
std::string to_parenthesized_string() const; std::string paren_str() const;
/* Advance to the next column in the file. */ /* Advance to the next column in the file. */
void advance(); void advance();
/* Advance to the next line if provided a newline. */ /* Advance to the next line if provided a newline. */
void pos_from_char(const char& character); void pos_from_char(const char& character);
void operator=(const Location& other); void operator=(const Location& other);
/* Copies the other location into this one. */ /* Copies the other location into this one. */
void copy(const Location& other); void copy(const Location& other);
}; };

View File

@ -2,72 +2,71 @@
#include "AST/NumberNode.h" #include "AST/NumberNode.h"
#include "Error.h" #include "Error.h"
#include "Lexer.h" #include "Lexer.h"
#include <cassert> #include "sapphirepch.h"
#include <memory>
/* Parser class for the Sapphire compiler. */ /* Parser class for the Sapphire compiler. */
class Parser class Parser
{ {
/* Struct to store a parsing result which can be either a parsing error or a success, in which case it contains a /* 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. */ * pointer to the result. */
template<typename T> struct ErrorOr template<typename T> struct ErrorOr
{ {
/* Return the stored pointer. */ /* Return the stored pointer. */
std::shared_ptr<T> get() std::shared_ptr<T> get()
{ {
assert(!m_is_error); assert(!m_is_error);
return m_ptr; return m_ptr;
} }
/* Call Error::throw_error() with the stored error's location, line text, and the error string provided to this /* Call Error::throw_error() with the stored error's location, line text, and the error string provided to this
* struct instance. */ * struct instance. */
void ethrow() void ethrow()
{ {
assert(m_is_error); assert(m_is_error);
Error::throw_error(error_tok->loc, error_tok->line(), m_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. */ /* Construct a new successful ErrorOr with a heap-allocated pointer to the result class. */
ErrorOr(T* ptr) : m_ptr(ptr), m_is_error(false) 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. */ /* Construct a new failed ErrorOr with the error details and the token where parsing failed. */
ErrorOr(const std::string& error, const Token& error_tok) ErrorOr(const std::string& error, const Token& error_tok)
: m_error(error), m_is_error(true), error_tok(error_tok) : m_error(error), m_is_error(true), error_tok(error_tok)
{ {
} }
/* Is this ErrorOr instance successful or failed? */ /* Is this ErrorOr instance successful or failed? */
bool is_error() bool is_error()
{ {
return m_is_error; return m_is_error;
} }
private: private:
bool m_is_error; bool m_is_error;
std::string m_error; std::string m_error;
std::shared_ptr<Token> error_tok; std::unique_ptr<Token> error_tok;
std::shared_ptr<T> m_ptr; std::shared_ptr<T> m_ptr;
}; };
private: private:
Parser(const TokenStream& tokens); Parser(const TokenStream& tokens);
TokenStream tokens; TokenStream tokens;
ErrorOr<ExprNode> walk_expr(); ErrorOr<ExprNode> walk_expr();
ErrorOr<NumberNode> walk_number(); ErrorOr<NumberNode> walk_number();
int m_index; int m_index;
int saved_m_index; int saved_m_index;
void save_current_position(); void save_current_position();
void restore_current_position(); void restore_current_position();
public: public:
~Parser(); ~Parser();
/* Construct a new Parser with the given TokenStream. */ /* Construct a new Parser with the given TokenStream. */
static std::shared_ptr<Parser> new_parser(const TokenStream& tokens); static std::shared_ptr<Parser> new_parser(const TokenStream& tokens);
/* Parse the stored TokenStream and return the top-level node of the result Abstract Syntax Tree. */ /* Parse the stored TokenStream and return the top-level node of the result Abstract Syntax Tree. */
std::shared_ptr<ASTNode> parse(); std::shared_ptr<ASTNode> parse();
}; };

View File

@ -1,16 +0,0 @@
#include "StringConversion.h"
#include <cstdio>
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};
}

View File

@ -1,8 +0,0 @@
#pragma once
#include <string>
/* 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);

View File

@ -1,7 +1,6 @@
#include "Token.h" #include "Token.h"
#include "FormatString/FormatString.hpp" #include "FormatString/FormatString.hpp"
#include "StringConversion.h" #include "utils.h"
#include "replace.h"
const std::string token_strings[] = { const std::string token_strings[] = {
"TT_IDENTIFIER", "TT_NUMBER", "TT_FLOAT", "TT_KEYWORD", "TT_STRING", "TT_PLUS", "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 Token::to_string() const
{ {
std::string details = loc.to_parenthesized_string(); std::string details = loc.paren_str();
if (tk_type == TT_Number) if (tk_type == TT_Number)
{ {
return format_string("INT:%d %s", int_value, details); return format_string("INT:%d %s", int_value, details);

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Location.h" #include "Location.h"
#include <string> #include "sapphirepch.h"
#include <vector>
/* All current token types. Will change in the future. */ /* All current token types. Will change in the future. */
enum TokenType enum TokenType

View File

@ -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;
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <string>
/* Simple function to replace a substring in a string. */
bool replace(std::string& str, const std::string& from, const std::string& to);

View File

@ -3,7 +3,7 @@
#include "Importer.h" #include "Importer.h"
#include "Lexer.h" #include "Lexer.h"
#include "Normalizer.h" #include "Normalizer.h"
#include <iostream> #include "sapphirepch.h"
int main(int argc, char** argv) int main(int argc, char** argv)
{ {

6
src/sapphirepch.h Normal file
View File

@ -0,0 +1,6 @@
#include <algorithm>
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

24
src/utils.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "utils.h"
#include <sstream>
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();
}

11
src/utils.h Normal file
View File

@ -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);