commit 1fcbf19350c8294cd19982d8b50360baf64633f2
parent 907199802749d357c7f9a12bdb596fee78e5f6a7
Author: Pranav Prabhu Kumble <kumblepranavprabhu@gmail.com>
Date: Sun, 29 Mar 2026 21:04:36 +0530
Week 2: Implement AST Parser (Part 2: Core logic)
Diffstat:
| M | src/parser.cpp | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/parser.h | | | 47 | +++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/src/parser.cpp b/src/parser.cpp
@@ -40,3 +40,61 @@ std::unique_ptr<ASTNode> Parser::parseExpression() {
}
return left;
+}
+
+// Term -> Factor+
+std::unique_ptr<ASTNode> Parser::parseTerm() {
+ auto node = parseFactor();
+
+ while (!isAtEnd() &&
+ peek().type != TokenType::PIPE &&
+ peek().type != TokenType::RPAREN &&
+ peek().type != TokenType::END_OF_INPUT) {
+ auto next = parseFactor();
+ node = std::make_unique<ConcatenationNode>(std::move(node), std::move(next));
+ }
+
+ return node;
+}
+
+// Factor -> Atom ( '*' | '+' | '?' )?
+std::unique_ptr<ASTNode> Parser::parseFactor() {
+ auto node = parseAtom();
+
+ if (match(TokenType::STAR)) {
+ node = std::make_unique<StarNode>(std::move(node));
+ } else if (match(TokenType::PLUS)) {
+ node = std::make_unique<PlusNode>(std::move(node));
+ } else if (match(TokenType::QUESTION)) {
+ node = std::make_unique<OptionalNode>(std::move(node));
+ }
+
+ return node;
+}
+
+// Atom -> LITERAL | DOT | '(' Expression ')'
+std::unique_ptr<ASTNode> Parser::parseAtom() {
+ if (match(TokenType::LITERAL)) {
+ return std::make_unique<LiteralNode>(tokens[pos - 1].value);
+ }
+
+ if (match(TokenType::DOT)) {
+ return std::make_unique<DotNode>();
+ }
+
+ if (match(TokenType::LPAREN)) {
+ auto node = parseExpression();
+ if (!match(TokenType::RPAREN)) {
+ error("Unmatched parenthesis: expected ')'");
+ }
+ return node;
+ }
+
+ if (peek().type == TokenType::STAR || peek().type == TokenType::PLUS || peek().type == TokenType::QUESTION) {
+ error("Quantifier '" + tokenTypeToString(peek().type) + "' applied to nothing");
+ }
+
+ error("Unexpected token: " + tokenTypeToString(peek().type));
+ return nullptr; // Should not reach here
+}
+
diff --git a/src/parser.h b/src/parser.h
@@ -33,3 +33,50 @@ std::string nodeTypeToString(ASTNodeType type);
class LiteralNode : public ASTNode {
public:
+ char value;
+ int position; // Used for Glushkov's construction
+ explicit LiteralNode(char v) : ASTNode(ASTNodeType::LITERAL), value(v), position(-1) {}
+};
+
+class DotNode : public ASTNode {
+public:
+ int position; // Used for Glushkov's construction
+ DotNode() : ASTNode(ASTNodeType::DOT), position(-1) {}
+};
+
+class ConcatenationNode : public ASTNode {
+public:
+ std::unique_ptr<ASTNode> left;
+ std::unique_ptr<ASTNode> right;
+ ConcatenationNode(std::unique_ptr<ASTNode> l, std::unique_ptr<ASTNode> r)
+ : ASTNode(ASTNodeType::CONCATENATION), left(std::move(l)), right(std::move(r)) {}
+};
+
+class UnionNode : public ASTNode {
+public:
+ std::unique_ptr<ASTNode> left;
+ std::unique_ptr<ASTNode> right;
+ UnionNode(std::unique_ptr<ASTNode> l, std::unique_ptr<ASTNode> r)
+ : ASTNode(ASTNodeType::UNION), left(std::move(l)), right(std::move(r)) {}
+};
+
+class StarNode : public ASTNode {
+public:
+ std::unique_ptr<ASTNode> inner;
+ explicit StarNode(std::unique_ptr<ASTNode> i)
+ : ASTNode(ASTNodeType::STAR), inner(std::move(i)) {}
+};
+
+class PlusNode : public ASTNode {
+public:
+ std::unique_ptr<ASTNode> inner;
+ explicit PlusNode(std::unique_ptr<ASTNode> i)
+ : ASTNode(ASTNodeType::PLUS), inner(std::move(i)) {}
+};
+
+class OptionalNode : public ASTNode {
+public:
+ std::unique_ptr<ASTNode> inner;
+ explicit OptionalNode(std::unique_ptr<ASTNode> i)
+ : ASTNode(ASTNodeType::OPTIONAL), inner(std::move(i)) {}
+};