Compare commits
3 Commits
db485af7f6
...
ecdf6944a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
ecdf6944a7
|
|||
|
79b6b9742d
|
|||
|
2d40b9337c
|
@@ -102,6 +102,9 @@ class expr_node : public stmt_node {
|
||||
public:
|
||||
enum expr_type_e {
|
||||
Literal,
|
||||
|
||||
BinaryOp,
|
||||
UnaryOp,
|
||||
};
|
||||
public:
|
||||
category_e category() const override { return ast_node_cat::Expression; }
|
||||
@@ -111,6 +114,59 @@ public:
|
||||
virtual expr_type_e expr_type() const = 0;
|
||||
};
|
||||
|
||||
struct binary_op_expr_node final : public expr_node {
|
||||
enum binary_op_type {
|
||||
Add = 0,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
|
||||
Shl,
|
||||
Shr,
|
||||
BinAnd,
|
||||
BinOr,
|
||||
BinXor,
|
||||
And,
|
||||
Or,
|
||||
|
||||
Equals,
|
||||
NotEquals,
|
||||
LessThan,
|
||||
LessEquals,
|
||||
GreaterThan,
|
||||
GreaterEquals,
|
||||
};
|
||||
|
||||
expr_type_e expr_type() const override { return BinaryOp; }
|
||||
|
||||
expr_node* lhs = nullptr;
|
||||
expr_node* rhs = nullptr;
|
||||
binary_op_type type = Add;
|
||||
};
|
||||
|
||||
struct unary_op_expr_node final : public expr_node {
|
||||
enum unary_op_type {
|
||||
Positive = 0,
|
||||
Negative,
|
||||
PreInc,
|
||||
PreDec,
|
||||
PostInc,
|
||||
PostDec,
|
||||
BinNot,
|
||||
Not,
|
||||
|
||||
Sizeof,
|
||||
Pointerof,
|
||||
Lengthof,
|
||||
};
|
||||
|
||||
expr_type_e expr_type() const override { return UnaryOp; }
|
||||
|
||||
expr_node* lhs = nullptr;
|
||||
unary_op_type type = Positive;
|
||||
};
|
||||
|
||||
class lit_node : public expr_node {
|
||||
public:
|
||||
enum lit_type_e {
|
||||
|
||||
@@ -31,6 +31,10 @@ private:
|
||||
|
||||
ast_type parse_type();
|
||||
comp_stmt_node parse_comp();
|
||||
|
||||
expr_node* parse_expr_primary();
|
||||
expr_node* parse_expr_unary();
|
||||
expr_node* parse_expr_right(expr_node* lhs, std::uint32_t precedence = 15);
|
||||
private:
|
||||
template <typename... Types>
|
||||
token eat_token(Types... types) {
|
||||
|
||||
@@ -31,6 +31,8 @@ struct token {
|
||||
Star, /**< `*` */
|
||||
Slash, /**< `/` */
|
||||
Percent, /**< `%` */
|
||||
DblLT, /**< `<<` */
|
||||
DblGT, /**< `>>` */
|
||||
Ampersand, /**< `&` */
|
||||
Pipe, /**< `|` */
|
||||
Hat, /**< `^` */
|
||||
@@ -39,6 +41,7 @@ struct token {
|
||||
|
||||
DblPlus, /**< `++` */
|
||||
DblMinus, /**< `--` */
|
||||
Tilde, /**< `~` */
|
||||
ExMark, /**< `!` */
|
||||
CatEars, /**< `^^` */
|
||||
|
||||
@@ -90,6 +93,7 @@ struct token {
|
||||
// Errors:
|
||||
UnexpectedCharacter,
|
||||
UnexpectedEOF,
|
||||
InvalidInteger,
|
||||
EndOfFile,
|
||||
} type;
|
||||
union value {
|
||||
@@ -144,6 +148,8 @@ struct token {
|
||||
case token::Star: return os << "*";
|
||||
case token::Slash: return os << "/";
|
||||
case token::Percent: return os << "%";
|
||||
case token::DblLT: return os << "<<";
|
||||
case token::DblGT: return os << ">>";
|
||||
case token::Ampersand: return os << "&";
|
||||
case token::Pipe: return os << "|";
|
||||
case token::Hat: return os << "^";
|
||||
@@ -151,6 +157,7 @@ struct token {
|
||||
case token::DblPipe: return os << "||";
|
||||
case token::DblPlus: return os << "++";
|
||||
case token::DblMinus: return os << "--";
|
||||
case token::Tilde: return os << "~";
|
||||
case token::ExMark: return os << "!";
|
||||
case token::CatEars: return os << "^^";
|
||||
case token::Equals: return os << "=";
|
||||
@@ -192,6 +199,7 @@ struct token {
|
||||
case token::U64: return os << "u64";
|
||||
case token::UnexpectedCharacter: return os << "Unexpected character `" << token.value.character << "`";
|
||||
case token::UnexpectedEOF: return os << "Unexpected End Of File";
|
||||
case token::InvalidInteger: return os << "Invalid Integer";
|
||||
case token::EndOfFile: return os << "End Of File";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "furc/front/lexer.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -19,7 +20,28 @@ token lexer::next_token() {
|
||||
|
||||
auto loc = location();
|
||||
|
||||
if (std::isdigit(get()) != 0) {}
|
||||
if (std::isdigit(get()) != 0) {
|
||||
std::uint64_t value = get() - '0';
|
||||
next();
|
||||
while (m_cursor < m_content.size() && std::isdigit(get()) != 0) {
|
||||
static constexpr std::uint64_t MAX = std::numeric_limits<std::uint64_t>::max();
|
||||
static constexpr std::uint64_t MAX_MULTS = MAX / 10;
|
||||
static constexpr std::uint64_t LAST_DIGIT = MAX % 10;
|
||||
|
||||
if (value > MAX_MULTS) {
|
||||
return { location(), token::InvalidInteger };
|
||||
}
|
||||
std::uint64_t digit = get() - '0';
|
||||
if (value == MAX_MULTS && digit > LAST_DIGIT) {
|
||||
return { location(), token::InvalidInteger };
|
||||
}
|
||||
|
||||
value *= 10;
|
||||
value += digit;
|
||||
next();
|
||||
}
|
||||
return { loc, value };
|
||||
}
|
||||
|
||||
if (std::isalnum(get()) != 0 || get() == '_') {
|
||||
static std::unordered_map<std::string_view, token_t> s_keywords = {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace furc {
|
||||
@@ -85,8 +86,7 @@ decl_node* parser::parse_decl() {
|
||||
}
|
||||
|
||||
expr_node* parser::parse_expr() {
|
||||
if (auto* lit = parse_lit(); lit != nullptr) return lit;
|
||||
return nullptr;
|
||||
return parse_expr_right(parse_expr_unary());
|
||||
}
|
||||
|
||||
lit_node* parser::parse_lit() {
|
||||
@@ -130,4 +130,98 @@ comp_stmt_node parser::parse_comp() {
|
||||
return comp;
|
||||
}
|
||||
|
||||
expr_node* parser::parse_expr_primary() {
|
||||
return parse_lit();
|
||||
}
|
||||
|
||||
expr_node* parser::parse_expr_unary() {
|
||||
static std::unordered_map<token_t, unary_op_expr_node::unary_op_type> s_prefixOps = {
|
||||
{ token::Plus, unary_op_expr_node::Positive },
|
||||
{ token::Minus, unary_op_expr_node::Negative },
|
||||
{ token::DblPlus, unary_op_expr_node::PreInc },
|
||||
{ token::DblMinus, unary_op_expr_node::PreDec },
|
||||
{ token::Tilde, unary_op_expr_node::BinNot },
|
||||
{ token::ExMark, unary_op_expr_node::Not },
|
||||
|
||||
{ token::Sizeof, unary_op_expr_node::Sizeof },
|
||||
{ token::Pointerof, unary_op_expr_node::Pointerof },
|
||||
{ token::Lengthof, unary_op_expr_node::Lengthof },
|
||||
};
|
||||
|
||||
static std::unordered_map<token_t, unary_op_expr_node::unary_op_type> s_postfixOps = {
|
||||
{ token::DblPlus, unary_op_expr_node::PostInc },
|
||||
{ token::DblMinus, unary_op_expr_node::PostDec },
|
||||
};
|
||||
|
||||
auto it = s_prefixOps.find(m_lexer.peek_token().type);
|
||||
if (it == s_prefixOps.end()) {
|
||||
auto* expr = parse_expr_primary();
|
||||
while (true) {
|
||||
auto postIt = s_postfixOps.find(m_lexer.peek_token().type);
|
||||
if (postIt == s_postfixOps.end()) return expr;
|
||||
m_lexer.next_token();
|
||||
|
||||
unary_op_expr_node unary;
|
||||
unary.lhs = expr;
|
||||
unary.type = postIt->second;
|
||||
expr = m_arena->allocate<unary_op_expr_node>(std::move(unary));
|
||||
}
|
||||
}
|
||||
|
||||
auto token = m_lexer.next_token();
|
||||
|
||||
unary_op_expr_node unary;
|
||||
unary.lhs = parse_expr_unary();
|
||||
unary.type = it->second;
|
||||
return m_arena->allocate<unary_op_expr_node>(std::move(unary));
|
||||
}
|
||||
|
||||
expr_node* parser::parse_expr_right(expr_node* lhs, std::uint32_t precedence) {
|
||||
struct op_info {
|
||||
binary_op_expr_node::binary_op_type type;
|
||||
std::uint32_t precedence;
|
||||
bool right = false;
|
||||
};
|
||||
|
||||
static std::unordered_map<token_t, op_info> s_ops = {
|
||||
{ token::Plus, { binary_op_expr_node::Add, 4 } },
|
||||
{ token::Minus, { binary_op_expr_node::Sub, 4 } },
|
||||
{ token::Star, { binary_op_expr_node::Mul, 3 } },
|
||||
{ token::Slash, { binary_op_expr_node::Div, 3 } },
|
||||
{ token::Percent, { binary_op_expr_node::Mod, 3 } },
|
||||
{ token::DblLT, { binary_op_expr_node::Shl, 5 } },
|
||||
{ token::DblGT, { binary_op_expr_node::Shr, 5 } },
|
||||
{ token::Ampersand, { binary_op_expr_node::BinAnd, 8 } },
|
||||
{ token::Pipe, { binary_op_expr_node::BinOr, 10 } },
|
||||
{ token::Hat, { binary_op_expr_node::BinXor, 9 } },
|
||||
{ token::DblAmpersand, { binary_op_expr_node::And, 11 } },
|
||||
{ token::DblPipe, { binary_op_expr_node::Or, 12 } },
|
||||
{ token::DblEquals, { binary_op_expr_node::Equals, 7 } },
|
||||
{ token::ExEquals, { binary_op_expr_node::NotEquals, 7 } },
|
||||
{ token::LessThan, { binary_op_expr_node::LessThan, 6 } },
|
||||
{ token::LessEquals, { binary_op_expr_node::LessEquals, 6 } },
|
||||
{ token::GreaterThan, { binary_op_expr_node::GreaterThan, 6 } },
|
||||
{ token::GreaterEquals, { binary_op_expr_node::GreaterEquals, 6 } },
|
||||
};
|
||||
|
||||
while (true) {
|
||||
auto it = s_ops.find(m_lexer.peek_token().type);
|
||||
if (it == s_ops.end() || it->second.precedence >= precedence) return lhs;
|
||||
auto op = it->second;
|
||||
m_lexer.next_token();
|
||||
|
||||
expr_node* rhs = parse_expr_unary();
|
||||
auto nextIt = s_ops.find(m_lexer.peek_token().type);
|
||||
if (nextIt != s_ops.end()) {
|
||||
rhs = parse_expr_right(rhs, op.precedence + (op.right ? 1 : 0));
|
||||
}
|
||||
|
||||
binary_op_expr_node binary;
|
||||
binary.lhs = lhs;
|
||||
binary.rhs = rhs;
|
||||
binary.type = op.type;
|
||||
lhs = m_arena->allocate<binary_op_expr_node>(std::move(binary));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace furc
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
int main(void) {
|
||||
furlang::arena arena;
|
||||
|
||||
furc::lexer lexer = { "<AK>", "func main(argc: u64) -> s32 { x: s32 = '\\\\'; }" };
|
||||
furc::lexer lexer = { "<AK>", "func main(argc: u64) -> s32 { x: s32 = 10 + 67 - 6 * 7; }" };
|
||||
furc::parser parser = { std::move(lexer), arena };
|
||||
|
||||
auto program = parser.parse();
|
||||
|
||||
Reference in New Issue
Block a user