Add unary expression parsing
Signed-off-by: CHatingPython <chatingpython@gmail.com>
This commit is contained in:
@@ -9,7 +9,8 @@ namespace ast {
|
|||||||
|
|
||||||
enum class expression_node_t {
|
enum class expression_node_t {
|
||||||
Literal,
|
Literal,
|
||||||
Binop
|
Unaryop,
|
||||||
|
Binop,
|
||||||
};
|
};
|
||||||
|
|
||||||
class expression_node : public statement_node {
|
class expression_node : public statement_node {
|
||||||
@@ -25,6 +26,37 @@ protected:
|
|||||||
|
|
||||||
using expression_node_h = node_handle<expression_node>;
|
using expression_node_h = node_handle<expression_node>;
|
||||||
|
|
||||||
|
enum class unaryop_expression_node_t {
|
||||||
|
Positive,
|
||||||
|
Negative,
|
||||||
|
PrefixIncrement,
|
||||||
|
PostfixIncrement,
|
||||||
|
PrefixDecrement,
|
||||||
|
PostfixDecrement,
|
||||||
|
};
|
||||||
|
|
||||||
|
class unaryop_expression_node : public expression_node {
|
||||||
|
public:
|
||||||
|
unaryop_expression_node(unaryop_expression_node_t type, expression_node_h&& node)
|
||||||
|
: m_type(type), m_node(std::move(node)) {}
|
||||||
|
|
||||||
|
void set_node(expression_node_h&& node) { m_node = std::move(node); }
|
||||||
|
|
||||||
|
unaryop_expression_node_t type() const { return m_type; }
|
||||||
|
const expression_node_h& get_node() const { return m_node; }
|
||||||
|
expression_node_h& get_node() { return m_node; }
|
||||||
|
expression_node_h&& move_node() { return std::move(m_node); }
|
||||||
|
public:
|
||||||
|
expression_node_t expression_type() const override { return expression_node_t::Unaryop; }
|
||||||
|
|
||||||
|
std::ostream& print(std::ostream& os) const override;
|
||||||
|
private:
|
||||||
|
unaryop_expression_node_t m_type;
|
||||||
|
expression_node_h m_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
using unaryop_expression_node_h = node_handle<unaryop_expression_node>;
|
||||||
|
|
||||||
enum class binop_expression_node_t {
|
enum class binop_expression_node_t {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
@@ -40,7 +72,11 @@ public:
|
|||||||
|
|
||||||
binop_expression_node_t type() const { return m_type; };
|
binop_expression_node_t type() const { return m_type; };
|
||||||
const expression_node_h& lhs() const { return m_lhs; };
|
const expression_node_h& lhs() const { return m_lhs; };
|
||||||
|
expression_node_h& lhs() { return m_lhs; };
|
||||||
|
expression_node_h&& move_lhs() { return std::move(m_lhs); };
|
||||||
const expression_node_h& rhs() const { return m_rhs; };
|
const expression_node_h& rhs() const { return m_rhs; };
|
||||||
|
expression_node_h& rhs() { return m_rhs; };
|
||||||
|
expression_node_h&& move_rhs() { return std::move(m_rhs); };
|
||||||
public:
|
public:
|
||||||
expression_node_t expression_type() const override { return expression_node_t::Binop; }
|
expression_node_t expression_type() const override { return expression_node_t::Binop; }
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ private:
|
|||||||
ast::literal_node_h parse_literal();
|
ast::literal_node_h parse_literal();
|
||||||
|
|
||||||
ast::expression_node_h parse_expression_primary();
|
ast::expression_node_h parse_expression_primary();
|
||||||
ast::expression_node_h parse_expression_rhs(const ast::expression_node_h& init, std::uint32_t precedence);
|
ast::expression_node_h parse_expression_unary(std::uint32_t precedence);
|
||||||
|
ast::expression_node_h parse_expression_rhs(ast::expression_node_h&& init, std::uint32_t precedence);
|
||||||
|
|
||||||
ast::function_body_h parse_body();
|
ast::function_body_h parse_body();
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ enum class token_t {
|
|||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
Percent,
|
Percent,
|
||||||
|
DPlus,
|
||||||
|
DMinus,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
||||||
@@ -56,6 +58,8 @@ static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
|||||||
case token_t::Star: return os << "'*'";
|
case token_t::Star: return os << "'*'";
|
||||||
case token_t::Slash: return os << "'/'";
|
case token_t::Slash: return os << "'/'";
|
||||||
case token_t::Percent: return os << "'%'";
|
case token_t::Percent: return os << "'%'";
|
||||||
|
case token_t::DPlus: return os << "++";
|
||||||
|
case token_t::DMinus: return os << "--";
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@@ -82,6 +86,8 @@ static inline std::string operator+(const std::string& str, token_t type) {
|
|||||||
case token_t::Star: return str + "'*'";
|
case token_t::Star: return str + "'*'";
|
||||||
case token_t::Slash: return str + "'/'";
|
case token_t::Slash: return str + "'/'";
|
||||||
case token_t::Percent: return str + "'%'";
|
case token_t::Percent: return str + "'%'";
|
||||||
|
case token_t::DPlus: return str + "++";
|
||||||
|
case token_t::DMinus: return str + "--";
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -167,7 +173,9 @@ struct token {
|
|||||||
case token_t::Minus:
|
case token_t::Minus:
|
||||||
case token_t::Star:
|
case token_t::Star:
|
||||||
case token_t::Slash:
|
case token_t::Slash:
|
||||||
case token_t::Percent: return true;
|
case token_t::Percent:
|
||||||
|
case token_t::DPlus:
|
||||||
|
case token_t::DMinus: return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+28
-4
@@ -14,7 +14,7 @@ bool literal_node::equal(const node& rhs) const {
|
|||||||
|
|
||||||
std::ostream& integer_literal_node::print(std::ostream& os) const {
|
std::ostream& integer_literal_node::print(std::ostream& os) const {
|
||||||
if (m_value.has_error()) return os << m_value.error();
|
if (m_value.has_error()) return os << m_value.error();
|
||||||
return os << "integer literal (" << *m_value << ")";
|
return os << *m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool integer_literal_node::equal(const node& rhs) const {
|
bool integer_literal_node::equal(const node& rhs) const {
|
||||||
@@ -23,7 +23,7 @@ bool integer_literal_node::equal(const node& rhs) const {
|
|||||||
|
|
||||||
std::ostream& string_literal_node::print(std::ostream& os) const {
|
std::ostream& string_literal_node::print(std::ostream& os) const {
|
||||||
if (m_value.has_error()) return os << m_value.error();
|
if (m_value.has_error()) return os << m_value.error();
|
||||||
return os << "string literal (" << *m_value << ")";
|
return os << '"' << *m_value << '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_literal_node::equal(const node& rhs) const {
|
bool string_literal_node::equal(const node& rhs) const {
|
||||||
@@ -34,6 +34,30 @@ bool expression_node::equal(const node& rhs) const {
|
|||||||
return expression_type() == reinterpret_cast<const expression_node&>(rhs).expression_type();
|
return expression_type() == reinterpret_cast<const expression_node&>(rhs).expression_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, unaryop_expression_node_t type) {
|
||||||
|
switch (type) {
|
||||||
|
case unaryop_expression_node_t::Positive: return os << "+";
|
||||||
|
case unaryop_expression_node_t::Negative: return os << "-";
|
||||||
|
case unaryop_expression_node_t::PrefixIncrement:
|
||||||
|
case unaryop_expression_node_t::PostfixIncrement: return os << "++";
|
||||||
|
case unaryop_expression_node_t::PrefixDecrement:
|
||||||
|
case unaryop_expression_node_t::PostfixDecrement: return os << "--";
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& unaryop_expression_node::print(std::ostream& os) const {
|
||||||
|
switch (m_type) {
|
||||||
|
case unaryop_expression_node_t::Positive:
|
||||||
|
case unaryop_expression_node_t::Negative:
|
||||||
|
case unaryop_expression_node_t::PrefixIncrement:
|
||||||
|
case unaryop_expression_node_t::PrefixDecrement: return os << '(' << m_type << *m_node << ')';
|
||||||
|
case unaryop_expression_node_t::PostfixIncrement:
|
||||||
|
case unaryop_expression_node_t::PostfixDecrement: return os << '(' << *m_node << m_type << ')';
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) {
|
std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case binop_expression_node_t::Add: return os << '+';
|
case binop_expression_node_t::Add: return os << '+';
|
||||||
@@ -45,7 +69,7 @@ std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& binop_expression_node::print(std::ostream& os) const {
|
std::ostream& binop_expression_node::print(std::ostream& os) const {
|
||||||
return os << *m_lhs << ' ' << m_type << ' ' << *m_rhs;
|
return os << '(' << *m_lhs << ' ' << m_type << ' ' << *m_rhs << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool binop_expression_node::equal(const node& rhsNode) const {
|
bool binop_expression_node::equal(const node& rhsNode) const {
|
||||||
@@ -87,7 +111,7 @@ bool statement_node::equal(const node& rhs) const {
|
|||||||
|
|
||||||
std::ostream& return_statement_node::print(std::ostream& os) const {
|
std::ostream& return_statement_node::print(std::ostream& os) const {
|
||||||
os << "return statement";
|
os << "return statement";
|
||||||
if (m_value.present()) return os << " (" << *m_value << ')';
|
if (m_value.present()) return os << ' ' << *m_value;
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+45
-20
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -45,23 +46,7 @@ token_handle<> lexer::next_token() {
|
|||||||
|
|
||||||
location location = current_location();
|
location location = current_location();
|
||||||
|
|
||||||
char ch = get();
|
switch (get()) {
|
||||||
switch (ch) {
|
|
||||||
case '(': ++m_cursor; return { location, token_t::Lparen };
|
|
||||||
case ')': ++m_cursor; return { location, token_t::Rparen };
|
|
||||||
case '{': ++m_cursor; return { location, token_t::Lbrace };
|
|
||||||
case '}': ++m_cursor; return { location, token_t::Rbrace };
|
|
||||||
case '[': ++m_cursor; return { location, token_t::Lbracket };
|
|
||||||
case ']': ++m_cursor; return { location, token_t::Rbracket };
|
|
||||||
case ';': ++m_cursor; return { location, token_t::Semicolon };
|
|
||||||
case ':': ++m_cursor; return { location, token_t::Colon };
|
|
||||||
case ',': ++m_cursor; return { location, token_t::Comma };
|
|
||||||
case '.': ++m_cursor; return { location, token_t::Dot };
|
|
||||||
case '+': ++m_cursor; return { location, token_t::Plus };
|
|
||||||
case '-': ++m_cursor; return { location, token_t::Minus };
|
|
||||||
case '*': ++m_cursor; return { location, token_t::Star };
|
|
||||||
case '/': ++m_cursor; return { location, token_t::Slash };
|
|
||||||
case '%': ++m_cursor; return { location, token_t::Percent };
|
|
||||||
case '"': {
|
case '"': {
|
||||||
std::size_t begin = ++m_cursor;
|
std::size_t begin = ++m_cursor;
|
||||||
while (m_cursor < m_content.size() && m_content[m_cursor] != '"')
|
while (m_cursor < m_content.size() && m_content[m_cursor] != '"')
|
||||||
@@ -73,7 +58,7 @@ token_handle<> lexer::next_token() {
|
|||||||
}
|
}
|
||||||
case std::char_traits<char>::eof(): return { location, token_t::None };
|
case std::char_traits<char>::eof(): return { location, token_t::None };
|
||||||
default: {
|
default: {
|
||||||
if (std::isdigit(ch) != 0) {
|
if (std::isdigit(get()) != 0) {
|
||||||
integer_token integer = 0;
|
integer_token integer = 0;
|
||||||
integer_token max = std::numeric_limits<integer_token>::max();
|
integer_token max = std::numeric_limits<integer_token>::max();
|
||||||
integer_token upperBound = max / 10;
|
integer_token upperBound = max / 10;
|
||||||
@@ -95,7 +80,7 @@ token_handle<> lexer::next_token() {
|
|||||||
return { location, integer };
|
return { location, integer };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::isalnum(ch) != 0 || ch == '_') {
|
if (std::isalnum(get()) != 0 || get() == '_') {
|
||||||
std::size_t start = m_cursor++;
|
std::size_t start = m_cursor++;
|
||||||
while (std::isalnum(get()) != 0 || get() == '_')
|
while (std::isalnum(get()) != 0 || get() == '_')
|
||||||
next();
|
next();
|
||||||
@@ -111,7 +96,47 @@ token_handle<> lexer::next_token() {
|
|||||||
return { location, token_t::Identifier, value };
|
return { location, token_t::Identifier, value };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { location, "unexpected character '"s.append(m_content.substr(m_cursor, 1)) + "'" };
|
struct compare {
|
||||||
|
bool operator()(const std::string_view& lhs, const std::string_view& rhs) const {
|
||||||
|
if (lhs.size() != rhs.size()) return lhs.size() > rhs.size();
|
||||||
|
return lhs < rhs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string_view, token_t, compare> s_tokens = {
|
||||||
|
{ "(", token_t::Lparen },
|
||||||
|
{ ")", token_t::Rparen },
|
||||||
|
{ "{", token_t::Lbrace },
|
||||||
|
{ "}", token_t::Rbrace },
|
||||||
|
{ "[", token_t::Lbracket },
|
||||||
|
{ "]", token_t::Rbracket },
|
||||||
|
{ ";", token_t::Semicolon },
|
||||||
|
{ ":", token_t::Colon },
|
||||||
|
{ ",", token_t::Comma },
|
||||||
|
{ ".", token_t::Dot },
|
||||||
|
{ "+", token_t::Plus },
|
||||||
|
{ "-", token_t::Minus },
|
||||||
|
{ "*", token_t::Star },
|
||||||
|
{ "/", token_t::Slash },
|
||||||
|
{ "%", token_t::Percent },
|
||||||
|
{ "++", token_t::DPlus },
|
||||||
|
{ "--", token_t::DMinus },
|
||||||
|
};
|
||||||
|
|
||||||
|
token_t type = token_t::None;
|
||||||
|
std::size_t length = 1;
|
||||||
|
while (m_cursor + length <= m_content.size()) {
|
||||||
|
auto it = s_tokens.find(m_content.substr(m_cursor, length));
|
||||||
|
if (it == s_tokens.end()) break;
|
||||||
|
type = it->second;
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
if (type != token_t::None) {
|
||||||
|
m_cursor += length - 1;
|
||||||
|
return { location, type };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { location, "unexpected character '"s.append(m_content.substr(m_cursor, length)) + "'" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+117
-41
@@ -29,7 +29,7 @@ parser::parser(std::string_view filename)
|
|||||||
ast::program_node_h parser::parse() & {
|
ast::program_node_h parser::parse() & {
|
||||||
auto program = m_arena.allocate_shared<ast::program_node>();
|
auto program = m_arena.allocate_shared<ast::program_node>();
|
||||||
|
|
||||||
while (peek_token()->type != token_t::None && !m_lexer.empty()) {
|
while (peek_token().present() && peek_token()->type != token_t::None && !m_lexer.empty()) {
|
||||||
program->push(std::move(parse_declaration()));
|
program->push(std::move(parse_declaration()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ ast::statement_node_h parser::parse_statement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast::expression_node_h parser::parse_expression() {
|
ast::expression_node_h parser::parse_expression() {
|
||||||
return parse_expression_rhs(parse_expression_primary(), 16);
|
return parse_expression_rhs(parse_expression_unary(16), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::literal_node_h parser::parse_literal() {
|
ast::literal_node_h parser::parse_literal() {
|
||||||
@@ -143,25 +143,6 @@ ast::literal_node_h parser::parse_literal() {
|
|||||||
return { tok.location(), "unexpected token "s + tok->type + ", expected literal" };
|
return { tok.location(), "unexpected token "s + tok->type + ", expected literal" };
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class binop_associativity {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct binop_info {
|
|
||||||
ast::binop_expression_node_t type;
|
|
||||||
std::uint32_t precedence;
|
|
||||||
binop_associativity associativity;
|
|
||||||
|
|
||||||
static binop_info left(ast::binop_expression_node_t type, std::uint32_t precedence) {
|
|
||||||
return { type, precedence, binop_associativity::Left };
|
|
||||||
}
|
|
||||||
|
|
||||||
static binop_info right(ast::binop_expression_node_t type, std::uint32_t precedence) {
|
|
||||||
return { type, precedence, binop_associativity::Right };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ast::expression_node_h parser::parse_expression_primary() {
|
ast::expression_node_h parser::parse_expression_primary() {
|
||||||
const auto& tok = peek_token();
|
const auto& tok = peek_token();
|
||||||
|
|
||||||
@@ -170,35 +151,130 @@ ast::expression_node_h parser::parse_expression_primary() {
|
|||||||
return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" };
|
return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" };
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::expression_node_h parser::parse_expression_rhs(const ast::expression_node_h& init, std::uint32_t precedence) {
|
struct unaryop_info {
|
||||||
static std::unordered_map<token_t, binop_info> s_binops = {
|
ast::unaryop_expression_node_t type;
|
||||||
{ token_t::Plus, binop_info::left(ast::binop_expression_node_t::Add, 5) },
|
std::uint32_t precedence;
|
||||||
{ token_t::Minus, binop_info::left(ast::binop_expression_node_t::Sub, 5) },
|
};
|
||||||
{ token_t::Star, binop_info::left(ast::binop_expression_node_t::Mul, 4) },
|
|
||||||
{ token_t::Slash, binop_info::left(ast::binop_expression_node_t::Div, 4) },
|
ast::expression_node_h parser::parse_expression_unary(std::uint32_t precedence) {
|
||||||
{ token_t::Percent, binop_info::left(ast::binop_expression_node_t::Mod, 5) },
|
static std::unordered_map<token_t, unaryop_info> s_prefixes = {
|
||||||
|
{ token_t::Plus, unaryop_info{ ast::unaryop_expression_node_t::Positive, 3 } },
|
||||||
|
{ token_t::Minus, unaryop_info{ ast::unaryop_expression_node_t::Negative, 3 } },
|
||||||
|
{ token_t::DPlus, unaryop_info{ ast::unaryop_expression_node_t::PrefixIncrement, 2 } },
|
||||||
|
{ token_t::DMinus, unaryop_info{ ast::unaryop_expression_node_t::PrefixDecrement, 2 } },
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::expression_node_h lhs = init;
|
ast::unaryop_expression_node_h result;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto it = s_binops.find(peek_token()->type);
|
auto it = s_prefixes.find(peek_token()->type);
|
||||||
if (it == s_binops.end()) return lhs;
|
if (it == s_prefixes.end()) break;
|
||||||
binop_info current = it->second;
|
auto current = it->second;
|
||||||
|
if (current.precedence >= precedence) break;
|
||||||
|
auto token = next_token();
|
||||||
|
|
||||||
|
ast::expression_node_h expression;
|
||||||
|
|
||||||
|
auto nextIt = s_prefixes.find(peek_token()->type);
|
||||||
|
if (nextIt != s_prefixes.end()) {
|
||||||
|
auto next = nextIt->second;
|
||||||
|
expression = parse_expression_unary(current.precedence + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = { token.location(), m_arena, current.type, std::move(expression) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.present()) return parse_expression_primary();
|
||||||
|
if (!result->get_node().present()) result->set_node(parse_expression_primary());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class associativity {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class rhsop_info_t {
|
||||||
|
Unaryop,
|
||||||
|
Binop,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rhsop_info {
|
||||||
|
rhsop_info_t type;
|
||||||
|
std::uint32_t precedence;
|
||||||
|
associativity associativity;
|
||||||
|
union {
|
||||||
|
ast::unaryop_expression_node_t unary;
|
||||||
|
ast::binop_expression_node_t binary;
|
||||||
|
};
|
||||||
|
|
||||||
|
static rhsop_info create(ast::unaryop_expression_node_t type, std::uint32_t precedence) {
|
||||||
|
rhsop_info info{};
|
||||||
|
info.type = rhsop_info_t::Unaryop;
|
||||||
|
info.precedence = precedence;
|
||||||
|
info.associativity = associativity::Left;
|
||||||
|
info.unary = type;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rhsop_info create(ast::binop_expression_node_t type,
|
||||||
|
std::uint32_t precedence,
|
||||||
|
enum associativity associativity) {
|
||||||
|
rhsop_info info{};
|
||||||
|
info.type = rhsop_info_t::Binop;
|
||||||
|
info.precedence = precedence;
|
||||||
|
info.associativity = associativity;
|
||||||
|
info.binary = type;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& init, std::uint32_t precedence) {
|
||||||
|
static std::unordered_map<token_t, rhsop_info> s_rhsops = {
|
||||||
|
{ token_t::Plus, rhsop_info::create(ast::binop_expression_node_t::Add, 5, associativity::Left) },
|
||||||
|
{ token_t::Minus, rhsop_info::create(ast::binop_expression_node_t::Sub, 5, associativity::Left) },
|
||||||
|
{ token_t::Star, rhsop_info::create(ast::binop_expression_node_t::Mul, 4, associativity::Left) },
|
||||||
|
{ token_t::Slash, rhsop_info::create(ast::binop_expression_node_t::Div, 4, associativity::Left) },
|
||||||
|
{ token_t::Percent, rhsop_info::create(ast::binop_expression_node_t::Mod, 5, associativity::Left) },
|
||||||
|
{ token_t::DPlus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixIncrement, 1) },
|
||||||
|
{ token_t::DMinus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixDecrement, 1) },
|
||||||
|
};
|
||||||
|
|
||||||
|
ast::expression_node_h lhs = std::move(init);
|
||||||
|
while (peek_token().present()) {
|
||||||
|
auto it = s_rhsops.find(peek_token()->type);
|
||||||
|
if (it == s_rhsops.end()) return lhs;
|
||||||
|
|
||||||
|
rhsop_info current = it->second;
|
||||||
if (current.precedence >= precedence) return lhs;
|
if (current.precedence >= precedence) return lhs;
|
||||||
auto opToken = next_token();
|
auto opToken = next_token();
|
||||||
|
|
||||||
auto rhs = parse_expression_primary();
|
ast::expression_node_h rhs;
|
||||||
|
if (current.type == rhsop_info_t::Binop) {
|
||||||
auto nextIt = s_binops.find(peek_token()->type);
|
rhs = parse_expression_unary(current.precedence + 1); // unary prefix is always right-associative
|
||||||
if (nextIt != s_binops.end()) {
|
|
||||||
binop_info next = nextIt->second;
|
|
||||||
|
|
||||||
rhs = std::move(parse_expression_rhs(rhs,
|
|
||||||
current.precedence + static_cast<std::uint32_t>(current.associativity == binop_associativity::Right)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs = ast::binop_expression_node_h{ opToken.location(), m_arena, current.type, std::move(lhs), std::move(rhs) };
|
auto nextIt = s_rhsops.find(peek_token()->type);
|
||||||
|
if (nextIt != s_rhsops.end()) {
|
||||||
|
rhsop_info next = nextIt->second;
|
||||||
|
|
||||||
|
if (current.type == rhsop_info_t::Binop) {
|
||||||
|
rhs = std::move(parse_expression_rhs(std::move(rhs),
|
||||||
|
current.precedence + static_cast<std::uint32_t>(current.associativity == associativity::Right)));
|
||||||
|
} else {
|
||||||
|
lhs = std::move(parse_expression_rhs(std::move(lhs), current.precedence));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = current.type == rhsop_info_t::Binop
|
||||||
|
? ast::expression_node_h(ast::binop_expression_node_h{ opToken.location(),
|
||||||
|
m_arena,
|
||||||
|
current.binary,
|
||||||
|
std::move(lhs),
|
||||||
|
std::move(rhs) })
|
||||||
|
: ast::expression_node_h(
|
||||||
|
ast::unaryop_expression_node_h{ opToken.location(), m_arena, current.unary, std::move(lhs) });
|
||||||
|
}
|
||||||
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::function_body_h parser::parse_body() {
|
ast::function_body_h parser::parse_body() {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
furc::front::parser parser("<TEMP>", "func main() {\n return 7 + 6 * 10; // 130\n}");
|
furc::front::parser parser("<TEMP>", "func main() {\n return 6 - -7 * 9++;\n}");
|
||||||
std::cout << parser.parse() << '\n';
|
std::cout << parser.parse() << '\n';
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -133,4 +133,51 @@ TEST(Parser, OperatorPrecedence_Complex) {
|
|||||||
EXPECT_INTLIT(div->rhs(), 2);
|
EXPECT_INTLIT(div->rhs(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Parser, UnaryOperator_Simple) {
|
||||||
|
parser parser("<TEMP>", "func main() { return -5; }");
|
||||||
|
auto program = parser.parse();
|
||||||
|
EXPECT_TRUE(program.present());
|
||||||
|
EXPECT_EQ(program->declarations().size(), 1);
|
||||||
|
auto func = program->declarations()[0];
|
||||||
|
EXPECT_TRUE(func.present());
|
||||||
|
EXPECT_EQ(func->declaration_type(), declaration_node_t::FunctionDefinition);
|
||||||
|
function_definition_node_h funcDef = func;
|
||||||
|
EXPECT_EQ(funcDef->name()->string, "main");
|
||||||
|
EXPECT_EQ(funcDef->body()->statements.size(), 1);
|
||||||
|
return_statement_node_h ret = funcDef->body()->statements[0];
|
||||||
|
|
||||||
|
auto retVal = ret->value();
|
||||||
|
EXPECT_TRUE(retVal.present());
|
||||||
|
|
||||||
|
EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop);
|
||||||
|
unaryop_expression_node_h neg = retVal;
|
||||||
|
EXPECT_EQ(neg->type(), unaryop_expression_node_t::Negative);
|
||||||
|
EXPECT_INTLIT(neg->get_node(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Parser, UnaryOperator_PrePost) {
|
||||||
|
parser parser("<TEMP>", "func main() { return --5++; }");
|
||||||
|
auto program = parser.parse();
|
||||||
|
EXPECT_TRUE(program.present());
|
||||||
|
EXPECT_EQ(program->declarations().size(), 1);
|
||||||
|
auto func = program->declarations()[0];
|
||||||
|
EXPECT_TRUE(func.present());
|
||||||
|
EXPECT_EQ(func->declaration_type(), declaration_node_t::FunctionDefinition);
|
||||||
|
function_definition_node_h funcDef = func;
|
||||||
|
EXPECT_EQ(funcDef->name()->string, "main");
|
||||||
|
EXPECT_EQ(funcDef->body()->statements.size(), 1);
|
||||||
|
return_statement_node_h ret = funcDef->body()->statements[0];
|
||||||
|
|
||||||
|
auto retVal = ret->value();
|
||||||
|
EXPECT_TRUE(retVal.present());
|
||||||
|
|
||||||
|
EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop);
|
||||||
|
unaryop_expression_node_h inc = retVal;
|
||||||
|
EXPECT_EQ(inc->type(), unaryop_expression_node_t::PostfixIncrement);
|
||||||
|
|
||||||
|
EXPECT_EQ(inc->get_node()->expression_type(), expression_node_t::Unaryop);
|
||||||
|
unaryop_expression_node_h dec = inc->get_node();
|
||||||
|
EXPECT_INTLIT(dec->get_node(), 5);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
Reference in New Issue
Block a user