diff options
Diffstat (limited to 'lexer.c')
| -rw-r--r-- | lexer.c | 269 |
1 files changed, 269 insertions, 0 deletions
@@ -0,0 +1,269 @@ +#include "lexer.h" +#include <stdlib.h> +#include <ctype.h> +#include <stdio.h> + +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; +} |
