├── test ├── include3.h ├── include4.h ├── include2.h ├── include1.h ├── pragma-once.c ├── thirdparty │ ├── git.sh │ ├── common │ ├── tinycc.sh │ ├── libpng.sh │ ├── sqlite.sh │ └── cpython.sh ├── stdhdr.c ├── commonsym.c ├── const.c ├── offsetof.c ├── typeof.c ├── line.c ├── extern.c ├── compat.c ├── generic.c ├── asm.c ├── test.h ├── typedef.c ├── decl.c ├── alloca.c ├── complit.c ├── tls.c ├── enum.c ├── usualconv.c ├── vla.c ├── varargs.c ├── union.c ├── atomic.c ├── bitfield.c ├── alignof.c ├── builtin.c ├── cast.c ├── string.c ├── pointer.c ├── attribute.c ├── constexpr.c ├── variable.c ├── float.c ├── literal.c ├── common ├── sizeof.c ├── unicode.c ├── struct.c ├── arith.c ├── control.c ├── macro.c ├── driver.sh ├── initializer.c └── function.c ├── include ├── stdnoreturn.h ├── stdbool.h ├── stdalign.h ├── stddef.h ├── float.h ├── stdarg.h └── stdatomic.h ├── examples ├── helloworld ├── print ├── asm ├── x11window └── test ├── strings.c ├── LICENSE ├── README.md ├── xc ├── Makefile ├── hashmap.c ├── unicode.c ├── type.c ├── xcc.h ├── tokenize.c └── main.c /test/include3.h: -------------------------------------------------------------------------------- 1 | #define foo 3 2 | -------------------------------------------------------------------------------- /test/include4.h: -------------------------------------------------------------------------------- 1 | #define foo 4 2 | -------------------------------------------------------------------------------- /test/include2.h: -------------------------------------------------------------------------------- 1 | int include2 = 7; 2 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDNORETURN_H 2 | #define __STDNORETURN_H 3 | 4 | #define noreturn _Noreturn 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /test/include1.h: -------------------------------------------------------------------------------- 1 | #include "include2.h" 2 | 3 | char *include1_filename = __FILE__; 4 | int include1_line = __LINE__; 5 | 6 | int include1 = 5; 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/pragma-once.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #pragma once 4 | 5 | #include "test/pragma-once.c" 6 | 7 | int main() { 8 | printf("OK\n"); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/thirdparty/git.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:git/git.git' 3 | . test/thirdparty/common 4 | git reset --hard 54e85e7af1ac9e9a92888060d6811ae767fea1bc 5 | 6 | $make clean 7 | $make V=1 CC=$xcc test 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/thirdparty/common: -------------------------------------------------------------------------------- 1 | make="make -j$(nproc)" 2 | xcc=`pwd`/xcc 3 | 4 | dir=$(basename -s .git $repo) 5 | 6 | set -e -x 7 | 8 | mkdir -p thirdparty 9 | cd thirdparty 10 | [ -d $dir ] || git clone $repo 11 | cd $dir 12 | -------------------------------------------------------------------------------- /test/stdhdr.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | printf("OK\n"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/thirdparty/tinycc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:TinyCC/tinycc.git' 3 | . test/thirdparty/common 4 | git reset --hard df67d8617b7d1d03a480a28f9f901848ffbfb7ec 5 | 6 | ./configure --cc=$xcc 7 | $make clean 8 | $make 9 | $make CC=cc test 10 | -------------------------------------------------------------------------------- /test/thirdparty/libpng.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:rui314/libpng.git' 3 | . test/thirdparty/common 4 | git reset --hard dbe3e0c43e549a1602286144d94b0666549b18e6 5 | 6 | CC=$xcc ./configure 7 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 8 | $make clean 9 | $make 10 | $make test 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/thirdparty/sqlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:sqlite/sqlite.git' 3 | . test/thirdparty/common 4 | git reset --hard 86f477edaa17767b39c7bae5b67cac8580f7a8c1 5 | 6 | CC=$xcc CFLAGS=-D_GNU_SOURCE ./configure 7 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 8 | $make clean 9 | $make 10 | $make test 11 | -------------------------------------------------------------------------------- /test/commonsym.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int x; 4 | int x = 5; 5 | int y = 7; 6 | int y; 7 | int common_ext1; 8 | int common_ext2; 9 | static int common_local; 10 | 11 | int main() { 12 | ASSERT(5, x); 13 | ASSERT(7, y); 14 | ASSERT(0, common_ext1); 15 | ASSERT(3, common_ext2); 16 | 17 | printf("OK\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/const.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | { const x; } 5 | { int const x; } 6 | { const int x; } 7 | { const int const const x; } 8 | ASSERT(5, ({ const x = 5; x; })); 9 | ASSERT(8, ({ const x = 8; int *const y=&x; *y; })); 10 | ASSERT(6, ({ const x = 6; *(const * const)&x; })); 11 | 12 | printf("OK\n"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/offsetof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | 4 | typedef struct { 5 | int a; 6 | char b; 7 | int c; 8 | double d; 9 | } T; 10 | 11 | int main() { 12 | ASSERT(0, offsetof(T, a)); 13 | ASSERT(4, offsetof(T, b)); 14 | ASSERT(8, offsetof(T, c)); 15 | ASSERT(16, offsetof(T, d)); 16 | 17 | printf("OK\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/typeof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(3, ({ typeof(int) x=3; x; })); 5 | ASSERT(3, ({ typeof(1) x=3; x; })); 6 | ASSERT(4, ({ int x; typeof(x) y; sizeof(y); })); 7 | ASSERT(8, ({ int x; typeof(&x) y; sizeof(y); })); 8 | ASSERT(4, ({ typeof("foo") x; sizeof(x); })); 9 | ASSERT(12, sizeof(typeof(struct { int a,b,c; }))); 10 | 11 | printf("OK\n"); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/line.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | #line 500 "foo" 5 | ASSERT(501, __LINE__); 6 | ASSERT(0, strcmp(__FILE__, "foo")); 7 | 8 | #line 800 "bar" 9 | ASSERT(801, __LINE__); 10 | ASSERT(0, strcmp(__FILE__, "bar")); 11 | 12 | #line 1 13 | ASSERT(2, __LINE__); 14 | 15 | # 200 "xyz" 2 3 16 | ASSERT(201, __LINE__); 17 | ASSERT(0, strcmp(__FILE__, "xyz")); 18 | 19 | printf("OK\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/extern.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | extern int ext1; 4 | extern int *ext2; 5 | 6 | inline int inline_fn(void) { 7 | return 3; 8 | } 9 | 10 | int main() { 11 | ASSERT(5, ext1); 12 | ASSERT(5, *ext2); 13 | 14 | extern int ext3; 15 | ASSERT(7, ext3); 16 | 17 | int ext_fn1(int x); 18 | ASSERT(5, ext_fn1(5)); 19 | 20 | extern int ext_fn2(int x); 21 | ASSERT(8, ext_fn2(8)); 22 | 23 | printf("OK\n"); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compat.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | _Noreturn noreturn_fn(int restrict x) { 4 | exit(0); 5 | } 6 | 7 | void funcy_type(int arg[restrict static 3]) {} 8 | 9 | int main() { 10 | { volatile x; } 11 | { int volatile x; } 12 | { volatile int x; } 13 | { volatile int volatile volatile x; } 14 | { int volatile * volatile volatile x; } 15 | { auto ** restrict __restrict __restrict__ const volatile *x; } 16 | 17 | printf("OK\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/generic.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(1, _Generic(100.0, double: 1, int *: 2, int: 3, float: 4)); 5 | ASSERT(2, _Generic((int *)0, double: 1, int *: 2, int: 3, float: 4)); 6 | ASSERT(2, _Generic((int[3]){}, double: 1, int *: 2, int: 3, float: 4)); 7 | ASSERT(3, _Generic(100, double: 1, int *: 2, int: 3, float: 4)); 8 | ASSERT(4, _Generic(100f, double: 1, int *: 2, int: 3, float: 4)); 9 | 10 | printf("OK\n"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/thirdparty/cpython.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:python/cpython.git' 3 | . test/thirdparty/common 4 | git reset --hard c75330605d4795850ec74fdc4d69aa5d92f76c00 5 | 6 | # Python's './configure' command misidentifies xcc as icc 7 | # (Intel C Compiler) because icc is a substring of xcc. 8 | # Modify the configure file as a workaround. 9 | sed -i -e 1996,2011d configure.ac 10 | autoreconf 11 | 12 | CC=$xcc ./configure 13 | $make clean 14 | $make 15 | $make test 16 | -------------------------------------------------------------------------------- /test/asm.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | char *asm_fn1(void) { 4 | asm("mov $50, %rax\n\t" 5 | "mov %rbp, %rsp\n\t" 6 | "pop %rbp\n\t" 7 | "ret"); 8 | } 9 | 10 | char *asm_fn2(void) { 11 | asm inline volatile("mov $55, %rax\n\t" 12 | "mov %rbp, %rsp\n\t" 13 | "pop %rbp\n\t" 14 | "ret"); 15 | } 16 | 17 | int main() { 18 | ASSERT(50, asm_fn1()); 19 | ASSERT(55, asm_fn2()); 20 | 21 | printf("OK\n"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #define ASSERT(x, y) assert(x, y, #y) 2 | 3 | void assert(int expected, int actual, char *code); 4 | int printf(char *fmt, ...); 5 | int sprintf(char *buf, char *fmt, ...); 6 | int vsprintf(char *buf, char *fmt, void *ap); 7 | int strcmp(char *p, char *q); 8 | int strncmp(char *p, char *q, long n); 9 | int memcmp(char *p, char *q, long n); 10 | void exit(int n); 11 | int vsprintf(); 12 | long strlen(char *s); 13 | void *memcpy(void *dest, void *src, long n); 14 | void *memset(void *s, int c, long n); 15 | -------------------------------------------------------------------------------- /test/typedef.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | typedef int MyInt, MyInt2[4]; 4 | typedef int; 5 | 6 | int main() { 7 | ASSERT(1, ({ typedef int t; t x=1; x; })); 8 | ASSERT(1, ({ typedef struct {int a;} t; t x; x.a=1; x.a; })); 9 | ASSERT(1, ({ typedef int t; t t=1; t; })); 10 | ASSERT(2, ({ typedef struct {int a;} t; { typedef int t; } t x; x.a=2; x.a; })); 11 | ASSERT(4, ({ typedef t; t x; sizeof(x); })); 12 | ASSERT(3, ({ MyInt x=3; x; })); 13 | ASSERT(16, ({ MyInt2 x; sizeof(x); })); 14 | 15 | printf("OK\n"); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/decl.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(1, ({ char x; sizeof(x); })); 5 | ASSERT(2, ({ short int x; sizeof(x); })); 6 | ASSERT(2, ({ int short x; sizeof(x); })); 7 | ASSERT(4, ({ int x; sizeof(x); })); 8 | ASSERT(8, ({ long int x; sizeof(x); })); 9 | ASSERT(8, ({ int long x; sizeof(x); })); 10 | 11 | ASSERT(8, ({ long long x; sizeof(x); })); 12 | 13 | ASSERT(0, ({ _Bool x=0; x; })); 14 | ASSERT(1, ({ _Bool x=1; x; })); 15 | ASSERT(1, ({ _Bool x=2; x; })); 16 | ASSERT(1, (_Bool)1); 17 | ASSERT(1, (_Bool)2); 18 | ASSERT(0, (_Bool)(char)256); 19 | 20 | printf("OK\n"); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/alloca.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | void *fn(int x, void *p, int y) { return p; } 4 | 5 | int main() { 6 | int i = 0; 7 | 8 | char *p1 = alloca(16); 9 | char *p2 = alloca(16); 10 | char *p3 = 1 + (char *)alloca(3) + 1; 11 | p3 -= 2; 12 | char *p4 = fn(1, alloca(16), 3); 13 | 14 | ASSERT(16, p1 - p2); 15 | ASSERT(16, p2 - p3); 16 | ASSERT(16, p3 - p4); 17 | 18 | memcpy(p1, "0123456789abcdef", 16); 19 | memcpy(p2, "ghijklmnopqrstuv", 16); 20 | memcpy(p3, "wxy", 3); 21 | 22 | ASSERT(0, memcmp(p1, "0123456789abcdef", 16)); 23 | ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16)); 24 | ASSERT(0, memcmp(p3, "wxy", 3)); 25 | 26 | printf("OK\n"); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/complit.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | typedef struct Tree { 4 | int val; 5 | struct Tree *lhs; 6 | struct Tree *rhs; 7 | } Tree; 8 | 9 | Tree *tree = &(Tree){ 10 | 1, 11 | &(Tree){ 12 | 2, 13 | &(Tree){ 3, 0, 0 }, 14 | &(Tree){ 4, 0, 0 } 15 | }, 16 | 0 17 | }; 18 | 19 | int main() { 20 | ASSERT(1, (int){1}); 21 | ASSERT(2, ((int[]){0,1,2})[2]); 22 | ASSERT('a', ((struct {char a; int b;}){'a', 3}).a); 23 | ASSERT(3, ({ int x=3; (int){x}; })); 24 | (int){3} = 5; 25 | 26 | ASSERT(1, tree->val); 27 | ASSERT(2, tree->lhs->val); 28 | ASSERT(3, tree->lhs->lhs->val); 29 | ASSERT(4, tree->lhs->rhs->val); 30 | 31 | printf("OK\n"); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/tls.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | _Thread_local int v1; 6 | _Thread_local int v2 = 5; 7 | int v3 = 7; 8 | 9 | int thread_main(void *unused) { 10 | ASSERT(0, v1); 11 | ASSERT(5, v2); 12 | ASSERT(7, v3); 13 | 14 | v1 = 1; 15 | v2 = 2; 16 | v3 = 3; 17 | 18 | ASSERT(1, v1); 19 | ASSERT(2, v2); 20 | ASSERT(3, v3); 21 | 22 | return 0; 23 | } 24 | 25 | int main() { 26 | pthread_t thr; 27 | 28 | ASSERT(0, v1); 29 | ASSERT(5, v2); 30 | ASSERT(7, v3); 31 | 32 | ASSERT(0, pthread_create(&thr, NULL, thread_main, NULL)); 33 | ASSERT(0, pthread_join(thr, NULL)); 34 | 35 | ASSERT(0, v1); 36 | ASSERT(5, v2); 37 | ASSERT(3, v3); 38 | 39 | printf("OK\n"); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/enum.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(0, ({ enum { zero, one, two }; zero; })); 5 | ASSERT(1, ({ enum { zero, one, two }; one; })); 6 | ASSERT(2, ({ enum { zero, one, two }; two; })); 7 | ASSERT(5, ({ enum { five=5, six, seven }; five; })); 8 | ASSERT(6, ({ enum { five=5, six, seven }; six; })); 9 | ASSERT(0, ({ enum { zero, five=5, three=3, four }; zero; })); 10 | ASSERT(5, ({ enum { zero, five=5, three=3, four }; five; })); 11 | ASSERT(3, ({ enum { zero, five=5, three=3, four }; three; })); 12 | ASSERT(4, ({ enum { zero, five=5, three=3, four }; four; })); 13 | ASSERT(4, ({ enum { zero, one, two } x; sizeof(x); })); 14 | ASSERT(4, ({ enum t { zero, one, two }; enum t y; sizeof(y); })); 15 | 16 | printf("OK\n"); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /strings.c: -------------------------------------------------------------------------------- 1 | #include "xcc.h" 2 | 3 | void strarray_push(StringArray *arr, char *s) { 4 | if (!arr->data) { 5 | arr->data = calloc(8, sizeof(char *)); 6 | arr->capacity = 8; 7 | } 8 | 9 | if (arr->capacity == arr->len) { 10 | arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2); 11 | arr->capacity *= 2; 12 | for (int i = arr->len; i < arr->capacity; i++) 13 | arr->data[i] = NULL; 14 | } 15 | 16 | arr->data[arr->len++] = s; 17 | } 18 | 19 | // Takes a printf-style format string and returns a formatted string. 20 | char *format(char *fmt, ...) { 21 | char *buf; 22 | size_t buflen; 23 | FILE *out = open_memstream(&buf, &buflen); 24 | 25 | va_list ap; 26 | va_start(ap, fmt); 27 | vfprintf(out, fmt, ap); 28 | va_end(ap); 29 | fclose(out); 30 | return buf; 31 | } 32 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/usualconv.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | static int ret10(void) { return 10; } 4 | 5 | int main() { 6 | ASSERT((long)-5, -10 + (long)5); 7 | ASSERT((long)-15, -10 - (long)5); 8 | ASSERT((long)-50, -10 * (long)5); 9 | ASSERT((long)-2, -10 / (long)5); 10 | 11 | ASSERT(1, -2 < (long)-1); 12 | ASSERT(1, -2 <= (long)-1); 13 | ASSERT(0, -2 > (long)-1); 14 | ASSERT(0, -2 >= (long)-1); 15 | 16 | ASSERT(1, (long)-2 < -1); 17 | ASSERT(1, (long)-2 <= -1); 18 | ASSERT(0, (long)-2 > -1); 19 | ASSERT(0, (long)-2 >= -1); 20 | 21 | ASSERT(0, 2147483647 + 2147483647 + 2); 22 | ASSERT((long)-1, ({ long x; x=-1; x; })); 23 | 24 | ASSERT(1, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[0]; })); 25 | ASSERT(0, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[-1]; })); 26 | ASSERT(5, ({ struct t {char a;} x, y; x.a=5; y=x; y.a; })); 27 | 28 | ASSERT(10, (1 ? ret10 : (void *)0)()); 29 | 30 | printf("OK\n"); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/vla.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(20, ({ int n=5; int x[n]; sizeof(x); })); 5 | ASSERT((5+1)*(8*2)*4, ({ int m=5, n=8; int x[m+1][n*2]; sizeof(x); })); 6 | 7 | ASSERT(8, ({ char n=10; int (*x)[n][n+2]; sizeof(x); })); 8 | ASSERT(480, ({ char n=10; int (*x)[n][n+2]; sizeof(*x); })); 9 | ASSERT(48, ({ char n=10; int (*x)[n][n+2]; sizeof(**x); })); 10 | ASSERT(4, ({ char n=10; int (*x)[n][n+2]; sizeof(***x); })); 11 | 12 | ASSERT(60, ({ char n=3; int x[5][n]; sizeof(x); })); 13 | ASSERT(12, ({ char n=3; int x[5][n]; sizeof(*x); })); 14 | 15 | ASSERT(60, ({ char n=3; int x[n][5]; sizeof(x); })); 16 | ASSERT(20, ({ char n=3; int x[n][5]; sizeof(*x); })); 17 | 18 | ASSERT(0, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i 3 | 4 | int sum1(int x, ...) { 5 | va_list ap; 6 | va_start(ap, x); 7 | 8 | for (;;) { 9 | int y = va_arg(ap, int); 10 | if (y == 0) 11 | return x; 12 | x += y; 13 | } 14 | } 15 | 16 | int sum2(int x, ...) { 17 | va_list ap; 18 | va_start(ap, x); 19 | 20 | for (;;) { 21 | double y = va_arg(ap, double); 22 | x += y; 23 | 24 | int z = va_arg(ap, int); 25 | if (z == 0) 26 | return x; 27 | x += z; 28 | } 29 | } 30 | 31 | void fmt(char *buf, char *fmt, ...) { 32 | va_list ap; 33 | va_start(ap, fmt); 34 | 35 | va_list ap2; 36 | va_copy(ap2, ap); 37 | vsprintf(buf, fmt, ap2); 38 | va_end(buf); 39 | } 40 | 41 | int main() { 42 | ASSERT(6, sum1(1, 2, 3, 0)); 43 | ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0)); 44 | ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0)); 45 | ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0)); 46 | ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0)); 47 | ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d", 2, 3); strcmp(buf, "2 3"); })); 48 | 49 | printf("OK\n"); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /test/union.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(8, ({ union { int a; char b[6]; } x; sizeof(x); })); 5 | ASSERT(3, ({ union { int a; char b[4]; } x; x.a = 515; x.b[0]; })); 6 | ASSERT(2, ({ union { int a; char b[4]; } x; x.a = 515; x.b[1]; })); 7 | ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[2]; })); 8 | ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[3]; })); 9 | 10 | ASSERT(3, ({ union {int a,b;} x,y; x.a=3; y.a=5; y=x; y.a; })); 11 | ASSERT(3, ({ union {struct {int a,b;} c;} x,y; x.c.b=3; y.c.b=5; y=x; y.c.b; })); 12 | 13 | ASSERT(0xef, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.a; })); 14 | ASSERT(0xbe, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.b; })); 15 | ASSERT(0xad, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.c; })); 16 | ASSERT(0xde, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.d; })); 17 | 18 | ASSERT(3, ({struct { union { int a,b; }; union { int c,d; }; } x; x.a=3; x.b; })); 19 | ASSERT(5, ({struct { union { int a,b; }; union { int c,d; }; } x; x.d=5; x.c; })); 20 | 21 | printf("OK\n"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /xc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Xcompiler for C 3 | # bash patch to accept xxc as a shebang 4 | if [ "$#" -le 1 ]; then 5 | /usr/local/bin/xcc/xcc 6 | exit 7 | fi 8 | args=() 9 | split_arguments() { 10 | local arg="$1" 11 | local in_quote=false 12 | local part="" 13 | if [[ ! -z $2 ]]; then 14 | args+=("$arg") 15 | else 16 | for ((i = 0; i < ${#arg}; i++)); do 17 | char="${arg:$i:1}" 18 | if [[ $char == '"' ]]; then 19 | in_quote=!$in_quote 20 | elif [[ $char == ' ' && $in_quote == false ]]; then 21 | args+=("$part") 22 | part="" 23 | else 24 | part+="$char" 25 | fi 26 | done 27 | args+=("$part") 28 | fi 29 | } 30 | arguments=() 31 | while [ ! -f "${!#}" ]; do 32 | arg="${!#}" 33 | split_arguments "$arg" run 34 | arguments+=("\"${args[@]}\"") 35 | unset args 36 | set -- "${@:1:$(($#-1))}" 37 | done 38 | num_args=$# 39 | filename="${!num_args}" 40 | for arg in "${@:1:$((num_args - 1))}"; do 41 | split_arguments "$arg" 42 | done 43 | revrargs=() 44 | for ((i=${#arguments[@]}-1; i>=0; i--)); do 45 | revrargs+="${arguments[i]} " 46 | done 47 | if [ ${#revrargs[@]} -gt 0 ]; then 48 | /usr/local/bin/xcc/xcc "${args[@]}" -rarg "$(echo ${revrargs[@]})" "${filename}" 49 | else 50 | /usr/local/bin/xcc/xcc "${args[@]}" "${filename}" 51 | fi -------------------------------------------------------------------------------- /test/atomic.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | static int incr(_Atomic int *p) { 6 | int oldval = *p; 7 | int newval; 8 | do { 9 | newval = oldval + 1; 10 | } while (!atomic_compare_exchange_weak(p, &oldval, newval)); 11 | return newval; 12 | } 13 | 14 | static int add1(void *arg) { 15 | _Atomic int *x = arg; 16 | for (int i = 0; i < 1000*1000; i++) 17 | incr(x); 18 | return 0; 19 | } 20 | 21 | static int add2(void *arg) { 22 | _Atomic int *x = arg; 23 | for (int i = 0; i < 1000*1000; i++) 24 | (*x)++; 25 | return 0; 26 | } 27 | 28 | static int add3(void *arg) { 29 | _Atomic int *x = arg; 30 | for (int i = 0; i < 1000*1000; i++) 31 | *x += 5; 32 | return 0; 33 | } 34 | 35 | static int add_millions(void) { 36 | _Atomic int x = 0; 37 | 38 | pthread_t thr1; 39 | pthread_t thr2; 40 | pthread_t thr3; 41 | 42 | pthread_create(&thr1, NULL, add1, &x); 43 | pthread_create(&thr2, NULL, add2, &x); 44 | pthread_create(&thr3, NULL, add3, &x); 45 | 46 | for (int i = 0; i < 1000*1000; i++) 47 | x--; 48 | 49 | pthread_join(thr1, NULL); 50 | pthread_join(thr2, NULL); 51 | pthread_join(thr3, NULL); 52 | return x; 53 | } 54 | 55 | int main() { 56 | ASSERT(6*1000*1000, add_millions()); 57 | 58 | ASSERT(3, ({ int x=3; atomic_exchange(&x, 5); })); 59 | ASSERT(5, ({ int x=3; atomic_exchange(&x, 5); x; })); 60 | 61 | printf("OK\n"); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /test/bitfield.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | struct { 4 | char a; 5 | int b : 5; 6 | int c : 10; 7 | } g45 = {1, 2, 3}, g46={}; 8 | 9 | int main() { 10 | ASSERT(4, sizeof(struct {int x:1; })); 11 | ASSERT(8, sizeof(struct {long x:1; })); 12 | 13 | struct bit1 { 14 | short a; 15 | char b; 16 | int c : 2; 17 | int d : 3; 18 | int e : 3; 19 | }; 20 | 21 | ASSERT(4, sizeof(struct bit1)); 22 | ASSERT(1, ({ struct bit1 x; x.a=1; x.b=2; x.c=3; x.d=4; x.e=5; x.a; })); 23 | ASSERT(1, ({ struct bit1 x={1,2,3,4,5}; x.a; })); 24 | ASSERT(2, ({ struct bit1 x={1,2,3,4,5}; x.b; })); 25 | ASSERT(-1, ({ struct bit1 x={1,2,3,4,5}; x.c; })); 26 | ASSERT(-4, ({ struct bit1 x={1,2,3,4,5}; x.d; })); 27 | ASSERT(-3, ({ struct bit1 x={1,2,3,4,5}; x.e; })); 28 | 29 | ASSERT(1, g45.a); 30 | ASSERT(2, g45.b); 31 | ASSERT(3, g45.c); 32 | 33 | ASSERT(0, g46.a); 34 | ASSERT(0, g46.b); 35 | ASSERT(0, g46.c); 36 | 37 | typedef struct { 38 | int a : 10; 39 | int b : 10; 40 | int c : 10; 41 | } T3; 42 | 43 | ASSERT(1, ({ T3 x={1,2,3}; x.a++; })); 44 | ASSERT(2, ({ T3 x={1,2,3}; x.b++; })); 45 | ASSERT(3, ({ T3 x={1,2,3}; x.c++; })); 46 | 47 | ASSERT(2, ({ T3 x={1,2,3}; ++x.a; })); 48 | ASSERT(3, ({ T3 x={1,2,3}; ++x.b; })); 49 | ASSERT(4, ({ T3 x={1,2,3}; ++x.c; })); 50 | 51 | ASSERT(4, sizeof(struct {int a:3; int c:1; int c:5;})); 52 | ASSERT(8, sizeof(struct {int a:3; int:0; int c:5;})); 53 | ASSERT(4, sizeof(struct {int a:3; int:0;})); 54 | 55 | printf("OK\n"); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /test/alignof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int _Alignas(512) g1; 4 | int _Alignas(512) g2; 5 | char g3; 6 | int g4; 7 | long g5; 8 | char g6; 9 | 10 | int main() { 11 | ASSERT(1, _Alignof(char)); 12 | ASSERT(2, _Alignof(short)); 13 | ASSERT(4, _Alignof(int)); 14 | ASSERT(8, _Alignof(long)); 15 | ASSERT(8, _Alignof(long long)); 16 | ASSERT(1, _Alignof(char[3])); 17 | ASSERT(4, _Alignof(int[3])); 18 | ASSERT(1, _Alignof(struct {char a; char b;}[2])); 19 | ASSERT(8, _Alignof(struct {char a; long b;}[2])); 20 | 21 | ASSERT(1, ({ _Alignas(char) char x, y; &y-&x; })); 22 | ASSERT(8, ({ _Alignas(long) char x, y; &y-&x; })); 23 | ASSERT(32, ({ _Alignas(32) char x, y; &y-&x; })); 24 | ASSERT(32, ({ _Alignas(32) int *x, *y; ((char *)&y)-((char *)&x); })); 25 | ASSERT(16, ({ struct { _Alignas(16) char x, y; } a; &a.y-&a.x; })); 26 | ASSERT(8, ({ struct T { _Alignas(8) char a; }; _Alignof(struct T); })); 27 | 28 | ASSERT(0, (long)(char *)&g1 % 512); 29 | ASSERT(0, (long)(char *)&g2 % 512); 30 | ASSERT(0, (long)(char *)&g4 % 4); 31 | ASSERT(0, (long)(char *)&g5 % 8); 32 | 33 | ASSERT(1, ({ char x; _Alignof(x); })); 34 | ASSERT(4, ({ int x; _Alignof(x); })); 35 | ASSERT(1, ({ char x; _Alignof x; })); 36 | ASSERT(4, ({ int x; _Alignof x; })); 37 | 38 | ASSERT(1, _Alignof(char) << 31 >> 31); 39 | ASSERT(1, _Alignof(char) << 63 >> 63); 40 | ASSERT(1, ({ char x; _Alignof(x) << 63 >> 63; })); 41 | 42 | ASSERT(0, ({ char x[16]; (unsigned long)&x % 16; })); 43 | ASSERT(0, ({ char x[17]; (unsigned long)&x % 16; })); 44 | ASSERT(0, ({ char x[100]; (unsigned long)&x % 16; })); 45 | ASSERT(0, ({ char x[101]; (unsigned long)&x % 16; })); 46 | 47 | printf("OK\n"); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/builtin.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(1, __builtin_types_compatible_p(int, int)); 5 | ASSERT(1, __builtin_types_compatible_p(double, double)); 6 | ASSERT(0, __builtin_types_compatible_p(int, long)); 7 | ASSERT(0, __builtin_types_compatible_p(long, float)); 8 | ASSERT(1, __builtin_types_compatible_p(int *, int *)); 9 | ASSERT(0, __builtin_types_compatible_p(short *, int *)); 10 | ASSERT(0, __builtin_types_compatible_p(int **, int *)); 11 | ASSERT(1, __builtin_types_compatible_p(const int, int)); 12 | ASSERT(0, __builtin_types_compatible_p(unsigned, int)); 13 | ASSERT(1, __builtin_types_compatible_p(signed, int)); 14 | ASSERT(0, __builtin_types_compatible_p(struct {int a;}, struct {int a;})); 15 | 16 | ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void))); 17 | ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int))); 18 | ASSERT(1, __builtin_types_compatible_p(void (*)(int, double), void (*)(int, double))); 19 | ASSERT(1, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double))); 20 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int)); 21 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float))); 22 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double, int))); 23 | ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...))); 24 | ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void))); 25 | 26 | ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, T); })); 27 | ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, const T); })); 28 | 29 | ASSERT(1, ({ struct {int a; int b;} x; __builtin_types_compatible_p(typeof(x.a), typeof(x.b)); })); 30 | 31 | printf("OK\n"); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/cast.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(131585, (int)8590066177); 5 | ASSERT(513, (short)8590066177); 6 | ASSERT(1, (char)8590066177); 7 | ASSERT(1, (long)1); 8 | ASSERT(0, (long)&*(int *)0); 9 | ASSERT(513, ({ int x=512; *(char *)&x=1; x; })); 10 | ASSERT(5, ({ int x=5; long y=(long)&x; *(int*)y; })); 11 | 12 | (void)1; 13 | 14 | ASSERT(-1, (char)255); 15 | ASSERT(-1, (signed char)255); 16 | ASSERT(255, (unsigned char)255); 17 | ASSERT(-1, (short)65535); 18 | ASSERT(65535, (unsigned short)65535); 19 | ASSERT(-1, (int)0xffffffff); 20 | ASSERT(0xffffffff, (unsigned)0xffffffff); 21 | 22 | ASSERT(1, -1<1); 23 | ASSERT(0, -1<(unsigned)1); 24 | ASSERT(254, (char)127+(char)127); 25 | ASSERT(65534, (short)32767+(short)32767); 26 | ASSERT(-1, -1>>1); 27 | ASSERT(-1, (unsigned long)-1); 28 | ASSERT(2147483647, ((unsigned)-1)>>1); 29 | ASSERT(-50, (-100)/2); 30 | ASSERT(2147483598, ((unsigned)-100)/2); 31 | ASSERT(9223372036854775758, ((unsigned long)-100)/2); 32 | ASSERT(0, ((long)-1)/(unsigned)100); 33 | ASSERT(-2, (-100)%7); 34 | ASSERT(2, ((unsigned)-100)%7); 35 | ASSERT(6, ((unsigned long)-100)%9); 36 | 37 | ASSERT(65535, (int)(unsigned short)65535); 38 | ASSERT(65535, ({ unsigned short x = 65535; x; })); 39 | ASSERT(65535, ({ unsigned short x = 65535; (int)x; })); 40 | 41 | ASSERT(-1, ({ typedef short T; T x = 65535; (int)x; })); 42 | ASSERT(65535, ({ typedef unsigned short T; T x = 65535; (int)x; })); 43 | 44 | ASSERT(0, (_Bool)0.0); 45 | ASSERT(1, (_Bool)0.1); 46 | ASSERT(3, (char)3.0); 47 | ASSERT(1000, (short)1000.3); 48 | ASSERT(3, (int)3.99); 49 | ASSERT(2000000000000000, (long)2e15); 50 | ASSERT(3, (float)3.5); 51 | ASSERT(5, (double)(float)5.5); 52 | ASSERT(3, (float)3); 53 | ASSERT(3, (double)3); 54 | ASSERT(3, (float)3L); 55 | ASSERT(3, (double)3L); 56 | 57 | printf("OK\n"); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /test/string.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(0, ""[0]); 5 | ASSERT(1, sizeof("")); 6 | 7 | ASSERT(97, "abc"[0]); 8 | ASSERT(98, "abc"[1]); 9 | ASSERT(99, "abc"[2]); 10 | ASSERT(0, "abc"[3]); 11 | ASSERT(4, sizeof("abc")); 12 | 13 | ASSERT(7, "\a"[0]); 14 | ASSERT(8, "\b"[0]); 15 | ASSERT(9, "\t"[0]); 16 | ASSERT(10, "\n"[0]); 17 | ASSERT(11, "\v"[0]); 18 | ASSERT(12, "\f"[0]); 19 | ASSERT(13, "\r"[0]); 20 | ASSERT(27, "\e"[0]); 21 | 22 | ASSERT(106, "\j"[0]); 23 | ASSERT(107, "\k"[0]); 24 | ASSERT(108, "\l"[0]); 25 | 26 | ASSERT(7, "\ax\ny"[0]); 27 | ASSERT(120, "\ax\ny"[1]); 28 | ASSERT(10, "\ax\ny"[2]); 29 | ASSERT(121, "\ax\ny"[3]); 30 | 31 | ASSERT(0, "\0"[0]); 32 | ASSERT(16, "\20"[0]); 33 | ASSERT(65, "\101"[0]); 34 | ASSERT(104, "\1500"[0]); 35 | ASSERT(0, "\x00"[0]); 36 | ASSERT(119, "\x77"[0]); 37 | 38 | ASSERT(7, sizeof("abc" "def")); 39 | ASSERT(9, sizeof("abc" "d" "efgh")); 40 | ASSERT(0, strcmp("abc" "d" "\nefgh", "abcd\nefgh")); 41 | ASSERT(0, !strcmp("abc" "d", "abcd\nefgh")); 42 | ASSERT(0, strcmp("\x9" "0", "\t0")); 43 | 44 | ASSERT(16, sizeof(L"abc" "")); 45 | 46 | ASSERT(28, sizeof(L"abc" "def")); 47 | ASSERT(28, sizeof(L"abc" L"def")); 48 | ASSERT(14, sizeof(u"abc" "def")); 49 | ASSERT(14, sizeof(u"abc" u"def")); 50 | 51 | ASSERT(L'a', (L"abc" "def")[0]); 52 | ASSERT(L'd', (L"abc" "def")[3]); 53 | ASSERT(L'\0', (L"abc" "def")[6]); 54 | 55 | ASSERT(u'a', (u"abc" "def")[0]); 56 | ASSERT(u'd', (u"abc" "def")[3]); 57 | ASSERT(u'\0', (u"abc" "def")[6]); 58 | 59 | ASSERT(L'あ', ("あ" L"")[0]); 60 | ASSERT(0343, ("\343\201\202" L"")[0]); 61 | ASSERT(0201, ("\343\201\202" L"")[1]); 62 | ASSERT(0202, ("\343\201\202" L"")[2]); 63 | ASSERT(0, ("\343\201\202" L"")[3]); 64 | 65 | ASSERT(L'a', ("a" "b" L"c")[0]); 66 | ASSERT(L'b', ("a" "b" L"c")[1]); 67 | ASSERT(L'c', ("a" "b" L"c")[2]); 68 | ASSERT(0, ("a" "b" L"c")[3]); 69 | 70 | printf("OK\n"); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/pointer.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(3, ({ int x=3; *&x; })); 5 | ASSERT(3, ({ int x=3; int *y=&x; int **z=&y; **z; })); 6 | ASSERT(5, ({ int x=3; int y=5; *(&x+1); })); 7 | ASSERT(3, ({ int x=3; int y=5; *(&y-1); })); 8 | ASSERT(5, ({ int x=3; int y=5; *(&x-(-1)); })); 9 | ASSERT(5, ({ int x=3; int *y=&x; *y=5; x; })); 10 | ASSERT(7, ({ int x=3; int y=5; *(&x+1)=7; y; })); 11 | ASSERT(7, ({ int x=3; int y=5; *(&y-2+1)=7; x; })); 12 | ASSERT(5, ({ int x=3; (&x+2)-&x+3; })); 13 | ASSERT(8, ({ int x, y; x=3; y=5; x+y; })); 14 | ASSERT(8, ({ int x=3, y=5; x+y; })); 15 | 16 | ASSERT(3, ({ int x[2]; int *y=&x; *y=3; *x; })); 17 | 18 | ASSERT(3, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *x; })); 19 | ASSERT(4, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+1); })); 20 | ASSERT(5, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+2); })); 21 | 22 | ASSERT(0, ({ int x[2][3]; int *y=x; *y=0; **x; })); 23 | ASSERT(1, ({ int x[2][3]; int *y=x; *(y+1)=1; *(*x+1); })); 24 | ASSERT(2, ({ int x[2][3]; int *y=x; *(y+2)=2; *(*x+2); })); 25 | ASSERT(3, ({ int x[2][3]; int *y=x; *(y+3)=3; **(x+1); })); 26 | ASSERT(4, ({ int x[2][3]; int *y=x; *(y+4)=4; *(*(x+1)+1); })); 27 | ASSERT(5, ({ int x[2][3]; int *y=x; *(y+5)=5; *(*(x+1)+2); })); 28 | 29 | ASSERT(3, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *x; })); 30 | ASSERT(4, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+1); })); 31 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); })); 32 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); })); 33 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; 2[x]=5; *(x+2); })); 34 | 35 | ASSERT(0, ({ int x[2][3]; int *y=x; y[0]=0; x[0][0]; })); 36 | ASSERT(1, ({ int x[2][3]; int *y=x; y[1]=1; x[0][1]; })); 37 | ASSERT(2, ({ int x[2][3]; int *y=x; y[2]=2; x[0][2]; })); 38 | ASSERT(3, ({ int x[2][3]; int *y=x; y[3]=3; x[1][0]; })); 39 | ASSERT(4, ({ int x[2][3]; int *y=x; y[4]=4; x[1][1]; })); 40 | ASSERT(5, ({ int x[2][3]; int *y=x; y[5]=5; x[1][2]; })); 41 | 42 | printf("OK\n"); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/attribute.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "stddef.h" 3 | 4 | int main() { 5 | ASSERT(5, ({ struct { char a; int b; } __attribute__((packed)) x; sizeof(x); })); 6 | ASSERT(0, offsetof(struct __attribute__((packed)) { char a; int b; }, a)); 7 | ASSERT(1, offsetof(struct __attribute__((packed)) { char a; int b; }, b)); 8 | 9 | ASSERT(5, ({ struct __attribute__((packed)) { char a; int b; } x; sizeof(x); })); 10 | ASSERT(0, offsetof(struct { char a; int b; } __attribute__((packed)), a)); 11 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((packed)), b)); 12 | 13 | ASSERT(9, ({ typedef struct { char a; int b[2]; } __attribute__((packed)) T; sizeof(T); })); 14 | ASSERT(9, ({ typedef struct __attribute__((packed)) { char a; int b[2]; } T; sizeof(T); })); 15 | 16 | ASSERT(1, offsetof(struct __attribute__((packed)) T { char a; int b[2]; }, b)); 17 | ASSERT(1, _Alignof(struct __attribute__((packed)) { char a; int b[2]; })); 18 | 19 | ASSERT(8, ({ struct __attribute__((aligned(8))) { int a; } x; _Alignof(x); })); 20 | ASSERT(8, ({ struct { int a; } __attribute__((aligned(8))) x; _Alignof(x); })); 21 | 22 | ASSERT(8, ({ struct __attribute__((aligned(8), packed)) { char a; int b; } x; _Alignof(x); })); 23 | ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8), packed)) x; _Alignof(x); })); 24 | ASSERT(1, offsetof(struct __attribute__((aligned(8), packed)) { char a; int b; }, b)); 25 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8), packed)), b)); 26 | 27 | ASSERT(8, ({ struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; } x; _Alignof(x); })); 28 | ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)) x; _Alignof(x); })); 29 | ASSERT(1, offsetof(struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; }, b)); 30 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)), b)); 31 | 32 | ASSERT(8, ({ struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)) x; _Alignof(x); })); 33 | ASSERT(1, offsetof(struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)), b)); 34 | 35 | ASSERT(16, ({ struct __attribute__((aligned(8+8))) { char a; int b; } x; _Alignof(x); })); 36 | 37 | printf("OK\n"); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /test/constexpr.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | float g40 = 1.5; 4 | double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0); 5 | 6 | int main() { 7 | ASSERT(10, ({ enum { ten=1+2+3+4 }; ten; })); 8 | ASSERT(1, ({ int i=0; switch(3) { case 5-2+0*3: i++; } i; })); 9 | ASSERT(8, ({ int x[1+1]; sizeof(x); })); 10 | ASSERT(6, ({ char x[8-2]; sizeof(x); })); 11 | ASSERT(6, ({ char x[2*3]; sizeof(x); })); 12 | ASSERT(3, ({ char x[12/4]; sizeof(x); })); 13 | ASSERT(2, ({ char x[12%10]; sizeof(x); })); 14 | ASSERT(0b100, ({ char x[0b110&0b101]; sizeof(x); })); 15 | ASSERT(0b111, ({ char x[0b110|0b101]; sizeof(x); })); 16 | ASSERT(0b110, ({ char x[0b111^0b001]; sizeof(x); })); 17 | ASSERT(4, ({ char x[1<<2]; sizeof(x); })); 18 | ASSERT(2, ({ char x[4>>1]; sizeof(x); })); 19 | ASSERT(2, ({ char x[(1==1)+1]; sizeof(x); })); 20 | ASSERT(1, ({ char x[(1!=1)+1]; sizeof(x); })); 21 | ASSERT(1, ({ char x[(1<1)+1]; sizeof(x); })); 22 | ASSERT(2, ({ char x[(1<=1)+1]; sizeof(x); })); 23 | ASSERT(2, ({ char x[1?2:3]; sizeof(x); })); 24 | ASSERT(3, ({ char x[0?2:3]; sizeof(x); })); 25 | ASSERT(3, ({ char x[(1,3)]; sizeof(x); })); 26 | ASSERT(2, ({ char x[!0+1]; sizeof(x); })); 27 | ASSERT(1, ({ char x[!1+1]; sizeof(x); })); 28 | ASSERT(2, ({ char x[~-3]; sizeof(x); })); 29 | ASSERT(2, ({ char x[(5||6)+1]; sizeof(x); })); 30 | ASSERT(1, ({ char x[(0||0)+1]; sizeof(x); })); 31 | ASSERT(2, ({ char x[(1&&1)+1]; sizeof(x); })); 32 | ASSERT(1, ({ char x[(1&&0)+1]; sizeof(x); })); 33 | ASSERT(3, ({ char x[(int)3]; sizeof(x); })); 34 | ASSERT(15, ({ char x[(char)0xffffff0f]; sizeof(x); })); 35 | ASSERT(0x10f, ({ char x[(short)0xffff010f]; sizeof(x); })); 36 | ASSERT(4, ({ char x[(int)0xfffffffffff+5]; sizeof(x); })); 37 | ASSERT(8, ({ char x[(int*)0+2]; sizeof(x); })); 38 | ASSERT(12, ({ char x[(int*)16-1]; sizeof(x); })); 39 | ASSERT(3, ({ char x[(int*)16-(int*)4]; sizeof(x); })); 40 | 41 | ASSERT(4, ({ char x[(-1>>31)+5]; sizeof(x); })); 42 | ASSERT(255, ({ char x[(unsigned char)0xffffffff]; sizeof(x); })); 43 | ASSERT(0x800f, ({ char x[(unsigned short)0xffff800f]; sizeof(x); })); 44 | ASSERT(1, ({ char x[(unsigned int)0xfffffffffff>>31]; sizeof(x); })); 45 | ASSERT(1, ({ char x[(long)-1/((long)1<<62)+1]; sizeof(x); })); 46 | ASSERT(4, ({ char x[(unsigned long)-1/((long)1<<62)+1]; sizeof(x); })); 47 | ASSERT(1, ({ char x[(unsigned)1<-1]; sizeof(x); })); 48 | ASSERT(1, ({ char x[(unsigned)1<=-1]; sizeof(x); })); 49 | 50 | ASSERT(1, g40==1.5); 51 | ASSERT(1, g41==11); 52 | 53 | printf("OK\n"); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /test/variable.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int g1, g2[4]; 4 | static int g3 = 3; 5 | 6 | int main() { 7 | ASSERT(3, ({ int a; a=3; a; })); 8 | ASSERT(3, ({ int a=3; a; })); 9 | ASSERT(8, ({ int a=3; int z=5; a+z; })); 10 | 11 | ASSERT(3, ({ int a=3; a; })); 12 | ASSERT(8, ({ int a=3; int z=5; a+z; })); 13 | ASSERT(6, ({ int a; int b; a=b=3; a+b; })); 14 | ASSERT(3, ({ int foo=3; foo; })); 15 | ASSERT(8, ({ int foo123=3; int bar=5; foo123+bar; })); 16 | 17 | ASSERT(4, ({ int x; sizeof(x); })); 18 | ASSERT(4, ({ int x; sizeof x; })); 19 | ASSERT(8, ({ int *x; sizeof(x); })); 20 | ASSERT(16, ({ int x[4]; sizeof(x); })); 21 | ASSERT(48, ({ int x[3][4]; sizeof(x); })); 22 | ASSERT(16, ({ int x[3][4]; sizeof(*x); })); 23 | ASSERT(4, ({ int x[3][4]; sizeof(**x); })); 24 | ASSERT(5, ({ int x[3][4]; sizeof(**x) + 1; })); 25 | ASSERT(5, ({ int x[3][4]; sizeof **x + 1; })); 26 | ASSERT(4, ({ int x[3][4]; sizeof(**x + 1); })); 27 | ASSERT(4, ({ int x=1; sizeof(x=2); })); 28 | ASSERT(1, ({ int x=1; sizeof(x=2); x; })); 29 | 30 | ASSERT(0, g1); 31 | ASSERT(3, ({ g1=3; g1; })); 32 | ASSERT(0, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[0]; })); 33 | ASSERT(1, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[1]; })); 34 | ASSERT(2, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[2]; })); 35 | ASSERT(3, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[3]; })); 36 | 37 | ASSERT(4, sizeof(g1)); 38 | ASSERT(16, sizeof(g2)); 39 | 40 | ASSERT(1, ({ char x=1; x; })); 41 | ASSERT(1, ({ char x=1; char y=2; x; })); 42 | ASSERT(2, ({ char x=1; char y=2; y; })); 43 | 44 | ASSERT(1, ({ char x; sizeof(x); })); 45 | ASSERT(10, ({ char x[10]; sizeof(x); })); 46 | 47 | ASSERT(2, ({ int x=2; { int x=3; } x; })); 48 | ASSERT(2, ({ int x=2; { int x=3; } int y=4; x; })); 49 | ASSERT(3, ({ int x=2; { x=3; } x; })); 50 | 51 | ASSERT(7, ({ int x; int y; char z; char *a=&y; char *b=&z; b-a; })); 52 | ASSERT(1, ({ int x; char y; int z; char *a=&y; char *b=&z; b-a; })); 53 | 54 | ASSERT(8, ({ long x; sizeof(x); })); 55 | ASSERT(2, ({ short x; sizeof(x); })); 56 | 57 | ASSERT(24, ({ char *x[3]; sizeof(x); })); 58 | ASSERT(8, ({ char (*x)[3]; sizeof(x); })); 59 | ASSERT(1, ({ char (x); sizeof(x); })); 60 | ASSERT(3, ({ char (x)[3]; sizeof(x); })); 61 | ASSERT(12, ({ char (x[3])[4]; sizeof(x); })); 62 | ASSERT(4, ({ char (x[3])[4]; sizeof(x[0]); })); 63 | ASSERT(3, ({ char *x[3]; char y; x[0]=&y; y=3; x[0][0]; })); 64 | ASSERT(4, ({ char x[3]; char (*y)[3]=x; y[0][0]=4; y[0][0]; })); 65 | 66 | { void *x; } 67 | 68 | ASSERT(3, g3); 69 | 70 | printf("OK\n"); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /test/float.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(35, (float)(char)35); 5 | ASSERT(35, (float)(short)35); 6 | ASSERT(35, (float)(int)35); 7 | ASSERT(35, (float)(long)35); 8 | ASSERT(35, (float)(unsigned char)35); 9 | ASSERT(35, (float)(unsigned short)35); 10 | ASSERT(35, (float)(unsigned int)35); 11 | ASSERT(35, (float)(unsigned long)35); 12 | 13 | ASSERT(35, (double)(char)35); 14 | ASSERT(35, (double)(short)35); 15 | ASSERT(35, (double)(int)35); 16 | ASSERT(35, (double)(long)35); 17 | ASSERT(35, (double)(unsigned char)35); 18 | ASSERT(35, (double)(unsigned short)35); 19 | ASSERT(35, (double)(unsigned int)35); 20 | ASSERT(35, (double)(unsigned long)35); 21 | 22 | ASSERT(35, (char)(float)35); 23 | ASSERT(35, (short)(float)35); 24 | ASSERT(35, (int)(float)35); 25 | ASSERT(35, (long)(float)35); 26 | ASSERT(35, (unsigned char)(float)35); 27 | ASSERT(35, (unsigned short)(float)35); 28 | ASSERT(35, (unsigned int)(float)35); 29 | ASSERT(35, (unsigned long)(float)35); 30 | 31 | ASSERT(35, (char)(double)35); 32 | ASSERT(35, (short)(double)35); 33 | ASSERT(35, (int)(double)35); 34 | ASSERT(35, (long)(double)35); 35 | ASSERT(35, (unsigned char)(double)35); 36 | ASSERT(35, (unsigned short)(double)35); 37 | ASSERT(35, (unsigned int)(double)35); 38 | ASSERT(35, (unsigned long)(double)35); 39 | 40 | ASSERT(-2147483648, (double)(unsigned long)(long)-1); 41 | 42 | ASSERT(1, 2e3==2e3); 43 | ASSERT(0, 2e3==2e5); 44 | ASSERT(1, 2.0==2); 45 | ASSERT(0, 5.1<5); 46 | ASSERT(0, 5.0<5); 47 | ASSERT(1, 4.9<5); 48 | ASSERT(0, 5.1<=5); 49 | ASSERT(1, 5.0<=5); 50 | ASSERT(1, 4.9<=5); 51 | 52 | ASSERT(1, 2e3f==2e3); 53 | ASSERT(0, 2e3f==2e5); 54 | ASSERT(1, 2.0f==2); 55 | ASSERT(0, 5.1f<5); 56 | ASSERT(0, 5.0f<5); 57 | ASSERT(1, 4.9f<5); 58 | ASSERT(0, 5.1f<=5); 59 | ASSERT(1, 5.0f<=5); 60 | ASSERT(1, 4.9f<=5); 61 | 62 | ASSERT(6, 2.3+3.8); 63 | ASSERT(-1, 2.3-3.8); 64 | ASSERT(-3, -3.8); 65 | ASSERT(13, 3.3*4); 66 | ASSERT(2, 5.0/2); 67 | 68 | ASSERT(6, 2.3f+3.8f); 69 | ASSERT(6, 2.3f+3.8); 70 | ASSERT(-1, 2.3f-3.8); 71 | ASSERT(-3, -3.8f); 72 | ASSERT(13, 3.3f*4); 73 | ASSERT(2, 5.0f/2); 74 | 75 | ASSERT(0, 0.0/0.0 == 0.0/0.0); 76 | ASSERT(1, 0.0/0.0 != 0.0/0.0); 77 | 78 | ASSERT(0, 0.0/0.0 < 0); 79 | ASSERT(0, 0.0/0.0 <= 0); 80 | ASSERT(0, 0.0/0.0 > 0); 81 | ASSERT(0, 0.0/0.0 >= 0); 82 | 83 | ASSERT(0, !3.); 84 | ASSERT(1, !0.); 85 | ASSERT(0, !3.f); 86 | ASSERT(1, !0.f); 87 | 88 | ASSERT(5, 0.0 ? 3 : 5); 89 | ASSERT(3, 1.2 ? 3 : 5); 90 | 91 | printf("OK\n"); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /test/literal.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(97, 'a'); 5 | ASSERT(10, '\n'); 6 | ASSERT(-128, '\x80'); 7 | 8 | ASSERT(511, 0777); 9 | ASSERT(0, 0x0); 10 | ASSERT(10, 0xa); 11 | ASSERT(10, 0XA); 12 | ASSERT(48879, 0xbeef); 13 | ASSERT(48879, 0xBEEF); 14 | ASSERT(48879, 0XBEEF); 15 | ASSERT(0, 0b0); 16 | ASSERT(1, 0b1); 17 | ASSERT(47, 0b101111); 18 | ASSERT(47, 0B101111); 19 | 20 | ASSERT(4, sizeof(0)); 21 | ASSERT(8, sizeof(0L)); 22 | ASSERT(8, sizeof(0LU)); 23 | ASSERT(8, sizeof(0UL)); 24 | ASSERT(8, sizeof(0LL)); 25 | ASSERT(8, sizeof(0LLU)); 26 | ASSERT(8, sizeof(0Ull)); 27 | ASSERT(8, sizeof(0l)); 28 | ASSERT(8, sizeof(0ll)); 29 | ASSERT(8, sizeof(0x0L)); 30 | ASSERT(8, sizeof(0b0L)); 31 | ASSERT(4, sizeof(2147483647)); 32 | ASSERT(8, sizeof(2147483648)); 33 | ASSERT(-1, 0xffffffffffffffff); 34 | ASSERT(8, sizeof(0xffffffffffffffff)); 35 | ASSERT(4, sizeof(4294967295U)); 36 | ASSERT(8, sizeof(4294967296U)); 37 | 38 | ASSERT(3, -1U>>30); 39 | ASSERT(3, -1Ul>>62); 40 | ASSERT(3, -1ull>>62); 41 | 42 | ASSERT(1, 0xffffffffffffffffl>>63); 43 | ASSERT(1, 0xffffffffffffffffll>>63); 44 | 45 | ASSERT(-1, 18446744073709551615); 46 | ASSERT(8, sizeof(18446744073709551615)); 47 | ASSERT(-1, 18446744073709551615>>63); 48 | 49 | ASSERT(-1, 0xffffffffffffffff); 50 | ASSERT(8, sizeof(0xffffffffffffffff)); 51 | ASSERT(1, 0xffffffffffffffff>>63); 52 | 53 | ASSERT(-1, 01777777777777777777777); 54 | ASSERT(8, sizeof(01777777777777777777777)); 55 | ASSERT(1, 01777777777777777777777>>63); 56 | 57 | ASSERT(-1, 0b1111111111111111111111111111111111111111111111111111111111111111); 58 | ASSERT(8, sizeof(0b1111111111111111111111111111111111111111111111111111111111111111)); 59 | ASSERT(1, 0b1111111111111111111111111111111111111111111111111111111111111111>>63); 60 | 61 | ASSERT(8, sizeof(2147483648)); 62 | ASSERT(4, sizeof(2147483647)); 63 | 64 | ASSERT(8, sizeof(0x1ffffffff)); 65 | ASSERT(4, sizeof(0xffffffff)); 66 | ASSERT(1, 0xffffffff>>31); 67 | 68 | ASSERT(8, sizeof(040000000000)); 69 | ASSERT(4, sizeof(037777777777)); 70 | ASSERT(1, 037777777777>>31); 71 | 72 | ASSERT(8, sizeof(0b111111111111111111111111111111111)); 73 | ASSERT(4, sizeof(0b11111111111111111111111111111111)); 74 | ASSERT(1, 0b11111111111111111111111111111111>>31); 75 | 76 | ASSERT(-1, 1 << 31 >> 31); 77 | ASSERT(-1, 01 << 31 >> 31); 78 | ASSERT(-1, 0x1 << 31 >> 31); 79 | ASSERT(-1, 0b1 << 31 >> 31); 80 | 81 | 0.0; 82 | 1.0; 83 | 3e+8; 84 | 0x10.1p0; 85 | .1E4f; 86 | 87 | ASSERT(4, sizeof(8f)); 88 | ASSERT(4, sizeof(0.3F)); 89 | ASSERT(8, sizeof(0.)); 90 | ASSERT(8, sizeof(.0)); 91 | ASSERT(16, sizeof(5.l)); 92 | ASSERT(16, sizeof(2.0L)); 93 | 94 | assert(1, size\ 95 | of(char), \ 96 | "sizeof(char)"); 97 | 98 | ASSERT(4, sizeof(L'\0')); 99 | ASSERT(97, L'a'); 100 | 101 | printf("OK\n"); 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /test/common: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void assert(int expected, int actual, char *code) { 6 | if (expected == actual) { 7 | printf("%s => %d\n", code, actual); 8 | } else { 9 | printf("%s => %d expected but got %d\n", code, expected, actual); 10 | exit(1); 11 | } 12 | } 13 | 14 | static int static_fn() { return 5; } 15 | int ext1 = 5; 16 | int *ext2 = &ext1; 17 | int ext3 = 7; 18 | int ext_fn1(int x) { return x; } 19 | int ext_fn2(int x) { return x; } 20 | int common_ext2 = 3; 21 | static int common_local; 22 | 23 | int false_fn() { return 512; } 24 | int true_fn() { return 513; } 25 | int char_fn() { return (2<<8)+3; } 26 | int short_fn() { return (2<<16)+5; } 27 | 28 | int uchar_fn() { return (2<<10)-1-4; } 29 | int ushort_fn() { return (2<<20)-1-7; } 30 | 31 | int schar_fn() { return (2<<10)-1-4; } 32 | int sshort_fn() { return (2<<20)-1-7; } 33 | 34 | int add_all(int n, ...) { 35 | va_list ap; 36 | va_start(ap, n); 37 | 38 | int sum = 0; 39 | for (int i = 0; i < n; i++) 40 | sum += va_arg(ap, int); 41 | return sum; 42 | } 43 | 44 | float add_float(float x, float y) { 45 | return x + y; 46 | } 47 | 48 | double add_double(double x, double y) { 49 | return x + y; 50 | } 51 | 52 | int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10) { 53 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 54 | } 55 | 56 | float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10) { 57 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 58 | } 59 | 60 | double add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10) { 61 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 62 | } 63 | 64 | typedef struct { int a,b; short c; char d; } Ty4; 65 | typedef struct { int a; float b; double c; } Ty5; 66 | typedef struct { unsigned char a[3]; } Ty6; 67 | typedef struct { long a, b, c; } Ty7; 68 | 69 | int struct_test4(Ty4 x, int n) { 70 | switch (n) { 71 | case 0: return x.a; 72 | case 1: return x.b; 73 | case 2: return x.c; 74 | default: return x.d; 75 | } 76 | } 77 | 78 | int struct_test5(Ty5 x, int n) { 79 | switch (n) { 80 | case 0: return x.a; 81 | case 1: return x.b; 82 | default: return x.c; 83 | } 84 | } 85 | 86 | int struct_test6(Ty6 x, int n) { 87 | return x.a[n]; 88 | } 89 | 90 | int struct_test7(Ty7 x, int n) { 91 | switch (n) { 92 | case 0: return x.a; 93 | case 1: return x.b; 94 | default: return x.c; 95 | } 96 | } 97 | 98 | Ty4 struct_test24(void) { 99 | return (Ty4){10, 20, 30, 40}; 100 | } 101 | 102 | Ty5 struct_test25(void) { 103 | return (Ty5){10, 20, 30}; 104 | } 105 | 106 | Ty6 struct_test26(void) { 107 | return (Ty6){10, 20, 30}; 108 | } 109 | 110 | typedef struct { unsigned char a[10]; } Ty20; 111 | typedef struct { unsigned char a[20]; } Ty21; 112 | 113 | Ty20 struct_test27(void) { 114 | return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; 115 | } 116 | 117 | Ty21 struct_test28(void) { 118 | return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; 119 | } 120 | -------------------------------------------------------------------------------- /test/sizeof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(1, sizeof(char)); 5 | ASSERT(2, sizeof(short)); 6 | ASSERT(2, sizeof(short int)); 7 | ASSERT(2, sizeof(int short)); 8 | ASSERT(4, sizeof(int)); 9 | ASSERT(8, sizeof(long)); 10 | ASSERT(8, sizeof(long int)); 11 | ASSERT(8, sizeof(long int)); 12 | ASSERT(8, sizeof(char *)); 13 | ASSERT(8, sizeof(int *)); 14 | ASSERT(8, sizeof(long *)); 15 | ASSERT(8, sizeof(int **)); 16 | ASSERT(8, sizeof(int(*)[4])); 17 | ASSERT(32, sizeof(int*[4])); 18 | ASSERT(16, sizeof(int[4])); 19 | ASSERT(48, sizeof(int[3][4])); 20 | ASSERT(8, sizeof(struct {int a; int b;})); 21 | 22 | ASSERT(8, sizeof(-10 + (long)5)); 23 | ASSERT(8, sizeof(-10 - (long)5)); 24 | ASSERT(8, sizeof(-10 * (long)5)); 25 | ASSERT(8, sizeof(-10 / (long)5)); 26 | ASSERT(8, sizeof((long)-10 + 5)); 27 | ASSERT(8, sizeof((long)-10 - 5)); 28 | ASSERT(8, sizeof((long)-10 * 5)); 29 | ASSERT(8, sizeof((long)-10 / 5)); 30 | 31 | ASSERT(1, ({ char i; sizeof(++i); })); 32 | ASSERT(1, ({ char i; sizeof(i++); })); 33 | 34 | ASSERT(8, sizeof(int(*)[10])); 35 | ASSERT(8, sizeof(int(*)[][10])); 36 | 37 | ASSERT(4, sizeof(struct { int x, y[]; })); 38 | 39 | ASSERT(1, sizeof(char)); 40 | ASSERT(1, sizeof(signed char)); 41 | ASSERT(1, sizeof(signed char signed)); 42 | ASSERT(1, sizeof(unsigned char)); 43 | ASSERT(1, sizeof(unsigned char unsigned)); 44 | 45 | ASSERT(2, sizeof(short)); 46 | ASSERT(2, sizeof(int short)); 47 | ASSERT(2, sizeof(short int)); 48 | ASSERT(2, sizeof(signed short)); 49 | ASSERT(2, sizeof(int short signed)); 50 | ASSERT(2, sizeof(unsigned short)); 51 | ASSERT(2, sizeof(int short unsigned)); 52 | 53 | ASSERT(4, sizeof(int)); 54 | ASSERT(4, sizeof(signed int)); 55 | ASSERT(4, sizeof(signed)); 56 | ASSERT(4, sizeof(signed signed)); 57 | ASSERT(4, sizeof(unsigned int)); 58 | ASSERT(4, sizeof(unsigned)); 59 | ASSERT(4, sizeof(unsigned unsigned)); 60 | 61 | ASSERT(8, sizeof(long)); 62 | ASSERT(8, sizeof(signed long)); 63 | ASSERT(8, sizeof(signed long int)); 64 | ASSERT(8, sizeof(unsigned long)); 65 | ASSERT(8, sizeof(unsigned long int)); 66 | 67 | ASSERT(8, sizeof(long long)); 68 | ASSERT(8, sizeof(signed long long)); 69 | ASSERT(8, sizeof(signed long long int)); 70 | ASSERT(8, sizeof(unsigned long long)); 71 | ASSERT(8, sizeof(unsigned long long int)); 72 | 73 | ASSERT(1, sizeof((char)1)); 74 | ASSERT(2, sizeof((short)1)); 75 | ASSERT(4, sizeof((int)1)); 76 | ASSERT(8, sizeof((long)1)); 77 | 78 | ASSERT(4, sizeof((char)1 + (char)1)); 79 | ASSERT(4, sizeof((short)1 + (short)1)); 80 | ASSERT(4, sizeof(1?2:3)); 81 | ASSERT(4, sizeof(1?(short)2:(char)3)); 82 | ASSERT(8, sizeof(1?(long)2:(char)3)); 83 | 84 | ASSERT(1, sizeof(char) << 31 >> 31); 85 | ASSERT(1, sizeof(char) << 63 >> 63); 86 | 87 | ASSERT(4, sizeof(float)); 88 | ASSERT(8, sizeof(double)); 89 | 90 | ASSERT(4, sizeof(1f+2)); 91 | ASSERT(8, sizeof(1.0+2)); 92 | ASSERT(4, sizeof(1f-2)); 93 | ASSERT(8, sizeof(1.0-2)); 94 | ASSERT(4, sizeof(1f*2)); 95 | ASSERT(8, sizeof(1.0*2)); 96 | ASSERT(4, sizeof(1f/2)); 97 | ASSERT(8, sizeof(1.0/2)); 98 | 99 | ASSERT(16, sizeof(long double)); 100 | 101 | ASSERT(1, sizeof(main)); 102 | 103 | printf("OK\n"); 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /test/unicode.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #define STR(x) #x 4 | 5 | typedef unsigned short char16_t; 6 | typedef unsigned int char32_t; 7 | typedef int wchar_t; 8 | 9 | int π = 3; 10 | 11 | int main() { 12 | ASSERT(4, sizeof(L'\0')); 13 | ASSERT(97, L'a'); 14 | 15 | ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3")); 16 | ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E")); 17 | ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E")); 18 | ASSERT(0, strcmp("🌮", "\U0001F32E")); 19 | 20 | ASSERT(-1, L'\xffffffff'>>31); 21 | ASSERT(946, L'β'); 22 | ASSERT(12354, L'あ'); 23 | ASSERT(127843, L'🍣'); 24 | 25 | ASSERT(2, sizeof(u'\0')); 26 | ASSERT(1, u'\xffff'>>15); 27 | ASSERT(97, u'a'); 28 | ASSERT(946, u'β'); 29 | ASSERT(12354, u'あ'); 30 | ASSERT(62307, u'🍣'); 31 | 32 | ASSERT(0, strcmp(STR(u'a'), "u'a'")); 33 | 34 | ASSERT(4, sizeof(U'\0')); 35 | ASSERT(1, U'\xffffffff'>>31); 36 | ASSERT(97, U'a'); 37 | ASSERT(946, U'β'); 38 | ASSERT(12354, U'あ'); 39 | ASSERT(127843, U'🍣'); 40 | 41 | ASSERT(0, strcmp(STR(U'a'), "U'a'")); 42 | 43 | ASSERT(4, sizeof(u8"abc")); 44 | ASSERT(0, strcmp(u8"abc", "abc")); 45 | 46 | ASSERT(0, strcmp(STR(u8"a"), "u8\"a\"")); 47 | 48 | ASSERT(2, sizeof(u"")); 49 | ASSERT(10, sizeof(u"\xffzzz")); 50 | ASSERT(0, memcmp(u"", "\0\0", 2)); 51 | ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8)); 52 | ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8)); 53 | ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6)); 54 | ASSERT(u'β', u"βb"[0]); 55 | ASSERT(u'b', u"βb"[1]); 56 | ASSERT(0, u"βb"[2]); 57 | 58 | ASSERT(0, strcmp(STR(u"a"), "u\"a\"")); 59 | 60 | ASSERT(4, sizeof(U"")); 61 | ASSERT(20, sizeof(U"\xffzzz")); 62 | ASSERT(0, memcmp(U"", "\0\0\0\0", 4)); 63 | ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); 64 | ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); 65 | ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8)); 66 | ASSERT(u'β', U"βb"[0]); 67 | ASSERT(u'b', U"βb"[1]); 68 | ASSERT(0, U"βb"[2]); 69 | ASSERT(1, U"\xffffffff"[0] >> 31); 70 | 71 | ASSERT(0, strcmp(STR(U"a"), "U\"a\"")); 72 | 73 | ASSERT(4, sizeof(L"")); 74 | ASSERT(20, sizeof(L"\xffzzz")); 75 | ASSERT(0, memcmp(L"", "\0\0\0\0", 4)); 76 | ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); 77 | ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); 78 | ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8)); 79 | ASSERT(u'β', L"βb"[0]); 80 | ASSERT(u'b', L"βb"[1]); 81 | ASSERT(0, L"βb"[2]); 82 | ASSERT(-1, L"\xffffffff"[0] >> 31); 83 | 84 | ASSERT(0, strcmp(STR(L"a"), "L\"a\"")); 85 | 86 | ASSERT(u'α', ({ char16_t x[] = u"αβ"; x[0]; })); 87 | ASSERT(u'β', ({ char16_t x[] = u"αβ"; x[1]; })); 88 | ASSERT(6, ({ char16_t x[] = u"αβ"; sizeof(x); })); 89 | 90 | ASSERT(U'🤔', ({ char32_t x[] = U"🤔x"; x[0]; })); 91 | ASSERT(U'x', ({ char32_t x[] = U"🤔x"; x[1]; })); 92 | ASSERT(12, ({ char32_t x[] = U"🤔x"; sizeof(x); })); 93 | 94 | ASSERT(L'🤔', ({ wchar_t x[] = L"🤔x"; x[0]; })); 95 | ASSERT(L'x', ({ wchar_t x[] = L"🤔x"; x[1]; })); 96 | ASSERT(12, ({ wchar_t x[] = L"🤔x"; sizeof(x); })); 97 | 98 | ASSERT(3, π); 99 | ASSERT(3, ({ int あβ0¾=3; あβ0¾; })); 100 | ASSERT(5, ({ int $$$=5; $$$; })); 101 | 102 | printf("OK\n"); 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /test/struct.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(1, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.a; })); 5 | ASSERT(2, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.b; })); 6 | ASSERT(1, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.a; })); 7 | ASSERT(2, ({ struct {char a; int b; char c;} x; x.b=1; x.b=2; x.c=3; x.b; })); 8 | ASSERT(3, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.c; })); 9 | 10 | ASSERT(0, ({ struct {char a; char b;} x[3]; char *p=x; p[0]=0; x[0].a; })); 11 | ASSERT(1, ({ struct {char a; char b;} x[3]; char *p=x; p[1]=1; x[0].b; })); 12 | ASSERT(2, ({ struct {char a; char b;} x[3]; char *p=x; p[2]=2; x[1].a; })); 13 | ASSERT(3, ({ struct {char a; char b;} x[3]; char *p=x; p[3]=3; x[1].b; })); 14 | 15 | ASSERT(6, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.a[0]=6; p[0]; })); 16 | ASSERT(7, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.b[0]=7; p[3]; })); 17 | 18 | ASSERT(6, ({ struct { struct { char b; } a; } x; x.a.b=6; x.a.b; })); 19 | 20 | ASSERT(4, ({ struct {int a;} x; sizeof(x); })); 21 | ASSERT(8, ({ struct {int a; int b;} x; sizeof(x); })); 22 | ASSERT(8, ({ struct {int a, b;} x; sizeof(x); })); 23 | ASSERT(12, ({ struct {int a[3];} x; sizeof(x); })); 24 | ASSERT(16, ({ struct {int a;} x[4]; sizeof(x); })); 25 | ASSERT(24, ({ struct {int a[3];} x[2]; sizeof(x); })); 26 | ASSERT(2, ({ struct {char a; char b;} x; sizeof(x); })); 27 | ASSERT(0, ({ struct {} x; sizeof(x); })); 28 | ASSERT(8, ({ struct {char a; int b;} x; sizeof(x); })); 29 | ASSERT(8, ({ struct {int a; char b;} x; sizeof(x); })); 30 | 31 | ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); })); 32 | ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); })); 33 | ASSERT(2, ({ struct t {char a[2];}; { struct t {char a[4];}; } struct t y; sizeof(y); })); 34 | ASSERT(3, ({ struct t {int x;}; int t=1; struct t y; y.x=2; t+y.x; })); 35 | 36 | ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; x.a=3; y->a; })); 37 | ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; y->a=3; x.a; })); 38 | 39 | ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; })); 40 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; })); 41 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; })); 42 | ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; })); 43 | 44 | ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; })); 45 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; })); 46 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; })); 47 | ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; })); 48 | 49 | ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); })); 50 | ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); })); 51 | 52 | ASSERT(16, ({ struct {char a; long b;} x; sizeof(x); })); 53 | ASSERT(4, ({ struct {char a; short b;} x; sizeof(x); })); 54 | 55 | ASSERT(8, ({ struct foo *bar; sizeof(bar); })); 56 | ASSERT(4, ({ struct T *foo; struct T {int x;}; sizeof(struct T); })); 57 | ASSERT(1, ({ struct T { struct T *next; int x; } a; struct T b; b.x=1; a.next=&b; a.next->x; })); 58 | ASSERT(4, ({ typedef struct T T; struct T { int x; }; sizeof(T); })); 59 | 60 | ASSERT(2, ({ struct {int a;} x={1}, y={2}; (x=y).a; })); 61 | ASSERT(1, ({ struct {int a;} x={1}, y={2}; (1?x:y).a; })); 62 | ASSERT(2, ({ struct {int a;} x={1}, y={2}; (0?x:y).a; })); 63 | 64 | printf("OK\n"); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/arith.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | ASSERT(0, 0); 5 | ASSERT(42, 42); 6 | ASSERT(21, 5+20-4); 7 | ASSERT(41, 12 + 34 - 5 ); 8 | ASSERT(47, 5+6*7); 9 | ASSERT(15, 5*(9-6)); 10 | ASSERT(4, (3+5)/2); 11 | ASSERT(10, -10+20); 12 | ASSERT(10, - -10); 13 | ASSERT(10, - - +10); 14 | 15 | ASSERT(0, 0==1); 16 | ASSERT(1, 42==42); 17 | ASSERT(1, 0!=1); 18 | ASSERT(0, 42!=42); 19 | 20 | ASSERT(1, 0<1); 21 | ASSERT(0, 1<1); 22 | ASSERT(0, 2<1); 23 | ASSERT(1, 0<=1); 24 | ASSERT(1, 1<=1); 25 | ASSERT(0, 2<=1); 26 | 27 | ASSERT(1, 1>0); 28 | ASSERT(0, 1>1); 29 | ASSERT(0, 1>2); 30 | ASSERT(1, 1>=0); 31 | ASSERT(1, 1>=1); 32 | ASSERT(0, 1>=2); 33 | 34 | ASSERT(0, 1073741824 * 100 / 100); 35 | 36 | ASSERT(7, ({ int i=2; i+=5; i; })); 37 | ASSERT(7, ({ int i=2; i+=5; })); 38 | ASSERT(3, ({ int i=5; i-=2; i; })); 39 | ASSERT(3, ({ int i=5; i-=2; })); 40 | ASSERT(6, ({ int i=3; i*=2; i; })); 41 | ASSERT(6, ({ int i=3; i*=2; })); 42 | ASSERT(3, ({ int i=6; i/=2; i; })); 43 | ASSERT(3, ({ int i=6; i/=2; })); 44 | 45 | ASSERT(3, ({ int i=2; ++i; })); 46 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; ++*p; })); 47 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; --*p; })); 48 | 49 | ASSERT(2, ({ int i=2; i++; })); 50 | ASSERT(2, ({ int i=2; i--; })); 51 | ASSERT(3, ({ int i=2; i++; i; })); 52 | ASSERT(1, ({ int i=2; i--; i; })); 53 | ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p++; })); 54 | ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p--; })); 55 | 56 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; })); 57 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*(p--))--; a[1]; })); 58 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; a[2]; })); 59 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; p++; *p; })); 60 | 61 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; })); 62 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[1]; })); 63 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[2]; })); 64 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; *p; })); 65 | 66 | ASSERT(0, !1); 67 | ASSERT(0, !2); 68 | ASSERT(1, !0); 69 | ASSERT(1, !(char)0); 70 | ASSERT(0, !(long)3); 71 | ASSERT(4, sizeof(!(char)0)); 72 | ASSERT(4, sizeof(!(long)0)); 73 | 74 | ASSERT(-1, ~0); 75 | ASSERT(0, ~-1); 76 | 77 | ASSERT(5, 17%6); 78 | ASSERT(5, ((long)17)%6); 79 | ASSERT(2, ({ int i=10; i%=4; i; })); 80 | ASSERT(2, ({ long i=10; i%=4; i; })); 81 | 82 | ASSERT(0, 0&1); 83 | ASSERT(1, 3&1); 84 | ASSERT(3, 7&3); 85 | ASSERT(10, -1&10); 86 | 87 | ASSERT(1, 0|1); 88 | ASSERT(0b10011, 0b10000|0b00011); 89 | 90 | ASSERT(0, 0^0); 91 | ASSERT(0, 0b1111^0b1111); 92 | ASSERT(0b110100, 0b111000^0b001100); 93 | 94 | ASSERT(2, ({ int i=6; i&=3; i; })); 95 | ASSERT(7, ({ int i=6; i|=3; i; })); 96 | ASSERT(10, ({ int i=15; i^=5; i; })); 97 | 98 | ASSERT(1, 1<<0); 99 | ASSERT(8, 1<<3); 100 | ASSERT(10, 5<<1); 101 | ASSERT(2, 5>>1); 102 | ASSERT(-1, -1>>1); 103 | ASSERT(1, ({ int i=1; i<<=0; i; })); 104 | ASSERT(8, ({ int i=1; i<<=3; i; })); 105 | ASSERT(10, ({ int i=5; i<<=1; i; })); 106 | ASSERT(2, ({ int i=5; i>>=1; i; })); 107 | ASSERT(-1, -1); 108 | ASSERT(-1, ({ int i=-1; i; })); 109 | ASSERT(-1, ({ int i=-1; i>>=1; i; })); 110 | 111 | ASSERT(2, 0?1:2); 112 | ASSERT(1, 1?1:2); 113 | ASSERT(-1, 0?-2:-1); 114 | ASSERT(-2, 1?-2:-1); 115 | ASSERT(4, sizeof(0?1:2)); 116 | ASSERT(8, sizeof(0?(long)1:(long)2)); 117 | ASSERT(-1, 0?(long)-2:-1); 118 | ASSERT(-1, 0?-2:(long)-1); 119 | ASSERT(-2, 1?(long)-2:-1); 120 | ASSERT(-2, 1?-2:(long)-1); 121 | 122 | 1 ? -2 : (void)-1; 123 | 124 | ASSERT(20, ({ int x; int *p=&x; p+20-p; })); 125 | ASSERT(1, ({ int x; int *p=&x; p+20-p>0; })); 126 | ASSERT(-20, ({ int x; int *p=&x; p-20-p; })); 127 | ASSERT(1, ({ int x; int *p=&x; p-20-p<0; })); 128 | 129 | ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0); 130 | ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff); 131 | ASSERT(1, (void *)0xffffffffffffffff > (void *)0); 132 | 133 | ASSERT(3, 3?:5); 134 | ASSERT(5, 0?:5); 135 | ASSERT(4, ({ int i = 3; ++i?:10; })); 136 | 137 | ASSERT(3, (long double)3); 138 | ASSERT(5, (long double)3+2); 139 | ASSERT(6, (long double)3*2); 140 | ASSERT(5, (long double)3+2.0); 141 | 142 | printf("OK\n"); 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /test/control.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | /* 4 | * This is a block comment. 5 | */ 6 | 7 | int main() { 8 | ASSERT(3, ({ int x; if (0) x=2; else x=3; x; })); 9 | ASSERT(3, ({ int x; if (1-1) x=2; else x=3; x; })); 10 | ASSERT(2, ({ int x; if (1) x=2; else x=3; x; })); 11 | ASSERT(2, ({ int x; if (2-1) x=2; else x=3; x; })); 12 | 13 | ASSERT(55, ({ int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; j; })); 14 | 15 | ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; })); 16 | 17 | ASSERT(3, ({ 1; {2;} 3; })); 18 | ASSERT(5, ({ ;;; 5; })); 19 | 20 | ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; })); 21 | ASSERT(55, ({ int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} j; })); 22 | 23 | ASSERT(3, (1,2,3)); 24 | ASSERT(5, ({ int i=2, j=3; (i=5,j)=6; i; })); 25 | ASSERT(6, ({ int i=2, j=3; (i=5,j)=6; j; })); 26 | 27 | ASSERT(55, ({ int j=0; for (int i=0; i<=10; i=i+1) j=j+i; j; })); 28 | ASSERT(3, ({ int i=3; int j=0; for (int i=0; i<=10; i=i+1) j=j+i; i; })); 29 | 30 | ASSERT(1, 0||1); 31 | ASSERT(1, 0||(2-2)||5); 32 | ASSERT(0, 0||0); 33 | ASSERT(0, 0||(2-2)); 34 | 35 | ASSERT(0, 0&&1); 36 | ASSERT(0, (2-2)&&5); 37 | ASSERT(1, 1&&5); 38 | 39 | ASSERT(3, ({ int i=0; goto a; a: i++; b: i++; c: i++; i; })); 40 | ASSERT(2, ({ int i=0; goto e; d: i++; e: i++; f: i++; i; })); 41 | ASSERT(1, ({ int i=0; goto i; g: i++; h: i++; i: i++; i; })); 42 | 43 | ASSERT(1, ({ typedef int foo; goto foo; foo:; 1; })); 44 | 45 | ASSERT(3, ({ int i=0; for(;i<10;i++) { if (i == 3) break; } i; })); 46 | ASSERT(4, ({ int i=0; while (1) { if (i++ == 3) break; } i; })); 47 | ASSERT(3, ({ int i=0; for(;i<10;i++) { for (;;) break; if (i == 3) break; } i; })); 48 | ASSERT(4, ({ int i=0; while (1) { while(1) break; if (i++ == 3) break; } i; })); 49 | 50 | ASSERT(10, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } i; })); 51 | ASSERT(6, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } j; })); 52 | ASSERT(10, ({ int i=0; int j=0; for(;!i;) { for (;j!=10;j++) continue; break; } j; })); 53 | ASSERT(11, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } i; })); 54 | ASSERT(5, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } j; })); 55 | ASSERT(11, ({ int i=0; int j=0; while(!i) { while (j++!=10) continue; break; } j; })); 56 | 57 | ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 58 | ASSERT(6, ({ int i=0; switch(1) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 59 | ASSERT(7, ({ int i=0; switch(2) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 60 | ASSERT(0, ({ int i=0; switch(3) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 61 | ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; default:i=7; } i; })); 62 | ASSERT(7, ({ int i=0; switch(1) { case 0:i=5;break; default:i=7; } i; })); 63 | ASSERT(2, ({ int i=0; switch(1) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; })); 64 | ASSERT(0, ({ int i=0; switch(3) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; })); 65 | 66 | ASSERT(3, ({ int i=0; switch(-1) { case 0xffffffff: i=3; break; } i; })); 67 | 68 | ASSERT(7, ({ int i=0; int j=0; do { j++; } while (i++ < 6); j; })); 69 | ASSERT(4, ({ int i=0; int j=0; int k=0; do { if (++j > 3) break; continue; k++; } while (1); j; })); 70 | 71 | ASSERT(0, 0.0 && 0.0); 72 | ASSERT(0, 0.0 && 0.1); 73 | ASSERT(0, 0.3 && 0.0); 74 | ASSERT(1, 0.3 && 0.5); 75 | ASSERT(0, 0.0 || 0.0); 76 | ASSERT(1, 0.0 || 0.1); 77 | ASSERT(1, 0.3 || 0.0); 78 | ASSERT(1, 0.3 || 0.5); 79 | ASSERT(5, ({ int x; if (0.0) x=3; else x=5; x; })); 80 | ASSERT(3, ({ int x; if (0.1) x=3; else x=5; x; })); 81 | ASSERT(5, ({ int x=5; if (0.0) x=3; x; })); 82 | ASSERT(3, ({ int x=5; if (0.1) x=3; x; })); 83 | ASSERT(10, ({ double i=10.0; int j=0; for (; i; i--, j++); j; })); 84 | ASSERT(10, ({ double i=10.0; int j=0; do j++; while(--i); j; })); 85 | 86 | ASSERT(2, ({ int i=0; switch(7) { case 0 ... 5: i=1; break; case 6 ... 20: i=2; break; } i; })); 87 | ASSERT(1, ({ int i=0; switch(7) { case 0 ... 7: i=1; break; case 8 ... 10: i=2; break; } i; })); 88 | ASSERT(1, ({ int i=0; switch(7) { case 0: i=1; break; case 7 ... 7: i=1; break; } i; })); 89 | 90 | ASSERT(3, ({ void *p = &&v11; int i=0; goto *p; v11:i++; v12:i++; v13:i++; i; })); 91 | ASSERT(2, ({ void *p = &&v22; int i=0; goto *p; v21:i++; v22:i++; v23:i++; i; })); 92 | ASSERT(1, ({ void *p = &&v33; int i=0; goto *p; v31:i++; v32:i++; v33:i++; i; })); 93 | 94 | ASSERT(3, ({ static void *p[]={&&v41,&&v42,&&v43}; int i=0; goto *p[0]; v41:i++; v42:i++; v43:i++; i; })); 95 | ASSERT(2, ({ static void *p[]={&&v52,&&v52,&&v53}; int i=0; goto *p[1]; v51:i++; v52:i++; v53:i++; i; })); 96 | ASSERT(1, ({ static void *p[]={&&v62,&&v62,&&v63}; int i=0; goto *p[2]; v61:i++; v62:i++; v63:i++; i; })); 97 | 98 | printf("OK\n"); 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /unicode.c: -------------------------------------------------------------------------------- 1 | #include "xcc.h" 2 | 3 | // Encode a given character in UTF-8. 4 | int encode_utf8(char *buf, uint32_t c) { 5 | if (c <= 0x7F) { 6 | buf[0] = c; 7 | return 1; 8 | } 9 | 10 | if (c <= 0x7FF) { 11 | buf[0] = 0b11000000 | (c >> 6); 12 | buf[1] = 0b10000000 | (c & 0b00111111); 13 | return 2; 14 | } 15 | 16 | if (c <= 0xFFFF) { 17 | buf[0] = 0b11100000 | (c >> 12); 18 | buf[1] = 0b10000000 | ((c >> 6) & 0b00111111); 19 | buf[2] = 0b10000000 | (c & 0b00111111); 20 | return 3; 21 | } 22 | 23 | buf[0] = 0b11110000 | (c >> 18); 24 | buf[1] = 0b10000000 | ((c >> 12) & 0b00111111); 25 | buf[2] = 0b10000000 | ((c >> 6) & 0b00111111); 26 | buf[3] = 0b10000000 | (c & 0b00111111); 27 | return 4; 28 | } 29 | 30 | // Read a UTF-8-encoded Unicode code point from a source file. 31 | // We assume that source files are always in UTF-8. 32 | // 33 | // UTF-8 is a variable-width encoding in which one code point is 34 | // encoded in one to four bytes. One byte UTF-8 code points are 35 | // identical to ASCII. Non-ASCII characters are encoded using more 36 | // than one byte. 37 | uint32_t decode_utf8(char **new_pos, char *p) { 38 | if ((unsigned char)*p < 128) { 39 | *new_pos = p + 1; 40 | return *p; 41 | } 42 | 43 | char *start = p; 44 | int len; 45 | uint32_t c; 46 | 47 | if ((unsigned char)*p >= 0b11110000) { 48 | len = 4; 49 | c = *p & 0b111; 50 | } else if ((unsigned char)*p >= 0b11100000) { 51 | len = 3; 52 | c = *p & 0b1111; 53 | } else if ((unsigned char)*p >= 0b11000000) { 54 | len = 2; 55 | c = *p & 0b11111; 56 | } else { 57 | error_at(start, "invalid UTF-8 sequence"); 58 | } 59 | 60 | for (int i = 1; i < len; i++) { 61 | if ((unsigned char)p[i] >> 6 != 0b10) 62 | error_at(start, "invalid UTF-8 sequence"); 63 | c = (c << 6) | (p[i] & 0b111111); 64 | } 65 | 66 | *new_pos = p + len; 67 | return c; 68 | } 69 | 70 | static bool in_range(uint32_t *range, uint32_t c) { 71 | for (int i = 0; range[i] != -1; i += 2) 72 | if (range[i] <= c && c <= range[i + 1]) 73 | return true; 74 | return false; 75 | } 76 | 77 | // [https://www.sigbus.info/n1570#D] C11 allows not only ASCII but 78 | // some multibyte characters in certan Unicode ranges to be used in an 79 | // identifier. 80 | // 81 | // This function returns true if a given character is acceptable as 82 | // the first character of an identifier. 83 | // 84 | // For example, ¾ (U+00BE) is a valid identifier because characters in 85 | // 0x00BE-0x00C0 are allowed, while neither ⟘ (U+27D8) nor ' ' 86 | // (U+3000, full-width space) are allowed because they are out of range. 87 | bool is_ident1(uint32_t c) { 88 | static uint32_t range[] = { 89 | '_', '_', 'a', 'z', 'A', 'Z', '$', '$', 90 | 0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF, 91 | 0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6, 92 | 0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F, 93 | 0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D, 94 | 0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F, 95 | 0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793, 96 | 0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F, 97 | 0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF, 98 | 0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD, 99 | 0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 100 | 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 101 | 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 102 | 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, -1, 103 | }; 104 | 105 | return in_range(range, c); 106 | } 107 | 108 | // Returns true if a given character is acceptable as a non-first 109 | // character of an identifier. 110 | bool is_ident2(uint32_t c) { 111 | static uint32_t range[] = { 112 | '0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF, 113 | 0xFE20, 0xFE2F, -1, 114 | }; 115 | 116 | return is_ident1(c) || in_range(range, c); 117 | } 118 | 119 | // Returns the number of columns needed to display a given 120 | // character in a fixed-width font. 121 | // 122 | // Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c 123 | static int char_width(uint32_t c) { 124 | static uint32_t range1[] = { 125 | 0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486, 126 | 0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2, 127 | 0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615, 128 | 0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8, 129 | 0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A, 130 | 0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C, 131 | 0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963, 132 | 0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD, 133 | 0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42, 134 | 0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82, 135 | 0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD, 136 | 0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F, 137 | 0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82, 138 | 0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48, 139 | 0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF, 140 | 0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43, 141 | 0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6, 142 | 0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1, 143 | 0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19, 144 | 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E, 145 | 0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC, 146 | 0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037, 147 | 0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F, 148 | 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 149 | 0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3, 150 | 0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922, 151 | 0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18, 152 | 0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C, 153 | 0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF, 154 | 0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F, 155 | 0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806, 156 | 0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F, 157 | 0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03, 158 | 0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F, 159 | 0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD, 160 | 0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF, 161 | -1, 162 | }; 163 | 164 | if (in_range(range1, c)) 165 | return 0; 166 | 167 | static uint32_t range2[] = { 168 | 0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E, 169 | 0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19, 170 | 0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644, 171 | 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1, 172 | }; 173 | 174 | if (in_range(range2, c)) 175 | return 2; 176 | return 1; 177 | } 178 | 179 | // Returns the number of columns needed to display a given 180 | // string in a fixed-width font. 181 | int display_width(char *p, int len) { 182 | char *start = p; 183 | int w = 0; 184 | while (p - start < len) { 185 | uint32_t c = decode_utf8(&p, p); 186 | w += char_width(c); 187 | } 188 | return w; 189 | } 190 | -------------------------------------------------------------------------------- /test/macro.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "include1.h" 3 | 4 | char *main_filename1 = __FILE__; 5 | int main_line1 = __LINE__; 6 | #define LINE() __LINE__ 7 | int main_line2 = LINE(); 8 | 9 | # 10 | 11 | /* */ # 12 | 13 | int ret3(void) { return 3; } 14 | int dbl(int x) { return x*x; } 15 | 16 | int add2(int x, int y) { 17 | return x + y; 18 | } 19 | 20 | int add6(int a, int b, int c, int d, int e, int f) { 21 | return a + b + c + d + e + f; 22 | } 23 | 24 | int main() { 25 | ASSERT(5, include1); 26 | ASSERT(7, include2); 27 | 28 | #if 0 29 | #include "/no/such/file" 30 | ASSERT(0, 1); 31 | #if nested 32 | #endif 33 | #endif 34 | 35 | int m = 0; 36 | 37 | #if 1 38 | m = 5; 39 | #endif 40 | ASSERT(5, m); 41 | 42 | #if 1 43 | # if 0 44 | # if 1 45 | foo bar 46 | # endif 47 | # endif 48 | m = 3; 49 | #endif 50 | ASSERT(3, m); 51 | 52 | #if 1-1 53 | # if 1 54 | # endif 55 | # if 1 56 | # else 57 | # endif 58 | # if 0 59 | # else 60 | # endif 61 | m = 2; 62 | #else 63 | # if 1 64 | m = 3; 65 | # endif 66 | #endif 67 | ASSERT(3, m); 68 | 69 | #if 1 70 | m = 2; 71 | #else 72 | m = 3; 73 | #endif 74 | ASSERT(2, m); 75 | 76 | #if 1 77 | m = 2; 78 | #else 79 | m = 3; 80 | #endif 81 | ASSERT(2, m); 82 | 83 | #if 0 84 | m = 1; 85 | #elif 0 86 | m = 2; 87 | #elif 3+5 88 | m = 3; 89 | #elif 1*5 90 | m = 4; 91 | #endif 92 | ASSERT(3, m); 93 | 94 | #if 1+5 95 | m = 1; 96 | #elif 1 97 | m = 2; 98 | #elif 3 99 | m = 2; 100 | #endif 101 | ASSERT(1, m); 102 | 103 | #if 0 104 | m = 1; 105 | #elif 1 106 | # if 1 107 | m = 2; 108 | # else 109 | m = 3; 110 | # endif 111 | #else 112 | m = 5; 113 | #endif 114 | ASSERT(2, m); 115 | 116 | int M1 = 5; 117 | 118 | #define M1 3 119 | ASSERT(3, M1); 120 | #define M1 4 121 | ASSERT(4, M1); 122 | 123 | #define M1 3+4+ 124 | ASSERT(12, M1 5); 125 | 126 | #define M1 3+4 127 | ASSERT(23, M1*5); 128 | 129 | #define ASSERT_ assert( 130 | #define if 5 131 | #define five "5" 132 | #define END ) 133 | ASSERT_ 5, if, five END; 134 | 135 | #undef ASSERT_ 136 | #undef if 137 | #undef five 138 | #undef END 139 | 140 | if (0); 141 | 142 | #define M 5 143 | #if M 144 | m = 5; 145 | #else 146 | m = 6; 147 | #endif 148 | ASSERT(5, m); 149 | 150 | #define M 5 151 | #if M-5 152 | m = 6; 153 | #elif M 154 | m = 5; 155 | #endif 156 | ASSERT(5, m); 157 | 158 | int M2 = 6; 159 | #define M2 M2 + 3 160 | ASSERT(9, M2); 161 | 162 | #define M3 M2 + 3 163 | ASSERT(12, M3); 164 | 165 | int M4 = 3; 166 | #define M4 M5 * 5 167 | #define M5 M4 + 2 168 | ASSERT(13, M4); 169 | 170 | #ifdef M6 171 | m = 5; 172 | #else 173 | m = 3; 174 | #endif 175 | ASSERT(3, m); 176 | 177 | #define M6 178 | #ifdef M6 179 | m = 5; 180 | #else 181 | m = 3; 182 | #endif 183 | ASSERT(5, m); 184 | 185 | #ifndef M7 186 | m = 3; 187 | #else 188 | m = 5; 189 | #endif 190 | ASSERT(3, m); 191 | 192 | #define M7 193 | #ifndef M7 194 | m = 3; 195 | #else 196 | m = 5; 197 | #endif 198 | ASSERT(5, m); 199 | 200 | #if 0 201 | #ifdef NO_SUCH_MACRO 202 | #endif 203 | #ifndef NO_SUCH_MACRO 204 | #endif 205 | #else 206 | #endif 207 | 208 | #define M7() 1 209 | int M7 = 5; 210 | ASSERT(1, M7()); 211 | ASSERT(5, M7); 212 | 213 | #define M7 () 214 | ASSERT(3, ret3 M7); 215 | 216 | #define M8(x,y) x+y 217 | ASSERT(7, M8(3, 4)); 218 | 219 | #define M8(x,y) x*y 220 | ASSERT(24, M8(3+4, 4+5)); 221 | 222 | #define M8(x,y) (x)*(y) 223 | ASSERT(63, M8(3+4, 4+5)); 224 | 225 | #define M8(x,y) x y 226 | ASSERT(9, M8(, 4+5)); 227 | 228 | #define M8(x,y) x*y 229 | ASSERT(20, M8((2+3), 4)); 230 | 231 | #define M8(x,y) x*y 232 | ASSERT(12, M8((2,3), 4)); 233 | 234 | #define dbl(x) M10(x) * x 235 | #define M10(x) dbl(x) + 3 236 | ASSERT(10, dbl(2)); 237 | 238 | #define M11(x) #x 239 | ASSERT('a', M11( a!b `""c)[0]); 240 | ASSERT('!', M11( a!b `""c)[1]); 241 | ASSERT('b', M11( a!b `""c)[2]); 242 | ASSERT(' ', M11( a!b `""c)[3]); 243 | ASSERT('`', M11( a!b `""c)[4]); 244 | ASSERT('"', M11( a!b `""c)[5]); 245 | ASSERT('"', M11( a!b `""c)[6]); 246 | ASSERT('c', M11( a!b `""c)[7]); 247 | ASSERT(0, M11( a!b `""c)[8]); 248 | 249 | #define paste(x,y) x##y 250 | ASSERT(15, paste(1,5)); 251 | ASSERT(255, paste(0,xff)); 252 | ASSERT(3, ({ int foobar=3; paste(foo,bar); })); 253 | ASSERT(5, paste(5,)); 254 | ASSERT(5, paste(,5)); 255 | 256 | #define i 5 257 | ASSERT(101, ({ int i3=100; paste(1+i,3); })); 258 | #undef i 259 | 260 | #define paste2(x) x##5 261 | ASSERT(26, paste2(1+2)); 262 | 263 | #define paste3(x) 2##x 264 | ASSERT(23, paste3(1+2)); 265 | 266 | #define paste4(x, y, z) x##y##z 267 | ASSERT(123, paste4(1,2,3)); 268 | 269 | #define M12 270 | #if defined(M12) 271 | m = 3; 272 | #else 273 | m = 4; 274 | #endif 275 | ASSERT(3, m); 276 | 277 | #define M12 278 | #if defined M12 279 | m = 3; 280 | #else 281 | m = 4; 282 | #endif 283 | ASSERT(3, m); 284 | 285 | #if defined(M12) - 1 286 | m = 3; 287 | #else 288 | m = 4; 289 | #endif 290 | ASSERT(4, m); 291 | 292 | #if defined(NO_SUCH_MACRO) 293 | m = 3; 294 | #else 295 | m = 4; 296 | #endif 297 | ASSERT(4, m); 298 | 299 | #if no_such_symbol == 0 300 | m = 5; 301 | #else 302 | m = 6; 303 | #endif 304 | ASSERT(5, m); 305 | 306 | #define STR(x) #x 307 | #define M12(x) STR(x) 308 | #define M13(x) M12(foo.x) 309 | ASSERT(0, strcmp(M13(bar), "foo.bar")); 310 | 311 | #define M13(x) M12(foo. x) 312 | ASSERT(0, strcmp(M13(bar), "foo. bar")); 313 | 314 | #define M12 foo 315 | #define M13(x) STR(x) 316 | #define M14(x) M13(x.M12) 317 | ASSERT(0, strcmp(M14(bar), "bar.foo")); 318 | 319 | #define M14(x) M13(x. M12) 320 | ASSERT(0, strcmp(M14(bar), "bar. foo")); 321 | 322 | #include "include3.h" 323 | ASSERT(3, foo); 324 | 325 | #include "include4.h" 326 | ASSERT(4, foo); 327 | 328 | #define M13 "include3.h" 329 | #include M13 330 | ASSERT(3, foo); 331 | 332 | #define M13 < include4.h 333 | #include M13 > 334 | ASSERT(4, foo); 335 | 336 | #undef foo 337 | 338 | ASSERT(1, __STDC__); 339 | 340 | ASSERT(0, strcmp(main_filename1, "test/macro.c")); 341 | ASSERT(5, main_line1); 342 | ASSERT(7, main_line2); 343 | ASSERT(0, strcmp(include1_filename, "test/include1.h")); 344 | ASSERT(4, include1_line); 345 | 346 | #define M14(...) 3 347 | ASSERT(3, M14()); 348 | 349 | #define M14(...) __VA_ARGS__ 350 | ASSERT(2, M14() 2); 351 | ASSERT(5, M14(5)); 352 | 353 | #define M14(...) add2(__VA_ARGS__) 354 | ASSERT(8, M14(2, 6)); 355 | 356 | #define M14(...) add6(1,2,__VA_ARGS__,6) 357 | ASSERT(21, M14(3,4,5)); 358 | 359 | #define M14(x, ...) add6(1,2,x,__VA_ARGS__,6) 360 | ASSERT(21, M14(3,4,5)); 361 | 362 | #define M14(args...) 3 363 | ASSERT(3, M14()); 364 | 365 | #define M14(x, ...) x 366 | ASSERT(5, M14(5)); 367 | 368 | #define M14(args...) args 369 | ASSERT(2, M14() 2); 370 | ASSERT(5, M14(5)); 371 | 372 | #define M14(args...) add2(args) 373 | ASSERT(8, M14(2, 6)); 374 | 375 | #define M14(args...) add6(1,2,args,6) 376 | ASSERT(21, M14(3,4,5)); 377 | 378 | #define M14(x, args...) add6(1,2,x,args,6) 379 | ASSERT(21, M14(3,4,5)); 380 | 381 | #define M14(x, args...) x 382 | ASSERT(5, M14(5)); 383 | 384 | #define CONCAT(x,y) x##y 385 | ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); })); 386 | ASSERT(5, ({ CONCAT(4,.57) + 0.5; })); 387 | 388 | ASSERT(11, strlen(__DATE__)); 389 | ASSERT(8, strlen(__TIME__)); 390 | 391 | ASSERT(0, __COUNTER__); 392 | ASSERT(1, __COUNTER__); 393 | ASSERT(2, __COUNTER__); 394 | 395 | ASSERT(24, strlen(__TIMESTAMP__)); 396 | 397 | ASSERT(0, strcmp(__BASE_FILE__, "test/macro.c")); 398 | 399 | #define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(,) __VA_ARGS__) 400 | ASSERT(0, ({ char buf[100]; M30(buf, "foo"); strcmp(buf, "foo"); })); 401 | ASSERT(0, ({ char buf[100]; M30(buf, "foo%d", 3); strcmp(buf, "foo3"); })); 402 | ASSERT(0, ({ char buf[100]; M30(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); 403 | 404 | #define M31(buf, fmt, ...) sprintf(buf, fmt, ## __VA_ARGS__) 405 | ASSERT(0, ({ char buf[100]; M31(buf, "foo"); strcmp(buf, "foo"); })); 406 | ASSERT(0, ({ char buf[100]; M31(buf, "foo%d", 3); strcmp(buf, "foo3"); })); 407 | ASSERT(0, ({ char buf[100]; M31(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); 408 | 409 | #define M31(x, y) (1, ##x y) 410 | ASSERT(3, M31(, 3)); 411 | 412 | printf("OK\n"); 413 | return 0; 414 | } 415 | -------------------------------------------------------------------------------- /type.c: -------------------------------------------------------------------------------- 1 | #include "xcc.h" 2 | 3 | Type *ty_void = &(Type){TY_VOID, 1, 1}; 4 | Type *ty_bool = &(Type){TY_BOOL, 1, 1}; 5 | 6 | Type *ty_char = &(Type){TY_CHAR, 1, 1}; 7 | Type *ty_short = &(Type){TY_SHORT, 2, 2}; 8 | Type *ty_int = &(Type){TY_INT, 4, 4}; 9 | Type *ty_long = &(Type){TY_LONG, 8, 8}; 10 | 11 | Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true}; 12 | Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true}; 13 | Type *ty_uint = &(Type){TY_INT, 4, 4, true}; 14 | Type *ty_ulong = &(Type){TY_LONG, 8, 8, true}; 15 | 16 | Type *ty_float = &(Type){TY_FLOAT, 4, 4}; 17 | Type *ty_double = &(Type){TY_DOUBLE, 8, 8}; 18 | Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16}; 19 | 20 | static Type *new_type(TypeKind kind, int size, int align) { 21 | Type *ty = calloc(1, sizeof(Type)); 22 | ty->kind = kind; 23 | ty->size = size; 24 | ty->align = align; 25 | return ty; 26 | } 27 | 28 | bool is_integer(Type *ty) { 29 | TypeKind k = ty->kind; 30 | return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || 31 | k == TY_INT || k == TY_LONG || k == TY_ENUM; 32 | } 33 | 34 | bool is_flonum(Type *ty) { 35 | return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE || 36 | ty->kind == TY_LDOUBLE; 37 | } 38 | 39 | bool is_numeric(Type *ty) { 40 | return is_integer(ty) || is_flonum(ty); 41 | } 42 | 43 | bool is_compatible(Type *t1, Type *t2) { 44 | if (t1 == t2) 45 | return true; 46 | 47 | if (t1->origin) 48 | return is_compatible(t1->origin, t2); 49 | 50 | if (t2->origin) 51 | return is_compatible(t1, t2->origin); 52 | 53 | if (t1->kind != t2->kind) 54 | return false; 55 | 56 | switch (t1->kind) { 57 | case TY_CHAR: 58 | case TY_SHORT: 59 | case TY_INT: 60 | case TY_LONG: 61 | return t1->is_unsigned == t2->is_unsigned; 62 | case TY_FLOAT: 63 | case TY_DOUBLE: 64 | case TY_LDOUBLE: 65 | return true; 66 | case TY_PTR: 67 | return is_compatible(t1->base, t2->base); 68 | case TY_FUNC: { 69 | if (!is_compatible(t1->return_ty, t2->return_ty)) 70 | return false; 71 | if (t1->is_variadic != t2->is_variadic) 72 | return false; 73 | 74 | Type *p1 = t1->params; 75 | Type *p2 = t2->params; 76 | for (; p1 && p2; p1 = p1->next, p2 = p2->next) 77 | if (!is_compatible(p1, p2)) 78 | return false; 79 | return p1 == NULL && p2 == NULL; 80 | } 81 | case TY_ARRAY: 82 | if (!is_compatible(t1->base, t2->base)) 83 | return false; 84 | return t1->array_len < 0 && t2->array_len < 0 && 85 | t1->array_len == t2->array_len; 86 | } 87 | return false; 88 | } 89 | 90 | Type *copy_type(Type *ty) { 91 | Type *ret = calloc(1, sizeof(Type)); 92 | *ret = *ty; 93 | ret->origin = ty; 94 | return ret; 95 | } 96 | 97 | Type *pointer_to(Type *base) { 98 | Type *ty = new_type(TY_PTR, 8, 8); 99 | ty->base = base; 100 | ty->is_unsigned = true; 101 | return ty; 102 | } 103 | 104 | Type *func_type(Type *return_ty) { 105 | // The C spec disallows sizeof(), but 106 | // GCC allows that and the expression is evaluated to 1. 107 | Type *ty = new_type(TY_FUNC, 1, 1); 108 | ty->return_ty = return_ty; 109 | return ty; 110 | } 111 | 112 | Type *array_of(Type *base, int len) { 113 | Type *ty = new_type(TY_ARRAY, base->size * len, base->align); 114 | ty->base = base; 115 | ty->array_len = len; 116 | return ty; 117 | } 118 | 119 | Type *vla_of(Type *base, Node *len) { 120 | Type *ty = new_type(TY_VLA, 8, 8); 121 | ty->base = base; 122 | ty->vla_len = len; 123 | return ty; 124 | } 125 | 126 | Type *enum_type(void) { 127 | return new_type(TY_ENUM, 4, 4); 128 | } 129 | 130 | Type *struct_type(void) { 131 | return new_type(TY_STRUCT, 0, 1); 132 | } 133 | 134 | static Type *get_common_type(Type *ty1, Type *ty2) { 135 | if (ty1->base) 136 | return pointer_to(ty1->base); 137 | 138 | if (ty1->kind == TY_FUNC) 139 | return pointer_to(ty1); 140 | if (ty2->kind == TY_FUNC) 141 | return pointer_to(ty2); 142 | 143 | if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE) 144 | return ty_ldouble; 145 | if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) 146 | return ty_double; 147 | if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) 148 | return ty_float; 149 | 150 | if (ty1->size < 4) 151 | ty1 = ty_int; 152 | if (ty2->size < 4) 153 | ty2 = ty_int; 154 | 155 | if (ty1->size != ty2->size) 156 | return (ty1->size < ty2->size) ? ty2 : ty1; 157 | 158 | if (ty2->is_unsigned) 159 | return ty2; 160 | return ty1; 161 | } 162 | 163 | // For many binary operators, we implicitly promote operands so that 164 | // both operands have the same type. Any integral type smaller than 165 | // int is always promoted to int. If the type of one operand is larger 166 | // than the other's (e.g. "long" vs. "int"), the smaller operand will 167 | // be promoted to match with the other. 168 | // 169 | // This operation is called the "usual arithmetic conversion". 170 | static void usual_arith_conv(Node **lhs, Node **rhs) { 171 | Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty); 172 | *lhs = new_cast(*lhs, ty); 173 | *rhs = new_cast(*rhs, ty); 174 | } 175 | 176 | void add_type(Node *node) { 177 | if (!node || node->ty) 178 | return; 179 | 180 | add_type(node->lhs); 181 | add_type(node->rhs); 182 | add_type(node->cond); 183 | add_type(node->then); 184 | add_type(node->els); 185 | add_type(node->init); 186 | add_type(node->inc); 187 | 188 | for (Node *n = node->body; n; n = n->next) 189 | add_type(n); 190 | for (Node *n = node->args; n; n = n->next) 191 | add_type(n); 192 | 193 | switch (node->kind) { 194 | case ND_NUM: 195 | node->ty = ty_int; 196 | return; 197 | case ND_ADD: 198 | case ND_SUB: 199 | case ND_MUL: 200 | case ND_DIV: 201 | case ND_MOD: 202 | case ND_BITAND: 203 | case ND_BITOR: 204 | case ND_BITXOR: 205 | usual_arith_conv(&node->lhs, &node->rhs); 206 | node->ty = node->lhs->ty; 207 | return; 208 | case ND_NEG: { 209 | Type *ty = get_common_type(ty_int, node->lhs->ty); 210 | node->lhs = new_cast(node->lhs, ty); 211 | node->ty = ty; 212 | return; 213 | } 214 | case ND_ASSIGN: 215 | if (node->lhs->ty->kind == TY_ARRAY) 216 | error_tok(node->lhs->tok, "not an lvalue"); 217 | if (node->lhs->ty->kind != TY_STRUCT) 218 | node->rhs = new_cast(node->rhs, node->lhs->ty); 219 | node->ty = node->lhs->ty; 220 | return; 221 | case ND_EQ: 222 | case ND_NE: 223 | case ND_LT: 224 | case ND_LE: 225 | usual_arith_conv(&node->lhs, &node->rhs); 226 | node->ty = ty_int; 227 | return; 228 | case ND_FUNCALL: 229 | node->ty = node->func_ty->return_ty; 230 | return; 231 | case ND_NOT: 232 | case ND_LOGOR: 233 | case ND_LOGAND: 234 | node->ty = ty_int; 235 | return; 236 | case ND_BITNOT: 237 | case ND_SHL: 238 | case ND_SHR: 239 | node->ty = node->lhs->ty; 240 | return; 241 | case ND_VAR: 242 | case ND_VLA_PTR: 243 | node->ty = node->var->ty; 244 | return; 245 | case ND_COND: 246 | if (node->then->ty->kind == TY_VOID || node->els->ty->kind == TY_VOID) { 247 | node->ty = ty_void; 248 | } else { 249 | usual_arith_conv(&node->then, &node->els); 250 | node->ty = node->then->ty; 251 | } 252 | return; 253 | case ND_COMMA: 254 | node->ty = node->rhs->ty; 255 | return; 256 | case ND_MEMBER: 257 | node->ty = node->member->ty; 258 | return; 259 | case ND_ADDR: { 260 | Type *ty = node->lhs->ty; 261 | if (ty->kind == TY_ARRAY) 262 | node->ty = pointer_to(ty->base); 263 | else 264 | node->ty = pointer_to(ty); 265 | return; 266 | } 267 | case ND_DEREF: 268 | if (!node->lhs->ty->base) 269 | error_tok(node->tok, "invalid pointer dereference"); 270 | if (node->lhs->ty->base->kind == TY_VOID) 271 | error_tok(node->tok, "dereferencing a void pointer"); 272 | 273 | node->ty = node->lhs->ty->base; 274 | return; 275 | case ND_STMT_EXPR: 276 | if (node->body) { 277 | Node *stmt = node->body; 278 | while (stmt->next) 279 | stmt = stmt->next; 280 | if (stmt->kind == ND_EXPR_STMT) { 281 | node->ty = stmt->lhs->ty; 282 | return; 283 | } 284 | } 285 | error_tok(node->tok, "statement expression returning void is not supported"); 286 | return; 287 | case ND_LABEL_VAL: 288 | node->ty = pointer_to(ty_void); 289 | return; 290 | case ND_CAS: 291 | add_type(node->cas_addr); 292 | add_type(node->cas_old); 293 | add_type(node->cas_new); 294 | node->ty = ty_bool; 295 | 296 | if (node->cas_addr->ty->kind != TY_PTR) 297 | error_tok(node->cas_addr->tok, "pointer expected"); 298 | if (node->cas_old->ty->kind != TY_PTR) 299 | error_tok(node->cas_old->tok, "pointer expected"); 300 | return; 301 | case ND_EXCH: 302 | if (node->lhs->ty->kind != TY_PTR) 303 | error_tok(node->cas_addr->tok, "pointer expected"); 304 | node->ty = node->lhs->ty->base; 305 | return; 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /test/driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | xcc=$1 3 | 4 | tmp=`mktemp -d /tmp/xcc-test-XXXXXX` 5 | trap 'rm -rf $tmp' INT TERM HUP EXIT 6 | echo > $tmp/empty.c 7 | 8 | check() { 9 | if [ $? -eq 0 ]; then 10 | echo "testing $1 ... passed" 11 | else 12 | echo "testing $1 ... failed" 13 | exit 1 14 | fi 15 | } 16 | 17 | # -o 18 | rm -f $tmp/out 19 | ./xcc -c -o $tmp/out $tmp/empty.c 20 | [ -f $tmp/out ] 21 | check -o out 22 | 23 | rm -f $tmp/out 24 | ./xcc -c -o$tmp/out $tmp/empty.c 25 | [ -f $tmp/out ] 26 | check -oout 27 | 28 | # --help 29 | $xcc --help 2>&1 | grep -q xc 30 | check --help 31 | 32 | # -S 33 | echo 'int main() {}' | $xcc -S -o- -xc - | grep -q 'main:' 34 | check -S 35 | 36 | # Default output file 37 | rm -f $tmp/out.o $tmp/out.s 38 | echo 'int main() {}' > $tmp/out.c 39 | (cd $tmp; $OLDPWD/$xcc -c out.c) 40 | [ -f $tmp/out.o ] 41 | check 'default output file' 42 | 43 | (cd $tmp; $OLDPWD/$xcc -c -S out.c) 44 | [ -f $tmp/out.s ] 45 | check 'default output file' 46 | 47 | # Multiple input files 48 | rm -f $tmp/foo.o $tmp/bar.o 49 | echo 'int x;' > $tmp/foo.c 50 | echo 'int y;' > $tmp/bar.c 51 | (cd $tmp; $OLDPWD/$xcc -c $tmp/foo.c $tmp/bar.c) 52 | [ -f $tmp/foo.o ] && [ -f $tmp/bar.o ] 53 | check 'multiple input files' 54 | 55 | rm -f $tmp/foo.s $tmp/bar.s 56 | echo 'int x;' > $tmp/foo.c 57 | echo 'int y;' > $tmp/bar.c 58 | (cd $tmp; $OLDPWD/$xcc -c -S $tmp/foo.c $tmp/bar.c) 59 | [ -f $tmp/foo.s ] && [ -f $tmp/bar.s ] 60 | check 'multiple input files' 61 | 62 | # Run linker 63 | rm -f $tmp/foo 64 | echo 'int main() { return 0; }' | $xcc -o $tmp/foo -xc -xc - 65 | $tmp/foo 66 | check linker 67 | 68 | rm -f $tmp/foo 69 | echo 'int bar(); int main() { return bar(); }' > $tmp/foo.c 70 | echo 'int bar() { return 42; }' > $tmp/bar.c 71 | $xcc -o $tmp/foo $tmp/foo.c $tmp/bar.c 72 | $tmp/foo 73 | [ "$?" = 42 ] 74 | check linker 75 | 76 | # a.out 77 | rm -f $tmp/a.out 78 | echo 'int main() {}' > $tmp/foo.c 79 | (cd $tmp; $OLDPWD/$xcc foo.c) 80 | [ -f $tmp/a.out ] 81 | check a.out 82 | 83 | # -E 84 | echo foo > $tmp/out 85 | echo "#include \"$tmp/out\"" | $xcc -E -xc - | grep -q foo 86 | check -E 87 | 88 | echo foo > $tmp/out1 89 | echo "#include \"$tmp/out1\"" | $xcc -E -o $tmp/out2 -xc - 90 | cat $tmp/out2 | grep -q foo 91 | check '-E and -o' 92 | 93 | # -I 94 | mkdir $tmp/dir 95 | echo foo > $tmp/dir/i-option-test 96 | echo "#include \"i-option-test\"" | $xcc -I$tmp/dir -E -xc - | grep -q foo 97 | check -I 98 | 99 | # -D 100 | echo foo | $xcc -Dfoo -E -xc - | grep -q 1 101 | check -D 102 | 103 | # -D 104 | echo foo | $xcc -Dfoo=bar -E -xc - | grep -q bar 105 | check -D 106 | 107 | # -U 108 | echo foo | $xcc -Dfoo=bar -Ufoo -E -xc - | grep -q foo 109 | check -U 110 | 111 | # ignored options 112 | $xcc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \ 113 | -fno-omit-frame-pointer -fno-stack-protector -fno-strict-aliasing \ 114 | -m64 -mno-red-zone -w -o /dev/null $tmp/empty.c 115 | check 'ignored options' 116 | 117 | # BOM marker 118 | printf '\xef\xbb\xbfxyz\n' | $xcc -E -o- -xc - | grep -q '^xyz' 119 | check 'BOM marker' 120 | 121 | # Inline functions 122 | echo 'inline void foo() {}' > $tmp/inline1.c 123 | echo 'inline void foo() {}' > $tmp/inline2.c 124 | echo 'int main() { return 0; }' > $tmp/inline3.c 125 | $xcc -o /dev/null $tmp/inline1.c $tmp/inline2.c $tmp/inline3.c 126 | check inline 127 | 128 | echo 'extern inline void foo() {}' > $tmp/inline1.c 129 | echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c 130 | $xcc -o /dev/null $tmp/inline1.c $tmp/inline2.c 131 | check inline 132 | 133 | echo 'static inline void f1() {}' | $xcc -o- -S -xc - | grep -v -q f1: 134 | check inline 135 | 136 | echo 'static inline void f1() {} void foo() { f1(); }' | $xcc -o- -S -xc - | grep -q f1: 137 | check inline 138 | 139 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $xcc -o- -S -xc - | grep -q f1: 140 | check inline 141 | 142 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $xcc -o- -S -xc - | grep -v -q f2: 143 | check inline 144 | 145 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $xcc -o- -S -xc - | grep -q f1: 146 | check inline 147 | 148 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $xcc -o- -S -xc - | grep -q f2: 149 | check inline 150 | 151 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $xcc -o- -S -xc - | grep -v -q f1: 152 | check inline 153 | 154 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $xcc -o- -S -xc - | grep -v -q f2: 155 | check inline 156 | 157 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $xcc -o- -S -xc - | grep -q f1: 158 | check inline 159 | 160 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $xcc -o- -S -xc - | grep -q f2: 161 | check inline 162 | 163 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $xcc -o- -S -xc - | grep -q f1: 164 | check inline 165 | 166 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $xcc -o- -S -xc - | grep -q f2: 167 | check inline 168 | 169 | # -idirafter 170 | mkdir -p $tmp/dir1 $tmp/dir2 171 | echo foo > $tmp/dir1/idirafter 172 | echo bar > $tmp/dir2/idirafter 173 | echo "#include \"idirafter\"" | $xcc -I$tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q foo 174 | check -idirafter 175 | echo "#include \"idirafter\"" | $xcc -idirafter $tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q bar 176 | check -idirafter 177 | 178 | # -fcommon 179 | echo 'int foo;' | $xcc -S -o- -xc - | grep -q '\.comm foo' 180 | check '-fcommon (default)' 181 | 182 | echo 'int foo;' | $xcc -fcommon -S -o- -xc - | grep -q '\.comm foo' 183 | check '-fcommon' 184 | 185 | # -fno-common 186 | echo 'int foo;' | $xcc -fno-common -S -o- -xc - | grep -q '^foo:' 187 | check '-fno-common' 188 | 189 | # -include 190 | echo foo > $tmp/out.h 191 | echo bar | $xcc -include $tmp/out.h -E -o- -xc - | grep -q -z 'foo.*bar' 192 | check -include 193 | echo NULL | $xcc -Iinclude -include stdio.h -E -o- -xc - | grep -q 0 194 | check -include 195 | 196 | # -x 197 | echo 'int x;' | $xcc -c -xc -o $tmp/foo.o - 198 | check -xc 199 | echo 'x:' | $xcc -c -x assembler -o $tmp/foo.o - 200 | check '-x assembler' 201 | 202 | echo 'int x;' > $tmp/foo.c 203 | $xcc -c -x assembler -x none -o $tmp/foo.o $tmp/foo.c 204 | check '-x none' 205 | 206 | # -E 207 | echo foo | $xcc -E - | grep -q foo 208 | check -E 209 | 210 | # .a file 211 | echo 'void foo() {}' | $xcc -c -xc -o $tmp/foo.o - 212 | echo 'void bar() {}' | $xcc -c -xc -o $tmp/bar.o - 213 | ar rcs $tmp/foo.a $tmp/foo.o $tmp/bar.o 214 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 215 | $xcc -o $tmp/foo $tmp/main.c $tmp/foo.a 216 | check '.a' 217 | 218 | # .so file 219 | echo 'void foo() {}' | cc -fPIC -c -xc -o $tmp/foo.o - 220 | echo 'void bar() {}' | cc -fPIC -c -xc -o $tmp/bar.o - 221 | cc -shared -o $tmp/foo.so $tmp/foo.o $tmp/bar.o 222 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 223 | $xcc -o $tmp/foo $tmp/main.c $tmp/foo.so 224 | check '.so' 225 | 226 | $xcc -hashmap-test 227 | check 'hashmap' 228 | 229 | # -M 230 | echo '#include "out2.h"' > $tmp/out.c 231 | echo '#include "out3.h"' >> $tmp/out.c 232 | touch $tmp/out2.h $tmp/out3.h 233 | $xcc -M -I$tmp $tmp/out.c | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' 234 | check -M 235 | 236 | # -MF 237 | $xcc -MF $tmp/mf -M -I$tmp $tmp/out.c 238 | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' $tmp/mf 239 | check -MF 240 | 241 | # -MP 242 | $xcc -MF $tmp/mp -MP -M -I$tmp $tmp/out.c 243 | grep -q '^.*/out2.h:' $tmp/mp 244 | check -MP 245 | grep -q '^.*/out3.h:' $tmp/mp 246 | check -MP 247 | 248 | # -MT 249 | $xcc -MT foo -M -I$tmp $tmp/out.c | grep -q '^foo:' 250 | check -MT 251 | $xcc -MT foo -MT bar -M -I$tmp $tmp/out.c | grep -q '^foo bar:' 252 | check -MT 253 | 254 | # -MD 255 | echo '#include "out2.h"' > $tmp/md2.c 256 | echo '#include "out3.h"' > $tmp/md3.c 257 | (cd $tmp; $OLDPWD/$xcc -c -MD -I. md2.c md3.c) 258 | grep -q -z '^md2.o:.* md2\.c .* ./out2\.h' $tmp/md2.d 259 | check -MD 260 | grep -q -z '^md3.o:.* md3\.c .* ./out3\.h' $tmp/md3.d 261 | check -MD 262 | 263 | $xcc -c -MD -MF $tmp/md-mf.d -I. $tmp/md2.c 264 | grep -q -z '^md2.o:.*md2\.c .*/out2\.h' $tmp/md-mf.d 265 | check -MD 266 | 267 | echo 'extern int bar; int foo() { return bar; }' | $xcc -fPIC -xc -c -o $tmp/foo.o - 268 | cc -shared -o $tmp/foo.so $tmp/foo.o 269 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/main.c 270 | $xcc -o $tmp/foo $tmp/main.c $tmp/foo.so 271 | check -fPIC 272 | 273 | # #include_next 274 | mkdir -p $tmp/next1 $tmp/next2 $tmp/next3 275 | echo '#include "file1.h"' > $tmp/file.c 276 | echo '#include_next "file1.h"' > $tmp/next1/file1.h 277 | echo '#include_next "file2.h"' > $tmp/next2/file1.h 278 | echo 'foo' > $tmp/next3/file2.h 279 | $xcc -I$tmp/next1 -I$tmp/next2 -I$tmp/next3 -E $tmp/file.c | grep -q foo 280 | check '#include_next' 281 | 282 | # -static 283 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 284 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 285 | $xcc -static -o $tmp/foo $tmp/foo.c $tmp/bar.c 286 | check -static 287 | file $tmp/foo | grep -q 'statically linked' 288 | check -static 289 | 290 | # -shared 291 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 292 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 293 | $xcc -fPIC -shared -o $tmp/foo.so $tmp/foo.c $tmp/bar.c 294 | check -shared 295 | 296 | # -L 297 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 298 | $xcc -fPIC -shared -o $tmp/libfoobar.so $tmp/foo.c 299 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 300 | $xcc -o $tmp/foo $tmp/bar.c -L$tmp -lfoobar 301 | check -L 302 | 303 | # -Wl, 304 | echo 'int foo() {}' | $xcc -c -o $tmp/foo.o -xc - 305 | echo 'int foo() {}' | $xcc -c -o $tmp/bar.o -xc - 306 | echo 'int main() {}' | $xcc -c -o $tmp/baz.o -xc - 307 | cc -Wl,-z,muldefs,--gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 308 | check -Wl, 309 | 310 | # -Xlinker 311 | echo 'int foo() {}' | $xcc -c -o $tmp/foo.o -xc - 312 | echo 'int foo() {}' | $xcc -c -o $tmp/bar.o -xc - 313 | echo 'int main() {}' | $xcc -c -o $tmp/baz.o -xc - 314 | cc -Xlinker -z -Xlinker muldefs -Xlinker --gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 315 | check -Xlinker 316 | 317 | # -soname 318 | echo 'int main() { return 0; }' | $xcc -c -o $tmp/foo.o -xc - 319 | $xcc -shared -soname libfoo.so.0 -o $tmp/libfoo.so $tmp/foo.o 320 | check -soname 321 | 322 | echo OK 323 | -------------------------------------------------------------------------------- /test/initializer.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | char g3 = 3; 4 | short g4 = 4; 5 | int g5 = 5; 6 | long g6 = 6; 7 | int g9[3] = {0, 1, 2}; 8 | struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}}; 9 | struct {int a[2];} g12[2] = {{{1, 2}}}; 10 | union { int a; char b[8]; } g13[2] = {0x01020304, 0x05060708}; 11 | char g17[] = "foobar"; 12 | char g18[10] = "foobar"; 13 | char g19[3] = "foobar"; 14 | char *g20 = g17+0; 15 | char *g21 = g17+3; 16 | char *g22 = &g17-3; 17 | char *g23[] = {g17+0, g17+3, g17-3}; 18 | int g24=3; 19 | int *g25=&g24; 20 | int g26[3] = {1, 2, 3}; 21 | int *g27 = g26 + 1; 22 | int *g28 = &g11[1].a; 23 | long g29 = (long)(long)g26; 24 | struct { struct { int a[3]; } a; } g30 = {{{1,2,3}}}; 25 | int *g31=g30.a.a; 26 | struct {int a[2];} g40[2] = {{1, 2}, 3, 4}; 27 | struct {int a[2];} g41[2] = {1, 2, 3, 4}; 28 | char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; 29 | char *g44 = {"foo"}; 30 | union { int a; char b[4]; } g50 = {.b[2]=0x12}; 31 | union { int a; } g51[2] = {}; 32 | 33 | typedef char T60[]; 34 | T60 g60 = {1, 2, 3}; 35 | T60 g61 = {1, 2, 3, 4, 5, 6}; 36 | 37 | typedef struct { char a, b[]; } T65; 38 | T65 g65 = {'f','o','o',0}; 39 | T65 g66 = {'f','o','o','b','a','r',0}; 40 | 41 | int main() { 42 | ASSERT(1, ({ int x[3]={1,2,3}; x[0]; })); 43 | ASSERT(2, ({ int x[3]={1,2,3}; x[1]; })); 44 | ASSERT(3, ({ int x[3]={1,2,3}; x[2]; })); 45 | ASSERT(3, ({ int x[3]={1,2,3}; x[2]; })); 46 | 47 | ASSERT(2, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[0][1]; })); 48 | ASSERT(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; })); 49 | ASSERT(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; })); 50 | 51 | ASSERT(0, ({ int x[3]={}; x[0]; })); 52 | ASSERT(0, ({ int x[3]={}; x[1]; })); 53 | ASSERT(0, ({ int x[3]={}; x[2]; })); 54 | 55 | ASSERT(2, ({ int x[2][3]={{1,2}}; x[0][1]; })); 56 | ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][0]; })); 57 | ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][2]; })); 58 | 59 | ASSERT('a', ({ char x[4]="abc"; x[0]; })); 60 | ASSERT('c', ({ char x[4]="abc"; x[2]; })); 61 | ASSERT(0, ({ char x[4]="abc"; x[3]; })); 62 | ASSERT('a', ({ char x[2][4]={"abc","def"}; x[0][0]; })); 63 | ASSERT(0, ({ char x[2][4]={"abc","def"}; x[0][3]; })); 64 | ASSERT('d', ({ char x[2][4]={"abc","def"}; x[1][0]; })); 65 | ASSERT('f', ({ char x[2][4]={"abc","def"}; x[1][2]; })); 66 | 67 | ASSERT(4, ({ int x[]={1,2,3,4}; x[3]; })); 68 | ASSERT(16, ({ int x[]={1,2,3,4}; sizeof(x); })); 69 | ASSERT(4, ({ char x[]="foo"; sizeof(x); })); 70 | 71 | ASSERT(4, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(x); })); 72 | ASSERT(2, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(y); })); 73 | ASSERT(2, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(x); })); 74 | ASSERT(4, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(y); })); 75 | 76 | ASSERT(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; })); 77 | ASSERT(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; })); 78 | ASSERT(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; })); 79 | ASSERT(1, ({ struct {int a; int b; int c;} x={1}; x.a; })); 80 | ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.b; })); 81 | ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.c; })); 82 | 83 | ASSERT(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; })); 84 | ASSERT(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; })); 85 | ASSERT(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; })); 86 | ASSERT(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; })); 87 | 88 | ASSERT(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; })); 89 | 90 | ASSERT(0, ({ struct {int a; int b;} x={}; x.a; })); 91 | ASSERT(0, ({ struct {int a; int b;} x={}; x.b; })); 92 | 93 | ASSERT(5, ({ typedef struct {int a,b,c,d,e,f;} T; T x={1,2,3,4,5,6}; T y; y=x; y.e; })); 94 | ASSERT(2, ({ typedef struct {int a,b;} T; T x={1,2}; T y, z; z=y=x; z.b; })); 95 | 96 | ASSERT(1, ({ typedef struct {int a,b;} T; T x={1,2}; T y=x; y.a; })); 97 | 98 | ASSERT(4, ({ union { int a; char b[4]; } x={0x01020304}; x.b[0]; })); 99 | ASSERT(3, ({ union { int a; char b[4]; } x={0x01020304}; x.b[1]; })); 100 | 101 | ASSERT(0x01020304, ({ union { struct { char a,b,c,d; } e; int f; } x={{4,3,2,1}}; x.f; })); 102 | 103 | ASSERT(3, g3); 104 | ASSERT(4, g4); 105 | ASSERT(5, g5); 106 | ASSERT(6, g6); 107 | 108 | ASSERT(0, g9[0]); 109 | ASSERT(1, g9[1]); 110 | ASSERT(2, g9[2]); 111 | 112 | ASSERT(1, g11[0].a); 113 | ASSERT(2, g11[0].b); 114 | ASSERT(3, g11[1].a); 115 | ASSERT(4, g11[1].b); 116 | 117 | ASSERT(1, g12[0].a[0]); 118 | ASSERT(2, g12[0].a[1]); 119 | ASSERT(0, g12[1].a[0]); 120 | ASSERT(0, g12[1].a[1]); 121 | 122 | ASSERT(4, g13[0].b[0]); 123 | ASSERT(3, g13[0].b[1]); 124 | ASSERT(8, g13[1].b[0]); 125 | ASSERT(7, g13[1].b[1]); 126 | 127 | ASSERT(7, sizeof(g17)); 128 | ASSERT(10, sizeof(g18)); 129 | ASSERT(3, sizeof(g19)); 130 | 131 | ASSERT(0, memcmp(g17, "foobar", 7)); 132 | ASSERT(0, memcmp(g18, "foobar\0\0\0", 10)); 133 | ASSERT(0, memcmp(g19, "foo", 3)); 134 | 135 | ASSERT(0, strcmp(g20, "foobar")); 136 | ASSERT(0, strcmp(g21, "bar")); 137 | ASSERT(0, strcmp(g22+3, "foobar")); 138 | 139 | ASSERT(0, strcmp(g23[0], "foobar")); 140 | ASSERT(0, strcmp(g23[1], "bar")); 141 | ASSERT(0, strcmp(g23[2]+3, "foobar")); 142 | 143 | ASSERT(3, g24); 144 | ASSERT(3, *g25); 145 | ASSERT(2, *g27); 146 | ASSERT(3, *g28); 147 | ASSERT(1, *(int *)g29); 148 | 149 | ASSERT(1, g31[0]); 150 | ASSERT(2, g31[1]); 151 | ASSERT(3, g31[2]); 152 | 153 | ASSERT(1, g40[0].a[0]); 154 | ASSERT(2, g40[0].a[1]); 155 | ASSERT(3, g40[1].a[0]); 156 | ASSERT(4, g40[1].a[1]); 157 | 158 | ASSERT(1, g41[0].a[0]); 159 | ASSERT(2, g41[0].a[1]); 160 | ASSERT(3, g41[1].a[0]); 161 | ASSERT(4, g41[1].a[1]); 162 | 163 | ASSERT(0, ({ int x[2][3]={0,1,2,3,4,5}; x[0][0]; })); 164 | ASSERT(3, ({ int x[2][3]={0,1,2,3,4,5}; x[1][0]; })); 165 | 166 | ASSERT(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; })); 167 | ASSERT(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; })); 168 | 169 | ASSERT(0, strcmp(g43[0], "foo")); 170 | ASSERT(0, strcmp(g43[1], "bar")); 171 | ASSERT(0, strcmp(g44, "foo")); 172 | 173 | ASSERT(3, ({ int a[]={1,2,3,}; a[2]; })); 174 | ASSERT(1, ({ struct {int a,b,c;} x={1,2,3,}; x.a; })); 175 | ASSERT(1, ({ union {int a; char b;} x={1,}; x.a; })); 176 | ASSERT(2, ({ enum {x,y,z,}; z; })); 177 | 178 | ASSERT(3, sizeof(g60)); 179 | ASSERT(6, sizeof(g61)); 180 | 181 | ASSERT(4, sizeof(g65)); 182 | ASSERT(7, sizeof(g66)); 183 | ASSERT(0, strcmp(g65.b, "oo")); 184 | ASSERT(0, strcmp(g66.b, "oobar")); 185 | 186 | ASSERT(4, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[0]; })); 187 | ASSERT(5, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[1]; })); 188 | ASSERT(3, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[2]; })); 189 | 190 | ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][0]; })); 191 | ASSERT(11, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][1]; })); 192 | ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][2]; })); 193 | ASSERT(12, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][0]; })); 194 | ASSERT(5, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][1]; })); 195 | ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][2]; })); 196 | 197 | ASSERT(7, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][0]; })); 198 | ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][1]; })); 199 | ASSERT(3, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][2]; })); 200 | ASSERT(9, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][0]; })); 201 | ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][1]; })); 202 | ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][2]; })); 203 | 204 | ASSERT(7, ((int[10]){ [3]=7 })[3]); 205 | ASSERT(0, ((int[10]){ [3]=7 })[4]); 206 | 207 | ASSERT(10, ({ char x[]={[10-3]=1,2,3}; sizeof(x); })); 208 | ASSERT(20, ({ char x[][2]={[8][1]=1,2}; sizeof(x); })); 209 | 210 | ASSERT(3, sizeof(g60)); 211 | ASSERT(6, sizeof(g61)); 212 | 213 | ASSERT(4, sizeof(g65)); 214 | ASSERT(7, sizeof(g66)); 215 | ASSERT(0, strcmp(g65.b, "oo")); 216 | ASSERT(0, strcmp(g66.b, "oobar")); 217 | 218 | ASSERT(7, ((int[10]){ [3] 7 })[3]); 219 | ASSERT(0, ((int[10]){ [3] 7 })[4]); 220 | 221 | ASSERT(4, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.a; })); 222 | ASSERT(3, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.b; })); 223 | 224 | ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.a; })); 225 | ASSERT(2, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.b; })); 226 | 227 | ASSERT(0, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.a; })); 228 | ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.b; })); 229 | 230 | ASSERT(1, ({ struct { int a[2]; } x={.a=1,2}; x.a[0]; })); 231 | ASSERT(2, ({ struct { int a[2]; } x={.a=1,2}; x.a[1]; })); 232 | 233 | ASSERT(0, ({ struct { int a[2]; } x={.a[1]=1}; x.a[0]; })); 234 | ASSERT(1, ({ struct { int a[2]; } x={.a[1]=1}; x.a[1]; })); 235 | 236 | ASSERT(3, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].a; })); 237 | ASSERT(4, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].b; })); 238 | ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].a; })); 239 | ASSERT(1, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].b; })); 240 | ASSERT(2, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].a; })); 241 | ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].b; })); 242 | 243 | ASSERT(1, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].a; })); 244 | ASSERT(2, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].b; })); 245 | ASSERT(0, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].a; })); 246 | ASSERT(3, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].b; })); 247 | 248 | ASSERT(5, ((struct { int a,b,c; }){ .c=5 }).c); 249 | ASSERT(0, ((struct { int a,b,c; }){ .c=5 }).a); 250 | 251 | ASSERT(0x00ff, ({ union { unsigned short a; char b[2]; } x={.b[0]=0xff}; x.a; })); 252 | ASSERT(0xff00, ({ union { unsigned short a; char b[2]; } x={.b[1]=0xff}; x.a; })); 253 | 254 | ASSERT(0x00120000, g50.a); 255 | ASSERT(0, g51[0].a); 256 | ASSERT(0, g51[1].a); 257 | 258 | ASSERT(1, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.a; })); 259 | ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; })); 260 | ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; })); 261 | 262 | ASSERT(16, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; sizeof(x); })); 263 | ASSERT(0, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); })); 264 | 265 | printf("OK\n"); 266 | return 0; 267 | } 268 | -------------------------------------------------------------------------------- /test/function.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int ret3(void) { 4 | return 3; 5 | return 5; 6 | } 7 | 8 | int add2(int x, int y) { 9 | return x + y; 10 | } 11 | 12 | int sub2(int x, int y) { 13 | return x - y; 14 | } 15 | 16 | int add6(int a, int b, int c, int d, int e, int f) { 17 | return a + b + c + d + e + f; 18 | } 19 | 20 | int addx(int *x, int y) { 21 | return *x + y; 22 | } 23 | 24 | int sub_char(char a, char b, char c) { 25 | return a - b - c; 26 | } 27 | 28 | int fib(int x) { 29 | if (x<=1) 30 | return 1; 31 | return fib(x-1) + fib(x-2); 32 | } 33 | 34 | int sub_long(long a, long b, long c) { 35 | return a - b - c; 36 | } 37 | 38 | int sub_short(short a, short b, short c) { 39 | return a - b - c; 40 | } 41 | 42 | int g1; 43 | 44 | int *g1_ptr(void) { return &g1; } 45 | char int_to_char(int x) { return x; } 46 | 47 | int div_long(long a, long b) { 48 | return a / b; 49 | } 50 | 51 | _Bool bool_fn_add(_Bool x) { return x + 1; } 52 | _Bool bool_fn_sub(_Bool x) { return x - 1; } 53 | 54 | static int static_fn(void) { return 3; } 55 | 56 | int param_decay(int x[]) { return x[0]; } 57 | 58 | int counter() { 59 | static int i; 60 | static int j = 1+1; 61 | return i++ + j++; 62 | } 63 | 64 | void ret_none() { 65 | return; 66 | } 67 | 68 | _Bool true_fn(); 69 | _Bool false_fn(); 70 | char char_fn(); 71 | short short_fn(); 72 | 73 | unsigned char uchar_fn(); 74 | unsigned short ushort_fn(); 75 | 76 | char schar_fn(); 77 | short sshort_fn(); 78 | 79 | int add_all(int n, ...); 80 | 81 | typedef struct { 82 | int gp_offset; 83 | int fp_offset; 84 | void *overflow_arg_area; 85 | void *reg_save_area; 86 | } __va_elem; 87 | 88 | typedef __va_elem va_list[1]; 89 | 90 | int add_all(int n, ...); 91 | int sprintf(char *buf, char *fmt, ...); 92 | int vsprintf(char *buf, char *fmt, va_list ap); 93 | 94 | char *fmt(char *buf, char *fmt, ...) { 95 | va_list ap; 96 | *ap = *(__va_elem *)__va_area__; 97 | vsprintf(buf, fmt, ap); 98 | } 99 | 100 | double add_double(double x, double y); 101 | float add_float(float x, float y); 102 | 103 | float add_float3(float x, float y, float z) { 104 | return x + y + z; 105 | } 106 | 107 | double add_double3(double x, double y, double z) { 108 | return x + y + z; 109 | } 110 | 111 | int (*fnptr(int (*fn)(int n, ...)))(int, ...) { 112 | return fn; 113 | } 114 | 115 | int param_decay2(int x()) { return x(); } 116 | 117 | char *func_fn(void) { 118 | return __func__; 119 | } 120 | 121 | char *function_fn(void) { 122 | return __FUNCTION__; 123 | } 124 | 125 | int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10); 126 | float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10); 127 | double add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10); 128 | 129 | int many_args1(int a, int b, int c, int d, int e, int f, int g, int h) { 130 | return g / h; 131 | } 132 | 133 | double many_args2(double a, double b, double c, double d, double e, 134 | double f, double g, double h, double i, double j) { 135 | return i / j; 136 | } 137 | 138 | int many_args3(int a, double b, int c, int d, double e, int f, 139 | double g, int h, double i, double j, double k, 140 | double l, double m, int n, int o, double p) { 141 | return o / p; 142 | } 143 | 144 | typedef struct { int a,b; short c; char d; } Ty4; 145 | typedef struct { int a; float b; double c; } Ty5; 146 | typedef struct { unsigned char a[3]; } Ty6; 147 | typedef struct { long a, b, c; } Ty7; 148 | 149 | int struct_test5(Ty5 x, int n); 150 | int struct_test4(Ty4 x, int n); 151 | int struct_test6(Ty6 x, int n); 152 | int struct_test7(Ty7 x, int n); 153 | 154 | int struct_test14(Ty4 x, int n) { 155 | switch (n) { 156 | case 0: return x.a; 157 | case 1: return x.b; 158 | case 2: return x.c; 159 | default: return x.d; 160 | } 161 | } 162 | 163 | int struct_test15(Ty5 x, int n) { 164 | switch (n) { 165 | case 0: return x.a; 166 | case 1: return x.b; 167 | default: return x.c; 168 | } 169 | } 170 | 171 | typedef struct { unsigned char a[10]; } Ty20; 172 | typedef struct { unsigned char a[20]; } Ty21; 173 | 174 | Ty4 struct_test24(void); 175 | Ty5 struct_test25(void); 176 | Ty6 struct_test26(void); 177 | Ty20 struct_test27(void); 178 | Ty21 struct_test28(void); 179 | 180 | Ty4 struct_test34(void) { 181 | return (Ty4){10, 20, 30, 40}; 182 | } 183 | 184 | Ty5 struct_test35(void) { 185 | return (Ty5){10, 20, 30}; 186 | } 187 | 188 | Ty6 struct_test36(void) { 189 | return (Ty6){10, 20, 30}; 190 | } 191 | 192 | Ty20 struct_test37(void) { 193 | return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; 194 | } 195 | 196 | Ty21 struct_test38(void) { 197 | return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; 198 | } 199 | 200 | inline int inline_fn(void) { 201 | return 3; 202 | } 203 | 204 | double to_double(long double x) { 205 | return x; 206 | } 207 | 208 | long double to_ldouble(int x) { 209 | return x; 210 | } 211 | 212 | int main() { 213 | ASSERT(3, ret3()); 214 | ASSERT(8, add2(3, 5)); 215 | ASSERT(2, sub2(5, 3)); 216 | ASSERT(21, add6(1,2,3,4,5,6)); 217 | ASSERT(66, add6(1,2,add6(3,4,5,6,7,8),9,10,11)); 218 | ASSERT(136, add6(1,2,add6(3,add6(4,5,6,7,8,9),10,11,12,13),14,15,16)); 219 | 220 | ASSERT(7, add2(3,4)); 221 | ASSERT(1, sub2(4,3)); 222 | ASSERT(55, fib(9)); 223 | 224 | ASSERT(1, ({ sub_char(7, 3, 3); })); 225 | 226 | ASSERT(1, sub_long(7, 3, 3)); 227 | ASSERT(1, sub_short(7, 3, 3)); 228 | 229 | g1 = 3; 230 | 231 | ASSERT(3, *g1_ptr()); 232 | ASSERT(5, int_to_char(261)); 233 | ASSERT(5, int_to_char(261)); 234 | ASSERT(-5, div_long(-10, 2)); 235 | 236 | ASSERT(1, bool_fn_add(3)); 237 | ASSERT(0, bool_fn_sub(3)); 238 | ASSERT(1, bool_fn_add(-3)); 239 | ASSERT(0, bool_fn_sub(-3)); 240 | ASSERT(1, bool_fn_add(0)); 241 | ASSERT(1, bool_fn_sub(0)); 242 | 243 | ASSERT(3, static_fn()); 244 | 245 | ASSERT(3, ({ int x[2]; x[0]=3; param_decay(x); })); 246 | 247 | ASSERT(2, counter()); 248 | ASSERT(4, counter()); 249 | ASSERT(6, counter()); 250 | 251 | ret_none(); 252 | 253 | ASSERT(1, true_fn()); 254 | ASSERT(0, false_fn()); 255 | ASSERT(3, char_fn()); 256 | ASSERT(5, short_fn()); 257 | 258 | ASSERT(6, add_all(3,1,2,3)); 259 | ASSERT(5, add_all(4,1,2,3,-1)); 260 | 261 | { char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); printf("%s\n", buf); } 262 | 263 | ASSERT(0, ({ char buf[100]; sprintf(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); })); 264 | 265 | ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d %s", 1, 2, "foo"); strcmp("1 2 foo", buf); })); 266 | 267 | ASSERT(251, uchar_fn()); 268 | ASSERT(65528, ushort_fn()); 269 | ASSERT(-5, schar_fn()); 270 | ASSERT(-8, sshort_fn()); 271 | 272 | ASSERT(6, add_float(2.3, 3.8)); 273 | ASSERT(6, add_double(2.3, 3.8)); 274 | 275 | ASSERT(7, add_float3(2.5, 2.5, 2.5)); 276 | ASSERT(7, add_double3(2.5, 2.5, 2.5)); 277 | 278 | ASSERT(0, ({ char buf[100]; sprintf(buf, "%.1f", (float)3.5); strcmp(buf, "3.5"); })); 279 | 280 | ASSERT(0, ({ char buf[100]; fmt(buf, "%.1f", (float)3.5); strcmp(buf, "3.5"); })); 281 | 282 | ASSERT(5, (add2)(2,3)); 283 | ASSERT(5, (&add2)(2,3)); 284 | ASSERT(7, ({ int (*fn)(int,int) = add2; fn(2,5); })); 285 | ASSERT(6, fnptr(add_all)(3, 1, 2, 3)); 286 | 287 | ASSERT(3, param_decay2(ret3)); 288 | 289 | ASSERT(5, sizeof(__func__)); 290 | ASSERT(0, strcmp("main", __func__)); 291 | ASSERT(0, strcmp("func_fn", func_fn())); 292 | ASSERT(0, strcmp("main", __FUNCTION__)); 293 | ASSERT(0, strcmp("function_fn", function_fn())); 294 | 295 | 296 | ASSERT(55, add10_int(1,2,3,4,5,6,7,8,9,10)); 297 | ASSERT(55, add10_float(1,2,3,4,5,6,7,8,9,10)); 298 | ASSERT(55, add10_double(1,2,3,4,5,6,7,8,9,10)); 299 | 300 | ASSERT(0, ({ char buf[200]; sprintf(buf, "%d %.1f %.1f %.1f %d %d %.1f %d %d %d %d %.1f %d %d %.1f %.1f %.1f %.1f %d", 1, 1.0, 1.0, 1.0, 1, 1, 1.0, 1, 1, 1, 1, 1.0, 1, 1, 1.0, 1.0, 1.0, 1.0, 1); strcmp("1 1.0 1.0 1.0 1 1 1.0 1 1 1 1 1.0 1 1 1.0 1.0 1.0 1.0 1", buf); })); 301 | 302 | ASSERT(4, many_args1(1,2,3,4,5,6,40,10)); 303 | ASSERT(4, many_args2(1,2,3,4,5,6,7,8,40,10)); 304 | ASSERT(8, many_args3(1,2,3,4,5,6,7,8,9,10,11,12,13,14,80,10)); 305 | 306 | ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test4(x, 0); })); 307 | ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test4(x, 1); })); 308 | ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test4(x, 2); })); 309 | ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test4(x, 3); })); 310 | 311 | ASSERT(10, ({ Ty5 x={10,20,30}; struct_test5(x, 0); })); 312 | ASSERT(20, ({ Ty5 x={10,20,30}; struct_test5(x, 1); })); 313 | ASSERT(30, ({ Ty5 x={10,20,30}; struct_test5(x, 2); })); 314 | 315 | ASSERT(10, ({ Ty6 x={10,20,30}; struct_test6(x, 0); })); 316 | ASSERT(20, ({ Ty6 x={10,20,30}; struct_test6(x, 1); })); 317 | ASSERT(30, ({ Ty6 x={10,20,30}; struct_test6(x, 2); })); 318 | 319 | ASSERT(10, ({ Ty7 x={10,20,30}; struct_test7(x, 0); })); 320 | ASSERT(20, ({ Ty7 x={10,20,30}; struct_test7(x, 1); })); 321 | ASSERT(30, ({ Ty7 x={10,20,30}; struct_test7(x, 2); })); 322 | 323 | ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test14(x, 0); })); 324 | ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test14(x, 1); })); 325 | ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test14(x, 2); })); 326 | ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test14(x, 3); })); 327 | 328 | ASSERT(10, ({ Ty5 x={10,20,30}; struct_test15(x, 0); })); 329 | ASSERT(20, ({ Ty5 x={10,20,30}; struct_test15(x, 1); })); 330 | ASSERT(30, ({ Ty5 x={10,20,30}; struct_test15(x, 2); })); 331 | 332 | ASSERT(10, struct_test24().a); 333 | ASSERT(20, struct_test24().b); 334 | ASSERT(30, struct_test24().c); 335 | ASSERT(40, struct_test24().d); 336 | 337 | ASSERT(10, struct_test25().a); 338 | ASSERT(20, struct_test25().b); 339 | ASSERT(30, struct_test25().c); 340 | 341 | ASSERT(10, struct_test26().a[0]); 342 | ASSERT(20, struct_test26().a[1]); 343 | ASSERT(30, struct_test26().a[2]); 344 | 345 | ASSERT(10, struct_test27().a[0]); 346 | ASSERT(60, struct_test27().a[5]); 347 | ASSERT(100, struct_test27().a[9]); 348 | 349 | ASSERT(1, struct_test28().a[0]); 350 | ASSERT(5, struct_test28().a[4]); 351 | ASSERT(10, struct_test28().a[9]); 352 | ASSERT(15, struct_test28().a[14]); 353 | ASSERT(20, struct_test28().a[19]); 354 | 355 | ASSERT(10, struct_test34().a); 356 | ASSERT(20, struct_test34().b); 357 | ASSERT(30, struct_test34().c); 358 | ASSERT(40, struct_test34().d); 359 | 360 | ASSERT(10, struct_test35().a); 361 | ASSERT(20, struct_test35().b); 362 | ASSERT(30, struct_test35().c); 363 | 364 | ASSERT(10, struct_test36().a[0]); 365 | ASSERT(20, struct_test36().a[1]); 366 | ASSERT(30, struct_test36().a[2]); 367 | 368 | ASSERT(10, struct_test37().a[0]); 369 | ASSERT(60, struct_test37().a[5]); 370 | ASSERT(100, struct_test37().a[9]); 371 | 372 | ASSERT(1, struct_test38().a[0]); 373 | ASSERT(5, struct_test38().a[4]); 374 | ASSERT(10, struct_test38().a[9]); 375 | ASSERT(15, struct_test38().a[14]); 376 | ASSERT(20, struct_test38().a[19]); 377 | 378 | ASSERT(5, (***add2)(2,3)); 379 | 380 | ASSERT(3, inline_fn()); 381 | 382 | ASSERT(0, ({ char buf[100]; sprintf(buf, "%Lf", (long double)12.3); strncmp(buf, "12.3", 4); })); 383 | 384 | ASSERT(1, to_double(3.5) == 3.5); 385 | ASSERT(0, to_double(3.5) == 3); 386 | 387 | ASSERT(1, (long double)5.0 == (long double)5.0); 388 | ASSERT(0, (long double)5.0 == (long double)5.2); 389 | 390 | ASSERT(1, to_ldouble(5.0) == 5.0); 391 | ASSERT(0, to_ldouble(5.0) == 5.2); 392 | 393 | printf("OK\n"); 394 | } 395 | -------------------------------------------------------------------------------- /xcc.h: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809L 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifndef VERSION 22 | #define VERSION "0.1" 23 | #endif 24 | 25 | #define MAX(x, y) ((x) < (y) ? (y) : (x)) 26 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 27 | 28 | #ifndef __GNUC__ 29 | # define __attribute__(x) 30 | #endif 31 | 32 | typedef struct Type Type; 33 | typedef struct Node Node; 34 | typedef struct Member Member; 35 | typedef struct Relocation Relocation; 36 | typedef struct Hideset Hideset; 37 | 38 | // 39 | // strings.c 40 | // 41 | 42 | typedef struct { 43 | char **data; 44 | int capacity; 45 | int len; 46 | } StringArray; 47 | 48 | void strarray_push(StringArray *arr, char *s); 49 | char *format(char *fmt, ...) __attribute__((format(printf, 1, 2))); 50 | 51 | // 52 | // tokenize.c 53 | // 54 | 55 | // Token 56 | typedef enum { 57 | TK_IDENT, // Identifiers 58 | TK_PUNCT, // Punctuators 59 | TK_KEYWORD, // Keywords 60 | TK_STR, // String literals 61 | TK_NUM, // Numeric literals 62 | TK_PP_NUM, // Preprocessing numbers 63 | TK_EOF, // End-of-file markers 64 | } TokenKind; 65 | 66 | typedef struct { 67 | char *name; 68 | unsigned file_no; 69 | char *contents; 70 | 71 | // For #line directive 72 | char *display_name; 73 | int line_delta; 74 | } File; 75 | 76 | // Token type 77 | typedef struct Token Token; 78 | struct Token { 79 | TokenKind kind; // Token kind 80 | Token *next; // Next token 81 | int64_t val; // If kind is TK_NUM, its value 82 | long double fval; // If kind is TK_NUM, its value 83 | char *loc; // Token location 84 | int len; // Token length 85 | Type *ty; // Used if TK_NUM or TK_STR 86 | char *str; // String literal contents including terminating '\0' 87 | 88 | File *file; // Source location 89 | char *filename; // Filename 90 | unsigned line_no; // Line number 91 | int line_delta; // Line number 92 | bool at_bol; // True if this token is at beginning of line 93 | bool has_space; // True if this token follows a space character 94 | Hideset *hideset; // For macro expansion 95 | Token *origin; // If this is expanded from a macro, the original token 96 | }; 97 | 98 | noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2))); 99 | noreturn void error_at(char *loc, char *fmt, ...) __attribute__((format(printf, 2, 3))); 100 | noreturn void error_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3))); 101 | void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3))); 102 | bool equal(Token *tok, char *op); 103 | Token *skip(Token *tok, char *op); 104 | bool consume(Token **rest, Token *tok, char *str); 105 | void convert_pp_tokens(Token *tok); 106 | File **get_input_files(void); 107 | File *new_file(char *name, unsigned file_no, char *contents); 108 | Token *tokenize_string_literal(Token *tok, Type *basety); 109 | Token *tokenize(File *file); 110 | Token *tokenize_file(char *filename); 111 | 112 | #define unreachable() \ 113 | error("internal error at %s:%u", __FILE__, __LINE__) 114 | 115 | // 116 | // preprocess.c 117 | // 118 | 119 | char *search_include_paths(char *filename); 120 | void init_macros(void); 121 | void define_macro(char *name, char *buf); 122 | void undef_macro(char *name); 123 | Token *preprocess(Token *tok); 124 | 125 | // 126 | // parse.c 127 | // 128 | 129 | // Variable or function 130 | typedef struct Obj Obj; 131 | struct Obj { 132 | Obj *next; 133 | char *name; // Variable name 134 | Type *ty; // Type 135 | Token *tok; // representative token 136 | bool is_local; // local or global/function 137 | int align; // alignment 138 | 139 | // Local variable 140 | int offset; 141 | 142 | // Global variable or function 143 | bool is_function; 144 | bool is_definition; 145 | bool is_static; 146 | 147 | // Global variable 148 | bool is_tentative; 149 | bool is_tls; 150 | char *init_data; 151 | Relocation *rel; 152 | 153 | // Function 154 | bool is_inline; 155 | Obj *params; 156 | Node *body; 157 | Obj *locals; 158 | Obj *va_area; 159 | Obj *alloca_bottom; 160 | int stack_size; 161 | 162 | // Static inline function 163 | bool is_live; 164 | bool is_root; 165 | StringArray refs; 166 | }; 167 | 168 | // Global variable can be initialized either by a constant expression 169 | // or a pointer to another global variable. This struct represents the 170 | // latter. 171 | typedef struct Relocation Relocation; 172 | struct Relocation { 173 | Relocation *next; 174 | int offset; 175 | char **label; 176 | long addend; 177 | }; 178 | 179 | // AST node 180 | typedef enum { 181 | ND_NULL_EXPR, // Do nothing 182 | ND_ADD, // + 183 | ND_SUB, // - 184 | ND_MUL, // * 185 | ND_DIV, // / 186 | ND_NEG, // unary - 187 | ND_MOD, // % 188 | ND_BITAND, // & 189 | ND_BITOR, // | 190 | ND_BITXOR, // ^ 191 | ND_SHL, // << 192 | ND_SHR, // >> 193 | ND_EQ, // == 194 | ND_NE, // != 195 | ND_LT, // < 196 | ND_LE, // <= 197 | ND_ASSIGN, // = 198 | ND_COND, // ?: 199 | ND_COMMA, // , 200 | ND_MEMBER, // . (struct member access) 201 | ND_ADDR, // unary & 202 | ND_DEREF, // unary * 203 | ND_NOT, // ! 204 | ND_BITNOT, // ~ 205 | ND_LOGAND, // && 206 | ND_LOGOR, // || 207 | ND_RETURN, // "return" 208 | ND_IF, // "if" 209 | ND_FOR, // "for" or "while" 210 | ND_DO, // "do" 211 | ND_SWITCH, // "switch" 212 | ND_CASE, // "case" 213 | ND_BLOCK, // { ... } 214 | ND_GOTO, // "goto" 215 | ND_GOTO_EXPR, // "goto" labels-as-values 216 | ND_LABEL, // Labeled statement 217 | ND_LABEL_VAL, // [GNU] Labels-as-values 218 | ND_FUNCALL, // Function call 219 | ND_EXPR_STMT, // Expression statement 220 | ND_STMT_EXPR, // Statement expression 221 | ND_VAR, // Variable 222 | ND_VLA_PTR, // VLA designator 223 | ND_NUM, // Integer 224 | ND_CAST, // Type cast 225 | ND_MEMZERO, // Zero-clear a stack variable 226 | ND_ASM, // "asm" 227 | ND_CAS, // Atomic compare-and-swap 228 | ND_EXCH, // Atomic exchange 229 | } NodeKind; 230 | 231 | // AST node type 232 | struct Node { 233 | NodeKind kind; // Node kind 234 | Node *next; // Next node 235 | Type *ty; // Type, e.g. int or pointer to int 236 | Token *tok; // Representative token 237 | 238 | Node *lhs; // Left-hand side 239 | Node *rhs; // Right-hand side 240 | 241 | // "if" or "for" statement 242 | Node *cond; 243 | Node *then; 244 | Node *els; 245 | Node *init; 246 | Node *inc; 247 | 248 | // "break" and "continue" labels 249 | char *brk_label; 250 | char *cont_label; 251 | 252 | // Block or statement expression 253 | Node *body; 254 | 255 | // Struct member access 256 | Member *member; 257 | 258 | // Function call 259 | Type *func_ty; 260 | Node *args; 261 | bool pass_by_stack; 262 | Obj *ret_buffer; 263 | 264 | // Goto or labeled statement, or labels-as-values 265 | char *label; 266 | char *unique_label; 267 | Node *goto_next; 268 | 269 | // Switch 270 | Node *case_next; 271 | Node *default_case; 272 | 273 | // Case 274 | long begin; 275 | long end; 276 | 277 | // "asm" string literal 278 | char *asm_str; 279 | 280 | // Atomic compare-and-swap 281 | Node *cas_addr; 282 | Node *cas_old; 283 | Node *cas_new; 284 | 285 | // Atomic op= operators 286 | Obj *atomic_addr; 287 | Node *atomic_expr; 288 | 289 | // Variable 290 | Obj *var; 291 | 292 | // Numeric literal 293 | int64_t val; 294 | long double fval; 295 | }; 296 | 297 | Node *new_cast(Node *expr, Type *ty); 298 | int64_t const_expr(Token **rest, Token *tok); 299 | Obj *parse(Token *tok); 300 | 301 | // 302 | // type.c 303 | // 304 | 305 | typedef enum { 306 | TY_VOID, 307 | TY_BOOL, 308 | TY_CHAR, 309 | TY_SHORT, 310 | TY_INT, 311 | TY_LONG, 312 | TY_FLOAT, 313 | TY_DOUBLE, 314 | TY_LDOUBLE, 315 | TY_ENUM, 316 | TY_PTR, 317 | TY_FUNC, 318 | TY_ARRAY, 319 | TY_VLA, // variable-length array 320 | TY_STRUCT, 321 | TY_UNION, 322 | } TypeKind; 323 | 324 | struct Type { 325 | TypeKind kind; 326 | int size; // sizeof() value 327 | int align; // alignment 328 | bool is_unsigned; // unsigned or signed 329 | bool is_atomic; // true if _Atomic 330 | Type *origin; // for type compatibility check 331 | 332 | // Pointer-to or array-of type. We intentionally use the same member 333 | // to represent pointer/array duality in C. 334 | // 335 | // In many contexts in which a pointer is expected, we examine this 336 | // member instead of "kind" member to determine whether a type is a 337 | // pointer or not. That means in many contexts "array of T" is 338 | // naturally handled as if it were "pointer to T", as required by 339 | // the C spec. 340 | Type *base; 341 | 342 | // Declaration 343 | Token *name; 344 | Token *name_pos; 345 | 346 | // Array 347 | int array_len; 348 | 349 | // Variable-length array 350 | Node *vla_len; // # of elements 351 | Obj *vla_size; // sizeof() value 352 | 353 | // Struct 354 | Member *members; 355 | bool is_flexible; 356 | bool is_packed; 357 | 358 | // Function type 359 | Type *return_ty; 360 | Type *params; 361 | bool is_variadic; 362 | Type *next; 363 | }; 364 | 365 | // Struct member 366 | struct Member { 367 | Member *next; 368 | Type *ty; 369 | Token *tok; // for error message 370 | Token *name; 371 | int idx; 372 | int align; 373 | int offset; 374 | 375 | // Bitfield 376 | bool is_bitfield; 377 | int bit_offset; 378 | int bit_width; 379 | }; 380 | 381 | extern Type *ty_void; 382 | extern Type *ty_bool; 383 | 384 | extern Type *ty_char; 385 | extern Type *ty_short; 386 | extern Type *ty_int; 387 | extern Type *ty_long; 388 | 389 | extern Type *ty_uchar; 390 | extern Type *ty_ushort; 391 | extern Type *ty_uint; 392 | extern Type *ty_ulong; 393 | 394 | extern Type *ty_float; 395 | extern Type *ty_double; 396 | extern Type *ty_ldouble; 397 | 398 | bool is_integer(Type *ty); 399 | bool is_flonum(Type *ty); 400 | bool is_numeric(Type *ty); 401 | bool is_compatible(Type *t1, Type *t2); 402 | Type *copy_type(Type *ty); 403 | Type *pointer_to(Type *base); 404 | Type *func_type(Type *return_ty); 405 | Type *array_of(Type *base, int size); 406 | Type *vla_of(Type *base, Node *expr); 407 | Type *enum_type(void); 408 | Type *struct_type(void); 409 | void add_type(Node *node); 410 | 411 | // 412 | // codegen.c 413 | // 414 | 415 | void codegen(Obj *prog, FILE *out); 416 | int align_to(int n, int align); 417 | 418 | // 419 | // unicode.c 420 | // 421 | 422 | int encode_utf8(char *buf, uint32_t c); 423 | uint32_t decode_utf8(char **new_pos, char *p); 424 | bool is_ident1(uint32_t c); 425 | bool is_ident2(uint32_t c); 426 | int display_width(char *p, int len); 427 | 428 | // 429 | // hashmap.c 430 | // 431 | 432 | typedef struct { 433 | char *key; 434 | int keylen; 435 | void *val; 436 | } HashEntry; 437 | 438 | typedef struct { 439 | HashEntry *buckets; 440 | int capacity; 441 | int used; 442 | } HashMap; 443 | 444 | void *hashmap_get(HashMap *map, char *key); 445 | void *hashmap_get2(HashMap *map, char *key, int keylen); 446 | void hashmap_put(HashMap *map, char *key, void *val); 447 | void hashmap_put2(HashMap *map, char *key, int keylen, void *val); 448 | void hashmap_delete(HashMap *map, char *key); 449 | void hashmap_delete2(HashMap *map, char *key, int keylen); 450 | void hashmap_test(void); 451 | 452 | // 453 | // main.c 454 | // 455 | 456 | bool file_exists(char *path); 457 | 458 | extern StringArray include_paths; 459 | extern int opt_O; 460 | extern bool opt_asm; 461 | extern bool opt_fpic; 462 | extern bool opt_fcommon; 463 | extern char *base_file; 464 | -------------------------------------------------------------------------------- /tokenize.c: -------------------------------------------------------------------------------- 1 | #include "xcc.h" 2 | 3 | // Input file 4 | static File *current_file; 5 | 6 | // A list of all input files. 7 | static File **input_files; 8 | 9 | // True if the current position is at the beginning of a line 10 | static bool at_bol; 11 | 12 | // True if the current position follows a space character 13 | static bool has_space; 14 | 15 | // Reports an error and exit. 16 | void error(char *fmt, ...) { 17 | va_list ap; 18 | va_start(ap, fmt); 19 | vfprintf(stderr, fmt, ap); 20 | fprintf(stderr, "\n"); 21 | exit(1); 22 | } 23 | 24 | // Reports an error message in the following format. 25 | // 26 | // foo.c:10: x = y + 1; 27 | // ^ 28 | static void verror_at(char *filename, char *input, unsigned line_no, 29 | char *loc, char *fmt, va_list ap) { 30 | // Find a line containing `loc`. 31 | char *line = loc; 32 | while (input < line && line[-1] != '\n') 33 | line--; 34 | 35 | char *end = loc; 36 | while (*end && *end != '\n') 37 | end++; 38 | 39 | // Print out the line. 40 | int indent = fprintf(stderr, "%s:%u: ", filename, line_no); 41 | fprintf(stderr, "%.*s\n", (int)(end - line), line); 42 | 43 | // Show the error message. 44 | int pos = display_width(line, loc - line) + indent; 45 | 46 | fprintf(stderr, "%*s", pos, ""); // print pos spaces. 47 | fprintf(stderr, "^ "); 48 | vfprintf(stderr, fmt, ap); 49 | fprintf(stderr, "\n"); 50 | } 51 | 52 | void error_at(char *loc, char *fmt, ...) { 53 | unsigned line_no = 1; 54 | for (char *p = current_file->contents; p < loc; p++) 55 | if (*p == '\n') 56 | line_no++; 57 | 58 | va_list ap; 59 | va_start(ap, fmt); 60 | verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap); 61 | va_end(ap); 62 | exit(1); 63 | } 64 | 65 | void error_tok(Token *tok, char *fmt, ...) { 66 | va_list ap; 67 | va_start(ap, fmt); 68 | verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap); 69 | va_end(ap); 70 | exit(1); 71 | } 72 | 73 | void warn_tok(Token *tok, char *fmt, ...) { 74 | va_list ap; 75 | va_start(ap, fmt); 76 | verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap); 77 | va_end(ap); 78 | } 79 | 80 | // Consumes the current token if it matches `op`. 81 | bool equal(Token *tok, char *op) { 82 | return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0'; 83 | } 84 | 85 | // Ensure that the current token is `op`. 86 | Token *skip(Token *tok, char *op) { 87 | if (!equal(tok, op)) 88 | error_tok(tok, "expected '%s'", op); 89 | return tok->next; 90 | } 91 | 92 | bool consume(Token **rest, Token *tok, char *str) { 93 | if (equal(tok, str)) { 94 | *rest = tok->next; 95 | return true; 96 | } 97 | *rest = tok; 98 | return false; 99 | } 100 | 101 | // Create a new token. 102 | static Token *new_token(TokenKind kind, char *start, char *end) { 103 | Token *tok = calloc(1, sizeof(Token)); 104 | tok->kind = kind; 105 | tok->loc = start; 106 | tok->len = end - start; 107 | tok->file = current_file; 108 | tok->filename = current_file->display_name; 109 | tok->at_bol = at_bol; 110 | tok->has_space = has_space; 111 | 112 | at_bol = has_space = false; 113 | return tok; 114 | } 115 | 116 | static bool startswith(char *p, char *q) { 117 | return strncmp(p, q, strlen(q)) == 0; 118 | } 119 | 120 | // Read an identifier and returns the length of it. 121 | // If p does not point to a valid identifier, 0 is returned. 122 | static int read_ident(char *start) { 123 | char *p = start; 124 | uint32_t c = decode_utf8(&p, p); 125 | if (!is_ident1(c)) 126 | return 0; 127 | 128 | for (;;) { 129 | char *q; 130 | c = decode_utf8(&q, p); 131 | if (!is_ident2(c)) 132 | return p - start; 133 | p = q; 134 | } 135 | } 136 | 137 | static int from_hex(char c) { 138 | if ('0' <= c && c <= '9') 139 | return c - '0'; 140 | if ('a' <= c && c <= 'f') 141 | return c - 'a' + 10; 142 | return c - 'A' + 10; 143 | } 144 | 145 | // Read a punctuator token from p and returns its length. 146 | static int read_punct(char *p) { 147 | static char *kw[] = { 148 | "<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=", 149 | "-=", "*=", "/=", "++", "--", "%=", "&=", "|=", "^=", "&&", 150 | "||", "<<", ">>", "##" 151 | }; 152 | 153 | for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) 154 | if (startswith(p, kw[i])) 155 | return strlen(kw[i]); 156 | 157 | return ispunct(*p) ? 1 : 0; 158 | } 159 | 160 | static bool is_keyword(Token *tok) { 161 | static HashMap map; 162 | 163 | if (map.capacity == 0) { 164 | static char *kw[] = { 165 | "return", "if", "else", "for", "while", "int", "sizeof", "char", 166 | "struct", "union", "short", "long", "void", "typedef", "_Bool", 167 | "enum", "static", "goto", "break", "continue", "switch", "case", 168 | "default", "extern", "_Alignof", "_Alignas", "do", "signed", 169 | "unsigned", "const", "volatile", "auto", "register", "restrict", 170 | "__restrict", "__restrict__", "_Noreturn", "float", "double", 171 | "typeof", "asm", "_Thread_local", "__thread", "_Atomic", 172 | "__attribute__", 173 | }; 174 | 175 | for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) 176 | hashmap_put(&map, kw[i], (void *)1); 177 | } 178 | 179 | return hashmap_get2(&map, tok->loc, tok->len); 180 | } 181 | 182 | static int read_escaped_char(char **new_pos, char *p) { 183 | if ('0' <= *p && *p <= '7') { 184 | // Read an octal number. 185 | int c = *p++ - '0'; 186 | if ('0' <= *p && *p <= '7') { 187 | c = (c << 3) + (*p++ - '0'); 188 | if ('0' <= *p && *p <= '7') 189 | c = (c << 3) + (*p++ - '0'); 190 | } 191 | *new_pos = p; 192 | return c; 193 | } 194 | 195 | if (*p == 'x') { 196 | // Read a hexadecimal number. 197 | p++; 198 | if (!isxdigit(*p)) 199 | error_at(p, "invalid hex escape sequence"); 200 | 201 | int c = 0; 202 | for (; isxdigit(*p); p++) 203 | c = (c << 4) + from_hex(*p); 204 | *new_pos = p; 205 | return c; 206 | } 207 | 208 | *new_pos = p + 1; 209 | 210 | // Escape sequences are defined using themselves here. E.g. 211 | // '\n' is implemented using '\n'. This tautological definition 212 | // works because the compiler that compiles our compiler knows 213 | // what '\n' actually is. In other words, we "inherit" the ASCII 214 | // code of '\n' from the compiler that compiles our compiler, 215 | // so we don't have to teach the actual code here. 216 | // 217 | // This fact has huge implications not only for the correctness 218 | // of the compiler but also for the security of the generated code. 219 | // For more info, read "Reflections on Trusting Trust" by Ken Thompson. 220 | // https://github.com/rui314/xcc/wiki/thompson1984.pdf 221 | switch (*p) { 222 | case 'a': return '\a'; 223 | case 'b': return '\b'; 224 | case 't': return '\t'; 225 | case 'n': return '\n'; 226 | case 'v': return '\v'; 227 | case 'f': return '\f'; 228 | case 'r': return '\r'; 229 | // [GNU] \e for the ASCII escape character is a GNU C extension. 230 | case 'e': return 27; 231 | default: return *p; 232 | } 233 | } 234 | 235 | // Find a closing double-quote. 236 | static char *string_literal_end(char *p) { 237 | char *start = p; 238 | for (; *p != '"'; p++) { 239 | if (*p == '\n' || *p == '\0') 240 | error_at(start, "unclosed string literal"); 241 | if (*p == '\\') 242 | p++; 243 | } 244 | return p; 245 | } 246 | 247 | static Token *read_string_literal(char *start, char *quote) { 248 | char *end = string_literal_end(quote + 1); 249 | char *buf = calloc(1, end - quote); 250 | int len = 0; 251 | 252 | for (char *p = quote + 1; p < end;) { 253 | if (*p == '\\') 254 | buf[len++] = read_escaped_char(&p, p + 1); 255 | else 256 | buf[len++] = *p++; 257 | } 258 | 259 | Token *tok = new_token(TK_STR, start, end + 1); 260 | tok->ty = array_of(ty_char, len + 1); 261 | tok->str = buf; 262 | return tok; 263 | } 264 | 265 | // Read a UTF-8-encoded string literal and transcode it in UTF-16. 266 | // 267 | // UTF-16 is yet another variable-width encoding for Unicode. Code 268 | // points smaller than U+10000 are encoded in 2 bytes. Code points 269 | // equal to or larger than that are encoded in 4 bytes. Each 2 bytes 270 | // in the 4 byte sequence is called "surrogate", and a 4 byte sequence 271 | // is called a "surrogate pair". 272 | static Token *read_utf16_string_literal(char *start, char *quote) { 273 | char *end = string_literal_end(quote + 1); 274 | uint16_t *buf = calloc(2, end - start); 275 | int len = 0; 276 | 277 | for (char *p = quote + 1; p < end;) { 278 | if (*p == '\\') { 279 | buf[len++] = read_escaped_char(&p, p + 1); 280 | continue; 281 | } 282 | 283 | uint32_t c = decode_utf8(&p, p); 284 | if (c < 0x10000) { 285 | // Encode a code point in 2 bytes. 286 | buf[len++] = c; 287 | } else { 288 | // Encode a code point in 4 bytes. 289 | c -= 0x10000; 290 | buf[len++] = 0xd800 + ((c >> 10) & 0x3ff); 291 | buf[len++] = 0xdc00 + (c & 0x3ff); 292 | } 293 | } 294 | 295 | Token *tok = new_token(TK_STR, start, end + 1); 296 | tok->ty = array_of(ty_ushort, len + 1); 297 | tok->str = (char *)buf; 298 | return tok; 299 | } 300 | 301 | // Read a UTF-8-encoded string literal and transcode it in UTF-32. 302 | // 303 | // UTF-32 is a fixed-width encoding for Unicode. Each code point is 304 | // encoded in 4 bytes. 305 | static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) { 306 | char *end = string_literal_end(quote + 1); 307 | uint32_t *buf = calloc(4, end - quote); 308 | int len = 0; 309 | 310 | for (char *p = quote + 1; p < end;) { 311 | if (*p == '\\') 312 | buf[len++] = read_escaped_char(&p, p + 1); 313 | else 314 | buf[len++] = decode_utf8(&p, p); 315 | } 316 | 317 | Token *tok = new_token(TK_STR, start, end + 1); 318 | tok->ty = array_of(ty, len + 1); 319 | tok->str = (char *)buf; 320 | return tok; 321 | } 322 | 323 | static Token *read_char_literal(char *start, char *quote, Type *ty) { 324 | char *p = quote + 1; 325 | if (*p == '\0') 326 | error_at(start, "unclosed char literal"); 327 | 328 | int c; 329 | if (*p == '\\') 330 | c = read_escaped_char(&p, p + 1); 331 | else 332 | c = decode_utf8(&p, p); 333 | 334 | char *end = strchr(p, '\''); 335 | if (!end) 336 | error_at(p, "unclosed char literal"); 337 | 338 | Token *tok = new_token(TK_NUM, start, end + 1); 339 | tok->val = c; 340 | tok->ty = ty; 341 | return tok; 342 | } 343 | 344 | static bool convert_pp_int(Token *tok) { 345 | char *p = tok->loc; 346 | 347 | // Read a binary, octal, decimal or hexadecimal number. 348 | int base = 10; 349 | if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) { 350 | p += 2; 351 | base = 16; 352 | } else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) { 353 | p += 2; 354 | base = 2; 355 | } else if (*p == '0') { 356 | base = 8; 357 | } 358 | 359 | int64_t val = strtoul(p, &p, base); 360 | 361 | // Read U, L or LL suffixes. 362 | bool l = false; 363 | bool u = false; 364 | 365 | if (startswith(p, "LLU") || startswith(p, "LLu") || 366 | startswith(p, "llU") || startswith(p, "llu") || 367 | startswith(p, "ULL") || startswith(p, "Ull") || 368 | startswith(p, "uLL") || startswith(p, "ull")) { 369 | p += 3; 370 | l = u = true; 371 | } else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) { 372 | p += 2; 373 | l = u = true; 374 | } else if (startswith(p, "LL") || startswith(p, "ll")) { 375 | p += 2; 376 | l = true; 377 | } else if (*p == 'L' || *p == 'l') { 378 | p++; 379 | l = true; 380 | } else if (*p == 'U' || *p == 'u') { 381 | p++; 382 | u = true; 383 | } 384 | 385 | if (p != tok->loc + tok->len) 386 | return false; 387 | 388 | // Infer a type. 389 | Type *ty; 390 | if (base == 10) { 391 | if (l && u) 392 | ty = ty_ulong; 393 | else if (l) 394 | ty = ty_long; 395 | else if (u) 396 | ty = (val >> 32) ? ty_ulong : ty_uint; 397 | else 398 | ty = (val >> 31) ? ty_long : ty_int; 399 | } else { 400 | if (l && u) 401 | ty = ty_ulong; 402 | else if (l) 403 | ty = (val >> 63) ? ty_ulong : ty_long; 404 | else if (u) 405 | ty = (val >> 32) ? ty_ulong : ty_uint; 406 | else if (val >> 63) 407 | ty = ty_ulong; 408 | else if (val >> 32) 409 | ty = ty_long; 410 | else if (val >> 31) 411 | ty = ty_uint; 412 | else 413 | ty = ty_int; 414 | } 415 | 416 | tok->kind = TK_NUM; 417 | tok->val = val; 418 | tok->ty = ty; 419 | return true; 420 | } 421 | 422 | // The definition of the numeric literal at the preprocessing stage 423 | // is more relaxed than the definition of that at the later stages. 424 | // In order to handle that, a numeric literal is tokenized as a 425 | // "pp-number" token first and then converted to a regular number 426 | // token after preprocessing. 427 | // 428 | // This function converts a pp-number token to a regular number token. 429 | static void convert_pp_number(Token *tok) { 430 | // Try to parse as an integer constant. 431 | if (convert_pp_int(tok)) 432 | return; 433 | 434 | // If it's not an integer, it must be a floating point constant. 435 | char *end; 436 | long double val = strtold(tok->loc, &end); 437 | 438 | Type *ty; 439 | if (*end == 'f' || *end == 'F') { 440 | ty = ty_float; 441 | end++; 442 | } else if (*end == 'l' || *end == 'L') { 443 | ty = ty_ldouble; 444 | end++; 445 | } else { 446 | ty = ty_double; 447 | } 448 | 449 | if (tok->loc + tok->len != end) 450 | error_tok(tok, "invalid numeric constant"); 451 | 452 | tok->kind = TK_NUM; 453 | tok->fval = val; 454 | tok->ty = ty; 455 | } 456 | 457 | void convert_pp_tokens(Token *tok) { 458 | for (Token *t = tok; t->kind != TK_EOF; t = t->next) { 459 | if (is_keyword(t)) 460 | t->kind = TK_KEYWORD; 461 | else if (t->kind == TK_PP_NUM) 462 | convert_pp_number(t); 463 | } 464 | } 465 | 466 | // Initialize line info for all tokens. 467 | static void add_line_numbers(Token *tok) { 468 | char *p = current_file->contents; 469 | int n = 1; 470 | 471 | do { 472 | if (p == tok->loc) { 473 | tok->line_no = n; 474 | tok = tok->next; 475 | } 476 | if (*p == '\n') 477 | n++; 478 | } while (*p++); 479 | } 480 | 481 | Token *tokenize_string_literal(Token *tok, Type *basety) { 482 | Token *t; 483 | if (basety->size == 2) 484 | t = read_utf16_string_literal(tok->loc, tok->loc); 485 | else 486 | t = read_utf32_string_literal(tok->loc, tok->loc, basety); 487 | t->next = tok->next; 488 | return t; 489 | } 490 | 491 | // Tokenize a given string and returns new tokens. 492 | Token *tokenize(File *file) { 493 | current_file = file; 494 | 495 | char *p = file->contents; 496 | Token head = {}; 497 | Token *cur = &head; 498 | 499 | at_bol = true; 500 | has_space = false; 501 | 502 | while (*p) { 503 | 504 | // Skip line shebang. 505 | if (startswith(p, "#!")) { 506 | p += 2; 507 | while (*p != '\n') 508 | p++; 509 | has_space = true; 510 | continue; 511 | } 512 | 513 | // Skip line comments. 514 | if (startswith(p, "//")) { 515 | p += 2; 516 | while (*p != '\n') 517 | p++; 518 | has_space = true; 519 | continue; 520 | } 521 | 522 | // Skip block comments. 523 | if (startswith(p, "/*")) { 524 | char *q = strstr(p + 2, "*/"); 525 | if (!q) 526 | error_at(p, "unclosed block comment"); 527 | p = q + 2; 528 | has_space = true; 529 | continue; 530 | } 531 | 532 | // Skip newline. 533 | if (*p == '\n') { 534 | p++; 535 | at_bol = true; 536 | has_space = false; 537 | continue; 538 | } 539 | 540 | // Skip whitespace characters. 541 | if (isspace(*p)) { 542 | p++; 543 | has_space = true; 544 | continue; 545 | } 546 | 547 | // Numeric literal 548 | if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) { 549 | char *q = p++; 550 | for (;;) { 551 | if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) 552 | p += 2; 553 | else if (isalnum(*p) || *p == '.') 554 | p++; 555 | else 556 | break; 557 | } 558 | cur = cur->next = new_token(TK_PP_NUM, q, p); 559 | continue; 560 | } 561 | 562 | // String literal 563 | if (*p == '"') { 564 | cur = cur->next = read_string_literal(p, p); 565 | p += cur->len; 566 | continue; 567 | } 568 | 569 | // UTF-8 string literal 570 | if (startswith(p, "u8\"")) { 571 | cur = cur->next = read_string_literal(p, p + 2); 572 | p += cur->len; 573 | continue; 574 | } 575 | 576 | // UTF-16 string literal 577 | if (startswith(p, "u\"")) { 578 | cur = cur->next = read_utf16_string_literal(p, p + 1); 579 | p += cur->len; 580 | continue; 581 | } 582 | 583 | // Wide string literal 584 | if (startswith(p, "L\"")) { 585 | cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int); 586 | p += cur->len; 587 | continue; 588 | } 589 | 590 | // UTF-32 string literal 591 | if (startswith(p, "U\"")) { 592 | cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint); 593 | p += cur->len; 594 | continue; 595 | } 596 | 597 | // Character literal 598 | if (*p == '\'') { 599 | cur = cur->next = read_char_literal(p, p, ty_int); 600 | cur->val = (char)cur->val; 601 | p += cur->len; 602 | continue; 603 | } 604 | 605 | // UTF-16 character literal 606 | if (startswith(p, "u'")) { 607 | cur = cur->next = read_char_literal(p, p + 1, ty_ushort); 608 | cur->val &= 0xffff; 609 | p += cur->len; 610 | continue; 611 | } 612 | 613 | // Wide character literal 614 | if (startswith(p, "L'")) { 615 | cur = cur->next = read_char_literal(p, p + 1, ty_int); 616 | p += cur->len; 617 | continue; 618 | } 619 | 620 | // UTF-32 character literal 621 | if (startswith(p, "U'")) { 622 | cur = cur->next = read_char_literal(p, p + 1, ty_uint); 623 | p += cur->len; 624 | continue; 625 | } 626 | 627 | // Identifier or keyword 628 | int ident_len = read_ident(p); 629 | if (ident_len) { 630 | cur = cur->next = new_token(TK_IDENT, p, p + ident_len); 631 | p += cur->len; 632 | continue; 633 | } 634 | 635 | // Punctuators 636 | int punct_len = read_punct(p); 637 | if (punct_len) { 638 | cur = cur->next = new_token(TK_PUNCT, p, p + punct_len); 639 | p += cur->len; 640 | continue; 641 | } 642 | 643 | error_at(p, "invalid token"); 644 | } 645 | 646 | cur = cur->next = new_token(TK_EOF, p, p); 647 | add_line_numbers(head.next); 648 | return head.next; 649 | } 650 | 651 | // Returns the contents of a given file. 652 | static char *read_file(char *path) { 653 | FILE *fp; 654 | 655 | if (strcmp(path, "-") == 0) { 656 | // By convention, read from stdin if a given filename is "-". 657 | fp = stdin; 658 | } else { 659 | fp = fopen(path, "r"); 660 | if (!fp) 661 | return NULL; 662 | } 663 | 664 | char *buf; 665 | size_t buflen; 666 | FILE *out = open_memstream(&buf, &buflen); 667 | 668 | // Read the entire file. 669 | for (;;) { 670 | char buf2[4096]; 671 | int n = fread(buf2, 1, sizeof(buf2), fp); 672 | if (n == 0) 673 | break; 674 | fwrite(buf2, 1, n, out); 675 | } 676 | 677 | if (fp != stdin) 678 | fclose(fp); 679 | 680 | // Make sure that the last line is properly terminated with '\n'. 681 | fflush(out); 682 | if (buflen == 0 || buf[buflen - 1] != '\n') 683 | fputc('\n', out); 684 | fputc('\0', out); 685 | fclose(out); 686 | return buf; 687 | } 688 | 689 | File **get_input_files(void) { 690 | return input_files; 691 | } 692 | 693 | File *new_file(char *name, unsigned file_no, char *contents) { 694 | File *file = calloc(1, sizeof(File)); 695 | file->name = name; 696 | file->display_name = name; 697 | file->file_no = file_no; 698 | file->contents = contents; 699 | return file; 700 | } 701 | 702 | // Replaces \r or \r\n with \n. 703 | static void canonicalize_newline(char *p) { 704 | int i = 0, j = 0; 705 | 706 | while (p[i]) { 707 | if (p[i] == '\r' && p[i + 1] == '\n') { 708 | i += 2; 709 | p[j++] = '\n'; 710 | } else if (p[i] == '\r') { 711 | i++; 712 | p[j++] = '\n'; 713 | } else { 714 | p[j++] = p[i++]; 715 | } 716 | } 717 | 718 | p[j] = '\0'; 719 | } 720 | 721 | // Removes backslashes followed by a newline. 722 | static void remove_backslash_newline(char *p) { 723 | int i = 0, j = 0; 724 | 725 | // We want to keep the number of newline characters so that 726 | // the logical line number matches the physical one. 727 | // This counter maintain the number of newlines we have removed. 728 | int n = 0; 729 | 730 | while (p[i]) { 731 | if (p[i] == '\\' && p[i + 1] == '\n') { 732 | i += 2; 733 | n++; 734 | } else if (p[i] == '\n') { 735 | p[j++] = p[i++]; 736 | for (; n > 0; n--) 737 | p[j++] = '\n'; 738 | } else { 739 | p[j++] = p[i++]; 740 | } 741 | } 742 | 743 | for (; n > 0; n--) 744 | p[j++] = '\n'; 745 | p[j] = '\0'; 746 | } 747 | 748 | static uint32_t read_universal_char(char *p, int len) { 749 | uint32_t c = 0; 750 | for (int i = 0; i < len; i++) { 751 | if (!isxdigit(p[i])) 752 | return 0; 753 | c = (c << 4) | from_hex(p[i]); 754 | } 755 | return c; 756 | } 757 | 758 | // Replace \u or \U escape sequences with corresponding UTF-8 bytes. 759 | static void convert_universal_chars(char *p) { 760 | char *q = p; 761 | 762 | while (*p) { 763 | if (startswith(p, "\\u")) { 764 | uint32_t c = read_universal_char(p + 2, 4); 765 | if (c) { 766 | p += 6; 767 | q += encode_utf8(q, c); 768 | } else { 769 | *q++ = *p++; 770 | } 771 | } else if (startswith(p, "\\U")) { 772 | uint32_t c = read_universal_char(p + 2, 8); 773 | if (c) { 774 | p += 10; 775 | q += encode_utf8(q, c); 776 | } else { 777 | *q++ = *p++; 778 | } 779 | } else if (p[0] == '\\') { 780 | *q++ = *p++; 781 | *q++ = *p++; 782 | } else { 783 | *q++ = *p++; 784 | } 785 | } 786 | 787 | *q = '\0'; 788 | } 789 | 790 | Token *tokenize_file(char *path) { 791 | char *p = read_file(path); 792 | if (!p) 793 | return NULL; 794 | 795 | // UTF-8 texts may start with a 3-byte "BOM" marker sequence. 796 | // If exists, just skip them because they are useless bytes. 797 | // (It is actually not recommended to add BOM markers to UTF-8 798 | // texts, but it's not uncommon particularly on Windows.) 799 | if (!memcmp(p, "\xef\xbb\xbf", 3)) 800 | p += 3; 801 | 802 | canonicalize_newline(p); 803 | remove_backslash_newline(p); 804 | convert_universal_chars(p); 805 | 806 | // Save the filename for assembler .file directive. 807 | static int file_no; 808 | File *file = new_file(path, file_no + 1, p); 809 | 810 | // Save the filename for assembler .file directive. 811 | input_files = realloc(input_files, sizeof(char *) * (file_no + 2)); 812 | input_files[file_no] = file; 813 | input_files[file_no + 1] = NULL; 814 | file_no++; 815 | 816 | return tokenize(file); 817 | } 818 | -------------------------------------------------------------------------------- /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,