#include "Parser.hpp" #include "Node.hpp" namespace muz { /*explicit*/ Parser::Parser() { } /*virtual*/ Parser::~Parser() { } std::shared_ptr Parser::parse(Lexer& lexer) { m_tokens = lexer.all(); m_cursor = 0; return parse_prog(); } int Parser::current_line() { if (m_cursor < m_tokens.size()) { return m_tokens[m_cursor]->line(); } return 0; } std::shared_ptr Parser::consume(std::optional type) { if (m_cursor >= m_tokens.size()) { std::string ty_desired = NodeTypeStr[*type] + strlen("NODE_"); format_error(current_line(), "unexpected end: expected <" + ty_desired + ">, got nothing."); } auto node = m_tokens[m_cursor]; if (type && node->type() != *type) { std::string ty_got = NodeTypeStr[node->type()] + strlen("NODE_"); std::string ty_desired = NodeTypeStr[*type] + strlen("NODE_"); format_error(current_line(), "expected <" + ty_desired + ">, got <" + ty_got + ">."); } m_cursor++; return node; } NodeType Parser::peek(size_t lookahead) const { return m_tokens[m_cursor + lookahead]->type(); } bool Parser::next_is(NodeType type, size_t lookahead) const { if (m_cursor + lookahead >= m_tokens.size()) { return false; } return peek(lookahead) == type; } std::shared_ptr Parser::parse_prog() { auto node = std::make_shared(NODE_PROG, current_line()); while (m_cursor < m_tokens.size()) { node->add_child(parse_instr()); } return node; } std::shared_ptr Parser::parse_instr() { if (next_is(NODE_DIR_IDENT)) { return parse_dir(); } return parse_cmd(); } std::shared_ptr Parser::parse_dir() { auto node = std::make_shared(NODE_DIR, current_line()); node->add_child(consume(NODE_DIR_IDENT)); node->add_child(parse_cmd()); return node; } std::shared_ptr Parser::parse_cmd() { consume(NODE_OSQUARE); auto node = std::make_shared(NODE_CMD, current_line()); node->add_child(consume(NODE_IDENT)); while (!next_is(NODE_CSQUARE)) { node->add_child(parse_arg()); } consume(NODE_CSQUARE); return node; } std::shared_ptr Parser::parse_arg() { if (next_is(NODE_OSQUARE)) { return parse_cmd(); } return parse_literal(); } std::shared_ptr Parser::parse_literal() { return consume(NODE_NUM); } }