122 lines
2.7 KiB
C++
122 lines
2.7 KiB
C++
#include "scanner.hh"
|
|
#include "token.hh"
|
|
#include "error_handler.hh"
|
|
#include "object.hh"
|
|
#include <vector>
|
|
|
|
extern ErrorHandler error_handler;
|
|
|
|
std::vector<Token> Scanner::scan_tokens() {
|
|
while (!is_at_end()) {
|
|
start = current;
|
|
scan_token();
|
|
}
|
|
|
|
tokens.push_back(Token(TokenType::EOFILE, "", Object{}, line));
|
|
return tokens;
|
|
}
|
|
|
|
bool Scanner::is_at_end() {
|
|
return current >= code.size();
|
|
}
|
|
|
|
void Scanner::scan_token() {
|
|
char c = advance();
|
|
switch (c) {
|
|
case '(': add_token(TokenType::LEFT_PAREN); break;
|
|
case ')': add_token(TokenType::RIGHT_PAREN); break;
|
|
case '{': add_token(TokenType::LEFT_BRACE); break;
|
|
case '}': add_token(TokenType::RIGHT_BRACE); break;
|
|
case ',': add_token(TokenType::COMMA); break;
|
|
case '.': add_token(TokenType::DOT); break;
|
|
case '-': add_token(TokenType::MINUS); break;
|
|
case '+': add_token(TokenType::PLUS); break;
|
|
case ';': add_token(TokenType::SEMICOLON); break;
|
|
case '*': add_token(TokenType::STAR); break;
|
|
case '!':
|
|
add_token(match('=') ? TokenType::BANG_EQUAL : TokenType::BANG);
|
|
break;
|
|
case '=':
|
|
add_token(match('=') ? TokenType::EQUAL_EQUAL : TokenType::EQUAL);
|
|
break;
|
|
case '<':
|
|
add_token(match('=') ? TokenType::LESS_EQUAL : TokenType::LESS);
|
|
break;
|
|
case '>':
|
|
add_token(match('=') ? TokenType::GREATER_EQUAL : TokenType::GREATER);
|
|
break;
|
|
case '/':
|
|
if (match('/')) {
|
|
while (peek() != '\n' && !is_at_end()) {
|
|
advance();
|
|
}
|
|
} else {
|
|
add_token(TokenType::SLASH);
|
|
}
|
|
|
|
break;
|
|
case ' ':
|
|
case '\r':
|
|
case '\t':
|
|
break;
|
|
case '\n':
|
|
++line;
|
|
break;
|
|
case '"':
|
|
string();
|
|
break;
|
|
default:
|
|
error_handler.error(line, "Unexpected character.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
char Scanner::advance() {
|
|
return code.at(current++);
|
|
}
|
|
|
|
bool Scanner::match(char expected) {
|
|
if (is_at_end() || peek() != expected) {
|
|
return false;
|
|
}
|
|
|
|
current++;
|
|
return true;
|
|
}
|
|
|
|
char Scanner::peek() {
|
|
if (is_at_end()) {
|
|
return '\0';
|
|
}
|
|
|
|
return code.at(current);
|
|
}
|
|
|
|
void Scanner::add_token(TokenType type) {
|
|
add_token(type, Object{});
|
|
}
|
|
|
|
void Scanner::add_token(TokenType type, Object literal) {
|
|
std::string text = code.substr(start, current - start);
|
|
tokens.push_back(Token(type, text, literal, line));
|
|
}
|
|
|
|
void Scanner::string() {
|
|
while (peek() != '"' && !is_at_end()) {
|
|
if (peek() == '\n') line++;
|
|
advance();
|
|
}
|
|
|
|
if (is_at_end()) {
|
|
error_handler.error(line, "Unterminated string.");
|
|
return;
|
|
}
|
|
|
|
// The closing ".
|
|
advance();
|
|
|
|
// Trim the surrounding quotes.
|
|
std::string value = code.substr(start + 1, current - 1);
|
|
add_token(TokenType::STRING, Object(StringObjectType::LITERAL, value));
|
|
}
|