include, ifndef, endif
This commit is contained in:
parent
a9d34f6725
commit
1c301c3fe3
@ -1,11 +1,6 @@
|
|||||||
#include "not_stdio.h"
|
#include "not_stdio.h"
|
||||||
|
|
||||||
#define B(V, W) A(V)
|
|
||||||
#define D B
|
|
||||||
#define C D("hello world", 123)
|
|
||||||
#define A puts
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
C;
|
puts("hello world");
|
||||||
}
|
}
|
||||||
|
|||||||
9
examples/macro_usage.c
Normal file
9
examples/macro_usage.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#define B(V, W) A(V)
|
||||||
|
#define D B
|
||||||
|
#define C D("hello world", 123)
|
||||||
|
#define A puts
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
C;
|
||||||
|
}
|
||||||
@ -1,2 +1,6 @@
|
|||||||
|
#ifndef NOT_STDIO_H
|
||||||
|
#define NOT_STDIO_H
|
||||||
|
|
||||||
int puts(const char* __s);
|
int puts(const char* __s);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
3
main.c
3
main.c
@ -30,6 +30,9 @@ int main(int argc, char* argv[])
|
|||||||
Tok tok;
|
Tok tok;
|
||||||
while ((tok = preproc_next(preproc)).ty != Tok_Eof) {
|
while ((tok = preproc_next(preproc)).ty != Tok_Eof) {
|
||||||
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
|
// printf("%s\t%s\n", tokty_str(tok.ty), tok.text);
|
||||||
|
if (line > tok.line) {
|
||||||
|
line = 0;
|
||||||
|
}
|
||||||
while (line < tok.line) {
|
while (line < tok.line) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
line += 1;
|
line += 1;
|
||||||
|
|||||||
180
preproc.c
180
preproc.c
@ -68,6 +68,28 @@ static size_t* syms_get(Syms* s, const char* ident)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t conds;
|
||||||
|
size_t depth;
|
||||||
|
} CondStack;
|
||||||
|
|
||||||
|
void condstack_push(CondStack* s, bool cond)
|
||||||
|
{
|
||||||
|
if (cond) {
|
||||||
|
s->conds |= 1ul << s->depth;
|
||||||
|
} else {
|
||||||
|
s->conds &= ~(1ul << s->depth);
|
||||||
|
}
|
||||||
|
s->depth += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condstack_pop(CondStack* s)
|
||||||
|
{
|
||||||
|
assert(s->depth > 0);
|
||||||
|
s->depth -= 1;
|
||||||
|
return (s->conds >> s->depth) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* filename;
|
char* filename;
|
||||||
char* text;
|
char* text;
|
||||||
@ -94,6 +116,8 @@ struct Preproc {
|
|||||||
ARRAY_FIELD(Def, defs);
|
ARRAY_FIELD(Def, defs);
|
||||||
Syms syms;
|
Syms syms;
|
||||||
|
|
||||||
|
CondStack condstack;
|
||||||
|
|
||||||
bool next_can_be_directive;
|
bool next_can_be_directive;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,14 +126,16 @@ void preproc_init(Preproc** p, char* filename, char* text)
|
|||||||
*p = malloc(sizeof(Preproc));
|
*p = malloc(sizeof(Preproc));
|
||||||
|
|
||||||
**p = (Preproc) {
|
**p = (Preproc) {
|
||||||
|
.tok_arena = { },
|
||||||
ARRAY_FIELD_INIT(files),
|
ARRAY_FIELD_INIT(files),
|
||||||
|
|
||||||
ARRAY_FIELD_INIT(tok_stack),
|
ARRAY_FIELD_INIT(tok_stack),
|
||||||
.curr = { },
|
.curr = { },
|
||||||
|
|
||||||
ARRAY_FIELD_INIT(defs),
|
ARRAY_FIELD_INIT(defs),
|
||||||
.syms = { },
|
.syms = { },
|
||||||
|
|
||||||
.tok_arena = { },
|
.condstack = { },
|
||||||
|
|
||||||
.next_can_be_directive = true,
|
.next_can_be_directive = true,
|
||||||
};
|
};
|
||||||
@ -409,6 +435,8 @@ static Tok do_undef(Preproc* p)
|
|||||||
return p->curr;
|
return p->curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tok preproc_next_with_newline(Preproc* p);
|
||||||
|
|
||||||
static Tok do_include(Preproc* p)
|
static Tok do_include(Preproc* p)
|
||||||
{
|
{
|
||||||
File* curr_file = &p->files[p->files_size - 1];
|
File* curr_file = &p->files[p->files_size - 1];
|
||||||
@ -470,46 +498,123 @@ static Tok do_include(Preproc* p)
|
|||||||
lexer_init(&file->lexer, &file->lsl_iter, &p->tok_arena);
|
lexer_init(&file->lexer, &file->lsl_iter, &p->tok_arena);
|
||||||
p->curr = lexer_next(&file->lexer);
|
p->curr = lexer_next(&file->lexer);
|
||||||
|
|
||||||
|
p->next_can_be_directive = true;
|
||||||
|
|
||||||
|
return preproc_next_with_newline(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tok interpret_directive(Preproc* p);
|
||||||
|
|
||||||
|
static Tok do_ifndef(Preproc* p)
|
||||||
|
{
|
||||||
|
int original_line = p->curr.line;
|
||||||
|
|
||||||
|
step(p);
|
||||||
|
if (p->curr.ty != Tok_Ident) {
|
||||||
|
fprintf(
|
||||||
|
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
Tok ident = p->curr;
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cond = syms_get(&p->syms, ident.text) == nullptr;
|
||||||
|
|
||||||
|
condstack_push(&p->condstack, cond);
|
||||||
|
|
||||||
|
if (!cond) {
|
||||||
|
|
||||||
|
while (p->curr.ty != Tok_Eof) {
|
||||||
|
while (p->curr.ty != Tok_Eof
|
||||||
|
&& (!p->next_can_be_directive || p->curr.ty != '#'))
|
||||||
|
step(p);
|
||||||
|
if (p->curr.ty == Tok_Eof)
|
||||||
|
break;
|
||||||
|
step(p);
|
||||||
|
if (p->curr.ty != Tok_Ident)
|
||||||
|
continue;
|
||||||
|
if (strcmp(p->curr.text, "endif") == 0)
|
||||||
|
return interpret_directive(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->curr.ty != Tok_Eof) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"error: unclosed '#ifndef' on line %d\n",
|
||||||
|
original_line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tok do_endif(Preproc* p)
|
||||||
|
{
|
||||||
|
step(p);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
condstack_pop(&p->condstack);
|
||||||
|
|
||||||
return p->curr;
|
return p->curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tok interpret_directive(Preproc* p)
|
static Tok interpret_directive(Preproc* p)
|
||||||
{
|
{
|
||||||
assert(p->curr.ty == '#');
|
if (p->curr.ty == Tok_Eol)
|
||||||
step(p);
|
return p->curr;
|
||||||
|
|
||||||
|
if (p->curr.ty != Tok_Ident) {
|
||||||
|
fprintf(
|
||||||
|
stderr, "error: expected identifier on line %d\n", p->curr.line);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
Tok kw = p->curr;
|
Tok kw = p->curr;
|
||||||
|
|
||||||
if (strcmp(kw.text, "define") == 0) {
|
struct {
|
||||||
return do_define(p);
|
const char* keyword;
|
||||||
} else if (strcmp(kw.text, "undef") == 0) {
|
Tok (*fn)(Preproc* p);
|
||||||
return do_undef(p);
|
} directives[] = {
|
||||||
} else if (strcmp(kw.text, "include") == 0) {
|
{ "define", do_define },
|
||||||
return do_include(p);
|
{ "undef", do_undef },
|
||||||
} else if (strcmp(kw.text, "if") == 0) {
|
{ "include", do_include },
|
||||||
assert(false && "not implemented");
|
{ "ifndef", do_ifndef },
|
||||||
} else if (strcmp(kw.text, "ifdef") == 0) {
|
{ "endif", do_endif },
|
||||||
assert(false && "not implemented");
|
|
||||||
} else if (strcmp(kw.text, "ifndef") == 0) {
|
{ "if", nullptr },
|
||||||
assert(false && "not implemented");
|
{ "ifdef", nullptr },
|
||||||
} else if (strcmp(kw.text, "else") == 0) {
|
{ "else", nullptr },
|
||||||
assert(false && "not implemented");
|
{ "elif", nullptr },
|
||||||
} else if (strcmp(kw.text, "elif") == 0) {
|
{ "elifdef", nullptr },
|
||||||
assert(false && "not implemented");
|
{ "elifndef", nullptr },
|
||||||
} else if (strcmp(kw.text, "elifdef") == 0) {
|
{ "line", nullptr },
|
||||||
assert(false && "not implemented");
|
{ "embed", nullptr },
|
||||||
} else if (strcmp(kw.text, "elifndef") == 0) {
|
{ "error", nullptr },
|
||||||
assert(false && "not implemented");
|
{ "warning", nullptr },
|
||||||
} else if (strcmp(kw.text, "endif") == 0) {
|
{ "pragma", nullptr },
|
||||||
assert(false && "not implemented");
|
};
|
||||||
} else if (strcmp(kw.text, "line") == 0) {
|
|
||||||
assert(false && "not implemented");
|
for (size_t i = 0; i < sizeof(directives) / sizeof(directives[0]); ++i) {
|
||||||
} else if (strcmp(kw.text, "embed") == 0) {
|
if (strcmp(kw.text, directives[i].keyword) == 0) {
|
||||||
assert(false && "not implemented");
|
assert(directives[i].fn && "not implemented");
|
||||||
} else if (strcmp(kw.text, "error") == 0) {
|
|
||||||
assert(false && "not implemented");
|
return directives[i].fn(p);
|
||||||
} else if (strcmp(kw.text, "warning") == 0) {
|
}
|
||||||
assert(false && "not implemented");
|
}
|
||||||
} else if (strcmp(kw.text, "pragma") == 0) {
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"error: '%s' is not a preprocessor instruction on line %d\n",
|
"error: '%s' is not a preprocessor instruction on line %d\n",
|
||||||
kw.text,
|
kw.text,
|
||||||
@ -517,13 +622,12 @@ static Tok interpret_directive(Preproc* p)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false && "unreachable");
|
|
||||||
}
|
|
||||||
|
|
||||||
Tok preproc_next_with_newline(Preproc* p)
|
Tok preproc_next_with_newline(Preproc* p)
|
||||||
{
|
{
|
||||||
if (p->next_can_be_directive && p->curr.ty == '#')
|
if (p->next_can_be_directive && p->curr.ty == '#') {
|
||||||
|
step(p);
|
||||||
return interpret_directive(p);
|
return interpret_directive(p);
|
||||||
|
}
|
||||||
return expand_tok(p);
|
return expand_tok(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user