diff --git a/.gitignore b/.gitignore index 171fa70..fa3a3af 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ tmp* # for debug test +ext +test.* +ext.* .gdb_history # stages diff --git a/.vscode/settings.json b/.vscode/settings.json index b07e718..0ca462a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } \ No newline at end of file diff --git a/Makefile b/Makefile index 6708c3b..950ae4f 100644 --- a/Makefile +++ b/Makefile @@ -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" @@ -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 @@ -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 \ No newline at end of file diff --git a/ccc.h b/ccc.h index 5facb8b..f866c4b 100644 --- a/ccc.h +++ b/ccc.h @@ -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 diff --git a/codegen.c b/codegen.c index ca2c39a..3412b20 100644 --- a/codegen.c +++ b/codegen.c @@ -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)); diff --git a/parse.c b/parse.c index e906350..abff39f 100644 --- a/parse.c +++ b/parse.c @@ -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"); @@ -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 @@ -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")) { @@ -318,6 +322,7 @@ Type *type_specifier() { } ty->is_typedef = is_typedef; ty->is_static = is_static; + ty->is_extern = is_extern; return ty; } @@ -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; @@ -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 ";" diff --git a/tests b/tests index af6870e..ef70c0c 100644 --- a/tests +++ b/tests @@ -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; @@ -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; } diff --git a/tokenize.c b/tokenize.c index 4cb3dda..060282a 100644 --- a/tokenize.c +++ b/tokenize.c @@ -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])) {