summaryrefslogtreecommitdiff
path: root/lexer.c
diff options
context:
space:
mode:
Diffstat (limited to 'lexer.c')
-rw-r--r--lexer.c127
1 files changed, 121 insertions, 6 deletions
diff --git a/lexer.c b/lexer.c
index 87e146a..8639f91 100644
--- a/lexer.c
+++ b/lexer.c
@@ -2,6 +2,97 @@
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
+#include <string.h>
+
+struct keywords_cell {
+ token_type type;
+ struct keywords_cell *next;
+ char *keyword;
+ size_t keyword_length;
+};
+
+static struct keywords_cell *keywords[TOKEN_VOLATILE - TOKEN_IF] = {0};
+
+static size_t hash_keyword(char *keyword, size_t length)
+{
+ size_t sum = 0;
+ for (size_t i=0; i < length; i++) {
+ sum += (uint8_t) keyword[i];
+ }
+
+ return sum % (TOKEN_VOLATILE - TOKEN_IF);
+}
+
+static void insert_keyword(char *keyword, size_t length, token_type type)
+{
+ struct keywords_cell *next = keywords[hash_keyword(keyword, length)];
+ if (!next) {
+ keywords[hash_keyword(keyword, length)] = calloc(1, sizeof(struct keywords_cell));
+ keywords[hash_keyword(keyword, length)]->keyword = keyword;
+ keywords[hash_keyword(keyword, length)]->keyword_length = length;
+ keywords[hash_keyword(keyword, length)]->type = type;
+ keywords[hash_keyword(keyword, length)]->next = NULL;
+ return;
+ }
+
+ while (next->next) {
+ next = next->next;
+ }
+
+ next->next = calloc(1, sizeof(struct keywords_cell));
+ next->next->keyword = keyword;
+ next->next->keyword_length = length;
+ next->next->type = type;
+ next->next->next = NULL;
+}
+
+static token_type get_keyword(char *keyword, size_t length)
+{
+ struct keywords_cell *cell = keywords[hash_keyword(keyword, length)];
+ if (!cell) return 0;
+ if (cell->next == NULL) return cell->type;
+ while (cell->next != NULL) {
+ if (cell->keyword_length != length) {
+ cell = cell->next;
+ continue;
+ }
+ if (strncmp(cell->keyword, keyword, length) == 0) {
+ return cell->type;
+ }
+ cell = cell->next;
+ }
+
+ if (strncmp(cell->keyword, keyword, length) == 0) {
+ return cell->type;
+ }
+
+ return 0;
+}
+
+static void populate_keywords(void)
+{
+ insert_keyword("if", 2, TOKEN_IF);
+ insert_keyword("else", 4, TOKEN_ELSE);
+ insert_keyword("while", 5, TOKEN_WHILE);
+ insert_keyword("for", 3, TOKEN_FOR);
+ insert_keyword("break", 5, TOKEN_BREAK);
+ insert_keyword("case", 4, TOKEN_CASE);
+ insert_keyword("const", 5, TOKEN_CONST);
+ insert_keyword("do", 2, TOKEN_DO);
+ insert_keyword("enum", 4, TOKEN_ENUM);
+ insert_keyword("extern", 6, TOKEN_EXTERN);
+ insert_keyword("goto", 4, TOKEN_GOTO);
+ insert_keyword("inline", 6, TOKEN_INLINE);
+ insert_keyword("return", 6, TOKEN_RETURN);
+ insert_keyword("signed", 6, TOKEN_SIGNED);
+ insert_keyword("unsigned", 8, TOKEN_UNSIGNED);
+ insert_keyword("static", 6, TOKEN_STATIC);
+ insert_keyword("struct", 6, TOKEN_STRUCT);
+ insert_keyword("switch", 6, TOKEN_SWITCH);
+ insert_keyword("typedef", 7, TOKEN_TYPEDEF);
+ insert_keyword("union", 5, TOKEN_UNION);
+ insert_keyword("volatile", 8, TOKEN_VOLATILE);
+}
static token *token_create(char *lexeme, size_t length, token_type type)
{
@@ -151,24 +242,34 @@ size_t check_symbol(char *src, size_t index, token **last)
}
case '{':
token_add(last, token_create(src+index, 1, TOKEN_LCURLY));
+ return 1;
case '}':
token_add(last, token_create(src+index, 1, TOKEN_RCURLY));
+ return 1;
case '(':
token_add(last, token_create(src+index, 1, TOKEN_LPAREN));
+ return 1;
case ')':
token_add(last, token_create(src+index, 1, TOKEN_RPAREN));
+ return 1;
case '[':
token_add(last, token_create(src+index, 1, TOKEN_LSQUARE));
+ return 1;
case ']':
token_add(last, token_create(src+index, 1, TOKEN_RSQUARE));
+ return 1;
case ':':
token_add(last, token_create(src+index, 1, TOKEN_COLON));
+ return 1;
case ';':
token_add(last, token_create(src+index, 1, TOKEN_SEMICOLON));
+ return 1;
case ',':
token_add(last, token_create(src+index, 1, TOKEN_COMMA));
+ return 1;
case '.':
token_add(last, token_create(src+index, 1, TOKEN_DOT));
+ return 1;
default:
return 0;
@@ -177,10 +278,18 @@ size_t check_symbol(char *src, size_t index, token **last)
token *lexer_parse(char *src)
{
+ populate_keywords();
size_t index = 0;
token *head = token_create(src, 0, TOKEN_HEAD);
token *last = head;
+ size_t row = 1, col = 1;
while (src[index] != '\0') {
+ if (src[index] == '\n') {
+ index++;
+ col++;
+ row = 1;
+ continue;
+ }
if (isspace(src[index])) {
index++;
continue;
@@ -194,7 +303,7 @@ token *lexer_parse(char *src)
if (src[index] == '\'') {
if (src[index+1] != '\\' && src[index+2] != '\'') {
- // TODO: error
+ fprintf(stderr, "%zu:%zu: invalid character\n", row, col);
return NULL;
}
token_add(&last, token_create(src+index+1, 1, TOKEN_CHAR));
@@ -208,7 +317,7 @@ token *lexer_parse(char *src)
size_t string_length = index;
while (src[index++] != '\"') {
if (src[index] == '\0') {
- // TODO: error
+ fprintf(stderr, "%zu:%zu: unterminated string\n", row, col);
return NULL;
}
}
@@ -224,7 +333,13 @@ token *lexer_parse(char *src)
index++;
}
identifier_length = index - identifier_length;
- token_add(&last, token_create(identifier_start, identifier_length, TOKEN_IDENTIFIER));
+
+ token_type keyword = get_keyword(identifier_start, identifier_length);
+ if (keyword == 0) {
+ token_add(&last, token_create(identifier_start, identifier_length, TOKEN_IDENTIFIER));
+ } else {
+ token_add(&last, token_create(identifier_start, identifier_length, keyword));
+ }
continue;
}
@@ -233,7 +348,7 @@ token *lexer_parse(char *src)
size_t number_length = index;
uint8_t is_float = 0;
- if (src[index] == '0' && !isdigit(src[index+1]) && src[index+1] != '.') {
+ if (src[index] == '0' && !isdigit(src[index+1]) && src[index+1] != '.' && (isdigit(src[index+2]) || ((src[index+2] >= 65 && src[index+2] <= 70) && (src[index+2] >= 97 && src[index+2] <= 102)))) {
if (src[index+1] == 'x') {
index += 2;
} else if (src[index+1] == 'o') {
@@ -241,7 +356,7 @@ token *lexer_parse(char *src)
} else if (src[index+1] == 'b') {
index += 2;
} else {
- // TODO: error
+ fprintf(stderr, "%zu:%zu: invalid integer\n", row, col);
return NULL;
}
}
@@ -249,7 +364,7 @@ token *lexer_parse(char *src)
while (isdigit(src[index]) || src[index] == '.') {
if (src[index] == '.') {
if (is_float) {
- // TODO: error
+ fprintf(stderr, "%zu:%zu: invalid float\n", row, col);
return NULL;
}
is_float = 1;