summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/parser.c93
-rw-r--r--core/state.c6
-rw-r--r--core/symbol.c130
3 files changed, 221 insertions, 8 deletions
diff --git a/core/parser.c b/core/parser.c
index b4f5696..fb8d817 100644
--- a/core/parser.c
+++ b/core/parser.c
@@ -26,6 +26,14 @@
#define tokstr(tok) \
toktab[(tok)->type]
+/* Unexpected token */
+#define utok(tok) \
+ cc_error("unexpected token %s\n", tokstr(tok));
+#define utok1(tok, exp_tt) \
+ cc_error("unexpected token %s, expected %s\n", tokstr(tok), tokstr1(exp_tt))
+
+static int parser_expect(struct cescal_state *state, struct token *res, tt_t exp);
+
/*
* Converts numeric tokens into human readable strings
*/
@@ -58,16 +66,51 @@ static const char *toktab[] = {
[TT_U64] = qtok("u64")
};
+
+/*
+ * Parse a preprocessor define directive
+ */
+static int
+parse_define(struct cescal_state *state, struct token *tok)
+{
+ struct symbol *sym;
+ int error;
+
+ if (state == NULL || tok == NULL) {
+ return -1;
+ }
+
+ if (parser_expect(state, tok, TT_IDENT) < 0) {
+ return -1;
+ }
+
+ /* XXX: Should probably be a warning */
+ if ((sym = symbol_byname(&state->symtab, tok->s)) != NULL) {
+ cc_error("redefinition of symbol %s\n", tok->s);
+ return -1;
+ }
+
+ /* Allocate the symbol */
+ error = symbol_allocate(&state->symtab, tok->s, SYMBOL_NONE, &sym);
+ if (error < 0) {
+ cc_error("[internal]: failed to allocate symbol\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Push a token to the token buffer in the preprocessing stage
*
+ * @state: Compiler state
* @tokbuf: Token buffer to push to
* @tok: Token to push
*
* Returns zero on success
*/
static int
-preprocessor_push(struct tokbuf *tokbuf, struct token *tok)
+preprocessor_push(struct cescal_state *state, struct tokbuf *tokbuf, struct token *tok)
{
if (tokbuf == NULL || tok == NULL) {
return -1;
@@ -75,8 +118,14 @@ preprocessor_push(struct tokbuf *tokbuf, struct token *tok)
switch (tok->type) {
case TT_IFNDEF:
+ break;
case TT_IFDEF:
+ break;
case TT_DEFINE:
+ if (parse_define(state, tok) < 0) {
+ return -1;
+ }
+
break;
default:
if (tokbuf_push(tokbuf, tok) < 0) {
@@ -90,8 +139,6 @@ preprocessor_push(struct tokbuf *tokbuf, struct token *tok)
static int
parser_nom(struct cescal_state *state, struct token *res)
{
- struct token tok;
-
if (state == NULL || res == NULL) {
errno = EINVAL;
return -1;
@@ -99,24 +146,52 @@ parser_nom(struct cescal_state *state, struct token *res)
switch (state->pass) {
case 0: /* Pre-processor */
- if (lexer_nom(state, &tok) < 0) {
+ if (lexer_nom(state, res) < 0) {
return -1;
}
- if (preprocessor_push(&state->tokbuf, &tok) < 0) {
+ if (preprocessor_push(state, &state->tokbuf, res) < 0) {
return -1;
}
break;
case 1: /* Parse */
- if (tokbuf_pop(&state->tokbuf, &tok) < 0) {
+ if (tokbuf_pop(&state->tokbuf, res) < 0) {
return -1;
}
break;
}
- *res = tok;
+ return 0;
+}
+
+/*
+ * Assert that the next token is of a specific type
+ *
+ * @state: Compiler state
+ * @res: Token result is written here
+ * @exp: Token expedcted
+ *
+ * Returns zero on success
+ */
+static int
+parser_expect(struct cescal_state *state, struct token *res, tt_t exp)
+{
+ if (state == NULL || res == NULL) {
+ return -1;
+ }
+
+ if (parser_nom(state, res) < 0) {
+ cc_error("unexpected end of file\n");
+ return -1;
+ }
+
+ if (res->type != exp) {
+ utok1(res, exp);
+ return -1;
+ }
+
return 0;
}
@@ -131,7 +206,9 @@ parser_parse(struct cescal_state *state)
}
while (parser_nom(state, &tok) == 0) {
- cc_trace("got token %s\n", tokstr(&tok));
+ if (state->pass > 0) {
+ cc_trace("got token %s\n", tokstr(&tok));
+ }
}
++state->pass;
diff --git a/core/state.c b/core/state.c
index f6ed48e..b64271c 100644
--- a/core/state.c
+++ b/core/state.c
@@ -35,6 +35,11 @@ state_init(struct cescal_state *state, const char *pathname)
return -1;
}
+ if (symbol_table_init(&state->symtab) < 0) {
+ close(state->in_fd);
+ return -1;
+ }
+
if (ptrbox_init(&state->ptrbox) < 0) {
close(state->in_fd);
return -1;
@@ -50,4 +55,5 @@ state_close(struct cescal_state *state)
state->in_fd = -1;
ptrbox_destroy(&state->ptrbox);
tokbuf_destroy(&state->tokbuf);
+ symbol_table_destroy(&state->symtab);
}
diff --git a/core/symbol.c b/core/symbol.c
new file mode 100644
index 0000000..daa4411
--- /dev/null
+++ b/core/symbol.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2026, Chloe M.
+ * Provided under the BSD-3 clause
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "cescal/symbol.h"
+
+/*
+ * Push a symbol into a symbol table
+ *
+ * @symtab: Symbol table to push to
+ * @symbol: Symbol to push
+ *
+ * Returns zero on success
+ */
+static int
+symbol_table_push(struct symbol_table *symtab, struct symbol *symbol)
+{
+ if (symtab == NULL || symbol == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ symbol->next = NULL;
+ if (symtab->head == NULL || symtab->tail == NULL) {
+ symtab->head = symbol;
+ symtab->tail = symbol;
+ } else {
+ symtab->head->next = symbol;
+ symtab->head = symbol;
+ }
+
+ return 0;
+}
+
+int
+symbol_table_init(struct symbol_table *symtab)
+{
+ if (symtab == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ symtab->head = NULL;
+ symtab->tail = NULL;
+ return 0;
+}
+
+int
+symbol_allocate(struct symbol_table *symtab, const char *name,
+ symtype_t type, struct symbol **res)
+{
+ struct symbol *symbol;
+
+ if (symtab == NULL || name == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (res == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ symbol = malloc(sizeof(*symbol));
+ if (symbol == NULL) {
+ errno = -ENOMEM;
+ return -1;
+ }
+
+ symbol->name = strdup(name);
+ symbol->type = type;
+ if (symbol_table_push(symtab, symbol) < 0) {
+ free(symbol);
+ return -1;
+ }
+
+ *res = symbol;
+ return 0;
+}
+
+void
+symbol_table_destroy(struct symbol_table *symtab)
+{
+ struct symbol *symbol, *tmp;
+
+ if (symtab == NULL) {
+ return;
+ }
+
+ symbol = symtab->tail;
+ while (symbol != NULL) {
+ tmp = symbol;
+ if (tmp->name != NULL)
+ free(tmp->name);
+ free(tmp);
+ symbol = symbol->next;
+ }
+}
+
+struct symbol *
+symbol_byname(struct symbol_table *symtab, const char *name)
+{
+ struct symbol *symbol;
+
+ if (symtab == NULL || name == NULL) {
+ return NULL;
+ }
+
+ symbol = symtab->head;
+ while (symbol != NULL) {
+ if (*symbol->name != *name) {
+ symbol = symbol->next;
+ continue;
+ }
+
+ if (strcmp(symbol->name, name) == 0) {
+ return symbol;
+ }
+
+ symbol = symbol->next;
+ }
+
+ return NULL;
+}