Complete Scanner
This commit is contained in:
		@@ -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:
 | 
				
			||||||
 | 
					      if (is_digit(c)) {
 | 
				
			||||||
 | 
					        number();
 | 
				
			||||||
 | 
					      } else if(is_alpha(c)) {
 | 
				
			||||||
 | 
					        identifier();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
        error_handler.error(line, "Unexpected character.");
 | 
					        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;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user