Skip to content

Commit

Permalink
#74 version that builds
Browse files Browse the repository at this point in the history
  • Loading branch information
dibyendumajumdar committed Sep 6, 2021
1 parent 40e1879 commit dbc63cb
Show file tree
Hide file tree
Showing 9 changed files with 747 additions and 5 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ set(SRCS
src/ravi_binding.c
src/chibicc_tokenize.c
src/chibicc_parse.c
src/chibicc_type.c
src/chibicc_strings.c
src/chibicc_unicode.c
src/chibicc_hashmap.c
)

message("SOURCE dir is ${RaviCompiler_SOURCE_DIR}")
Expand Down Expand Up @@ -130,6 +134,13 @@ target_include_directories(tgraph
PRIVATE "${RaviCompiler_SOURCE_DIR}/src"
PRIVATE "${RaviCompiler_SOURCE_DIR}/include")

add_executable(tchibicc tests/tchibicc.c)
target_link_libraries(tchibicc ravicomp)
target_include_directories(tchibicc
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}"
PRIVATE "${RaviCompiler_SOURCE_DIR}/src"
PRIVATE "${RaviCompiler_SOURCE_DIR}/include")

install(FILES ${PUBLIC_HEADERS}
DESTINATION include/ravicomp)
install(TARGETS ravicomp
Expand Down
8 changes: 7 additions & 1 deletion src/chibicc.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#ifdef _WIN32
# define noreturn
# define strncasecmp strnicmp
# define strndup _strndup
#endif

typedef struct Type Type;
Expand Down Expand Up @@ -416,7 +417,12 @@ void add_type(Node *node);
//

void codegen(Obj *prog, FILE *out);
int align_to(int n, int align);
// Round up `n` to the nearest multiple of `align`. For instance,
// align_to(5, 8) returns 8 and align_to(11, 8) returns 16.
static inline int align_to(int n, int align) {
return (n + align - 1) / align * align;
}


//
// unicode.c
Expand Down
167 changes: 167 additions & 0 deletions src/chibicc_hashmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// This is an implementation of the open-addressing hash table.

#include "chibicc.h"

// Initial hash bucket size
#define INIT_SIZE 16

// Rehash if the usage exceeds 70%.
#define HIGH_WATERMARK 70

// We'll keep the usage below 50% after rehashing.
#define LOW_WATERMARK 50

// Represents a deleted hash entry
#define TOMBSTONE ((void *)-1)

static uint64_t fnv_hash(char *s, int len) {
uint64_t hash = 0xcbf29ce484222325;
for (int i = 0; i < len; i++) {
hash *= 0x100000001b3;
hash ^= (unsigned char)s[i];
}
return hash;
}

// Make room for new entires in a given hashmap by removing
// tombstones and possibly extending the bucket size.
static void rehash(HashMap *map) {
// Compute the size of the new hashmap.
int nkeys = 0;
for (int i = 0; i < map->capacity; i++)
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE)
nkeys++;

int cap = map->capacity;
while ((nkeys * 100) / cap >= LOW_WATERMARK)
cap = cap * 2;
assert(cap > 0);

// Create a new hashmap and copy all key-values.
HashMap map2 = {0};
map2.buckets = calloc(cap, sizeof(HashEntry));
map2.capacity = cap;

for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[i];
if (ent->key && ent->key != TOMBSTONE)
hashmap_put2(&map2, ent->key, ent->keylen, ent->val);
}

assert(map2.used == nkeys);
*map = map2;
}

static bool match(HashEntry *ent, char *key, int keylen) {
return ent->key && ent->key != TOMBSTONE &&
ent->keylen == keylen && memcmp(ent->key, key, keylen) == 0;
}

static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
if (!map->buckets)
return NULL;

uint64_t hash = fnv_hash(key, keylen);

for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
if (match(ent, key, keylen))
return ent;
if (ent->key == NULL)
return NULL;
}
unreachable();
}

static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {
if (!map->buckets) {
map->buckets = calloc(INIT_SIZE, sizeof(HashEntry));
map->capacity = INIT_SIZE;
} else if ((map->used * 100) / map->capacity >= HIGH_WATERMARK) {
rehash(map);
}

uint64_t hash = fnv_hash(key, keylen);

for (int i = 0; i < map->capacity; i++) {
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];

if (match(ent, key, keylen))
return ent;

if (ent->key == TOMBSTONE) {
ent->key = key;
ent->keylen = keylen;
return ent;
}

if (ent->key == NULL) {
ent->key = key;
ent->keylen = keylen;
map->used++;
return ent;
}
}
unreachable();
}

void *hashmap_get(HashMap *map, char *key) {
return hashmap_get2(map, key, strlen(key));
}

void *hashmap_get2(HashMap *map, char *key, int keylen) {
HashEntry *ent = get_entry(map, key, keylen);
return ent ? ent->val : NULL;
}

void hashmap_put(HashMap *map, char *key, void *val) {
hashmap_put2(map, key, strlen(key), val);
}

void hashmap_put2(HashMap *map, char *key, int keylen, void *val) {
HashEntry *ent = get_or_insert_entry(map, key, keylen);
ent->val = val;
}

void hashmap_delete(HashMap *map, char *key) {
hashmap_delete2(map, key, strlen(key));
}

void hashmap_delete2(HashMap *map, char *key, int keylen) {
HashEntry *ent = get_entry(map, key, keylen);
if (ent)
ent->key = TOMBSTONE;
}

#if 0
void hashmap_test(void) {
HashMap *map = calloc(1, sizeof(HashMap));

for (int i = 0; i < 5000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 1000; i < 2000; i++)
hashmap_delete(map, format("key %d", i));
for (int i = 1500; i < 1600; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);

for (int i = 0; i < 1000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 1000; i < 1500; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 1500; i < 1600; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 1600; i < 2000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 2000; i < 5000; i++)
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
for (int i = 5000; i < 6000; i++)
assert(hashmap_get(map, "no such key") == NULL);
for (int i = 6000; i < 7000; i++)
hashmap_put(map, format("key %d", i), (void *)(size_t)i);

assert(hashmap_get(map, "no such key") == NULL);
printf("OK\n");
}
#endif
15 changes: 12 additions & 3 deletions src/chibicc_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ static int align_down(int n, int align) {
return align_to(n - align + 1, align);
}

static char *str_dup(const char *temp, size_t len) {
char *p = (char *) calloc(1, len+1);
strncpy(p, temp, len+1);
return p;
}

static void enter_scope(void) {
Scope *sc = calloc(1, sizeof(Scope));
sc->next = scope;
Expand Down Expand Up @@ -326,7 +332,10 @@ static Obj *new_gvar(char *name, Type *ty) {

static char *new_unique_name(void) {
static int id = 0;
return format(".L..%d", id++);
char temp[64];

snprintf(temp, sizeof temp, ".L..%d", id++);
return str_dup(temp, strlen(temp));
}

static Obj *new_anon_gvar(Type *ty) {
Expand All @@ -342,7 +351,7 @@ static Obj *new_string_literal(char *p, Type *ty) {
static char *get_ident(Token *tok) {
if (tok->kind != TK_IDENT)
error_tok(tok, "expected an identifier");
return strndup(tok->loc, tok->len);
return str_dup(tok->loc, tok->len);
}

static Type *find_typedef(Token *tok) {
Expand Down Expand Up @@ -1745,7 +1754,7 @@ static Node *stmt(Token **rest, Token *tok) {

if (tok->kind == TK_IDENT && equal(tok->next, ":")) {
Node *node = new_node(ND_LABEL, tok);
node->label = strndup(tok->loc, tok->len);
node->label = str_dup(tok->loc, tok->len);
node->unique_label = new_unique_name();
node->lhs = stmt(rest, tok->next->next);
node->goto_next = labels;
Expand Down
33 changes: 33 additions & 0 deletions src/chibicc_strings.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "chibicc.h"

void strarray_push(StringArray *arr, char *s) {
if (!arr->data) {
arr->data = calloc(8, sizeof(char *));
arr->capacity = 8;
}

if (arr->capacity == arr->len) {
arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
arr->capacity *= 2;
for (int i = arr->len; i < arr->capacity; i++)
arr->data[i] = NULL;
}

arr->data[arr->len++] = s;
}

#if 0
// Takes a printf-style format string and returns a formatted string.
char *format(char *fmt, ...) {
char *buf;
size_t buflen;
FILE *out = open_memstream(&buf, &buflen);

va_list ap;
va_start(ap, fmt);
vfprintf(out, fmt, ap);
va_end(ap);
fclose(out);
return buf;
}
#endif
5 changes: 4 additions & 1 deletion src/chibicc_tokenize.c
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ static char *read_file(char *path) {
fclose(out);
return buf;
}
#endif

File **get_input_files(void) {
return input_files;
Expand All @@ -687,7 +688,7 @@ File *new_file(char *name, int file_no, char *contents) {
file->contents = contents;
return file;
}
#endif


// Replaces \r or \r\n with \n.
static void canonicalize_newline(char *p) {
Expand Down Expand Up @@ -777,12 +778,14 @@ static void convert_universal_chars(char *p) {
*q = '\0';
}

#if 0
Token *tokenize_file(char *path) {
char *p = read_file(path);
if (!p)
return NULL;
return tokenize_buffer(p);
}
#endif

Token *tokenize_buffer(char *p) {
if (!p)
Expand Down
Loading

0 comments on commit dbc63cb

Please sign in to comment.