docs: added parser documentation

This commit is contained in:
lisk77 2025-06-30 21:07:29 +02:00
parent bce708be5f
commit 777ff3d3fb
2 changed files with 69 additions and 104 deletions

View file

@ -1,4 +1,3 @@
// src/parser.cpp
#include "parser.hpp" #include "parser.hpp"
#include "ast.hpp" #include "ast.hpp"
@ -20,139 +19,103 @@ const std::unordered_map<std::string, std::unique_ptr<Expr>>& Parser::definition
} }
const Token& Parser::peek() const { const Token& Parser::peek() const {
if (position >= tokens.size()) if (position >= tokens.size())
throw std::runtime_error("parser: unexpected end of file"); throw std::runtime_error("parser: unexpected end of file");
return tokens[position]; return tokens[position];
} }
const Token& Parser::get() { const Token& Parser::get() {
if (position >= tokens.size()) if (position >= tokens.size())
throw std::runtime_error("parser: unexpected end of file"); throw std::runtime_error("parser: unexpected end of file");
return tokens[position++]; return tokens[position++];
} }
bool Parser::accept(TokenType t) { bool Parser::accept(TokenType t) {
if (position < tokens.size() && tokens[position].type == t) { if (position < tokens.size() && tokens[position].type == t) {
++position; ++position;
return true; return true;
} }
return false; return false;
} }
void Parser::expect(TokenType t) { void Parser::expect(TokenType t) {
if (!accept(t)) { if (!accept(t)) {
std::cout << display_tokentype(t) << std::endl; std::cout << display_tokentype(t) << std::endl;
throw std::runtime_error("parser: unexpected token at position " throw std::runtime_error("parser: unexpected token at position " + std::to_string(peek().start));
+ std::to_string(peek().start)); }
}
} }
// Try to parse a definition of the form: // parse expressions like "main = \ x . x;"
// <variable> '=' <term> ';'
// Returns true if a definition was parsed and stored in defs.
bool Parser::tryParseDefinition() { bool Parser::tryParseDefinition() {
if (peek().type == TokenType::VARIABLE if (peek().type == TokenType::VARIABLE && position+1 < tokens.size() && tokens[position+1].type == TokenType::EQUALS) {
&& position+1 < tokens.size() std::string name = get().lexeme;
&& tokens[position+1].type == TokenType::EQUALS) expect(TokenType::EQUALS);
{
std::string name = get().lexeme; // consume VARIABLE
expect(TokenType::EQUALS); // consume '='
// parse the right-hand term std::unique_ptr<Expr> value = parseApplication();
std::unique_ptr<Expr> value = parseTerm();
// require a semicolon (EOL token) expect(TokenType::EOL);
expect(TokenType::EOL);
// store in definitions map defs.emplace(std::move(name), std::move(value));
defs.emplace(std::move(name), std::move(value)); return true;
return true; }
} return false;
return false;
} }
// <simple> ::= '\' <variable>+ '.' <term> // parse simple expressions like "\ x . x" or "x" or stuff in parenthesis
// | <variable>
// | '(' <term> ')'
std::unique_ptr<Expr> Parser::parseSimple() { std::unique_ptr<Expr> Parser::parseSimple() {
// abstraction with one-or-more parameters if (accept(TokenType::LAMBDA)) {
if (accept(TokenType::LAMBDA)) { std::vector<std::string> params;
std::vector<std::string> params; while (peek().type == TokenType::VARIABLE) {
while (peek().type == TokenType::VARIABLE) { params.push_back(get().lexeme);
params.push_back(get().lexeme); }
expect(TokenType::DOT);
std::unique_ptr<Expr> body = parseApplication();
for (auto it = params.rbegin(); it != params.rend(); ++it) {
body = std::make_unique<Abstraction>(*it, std::move(body));
}
return body;
} }
expect(TokenType::DOT);
std::unique_ptr<Expr> body = parseTerm(); if (peek().type == TokenType::VARIABLE) {
// right-nest them: \p1.\p2.…body const auto &tok = get();
for (auto it = params.rbegin(); it != params.rend(); ++it) { return std::make_unique<Variable>(tok.lexeme);
body = std::make_unique<Abstraction>(*it, std::move(body));
} }
return body;
}
// variable if (accept(TokenType::LPAREN)) {
if (peek().type == TokenType::VARIABLE) { std::unique_ptr<Expr> e = parseApplication();
const auto &tok = get(); expect(TokenType::RPAREN);
return std::make_unique<Variable>(tok.lexeme); return e;
} }
// parenthesized term throw std::runtime_error("parser: expected \\, variable, or '(' at position " + std::to_string(peek().start));
if (accept(TokenType::LPAREN)) {
std::unique_ptr<Expr> e = parseTerm();
expect(TokenType::RPAREN);
return e;
}
throw std::runtime_error("parser: expected \\, variable, or '(' at position "
+ std::to_string(peek().start));
} }
// <application> ::= <simple> { <simple> } // parse function applications
std::unique_ptr<Expr> Parser::parseApplication() { std::unique_ptr<Expr> Parser::parseApplication() {
std::unique_ptr<Expr> expr = parseSimple(); std::unique_ptr<Expr> expr = parseSimple();
while (true) { while (true) {
TokenType t = peek().type; TokenType t = peek().type;
if (t == TokenType::VARIABLE || if (t == TokenType::VARIABLE || t == TokenType::LAMBDA || t == TokenType::LPAREN) {
t == TokenType::LAMBDA || std::unique_ptr<Expr> rhs = parseSimple();
t == TokenType::LPAREN) expr = std::make_unique<Application>(std::move(expr), std::move(rhs));
{ }
std::unique_ptr<Expr> rhs = parseSimple(); else break;
expr = std::make_unique<Application>(std::move(expr), std::move(rhs));
} else {
break;
} }
} return expr;
return expr;
} }
// <term> ::= <application> // uuum... i think the name says it?
std::unique_ptr<Expr> Parser::parseTerm() {
return parseApplication();
}
// parse exactly one term and expect EOC
std::unique_ptr<Expr> Parser::parse() {
std::unique_ptr<Expr> root = parseTerm();
expect(TokenType::EOC);
return root;
}
// <program> ::= { <definition> | <term> EOL } EOC
std::vector<std::unique_ptr<Expr>> Parser::parseProgram() { std::vector<std::unique_ptr<Expr>> Parser::parseProgram() {
std::vector<std::unique_ptr<Expr>> results; std::vector<std::unique_ptr<Expr>> results;
while (peek().type != TokenType::EOC) { while (peek().type != TokenType::EOC) {
// first try a definition if (tryParseDefinition()) continue;
if (tryParseDefinition())
continue;
// otherwise a bare term ending in EOL results.push_back(parseApplication());
results.push_back(parseTerm()); expect(TokenType::EOL);
expect(TokenType::EOL); }
}
expect(TokenType::EOC); expect(TokenType::EOC);
return results; return results;
} }

View file

@ -3,6 +3,8 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
// thank you chatgpt lol
// Forwarddeclare // Forwarddeclare
static void _print(const Expr* e, std::ostream& out); static void _print(const Expr* e, std::ostream& out);
@ -51,6 +53,6 @@ static void _print(const Expr* e, std::ostream& out) {
} }
// fallback // fallback
out << "<??>"; out << "print: unknown expression";
} }