-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscanner.cpp
More file actions
119 lines (114 loc) · 3.1 KB
/
scanner.cpp
File metadata and controls
119 lines (114 loc) · 3.1 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
#include "scanner.h"
static std::unordered_map<std::string, Token::Type> keywords = {
{"and", Token::AND}, {"class", Token::CLASS}, {"or", Token::OR}, {"else", Token::ELSE},
{"false", Token::FALSE}, {"for", Token::FOR}, {"fun", Token::FUN}, {"if", Token::IF},
{"null", Token::NUL}, {"print", Token::PRINT}, {"return", Token::RETURN}, {"super", Token::SUPER},
{"this", Token::THIS}, {"true", Token::TRUE}, {"let", Token::LET}, {"while", Token::WHILE} };
bool Scanner::isDigit(char c) {
return (c >= '0' && c <= '9');
}
bool Scanner::isAlpha(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_');
}
void Scanner::error(std::string message) {
hadError = true;
std::cerr << "error: " << message << std::endl;
}
std::vector<Token> Scanner::getTokens(std::istream& input, bool& err) {
auto match{
[&](char c) {
char a = input.get();
if (a != EOF && c == a)
return true;
else
input.unget();
return false;
}
};
std::vector<Token> tokens;
for (char c = input.get(); c != EOF; c = input.get()) {
switch (c) {
case ' ':
case '\r':
case '\t':
break;
case '\n':
lineNum++;
break;
case '(':
tokens.push_back(Token::LPARAN); break;
case ')':
tokens.push_back(Token::RPARAN); break;
case '{':
tokens.push_back(Token::LBRACE); break;
case '}':
tokens.push_back(Token::RBRACE); break;
case '.':
tokens.push_back(Token::DOT); break;
case ',':
tokens.push_back(Token::COMMA); break;
case '+':
tokens.push_back(Token::PLUS); break;
case '-':
tokens.push_back(Token::MINUS); break;
case '*':
tokens.push_back(Token::STAR); break;
case ';':
tokens.push_back(Token::SEMICOLON); break;
case '/':
if (match('/')) {
while ((c = input.get()) && c != EOF && c != '\n');
lineNum++;
}
else
tokens.push_back(Token::SLASH);
break;
case '!':
tokens.push_back(match('=') ? Token::UNEQUAL : Token::BANG); break;
case '=':
tokens.push_back(match('=') ? Token::EQUAL : Token::ASSIGN); break;
case '>':
tokens.push_back(match('=') ? Token::GREATEREQ : Token::GREATER); break;
case '<':
tokens.push_back(match('=') ? Token::LESSEREQ : Token::LESSER); break;
case '"':
{
std::string stringLit{ "" };
while ((c = input.get()) && c != EOF && c != '"') {
if (c == '\n')
lineNum++;
stringLit += c;
}
if (c == EOF)
error("Unterminated string");
tokens.push_back(Token(Token::STRING, stringLit));
break;
}
default:
if (isDigit(c)) {
std::string num{ c };
while (isDigit(c = input.get()))
num += c;
if (c == '.') {
num += c;
while (isDigit(c = input.get()))
num += c;
}
tokens.push_back(Token(Token::NUM, num));
input.unget();
}
else if (isAlpha(c)) {
std::string s{ c };
while ((c = input.get()) && (isAlpha(c) || isDigit(c)))
s += c;
tokens.push_back(keywords.find(s) != keywords.end() ? keywords[s] : Token(Token::IDENTIFIER, s));
input.unget();
}
else
error("Unknown token at line " + std::to_string(lineNum));
}
}
tokens.push_back(Token::FILEEND);
err = hadError;
return std::move(tokens);
}