#pragma once #include #include "parser/lexer.hpp" #include "parser/nodes.hpp" class AstParser { public: AstParser(Lexer* lexer) : m_lexer(lexer) {} public: ExternNode* ParseExtern() { m_lexer->NextExpect(TokenType::Id); return new ExternNode(m_lexer->token().string); } FnDeclNode* ParseFnDecl() { // Function Declaration m_lexer->NextExpect(TokenType::Id); StringView name = m_lexer->token().string; m_lexer->NextExpect('('); Builder params; // TODO: support multiple params if (m_lexer->seek_token()->token != ')') { m_lexer->NextExpect(TokenType::Id); params.Push(m_lexer->token().string); } m_lexer->NextExpect(')'); m_lexer->NextExpect('{'); auto compound = new CompoundNode(); while (m_lexer->seek_token()->token != '}') { compound->addNode(ParseStatement()); } m_lexer->NextExpect('}'); return new FnDeclNode(name, compound, params.view()); } FnCallNode* ParseFnCall(const StringView& name) { // m_lexer->NextExpect(TokenType::Id); // char* name = strdup(m_lexer->token().string); m_lexer->NextExpect('('); Node* arg = nullptr; // TODO: support multiple arguments if (m_lexer->seek_token()->token != ')') { arg = ParseExpression(); } m_lexer->NextExpect(')'); return new FnCallNode(name, arg); } Node* ParseFactor() { auto token = m_lexer->seek_token(); switch (token->token) { case TokenType::IntLiteral: // integer { m_lexer->NextExpect(TokenType::IntLiteral); auto node = new IntLiteralNode(m_lexer->token().int_number); return node; } case TokenType::Id: // variable name or function call { m_lexer->NextExpect(TokenType::Id); auto name = m_lexer->token().string; token = m_lexer->seek_token(); if (token->token == '(') { return ParseFnCall(name); } return new VariableNode(name); } default: fprintf(stderr, "%s:%d:%d: ERROR: unexpected token while parsing %ld\n", m_lexer->filename(), token->line_number, token->offset_start, token->token); Exit(1); break; } assert(0 && "unreachable"); } Node* ParseTerm() { auto t = ParseFactor(); for (auto op = m_lexer->seek_token(); is_one_of(op->token, '/', '*'); op = m_lexer->seek_token()) { m_lexer->NextToken(); ExpressionNode::Operator eop; assert((int)ExpressionNode::Operator::COUNT_OPERATORS == 4 && "some operators may not be handled"); switch((char)op->token) { case '/': eop = ExpressionNode::Operator::Divide; break; case '*': eop = ExpressionNode::Operator::Multiply; break; default: assert(false && "should be unreachable"); break; } auto expr = new ExpressionNode(t, ParseTerm(), eop); t = expr; } return t; } Node* ParseExpression() { auto t = ParseTerm(); for (auto op = m_lexer->seek_token(); is_one_of(op->token, '+', '-'); op = m_lexer->seek_token()) { m_lexer->NextToken(); ExpressionNode::Operator eop; assert((int)ExpressionNode::Operator::COUNT_OPERATORS == 4 && "some operators may not be handled"); switch((char)op->token) { case '+': eop = ExpressionNode::Operator::Plus; break; case '-': eop = ExpressionNode::Operator::Minus; break; default: assert(false && "should be unreachable"); break; } auto expr = new ExpressionNode(t, ParseTerm(), eop); t = expr; } return t; } VarDeclNode* ParseVarDecl() { m_lexer->NextExpect(TokenType::Local); m_lexer->NextExpect(TokenType::Id); auto name = m_lexer->token().string; m_lexer->NextExpect('='); Node* value = ParseExpression(); return new VarDeclNode(name, value); } Node* ParseStatement() { auto token = m_lexer->seek_token(); // TODO: proper error handling assert(token != nullptr && "next token should be available"); switch(token->token) { case TokenType::Local: return ParseVarDecl(); default: return ParseExpression(); } assert(0 && "unreachable"); return nullptr; } ProgramNode* Parse() { auto program = new ProgramNode; while (m_lexer->NextToken()) { auto token = m_lexer->token(); switch(token.token) { case TokenType::Extern: program->PushExtern(ParseExtern()); break; case TokenType::Fn: program->PushFunction(ParseFnDecl()); break; default: { fprintf(stderr, "%s:%d:%d: ERROR: unexpected token while parsing %ld\n", m_lexer->filename(), token.line_number, token.offset_start, token.token); Exit(1); break; } } } return program; } private: void Exit(int status) { std::exit(status); } private: Lexer* m_lexer; };