├── LICENSE ├── Makefile ├── README.md ├── codegen.c ├── examples ├── asm ├── helloworld ├── print ├── test └── x11window ├── hashmap.c ├── include ├── float.h ├── stdalign.h ├── stdarg.h ├── stdatomic.h ├── stdbool.h ├── stddef.h └── stdnoreturn.h ├── main.c ├── parse.c ├── preprocess.c ├── strings.c ├── test ├── alignof.c ├── alloca.c ├── arith.c ├── asm.c ├── atomic.c ├── attribute.c ├── bitfield.c ├── builtin.c ├── cast.c ├── common ├── commonsym.c ├── compat.c ├── complit.c ├── const.c ├── constexpr.c ├── control.c ├── decl.c ├── driver.sh ├── enum.c ├── extern.c ├── float.c ├── function.c ├── generic.c ├── include1.h ├── include2.h ├── include3.h ├── include4.h ├── initializer.c ├── line.c ├── literal.c ├── macro.c ├── offsetof.c ├── pointer.c ├── pragma-once.c ├── sizeof.c ├── stdhdr.c ├── string.c ├── struct.c ├── test.h ├── thirdparty │ ├── common │ ├── cpython.sh │ ├── git.sh │ ├── libpng.sh │ ├── sqlite.sh │ └── tinycc.sh ├── tls.c ├── typedef.c ├── typeof.c ├── unicode.c ├── union.c ├── usualconv.c ├── varargs.c ├── variable.c └── vla.c ├── tokenize.c ├── type.c ├── unicode.c ├── xc └── xcc.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 x3ric 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-std=c11 -g -lcurl -fno-common -Wall -Wno-switch 2 | SRCS=$(wildcard *.c) 3 | OBJS=$(SRCS:.c=.o) 4 | 5 | TEST_SRCS=$(wildcard test/*.c) 6 | TESTS=$(TEST_SRCS:.c=.exe) 7 | 8 | PREFIX=/usr/local 9 | BINDIR=$(PREFIX)/bin/xcc 10 | 11 | # Stage 1 12 | xcc: $(OBJS) 13 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 14 | 15 | $(OBJS): xcc.h 16 | 17 | test/%.exe: xcc test/%.c 18 | ./xcc -Iinclude -Itest -c -o test/$*.o test/$*.c 19 | $(CC) -pthread -o $@ test/$*.o -xc test/common 20 | 21 | test: $(TESTS) 22 | for i in $^; do echo $$i; ./$$i || exit 1; echo; done 23 | test/driver.sh ./xcc 24 | 25 | test-all: test test-stage2 26 | 27 | # Stage 2 28 | stage2/xcc: $(OBJS:%=stage2/%) 29 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 30 | 31 | stage2/%.o: xcc %.c 32 | mkdir -p stage2/test 33 | ./xcc -c -o $(@D)/$*.o $*.c 34 | 35 | stage2/test/%.exe: stage2/xcc test/%.c 36 | mkdir -p stage2/test 37 | ./stage2/xcc -Iinclude -Itest -c -o stage2/test/$*.o test/$*.c 38 | $(CC) -pthread -o $@ stage2/test/$*.o -xc test/common 39 | 40 | test-stage2: $(TESTS:test/%=stage2/test/%) 41 | for i in $^; do echo $$i; ./$$i || exit 1; echo; done 42 | test/driver.sh ./stage2/xcc 43 | 44 | # Stage 3 45 | .SILENT: uninstall 46 | install: xcc 47 | @if [ ! -d $(BINDIR) ]; then \ 48 | install -d $(BINDIR); \ 49 | fi 50 | install -m 755 xcc $(BINDIR) 51 | sudo install -m 755 ./xc /usr/local/bin/ 52 | @if [ ! -d /usr/local/include/xcc/ ]; then \ 53 | sudo mkdir -p /usr/local/include/xcc/; \ 54 | fi 55 | @sudo chmod +x xc 56 | @sudo cp -r ./include/* /usr/local/include/xcc/ 57 | @rm -rf xcc tmp* $(TESTS) test/*.s test/*.exe stage2 58 | @find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';' 59 | 60 | .SILENT: clean 61 | uninstall: 62 | sudo rm -rf /usr/local/bin/xcc /usr/local/bin/xc /usr/local/include/xcc/ 63 | 64 | clean: 65 | rm -rf xcc tmp* $(TESTS) test/*.s test/*.exe stage2 66 | find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';' 67 | 68 | .PHONY: test clean test-stage2 install uninstall 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ### XCC 4 | 5 | XCC is a simple C compiler based on chibic, featuring support for including files from websites using curl and shebang support. 6 | 7 | #### Installation 8 | 9 |
10 | git clone https://github.com/x3ric/xcc
11 | cd xcc
12 | sudo make install
13 | 
14 | 15 | #### Usage 16 | 17 |
18 | xc
19 | 
20 | 21 | #### Features 22 | 23 | **Chibic Based:** Built upon chibic, XCC supports most C11 features. 24 | 25 | **GCC Backend:** Runs gcc with Web Includes & Shebang Support through XCC. 26 | 27 | **Web Includes:** Includes files from websites using curl. 28 | 29 | **Shebang Support:** Supports executing C scripts directly. 30 | 31 | #### For examples: 32 | 33 |
34 | ./examples/x11window
35 | 
36 | 37 | #### Internals 38 | 39 | XCC comprises the following stages: 40 | 41 | **Tokenize:** Breaks input into tokens. 42 | 43 | **Preprocess:** Expands macros and interprets preprocessor directives. 44 | 45 | **Parse:** Constructs abstract syntax trees and assigns types. 46 | 47 | **Codegen:** Generates assembly text for AST nodes. 48 | 49 | 50 |
51 |

Arch Linux
52 | -------------------------------------------------------------------------------- /examples/asm: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/xc -run 2 | #include 3 | #include 4 | #include 5 | 6 | void assert(int expected, int actual, char *code) { 7 | if (expected == actual) { 8 | printf("%s => %d\n", code, actual); 9 | } else { 10 | printf("%s => %d expected but got %d\n", code, expected, actual); 11 | exit(1); 12 | } 13 | } 14 | #define ASSERT(x, y) assert(x, y, #y) 15 | 16 | char *asm_fn1(void) { 17 | asm("mov $50, %rax\n\t" 18 | "mov %rbp, %rsp\n\t" 19 | "pop %rbp\n\t" 20 | "ret"); 21 | } 22 | 23 | char *asm_fn2(void) { 24 | asm inline volatile("mov $55, %rax\n\t" 25 | "mov %rbp, %rsp\n\t" 26 | "pop %rbp\n\t" 27 | "ret"); 28 | } 29 | 30 | int main() { 31 | ASSERT(50, asm_fn1()); 32 | ASSERT(55, asm_fn2()); 33 | 34 | printf("OK\n"); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/helloworld: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/xc -run 2 | #include 3 | 4 | int main() { 5 | printf("Hello World!\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /examples/print: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/xc -run 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | printf("%s %s\n",argv[1],argv[2]); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /examples/test: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/xc -run -O1 2 | #include 3 | #include 4 | #include 5 | 6 | #define ARRAY_SIZE 10000 7 | #define NUM_ITERATIONS 10000 8 | 9 | // Function to calculate the sum of an array 10 | int sum_array(int arr[], int size) { 11 | int sum = 0; 12 | for (int i = 0; i < size; i++) { 13 | sum += arr[i]; 14 | } 15 | return sum; 16 | } 17 | 18 | // Function to calculate the product of an array 19 | long long product_array(int arr[], int size) { 20 | long long product = 1; 21 | for (int i = 0; i < size; i++) { 22 | product *= arr[i]; 23 | } 24 | return product; 25 | } 26 | 27 | int main() { 28 | int array[ARRAY_SIZE]; 29 | srand(time(NULL)); 30 | 31 | // Fill array with random numbers 32 | for (int i = 0; i < ARRAY_SIZE; i++) { 33 | array[i] = rand() % 100; 34 | } 35 | 36 | clock_t start_time, end_time; 37 | double total_time; 38 | 39 | // Benchmarking sum_array function 40 | start_time = clock(); 41 | for (int i = 0; i < NUM_ITERATIONS; i++) { 42 | int result = sum_array(array, ARRAY_SIZE); 43 | } 44 | end_time = clock(); 45 | total_time = (double)(end_time - start_time) / CLOCKS_PER_SEC; 46 | printf("Time taken for sum_array function: %.6f seconds\n", total_time); 47 | 48 | // Benchmarking product_array function 49 | start_time = clock(); 50 | for (int i = 0; i < NUM_ITERATIONS; i++) { 51 | long long result = product_array(array, ARRAY_SIZE); 52 | } 53 | end_time = clock(); 54 | total_time = (double)(end_time - start_time) / CLOCKS_PER_SEC; 55 | printf("Time taken for product_array function: %.6f seconds\n", total_time); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/x11window: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/xc -run -lX11 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | Display *display; 8 | Window window; 9 | XEvent event; 10 | display = XOpenDisplay(NULL); 11 | if (display == NULL) { 12 | fprintf(stderr, "Cannot open display\n"); 13 | exit(1); 14 | } 15 | int screen = DefaultScreen(display); 16 | window = XCreateSimpleWindow(display, RootWindow(display, screen), 100, 100, 500, 500, 1,BlackPixel(display, screen), WhitePixel(display, screen)); 17 | XSelectInput(display, window, ExposureMask | KeyPressMask); 18 | XMapWindow(display, window); 19 | while (1) { 20 | XNextEvent(display, &event); 21 | if (event.type == Expose) { 22 | printf("Window exposed\n"); 23 | } 24 | if (event.type == KeyPress) { 25 | break; 26 | } 27 | } 28 | XDestroyWindow(display, window); 29 | XCloseDisplay(display); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /hashmap.c: -------------------------------------------------------------------------------- 1 | // This is an implementation of the open-addressing hash table. 2 | 3 | #include "xcc.h" 4 | 5 | // Initial hash bucket size 6 | #define INIT_SIZE 16 7 | 8 | // Rehash if the usage exceeds 70%. 9 | #define HIGH_WATERMARK 70 10 | 11 | // We'll keep the usage below 50% after rehashing. 12 | #define LOW_WATERMARK 50 13 | 14 | // Represents a deleted hash entry 15 | #define TOMBSTONE ((void *)-1) 16 | 17 | static uint64_t fnv_hash(char *s, int len) { 18 | uint64_t hash = 0xcbf29ce484222325; 19 | for (int i = 0; i < len; i++) { 20 | hash *= 0x100000001b3; 21 | hash ^= (unsigned char)s[i]; 22 | } 23 | return hash; 24 | } 25 | 26 | // Make room for new entires in a given hashmap by removing 27 | // tombstones and possibly extending the bucket size. 28 | static void rehash(HashMap *map) { 29 | // Compute the size of the new hashmap. 30 | int nkeys = 0; 31 | for (int i = 0; i < map->capacity; i++) 32 | if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) 33 | nkeys++; 34 | 35 | int cap = map->capacity; 36 | while ((nkeys * 100) / cap >= LOW_WATERMARK) 37 | cap = cap * 2; 38 | assert(cap > 0); 39 | 40 | // Create a new hashmap and copy all key-values. 41 | HashMap map2 = {}; 42 | map2.buckets = calloc(cap, sizeof(HashEntry)); 43 | map2.capacity = cap; 44 | 45 | for (int i = 0; i < map->capacity; i++) { 46 | HashEntry *ent = &map->buckets[i]; 47 | if (ent->key && ent->key != TOMBSTONE) 48 | hashmap_put2(&map2, ent->key, ent->keylen, ent->val); 49 | } 50 | 51 | assert(map2.used == nkeys); 52 | *map = map2; 53 | } 54 | 55 | static bool match(HashEntry *ent, char *key, int keylen) { 56 | return ent->key && ent->key != TOMBSTONE && 57 | ent->keylen == keylen && memcmp(ent->key, key, keylen) == 0; 58 | } 59 | 60 | static HashEntry *get_entry(HashMap *map, char *key, int keylen) { 61 | if (!map->buckets) 62 | return NULL; 63 | 64 | uint64_t hash = fnv_hash(key, keylen); 65 | 66 | for (int i = 0; i < map->capacity; i++) { 67 | HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; 68 | if (match(ent, key, keylen)) 69 | return ent; 70 | if (ent->key == NULL) 71 | return NULL; 72 | } 73 | unreachable(); 74 | } 75 | 76 | static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) { 77 | if (!map->buckets) { 78 | map->buckets = calloc(INIT_SIZE, sizeof(HashEntry)); 79 | map->capacity = INIT_SIZE; 80 | } else if ((map->used * 100) / map->capacity >= HIGH_WATERMARK) { 81 | rehash(map); 82 | } 83 | 84 | uint64_t hash = fnv_hash(key, keylen); 85 | 86 | for (int i = 0; i < map->capacity; i++) { 87 | HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; 88 | 89 | if (match(ent, key, keylen)) 90 | return ent; 91 | 92 | if (ent->key == TOMBSTONE) { 93 | ent->key = key; 94 | ent->keylen = keylen; 95 | return ent; 96 | } 97 | 98 | if (ent->key == NULL) { 99 | ent->key = key; 100 | ent->keylen = keylen; 101 | map->used++; 102 | return ent; 103 | } 104 | } 105 | unreachable(); 106 | } 107 | 108 | void *hashmap_get(HashMap *map, char *key) { 109 | return hashmap_get2(map, key, strlen(key)); 110 | } 111 | 112 | void *hashmap_get2(HashMap *map, char *key, int keylen) { 113 | HashEntry *ent = get_entry(map, key, keylen); 114 | return ent ? ent->val : NULL; 115 | } 116 | 117 | void hashmap_put(HashMap *map, char *key, void *val) { 118 | hashmap_put2(map, key, strlen(key), val); 119 | } 120 | 121 | void hashmap_put2(HashMap *map, char *key, int keylen, void *val) { 122 | HashEntry *ent = get_or_insert_entry(map, key, keylen); 123 | ent->val = val; 124 | } 125 | 126 | void hashmap_delete(HashMap *map, char *key) { 127 | hashmap_delete2(map, key, strlen(key)); 128 | } 129 | 130 | void hashmap_delete2(HashMap *map, char *key, int keylen) { 131 | HashEntry *ent = get_entry(map, key, keylen); 132 | if (ent) 133 | ent->key = TOMBSTONE; 134 | } 135 | 136 | void hashmap_test(void) { 137 | HashMap *map = calloc(1, sizeof(HashMap)); 138 | 139 | for (int i = 0; i < 5000; i++) 140 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 141 | for (int i = 1000; i < 2000; i++) 142 | hashmap_delete(map, format("key %d", i)); 143 | for (int i = 1500; i < 1600; i++) 144 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 145 | for (int i = 6000; i < 7000; i++) 146 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 147 | 148 | for (int i = 0; i < 1000; i++) 149 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 150 | for (int i = 1000; i < 1500; i++) 151 | assert(hashmap_get(map, "no such key") == NULL); 152 | for (int i = 1500; i < 1600; i++) 153 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 154 | for (int i = 1600; i < 2000; i++) 155 | assert(hashmap_get(map, "no such key") == NULL); 156 | for (int i = 2000; i < 5000; i++) 157 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 158 | for (int i = 5000; i < 6000; i++) 159 | assert(hashmap_get(map, "no such key") == NULL); 160 | for (int i = 6000; i < 7000; i++) 161 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 162 | 163 | assert(hashmap_get(map, "no such key") == NULL); 164 | printf("OK\n"); 165 | } 166 | -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDFLOAT_H 2 | #define __STDFLOAT_H 3 | 4 | #define DECIMAL_DIG 21 5 | #define FLT_EVAL_METHOD 0 // C11 5.2.4.2.2p9 6 | #define FLT_RADIX 2 7 | #define FLT_ROUNDS 1 // C11 5.2.4.2.2p8: to nearest 8 | 9 | #define FLT_DIG 6 10 | #define FLT_EPSILON 0x1p-23 11 | #define FLT_MANT_DIG 24 12 | #define FLT_MAX 0x1.fffffep+127 13 | #define FLT_MAX_10_EXP 38 14 | #define FLT_MAX_EXP 128 15 | #define FLT_MIN 0x1p-126 16 | #define FLT_MIN_10_EXP -37 17 | #define FLT_MIN_EXP -125 18 | #define FLT_TRUE_MIN 0x1p-149 19 | 20 | #define DBL_DIG 15 21 | #define DBL_EPSILON 0x1p-52 22 | #define DBL_MANT_DIG 53 23 | #define DBL_MAX 0x1.fffffffffffffp+1023 24 | #define DBL_MAX_10_EXP 308 25 | #define DBL_MAX_EXP 1024 26 | #define DBL_MIN 0x1p-1022 27 | #define DBL_MIN_10_EXP -307 28 | #define DBL_MIN_EXP -1021 29 | #define DBL_TRUE_MIN 0x0.0000000000001p-1022 30 | 31 | #define LDBL_DIG 15 32 | #define LDBL_EPSILON 0x1p-52 33 | #define LDBL_MANT_DIG 53 34 | #define LDBL_MAX 0x1.fffffffffffffp+1023 35 | #define LDBL_MAX_10_EXP 308 36 | #define LDBL_MAX_EXP 1024 37 | #define LDBL_MIN 0x1p-1022 38 | #define LDBL_MIN_10_EXP -307 39 | #define LDBL_MIN_EXP -1021 40 | #define LDBL_TRUE_MIN 0x0.0000000000001p-1022 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/stdalign.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDALIGN_H 2 | #define __STDALIGN_H 3 | 4 | #define alignas _Alignas 5 | #define alignof _Alignof 6 | #define __alignas_is_defined 1 7 | #define __alignof_is_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDARG_H 2 | #define __STDARG_H 3 | 4 | typedef struct { 5 | unsigned int gp_offset; 6 | unsigned int fp_offset; 7 | void *overflow_arg_area; 8 | void *reg_save_area; 9 | } __va_elem; 10 | 11 | typedef __va_elem va_list[1]; 12 | 13 | #define va_start(ap, last) \ 14 | do { *(ap) = *(__va_elem *)__va_area__; } while (0) 15 | 16 | #define va_end(ap) 17 | 18 | static void *__va_arg_mem(__va_elem *ap, int sz, int align) { 19 | void *p = ap->overflow_arg_area; 20 | if (align > 8) 21 | p = (p + 15) / 16 * 16; 22 | ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8; 23 | return p; 24 | } 25 | 26 | static void *__va_arg_gp(__va_elem *ap, int sz, int align) { 27 | if (ap->gp_offset >= 48) 28 | return __va_arg_mem(ap, sz, align); 29 | 30 | void *r = ap->reg_save_area + ap->gp_offset; 31 | ap->gp_offset += 8; 32 | return r; 33 | } 34 | 35 | static void *__va_arg_fp(__va_elem *ap, int sz, int align) { 36 | if (ap->fp_offset >= 112) 37 | return __va_arg_mem(ap, sz, align); 38 | 39 | void *r = ap->reg_save_area + ap->fp_offset; 40 | ap->fp_offset += 8; 41 | return r; 42 | } 43 | 44 | #define va_arg(ap, ty) \ 45 | ({ \ 46 | int klass = __builtin_reg_class(ty); \ 47 | *(ty *)(klass == 0 ? __va_arg_gp(ap, sizeof(ty), _Alignof(ty)) : \ 48 | klass == 1 ? __va_arg_fp(ap, sizeof(ty), _Alignof(ty)) : \ 49 | __va_arg_mem(ap, sizeof(ty), _Alignof(ty))); \ 50 | }) 51 | 52 | #define va_copy(dest, src) ((dest)[0] = (src)[0]) 53 | 54 | #define __GNUC_VA_LIST 1 55 | typedef va_list __gnuc_va_list; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/stdatomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDATOMIC_H 2 | #define __STDATOMIC_H 3 | 4 | #define ATOMIC_BOOL_LOCK_FREE 1 5 | #define ATOMIC_CHAR_LOCK_FREE 1 6 | #define ATOMIC_CHAR16_T_LOCK_FREE 1 7 | #define ATOMIC_CHAR32_T_LOCK_FREE 1 8 | #define ATOMIC_WCHAR_T_LOCK_FREE 1 9 | #define ATOMIC_SHORT_LOCK_FREE 1 10 | #define ATOMIC_INT_LOCK_FREE 1 11 | #define ATOMIC_LONG_LOCK_FREE 1 12 | #define ATOMIC_LLONG_LOCK_FREE 1 13 | #define ATOMIC_POINTER_LOCK_FREE 1 14 | 15 | typedef enum { 16 | memory_order_relaxed, 17 | memory_order_consume, 18 | memory_order_acquire, 19 | memory_order_release, 20 | memory_order_acq_rel, 21 | memory_order_seq_cst, 22 | } memory_order; 23 | 24 | #define ATOMIC_FLAG_INIT(x) (x) 25 | #define atomic_init(addr, val) (*(addr) = (val)) 26 | #define kill_dependency(x) (x) 27 | #define atomic_thread_fence(order) 28 | #define atomic_signal_fence(order) 29 | #define atomic_is_lock_free(x) 1 30 | 31 | #define atomic_load(addr) (*(addr)) 32 | #define atomic_store(addr, val) (*(addr) = (val)) 33 | 34 | #define atomic_load_explicit(addr, order) (*(addr)) 35 | #define atomic_store_explicit(addr, val, order) (*(addr) = (val)) 36 | 37 | #define atomic_fetch_add(obj, val) (*(obj) += (val)) 38 | #define atomic_fetch_sub(obj, val) (*(obj) -= (val)) 39 | #define atomic_fetch_or(obj, val) (*(obj) |= (val)) 40 | #define atomic_fetch_xor(obj, val) (*(obj) ^= (val)) 41 | #define atomic_fetch_and(obj, val) (*(obj) &= (val)) 42 | 43 | #define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val)) 44 | #define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val)) 45 | #define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val)) 46 | #define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val)) 47 | #define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val)) 48 | 49 | #define atomic_compare_exchange_weak(p, old, new) \ 50 | __builtin_compare_and_swap((p), (old), (new)) 51 | 52 | #define atomic_compare_exchange_strong(p, old, new) \ 53 | __builtin_compare_and_swap((p), (old), (new)) 54 | 55 | #define atomic_exchange(obj, val) __builtin_atomic_exchange((obj), (val)) 56 | #define atomic_exchange_explicit(obj, val, order) __builtin_atomic_exchange((obj), (val)) 57 | 58 | #define atomic_flag_test_and_set(obj) atomic_exchange((obj), 1) 59 | #define atomic_flag_test_and_set_explicit(obj, order) atomic_exchange((obj), 1) 60 | #define atomic_flag_clear(obj) (*(obj) = 0) 61 | #define atomic_flag_clear_explicit(obj, order) (*(obj) = 0) 62 | 63 | typedef _Atomic _Bool atomic_flag; 64 | typedef _Atomic _Bool atomic_bool; 65 | typedef _Atomic char atomic_char; 66 | typedef _Atomic signed char atomic_schar; 67 | typedef _Atomic unsigned char atomic_uchar; 68 | typedef _Atomic short atomic_short; 69 | typedef _Atomic unsigned short atomic_ushort; 70 | typedef _Atomic int atomic_int; 71 | typedef _Atomic unsigned int atomic_uint; 72 | typedef _Atomic long atomic_long; 73 | typedef _Atomic unsigned long atomic_ulong; 74 | typedef _Atomic long long atomic_llong; 75 | typedef _Atomic unsigned long long atomic_ullong; 76 | typedef _Atomic unsigned short atomic_char16_t; 77 | typedef _Atomic unsigned atomic_char32_t; 78 | typedef _Atomic unsigned atomic_wchar_t; 79 | typedef _Atomic signed char atomic_int_least8_t; 80 | typedef _Atomic unsigned char atomic_uint_least8_t; 81 | typedef _Atomic short atomic_int_least16_t; 82 | typedef _Atomic unsigned short atomic_uint_least16_t; 83 | typedef _Atomic int atomic_int_least32_t; 84 | typedef _Atomic unsigned int atomic_uint_least32_t; 85 | typedef _Atomic long atomic_int_least64_t; 86 | typedef _Atomic unsigned long atomic_uint_least64_t; 87 | typedef _Atomic signed char atomic_int_fast8_t; 88 | typedef _Atomic unsigned char atomic_uint_fast8_t; 89 | typedef _Atomic short atomic_int_fast16_t; 90 | typedef _Atomic unsigned short atomic_uint_fast16_t; 91 | typedef _Atomic int atomic_int_fast32_t; 92 | typedef _Atomic unsigned int atomic_uint_fast32_t; 93 | typedef _Atomic long atomic_int_fast64_t; 94 | typedef _Atomic unsigned long atomic_uint_fast64_t; 95 | typedef _Atomic long atomic_intptr_t; 96 | typedef _Atomic unsigned long atomic_uintptr_t; 97 | typedef _Atomic unsigned long atomic_size_t; 98 | typedef _Atomic long atomic_ptrdiff_t; 99 | typedef _Atomic long atomic_intmax_t; 100 | typedef _Atomic unsigned long atomic_uintmax_t; 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDDEF_H 2 | #define __STDDEF_H 3 | 4 | #define NULL ((void *)0) 5 | 6 | typedef unsigned long size_t; 7 | typedef long ptrdiff_t; 8 | typedef unsigned int wchar_t; 9 | typedef long max_align_t; 10 | 11 | #define offsetof(type, member) ((size_t)&(((type *)0)->member)) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDNORETURN_H 2 | #define __STDNORETURN_H 3 | 4 | #define noreturn _Noreturn 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "xcc.h" 2 | #include 3 | #include 4 | 5 | typedef enum { 6 | FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO, 7 | } FileType; 8 | 9 | StringArray include_paths; 10 | int opt_O = 0; 11 | bool opt_fcommon = true; 12 | bool opt_run; 13 | bool opt_asm; 14 | bool opt_fpic; 15 | 16 | char *opt_gccarg; 17 | char *opt_rarg; 18 | 19 | static FileType opt_x; 20 | static StringArray opt_include; 21 | static bool opt_E; 22 | static bool opt_M; 23 | static bool opt_MD; 24 | static bool opt_MMD; 25 | static bool opt_MP; 26 | static bool opt_S; 27 | static bool opt_c; 28 | static bool opt_cc1; 29 | static bool opt_gcc; 30 | static bool opt_hash_hash_hash; 31 | static bool opt_static; 32 | static bool opt_shared; 33 | static char *opt_MF; 34 | static char *opt_MT; 35 | static char *opt_o; 36 | 37 | static StringArray ld_extra_args; 38 | static StringArray std_include_paths; 39 | 40 | char *base_file; 41 | static char *output_file; 42 | 43 | static StringArray input_paths; 44 | static StringArray tmpfiles; 45 | 46 | static void usage(int status) { 47 | fprintf(stderr, "XCompiler %s - a simple C compiler\n", VERSION); 48 | fprintf(stderr, "Usage: xc [options] file...\n"); 49 | fprintf(stderr, "Options:\n"); 50 | fprintf(stderr, "Compilation Options:\n"); 51 | fprintf(stderr, " %-20s %s\n", "-o ", "Output to specified file"); 52 | fprintf(stderr, " %-20s %s\n", "-S", "Compile only; do not assemble or link"); 53 | fprintf(stderr, " %-20s %s\n", "-c", "Compile source files without linking"); 54 | fprintf(stderr, " %-20s %s\n", "-E", "Preprocess only; do not compile, assemble, or link"); 55 | fprintf(stderr, " %-20s %s\n", "-I", "Add directory to the include search path"); 56 | fprintf(stderr, " %-20s %s\n", "-D", "Define macro"); 57 | fprintf(stderr, " %-20s %s\n", "-U", "Undefine macro"); 58 | fprintf(stderr, " %-20s %s\n", "-include ", "Process file as if included"); 59 | fprintf(stderr, " %-20s %s\n", "-x ", "Specify source language"); 60 | fprintf(stderr, " %-20s %s\n", "-O", "Compile and Optimize using gcc backend"); 61 | fprintf(stderr, " %-20s %s\n", "-fpic", "Generate position-independent code (PIC)"); 62 | fprintf(stderr, " %-20s %s\n", "-fPIC", "Generate PIC suitable for use in shared libraries"); 63 | fprintf(stderr, " %-20s %s\n", "-idirafter ", "Add directory to include search path after system directories"); 64 | fprintf(stderr, " %-20s %s\n", "-static", "Link statically"); 65 | fprintf(stderr, " %-20s %s\n", "-shared", "Create shared object"); 66 | fprintf(stderr, " %-20s %s\n", "-L ", "Add directory to the library search path"); 67 | fprintf(stderr, " %-20s %s\n", "--help", "Display help message"); 68 | fprintf(stderr, "\nLinking Options:\n"); 69 | fprintf(stderr, " %-20s %s\n", "-l", "Link with specified library"); 70 | fprintf(stderr, " %-20s %s\n", "-Wl,