forked from KPGPMC/furlang
@@ -235,7 +235,13 @@ using compound_statement_node_p =
|
|||||||
|
|
||||||
using compound_statement_node_r = node_r<compound_statement_node>; /**< Alias for compound_statement_node result */
|
using compound_statement_node_r = node_r<compound_statement_node>; /**< Alias for compound_statement_node result */
|
||||||
|
|
||||||
|
class while_statement_node;
|
||||||
|
|
||||||
|
using while_statement_node_p = node_p<while_statement_node>; /**< Alias for a shared pointer to while_statement_node. */
|
||||||
|
|
||||||
|
using while_statement_node_r = node_r<while_statement_node>; /**< Alias for while_statement_node result */
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_AST_FWD_HPP
|
#endif // FURC_AST_FWD_HPP
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef FURC_AST_STATEMENT_HPP
|
#ifndef FURC_AST_STATEMENT_HPP
|
||||||
#define FURC_AST_STATEMENT_HPP
|
#define FURC_AST_STATEMENT_HPP
|
||||||
|
|
||||||
|
#include "furc/ast/fwd.hpp"
|
||||||
#include "furc/ast/node.hpp"
|
#include "furc/ast/node.hpp"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -17,6 +18,7 @@ enum class statement_node_t {
|
|||||||
Return, /**< Return statement */
|
Return, /**< Return statement */
|
||||||
If, /**< If statement */
|
If, /**< If statement */
|
||||||
Compound, /**< Compound statement */
|
Compound, /**< Compound statement */
|
||||||
|
While, /**< While loop statement. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,7 +193,52 @@ private:
|
|||||||
struct body m_body; /**< The body handle. */
|
struct body m_body; /**< The body handle. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief while statement AST node.
|
||||||
|
*/
|
||||||
|
class while_statement_node final : public statement_node, public abstract_node {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new while statement AST node.
|
||||||
|
*
|
||||||
|
* @param location Node location.
|
||||||
|
* @param body Body handle.
|
||||||
|
*/
|
||||||
|
while_statement_node(struct location location, expression_node_p&& cond, statement_node_p&& body)
|
||||||
|
: abstract_node(location), m_cond(std::move(cond)), m_body(std::move(body)) {}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this node's condition expression.
|
||||||
|
*
|
||||||
|
* @return The condition expression.
|
||||||
|
*/
|
||||||
|
const expression_node_p& condition() const { return m_cond; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this node's body handle.
|
||||||
|
*
|
||||||
|
* @return The body handle.
|
||||||
|
*/
|
||||||
|
const statement_node_p& body() const { return m_body; }
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this node's statement type.
|
||||||
|
*
|
||||||
|
* @return statement_node_t::while.
|
||||||
|
*/
|
||||||
|
statement_node_t statement_type() const override { return statement_node_t::While; }
|
||||||
|
public:
|
||||||
|
void accept(visitor& visitor) const override;
|
||||||
|
|
||||||
|
std::ostream& print(std::ostream& os) const override;
|
||||||
|
protected:
|
||||||
|
bool equal(const node& rhs) const override;
|
||||||
|
private:
|
||||||
|
expression_node_p m_cond; /**< The condition expression. */
|
||||||
|
statement_node_p m_body; /**< The body handle. */
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_AST_STATEMENT_HPP
|
#endif // FURC_AST_STATEMENT_HPP
|
||||||
|
|||||||
@@ -122,6 +122,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void visit(const compound_statement_node& node) {}
|
virtual void visit(const compound_statement_node& node) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Visit a while_statement_node.
|
||||||
|
* @see while_statement_node
|
||||||
|
*
|
||||||
|
* @param node Node.
|
||||||
|
*/
|
||||||
|
virtual void visit(const while_statement_node& node) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Visit an AST error.
|
* @brief Visit an AST error.
|
||||||
*
|
*
|
||||||
@@ -133,4 +141,4 @@ public:
|
|||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_AST_VISITOR_HPP
|
#endif // FURC_AST_VISITOR_HPP
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
void visit(const ast::function_definition_node& funcDef) override;
|
void visit(const ast::function_definition_node& funcDef) override;
|
||||||
void visit(const ast::return_statement_node& returnStmt) override;
|
void visit(const ast::return_statement_node& returnStmt) override;
|
||||||
void visit(const ast::if_statement_node& node) override;
|
void visit(const ast::if_statement_node& node) override;
|
||||||
|
void visit(const ast::while_statement_node& node) override;
|
||||||
void visit(const ast::compound_statement_node& node) override;
|
void visit(const ast::compound_statement_node& node) override;
|
||||||
void visit(const ast::string_literal_node& node) override;
|
void visit(const ast::string_literal_node& node) override;
|
||||||
void visit(const ast::integer_literal_node& node) override;
|
void visit(const ast::integer_literal_node& node) override;
|
||||||
@@ -42,7 +43,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furlang::ir::block_index push_block();
|
furlang::ir::block_index push_block(bool validate = true);
|
||||||
private:
|
private:
|
||||||
furlang::ir::module m_module;
|
furlang::ir::module m_module;
|
||||||
std::unique_ptr<furlang::ir::function> m_currentFunction;
|
std::unique_ptr<furlang::ir::function> m_currentFunction;
|
||||||
@@ -55,4 +56,4 @@ private:
|
|||||||
} // namespace front
|
} // namespace front
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_FRONT_IR_GENERATOR_HPP
|
#endif // FURC_FRONT_IR_GENERATOR_HPP
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ enum class keyword_token {
|
|||||||
Return, /**< `return` */
|
Return, /**< `return` */
|
||||||
If, /**< `if` */
|
If, /**< `if` */
|
||||||
Else, /**< `else` */
|
Else, /**< `else` */
|
||||||
|
While, /**< `while` */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) {
|
static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) {
|
||||||
@@ -154,6 +155,7 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword)
|
|||||||
case keyword_token::Return: return os << "return";
|
case keyword_token::Return: return os << "return";
|
||||||
case keyword_token::If: return os << "if";
|
case keyword_token::If: return os << "if";
|
||||||
case keyword_token::Else: return os << "else";
|
case keyword_token::Else: return os << "else";
|
||||||
|
case keyword_token::While: return os << "while";
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@@ -165,6 +167,7 @@ static inline std::string operator+(const std::string& str, keyword_token keywor
|
|||||||
case keyword_token::Return: return str + "return";
|
case keyword_token::Return: return str + "return";
|
||||||
case keyword_token::If: return str + "if";
|
case keyword_token::If: return str + "if";
|
||||||
case keyword_token::Else: return str + "else";
|
case keyword_token::Else: return str + "else";
|
||||||
|
case keyword_token::While: return str + "while";
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -377,4 +380,4 @@ using token_r = furlang::result<token, token_error>; /**< Alias to a token resul
|
|||||||
} // namespace front
|
} // namespace front
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_FRONT_TOKEN_HPP
|
#endif // FURC_FRONT_TOKEN_HPP
|
||||||
|
|||||||
+13
-1
@@ -186,6 +186,18 @@ bool compound_statement_node::equal(const node& rhs) const {
|
|||||||
return statement_node::equal(rhs) && m_body == dynamic_cast<const compound_statement_node&>(rhs).m_body;
|
return statement_node::equal(rhs) && m_body == dynamic_cast<const compound_statement_node&>(rhs).m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void while_statement_node::accept(visitor& visitor) const {
|
||||||
|
visitor.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& while_statement_node::print(std::ostream& os) const {
|
||||||
|
return os << m_body;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool while_statement_node::equal(const node& rhs) const {
|
||||||
|
return statement_node::equal(rhs) && m_body == dynamic_cast<const while_statement_node&>(rhs).m_body;
|
||||||
|
}
|
||||||
|
|
||||||
void program_node::accept(visitor& visitor) const {
|
void program_node::accept(visitor& visitor) const {
|
||||||
for (const auto& decl : m_declarations) {
|
for (const auto& decl : m_declarations) {
|
||||||
decl->accept(visitor);
|
decl->accept(visitor);
|
||||||
@@ -212,4 +224,4 @@ std::ostream& operator<<(std::ostream& os, const body& body) {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furc::ast
|
} // namespace furc::ast
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include "furc/ast/expression.hpp" // IWYU pragma: keep
|
#include "furc/ast/expression.hpp" // IWYU pragma: keep
|
||||||
#include "furc/ast/literal.hpp" // IWYU pragma: keep
|
#include "furc/ast/literal.hpp" // IWYU pragma: keep
|
||||||
#include "furc/ast/statement.hpp" // IWYU pragma: keep
|
#include "furc/ast/statement.hpp" // IWYU pragma: keep
|
||||||
|
#include "furlang/ir/instruction.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace furc::front {
|
namespace furc::front {
|
||||||
|
|
||||||
@@ -55,6 +57,33 @@ void ir_generator::visit(const ast::if_statement_node& node) {
|
|||||||
push_block(); // merge block
|
push_block(); // merge block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ir_generator::visit(const ast::while_statement_node& node) {
|
||||||
|
node.condition()->accept(*this);
|
||||||
|
ir_register cond = m_registerCounter - 1;
|
||||||
|
std::shared_ptr<ir::block> entry = m_currentBlock;
|
||||||
|
ir::block_index headerIdx = m_currentFunction->blocks().size();
|
||||||
|
|
||||||
|
push_block(false); // loop header
|
||||||
|
push<ir::branch_instruction>(m_currentFunction->blocks().size());
|
||||||
|
|
||||||
|
push_block(); // loop condition
|
||||||
|
node.condition()->accept(*this);
|
||||||
|
std::shared_ptr<ir::block> condBlock = m_currentBlock;
|
||||||
|
ir_register cond2 = m_registerCounter - 1;
|
||||||
|
|
||||||
|
push_block(false); // loop body
|
||||||
|
node.body()->accept(*this);
|
||||||
|
push<ir::branch_instruction>(headerIdx);
|
||||||
|
|
||||||
|
entry->emplace<ir::branch_cond_instruction>(ir::operand::new_reg(cond),
|
||||||
|
headerIdx,
|
||||||
|
m_currentFunction->blocks().size());
|
||||||
|
condBlock->emplace<ir::branch_cond_instruction>(ir::operand::new_reg(cond2),
|
||||||
|
m_currentFunction->blocks().size() - 1,
|
||||||
|
m_currentFunction->blocks().size());
|
||||||
|
push_block(); // merge block
|
||||||
|
}
|
||||||
|
|
||||||
void ir_generator::visit(const ast::compound_statement_node& node) {
|
void ir_generator::visit(const ast::compound_statement_node& node) {
|
||||||
for (const auto& stmt : node.body().statements) {
|
for (const auto& stmt : node.body().statements) {
|
||||||
stmt.value()->accept(*this);
|
stmt.value()->accept(*this);
|
||||||
@@ -138,8 +167,8 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furlang::ir::block_index ir_generator::push_block() {
|
furlang::ir::block_index ir_generator::push_block(bool validate) {
|
||||||
if (!m_currentFunction->blocks().empty() && !m_currentFunction->blocks().back()->has_exit()) {
|
if (validate && !m_currentFunction->blocks().empty() && !m_currentFunction->blocks().back()->has_exit()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"block " + std::to_string(m_currentFunction->blocks().size() - 1) + " is lacking an exit");
|
"block " + std::to_string(m_currentFunction->blocks().size() - 1) + " is lacking an exit");
|
||||||
}
|
}
|
||||||
@@ -148,4 +177,4 @@ furlang::ir::block_index ir_generator::push_block() {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furc::front
|
} // namespace furc::front
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "furc/front/lexer.hpp"
|
#include "furc/front/lexer.hpp"
|
||||||
|
|
||||||
|
#include "furc/front/token.hpp"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -97,6 +99,7 @@ token_r lexer::next_token() {
|
|||||||
{ "return", keyword_token::Return },
|
{ "return", keyword_token::Return },
|
||||||
{ "if", keyword_token::If },
|
{ "if", keyword_token::If },
|
||||||
{ "else", keyword_token::Else },
|
{ "else", keyword_token::Else },
|
||||||
|
{ "while", keyword_token::While },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto it = s_keywords.find(value); it != s_keywords.end()) return { location, it->second };
|
if (auto it = s_keywords.find(value); it != s_keywords.end()) return { location, it->second };
|
||||||
@@ -185,4 +188,4 @@ location lexer::current_location() {
|
|||||||
return { m_filename, m_row, m_cursor - m_lineStart };
|
return { m_filename, m_row, m_cursor - m_lineStart };
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furc::front
|
} // namespace furc::front
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#include "furc/ast/declaration.hpp" // IWYU pragma: keep
|
#include "furc/ast/declaration.hpp" // IWYU pragma: keep
|
||||||
#include "furc/ast/expression.hpp" // IWYU pragma: keep
|
#include "furc/ast/expression.hpp" // IWYU pragma: keep
|
||||||
#include "furc/ast/literal.hpp" // IWYU pragma: keep
|
#include "furc/ast/fwd.hpp"
|
||||||
#include "furc/ast/program.hpp" // IWYU pragma: keep
|
#include "furc/ast/literal.hpp" // IWYU pragma: keep
|
||||||
#include "furc/ast/statement.hpp" // IWYU pragma: keep
|
#include "furc/ast/program.hpp" // IWYU pragma: keep
|
||||||
|
#include "furc/ast/statement.hpp" // IWYU pragma: keep
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -145,6 +146,24 @@ ast::statement_node_r parser::parse_statement() {
|
|||||||
std::move(cond.value()),
|
std::move(cond.value()),
|
||||||
std::move(then.value()));
|
std::move(then.value()));
|
||||||
}
|
}
|
||||||
|
case keyword_token::While: {
|
||||||
|
auto tok = next_token();
|
||||||
|
auto err = eat_token(token_t::LParen);
|
||||||
|
if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location });
|
||||||
|
|
||||||
|
auto cond = parse_expression();
|
||||||
|
if (cond.has_error()) return ast::statement_node_r(ast::error{ cond.error().location });
|
||||||
|
|
||||||
|
err = eat_token(token_t::RParen);
|
||||||
|
if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location });
|
||||||
|
|
||||||
|
auto body = parse_statement();
|
||||||
|
if (body.has_error()) return ast::statement_node_r(ast::error{ body.error().location });
|
||||||
|
|
||||||
|
return m_arena.allocate_shared<ast::while_statement_node>(location,
|
||||||
|
std::move(cond.value()),
|
||||||
|
std::move(body.value()));
|
||||||
|
}
|
||||||
case keyword_token::None:
|
case keyword_token::None:
|
||||||
case keyword_token::Func:
|
case keyword_token::Func:
|
||||||
default: break;
|
default: break;
|
||||||
@@ -438,4 +457,4 @@ token_r parser::eat_token(token_t type) {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace furc::front
|
} // namespace furc::front
|
||||||
|
|||||||
+5
-9
@@ -11,16 +11,12 @@ int main(void) {
|
|||||||
try {
|
try {
|
||||||
std::string programStr = R"(
|
std::string programStr = R"(
|
||||||
func main() {
|
func main() {
|
||||||
x = 5;
|
x = 0;
|
||||||
x -= 3;
|
y = 10;
|
||||||
if (x < 3) {
|
z = 1;
|
||||||
y = x * 2;
|
while (x < y) {
|
||||||
w = y;
|
x = x + z;
|
||||||
} else {
|
|
||||||
y = x - 3;
|
|
||||||
}
|
}
|
||||||
w = x - y;
|
|
||||||
z = x + y;
|
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
furc::front::parser parser("<TEMP>", programStr);
|
furc::front::parser parser("<TEMP>", programStr);
|
||||||
|
|||||||
@@ -444,6 +444,9 @@ public:
|
|||||||
public:
|
public:
|
||||||
instruction_t type() const override { return instruction_t::BranchCond; }
|
instruction_t type() const override { return instruction_t::BranchCond; }
|
||||||
|
|
||||||
|
std::vector<operand*> sources() override { return { &m_condition }; }
|
||||||
|
std::vector<const operand*> sources() const override { return { &m_condition }; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns this instruction's condition operand.
|
* @brief Returns this instruction's condition operand.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user