Complete Scanner
This commit is contained in:
parent
cae1a9347e
commit
dd2b76eea7
@ -2,10 +2,32 @@
|
|||||||
#include "token.hh"
|
#include "token.hh"
|
||||||
#include "error_handler.hh"
|
#include "error_handler.hh"
|
||||||
#include "object.hh"
|
#include "object.hh"
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
extern ErrorHandler error_handler;
|
extern ErrorHandler error_handler;
|
||||||
|
|
||||||
|
Scanner::Scanner(const std::string &code) : code{code}, tokens{}, start{0}, current{0}, line{1} {
|
||||||
|
keywords = {
|
||||||
|
std::pair<std::string, TokenType>("and", TokenType::AND),
|
||||||
|
std::pair<std::string, TokenType>("class", TokenType::CLASS),
|
||||||
|
std::pair<std::string, TokenType>("else", TokenType::ELSE),
|
||||||
|
std::pair<std::string, TokenType>("false", TokenType::FALSE),
|
||||||
|
std::pair<std::string, TokenType>("for", TokenType::FOR),
|
||||||
|
std::pair<std::string, TokenType>("fun", TokenType::FUN),
|
||||||
|
std::pair<std::string, TokenType>("if", TokenType::IF),
|
||||||
|
std::pair<std::string, TokenType>("nil", TokenType::NIL),
|
||||||
|
std::pair<std::string, TokenType>("or", TokenType::OR),
|
||||||
|
std::pair<std::string, TokenType>("print", TokenType::PRINT),
|
||||||
|
std::pair<std::string, TokenType>("return", TokenType::RETURN),
|
||||||
|
std::pair<std::string, TokenType>("super", TokenType::SUPER),
|
||||||
|
std::pair<std::string, TokenType>("this", TokenType::THIS),
|
||||||
|
std::pair<std::string, TokenType>("true", TokenType::TRUE),
|
||||||
|
std::pair<std::string, TokenType>("var", TokenType::VAR),
|
||||||
|
std::pair<std::string, TokenType>("while", TokenType::WHILE),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Token> Scanner::scan_tokens() {
|
std::vector<Token> Scanner::scan_tokens() {
|
||||||
while (!is_at_end()) {
|
while (!is_at_end()) {
|
||||||
start = current;
|
start = current;
|
||||||
@ -20,6 +42,18 @@ bool Scanner::is_at_end() {
|
|||||||
return current >= code.size();
|
return current >= code.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Scanner::is_digit(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scanner::is_alpha(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scanner::is_alphanumeric(char c) {
|
||||||
|
return is_alpha(c) || is_digit(c);
|
||||||
|
}
|
||||||
|
|
||||||
void Scanner::scan_token() {
|
void Scanner::scan_token() {
|
||||||
char c = advance();
|
char c = advance();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@ -66,7 +100,14 @@ void Scanner::scan_token() {
|
|||||||
string();
|
string();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error_handler.error(line, "Unexpected character.");
|
if (is_digit(c)) {
|
||||||
|
number();
|
||||||
|
} else if(is_alpha(c)) {
|
||||||
|
identifier();
|
||||||
|
} else {
|
||||||
|
error_handler.error(line, "Unexpected character.");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,6 +133,14 @@ char Scanner::peek() {
|
|||||||
return code.at(current);
|
return code.at(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char Scanner::peek_next() {
|
||||||
|
if (current + 1 >= code.size()) {
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return code.at(current + 1);
|
||||||
|
}
|
||||||
|
|
||||||
void Scanner::add_token(TokenType type) {
|
void Scanner::add_token(TokenType type) {
|
||||||
add_token(type, Object{});
|
add_token(type, Object{});
|
||||||
}
|
}
|
||||||
@ -121,3 +170,36 @@ void Scanner::string() {
|
|||||||
std::string value = code.substr(no_quote_start, no_quote_end - no_quote_start);
|
std::string value = code.substr(no_quote_start, no_quote_end - no_quote_start);
|
||||||
add_token(TokenType::STRING, Object(StringObjectType::LITERAL, value));
|
add_token(TokenType::STRING, Object(StringObjectType::LITERAL, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scanner::number() {
|
||||||
|
while (is_digit(peek())) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() == '.' && is_digit(peek_next())) {
|
||||||
|
// Consume the "."
|
||||||
|
advance();
|
||||||
|
|
||||||
|
while (is_digit(peek())) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value = code.substr(start, current - start);
|
||||||
|
add_token(TokenType::NUMBER, Object(std::stod(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::identifier() {
|
||||||
|
while (is_alphanumeric(peek())) {
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value = code.substr(start, current - start);
|
||||||
|
auto it = keywords.find(value);
|
||||||
|
if (it != keywords.end()) {
|
||||||
|
TokenType type = it->second;
|
||||||
|
add_token(type);
|
||||||
|
} else {
|
||||||
|
add_token(TokenType::IDENTIFIER, Object(StringObjectType::IDENTIFIER, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,20 +3,29 @@
|
|||||||
#include "token.hh"
|
#include "token.hh"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
struct Scanner {
|
struct Scanner {
|
||||||
Scanner(const std::string &code) : code{code}, tokens{}, start{0}, current{0}, line{1} {};
|
Scanner(const std::string &code);
|
||||||
std::vector<Token> scan_tokens();
|
std::vector<Token> scan_tokens();
|
||||||
bool is_at_end();
|
bool is_at_end();
|
||||||
|
bool is_digit(char c);
|
||||||
|
bool is_alpha(char c);
|
||||||
|
bool is_alphanumeric(char c);
|
||||||
void scan_token();
|
void scan_token();
|
||||||
char advance();
|
char advance();
|
||||||
bool match(char expected);
|
bool match(char expected);
|
||||||
char peek();
|
char peek();
|
||||||
|
char peek_next();
|
||||||
void add_token(TokenType type);
|
void add_token(TokenType type);
|
||||||
void add_token(TokenType type, Object literal);
|
void add_token(TokenType type, Object literal);
|
||||||
void string();
|
void string();
|
||||||
|
void number();
|
||||||
|
void identifier();
|
||||||
|
|
||||||
std::string code;
|
std::string code;
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::size_t start, current, line;
|
std::size_t start, current, line;
|
||||||
|
std::unordered_map<std::string, TokenType> keywords;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user