Skip to content

Commit

Permalink
feat: support extern
Browse files Browse the repository at this point in the history
  • Loading branch information
diohabara committed Aug 2, 2023
1 parent 7fadafd commit 2c803ae
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ tmp*

# for debug
test
ext
test.*
ext.*
.gdb_history

# stages
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"*.plt": "prolog",
"stdbool.h": "c",
"tests": "cpp",
"initializer_list": "c"
"initializer_list": "c",
"string.h": "c"
},
"C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools"
}
53 changes: 34 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,8 @@ CFLAGS=-std=c11 -g -static
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)

ccc: $(OBJS)
$(CC) -o $@ $(OBJS) $(CFLAGS)

$(OBJS): ccc.h

STAGES = stage1 stage2 stage3

define PROCESS_STAGE_RULE
$(1)/%.c: %.c
mkdir -p $(1)
gcc -E $$< | grep -v '^#' > $$@
endef

$(foreach stage,$(STAGES),$(eval $(call PROCESS_STAGE_RULE,$(stage))))

PROCESSED_SRCS = $(foreach stage,$(STAGES),$(addprefix $(stage)/,$(SRCS)))

process: $(PROCESSED_SRCS)

help:
@echo "Usage: make [lint|test|debug|clean|process]"
@echo " lint: run c and shell checker"
Expand All @@ -29,6 +12,9 @@ help:
@echo " clean: remove object files"
@echo " process: run the preprocessor on all source files for each stage"

ccc: $(OBJS)
$(CC) -o $@ $(OBJS) $(CFLAGS)

lint:
clang-format -i ./*.c
clang-format -i ./*.h
Expand All @@ -39,13 +25,42 @@ lintx:
test: ccc
./ccc tests > tmp.s
echo 'int char_fn() { return 257; }' | gcc -xc -c -o tmp2.o -
gcc -static -o tmp tmp.s tmp2.o
echo 'int ext1 = 5; int *ext2 = &ext1;' | gcc -xc -c -o tmp3.o -
gcc -static -o tmp tmp.s tmp2.o tmp3.o
./tmp

testx:
docker run --platform=linux/amd64 -v "${PWD}:/src" -w/src ccc make test

clean:
rm -f ccc *.o *~ tmp*
rm -f ccc *.o *~ tmp* stage*/*

.PHONY: help lint test clean process

# stage0: gcc
# stage1: ccc on host machine generated by stage0 (gcc)
# stage2: ccc on X86-64 machine generated by stage1
# stage3: ccc on X86-64 machine generated by stage2

STAGES = stage1 stage2 stage3

define PROCESS_STAGE_RULE
$(1)/%.c: %.c
mkdir -p $(1)
gcc -E -P $$< -o $$@
endef

$(foreach stage,$(STAGES),$(eval $(call PROCESS_STAGE_RULE,$(stage))))

PROCESSED_SRCS = $(foreach stage,$(STAGES),$(addprefix $(stage)/,$(SRCS)))

process: $(PROCESSED_SRCS)

ccc-stage1: $(OBJS)
$(CC) -o $@ $(OBJS) $(CFLAGS)

ccc-stage2:
@echo TODO

ccc-stage3:
@echo TODO
1 change: 1 addition & 0 deletions ccc.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ struct Type {
TypeKind kind;
bool is_typedef; // typedef
bool is_static; // static
bool is_extern; // extern
bool is_incomplete; // incomplete array
int align; // alignment
Type *base; // pointer or array
Expand Down
3 changes: 3 additions & 0 deletions codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ void emit_data(Program *prog) {
printf(".data\n");
for (VarList *vl = prog->globals; vl; vl = vl->next) {
Var *var = vl->var;
if (var->ty->is_extern) {
continue;
}
printf("%s:\n", var->name);
if (!var->initializer) {
printf(" .zero %d\n", size_of(var->ty, var->tok));
Expand Down
12 changes: 10 additions & 2 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ Program *program() {
// | "short" | "short" "int" | "int" "short"
// | "int"
// | "long" | "long" "int" | "int" "long"
// note that "typedef" and "static" can appear anywhere in a function body.
// note that "typedef", "static", and "extern" can appear anywhere in a function
// body.
Type *type_specifier() {
if (!is_typename(token)) {
error_tok(token, "typename expected");
Expand All @@ -244,6 +245,7 @@ Type *type_specifier() {

bool is_typedef = false;
bool is_static = false;
bool is_extern = false;

for (;;) {
// read one token at a time
Expand All @@ -252,6 +254,8 @@ Type *type_specifier() {
is_typedef = true;
} else if (consume("static")) {
is_static = true;
} else if (consume("extern")) {
is_extern = true;
} else if (consume("void")) {
base_type += VOID;
} else if (consume("_Bool")) {
Expand Down Expand Up @@ -318,6 +322,7 @@ Type *type_specifier() {
}
ty->is_typedef = is_typedef;
ty->is_static = is_static;
ty->is_extern = is_extern;
return ty;
}

Expand Down Expand Up @@ -772,10 +777,12 @@ Initializer *gvar_initializer(Initializer *cur, Type *ty) {
// = type-specifier declarator type-suffix ("=" gvar-initializer)? ";"
void global_var() {
Type *ty = type_specifier();
bool is_extern = ty->is_extern;
char *name = NULL;
Token *tok = token;
ty = declarator(ty, &name);
ty = type_suffix(ty);
ty->is_extern = is_extern;

Var *var = push_var(name, ty, false, tok);
push_scope(name)->var = var;
Expand Down Expand Up @@ -989,7 +996,8 @@ Node *read_expr_stmt() {
bool is_typename() {
return peek("typedef") || peek("void") || peek("_Bool") || peek("char") ||
peek("short") || peek("int") || peek("long") || peek("struct") ||
peek("enum") || peek("static") || find_typedef(token);
peek("enum") || peek("static") || peek("extern") ||
find_typedef(token);
}

// stmt = "return" expr ";"
Expand Down
6 changes: 6 additions & 0 deletions tests
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ void voidfn(void) {}

static int static_fn(void) {}

extern int ext1;
extern int *ext2;

int main() {
assert(8, ({
int a = 3;
Expand Down Expand Up @@ -951,6 +954,9 @@ int main() {
assert(3, g23, "g23");
assert(3, *g24, "*g24");

assert(5, ext1, "ext1");
assert(5, *ext2, "*ext2");

printf("OK\n");
return 0;
}
10 changes: 5 additions & 5 deletions tokenize.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ bool is_alnum(char c) { return is_alpha(c) || ('0' <= c && c <= '9'); }

char *starts_with_reserved(char *p) {
// Keyword
static char *kw[] = {"return", "if", "else", "while", "for",
"char", "int", "sizeof", "struct", "typedef",
"short", "long", "void", "_Bool", "enum",
"static", "break", "continue", "goto", "switch",
"case", "default"};
static char *kw[] = {"return", "if", "else", "while", "for",
"char", "int", "sizeof", "struct", "typedef",
"short", "long", "void", "_Bool", "enum",
"static", "break", "continue", "goto", "switch",
"case", "default", "extern"};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
int len = strlen(kw[i]);
if (startswith(p, kw[i]) && !is_alnum(p[len])) {
Expand Down

0 comments on commit 2c803ae

Please sign in to comment.