-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.cpp
More file actions
117 lines (97 loc) · 3.61 KB
/
parser.cpp
File metadata and controls
117 lines (97 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "./headers/parser.h"
#include "./headers/statements.h"
#include <stdexcept>
#include <iostream>
Parser::Parser(const std::vector<Token>& tokens) : tokens(tokens) {}
std::vector<std::shared_ptr<Statement>> Parser::parse() {
std::vector<std::shared_ptr<Statement>> statements;
// Handle 'start' token
if (!match(TokenType::START)) {
throw std::runtime_error("Program must begin with 'start'.");
}
while (!isAtEnd()) {
if (peek().type == TokenType::END) {
// Ensure 'end' token is present and stop parsing
advance();
break;
}
try {
statements.push_back(statement());
} catch (const std::runtime_error& e) {
// Debugging output for errors
// std::cerr << "Parser error: " << e.what() << " at token: " << peek().lexeme << "\n";
throw;
}
}
// Ensure we are at the end of the file
if (!isAtEnd()) {
throw std::runtime_error("Program must end with 'end'.");
}
return statements;
}
bool Parser::isAtEnd() {
return peek().type == TokenType::END_OF_FILE;
}
const Token& Parser::advance() {
if (!isAtEnd()) current++;
// Debugging output
// std::cout << "Advance to token: " << peek().lexeme << " (Type: " << static_cast<int>(peek().type) << ")\n";
return previous();
}
const Token& Parser::peek() {
return tokens[current];
}
const Token& Parser::previous() {
return tokens[current - 1];
}
bool Parser::match(TokenType type) {
if (isAtEnd() || peek().type != type) return false;
advance();
return true;
}
const Token& Parser::consume(TokenType type, const std::string& errorMessage) {
if (match(type)) return previous();
throw std::runtime_error(errorMessage);
}
std::shared_ptr<Statement> Parser::statement() {
if (match(TokenType::PRINT)) return printStatement();
return expressionStatement();
}
std::shared_ptr<Statement> Parser::printStatement() {
std::string message;
// Parse multiple arguments separated by commas
do {
if (peek().type == TokenType::STRING) {
// Handle string literals
message += advance().lexeme + " ";
} else {
// Parse expressions (e.g., val * 3 or val * x)
message += parseExpression(false) + " "; // Do not consume semicolon here
}
} while (match(TokenType::COMMA));
// Ensure the semicolon is consumed at the end of the print statement
consume(TokenType::SEMICOLON, "Expected ';' at the end of the 'print' statement.");
return std::make_shared<PrintStatement>(message);
}
std::shared_ptr<Statement> Parser::expressionStatement() {
auto identifier = consume(TokenType::IDENTIFIER, "Expected identifier.");
// Debugging output
// std::cout << "Parsing expression statement for identifier: " << identifier.lexeme << "\n";
if (match(TokenType::EQUAL)) {
// Handle assignment
auto expression = parseExpression(); // Parse the right-hand side expression
return std::make_shared<ExpressionStatement>(identifier.lexeme + " = " + expression);
}
throw std::runtime_error("Expected '=' after identifier.");
}
std::string Parser::parseExpression(bool consumeSemicolon) {
// Parse a simple expression (e.g., numbers, identifiers, or arithmetic operations)
std::string expression;
while (!isAtEnd() && peek().type != TokenType::SEMICOLON && peek().type != TokenType::COMMA) {
expression += advance().lexeme + " ";
}
if (consumeSemicolon) {
consume(TokenType::SEMICOLON, "Expected ';' at the end of the expression.");
}
return expression;
}