#include #include #include #include #include #include void Lexer::init(char *script) { asprintf(&m_script, "%s", script); m_tokens = (List *) calloc(1, sizeof(List)); m_tokens->init(sizeof(Token)); m_start = 0; m_current = 0; m_end = strlen(m_script); m_line = 1; m_errored = false; } List * Lexer::scan(void) { while (!at_end()) { m_start = m_current; scan_token(); } if (m_errored) return NULL; Token token_eof; token_eof.init(EOFF, "EOF", m_line); m_tokens->add(&token_eof); token_eof.clean(); return m_tokens; } void Lexer::clean(void) { for (size_t i = 0; i < m_tokens->size(); i++) { Token *t = (Token *) m_tokens->get(i); t->clean(); } m_tokens->clean(); free(m_script); } bool Lexer::at_end(void) { return m_current >= m_end; } char Lexer::advance(void) { return m_script[m_current++]; } char Lexer::peek(void) { return m_script[m_current]; } bool Lexer::match(char c) { if (at_end()) return false; if (m_script[m_current] != c) return false; m_current++; return true; } void Lexer::string(void) { while (peek() != '"' && !at_end()) { if (peek() == '\n') m_line++; advance(); } if (at_end()) { printf("[-] Error: Unterminated string in line %lu\n", m_line); return; } int token_length = m_current - m_start - 1; if (token_length == 0) token_length++; char *lexeme; asprintf(&lexeme, "%.*s", token_length, m_script + m_start + 1); Token token; token.init(STRING, lexeme, m_line); m_tokens->add(&token); token.clean(); advance(); } void Lexer::add_token(token_type_e type) { int token_length = m_current - m_start; if (token_length == 0) token_length++; char *lexeme; asprintf(&lexeme, "%.*s", token_length, m_script + m_start); Token token; token.init(type, lexeme, m_line); m_tokens->add(&token); token.clean(); } void Lexer::scan_token(void) { char c = advance(); switch (c) { case '(': add_token(LEFT_PAREN); break; case ')': add_token(RIGHT_PAREN); break; case '{': add_token(LEFT_BRACE); break; case '}': add_token(RIGHT_BRACE); break; case ',': add_token(COMMA); break; case '.': add_token(DOT); break; case '-': add_token(MINUS); break; case '+': add_token(PLUS); break; case ';': add_token(SEMICOLON); break; case '*': add_token(STAR); break; case '!': add_token(match('=') ? BANG_EQUAL : BANG); break; case '=': add_token(match('=') ? EQUAL_EQUAL : EQUAL); break; case '<': add_token(match('=') ? LESS_EQUAL : LESS); break; case '>': add_token(match('=') ? GREATER_EQUAL : GREATER); break; case '"': string(); break; case '/': if (match('/')) while (peek() != '\n' && !at_end()) advance(); else add_token(SLASH); break; case '\n': m_line++; break; case ' ': case '\r': case '\t': break; default: printf("[-] Error: Unexpected character %c in line %lu\n", c, m_line); m_errored = true; break; } }