Repository navigation
Expand file tree
/
Copy pathscanner.cpp
More file actions
154 lines (134 loc) Β· 4.87 KB
/
Copy pathscanner.cpp
File metadata and controls
154 lines (134 loc) Β· 4.87 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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "scanner.h" // Include our own header file
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <cctype>
// Use 'using namespace std' in the .cpp file, but not the .h file
// This keeps the global namespace clean for the user.
using namespace std;
// --- "Private" Library Data ---
// These are not visible to main.cpp
unordered_set<string> keywords = {
"ignite", "engine",
"gear", "turbo", "exhaust", "flag",
"announce", "listen",
"track", "pitstop", "looplap", "overtake", "finishline",
"key", "#oil", "#car"
};
unordered_set<string> booleans = { "true", "false" };
unordered_set<char> operators = { '+', '-', '*', '/', '=', '<', '>' };
unordered_set<char> symbols = { '{', '}', '(', ')', ';' };
// ---
/*
* Implementation of the scan function
*/
vector<Token> scan(const string& code) {
vector<Token> tok;
int i = 0;
int line = 1; // Start at line 1
while (i < code.size()) {
// 1. Skip Whitespace
if (isspace(code[i])) {
if (code[i] == '\n') line++; // Increment line counter
i++;
continue;
}
// 2. String
if (code[i] == '"') {
string str;
i++; // Consume opening "
int startLine = line; // In case string is multi-line
while (i < code.size() && code[i] != '"') {
if (code[i] == '\n') line++; // Support multi-line strings
str += code[i++];
}
if (i == code.size()) {
cout << "Error [Line " << startLine << "]: Unterminated string!" << endl;
break; // Stop scanning
}
else {
tok.push_back({ STRING, str, startLine });
i++; // Consume closing "
}
}
// 3. Identifier or Keyword
else if (isalpha(code[i]) || code[i] == '#') {
string word;
while (i < code.size() && (isalnum(code[i]) || code[i] == '#' || code[i] == '_')) {
word += code[i++];
}
if (keywords.count(word))
tok.push_back({ KEYWORD, word, line });
else if (booleans.count(word))
tok.push_back({ BOOLEAN, word, line });
else
tok.push_back({ IDENTIFIER, word, line });
}
// 4. Number
else if (isdigit(code[i])) {
string num;
bool hasDecimal = false;
while (i < code.size() && (isdigit(code[i]) || code[i] == '.')) {
if (code[i] == '.') {
if (hasDecimal) break; // Found a second decimal
hasDecimal = true;
}
num += code[i++];
}
tok.push_back({ NUMBER, num, line });
}
// 5. Operator
else if (code[i] == '+' || code[i] == '-' || code[i] == '*' || code[i] == '/' || code[i] == '=' || code[i] == '<' || code[i] == '>') {
// Check for two-char operators
if (i + 1 < code.length()) {
char n = code[i + 1];
if ((code[i] == '=' && n == '=') ||
(code[i] == '<' && n == '=') ||
(code[i] == '>' && n == '=') ||
(code[i] == '!' && n == '=')) {
string op;
op += code[i];
op += n;
tok.push_back({ OPERATOR, op, line });
i += 2;
continue;
}
}
// Single char operator
tok.push_back({ OPERATOR, string(1, code[i]), line });
i++;
continue;
}
// 6. Symbol
else if (symbols.count(code[i])) {
string sym(1, code[i++]);
tok.push_back({ SYMBOL, sym, line });
}
// 7. Unknown
else {
string unknown(1, code[i++]);
cout << "Error [Line " << line << "]: Unknown character: " << unknown << endl;
tok.push_back({ UNKNOWN, unknown, line });
}
}
tok.push_back({ END_OF_FILE, "EOF", line });
return tok;
}
/*
* Implementation of the helper function
*/
std::string tokenTypeToString(TokenType type) {
switch (type) {
case KEYWORD: return "KEYWORD";
case IDENTIFIER: return "IDENTIFIER";
case NUMBER: return "NUMBER";
case STRING: return "STRING";
case OPERATOR: return "OPERATOR";
case SYMBOL: return "SYMBOL";
case BOOLEAN: return "BOOLEAN";
case END_OF_FILE: return "END_OF_FILE";
case UNKNOWN: return "UNKNOWN";
default: return "ERROR";
}
}