diff --git a/cclox_src/scanner.cc b/cclox_src/scanner.cc index dbc0a1d..2bd0668 100644 --- a/cclox_src/scanner.cc +++ b/cclox_src/scanner.cc @@ -2,10 +2,32 @@ #include "token.hh" #include "error_handler.hh" #include "object.hh" +#include #include extern ErrorHandler error_handler; +Scanner::Scanner(const std::string &code) : code{code}, tokens{}, start{0}, current{0}, line{1} { + keywords = { + std::pair("and", TokenType::AND), + std::pair("class", TokenType::CLASS), + std::pair("else", TokenType::ELSE), + std::pair("false", TokenType::FALSE), + std::pair("for", TokenType::FOR), + std::pair("fun", TokenType::FUN), + std::pair("if", TokenType::IF), + std::pair("nil", TokenType::NIL), + std::pair("or", TokenType::OR), + std::pair("print", TokenType::PRINT), + std::pair("return", TokenType::RETURN), + std::pair("super", TokenType::SUPER), + std::pair("this", TokenType::THIS), + std::pair("true", TokenType::TRUE), + std::pair("var", TokenType::VAR), + std::pair("while", TokenType::WHILE), + }; +} + std::vector Scanner::scan_tokens() { while (!is_at_end()) { start = current; @@ -20,6 +42,18 @@ bool Scanner::is_at_end() { 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() { char c = advance(); switch (c) { @@ -66,7 +100,14 @@ void Scanner::scan_token() { string(); break; 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; } } @@ -92,6 +133,14 @@ char Scanner::peek() { 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) { 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); 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)); + } +} diff --git a/cclox_src/scanner.hh b/cclox_src/scanner.hh index fb9b0e2..e819094 100644 --- a/cclox_src/scanner.hh +++ b/cclox_src/scanner.hh @@ -3,20 +3,29 @@ #include "token.hh" #include #include +#include +#include struct Scanner { - Scanner(const std::string &code) : code{code}, tokens{}, start{0}, current{0}, line{1} {}; + Scanner(const std::string &code); std::vector scan_tokens(); bool is_at_end(); + bool is_digit(char c); + bool is_alpha(char c); + bool is_alphanumeric(char c); void scan_token(); char advance(); bool match(char expected); char peek(); + char peek_next(); void add_token(TokenType type); void add_token(TokenType type, Object literal); void string(); + void number(); + void identifier(); std::string code; std::vector tokens; std::size_t start, current, line; + std::unordered_map keywords; };