add preproc
This commit is contained in:
parent
1767d1682c
commit
b19290f20e
77
collection.c
Normal file
77
collection.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "collection.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void array_push(
|
||||||
|
void** data, size_t* capacity, size_t* size, void* elem, size_t elem_size)
|
||||||
|
{
|
||||||
|
if (!*capacity) {
|
||||||
|
*capacity = 4;
|
||||||
|
}
|
||||||
|
if (!*data) {
|
||||||
|
*data = malloc(elem_size * *capacity);
|
||||||
|
*size = 0;
|
||||||
|
}
|
||||||
|
if (*size >= *capacity) {
|
||||||
|
*capacity *= 2;
|
||||||
|
*data = realloc(*data, *capacity * elem_size);
|
||||||
|
}
|
||||||
|
memcpy((unsigned char*)*data + *size, elem, elem_size);
|
||||||
|
*size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push_kwpair(Hashmap* m, KwPair* pair)
|
||||||
|
{
|
||||||
|
array_push((void**)&m->entries,
|
||||||
|
&m->entries_capacity,
|
||||||
|
&m->entries_size,
|
||||||
|
pair,
|
||||||
|
sizeof(*pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_init(Hashmap* m)
|
||||||
|
{
|
||||||
|
*m = (Hashmap) {
|
||||||
|
.entries = nullptr,
|
||||||
|
.entries_capacity = 8,
|
||||||
|
.entries_size = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_deinit(Hashmap* m)
|
||||||
|
{
|
||||||
|
if (m->entries) {
|
||||||
|
for (size_t i = 0; i < m->entries_size; ++i) {
|
||||||
|
free(m->entries[i].key);
|
||||||
|
}
|
||||||
|
free(m->entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static KwPair* find_entry(Hashmap* m, const char* key)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m->entries_size; ++i) {
|
||||||
|
if (strcmp(m->entries[i].key, key) == 0) {
|
||||||
|
return &m->entries[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_set(Hashmap* m, const char* key, void* val)
|
||||||
|
{
|
||||||
|
KwPair* existing = find_entry(m, key);
|
||||||
|
if (existing) {
|
||||||
|
existing->val = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_kwpair(m, &(KwPair) { strdup(key), val });
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hashmap_get(Hashmap* m, const char* key)
|
||||||
|
{
|
||||||
|
KwPair* existing = find_entry(m, key);
|
||||||
|
return existing ? existing->val : nullptr;
|
||||||
|
}
|
||||||
26
collection.h
Normal file
26
collection.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef COLLECTION_H
|
||||||
|
#define COLLECTION_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void array_push(
|
||||||
|
void** data, size_t* capacity, size_t* size, void* elem, size_t elem_size);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* key;
|
||||||
|
void* val;
|
||||||
|
} KwPair;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
KwPair* entries;
|
||||||
|
size_t entries_capacity;
|
||||||
|
size_t entries_size;
|
||||||
|
} Hashmap;
|
||||||
|
|
||||||
|
void hashmap_init(Hashmap* m);
|
||||||
|
void hashmap_deinit(Hashmap* m);
|
||||||
|
|
||||||
|
void hashmap_set(Hashmap* m, const char* key, void* val);
|
||||||
|
void* hashmap_get(Hashmap* m, const char* key);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#include <stdio.h>
|
int puts(const char* __s);
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
printf("hello\n");
|
puts("hello");
|
||||||
}
|
}
|
||||||
|
|||||||
109
parse.c → lex.c
109
parse.c → lex.c
@ -4,11 +4,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// phases:
|
|
||||||
// https://en.cppreference.com/c/language/translation_phases
|
|
||||||
|
|
||||||
// phase 1 - source chars
|
|
||||||
|
|
||||||
void source_char_iter_init(SourceCharIter* r, const char* text)
|
void source_char_iter_init(SourceCharIter* r, const char* text)
|
||||||
{
|
{
|
||||||
*r = (SourceCharIter) {
|
*r = (SourceCharIter) {
|
||||||
@ -19,7 +14,7 @@ void source_char_iter_init(SourceCharIter* r, const char* text)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceChar source_iter_next(SourceCharIter* r)
|
Char source_iter_next(SourceCharIter* r)
|
||||||
{
|
{
|
||||||
char ch = r->text[r->i];
|
char ch = r->text[r->i];
|
||||||
int line = r->line;
|
int line = r->line;
|
||||||
@ -35,14 +30,12 @@ SourceChar source_iter_next(SourceCharIter* r)
|
|||||||
r->i += 1;
|
r->i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (SourceChar) { ch, line, col };
|
return (Char) { ch, line, col };
|
||||||
}
|
}
|
||||||
|
|
||||||
// phase 2 - logical source lines
|
|
||||||
|
|
||||||
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter)
|
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter)
|
||||||
{
|
{
|
||||||
SourceChar curr = source_iter_next(source_char_iter);
|
Char curr = source_iter_next(source_char_iter);
|
||||||
|
|
||||||
*r = (LslCharIter) {
|
*r = (LslCharIter) {
|
||||||
.source_char_iter = source_char_iter,
|
.source_char_iter = source_char_iter,
|
||||||
@ -50,30 +43,30 @@ void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
LslChar lsl_iter_next(LslCharIter* r)
|
Char lsl_iter_next(LslCharIter* r)
|
||||||
{
|
{
|
||||||
SourceChar next = source_iter_next(r->source_char_iter);
|
Char next = source_iter_next(r->source_char_iter);
|
||||||
|
|
||||||
if (r->curr.ch == '\\' && next.ch == '\n') {
|
if (r->curr.ch == '\\' && next.ch == '\n') {
|
||||||
r->curr = source_iter_next(r->source_char_iter);
|
r->curr = source_iter_next(r->source_char_iter);
|
||||||
return lsl_iter_next(r);
|
return lsl_iter_next(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
LslChar lsl_char = { r->curr.ch, r->curr.line, r->curr.col };
|
Char lsl_char = { r->curr.ch, r->curr.line, r->curr.col };
|
||||||
|
|
||||||
r->curr = next;
|
r->curr = next;
|
||||||
return lsl_char;
|
return lsl_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
// phase 3 - preprocessor tokens
|
|
||||||
|
|
||||||
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter)
|
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter)
|
||||||
{
|
{
|
||||||
LslChar curr = lsl_iter_next(lsl_char_iter);
|
Char curr = lsl_iter_next(lsl_char_iter);
|
||||||
|
|
||||||
*r = (Lexer) {
|
*r = (Lexer) {
|
||||||
.lsl_char_iter = lsl_char_iter,
|
.lsl_char_iter = lsl_char_iter,
|
||||||
.curr = curr,
|
.curr = curr,
|
||||||
|
.lex_whitespace = false,
|
||||||
|
.lex_headername = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,14 +75,14 @@ static Tok tok(TokTy ty, const char* text, int line, int col)
|
|||||||
return (Tok) { ty, strdup(text), line, col };
|
return (Tok) { ty, strdup(text), line, col };
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool l_done(Lexer* l)
|
static bool done(Lexer* l)
|
||||||
{
|
{
|
||||||
return l->curr.ch == '\0';
|
return l->curr.ch == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t max_token_text_len = 64;
|
constexpr size_t max_token_text_len = 64;
|
||||||
|
|
||||||
static void l_step(Lexer* l, char text[], size_t* text_len)
|
static void step(Lexer* l, char text[], size_t* text_len)
|
||||||
{
|
{
|
||||||
assert(*text_len < max_token_text_len);
|
assert(*text_len < max_token_text_len);
|
||||||
text[*text_len] = l->curr.ch;
|
text[*text_len] = l->curr.ch;
|
||||||
@ -106,16 +99,19 @@ Tok lexer_next(Lexer* l)
|
|||||||
char text[max_token_text_len] = "";
|
char text[max_token_text_len] = "";
|
||||||
size_t text_len = 0;
|
size_t text_len = 0;
|
||||||
|
|
||||||
if (l_done(l)) {
|
if (done(l)) {
|
||||||
return tok(Tok_Eof, text, line, col);
|
return tok(Tok_Eof, text, line, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
while (strchr(" \t\r", l->curr.ch)) {
|
while (strchr(" \t\r", l->curr.ch)) {
|
||||||
matched = true;
|
matched = true;
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
|
if (l->lex_whitespace) {
|
||||||
|
return tok(Tok_Whitespace, text, line, col);
|
||||||
|
}
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +120,7 @@ Tok lexer_next(Lexer* l)
|
|||||||
|| (matched && l->curr.ch >= '0' && l->curr.ch <= '9')
|
|| (matched && l->curr.ch >= '0' && l->curr.ch <= '9')
|
||||||
|| strchr("_", l->curr.ch)) {
|
|| strchr("_", l->curr.ch)) {
|
||||||
matched = true;
|
matched = true;
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return tok(Tok_Ident, text, line, col);
|
return tok(Tok_Ident, text, line, col);
|
||||||
@ -133,52 +129,75 @@ Tok lexer_next(Lexer* l)
|
|||||||
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|
while ((l->curr.ch >= '1' && l->curr.ch <= '9')
|
||||||
|| (matched && l->curr.ch == '0')) {
|
|| (matched && l->curr.ch == '0')) {
|
||||||
matched = true;
|
matched = true;
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return tok(Tok_Int, text, line, col);
|
return tok(Tok_Int, text, line, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->curr.ch == '"') {
|
if (l->lex_headername && (l->curr.ch == '"' || l->curr.ch == '<')) {
|
||||||
l_step(l, text, &text_len);
|
char ter = l->curr.ch == '<' ? '>' : '"';
|
||||||
while (l->curr.ch != '"') {
|
while (l->curr.ch != '\0' && l->curr.ch != '\n' && l->curr.ch != ter) {
|
||||||
if (l->curr.ch == '\\') {
|
step(l, text, &text_len);
|
||||||
l_step(l, text, &text_len);
|
|
||||||
if (l_done(l))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
l_step(l, text, &text_len);
|
if (l->curr.ch != ter) {
|
||||||
}
|
fprintf(stderr,
|
||||||
if (l_done(l) || l->curr.ch != '"') {
|
"error: malformed header name, expected '%c' on line %d\n",
|
||||||
fprintf(stderr, "error: malformed string literal\n");
|
ter,
|
||||||
|
l->curr.line);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
|
return tok(Tok_HeaderName, text, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->curr.ch == '"') {
|
||||||
|
step(l, text, &text_len);
|
||||||
|
while (l->curr.ch != '"') {
|
||||||
|
if (l->curr.ch == '\\') {
|
||||||
|
step(l, text, &text_len);
|
||||||
|
if (done(l))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
step(l, text, &text_len);
|
||||||
|
}
|
||||||
|
if (done(l) || l->curr.ch != '"') {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: malformed string literal on line %d\n",
|
||||||
|
l->curr.line);
|
||||||
|
return lexer_next(l);
|
||||||
|
}
|
||||||
|
step(l, text, &text_len);
|
||||||
return tok(Tok_Str, text, line, col);
|
return tok(Tok_Str, text, line, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->curr.ch == '\'') {
|
if (l->curr.ch == '\'') {
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
if (l->curr.ch == '\\') {
|
if (l->curr.ch == '\\') {
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (!l_done(l)) {
|
if (!done(l)) {
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
}
|
}
|
||||||
if (l_done(l) && l->curr.ch != '\'') {
|
if (done(l) && l->curr.ch != '\'') {
|
||||||
fprintf(stderr, "error: malformed character literal\n");
|
fprintf(stderr,
|
||||||
|
"error: malformed character literal on line %d\n",
|
||||||
|
l->curr.line);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(Tok_Char, text, line, col);
|
return tok(Tok_Char, text, line, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strchr("\n;(){}", l->curr.ch)) {
|
if (strchr("\n;(){}#", l->curr.ch)) {
|
||||||
TokTy ty = (TokTy)l->curr.ch;
|
TokTy ty = (TokTy)l->curr.ch;
|
||||||
l_step(l, text, &text_len);
|
step(l, text, &text_len);
|
||||||
return tok(ty, text, line, col);
|
return tok(ty, text, line, col);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "error: illegal character '%c'\n", l->curr.ch);
|
fprintf(stderr,
|
||||||
l_step(l, text, &text_len);
|
"error: illegal character '%c' on line %d\n",
|
||||||
|
l->curr.ch,
|
||||||
|
l->curr.line);
|
||||||
|
step(l, text, &text_len);
|
||||||
return lexer_next(l);
|
return lexer_next(l);
|
||||||
}
|
}
|
||||||
49
parse.h
49
parse.h
@ -1,13 +1,19 @@
|
|||||||
#ifndef PARSE_H
|
#ifndef PARSE_H
|
||||||
#define PARSE_H
|
#define PARSE_H
|
||||||
|
|
||||||
|
#include "collection.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// phases:
|
||||||
|
// https://en.cppreference.com/c/language/translation_phases
|
||||||
|
|
||||||
|
// phase 1 - source chars
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char ch;
|
char ch;
|
||||||
int line;
|
int line;
|
||||||
int col;
|
int col;
|
||||||
} SourceChar;
|
} Char;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* text;
|
const char* text;
|
||||||
@ -17,36 +23,35 @@ typedef struct {
|
|||||||
} SourceCharIter;
|
} SourceCharIter;
|
||||||
|
|
||||||
void source_char_iter_init(SourceCharIter* r, const char* text);
|
void source_char_iter_init(SourceCharIter* r, const char* text);
|
||||||
SourceChar source_iter_next(SourceCharIter* r);
|
Char source_iter_next(SourceCharIter* r);
|
||||||
|
|
||||||
typedef struct {
|
// phase 2 - logical source lines
|
||||||
char ch;
|
|
||||||
int line;
|
|
||||||
int col;
|
|
||||||
} LslChar;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SourceCharIter* source_char_iter;
|
SourceCharIter* source_char_iter;
|
||||||
SourceChar curr;
|
Char curr;
|
||||||
} LslCharIter;
|
} LslCharIter;
|
||||||
|
|
||||||
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter);
|
void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter);
|
||||||
LslChar lsl_iter_next(LslCharIter* r);
|
Char lsl_iter_next(LslCharIter* r);
|
||||||
|
|
||||||
|
// phase 3 - preprocessor tokens
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Tok_Eof,
|
Tok_Eof,
|
||||||
Tok_Eol,
|
|
||||||
Tok_Ident,
|
Tok_Ident,
|
||||||
Tok_Int,
|
Tok_Int,
|
||||||
Tok_Str,
|
Tok_Str,
|
||||||
Tok_Char,
|
Tok_Char,
|
||||||
|
Tok_Whitespace,
|
||||||
Tok_HeaderName,
|
Tok_HeaderName,
|
||||||
Tok_Newline = '\n', // NOTE: has value 10
|
Tok_Eol = '\n', // NOTE: has value 10
|
||||||
Tok_Semicolon = ';',
|
Tok_Semicolon = ';',
|
||||||
Tok_LParen = '(',
|
Tok_LParen = '(',
|
||||||
Tok_RParen = ')',
|
Tok_RParen = ')',
|
||||||
Tok_LBrace = '{',
|
Tok_LBrace = '{',
|
||||||
Tok_RBrace = '}',
|
Tok_RBrace = '}',
|
||||||
|
Tok_Hashtag = '#',
|
||||||
} TokTy;
|
} TokTy;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -58,10 +63,30 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LslCharIter* lsl_char_iter;
|
LslCharIter* lsl_char_iter;
|
||||||
LslChar curr;
|
Char curr;
|
||||||
|
bool lex_whitespace;
|
||||||
|
bool lex_headername;
|
||||||
} Lexer;
|
} Lexer;
|
||||||
|
|
||||||
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter);
|
void lexer_init(Lexer* r, LslCharIter* lsl_char_iter);
|
||||||
Tok lexer_next(Lexer* l);
|
Tok lexer_next(Lexer* l);
|
||||||
|
|
||||||
|
// phase 4 - preprocessor
|
||||||
|
|
||||||
|
typedef struct DefToks DefToks;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lexer* lexer;
|
||||||
|
Tok curr;
|
||||||
|
|
||||||
|
DefToks* deftoks;
|
||||||
|
size_t deftoks_cap;
|
||||||
|
size_t deftoks_size;
|
||||||
|
Hashmap defs;
|
||||||
|
} Preproc;
|
||||||
|
|
||||||
|
void preproc_init(Preproc* p, Lexer* lexer);
|
||||||
|
void preproc_deinit(Preproc* p);
|
||||||
|
Tok preproc_next(Preproc* p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
158
preproc.c
Normal file
158
preproc.c
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "collection.h"
|
||||||
|
#include "parse.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct DefToks {
|
||||||
|
Tok* toks;
|
||||||
|
size_t toks_cap;
|
||||||
|
size_t toks_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
void preproc_init(Preproc* p, Lexer* lexer)
|
||||||
|
{
|
||||||
|
Tok curr = lexer_next(p->lexer);
|
||||||
|
|
||||||
|
*p = (Preproc) {
|
||||||
|
.lexer = lexer,
|
||||||
|
.curr = curr,
|
||||||
|
.deftoks = nullptr,
|
||||||
|
.deftoks_cap = 0,
|
||||||
|
.deftoks_size = 0,
|
||||||
|
.defs = { },
|
||||||
|
};
|
||||||
|
|
||||||
|
hashmap_init(&p->defs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preproc_deinit(Preproc* p)
|
||||||
|
{
|
||||||
|
if (p->deftoks) {
|
||||||
|
free(p->deftoks);
|
||||||
|
}
|
||||||
|
hashmap_deinit(&p->defs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void step(Preproc* p)
|
||||||
|
{
|
||||||
|
p->curr = lexer_next(p->lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tok preproc_next(Preproc* p)
|
||||||
|
{
|
||||||
|
if (p->curr.ty == '#') {
|
||||||
|
step(p);
|
||||||
|
Tok kw = p->curr;
|
||||||
|
|
||||||
|
if (strcmp(kw.text, "define") == 0) {
|
||||||
|
step(p);
|
||||||
|
if (p->curr.ty != Tok_Ident) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
Tok ident_tok = p->curr;
|
||||||
|
|
||||||
|
p->lexer->lex_whitespace = true;
|
||||||
|
step(p);
|
||||||
|
p->lexer->lex_whitespace = false;
|
||||||
|
|
||||||
|
if (p->curr.ty == '(') {
|
||||||
|
// function-like macro
|
||||||
|
assert(false && "not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
DefToks toks = { };
|
||||||
|
|
||||||
|
while (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
|
array_push((void**)&toks.toks,
|
||||||
|
&toks.toks_cap,
|
||||||
|
&toks.toks_size,
|
||||||
|
&p->curr,
|
||||||
|
sizeof(p->curr));
|
||||||
|
step(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
array_push((void**)&p->deftoks,
|
||||||
|
&p->deftoks_cap,
|
||||||
|
&p->deftoks_size,
|
||||||
|
&toks,
|
||||||
|
sizeof(toks));
|
||||||
|
|
||||||
|
DefToks* deftoks = &p->deftoks[p->deftoks_size - 1];
|
||||||
|
hashmap_set(&p->defs, ident_tok.text, deftoks);
|
||||||
|
|
||||||
|
return p->curr;
|
||||||
|
} else if (strcmp(kw.text, "undef") == 0) {
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
if (p->curr.ty != Tok_Ident) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: expected identifier on line %d\n",
|
||||||
|
p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
Tok ident_tok = p->curr;
|
||||||
|
|
||||||
|
if (p->curr.ty != Tok_Eof && p->curr.ty != Tok_Eol) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: unexpected extra tokens on line %d\n",
|
||||||
|
p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashmap_set(&p->defs, ident_tok.text, nullptr);
|
||||||
|
|
||||||
|
return p->curr;
|
||||||
|
} else if (strcmp(kw.text, "include") == 0) {
|
||||||
|
p->lexer->lex_headername = true;
|
||||||
|
step(p);
|
||||||
|
p->lexer->lex_headername = false;
|
||||||
|
|
||||||
|
if (p->curr.ty != Tok_HeaderName) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: expected header name line %d\n",
|
||||||
|
p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "if") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "ifdef") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "ifndef") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "else") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "elif") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "elifdef") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "elifndef") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "endif") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "line") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "embed") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "error") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "warning") == 0) {
|
||||||
|
assert(false && "not implemented");
|
||||||
|
} else if (strcmp(kw.text, "pragma") == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: '%s' is not a preprocessor instruction on line %d\n",
|
||||||
|
kw.text,
|
||||||
|
kw.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p->curr;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user