Precompiled Header :)
This commit is contained in:
parent
4f6a1235a0
commit
8b1bb00d75
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1 +1,9 @@
|
|||||||
#include "NumberNode.h"
|
#include "NumberNode.h"
|
||||||
|
|
||||||
|
NumberNode::NumberNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberNode::~NumberNode()
|
||||||
|
{
|
||||||
|
}
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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 << "^";
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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";
|
||||||
|
619
src/Lexer.cpp
619
src/Lexer.cpp
@ -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()
|
||||||
}
|
}
|
||||||
|
52
src/Lexer.h
52
src/Lexer.h
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
103
src/Parser.h
103
src/Parser.h
@ -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();
|
||||||
};
|
};
|
||||||
|
@ -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};
|
|
||||||
}
|
|
@ -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);
|
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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);
|
|
@ -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
6
src/sapphirepch.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
24
src/utils.cpp
Normal file
24
src/utils.cpp
Normal 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
11
src/utils.h
Normal 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);
|
Loading…
Reference in New Issue
Block a user