#include "Parser.hpp" namespace jk { /*explicit*/ Parser::Parser(Logger& logger, std::shared_ptr lexer) : m_logger { logger } , m_lexer { lexer } { } /*virtual*/ Parser::~Parser() { } std::shared_ptr Parser::parse(std::string const& source) { std::shared_ptr tok; m_cursor = 0; m_lexer->scan(source); while ( (tok=m_lexer->next()) ) { m_tokens.push_back(tok); } if (m_tokens.empty()) { return std::make_shared(NODE_PROG, "", Loc {m_lexer->loc().path(), 1, 1}); } return parse_prog(); } std::shared_ptr Parser::current() const { assert(m_cursor < m_tokens.size()); return m_tokens[m_cursor]; } Loc Parser::loc() const { return current()->loc(); } std::shared_ptr Parser::consume() { assert(m_cursor < m_tokens.size()); auto tok = m_tokens[m_cursor]; m_cursor++; return tok; } std::shared_ptr Parser::consume(NodeType type) { assert(m_cursor < m_tokens.size()); if (m_tokens[m_cursor]->type() != type) { std::stringstream ss; ss << "expected '" << std::string(NodeTypeStr[type]) .substr(std::string("NODE_").size()) << "', got '" << std::string(NodeTypeStr[m_tokens[m_cursor]->type()]) .substr(std::string("NODE_").size()) << "'"; m_logger.log(LOG_ERROR, m_tokens[m_cursor]->loc(), ss.str()); } return consume(); } bool Parser::type_is(NodeType type, int lookahead) const { if (m_cursor + lookahead >= m_tokens.size()) { return false; } return m_tokens[m_cursor + lookahead]->type() == type; } std::shared_ptr Parser::parse_prog() { auto root = std::make_shared(NODE_PROG, "", loc()); while (m_cursor < m_tokens.size()) { root->add_child(parse_funcall()); } return root; } std::shared_ptr Parser::parse_expr() { if (type_is(NODE_OPAR)) { return parse_funcall(); } return parse_literal(); } std::shared_ptr Parser::parse_funcall() { auto root = std::make_shared(NODE_FUNCALL, "", loc()); consume(NODE_OPAR); while (!type_is(NODE_CPAR)) { root->add_child(parse_expr()); } consume(NODE_CPAR); return root; } std::shared_ptr Parser::parse_literal() { if (type_is(NODE_INT) || type_is(NODE_IDENT)) { return consume(); } m_logger.log(LOG_ERROR, loc(), std::string() + "unexpected token '" + current()->repr() + "'"); abort(); } }