Compare commits
3 Commits
466d7f003b
...
03448d865e
| Author | SHA1 | Date | |
|---|---|---|---|
|
03448d865e
|
|||
|
cb845ca625
|
|||
|
798287ef47
|
@@ -1,6 +1,5 @@
|
|||||||
file(GLOB_RECURSE FURAS_SRCS "src/**.cpp")
|
file(GLOB_RECURSE FURAS_SRCS "src/**.cpp")
|
||||||
file(GLOB_RECURSE FURAS_HDRS "include/**.hpp")
|
file(GLOB_RECURSE FURAS_HDRS "include/**.hpp")
|
||||||
add_executable(furas ${FURAS_SRCS} ${FURAS_HDRS})
|
add_executable(furas ${FURAS_SRCS} ${FURAS_HDRS})
|
||||||
target_include_directories(furas PRIVATE include/)
|
target_include_directories(furas PUBLIC include/)
|
||||||
set_target_properties(furas PROPERTIES PREFIX "")
|
|
||||||
target_link_libraries(furas PRIVATE furlang libfurvm)
|
target_link_libraries(furas PRIVATE furlang libfurvm)
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef FURAS_LEXER_HPP
|
||||||
|
#define FURAS_LEXER_HPP
|
||||||
|
|
||||||
|
#include "furas/token.hpp"
|
||||||
|
#include "furlang/result.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace furas {
|
||||||
|
|
||||||
|
struct lexer_location {
|
||||||
|
std::string_view filename;
|
||||||
|
std::size_t row, col;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lexer_error {
|
||||||
|
enum type {
|
||||||
|
EndOfFile = 0,
|
||||||
|
UnknownCharacter,
|
||||||
|
} type;
|
||||||
|
|
||||||
|
lexer_location location;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
using token_r = furlang::result<token, lexer_error>;
|
||||||
|
|
||||||
|
class lexer {
|
||||||
|
public:
|
||||||
|
lexer(std::string_view filename, std::string_view content)
|
||||||
|
: m_filename(filename), m_content(content) {}
|
||||||
|
|
||||||
|
token_r next_token();
|
||||||
|
private:
|
||||||
|
constexpr lexer_location location() const { return { m_filename, m_cursor - m_lineStart, m_column }; }
|
||||||
|
private:
|
||||||
|
std::string_view m_filename;
|
||||||
|
std::string_view m_content;
|
||||||
|
std::size_t m_cursor = 0;
|
||||||
|
std::size_t m_lineStart = 0;
|
||||||
|
std::size_t m_column = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace furas
|
||||||
|
|
||||||
|
#endif // FURAS_LEXER_HPP
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef FURAS_TOKEN_HPP
|
||||||
|
#define FURAS_TOKEN_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace furas {
|
||||||
|
|
||||||
|
struct token {
|
||||||
|
enum type {
|
||||||
|
Identifier = 0, /**< An identifier. */
|
||||||
|
Signed, /**< A signed integer. */
|
||||||
|
Unsigned, /**< An unsigned integer. */
|
||||||
|
|
||||||
|
// Markers
|
||||||
|
Monkey, /**< Constant marker (`@`). */
|
||||||
|
Dolar, /**< Type marker(`$`). */
|
||||||
|
Sha256, /**< Label marker(`#`). */
|
||||||
|
Percent, /**< Variable marker(`%`). The more the better. */
|
||||||
|
|
||||||
|
Dot, /**< . */
|
||||||
|
|
||||||
|
// Keywords
|
||||||
|
Import, /**< `import` keyword for importing functions and types. */
|
||||||
|
Public, /**< `public` access specifier. */
|
||||||
|
Private, /**< `private` access specifier. */
|
||||||
|
|
||||||
|
// Instructions
|
||||||
|
Push,
|
||||||
|
Array,
|
||||||
|
Get,
|
||||||
|
Drop,
|
||||||
|
Dup,
|
||||||
|
Clone,
|
||||||
|
Ref,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
Eq,
|
||||||
|
Neq,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
|
Le,
|
||||||
|
Ge,
|
||||||
|
Ptrof,
|
||||||
|
Sizeof,
|
||||||
|
Lenof,
|
||||||
|
Load,
|
||||||
|
Store,
|
||||||
|
Call,
|
||||||
|
Jump,
|
||||||
|
Jnz,
|
||||||
|
Ret,
|
||||||
|
|
||||||
|
Count
|
||||||
|
} type = Count;
|
||||||
|
union value {
|
||||||
|
std::nullptr_t null = nullptr;
|
||||||
|
std::string_view string;
|
||||||
|
std::int64_t integer;
|
||||||
|
std::uint64_t uint;
|
||||||
|
} value;
|
||||||
|
|
||||||
|
token(enum type type)
|
||||||
|
: type(type) {}
|
||||||
|
|
||||||
|
token(enum type type, std::string_view string)
|
||||||
|
: type(type) {
|
||||||
|
value.string = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
token(std::uint64_t num)
|
||||||
|
: type(Unsigned) {
|
||||||
|
value.uint = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
token(std::int64_t num)
|
||||||
|
: type(Signed) {
|
||||||
|
value.integer = num;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace furas
|
||||||
|
|
||||||
|
#endif // FURAS_TOKEN_HPP
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#include "furas/lexer.hpp"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace furas {
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
token_r lexer::next_token() {
|
||||||
|
while (m_cursor < m_content.size() && std::isspace(m_content[m_cursor]) != 0) {
|
||||||
|
if (m_content[m_cursor] == '\n') {
|
||||||
|
m_lineStart = m_cursor + 1;
|
||||||
|
++m_column;
|
||||||
|
}
|
||||||
|
++m_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add support for single-line comments
|
||||||
|
// TODO: Add support for multi-line comments
|
||||||
|
|
||||||
|
if (m_cursor >= m_content.size()) return token_r{ lexer_error{ lexer_error::EndOfFile, location() } };
|
||||||
|
|
||||||
|
// TODO: Add support for negative integers (I am positive thanks to stasiu :v:)
|
||||||
|
// TODO: Add support for hexadecimal and binary numeric literals
|
||||||
|
if (std::isdigit(m_content[m_cursor]) != 0) {
|
||||||
|
std::uint64_t num = 0;
|
||||||
|
while (m_cursor < m_content.size() && std::isdigit(m_content[m_cursor]) != 0) {
|
||||||
|
num *= 10;
|
||||||
|
num += m_content[m_cursor++] - '0';
|
||||||
|
}
|
||||||
|
return { num };
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unordered_map<std::string_view, enum token::type> s_tokens = {
|
||||||
|
{ "import", token::Import },
|
||||||
|
{ "public", token::Public },
|
||||||
|
{ "private", token::Private },
|
||||||
|
|
||||||
|
{ "push", token::Push },
|
||||||
|
{ "array", token::Array },
|
||||||
|
{ "get", token::Get },
|
||||||
|
{ "drop", token::Drop },
|
||||||
|
{ "dup", token::Dup },
|
||||||
|
{ "clone", token::Clone },
|
||||||
|
{ "ref", token::Ref },
|
||||||
|
{ "add", token::Add },
|
||||||
|
{ "sub", token::Sub },
|
||||||
|
{ "mul", token::Mul },
|
||||||
|
{ "div", token::Div },
|
||||||
|
{ "mod", token::Mod },
|
||||||
|
{ "eq", token::Eq },
|
||||||
|
{ "neq", token::Neq },
|
||||||
|
{ "lt", token::Lt },
|
||||||
|
{ "gt", token::Gt },
|
||||||
|
{ "le", token::Le },
|
||||||
|
{ "ge", token::Ge },
|
||||||
|
{ "ptrof", token::Ptrof },
|
||||||
|
{ "sizeof", token::Sizeof },
|
||||||
|
{ "lenof", token::Lenof },
|
||||||
|
{ "load", token::Load },
|
||||||
|
{ "store", token::Store },
|
||||||
|
{ "call", token::Call },
|
||||||
|
{ "jump", token::Jump },
|
||||||
|
{ "jnz", token::Jnz },
|
||||||
|
{ "ret", token::Ret },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (std::isalnum(m_content[m_cursor]) != 0) {
|
||||||
|
std::size_t begin = m_cursor++;
|
||||||
|
while (m_cursor < m_content.size() && (std::isalnum(m_content[m_cursor]) != 0 || m_content[m_cursor] == '_'))
|
||||||
|
++m_cursor;
|
||||||
|
std::string_view str = m_content.substr(begin, m_cursor - begin);
|
||||||
|
if (auto it = s_tokens.find(str); it != s_tokens.end()) return { it->second };
|
||||||
|
return { token::Identifier, str };
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_content[m_cursor]) {
|
||||||
|
case '@': ++m_cursor; return { token::Monkey };
|
||||||
|
case '$': ++m_cursor; return { token::Dolar };
|
||||||
|
case '#': ++m_cursor; return { token::Sha256 };
|
||||||
|
case '%': ++m_cursor; return { token::Percent };
|
||||||
|
case '.': ++m_cursor; return { token::Dot };
|
||||||
|
default:
|
||||||
|
return token_r{
|
||||||
|
lexer_error{ lexer_error::UnknownCharacter, location(), "Unknown character '"s + m_content[m_cursor] + "'" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace furas
|
||||||
+13
-2
@@ -1,7 +1,18 @@
|
|||||||
|
#include "furas/lexer.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) { // NOLINT
|
||||||
std::cout << "Hello, Stasiu!\n";
|
std::string source = "%uwu 10 public private int le";
|
||||||
|
furas::lexer lexer("<NONE>", source);
|
||||||
|
while (true) {
|
||||||
|
furas::token_r token = lexer.next_token();
|
||||||
|
if (token.has_error()) {
|
||||||
|
std::cout << token.error().message << '\n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::cout << token->type << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,11 +143,7 @@ void furvm_generator::generate_instruction(furvm::mod& mod,
|
|||||||
generate_jump(mod, ctx, branch.else_block(), false);
|
generate_jump(mod, ctx, branch.else_block(), false);
|
||||||
} break;
|
} break;
|
||||||
case furlang::ir::instruction_t::Return: {
|
case furlang::ir::instruction_t::Return: {
|
||||||
if (instr.sources().empty()) {
|
mod.bytecode().push_back(static_cast<furvm::byte>(furvm::instruction_t::Return));
|
||||||
mod.bytecode().push_back(static_cast<furvm::byte>(furvm::instruction_t::Return));
|
|
||||||
} else {
|
|
||||||
mod.bytecode().push_back(static_cast<furvm::byte>(furvm::instruction_t::ReturnValue));
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case furlang::ir::instruction_t::Call: {
|
case furlang::ir::instruction_t::Call: {
|
||||||
const auto& call = dynamic_cast<const furlang::ir::call_instruction&>(instr);
|
const auto& call = dynamic_cast<const furlang::ir::call_instruction&>(instr);
|
||||||
|
|||||||
@@ -170,11 +170,6 @@ enum class instruction_t : byte {
|
|||||||
* @brief Pops the current call frame.
|
* @brief Pops the current call frame.
|
||||||
*/
|
*/
|
||||||
Return,
|
Return,
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Pops the current call frame and pushes the first element from the previous stack onto the new stack.
|
|
||||||
*/
|
|
||||||
ReturnValue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct instruction {
|
struct instruction {
|
||||||
|
|||||||
@@ -297,11 +297,6 @@ void executor::step() {
|
|||||||
pop_frame();
|
pop_frame();
|
||||||
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
if (m_frames.empty()) m_flags = m_flags | executor_flags::Done;
|
||||||
} break;
|
} break;
|
||||||
case instruction_t::ReturnValue: {
|
|
||||||
auto value = pop_thing();
|
|
||||||
pop_frame();
|
|
||||||
push_thing(std::move(value));
|
|
||||||
} break;
|
|
||||||
case instruction_t::PushConstant: throw std::runtime_error("unimplemented");
|
case instruction_t::PushConstant: throw std::runtime_error("unimplemented");
|
||||||
default: throw std::runtime_error("unknown instruction");
|
default: throw std::runtime_error("unknown instruction");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user