void *sbArena_alloc(hArena arena, usize size) {
while (size % ALIGN != 0) size++;
- if (size > arena->current->capacity - arena->current->used) {
- /* not enough space in current block. need to move to next block or allocate a new one */
- if (arena->current != arena->last) {
- /* move to next block */
- if (arena->current->next) {
- arena->current = arena->current->next;
- } else {
- PANIC("lost track of memory block in arena somehow; should not happen");
- }
+ if (arena->current->used > arena->current->capacity) {
+ PANIC("somehow arena values are out of sync");
+ }
+
+ while (arena->current != arena->last && size > arena->current->capacity - arena->current->used) {
+ /* move to next block until we find one that fits */
+ if (arena->current->next) {
+ arena->current = arena->current->next;
} else {
- /* need to allocate a new block */
- usize new_capacity = arena->current->capacity;
- if (size > new_capacity) new_capacity = size;
- struct block *block = calloc(sizeof(struct block) + new_capacity, 1);
- block->capacity = new_capacity;
- block->next = NULL;
-
- arena->current->next = block;
- arena->current = arena->last = block;
+ PANIC("lost track of memory block in arena somehow; should not happen");
}
}
+ if (size > arena->current->capacity - arena->current->used) {
+ /* if still doesn't fit, we must be at the end, need to allocate a new block */
+ usize new_capacity = arena->current->capacity;
+ if (size > new_capacity) new_capacity = size;
+ struct block *block = calloc(sizeof(struct block) + new_capacity, 1);
+ block->capacity = new_capacity;
+ block->next = NULL;
+
+ arena->current->next = block;
+ arena->current = arena->last = block;
+ }
+
void *allocated_ptr = &arena->current->data[arena->current->used];
arena->current->used += size;
memset(allocated_ptr, 0, size);
* which have different semantics. */
#define MEM_BLOCK_SIZE 65536
+#define TOKEN_BUFFER_SIZE 256
typedef struct sbScanner {
hFileReader file_reader;
return c == ' ' || c == '\t' || c == '\r';
}
-flag accept_char(char expected, hFileReader fr) {
- char actual = sbFileReader_peek(fr);
- if (expected == actual) {
- sbFileReader_next(fr);
- return 1;
+flag is_start_identifier(char c) {
+ return is_alpha(c);
+}
+
+flag is_mid_identifier(char c) {
+ return is_start_identifier(c) || is_digit(c);
+}
+
+flag is_end_identifier(char c) {
+ return is_mid_identifier(c) || c == '?';
+}
+
+flag is_base_digit(char c, int base) {
+ if (base == 10) {
+ return is_digit(c);
+ } else if (base == 16) {
+ return is_digit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+ } else if (base == 8) {
+ return '0' <= c && c <= '7';
+ } else if (base == 2) {
+ return '0' <= c && c <= '1';
} else {
return 0;
}
}
-char accept_digit(hFileReader fr) {
- char actual_char = sbFileReader_peek(fr);
- if (is_digit(actual_char)) {
- sbFileReader_next(fr);
- return actual_char;
+int base_digit_value(char c) {
+ if (is_digit(c)) {
+ return c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ return c - 'a' + 10;
+ } else if ('A' <= c && c <= 'Z') {
+ return c - 'A' + 10;
} else {
return 0;
}
}
-char accept_alpha(hFileReader fr) {
- char actual_char = sbFileReader_peek(fr);
- if (is_alpha(actual_char)) {
- sbFileReader_next(fr);
- return actual_char;
- } else {
- return 0;
+#define NEXT sbFileReader_next(sc->file_reader)
+#define PEEK sbFileReader_peek(sc->file_reader)
+
+usize read_identifier(hScanner sc, char *token_buffer, usize max_size) {
+ usize token_size = 0;
+ char ch = 0;
+
+ do {
+ token_buffer[token_size] = NEXT;
+ token_size ++;
+ ch = PEEK;
+ } while (is_mid_identifier(ch) && token_size < max_size - 1);
+
+ if (is_end_identifier(ch) && token_size < max_size - 1) {
+ token_buffer[token_size] = NEXT;
+ token_size ++;
}
+
+ token_buffer[token_size] = '\0';
+
+ return token_size;
}
sbLexToken compute_next_token(hScanner sc) {
- char ch = sbFileReader_peek(sc->file_reader);
+ int next = PEEK;
+ char ch = (char)next;
- char token_buffer[256];
- int token_size = 0;
+ char token_buffer[TOKEN_BUFFER_SIZE];
+ usize token_size;
sbLexToken new_token = {0};
- if (ch == EOF) {
+ if (next == EOF) {
new_token.type = T_EOF;
} else if (ch == '\n') {
new_token.type = T_NEWLINE;
/* skip all spaces after the newline */
do {
- sbFileReader_next(sc->file_reader);
- } while (is_space(sbFileReader_peek(sc->file_reader)));
+ NEXT;
+ } while (is_space(PEEK));
+ } else if (ch == '#') {
+ /* Comment. Ignore everything until the end of the line. */
+ do {
+ NEXT;
+ ch = PEEK;
+ } while (ch != '\n');
+ NEXT; /* eat the newline */
+ new_token.type = T_NEWLINE;
+ } else if (ch == '(' || ch == ')'
+ || ch == '[' || ch == ']'
+ || ch == '{' || ch == '}'
+ || ch == ';' || ch == '|'
+ || ch == '.' || ch == ','
+ || ch == '\\') {
+ /* unambiguously single-character tokens */
+ new_token.type = ch;
+ NEXT;
+ } else if (ch == '%') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '=') {
+ new_token.type = T_PERCENTEQUALS;
+ } else {
+ new_token.type = T_PERCENT;
+ }
+ } else if (ch == '/') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '/') {
+ new_token.type = T_DOUBLESLASH;
+ NEXT;
+ } else if (ch == '=') {
+ new_token.type = T_SLASHEQUALS;
+ NEXT;
+ } else {
+ new_token.type = T_SLASH;
+ }
+ } else if (ch == '*') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '*') {
+ new_token.type = T_DOUBLEASTERISK;
+ NEXT;
+ } else if (ch == '=') {
+ new_token.type = T_ASTERISKEQUALS;
+ NEXT;
+ } else {
+ new_token.type = T_ASTERISK;
+ }
+ } else if (ch == '=') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '=') {
+ new_token.type = T_DOUBLEEQUALS;
+ NEXT;
+ } else if (ch == '>') {
+ new_token.type = T_FATARROW;
+ NEXT;
+ } else {
+ new_token.type = T_EQUALS;
+ }
+ } else if (ch == '+') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '+') {
+ new_token.type = T_DOUBLEPLUS;
+ NEXT;
+ } else if (ch == '=') {
+ new_token.type = T_PLUSEQUALS;
+ NEXT;
+ } else {
+ new_token.type = T_PLUS;
+ }
+ } else if (ch == '-') {
+ NEXT;
+ ch = PEEK;
+ if (ch == '-') {
+ new_token.type = T_DOUBLEMINUS;
+ NEXT;
+ } else if (ch == '>') {
+ new_token.type = T_ARROW;
+ NEXT;
+ } else if (ch == '=') {
+ new_token.type = T_MINUSEQUALS;
+ NEXT;
+ } else {
+ new_token.type = T_MINUS;
+ }
+ } else if (ch == ':') {
+ NEXT;
+ ch = PEEK;
+ if (ch == ':') {
+ /* :: */
+ new_token.type = T_PAAMAYIM_NEKUDOTAYIM;
+ } else if (ch == '{') {
+ /* :{ */
+ new_token.type = T_COLONBRACE;
+ } else if (is_start_identifier(ch)) {
+ /* :abc... */
+ new_token.type = T_SYMBOL;
+
+ token_size = read_identifier(sc, token_buffer, TOKEN_BUFFER_SIZE);
+
+ char *storage = sbArena_alloc(sc->arena, token_size + 1);
+
+ sbstrncpy(storage, token_buffer, token_size + 1);
+
+ new_token.str = storage;
+ new_token.size = token_size;
+ } else {
+ /* : */
+ new_token.type = T_COLON;
+ }
} else if (is_space(ch)) {
new_token.type = T_SPACE;
/* skip all subsequent spaces */
do {
- sbFileReader_next(sc->file_reader);
- } while (is_space(sbFileReader_peek(sc->file_reader)));
+ NEXT;
+ } while (is_space(PEEK));
+
+ /* if we run into a comment, skip to the end of the line */
+ if (ch == '#') {
+ do {
+ NEXT;
+ } while (PEEK != '\n');
+ }
/* if we run into a newline, forget about the spaces */
- if (sbFileReader_peek(sc->file_reader) == '\n') {
+ if (PEEK == '\n') {
new_token.type = T_NEWLINE;
/* and skip all spaces after the newline */
do {
- sbFileReader_next(sc->file_reader);
- } while (is_space(sbFileReader_peek(sc->file_reader)));
+ NEXT;
+ } while (is_space(PEEK));
}
- } else if (is_alpha(ch)) {
+ } else if (is_start_identifier(ch)) {
new_token.type = T_IDENTIFIER;
- do {
- token_buffer[token_size] = sbFileReader_next(sc->file_reader);
- token_size ++;
- ch = sbFileReader_peek(sc->file_reader);
- } while (is_alpha(ch) || is_digit(ch));
-
- /* TODO: I am sleepy. Please check that this has not overflowed the buffer. */
-
- token_buffer[token_size] = '\0';
+ token_size = read_identifier(sc, token_buffer, TOKEN_BUFFER_SIZE);
char *storage = sbArena_alloc(sc->arena, token_size + 1);
- mystrncpy(storage, token_buffer, token_size + 1);
+ sbstrncpy(storage, token_buffer, token_size + 1);
new_token.str = storage;
+ new_token.size = token_size;
} else if (is_digit(ch)) {
new_token.type = T_INTEGER;
- /* TODO: yes, yes. this isn't correct. listen. i am tired. */
- i64 intval = ch - '0';
+ i64 intval = 0;
+ int base = 10;
+
+ if (ch == '0') {
+ NEXT;
+ ch = PEEK;
+ if (ch == 'b') {
+ NEXT;
+ ch = PEEK;
+ base = 2;
+ } else if (ch == 'o') {
+ NEXT;
+ ch = PEEK;
+ base = 8;
+ } else if (ch == 'x') {
+ NEXT;
+ ch = PEEK;
+ base = 16;
+ }
+ }
- while (is_digit(sbFileReader_peek(sc->file_reader))) {
- ch = sbFileReader_next(sc->file_reader);
- intval *= 10;
- intval += ch - '0';
+ do {
+ /* TODO: promote to bigint, don't allow overflow */
+ NEXT;
+ intval *= base;
+ intval += base_digit_value(ch);
+ ch = PEEK;
+ } while (is_base_digit(ch, base));
+
+ /* if we are now looking at still a character that's a letter or digit, throw error */
+ if (is_digit(ch) || is_alpha(ch)) {
+ if (base == 10) {
+ fprintf(stderr, "unexpected character in numeric literal: '%c'\n", ch);
+ } else {
+ fprintf(stderr, "unexpected character in base %d numeric literal: '%c'\n", base, ch);
+ }
+ new_token.type = T_ERROR;
+ NEXT;
+ } else {
+ new_token.i = intval;
}
} else {
new_token.type = T_ERROR;
- switch (ch) {
- case '(':
- case ')':
- case '.':
- /* TODO ok blah blah this isn't right */
- new_token.type = ch;
- break;
- default:
- fprintf(stderr, "don't know how to process character: '%c'\n", ch);
- }
+ fprintf(stderr, "don't know how to process character: '%c'\n", ch);
- sbFileReader_next(sc->file_reader);
+ NEXT;
}
return new_token;