#include "lexer.h" #include #include #include static token *token_create(char *lexeme, size_t length, token_type type) { token *t = calloc(1, sizeof(token)); t->lexeme = lexeme; t->length = length; t->type = type; return t; } static void token_add(token **t, token *new) { if (t) { (*t)->next = new; new->prev = (*t); } *t = new; } size_t check_symbol(char *src, size_t index, token **last) { switch(src[index]) { case '+': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_PLUS_EQ)); return 2; } else if (src[index+1] == '+') { token_add(last, token_create(src+index, 2, TOKEN_PLUS_PLUS)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_PLUS)); return 1; } } case '-': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_MINUS_EQ)); return 2; } else if (src[index+1] == '-') { token_add(last, token_create(src+index, 2, TOKEN_MINUS_MINUS)); return 2; } else if (src[index+1] == '>') { token_add(last, token_create(src+index, 2, TOKEN_ARROW)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_MINUS)); return 1; } } case '/': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_SLASH_EQ)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_SLASH)); return 1; } } case '*': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_STAR_EQ)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_STAR)); return 1; } } case '>': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_GREATER_EQ)); return 2; } else if (src[index+1] == '>') { if (src[index+2] == '=') { token_add(last, token_create(src+index, 2, TOKEN_RSHIFT_EQ)); return 2; } else { token_add(last, token_create(src+index, 2, TOKEN_RSHIFT)); return 2; } } else { token_add(last, token_create(src+index, 1, TOKEN_GREATER)); return 1; } } case '<': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_LESS_EQ)); return 2; } else if (src[index+1] == '<') { if (src[index+2] == '=') { token_add(last, token_create(src+index, 2, TOKEN_LSHIFT_EQ)); return 2; } else { token_add(last, token_create(src+index, 2, TOKEN_LSHIFT)); return 2; } } else { token_add(last, token_create(src+index, 1, TOKEN_LESS)); return 1; } } case '!': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_NOT_EQ)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_NOT)); return 1; } } case '=': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_EQUAL)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_ASSIGN)); return 1; } } case '|': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_BOR_EQ)); return 2; } else if (src[index+1] == '|') { token_add(last, token_create(src+index, 2, TOKEN_OR)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_BOR)); return 1; } } case '^': { if (src[index+1] == '=') { token_add(last, token_create(src+index, 2, TOKEN_XOR_EQ)); return 2; } else { token_add(last, token_create(src+index, 1, TOKEN_XOR)); return 1; } } case '{': token_add(last, token_create(src+index, 1, TOKEN_LCURLY)); case '}': token_add(last, token_create(src+index, 1, TOKEN_RCURLY)); case '(': token_add(last, token_create(src+index, 1, TOKEN_LPAREN)); case ')': token_add(last, token_create(src+index, 1, TOKEN_RPAREN)); case '[': token_add(last, token_create(src+index, 1, TOKEN_LSQUARE)); case ']': token_add(last, token_create(src+index, 1, TOKEN_RSQUARE)); case ':': token_add(last, token_create(src+index, 1, TOKEN_COLON)); case ';': token_add(last, token_create(src+index, 1, TOKEN_SEMICOLON)); case ',': token_add(last, token_create(src+index, 1, TOKEN_COMMA)); case '.': token_add(last, token_create(src+index, 1, TOKEN_DOT)); default: return 0; } } token *lexer_parse(char *src) { size_t index = 0; token *head = token_create(src, 0, TOKEN_HEAD); token *last = head; while (src[index] != '\0') { if (isspace(src[index])) { index++; continue; } size_t skip = check_symbol(src, index, &last); if (skip) { index += skip; continue; } if (src[index] == '\'') { if (src[index+1] != '\\' && src[index+2] != '\'') { // TODO: error return NULL; } token_add(&last, token_create(src+index+1, 1, TOKEN_CHAR)); index += 3; continue; } if (src[index] == '\"') { index++; char *string_start = src+index; size_t string_length = index; while (src[index++] != '\"') { if (src[index] == '\0') { // TODO: error return NULL; } } string_length = index - string_length - 1; token_add(&last, token_create(string_start, string_length, TOKEN_STRING)); continue; } if (isalpha(src[index]) || src[index] == '_') { char *identifier_start = src+index; size_t identifier_length = index; while (isalnum(src[index]) || src[index] == '_') { index++; } identifier_length = index - identifier_length; token_add(&last, token_create(identifier_start, identifier_length, TOKEN_IDENTIFIER)); continue; } if (isdigit(src[index])) { char *number_start = src+index; size_t number_length = index; uint8_t is_float = 0; if (src[index] == '0' && !isdigit(src[index+1]) && src[index+1] != '.') { if (src[index+1] == 'x') { index += 2; } else if (src[index+1] == 'o') { index += 2; } else if (src[index+1] == 'b') { index += 2; } else { // TODO: error return NULL; } } index++; while (isdigit(src[index]) || src[index] == '.') { if (src[index] == '.') { if (is_float) { // TODO: error return NULL; } is_float = 1; } index++; } number_length = index - number_length; token_add(&last, token_create(number_start, number_length, is_float ? TOKEN_FLOAT : TOKEN_INTEGER)); continue; } index ++; } return head; }