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 "ast.hpp"
@ -42,40 +41,28 @@ bool Parser::accept(TokenType t) {
void Parser::expect(TokenType t) {
if (!accept(t)) {
std::cout << display_tokentype(t) << std::endl;
throw std::runtime_error("parser: unexpected token at position "
+ std::to_string(peek().start));
throw std::runtime_error("parser: unexpected token at position " + std::to_string(peek().start));
}
}
// Try to parse a definition of the form:
// <variable> '=' <term> ';'
// Returns true if a definition was parsed and stored in defs.
// parse expressions like "main = \ x . x;"
bool Parser::tryParseDefinition() {
if (peek().type == TokenType::VARIABLE
&& position+1 < tokens.size()
&& tokens[position+1].type == TokenType::EQUALS)
{
std::string name = get().lexeme; // consume VARIABLE
expect(TokenType::EQUALS); // consume '='
if (peek().type == TokenType::VARIABLE && position+1 < tokens.size() && tokens[position+1].type == TokenType::EQUALS) {
std::string name = get().lexeme;
expect(TokenType::EQUALS);
// parse the right-hand term
std::unique_ptr<Expr> value = parseTerm();
std::unique_ptr<Expr> value = parseApplication();
// require a semicolon (EOL token)
expect(TokenType::EOL);
// store in definitions map
defs.emplace(std::move(name), std::move(value));
return true;
}
return false;
}
// <simple> ::= '\' <variable>+ '.' <term>
// | <variable>
// | '(' <term> ')'
// parse simple expressions like "\ x . x" or "x" or stuff in parenthesis
std::unique_ptr<Expr> Parser::parseSimple() {
// abstraction with one-or-more parameters
if (accept(TokenType::LAMBDA)) {
std::vector<std::string> params;
while (peek().type == TokenType::VARIABLE) {
@ -83,76 +70,52 @@ std::unique_ptr<Expr> Parser::parseSimple() {
}
expect(TokenType::DOT);
std::unique_ptr<Expr> body = parseTerm();
// right-nest them: \p1.\p2.…body
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;
}
// variable
if (peek().type == TokenType::VARIABLE) {
const auto &tok = get();
return std::make_unique<Variable>(tok.lexeme);
}
// parenthesized term
if (accept(TokenType::LPAREN)) {
std::unique_ptr<Expr> e = parseTerm();
std::unique_ptr<Expr> e = parseApplication();
expect(TokenType::RPAREN);
return e;
}
throw std::runtime_error("parser: expected \\, variable, or '(' at position "
+ std::to_string(peek().start));
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> expr = parseSimple();
while (true) {
TokenType t = peek().type;
if (t == TokenType::VARIABLE ||
t == TokenType::LAMBDA ||
t == TokenType::LPAREN)
{
if (t == TokenType::VARIABLE || t == TokenType::LAMBDA || t == TokenType::LPAREN) {
std::unique_ptr<Expr> rhs = parseSimple();
expr = std::make_unique<Application>(std::move(expr), std::move(rhs));
} else {
break;
}
else break;
}
return expr;
}
// <term> ::= <application>
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
// uuum... i think the name says it?
std::vector<std::unique_ptr<Expr>> Parser::parseProgram() {
std::vector<std::unique_ptr<Expr>> results;
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(parseTerm());
results.push_back(parseApplication());
expect(TokenType::EOL);
}
expect(TokenType::EOC);
return results;
}

View file

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