193 lines
3.7 KiB
C++
193 lines
3.7 KiB
C++
#include "Parser.hpp"
|
|
|
|
namespace wg
|
|
{
|
|
/*explicit*/ Parser::Parser()
|
|
{
|
|
}
|
|
|
|
/*virtual*/ Parser::~Parser()
|
|
{
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse(std::vector<std::shared_ptr<Node>>
|
|
const& tokens)
|
|
{
|
|
m_cursor = 0;
|
|
m_tokens = tokens;
|
|
|
|
return parse_prog();
|
|
}
|
|
|
|
Loc Parser::loc() const
|
|
{
|
|
if (m_cursor >= m_tokens.size())
|
|
{
|
|
return Loc {};
|
|
}
|
|
|
|
return m_tokens[m_cursor]->loc();
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::consume(NodeType type)
|
|
{
|
|
if (m_cursor >= m_tokens.size())
|
|
{
|
|
std::stringstream ss;
|
|
ss << "type mismatch, expected '"
|
|
<< (NodeTypeStr[type] + strlen("NODE_"))
|
|
<< "', got nothing.";
|
|
|
|
loc().error<syntax_error>(ss);
|
|
}
|
|
|
|
auto current = m_tokens[m_cursor];
|
|
|
|
if (current->type() != type)
|
|
{
|
|
std::stringstream ss;
|
|
ss << "type mismatch, expected '"
|
|
<< (NodeTypeStr[type] + strlen("NODE_"))
|
|
<< "', got '"
|
|
<< (NodeTypeStr[current->type()] + strlen("NODE_"))
|
|
<< "'";
|
|
|
|
loc().error<syntax_error>(ss);
|
|
}
|
|
else
|
|
{
|
|
return consume();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::consume()
|
|
{
|
|
WG_ASSERT(m_cursor < m_tokens.size(), "cannot consume");
|
|
auto node = m_tokens[m_cursor];
|
|
m_cursor++;
|
|
return node;
|
|
}
|
|
|
|
bool Parser::type_is(NodeType type, int lookahead)
|
|
{
|
|
if (m_cursor + lookahead >= m_tokens.size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return m_tokens[m_cursor + lookahead]->type() == type;
|
|
}
|
|
|
|
bool Parser::type_isnt(NodeType type, int lookahead)
|
|
{
|
|
return !type_is(type, lookahead);
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::make_node(NodeType type) const
|
|
{
|
|
return std::make_shared<Node>(type, "", loc());
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_prog()
|
|
{
|
|
auto node = std::make_shared<Node>(NODE_PROG, "", Loc {});
|
|
|
|
|
|
while (m_cursor < m_tokens.size())
|
|
{
|
|
node->add_child(parse_instr());
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_instr()
|
|
{
|
|
if (type_is(NODE_HASH))
|
|
{
|
|
return parse_dir();
|
|
}
|
|
|
|
auto expr = parse_expr();
|
|
consume(NODE_SEMICOLON);
|
|
return expr;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_dir()
|
|
{
|
|
auto node = make_node(NODE_DIR);
|
|
consume(NODE_HASH);
|
|
node->add_child(consume(NODE_IDENT));
|
|
node->add_child(parse_expr());
|
|
return node;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_expr()
|
|
{
|
|
return parse_addsub();
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_addsub()
|
|
{
|
|
auto lhs = parse_muldivmod();
|
|
|
|
while (type_is(NODE_ADD)
|
|
|| type_is(NODE_SUB))
|
|
{
|
|
auto node = consume();
|
|
node->add_child(lhs);
|
|
node->add_child(parse_muldivmod());
|
|
lhs = node;
|
|
}
|
|
|
|
return lhs;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_muldivmod()
|
|
{
|
|
auto lhs = parse_literal();
|
|
|
|
while (type_is(NODE_MUL)
|
|
|| type_is(NODE_DIV)
|
|
|| type_is(NODE_MOD))
|
|
{
|
|
auto node = consume();
|
|
node->add_child(lhs);
|
|
node->add_child(parse_literal());
|
|
lhs = node;
|
|
}
|
|
|
|
return lhs;
|
|
}
|
|
|
|
std::shared_ptr<Node> Parser::parse_literal()
|
|
{
|
|
if (type_is(NODE_INT)
|
|
|| type_is(NODE_IDENT))
|
|
{
|
|
return consume();
|
|
}
|
|
|
|
// Groups
|
|
if (type_is(NODE_OPAR))
|
|
{
|
|
consume(NODE_OPAR);
|
|
|
|
auto expr = parse_expr();
|
|
|
|
consume(NODE_CPAR);
|
|
|
|
return expr;
|
|
}
|
|
|
|
loc().error<syntax_error>(std::string()
|
|
+ "unknown literal '"
|
|
+ (NodeTypeStr[m_tokens[m_cursor]->type()]
|
|
+ strlen("NODE_"))
|
|
+ "'");
|
|
return nullptr;
|
|
}
|
|
}
|