├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── chibicc.h ├── codegen.c ├── hashmap.c ├── include ├── float.h ├── stdalign.h ├── stdarg.h ├── stdatomic.h ├── stdbool.h ├── stddef.h └── stdnoreturn.h ├── main.c ├── parse.c ├── preprocess.c ├── strings.c ├── test ├── alignof.c ├── alloca.c ├── arith.c ├── asm.c ├── atomic.c ├── attribute.c ├── bitfield.c ├── builtin.c ├── cast.c ├── common ├── commonsym.c ├── compat.c ├── complit.c ├── const.c ├── constexpr.c ├── control.c ├── decl.c ├── driver.sh ├── enum.c ├── extern.c ├── float.c ├── function.c ├── generic.c ├── include1.h ├── include2.h ├── include3.h ├── include4.h ├── initializer.c ├── line.c ├── literal.c ├── macro.c ├── offsetof.c ├── pointer.c ├── pragma-once.c ├── sizeof.c ├── stdhdr.c ├── string.c ├── struct.c ├── test.h ├── thirdparty │ ├── common │ ├── cpython.sh │ ├── git.sh │ ├── libpng.sh │ ├── sqlite.sh │ └── tinycc.sh ├── tls.c ├── typedef.c ├── typeof.c ├── unicode.c ├── union.c ├── usualconv.c ├── varargs.c ├── variable.c └── vla.c ├── tokenize.c ├── type.c └── unicode.c /.gitignore: -------------------------------------------------------------------------------- 1 | **/*~ 2 | **/\#* 3 | **/*.o 4 | **/*.s 5 | **/a.out 6 | /tmp* 7 | /thirdparty 8 | /chibicc 9 | /test/*.exe 10 | /stage2 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rui Ueyama 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-std=c11 -g -fno-common -Wall -Wno-switch 2 | 3 | SRCS=$(wildcard *.c) 4 | OBJS=$(SRCS:.c=.o) 5 | 6 | TEST_SRCS=$(wildcard test/*.c) 7 | TESTS=$(TEST_SRCS:.c=.exe) 8 | 9 | # Stage 1 10 | 11 | chibicc: $(OBJS) 12 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 13 | 14 | $(OBJS): chibicc.h 15 | 16 | test/%.exe: chibicc test/%.c 17 | ./chibicc -Iinclude -Itest -c -o test/$*.o test/$*.c 18 | $(CC) -pthread -o $@ test/$*.o -xc test/common 19 | 20 | test: $(TESTS) 21 | for i in $^; do echo $$i; ./$$i || exit 1; echo; done 22 | test/driver.sh ./chibicc 23 | 24 | test-all: test test-stage2 25 | 26 | # Stage 2 27 | 28 | stage2/chibicc: $(OBJS:%=stage2/%) 29 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 30 | 31 | stage2/%.o: chibicc %.c 32 | mkdir -p stage2/test 33 | ./chibicc -c -o $(@D)/$*.o $*.c 34 | 35 | stage2/test/%.exe: stage2/chibicc test/%.c 36 | mkdir -p stage2/test 37 | ./stage2/chibicc -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/chibicc 43 | 44 | # Misc. 45 | 46 | clean: 47 | rm -rf chibicc tmp* $(TESTS) test/*.s test/*.exe stage2 48 | find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';' 49 | 50 | .PHONY: test clean test-stage2 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chibicc: A Small C Compiler 2 | 3 | (The old master has moved to 4 | [historical/old](https://github.com/rui314/chibicc/tree/historical/old) 5 | branch. This is a new one uploaded in September 2020.) 6 | 7 | chibicc is yet another small C compiler that implements most C11 8 | features. Even though it still probably falls into the "toy compilers" 9 | category just like other small compilers do, chibicc can compile 10 | several real-world programs, including [Git](https://git-scm.com/), 11 | [SQLite](https://sqlite.org), 12 | [libpng](http://www.libpng.org/pub/png/libpng.html) and chibicc 13 | itself, without making modifications to the compiled programs. 14 | Generated executables of these programs pass their corresponding test 15 | suites. So, chibicc actually supports a wide variety of C11 features 16 | and is able to compile hundreds of thousands of lines of real-world C 17 | code correctly. 18 | 19 | chibicc is developed as the reference implementation for a book I'm 20 | currently writing about the C compiler and the low-level programming. 21 | The book covers the vast topic with an incremental approach; in the first 22 | chapter, readers will implement a "compiler" that accepts just a single 23 | number as a "language", which will then gain one feature at a time in each 24 | section of the book until the language that the compiler accepts matches 25 | what the C11 spec specifies. I took this incremental approach from [the 26 | paper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz 27 | Ghuloum. 28 | 29 | Each commit of this project corresponds to a section of the book. For this 30 | purpose, not only the final state of the project but each commit was 31 | carefully written with readability in mind. Readers should be able to learn 32 | how a C language feature can be implemented just by reading one or a few 33 | commits of this project. For example, this is how 34 | [while](https://github.com/rui314/chibicc/commit/773115ab2a9c4b96f804311b95b20e9771f0190a), 35 | [[]](https://github.com/rui314/chibicc/commit/75fbd3dd6efde12eac8225d8b5723093836170a5), 36 | [?:](https://github.com/rui314/chibicc/commit/1d0e942fd567a35d296d0f10b7693e98b3dd037c), 37 | and [thread-local 38 | variable](https://github.com/rui314/chibicc/commit/79644e54cc1805e54428cde68b20d6d493b76d34) 39 | are implemented. If you have plenty of spare time, it might be fun to read 40 | it from the [first 41 | commit](https://github.com/rui314/chibicc/commit/0522e2d77e3ab82d3b80a5be8dbbdc8d4180561c). 42 | 43 | If you like this project, please consider purchasing a copy of the book 44 | when it becomes available! 😀 I publish the source code here to give people 45 | early access to it, because I was planing to do that anyway with a 46 | permissive open-source license after publishing the book. If I don't charge 47 | for the source code, it doesn't make much sense to me to keep it private. I 48 | hope to publish the book in 2021. 49 | You can sign up [here](https://forms.gle/sgrMWHGeGjeeEJcX7) to receive a 50 | notification when a free chapter is available online or the book is published. 51 | 52 | I pronounce chibicc as _chee bee cee cee_. "chibi" means "mini" or 53 | "small" in Japanese. "cc" stands for C compiler. 54 | 55 | ## Status 56 | 57 | chibicc supports almost all mandatory features and most optional 58 | features of C11 as well as a few GCC language extensions. 59 | 60 | Features that are often missing in a small compiler but supported by 61 | chibicc include (but not limited to): 62 | 63 | - Preprocessor 64 | - float, double and long double (x87 80-bit floating point numbers) 65 | - Bit-fields 66 | - alloca() 67 | - Variable-length arrays 68 | - Compound literals 69 | - Thread-local variables 70 | - Atomic variables 71 | - Common symbols 72 | - Designated initializers 73 | - L, u, U and u8 string literals 74 | - Functions that take or return structs as values, as specified by the 75 | x86-64 SystemV ABI 76 | 77 | chibicc does not support complex numbers, K&R-style function prototypes 78 | and GCC-style inline assembly. Digraphs and trigraphs are intentionally 79 | left out. 80 | 81 | chibicc outputs a simple but nice error message when it finds an error in 82 | source code. 83 | 84 | There's no optimization pass. chibicc emits terrible code which is probably 85 | twice or more slower than GCC's output. I have a plan to add an 86 | optimization pass once the frontend is done. 87 | 88 | I'm using Ubuntu 20.04 for x86-64 as a development platform. I made a 89 | few small changes so that chibicc works on Ubuntu 18.04, Fedora 32 and 90 | Gentoo 2.6, but portability is not my goal at this moment. It may or 91 | may not work on systems other than Ubuntu 20.04. 92 | 93 | ## Internals 94 | 95 | chibicc consists of the following stages: 96 | 97 | - Tokenize: A tokenizer takes a string as an input, breaks it into a list 98 | of tokens and returns them. 99 | 100 | - Preprocess: A preprocessor takes as an input a list of tokens and output 101 | a new list of macro-expanded tokens. It interprets preprocessor 102 | directives while expanding macros. 103 | 104 | - Parse: A recursive descendent parser constructs abstract syntax trees 105 | from the output of the preprocessor. It also adds a type to each AST 106 | node. 107 | 108 | - Codegen: A code generator emits an assembly text for given AST nodes. 109 | 110 | ## Contributing 111 | 112 | When I find a bug in this compiler, I go back to the original commit that 113 | introduced the bug and rewrite the commit history as if there were no such 114 | bug from the beginning. This is an unusual way of fixing bugs, but as a 115 | part of a book, it is important to keep every commit bug-free. 116 | 117 | Thus, I do not take pull requests in this repo. You can send me a pull 118 | request if you find a bug, but it is very likely that I will read your 119 | patch and then apply that to my previous commits by rewriting history. I'll 120 | credit your name somewhere, but your changes will be rewritten by me before 121 | submitted to this repository. 122 | 123 | Also, please assume that I will occasionally force-push my local repository 124 | to this public one to rewrite history. If you clone this project and make 125 | local commits on top of it, your changes will have to be rebased by hand 126 | when I force-push new commits. 127 | 128 | ## Design principles 129 | 130 | chibicc's core value is its simplicity and the reability of its source 131 | code. To achieve this goal, I was careful not to be too clever when 132 | writing code. Let me explain what that means. 133 | 134 | Oftentimes, as you get used to the code base, you are tempted to 135 | _improve_ the code using more abstractions and clever tricks. 136 | But that kind of _improvements_ don't always improve readability for 137 | first-time readers and can actually hurts it. I tried to avoid the 138 | pitfall as much as possible. I wrote this code not for me but for 139 | first-time readers. 140 | 141 | If you take a look at the source code, you'll find a couple of 142 | dumb-looking pieces of code. These are written intentionally that way 143 | (but at some places I might be actually missing something, 144 | though). Here is a few notable examples: 145 | 146 | - The recursive descendent parser contains many similar-looking functions 147 | for similar-looking generative grammar rules. You might be tempted 148 | to _improve_ it to reduce the duplication using higher-order functions 149 | or macros, but I thought that that's too complicated. It's better to 150 | allow small duplications instead. 151 | 152 | - chibicc doesn't try too hard to save memory. An entire input source 153 | file is read to memory first before the tokenizer kicks in, for example. 154 | 155 | - Slow algorithms are fine if we know that n isn't too big. 156 | For example, we use a linked list as a set in the preprocessor, so 157 | the membership check takes O(n) where n is the size of the set. But 158 | that's fine because we know n is usually very small. 159 | And even if n can be very big, I stick with a simple slow algorithm 160 | until it is proved by benchmarks that that's a bottleneck. 161 | 162 | - Each AST node type uses only a few members of the `Node` struct members. 163 | Other unused `Node` members are just a waste of memory at runtime. 164 | We could save memory using unions, but I decided to simply put everything 165 | in the same struct instead. I believe the inefficiency is negligible. 166 | Even if it matters, we can always change the code to use unions 167 | at any time. I wanted to avoid premature optimization. 168 | 169 | - chibicc always allocates heap memory using `calloc`, which is a 170 | variant of `malloc` that clears memory with zero. `calloc` is 171 | slightly slower than `malloc`, but that should be neligible. 172 | 173 | - Last but not least, chibicc allocates memory using `calloc` but never 174 | calls `free`. Allocated heap memory is not freed until the process exits. 175 | I'm sure that this memory management policy (or lack thereof) looks 176 | very odd, but it makes sense for short-lived programs such as compilers. 177 | DMD, a compiler for the D programming language, uses the same memory 178 | management scheme for the same reason, for example [1]. 179 | 180 | ## About the Author 181 | 182 | I'm Rui Ueyama. I'm the creator of [8cc](https://github.com/rui314/8cc), 183 | which is a hobby C compiler, and also the original creator of the current 184 | version of [LLVM lld](https://lld.llvm.org) linker, which is a 185 | production-quality linker used by various operating systems and large-scale 186 | build systems. 187 | 188 | ## References 189 | 190 | - [tcc](https://bellard.org/tcc/): A small C compiler written by Fabrice 191 | Bellard. I learned a lot from this compiler, but the design of tcc and 192 | chibicc are different. In particular, tcc is a one-pass compiler, while 193 | chibicc is a multi-pass one. 194 | 195 | - [lcc](https://github.com/drh/lcc): Another small C compiler. The creators 196 | wrote a [book](https://sites.google.com/site/lccretargetablecompiler/) 197 | about the internals of lcc, which I found a good resource to see how a 198 | compiler is implemented. 199 | 200 | - [An Incremental Approach to Compiler 201 | Construction](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) 202 | 203 | - [Rob Pike's 5 Rules of Programming](https://users.ece.utexas.edu/~adnan/pike.html) 204 | 205 | [1] https://www.drdobbs.com/cpp/increasing-compiler-speed-by-over-75/240158941 206 | 207 | > DMD does memory allocation in a bit of a sneaky way. Since compilers 208 | > are short-lived programs, and speed is of the essence, DMD just 209 | > mallocs away, and never frees. 210 | -------------------------------------------------------------------------------- /chibicc.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 | #define MAX(x, y) ((x) < (y) ? (y) : (x)) 22 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 23 | 24 | #ifndef __GNUC__ 25 | # define __attribute__(x) 26 | #endif 27 | 28 | typedef struct Type Type; 29 | typedef struct Node Node; 30 | typedef struct Member Member; 31 | typedef struct Relocation Relocation; 32 | typedef struct Hideset Hideset; 33 | 34 | // 35 | // strings.c 36 | // 37 | 38 | typedef struct { 39 | char **data; 40 | int capacity; 41 | int len; 42 | } StringArray; 43 | 44 | void strarray_push(StringArray *arr, char *s); 45 | char *format(char *fmt, ...) __attribute__((format(printf, 1, 2))); 46 | 47 | // 48 | // tokenize.c 49 | // 50 | 51 | // Token 52 | typedef enum { 53 | TK_IDENT, // Identifiers 54 | TK_PUNCT, // Punctuators 55 | TK_KEYWORD, // Keywords 56 | TK_STR, // String literals 57 | TK_NUM, // Numeric literals 58 | TK_PP_NUM, // Preprocessing numbers 59 | TK_EOF, // End-of-file markers 60 | } TokenKind; 61 | 62 | typedef struct { 63 | char *name; 64 | int file_no; 65 | char *contents; 66 | 67 | // For #line directive 68 | char *display_name; 69 | int line_delta; 70 | } File; 71 | 72 | // Token type 73 | typedef struct Token Token; 74 | struct Token { 75 | TokenKind kind; // Token kind 76 | Token *next; // Next token 77 | int64_t val; // If kind is TK_NUM, its value 78 | long double fval; // If kind is TK_NUM, its value 79 | char *loc; // Token location 80 | int len; // Token length 81 | Type *ty; // Used if TK_NUM or TK_STR 82 | char *str; // String literal contents including terminating '\0' 83 | 84 | File *file; // Source location 85 | char *filename; // Filename 86 | int line_no; // Line number 87 | int line_delta; // Line number 88 | bool at_bol; // True if this token is at beginning of line 89 | bool has_space; // True if this token follows a space character 90 | Hideset *hideset; // For macro expansion 91 | Token *origin; // If this is expanded from a macro, the original token 92 | }; 93 | 94 | noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2))); 95 | noreturn void error_at(char *loc, char *fmt, ...) __attribute__((format(printf, 2, 3))); 96 | noreturn void error_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3))); 97 | void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3))); 98 | bool equal(Token *tok, char *op); 99 | Token *skip(Token *tok, char *op); 100 | bool consume(Token **rest, Token *tok, char *str); 101 | void convert_pp_tokens(Token *tok); 102 | File **get_input_files(void); 103 | File *new_file(char *name, int file_no, char *contents); 104 | Token *tokenize_string_literal(Token *tok, Type *basety); 105 | Token *tokenize(File *file); 106 | Token *tokenize_file(char *filename); 107 | 108 | #define unreachable() \ 109 | error("internal error at %s:%d", __FILE__, __LINE__) 110 | 111 | // 112 | // preprocess.c 113 | // 114 | 115 | char *search_include_paths(char *filename); 116 | void init_macros(void); 117 | void define_macro(char *name, char *buf); 118 | void undef_macro(char *name); 119 | Token *preprocess(Token *tok); 120 | 121 | // 122 | // parse.c 123 | // 124 | 125 | // Variable or function 126 | typedef struct Obj Obj; 127 | struct Obj { 128 | Obj *next; 129 | char *name; // Variable name 130 | Type *ty; // Type 131 | Token *tok; // representative token 132 | bool is_local; // local or global/function 133 | int align; // alignment 134 | 135 | // Local variable 136 | int offset; 137 | 138 | // Global variable or function 139 | bool is_function; 140 | bool is_definition; 141 | bool is_static; 142 | 143 | // Global variable 144 | bool is_tentative; 145 | bool is_tls; 146 | char *init_data; 147 | Relocation *rel; 148 | 149 | // Function 150 | bool is_inline; 151 | Obj *params; 152 | Node *body; 153 | Obj *locals; 154 | Obj *va_area; 155 | Obj *alloca_bottom; 156 | int stack_size; 157 | 158 | // Static inline function 159 | bool is_live; 160 | bool is_root; 161 | StringArray refs; 162 | }; 163 | 164 | // Global variable can be initialized either by a constant expression 165 | // or a pointer to another global variable. This struct represents the 166 | // latter. 167 | typedef struct Relocation Relocation; 168 | struct Relocation { 169 | Relocation *next; 170 | int offset; 171 | char **label; 172 | long addend; 173 | }; 174 | 175 | // AST node 176 | typedef enum { 177 | ND_NULL_EXPR, // Do nothing 178 | ND_ADD, // + 179 | ND_SUB, // - 180 | ND_MUL, // * 181 | ND_DIV, // / 182 | ND_NEG, // unary - 183 | ND_MOD, // % 184 | ND_BITAND, // & 185 | ND_BITOR, // | 186 | ND_BITXOR, // ^ 187 | ND_SHL, // << 188 | ND_SHR, // >> 189 | ND_EQ, // == 190 | ND_NE, // != 191 | ND_LT, // < 192 | ND_LE, // <= 193 | ND_ASSIGN, // = 194 | ND_COND, // ?: 195 | ND_COMMA, // , 196 | ND_MEMBER, // . (struct member access) 197 | ND_ADDR, // unary & 198 | ND_DEREF, // unary * 199 | ND_NOT, // ! 200 | ND_BITNOT, // ~ 201 | ND_LOGAND, // && 202 | ND_LOGOR, // || 203 | ND_RETURN, // "return" 204 | ND_IF, // "if" 205 | ND_FOR, // "for" or "while" 206 | ND_DO, // "do" 207 | ND_SWITCH, // "switch" 208 | ND_CASE, // "case" 209 | ND_BLOCK, // { ... } 210 | ND_GOTO, // "goto" 211 | ND_GOTO_EXPR, // "goto" labels-as-values 212 | ND_LABEL, // Labeled statement 213 | ND_LABEL_VAL, // [GNU] Labels-as-values 214 | ND_FUNCALL, // Function call 215 | ND_EXPR_STMT, // Expression statement 216 | ND_STMT_EXPR, // Statement expression 217 | ND_VAR, // Variable 218 | ND_VLA_PTR, // VLA designator 219 | ND_NUM, // Integer 220 | ND_CAST, // Type cast 221 | ND_MEMZERO, // Zero-clear a stack variable 222 | ND_ASM, // "asm" 223 | ND_CAS, // Atomic compare-and-swap 224 | ND_EXCH, // Atomic exchange 225 | } NodeKind; 226 | 227 | // AST node type 228 | struct Node { 229 | NodeKind kind; // Node kind 230 | Node *next; // Next node 231 | Type *ty; // Type, e.g. int or pointer to int 232 | Token *tok; // Representative token 233 | 234 | Node *lhs; // Left-hand side 235 | Node *rhs; // Right-hand side 236 | 237 | // "if" or "for" statement 238 | Node *cond; 239 | Node *then; 240 | Node *els; 241 | Node *init; 242 | Node *inc; 243 | 244 | // "break" and "continue" labels 245 | char *brk_label; 246 | char *cont_label; 247 | 248 | // Block or statement expression 249 | Node *body; 250 | 251 | // Struct member access 252 | Member *member; 253 | 254 | // Function call 255 | Type *func_ty; 256 | Node *args; 257 | bool pass_by_stack; 258 | Obj *ret_buffer; 259 | 260 | // Goto or labeled statement, or labels-as-values 261 | char *label; 262 | char *unique_label; 263 | Node *goto_next; 264 | 265 | // Switch 266 | Node *case_next; 267 | Node *default_case; 268 | 269 | // Case 270 | long begin; 271 | long end; 272 | 273 | // "asm" string literal 274 | char *asm_str; 275 | 276 | // Atomic compare-and-swap 277 | Node *cas_addr; 278 | Node *cas_old; 279 | Node *cas_new; 280 | 281 | // Atomic op= operators 282 | Obj *atomic_addr; 283 | Node *atomic_expr; 284 | 285 | // Variable 286 | Obj *var; 287 | 288 | // Numeric literal 289 | int64_t val; 290 | long double fval; 291 | }; 292 | 293 | Node *new_cast(Node *expr, Type *ty); 294 | int64_t const_expr(Token **rest, Token *tok); 295 | Obj *parse(Token *tok); 296 | 297 | // 298 | // type.c 299 | // 300 | 301 | typedef enum { 302 | TY_VOID, 303 | TY_BOOL, 304 | TY_CHAR, 305 | TY_SHORT, 306 | TY_INT, 307 | TY_LONG, 308 | TY_FLOAT, 309 | TY_DOUBLE, 310 | TY_LDOUBLE, 311 | TY_ENUM, 312 | TY_PTR, 313 | TY_FUNC, 314 | TY_ARRAY, 315 | TY_VLA, // variable-length array 316 | TY_STRUCT, 317 | TY_UNION, 318 | } TypeKind; 319 | 320 | struct Type { 321 | TypeKind kind; 322 | int size; // sizeof() value 323 | int align; // alignment 324 | bool is_unsigned; // unsigned or signed 325 | bool is_atomic; // true if _Atomic 326 | Type *origin; // for type compatibility check 327 | 328 | // Pointer-to or array-of type. We intentionally use the same member 329 | // to represent pointer/array duality in C. 330 | // 331 | // In many contexts in which a pointer is expected, we examine this 332 | // member instead of "kind" member to determine whether a type is a 333 | // pointer or not. That means in many contexts "array of T" is 334 | // naturally handled as if it were "pointer to T", as required by 335 | // the C spec. 336 | Type *base; 337 | 338 | // Declaration 339 | Token *name; 340 | Token *name_pos; 341 | 342 | // Array 343 | int array_len; 344 | 345 | // Variable-length array 346 | Node *vla_len; // # of elements 347 | Obj *vla_size; // sizeof() value 348 | 349 | // Struct 350 | Member *members; 351 | bool is_flexible; 352 | bool is_packed; 353 | 354 | // Function type 355 | Type *return_ty; 356 | Type *params; 357 | bool is_variadic; 358 | Type *next; 359 | }; 360 | 361 | // Struct member 362 | struct Member { 363 | Member *next; 364 | Type *ty; 365 | Token *tok; // for error message 366 | Token *name; 367 | int idx; 368 | int align; 369 | int offset; 370 | 371 | // Bitfield 372 | bool is_bitfield; 373 | int bit_offset; 374 | int bit_width; 375 | }; 376 | 377 | extern Type *ty_void; 378 | extern Type *ty_bool; 379 | 380 | extern Type *ty_char; 381 | extern Type *ty_short; 382 | extern Type *ty_int; 383 | extern Type *ty_long; 384 | 385 | extern Type *ty_uchar; 386 | extern Type *ty_ushort; 387 | extern Type *ty_uint; 388 | extern Type *ty_ulong; 389 | 390 | extern Type *ty_float; 391 | extern Type *ty_double; 392 | extern Type *ty_ldouble; 393 | 394 | bool is_integer(Type *ty); 395 | bool is_flonum(Type *ty); 396 | bool is_numeric(Type *ty); 397 | bool is_compatible(Type *t1, Type *t2); 398 | Type *copy_type(Type *ty); 399 | Type *pointer_to(Type *base); 400 | Type *func_type(Type *return_ty); 401 | Type *array_of(Type *base, int size); 402 | Type *vla_of(Type *base, Node *expr); 403 | Type *enum_type(void); 404 | Type *struct_type(void); 405 | void add_type(Node *node); 406 | 407 | // 408 | // codegen.c 409 | // 410 | 411 | void codegen(Obj *prog, FILE *out); 412 | int align_to(int n, int align); 413 | 414 | // 415 | // unicode.c 416 | // 417 | 418 | int encode_utf8(char *buf, uint32_t c); 419 | uint32_t decode_utf8(char **new_pos, char *p); 420 | bool is_ident1(uint32_t c); 421 | bool is_ident2(uint32_t c); 422 | int display_width(char *p, int len); 423 | 424 | // 425 | // hashmap.c 426 | // 427 | 428 | typedef struct { 429 | char *key; 430 | int keylen; 431 | void *val; 432 | } HashEntry; 433 | 434 | typedef struct { 435 | HashEntry *buckets; 436 | int capacity; 437 | int used; 438 | } HashMap; 439 | 440 | void *hashmap_get(HashMap *map, char *key); 441 | void *hashmap_get2(HashMap *map, char *key, int keylen); 442 | void hashmap_put(HashMap *map, char *key, void *val); 443 | void hashmap_put2(HashMap *map, char *key, int keylen, void *val); 444 | void hashmap_delete(HashMap *map, char *key); 445 | void hashmap_delete2(HashMap *map, char *key, int keylen); 446 | void hashmap_test(void); 447 | 448 | // 449 | // main.c 450 | // 451 | 452 | bool file_exists(char *path); 453 | 454 | extern StringArray include_paths; 455 | extern bool opt_fpic; 456 | extern bool opt_fcommon; 457 | extern char *base_file; 458 | -------------------------------------------------------------------------------- /hashmap.c: -------------------------------------------------------------------------------- 1 | // This is an implementation of the open-addressing hash table. 2 | 3 | #include "chibicc.h" 4 | 5 | // Initial hash bucket size 6 | #define INIT_SIZE 16 7 | 8 | // Rehash if the usage exceeds 70%. 9 | #define HIGH_WATERMARK 70 10 | 11 | // We'll keep the usage below 50% after rehashing. 12 | #define LOW_WATERMARK 50 13 | 14 | // Represents a deleted hash entry 15 | #define TOMBSTONE ((void *)-1) 16 | 17 | static uint64_t fnv_hash(char *s, int len) { 18 | uint64_t hash = 0xcbf29ce484222325; 19 | for (int i = 0; i < len; i++) { 20 | hash *= 0x100000001b3; 21 | hash ^= (unsigned char)s[i]; 22 | } 23 | return hash; 24 | } 25 | 26 | // Make room for new entires in a given hashmap by removing 27 | // tombstones and possibly extending the bucket size. 28 | static void rehash(HashMap *map) { 29 | // Compute the size of the new hashmap. 30 | int nkeys = 0; 31 | for (int i = 0; i < map->capacity; i++) 32 | if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) 33 | nkeys++; 34 | 35 | int cap = map->capacity; 36 | while ((nkeys * 100) / cap >= LOW_WATERMARK) 37 | cap = cap * 2; 38 | assert(cap > 0); 39 | 40 | // Create a new hashmap and copy all key-values. 41 | HashMap map2 = {}; 42 | map2.buckets = calloc(cap, sizeof(HashEntry)); 43 | map2.capacity = cap; 44 | 45 | for (int i = 0; i < map->capacity; i++) { 46 | HashEntry *ent = &map->buckets[i]; 47 | if (ent->key && ent->key != TOMBSTONE) 48 | hashmap_put2(&map2, ent->key, ent->keylen, ent->val); 49 | } 50 | 51 | assert(map2.used == nkeys); 52 | *map = map2; 53 | } 54 | 55 | static bool match(HashEntry *ent, char *key, int keylen) { 56 | return ent->key && ent->key != TOMBSTONE && 57 | ent->keylen == keylen && memcmp(ent->key, key, keylen) == 0; 58 | } 59 | 60 | static HashEntry *get_entry(HashMap *map, char *key, int keylen) { 61 | if (!map->buckets) 62 | return NULL; 63 | 64 | uint64_t hash = fnv_hash(key, keylen); 65 | 66 | for (int i = 0; i < map->capacity; i++) { 67 | HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; 68 | if (match(ent, key, keylen)) 69 | return ent; 70 | if (ent->key == NULL) 71 | return NULL; 72 | } 73 | unreachable(); 74 | } 75 | 76 | static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) { 77 | if (!map->buckets) { 78 | map->buckets = calloc(INIT_SIZE, sizeof(HashEntry)); 79 | map->capacity = INIT_SIZE; 80 | } else if ((map->used * 100) / map->capacity >= HIGH_WATERMARK) { 81 | rehash(map); 82 | } 83 | 84 | uint64_t hash = fnv_hash(key, keylen); 85 | 86 | for (int i = 0; i < map->capacity; i++) { 87 | HashEntry *ent = &map->buckets[(hash + i) % map->capacity]; 88 | 89 | if (match(ent, key, keylen)) 90 | return ent; 91 | 92 | if (ent->key == TOMBSTONE) { 93 | ent->key = key; 94 | ent->keylen = keylen; 95 | return ent; 96 | } 97 | 98 | if (ent->key == NULL) { 99 | ent->key = key; 100 | ent->keylen = keylen; 101 | map->used++; 102 | return ent; 103 | } 104 | } 105 | unreachable(); 106 | } 107 | 108 | void *hashmap_get(HashMap *map, char *key) { 109 | return hashmap_get2(map, key, strlen(key)); 110 | } 111 | 112 | void *hashmap_get2(HashMap *map, char *key, int keylen) { 113 | HashEntry *ent = get_entry(map, key, keylen); 114 | return ent ? ent->val : NULL; 115 | } 116 | 117 | void hashmap_put(HashMap *map, char *key, void *val) { 118 | hashmap_put2(map, key, strlen(key), val); 119 | } 120 | 121 | void hashmap_put2(HashMap *map, char *key, int keylen, void *val) { 122 | HashEntry *ent = get_or_insert_entry(map, key, keylen); 123 | ent->val = val; 124 | } 125 | 126 | void hashmap_delete(HashMap *map, char *key) { 127 | hashmap_delete2(map, key, strlen(key)); 128 | } 129 | 130 | void hashmap_delete2(HashMap *map, char *key, int keylen) { 131 | HashEntry *ent = get_entry(map, key, keylen); 132 | if (ent) 133 | ent->key = TOMBSTONE; 134 | } 135 | 136 | void hashmap_test(void) { 137 | HashMap *map = calloc(1, sizeof(HashMap)); 138 | 139 | for (int i = 0; i < 5000; i++) 140 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 141 | for (int i = 1000; i < 2000; i++) 142 | hashmap_delete(map, format("key %d", i)); 143 | for (int i = 1500; i < 1600; i++) 144 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 145 | for (int i = 6000; i < 7000; i++) 146 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 147 | 148 | for (int i = 0; i < 1000; i++) 149 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 150 | for (int i = 1000; i < 1500; i++) 151 | assert(hashmap_get(map, "no such key") == NULL); 152 | for (int i = 1500; i < 1600; i++) 153 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 154 | for (int i = 1600; i < 2000; i++) 155 | assert(hashmap_get(map, "no such key") == NULL); 156 | for (int i = 2000; i < 5000; i++) 157 | assert((size_t)hashmap_get(map, format("key %d", i)) == i); 158 | for (int i = 5000; i < 6000; i++) 159 | assert(hashmap_get(map, "no such key") == NULL); 160 | for (int i = 6000; i < 7000; i++) 161 | hashmap_put(map, format("key %d", i), (void *)(size_t)i); 162 | 163 | assert(hashmap_get(map, "no such key") == NULL); 164 | printf("OK\n"); 165 | } 166 | -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDFLOAT_H 2 | #define __STDFLOAT_H 3 | 4 | #define DECIMAL_DIG 21 5 | #define FLT_EVAL_METHOD 0 // C11 5.2.4.2.2p9 6 | #define FLT_RADIX 2 7 | #define FLT_ROUNDS 1 // C11 5.2.4.2.2p8: to nearest 8 | 9 | #define FLT_DIG 6 10 | #define FLT_EPSILON 0x1p-23 11 | #define FLT_MANT_DIG 24 12 | #define FLT_MAX 0x1.fffffep+127 13 | #define FLT_MAX_10_EXP 38 14 | #define FLT_MAX_EXP 128 15 | #define FLT_MIN 0x1p-126 16 | #define FLT_MIN_10_EXP -37 17 | #define FLT_MIN_EXP -125 18 | #define FLT_TRUE_MIN 0x1p-149 19 | 20 | #define DBL_DIG 15 21 | #define DBL_EPSILON 0x1p-52 22 | #define DBL_MANT_DIG 53 23 | #define DBL_MAX 0x1.fffffffffffffp+1023 24 | #define DBL_MAX_10_EXP 308 25 | #define DBL_MAX_EXP 1024 26 | #define DBL_MIN 0x1p-1022 27 | #define DBL_MIN_10_EXP -307 28 | #define DBL_MIN_EXP -1021 29 | #define DBL_TRUE_MIN 0x0.0000000000001p-1022 30 | 31 | #define LDBL_DIG 15 32 | #define LDBL_EPSILON 0x1p-52 33 | #define LDBL_MANT_DIG 53 34 | #define LDBL_MAX 0x1.fffffffffffffp+1023 35 | #define LDBL_MAX_10_EXP 308 36 | #define LDBL_MAX_EXP 1024 37 | #define LDBL_MIN 0x1p-1022 38 | #define LDBL_MIN_10_EXP -307 39 | #define LDBL_MIN_EXP -1021 40 | #define LDBL_TRUE_MIN 0x0.0000000000001p-1022 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/stdalign.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDALIGN_H 2 | #define __STDALIGN_H 3 | 4 | #define alignas _Alignas 5 | #define alignof _Alignof 6 | #define __alignas_is_defined 1 7 | #define __alignof_is_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDARG_H 2 | #define __STDARG_H 3 | 4 | typedef struct { 5 | unsigned int gp_offset; 6 | unsigned int fp_offset; 7 | void *overflow_arg_area; 8 | void *reg_save_area; 9 | } __va_elem; 10 | 11 | typedef __va_elem va_list[1]; 12 | 13 | #define va_start(ap, last) \ 14 | do { *(ap) = *(__va_elem *)__va_area__; } while (0) 15 | 16 | #define va_end(ap) 17 | 18 | static void *__va_arg_mem(__va_elem *ap, int sz, int align) { 19 | void *p = ap->overflow_arg_area; 20 | if (align > 8) 21 | p = (p + 15) / 16 * 16; 22 | ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8; 23 | return p; 24 | } 25 | 26 | static void *__va_arg_gp(__va_elem *ap, int sz, int align) { 27 | if (ap->gp_offset >= 48) 28 | return __va_arg_mem(ap, sz, align); 29 | 30 | void *r = ap->reg_save_area + ap->gp_offset; 31 | ap->gp_offset += 8; 32 | return r; 33 | } 34 | 35 | static void *__va_arg_fp(__va_elem *ap, int sz, int align) { 36 | if (ap->fp_offset >= 112) 37 | return __va_arg_mem(ap, sz, align); 38 | 39 | void *r = ap->reg_save_area + ap->fp_offset; 40 | ap->fp_offset += 8; 41 | return r; 42 | } 43 | 44 | #define va_arg(ap, ty) \ 45 | ({ \ 46 | int klass = __builtin_reg_class(ty); \ 47 | *(ty *)(klass == 0 ? __va_arg_gp(ap, sizeof(ty), _Alignof(ty)) : \ 48 | klass == 1 ? __va_arg_fp(ap, sizeof(ty), _Alignof(ty)) : \ 49 | __va_arg_mem(ap, sizeof(ty), _Alignof(ty))); \ 50 | }) 51 | 52 | #define va_copy(dest, src) ((dest)[0] = (src)[0]) 53 | 54 | #define __GNUC_VA_LIST 1 55 | typedef va_list __gnuc_va_list; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/stdatomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDATOMIC_H 2 | #define __STDATOMIC_H 3 | 4 | #define ATOMIC_BOOL_LOCK_FREE 1 5 | #define ATOMIC_CHAR_LOCK_FREE 1 6 | #define ATOMIC_CHAR16_T_LOCK_FREE 1 7 | #define ATOMIC_CHAR32_T_LOCK_FREE 1 8 | #define ATOMIC_WCHAR_T_LOCK_FREE 1 9 | #define ATOMIC_SHORT_LOCK_FREE 1 10 | #define ATOMIC_INT_LOCK_FREE 1 11 | #define ATOMIC_LONG_LOCK_FREE 1 12 | #define ATOMIC_LLONG_LOCK_FREE 1 13 | #define ATOMIC_POINTER_LOCK_FREE 1 14 | 15 | typedef enum { 16 | memory_order_relaxed, 17 | memory_order_consume, 18 | memory_order_acquire, 19 | memory_order_release, 20 | memory_order_acq_rel, 21 | memory_order_seq_cst, 22 | } memory_order; 23 | 24 | #define ATOMIC_FLAG_INIT(x) (x) 25 | #define atomic_init(addr, val) (*(addr) = (val)) 26 | #define kill_dependency(x) (x) 27 | #define atomic_thread_fence(order) 28 | #define atomic_signal_fence(order) 29 | #define atomic_is_lock_free(x) 1 30 | 31 | #define atomic_load(addr) (*(addr)) 32 | #define atomic_store(addr, val) (*(addr) = (val)) 33 | 34 | #define atomic_load_explicit(addr, order) (*(addr)) 35 | #define atomic_store_explicit(addr, val, order) (*(addr) = (val)) 36 | 37 | #define atomic_fetch_add(obj, val) (*(obj) += (val)) 38 | #define atomic_fetch_sub(obj, val) (*(obj) -= (val)) 39 | #define atomic_fetch_or(obj, val) (*(obj) |= (val)) 40 | #define atomic_fetch_xor(obj, val) (*(obj) ^= (val)) 41 | #define atomic_fetch_and(obj, val) (*(obj) &= (val)) 42 | 43 | #define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val)) 44 | #define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val)) 45 | #define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val)) 46 | #define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val)) 47 | #define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val)) 48 | 49 | #define atomic_compare_exchange_weak(p, old, new) \ 50 | __builtin_compare_and_swap((p), (old), (new)) 51 | 52 | #define atomic_compare_exchange_strong(p, old, new) \ 53 | __builtin_compare_and_swap((p), (old), (new)) 54 | 55 | #define atomic_exchange(obj, val) __builtin_atomic_exchange((obj), (val)) 56 | #define atomic_exchange_explicit(obj, val, order) __builtin_atomic_exchange((obj), (val)) 57 | 58 | #define atomic_flag_test_and_set(obj) atomic_exchange((obj), 1) 59 | #define atomic_flag_test_and_set_explicit(obj, order) atomic_exchange((obj), 1) 60 | #define atomic_flag_clear(obj) (*(obj) = 0) 61 | #define atomic_flag_clear_explicit(obj, order) (*(obj) = 0) 62 | 63 | typedef _Atomic _Bool atomic_flag; 64 | typedef _Atomic _Bool atomic_bool; 65 | typedef _Atomic char atomic_char; 66 | typedef _Atomic signed char atomic_schar; 67 | typedef _Atomic unsigned char atomic_uchar; 68 | typedef _Atomic short atomic_short; 69 | typedef _Atomic unsigned short atomic_ushort; 70 | typedef _Atomic int atomic_int; 71 | typedef _Atomic unsigned int atomic_uint; 72 | typedef _Atomic long atomic_long; 73 | typedef _Atomic unsigned long atomic_ulong; 74 | typedef _Atomic long long atomic_llong; 75 | typedef _Atomic unsigned long long atomic_ullong; 76 | typedef _Atomic unsigned short atomic_char16_t; 77 | typedef _Atomic unsigned atomic_char32_t; 78 | typedef _Atomic unsigned atomic_wchar_t; 79 | typedef _Atomic signed char atomic_int_least8_t; 80 | typedef _Atomic unsigned char atomic_uint_least8_t; 81 | typedef _Atomic short atomic_int_least16_t; 82 | typedef _Atomic unsigned short atomic_uint_least16_t; 83 | typedef _Atomic int atomic_int_least32_t; 84 | typedef _Atomic unsigned int atomic_uint_least32_t; 85 | typedef _Atomic long atomic_int_least64_t; 86 | typedef _Atomic unsigned long atomic_uint_least64_t; 87 | typedef _Atomic signed char atomic_int_fast8_t; 88 | typedef _Atomic unsigned char atomic_uint_fast8_t; 89 | typedef _Atomic short atomic_int_fast16_t; 90 | typedef _Atomic unsigned short atomic_uint_fast16_t; 91 | typedef _Atomic int atomic_int_fast32_t; 92 | typedef _Atomic unsigned int atomic_uint_fast32_t; 93 | typedef _Atomic long atomic_int_fast64_t; 94 | typedef _Atomic unsigned long atomic_uint_fast64_t; 95 | typedef _Atomic long atomic_intptr_t; 96 | typedef _Atomic unsigned long atomic_uintptr_t; 97 | typedef _Atomic unsigned long atomic_size_t; 98 | typedef _Atomic long atomic_ptrdiff_t; 99 | typedef _Atomic long atomic_intmax_t; 100 | typedef _Atomic unsigned long atomic_uintmax_t; 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDDEF_H 2 | #define __STDDEF_H 3 | 4 | #define NULL ((void *)0) 5 | 6 | typedef unsigned long size_t; 7 | typedef long ptrdiff_t; 8 | typedef unsigned int wchar_t; 9 | typedef long max_align_t; 10 | 11 | #define offsetof(type, member) ((size_t)&(((type *)0)->member)) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDNORETURN_H 2 | #define __STDNORETURN_H 3 | 4 | #define noreturn _Noreturn 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "chibicc.h" 2 | 3 | typedef enum { 4 | FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO, 5 | } FileType; 6 | 7 | StringArray include_paths; 8 | bool opt_fcommon = true; 9 | bool opt_fpic; 10 | 11 | static FileType opt_x; 12 | static StringArray opt_include; 13 | static bool opt_E; 14 | static bool opt_M; 15 | static bool opt_MD; 16 | static bool opt_MMD; 17 | static bool opt_MP; 18 | static bool opt_S; 19 | static bool opt_c; 20 | static bool opt_cc1; 21 | static bool opt_hash_hash_hash; 22 | static bool opt_static; 23 | static bool opt_shared; 24 | static char *opt_MF; 25 | static char *opt_MT; 26 | static char *opt_o; 27 | 28 | static StringArray ld_extra_args; 29 | static StringArray std_include_paths; 30 | 31 | char *base_file; 32 | static char *output_file; 33 | 34 | static StringArray input_paths; 35 | static StringArray tmpfiles; 36 | 37 | static void usage(int status) { 38 | fprintf(stderr, "chibicc [ -o ] \n"); 39 | exit(status); 40 | } 41 | 42 | static bool take_arg(char *arg) { 43 | char *x[] = { 44 | "-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker", 45 | }; 46 | 47 | for (int i = 0; i < sizeof(x) / sizeof(*x); i++) 48 | if (!strcmp(arg, x[i])) 49 | return true; 50 | return false; 51 | } 52 | 53 | static void add_default_include_paths(char *argv0) { 54 | // We expect that chibicc-specific include files are installed 55 | // to ./include relative to argv[0]. 56 | strarray_push(&include_paths, format("%s/include", dirname(strdup(argv0)))); 57 | 58 | // Add standard include paths. 59 | strarray_push(&include_paths, "/usr/local/include"); 60 | strarray_push(&include_paths, "/usr/include/x86_64-linux-gnu"); 61 | strarray_push(&include_paths, "/usr/include"); 62 | 63 | // Keep a copy of the standard include paths for -MMD option. 64 | for (int i = 0; i < include_paths.len; i++) 65 | strarray_push(&std_include_paths, include_paths.data[i]); 66 | } 67 | 68 | static void define(char *str) { 69 | char *eq = strchr(str, '='); 70 | if (eq) 71 | define_macro(strndup(str, eq - str), eq + 1); 72 | else 73 | define_macro(str, "1"); 74 | } 75 | 76 | static FileType parse_opt_x(char *s) { 77 | if (!strcmp(s, "c")) 78 | return FILE_C; 79 | if (!strcmp(s, "assembler")) 80 | return FILE_ASM; 81 | if (!strcmp(s, "none")) 82 | return FILE_NONE; 83 | error(": unknown argument for -x: %s", s); 84 | } 85 | 86 | static char *quote_makefile(char *s) { 87 | char *buf = calloc(1, strlen(s) * 2 + 1); 88 | 89 | for (int i = 0, j = 0; s[i]; i++) { 90 | switch (s[i]) { 91 | case '$': 92 | buf[j++] = '$'; 93 | buf[j++] = '$'; 94 | break; 95 | case '#': 96 | buf[j++] = '\\'; 97 | buf[j++] = '#'; 98 | break; 99 | case ' ': 100 | case '\t': 101 | for (int k = i - 1; k >= 0 && s[k] == '\\'; k--) 102 | buf[j++] = '\\'; 103 | buf[j++] = '\\'; 104 | buf[j++] = s[i]; 105 | break; 106 | default: 107 | buf[j++] = s[i]; 108 | break; 109 | } 110 | } 111 | return buf; 112 | } 113 | 114 | static void parse_args(int argc, char **argv) { 115 | // Make sure that all command line options that take an argument 116 | // have an argument. 117 | for (int i = 1; i < argc; i++) 118 | if (take_arg(argv[i])) 119 | if (!argv[++i]) 120 | usage(1); 121 | 122 | StringArray idirafter = {}; 123 | 124 | for (int i = 1; i < argc; i++) { 125 | if (!strcmp(argv[i], "-###")) { 126 | opt_hash_hash_hash = true; 127 | continue; 128 | } 129 | 130 | if (!strcmp(argv[i], "-cc1")) { 131 | opt_cc1 = true; 132 | continue; 133 | } 134 | 135 | if (!strcmp(argv[i], "--help")) 136 | usage(0); 137 | 138 | if (!strcmp(argv[i], "-o")) { 139 | opt_o = argv[++i]; 140 | continue; 141 | } 142 | 143 | if (!strncmp(argv[i], "-o", 2)) { 144 | opt_o = argv[i] + 2; 145 | continue; 146 | } 147 | 148 | if (!strcmp(argv[i], "-S")) { 149 | opt_S = true; 150 | continue; 151 | } 152 | 153 | if (!strcmp(argv[i], "-fcommon")) { 154 | opt_fcommon = true; 155 | continue; 156 | } 157 | 158 | if (!strcmp(argv[i], "-fno-common")) { 159 | opt_fcommon = false; 160 | continue; 161 | } 162 | 163 | if (!strcmp(argv[i], "-c")) { 164 | opt_c = true; 165 | continue; 166 | } 167 | 168 | if (!strcmp(argv[i], "-E")) { 169 | opt_E = true; 170 | continue; 171 | } 172 | 173 | if (!strncmp(argv[i], "-I", 2)) { 174 | strarray_push(&include_paths, argv[i] + 2); 175 | continue; 176 | } 177 | 178 | if (!strcmp(argv[i], "-D")) { 179 | define(argv[++i]); 180 | continue; 181 | } 182 | 183 | if (!strncmp(argv[i], "-D", 2)) { 184 | define(argv[i] + 2); 185 | continue; 186 | } 187 | 188 | if (!strcmp(argv[i], "-U")) { 189 | undef_macro(argv[++i]); 190 | continue; 191 | } 192 | 193 | if (!strncmp(argv[i], "-U", 2)) { 194 | undef_macro(argv[i] + 2); 195 | continue; 196 | } 197 | 198 | if (!strcmp(argv[i], "-include")) { 199 | strarray_push(&opt_include, argv[++i]); 200 | continue; 201 | } 202 | 203 | if (!strcmp(argv[i], "-x")) { 204 | opt_x = parse_opt_x(argv[++i]); 205 | continue; 206 | } 207 | 208 | if (!strncmp(argv[i], "-x", 2)) { 209 | opt_x = parse_opt_x(argv[i] + 2); 210 | continue; 211 | } 212 | 213 | if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) { 214 | strarray_push(&input_paths, argv[i]); 215 | continue; 216 | } 217 | 218 | if (!strcmp(argv[i], "-Xlinker")) { 219 | strarray_push(&ld_extra_args, argv[++i]); 220 | continue; 221 | } 222 | 223 | if (!strcmp(argv[i], "-s")) { 224 | strarray_push(&ld_extra_args, "-s"); 225 | continue; 226 | } 227 | 228 | if (!strcmp(argv[i], "-M")) { 229 | opt_M = true; 230 | continue; 231 | } 232 | 233 | if (!strcmp(argv[i], "-MF")) { 234 | opt_MF = argv[++i]; 235 | continue; 236 | } 237 | 238 | if (!strcmp(argv[i], "-MP")) { 239 | opt_MP = true; 240 | continue; 241 | } 242 | 243 | if (!strcmp(argv[i], "-MT")) { 244 | if (opt_MT == NULL) 245 | opt_MT = argv[++i]; 246 | else 247 | opt_MT = format("%s %s", opt_MT, argv[++i]); 248 | continue; 249 | } 250 | 251 | if (!strcmp(argv[i], "-MD")) { 252 | opt_MD = true; 253 | continue; 254 | } 255 | 256 | if (!strcmp(argv[i], "-MQ")) { 257 | if (opt_MT == NULL) 258 | opt_MT = quote_makefile(argv[++i]); 259 | else 260 | opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i])); 261 | continue; 262 | } 263 | 264 | if (!strcmp(argv[i], "-MMD")) { 265 | opt_MD = opt_MMD = true; 266 | continue; 267 | } 268 | 269 | if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) { 270 | opt_fpic = true; 271 | continue; 272 | } 273 | 274 | if (!strcmp(argv[i], "-cc1-input")) { 275 | base_file = argv[++i]; 276 | continue; 277 | } 278 | 279 | if (!strcmp(argv[i], "-cc1-output")) { 280 | output_file = argv[++i]; 281 | continue; 282 | } 283 | 284 | if (!strcmp(argv[i], "-idirafter")) { 285 | strarray_push(&idirafter, argv[i++]); 286 | continue; 287 | } 288 | 289 | if (!strcmp(argv[i], "-static")) { 290 | opt_static = true; 291 | strarray_push(&ld_extra_args, "-static"); 292 | continue; 293 | } 294 | 295 | if (!strcmp(argv[i], "-shared")) { 296 | opt_shared = true; 297 | strarray_push(&ld_extra_args, "-shared"); 298 | continue; 299 | } 300 | 301 | if (!strcmp(argv[i], "-L")) { 302 | strarray_push(&ld_extra_args, "-L"); 303 | strarray_push(&ld_extra_args, argv[++i]); 304 | continue; 305 | } 306 | 307 | if (!strncmp(argv[i], "-L", 2)) { 308 | strarray_push(&ld_extra_args, "-L"); 309 | strarray_push(&ld_extra_args, argv[i] + 2); 310 | continue; 311 | } 312 | 313 | if (!strcmp(argv[i], "-hashmap-test")) { 314 | hashmap_test(); 315 | exit(0); 316 | } 317 | 318 | // These options are ignored for now. 319 | if (!strncmp(argv[i], "-O", 2) || 320 | !strncmp(argv[i], "-W", 2) || 321 | !strncmp(argv[i], "-g", 2) || 322 | !strncmp(argv[i], "-std=", 5) || 323 | !strcmp(argv[i], "-ffreestanding") || 324 | !strcmp(argv[i], "-fno-builtin") || 325 | !strcmp(argv[i], "-fno-omit-frame-pointer") || 326 | !strcmp(argv[i], "-fno-stack-protector") || 327 | !strcmp(argv[i], "-fno-strict-aliasing") || 328 | !strcmp(argv[i], "-m64") || 329 | !strcmp(argv[i], "-mno-red-zone") || 330 | !strcmp(argv[i], "-w")) 331 | continue; 332 | 333 | if (argv[i][0] == '-' && argv[i][1] != '\0') 334 | error("unknown argument: %s", argv[i]); 335 | 336 | strarray_push(&input_paths, argv[i]); 337 | } 338 | 339 | for (int i = 0; i < idirafter.len; i++) 340 | strarray_push(&include_paths, idirafter.data[i]); 341 | 342 | if (input_paths.len == 0) 343 | error("no input files"); 344 | 345 | // -E implies that the input is the C macro language. 346 | if (opt_E) 347 | opt_x = FILE_C; 348 | } 349 | 350 | static FILE *open_file(char *path) { 351 | if (!path || strcmp(path, "-") == 0) 352 | return stdout; 353 | 354 | FILE *out = fopen(path, "w"); 355 | if (!out) 356 | error("cannot open output file: %s: %s", path, strerror(errno)); 357 | return out; 358 | } 359 | 360 | static bool endswith(char *p, char *q) { 361 | int len1 = strlen(p); 362 | int len2 = strlen(q); 363 | return (len1 >= len2) && !strcmp(p + len1 - len2, q); 364 | } 365 | 366 | // Replace file extension 367 | static char *replace_extn(char *tmpl, char *extn) { 368 | char *filename = basename(strdup(tmpl)); 369 | char *dot = strrchr(filename, '.'); 370 | if (dot) 371 | *dot = '\0'; 372 | return format("%s%s", filename, extn); 373 | } 374 | 375 | static void cleanup(void) { 376 | for (int i = 0; i < tmpfiles.len; i++) 377 | unlink(tmpfiles.data[i]); 378 | } 379 | 380 | static char *create_tmpfile(void) { 381 | char *path = strdup("/tmp/chibicc-XXXXXX"); 382 | int fd = mkstemp(path); 383 | if (fd == -1) 384 | error("mkstemp failed: %s", strerror(errno)); 385 | close(fd); 386 | 387 | strarray_push(&tmpfiles, path); 388 | return path; 389 | } 390 | 391 | static void run_subprocess(char **argv) { 392 | // If -### is given, dump the subprocess's command line. 393 | if (opt_hash_hash_hash) { 394 | fprintf(stderr, "%s", argv[0]); 395 | for (int i = 1; argv[i]; i++) 396 | fprintf(stderr, " %s", argv[i]); 397 | fprintf(stderr, "\n"); 398 | } 399 | 400 | if (fork() == 0) { 401 | // Child process. Run a new command. 402 | execvp(argv[0], argv); 403 | fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno)); 404 | _exit(1); 405 | } 406 | 407 | // Wait for the child process to finish. 408 | int status; 409 | while (wait(&status) > 0); 410 | if (status != 0) 411 | exit(1); 412 | } 413 | 414 | static void run_cc1(int argc, char **argv, char *input, char *output) { 415 | char **args = calloc(argc + 10, sizeof(char *)); 416 | memcpy(args, argv, argc * sizeof(char *)); 417 | args[argc++] = "-cc1"; 418 | 419 | if (input) { 420 | args[argc++] = "-cc1-input"; 421 | args[argc++] = input; 422 | } 423 | 424 | if (output) { 425 | args[argc++] = "-cc1-output"; 426 | args[argc++] = output; 427 | } 428 | 429 | run_subprocess(args); 430 | } 431 | 432 | // Print tokens to stdout. Used for -E. 433 | static void print_tokens(Token *tok) { 434 | FILE *out = open_file(opt_o ? opt_o : "-"); 435 | 436 | int line = 1; 437 | for (; tok->kind != TK_EOF; tok = tok->next) { 438 | if (line > 1 && tok->at_bol) 439 | fprintf(out, "\n"); 440 | if (tok->has_space && !tok->at_bol) 441 | fprintf(out, " "); 442 | fprintf(out, "%.*s", tok->len, tok->loc); 443 | line++; 444 | } 445 | fprintf(out, "\n"); 446 | } 447 | 448 | static bool in_std_include_path(char *path) { 449 | for (int i = 0; i < std_include_paths.len; i++) { 450 | char *dir = std_include_paths.data[i]; 451 | int len = strlen(dir); 452 | if (strncmp(dir, path, len) == 0 && path[len] == '/') 453 | return true; 454 | } 455 | return false; 456 | } 457 | 458 | // If -M options is given, the compiler write a list of input files to 459 | // stdout in a format that "make" command can read. This feature is 460 | // used to automate file dependency management. 461 | static void print_dependencies(void) { 462 | char *path; 463 | if (opt_MF) 464 | path = opt_MF; 465 | else if (opt_MD) 466 | path = replace_extn(opt_o ? opt_o : base_file, ".d"); 467 | else if (opt_o) 468 | path = opt_o; 469 | else 470 | path = "-"; 471 | 472 | FILE *out = open_file(path); 473 | if (opt_MT) 474 | fprintf(out, "%s:", opt_MT); 475 | else 476 | fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o"))); 477 | 478 | File **files = get_input_files(); 479 | 480 | for (int i = 0; files[i]; i++) { 481 | if (opt_MMD && in_std_include_path(files[i]->name)) 482 | continue; 483 | fprintf(out, " \\\n %s", files[i]->name); 484 | } 485 | 486 | fprintf(out, "\n\n"); 487 | 488 | if (opt_MP) { 489 | for (int i = 1; files[i]; i++) { 490 | if (opt_MMD && in_std_include_path(files[i]->name)) 491 | continue; 492 | fprintf(out, "%s:\n\n", quote_makefile(files[i]->name)); 493 | } 494 | } 495 | } 496 | 497 | static Token *must_tokenize_file(char *path) { 498 | Token *tok = tokenize_file(path); 499 | if (!tok) 500 | error("%s: %s", path, strerror(errno)); 501 | return tok; 502 | } 503 | 504 | static Token *append_tokens(Token *tok1, Token *tok2) { 505 | if (!tok1 || tok1->kind == TK_EOF) 506 | return tok2; 507 | 508 | Token *t = tok1; 509 | while (t->next->kind != TK_EOF) 510 | t = t->next; 511 | t->next = tok2; 512 | return tok1; 513 | } 514 | 515 | static void cc1(void) { 516 | Token *tok = NULL; 517 | 518 | // Process -include option 519 | for (int i = 0; i < opt_include.len; i++) { 520 | char *incl = opt_include.data[i]; 521 | 522 | char *path; 523 | if (file_exists(incl)) { 524 | path = incl; 525 | } else { 526 | path = search_include_paths(incl); 527 | if (!path) 528 | error("-include: %s: %s", incl, strerror(errno)); 529 | } 530 | 531 | Token *tok2 = must_tokenize_file(path); 532 | tok = append_tokens(tok, tok2); 533 | } 534 | 535 | // Tokenize and parse. 536 | Token *tok2 = must_tokenize_file(base_file); 537 | tok = append_tokens(tok, tok2); 538 | tok = preprocess(tok); 539 | 540 | // If -M or -MD are given, print file dependencies. 541 | if (opt_M || opt_MD) { 542 | print_dependencies(); 543 | if (opt_M) 544 | return; 545 | } 546 | 547 | // If -E is given, print out preprocessed C code as a result. 548 | if (opt_E) { 549 | print_tokens(tok); 550 | return; 551 | } 552 | 553 | Obj *prog = parse(tok); 554 | 555 | // Open a temporary output buffer. 556 | char *buf; 557 | size_t buflen; 558 | FILE *output_buf = open_memstream(&buf, &buflen); 559 | 560 | // Traverse the AST to emit assembly. 561 | codegen(prog, output_buf); 562 | fclose(output_buf); 563 | 564 | // Write the asembly text to a file. 565 | FILE *out = open_file(output_file); 566 | fwrite(buf, buflen, 1, out); 567 | fclose(out); 568 | } 569 | 570 | static void assemble(char *input, char *output) { 571 | char *cmd[] = {"as", "-c", input, "-o", output, NULL}; 572 | run_subprocess(cmd); 573 | } 574 | 575 | static char *find_file(char *pattern) { 576 | char *path = NULL; 577 | glob_t buf = {}; 578 | glob(pattern, 0, NULL, &buf); 579 | if (buf.gl_pathc > 0) 580 | path = strdup(buf.gl_pathv[buf.gl_pathc - 1]); 581 | globfree(&buf); 582 | return path; 583 | } 584 | 585 | // Returns true if a given file exists. 586 | bool file_exists(char *path) { 587 | struct stat st; 588 | return !stat(path, &st); 589 | } 590 | 591 | static char *find_libpath(void) { 592 | if (file_exists("/usr/lib/x86_64-linux-gnu/crti.o")) 593 | return "/usr/lib/x86_64-linux-gnu"; 594 | if (file_exists("/usr/lib64/crti.o")) 595 | return "/usr/lib64"; 596 | error("library path is not found"); 597 | } 598 | 599 | static char *find_gcc_libpath(void) { 600 | char *paths[] = { 601 | "/usr/lib/gcc/x86_64-linux-gnu/*/crtbegin.o", 602 | "/usr/lib/gcc/x86_64-pc-linux-gnu/*/crtbegin.o", // For Gentoo 603 | "/usr/lib/gcc/x86_64-redhat-linux/*/crtbegin.o", // For Fedora 604 | }; 605 | 606 | for (int i = 0; i < sizeof(paths) / sizeof(*paths); i++) { 607 | char *path = find_file(paths[i]); 608 | if (path) 609 | return dirname(path); 610 | } 611 | 612 | error("gcc library path is not found"); 613 | } 614 | 615 | static void run_linker(StringArray *inputs, char *output) { 616 | StringArray arr = {}; 617 | 618 | strarray_push(&arr, "ld"); 619 | strarray_push(&arr, "-o"); 620 | strarray_push(&arr, output); 621 | strarray_push(&arr, "-m"); 622 | strarray_push(&arr, "elf_x86_64"); 623 | 624 | char *libpath = find_libpath(); 625 | char *gcc_libpath = find_gcc_libpath(); 626 | 627 | if (opt_shared) { 628 | strarray_push(&arr, format("%s/crti.o", libpath)); 629 | strarray_push(&arr, format("%s/crtbeginS.o", gcc_libpath)); 630 | } else { 631 | strarray_push(&arr, format("%s/crt1.o", libpath)); 632 | strarray_push(&arr, format("%s/crti.o", libpath)); 633 | strarray_push(&arr, format("%s/crtbegin.o", gcc_libpath)); 634 | } 635 | 636 | strarray_push(&arr, format("-L%s", gcc_libpath)); 637 | strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu"); 638 | strarray_push(&arr, "-L/usr/lib64"); 639 | strarray_push(&arr, "-L/lib64"); 640 | strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu"); 641 | strarray_push(&arr, "-L/usr/lib/x86_64-pc-linux-gnu"); 642 | strarray_push(&arr, "-L/usr/lib/x86_64-redhat-linux"); 643 | strarray_push(&arr, "-L/usr/lib"); 644 | strarray_push(&arr, "-L/lib"); 645 | 646 | if (!opt_static) { 647 | strarray_push(&arr, "-dynamic-linker"); 648 | strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2"); 649 | } 650 | 651 | for (int i = 0; i < ld_extra_args.len; i++) 652 | strarray_push(&arr, ld_extra_args.data[i]); 653 | 654 | for (int i = 0; i < inputs->len; i++) 655 | strarray_push(&arr, inputs->data[i]); 656 | 657 | if (opt_static) { 658 | strarray_push(&arr, "--start-group"); 659 | strarray_push(&arr, "-lgcc"); 660 | strarray_push(&arr, "-lgcc_eh"); 661 | strarray_push(&arr, "-lc"); 662 | strarray_push(&arr, "--end-group"); 663 | } else { 664 | strarray_push(&arr, "-lc"); 665 | strarray_push(&arr, "-lgcc"); 666 | strarray_push(&arr, "--as-needed"); 667 | strarray_push(&arr, "-lgcc_s"); 668 | strarray_push(&arr, "--no-as-needed"); 669 | } 670 | 671 | if (opt_shared) 672 | strarray_push(&arr, format("%s/crtendS.o", gcc_libpath)); 673 | else 674 | strarray_push(&arr, format("%s/crtend.o", gcc_libpath)); 675 | 676 | strarray_push(&arr, format("%s/crtn.o", libpath)); 677 | strarray_push(&arr, NULL); 678 | 679 | run_subprocess(arr.data); 680 | } 681 | 682 | static FileType get_file_type(char *filename) { 683 | if (opt_x != FILE_NONE) 684 | return opt_x; 685 | 686 | if (endswith(filename, ".a")) 687 | return FILE_AR; 688 | if (endswith(filename, ".so")) 689 | return FILE_DSO; 690 | if (endswith(filename, ".o")) 691 | return FILE_OBJ; 692 | if (endswith(filename, ".c")) 693 | return FILE_C; 694 | if (endswith(filename, ".s")) 695 | return FILE_ASM; 696 | 697 | error(": unknown file extension: %s", filename); 698 | } 699 | 700 | int main(int argc, char **argv) { 701 | atexit(cleanup); 702 | init_macros(); 703 | parse_args(argc, argv); 704 | 705 | if (opt_cc1) { 706 | add_default_include_paths(argv[0]); 707 | cc1(); 708 | return 0; 709 | } 710 | 711 | if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E)) 712 | error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files"); 713 | 714 | StringArray ld_args = {}; 715 | 716 | for (int i = 0; i < input_paths.len; i++) { 717 | char *input = input_paths.data[i]; 718 | 719 | if (!strncmp(input, "-l", 2)) { 720 | strarray_push(&ld_args, input); 721 | continue; 722 | } 723 | 724 | if (!strncmp(input, "-Wl,", 4)) { 725 | char *s = strdup(input + 4); 726 | char *arg = strtok(s, ","); 727 | while (arg) { 728 | strarray_push(&ld_args, arg); 729 | arg = strtok(NULL, ","); 730 | } 731 | continue; 732 | } 733 | 734 | char *output; 735 | if (opt_o) 736 | output = opt_o; 737 | else if (opt_S) 738 | output = replace_extn(input, ".s"); 739 | else 740 | output = replace_extn(input, ".o"); 741 | 742 | FileType type = get_file_type(input); 743 | 744 | // Handle .o or .a 745 | if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) { 746 | strarray_push(&ld_args, input); 747 | continue; 748 | } 749 | 750 | // Handle .s 751 | if (type == FILE_ASM) { 752 | if (!opt_S) 753 | assemble(input, output); 754 | continue; 755 | } 756 | 757 | assert(type == FILE_C); 758 | 759 | // Just preprocess 760 | if (opt_E || opt_M) { 761 | run_cc1(argc, argv, input, NULL); 762 | continue; 763 | } 764 | 765 | // Compile 766 | if (opt_S) { 767 | run_cc1(argc, argv, input, output); 768 | continue; 769 | } 770 | 771 | // Compile and assemble 772 | if (opt_c) { 773 | char *tmp = create_tmpfile(); 774 | run_cc1(argc, argv, input, tmp); 775 | assemble(tmp, output); 776 | continue; 777 | } 778 | 779 | // Compile, assemble and link 780 | char *tmp1 = create_tmpfile(); 781 | char *tmp2 = create_tmpfile(); 782 | run_cc1(argc, argv, input, tmp1); 783 | assemble(tmp1, tmp2); 784 | strarray_push(&ld_args, tmp2); 785 | continue; 786 | } 787 | 788 | if (ld_args.len > 0) 789 | run_linker(&ld_args, opt_o ? opt_o : "a.out"); 790 | return 0; 791 | } 792 | -------------------------------------------------------------------------------- /strings.c: -------------------------------------------------------------------------------- 1 | #include "chibicc.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chibicc=$1 3 | 4 | tmp=`mktemp -d /tmp/chibicc-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 | ./chibicc -c -o $tmp/out $tmp/empty.c 20 | [ -f $tmp/out ] 21 | check -o 22 | 23 | # --help 24 | $chibicc --help 2>&1 | grep -q chibicc 25 | check --help 26 | 27 | # -S 28 | echo 'int main() {}' | $chibicc -S -o- -xc - | grep -q 'main:' 29 | check -S 30 | 31 | # Default output file 32 | rm -f $tmp/out.o $tmp/out.s 33 | echo 'int main() {}' > $tmp/out.c 34 | (cd $tmp; $OLDPWD/$chibicc -c out.c) 35 | [ -f $tmp/out.o ] 36 | check 'default output file' 37 | 38 | (cd $tmp; $OLDPWD/$chibicc -c -S out.c) 39 | [ -f $tmp/out.s ] 40 | check 'default output file' 41 | 42 | # Multiple input files 43 | rm -f $tmp/foo.o $tmp/bar.o 44 | echo 'int x;' > $tmp/foo.c 45 | echo 'int y;' > $tmp/bar.c 46 | (cd $tmp; $OLDPWD/$chibicc -c $tmp/foo.c $tmp/bar.c) 47 | [ -f $tmp/foo.o ] && [ -f $tmp/bar.o ] 48 | check 'multiple input files' 49 | 50 | rm -f $tmp/foo.s $tmp/bar.s 51 | echo 'int x;' > $tmp/foo.c 52 | echo 'int y;' > $tmp/bar.c 53 | (cd $tmp; $OLDPWD/$chibicc -c -S $tmp/foo.c $tmp/bar.c) 54 | [ -f $tmp/foo.s ] && [ -f $tmp/bar.s ] 55 | check 'multiple input files' 56 | 57 | # Run linker 58 | rm -f $tmp/foo 59 | echo 'int main() { return 0; }' | $chibicc -o $tmp/foo -xc -xc - 60 | $tmp/foo 61 | check linker 62 | 63 | rm -f $tmp/foo 64 | echo 'int bar(); int main() { return bar(); }' > $tmp/foo.c 65 | echo 'int bar() { return 42; }' > $tmp/bar.c 66 | $chibicc -o $tmp/foo $tmp/foo.c $tmp/bar.c 67 | $tmp/foo 68 | [ "$?" = 42 ] 69 | check linker 70 | 71 | # a.out 72 | rm -f $tmp/a.out 73 | echo 'int main() {}' > $tmp/foo.c 74 | (cd $tmp; $OLDPWD/$chibicc foo.c) 75 | [ -f $tmp/a.out ] 76 | check a.out 77 | 78 | # -E 79 | echo foo > $tmp/out 80 | echo "#include \"$tmp/out\"" | $chibicc -E -xc - | grep -q foo 81 | check -E 82 | 83 | echo foo > $tmp/out1 84 | echo "#include \"$tmp/out1\"" | $chibicc -E -o $tmp/out2 -xc - 85 | cat $tmp/out2 | grep -q foo 86 | check '-E and -o' 87 | 88 | # -I 89 | mkdir $tmp/dir 90 | echo foo > $tmp/dir/i-option-test 91 | echo "#include \"i-option-test\"" | $chibicc -I$tmp/dir -E -xc - | grep -q foo 92 | check -I 93 | 94 | # -D 95 | echo foo | $chibicc -Dfoo -E -xc - | grep -q 1 96 | check -D 97 | 98 | # -D 99 | echo foo | $chibicc -Dfoo=bar -E -xc - | grep -q bar 100 | check -D 101 | 102 | # -U 103 | echo foo | $chibicc -Dfoo=bar -Ufoo -E -xc - | grep -q foo 104 | check -U 105 | 106 | # ignored options 107 | $chibicc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \ 108 | -fno-omit-frame-pointer -fno-stack-protector -fno-strict-aliasing \ 109 | -m64 -mno-red-zone -w -o /dev/null $tmp/empty.c 110 | check 'ignored options' 111 | 112 | # BOM marker 113 | printf '\xef\xbb\xbfxyz\n' | $chibicc -E -o- -xc - | grep -q '^xyz' 114 | check 'BOM marker' 115 | 116 | # Inline functions 117 | echo 'inline void foo() {}' > $tmp/inline1.c 118 | echo 'inline void foo() {}' > $tmp/inline2.c 119 | echo 'int main() { return 0; }' > $tmp/inline3.c 120 | $chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c $tmp/inline3.c 121 | check inline 122 | 123 | echo 'extern inline void foo() {}' > $tmp/inline1.c 124 | echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c 125 | $chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c 126 | check inline 127 | 128 | echo 'static inline void f1() {}' | $chibicc -o- -S -xc - | grep -v -q f1: 129 | check inline 130 | 131 | echo 'static inline void f1() {} void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: 132 | check inline 133 | 134 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: 135 | check inline 136 | 137 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -v -q f2: 138 | check inline 139 | 140 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1: 141 | check inline 142 | 143 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2: 144 | check inline 145 | 146 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f1: 147 | check inline 148 | 149 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f2: 150 | check inline 151 | 152 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1: 153 | check inline 154 | 155 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f2: 156 | check inline 157 | 158 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1: 159 | check inline 160 | 161 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2: 162 | check inline 163 | 164 | # -idirafter 165 | mkdir -p $tmp/dir1 $tmp/dir2 166 | echo foo > $tmp/dir1/idirafter 167 | echo bar > $tmp/dir2/idirafter 168 | echo "#include \"idirafter\"" | $chibicc -I$tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q foo 169 | check -idirafter 170 | echo "#include \"idirafter\"" | $chibicc -idirafter $tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q bar 171 | check -idirafter 172 | 173 | # -fcommon 174 | echo 'int foo;' | $chibicc -S -o- -xc - | grep -q '\.comm foo' 175 | check '-fcommon (default)' 176 | 177 | echo 'int foo;' | $chibicc -fcommon -S -o- -xc - | grep -q '\.comm foo' 178 | check '-fcommon' 179 | 180 | # -fno-common 181 | echo 'int foo;' | $chibicc -fno-common -S -o- -xc - | grep -q '^foo:' 182 | check '-fno-common' 183 | 184 | # -include 185 | echo foo > $tmp/out.h 186 | echo bar | $chibicc -include $tmp/out.h -E -o- -xc - | grep -q -z 'foo.*bar' 187 | check -include 188 | echo NULL | $chibicc -Iinclude -include stdio.h -E -o- -xc - | grep -q 0 189 | check -include 190 | 191 | # -x 192 | echo 'int x;' | $chibicc -c -xc -o $tmp/foo.o - 193 | check -xc 194 | echo 'x:' | $chibicc -c -x assembler -o $tmp/foo.o - 195 | check '-x assembler' 196 | 197 | echo 'int x;' > $tmp/foo.c 198 | $chibicc -c -x assembler -x none -o $tmp/foo.o $tmp/foo.c 199 | check '-x none' 200 | 201 | # -E 202 | echo foo | $chibicc -E - | grep -q foo 203 | check -E 204 | 205 | # .a file 206 | echo 'void foo() {}' | $chibicc -c -xc -o $tmp/foo.o - 207 | echo 'void bar() {}' | $chibicc -c -xc -o $tmp/bar.o - 208 | ar rcs $tmp/foo.a $tmp/foo.o $tmp/bar.o 209 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 210 | $chibicc -o $tmp/foo $tmp/main.c $tmp/foo.a 211 | check '.a' 212 | 213 | # .so file 214 | echo 'void foo() {}' | cc -fPIC -c -xc -o $tmp/foo.o - 215 | echo 'void bar() {}' | cc -fPIC -c -xc -o $tmp/bar.o - 216 | cc -shared -o $tmp/foo.so $tmp/foo.o $tmp/bar.o 217 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 218 | $chibicc -o $tmp/foo $tmp/main.c $tmp/foo.so 219 | check '.so' 220 | 221 | $chibicc -hashmap-test 222 | check 'hashmap' 223 | 224 | # -M 225 | echo '#include "out2.h"' > $tmp/out.c 226 | echo '#include "out3.h"' >> $tmp/out.c 227 | touch $tmp/out2.h $tmp/out3.h 228 | $chibicc -M -I$tmp $tmp/out.c | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' 229 | check -M 230 | 231 | # -MF 232 | $chibicc -MF $tmp/mf -M -I$tmp $tmp/out.c 233 | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' $tmp/mf 234 | check -MF 235 | 236 | # -MP 237 | $chibicc -MF $tmp/mp -MP -M -I$tmp $tmp/out.c 238 | grep -q '^.*/out2.h:' $tmp/mp 239 | check -MP 240 | grep -q '^.*/out3.h:' $tmp/mp 241 | check -MP 242 | 243 | # -MT 244 | $chibicc -MT foo -M -I$tmp $tmp/out.c | grep -q '^foo:' 245 | check -MT 246 | $chibicc -MT foo -MT bar -M -I$tmp $tmp/out.c | grep -q '^foo bar:' 247 | check -MT 248 | 249 | # -MD 250 | echo '#include "out2.h"' > $tmp/md2.c 251 | echo '#include "out3.h"' > $tmp/md3.c 252 | (cd $tmp; $OLDPWD/$chibicc -c -MD -I. md2.c md3.c) 253 | grep -q -z '^md2.o:.* md2\.c .* ./out2\.h' $tmp/md2.d 254 | check -MD 255 | grep -q -z '^md3.o:.* md3\.c .* ./out3\.h' $tmp/md3.d 256 | check -MD 257 | 258 | $chibicc -c -MD -MF $tmp/md-mf.d -I. $tmp/md2.c 259 | grep -q -z '^md2.o:.*md2\.c .*/out2\.h' $tmp/md-mf.d 260 | check -MD 261 | 262 | echo 'extern int bar; int foo() { return bar; }' | $chibicc -fPIC -xc -c -o $tmp/foo.o - 263 | cc -shared -o $tmp/foo.so $tmp/foo.o 264 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/main.c 265 | $chibicc -o $tmp/foo $tmp/main.c $tmp/foo.so 266 | check -fPIC 267 | 268 | # #include_next 269 | mkdir -p $tmp/next1 $tmp/next2 $tmp/next3 270 | echo '#include "file1.h"' > $tmp/file.c 271 | echo '#include_next "file1.h"' > $tmp/next1/file1.h 272 | echo '#include_next "file2.h"' > $tmp/next2/file1.h 273 | echo 'foo' > $tmp/next3/file2.h 274 | $chibicc -I$tmp/next1 -I$tmp/next2 -I$tmp/next3 -E $tmp/file.c | grep -q foo 275 | check '#include_next' 276 | 277 | # -static 278 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 279 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 280 | $chibicc -static -o $tmp/foo $tmp/foo.c $tmp/bar.c 281 | check -static 282 | file $tmp/foo | grep -q 'statically linked' 283 | check -static 284 | 285 | # -shared 286 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 287 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 288 | $chibicc -fPIC -shared -o $tmp/foo.so $tmp/foo.c $tmp/bar.c 289 | check -shared 290 | 291 | # -L 292 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 293 | $chibicc -fPIC -shared -o $tmp/libfoobar.so $tmp/foo.c 294 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 295 | $chibicc -o $tmp/foo $tmp/bar.c -L$tmp -lfoobar 296 | check -L 297 | 298 | # -Wl, 299 | echo 'int foo() {}' | $chibicc -c -o $tmp/foo.o -xc - 300 | echo 'int foo() {}' | $chibicc -c -o $tmp/bar.o -xc - 301 | echo 'int main() {}' | $chibicc -c -o $tmp/baz.o -xc - 302 | cc -Wl,-z,muldefs,--gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 303 | check -Wl, 304 | 305 | # -Xlinker 306 | echo 'int foo() {}' | $chibicc -c -o $tmp/foo.o -xc - 307 | echo 'int foo() {}' | $chibicc -c -o $tmp/bar.o -xc - 308 | echo 'int main() {}' | $chibicc -c -o $tmp/baz.o -xc - 309 | cc -Xlinker -z -Xlinker muldefs -Xlinker --gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 310 | check -Xlinker 311 | 312 | echo OK 313 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/include1.h: -------------------------------------------------------------------------------- 1 | #include "include2.h" 2 | 3 | char *include1_filename = __FILE__; 4 | int include1_line = __LINE__; 5 | 6 | int include1 = 5; 7 | -------------------------------------------------------------------------------- /test/include2.h: -------------------------------------------------------------------------------- 1 | int include2 = 7; 2 | -------------------------------------------------------------------------------- /test/include3.h: -------------------------------------------------------------------------------- 1 | #define foo 3 2 | -------------------------------------------------------------------------------- /test/include4.h: -------------------------------------------------------------------------------- 1 | #define foo 4 2 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/thirdparty/common: -------------------------------------------------------------------------------- 1 | make="make -j$(nproc)" 2 | chibicc=`pwd`/chibicc 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/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 chibicc as icc 7 | # (Intel C Compiler) because icc is a substring of chibicc. 8 | # Modify the configure file as a workaround. 9 | sed -i -e 1996,2011d configure.ac 10 | autoreconf 11 | 12 | CC=$chibicc ./configure 13 | $make clean 14 | $make 15 | $make test 16 | -------------------------------------------------------------------------------- /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=$chibicc test 8 | -------------------------------------------------------------------------------- /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=$chibicc ./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/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=$chibicc 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/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=$chibicc 7 | $make clean 8 | $make 9 | $make CC=cc test 10 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /test/varargs.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 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/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/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 28 | static void verror_at(char *filename, char *input, int 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:%d: ", 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 | int 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 | exit(1); 62 | } 63 | 64 | void error_tok(Token *tok, char *fmt, ...) { 65 | va_list ap; 66 | va_start(ap, fmt); 67 | verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap); 68 | exit(1); 69 | } 70 | 71 | void warn_tok(Token *tok, char *fmt, ...) { 72 | va_list ap; 73 | va_start(ap, fmt); 74 | verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap); 75 | va_end(ap); 76 | } 77 | 78 | // Consumes the current token if it matches `op`. 79 | bool equal(Token *tok, char *op) { 80 | return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0'; 81 | } 82 | 83 | // Ensure that the current token is `op`. 84 | Token *skip(Token *tok, char *op) { 85 | if (!equal(tok, op)) 86 | error_tok(tok, "expected '%s'", op); 87 | return tok->next; 88 | } 89 | 90 | bool consume(Token **rest, Token *tok, char *str) { 91 | if (equal(tok, str)) { 92 | *rest = tok->next; 93 | return true; 94 | } 95 | *rest = tok; 96 | return false; 97 | } 98 | 99 | // Create a new token. 100 | static Token *new_token(TokenKind kind, char *start, char *end) { 101 | Token *tok = calloc(1, sizeof(Token)); 102 | tok->kind = kind; 103 | tok->loc = start; 104 | tok->len = end - start; 105 | tok->file = current_file; 106 | tok->filename = current_file->display_name; 107 | tok->at_bol = at_bol; 108 | tok->has_space = has_space; 109 | 110 | at_bol = has_space = false; 111 | return tok; 112 | } 113 | 114 | static bool startswith(char *p, char *q) { 115 | return strncmp(p, q, strlen(q)) == 0; 116 | } 117 | 118 | // Read an identifier and returns the length of it. 119 | // If p does not point to a valid identifier, 0 is returned. 120 | static int read_ident(char *start) { 121 | char *p = start; 122 | uint32_t c = decode_utf8(&p, p); 123 | if (!is_ident1(c)) 124 | return 0; 125 | 126 | for (;;) { 127 | char *q; 128 | c = decode_utf8(&q, p); 129 | if (!is_ident2(c)) 130 | return p - start; 131 | p = q; 132 | } 133 | } 134 | 135 | static int from_hex(char c) { 136 | if ('0' <= c && c <= '9') 137 | return c - '0'; 138 | if ('a' <= c && c <= 'f') 139 | return c - 'a' + 10; 140 | return c - 'A' + 10; 141 | } 142 | 143 | // Read a punctuator token from p and returns its length. 144 | static int read_punct(char *p) { 145 | static char *kw[] = { 146 | "<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=", 147 | "-=", "*=", "/=", "++", "--", "%=", "&=", "|=", "^=", "&&", 148 | "||", "<<", ">>", "##", 149 | }; 150 | 151 | for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) 152 | if (startswith(p, kw[i])) 153 | return strlen(kw[i]); 154 | 155 | return ispunct(*p) ? 1 : 0; 156 | } 157 | 158 | static bool is_keyword(Token *tok) { 159 | static HashMap map; 160 | 161 | if (map.capacity == 0) { 162 | static char *kw[] = { 163 | "return", "if", "else", "for", "while", "int", "sizeof", "char", 164 | "struct", "union", "short", "long", "void", "typedef", "_Bool", 165 | "enum", "static", "goto", "break", "continue", "switch", "case", 166 | "default", "extern", "_Alignof", "_Alignas", "do", "signed", 167 | "unsigned", "const", "volatile", "auto", "register", "restrict", 168 | "__restrict", "__restrict__", "_Noreturn", "float", "double", 169 | "typeof", "asm", "_Thread_local", "__thread", "_Atomic", 170 | "__attribute__", 171 | }; 172 | 173 | for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) 174 | hashmap_put(&map, kw[i], (void *)1); 175 | } 176 | 177 | return hashmap_get2(&map, tok->loc, tok->len); 178 | } 179 | 180 | static int read_escaped_char(char **new_pos, char *p) { 181 | if ('0' <= *p && *p <= '7') { 182 | // Read an octal number. 183 | int c = *p++ - '0'; 184 | if ('0' <= *p && *p <= '7') { 185 | c = (c << 3) + (*p++ - '0'); 186 | if ('0' <= *p && *p <= '7') 187 | c = (c << 3) + (*p++ - '0'); 188 | } 189 | *new_pos = p; 190 | return c; 191 | } 192 | 193 | if (*p == 'x') { 194 | // Read a hexadecimal number. 195 | p++; 196 | if (!isxdigit(*p)) 197 | error_at(p, "invalid hex escape sequence"); 198 | 199 | int c = 0; 200 | for (; isxdigit(*p); p++) 201 | c = (c << 4) + from_hex(*p); 202 | *new_pos = p; 203 | return c; 204 | } 205 | 206 | *new_pos = p + 1; 207 | 208 | // Escape sequences are defined using themselves here. E.g. 209 | // '\n' is implemented using '\n'. This tautological definition 210 | // works because the compiler that compiles our compiler knows 211 | // what '\n' actually is. In other words, we "inherit" the ASCII 212 | // code of '\n' from the compiler that compiles our compiler, 213 | // so we don't have to teach the actual code here. 214 | // 215 | // This fact has huge implications not only for the correctness 216 | // of the compiler but also for the security of the generated code. 217 | // For more info, read "Reflections on Trusting Trust" by Ken Thompson. 218 | // https://github.com/rui314/chibicc/wiki/thompson1984.pdf 219 | switch (*p) { 220 | case 'a': return '\a'; 221 | case 'b': return '\b'; 222 | case 't': return '\t'; 223 | case 'n': return '\n'; 224 | case 'v': return '\v'; 225 | case 'f': return '\f'; 226 | case 'r': return '\r'; 227 | // [GNU] \e for the ASCII escape character is a GNU C extension. 228 | case 'e': return 27; 229 | default: return *p; 230 | } 231 | } 232 | 233 | // Find a closing double-quote. 234 | static char *string_literal_end(char *p) { 235 | char *start = p; 236 | for (; *p != '"'; p++) { 237 | if (*p == '\n' || *p == '\0') 238 | error_at(start, "unclosed string literal"); 239 | if (*p == '\\') 240 | p++; 241 | } 242 | return p; 243 | } 244 | 245 | static Token *read_string_literal(char *start, char *quote) { 246 | char *end = string_literal_end(quote + 1); 247 | char *buf = calloc(1, end - quote); 248 | int len = 0; 249 | 250 | for (char *p = quote + 1; p < end;) { 251 | if (*p == '\\') 252 | buf[len++] = read_escaped_char(&p, p + 1); 253 | else 254 | buf[len++] = *p++; 255 | } 256 | 257 | Token *tok = new_token(TK_STR, start, end + 1); 258 | tok->ty = array_of(ty_char, len + 1); 259 | tok->str = buf; 260 | return tok; 261 | } 262 | 263 | // Read a UTF-8-encoded string literal and transcode it in UTF-16. 264 | // 265 | // UTF-16 is yet another variable-width encoding for Unicode. Code 266 | // points smaller than U+10000 are encoded in 2 bytes. Code points 267 | // equal to or larger than that are encoded in 4 bytes. Each 2 bytes 268 | // in the 4 byte sequence is called "surrogate", and a 4 byte sequence 269 | // is called a "surrogate pair". 270 | static Token *read_utf16_string_literal(char *start, char *quote) { 271 | char *end = string_literal_end(quote + 1); 272 | uint16_t *buf = calloc(2, end - start); 273 | int len = 0; 274 | 275 | for (char *p = quote + 1; p < end;) { 276 | if (*p == '\\') { 277 | buf[len++] = read_escaped_char(&p, p + 1); 278 | continue; 279 | } 280 | 281 | uint32_t c = decode_utf8(&p, p); 282 | if (c < 0x10000) { 283 | // Encode a code point in 2 bytes. 284 | buf[len++] = c; 285 | } else { 286 | // Encode a code point in 4 bytes. 287 | c -= 0x10000; 288 | buf[len++] = 0xd800 + ((c >> 10) & 0x3ff); 289 | buf[len++] = 0xdc00 + (c & 0x3ff); 290 | } 291 | } 292 | 293 | Token *tok = new_token(TK_STR, start, end + 1); 294 | tok->ty = array_of(ty_ushort, len + 1); 295 | tok->str = (char *)buf; 296 | return tok; 297 | } 298 | 299 | // Read a UTF-8-encoded string literal and transcode it in UTF-32. 300 | // 301 | // UTF-32 is a fixed-width encoding for Unicode. Each code point is 302 | // encoded in 4 bytes. 303 | static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) { 304 | char *end = string_literal_end(quote + 1); 305 | uint32_t *buf = calloc(4, end - quote); 306 | int len = 0; 307 | 308 | for (char *p = quote + 1; p < end;) { 309 | if (*p == '\\') 310 | buf[len++] = read_escaped_char(&p, p + 1); 311 | else 312 | buf[len++] = decode_utf8(&p, p); 313 | } 314 | 315 | Token *tok = new_token(TK_STR, start, end + 1); 316 | tok->ty = array_of(ty, len + 1); 317 | tok->str = (char *)buf; 318 | return tok; 319 | } 320 | 321 | static Token *read_char_literal(char *start, char *quote, Type *ty) { 322 | char *p = quote + 1; 323 | if (*p == '\0') 324 | error_at(start, "unclosed char literal"); 325 | 326 | int c; 327 | if (*p == '\\') 328 | c = read_escaped_char(&p, p + 1); 329 | else 330 | c = decode_utf8(&p, p); 331 | 332 | char *end = strchr(p, '\''); 333 | if (!end) 334 | error_at(p, "unclosed char literal"); 335 | 336 | Token *tok = new_token(TK_NUM, start, end + 1); 337 | tok->val = c; 338 | tok->ty = ty; 339 | return tok; 340 | } 341 | 342 | static bool convert_pp_int(Token *tok) { 343 | char *p = tok->loc; 344 | 345 | // Read a binary, octal, decimal or hexadecimal number. 346 | int base = 10; 347 | if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) { 348 | p += 2; 349 | base = 16; 350 | } else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) { 351 | p += 2; 352 | base = 2; 353 | } else if (*p == '0') { 354 | base = 8; 355 | } 356 | 357 | int64_t val = strtoul(p, &p, base); 358 | 359 | // Read U, L or LL suffixes. 360 | bool l = false; 361 | bool u = false; 362 | 363 | if (startswith(p, "LLU") || startswith(p, "LLu") || 364 | startswith(p, "llU") || startswith(p, "llu") || 365 | startswith(p, "ULL") || startswith(p, "Ull") || 366 | startswith(p, "uLL") || startswith(p, "ull")) { 367 | p += 3; 368 | l = u = true; 369 | } else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) { 370 | p += 2; 371 | l = u = true; 372 | } else if (startswith(p, "LL") || startswith(p, "ll")) { 373 | p += 2; 374 | l = true; 375 | } else if (*p == 'L' || *p == 'l') { 376 | p++; 377 | l = true; 378 | } else if (*p == 'U' || *p == 'u') { 379 | p++; 380 | u = true; 381 | } 382 | 383 | if (p != tok->loc + tok->len) 384 | return false; 385 | 386 | // Infer a type. 387 | Type *ty; 388 | if (base == 10) { 389 | if (l && u) 390 | ty = ty_ulong; 391 | else if (l) 392 | ty = ty_long; 393 | else if (u) 394 | ty = (val >> 32) ? ty_ulong : ty_uint; 395 | else 396 | ty = (val >> 31) ? ty_long : ty_int; 397 | } else { 398 | if (l && u) 399 | ty = ty_ulong; 400 | else if (l) 401 | ty = (val >> 63) ? ty_ulong : ty_long; 402 | else if (u) 403 | ty = (val >> 32) ? ty_ulong : ty_uint; 404 | else if (val >> 63) 405 | ty = ty_ulong; 406 | else if (val >> 32) 407 | ty = ty_long; 408 | else if (val >> 31) 409 | ty = ty_uint; 410 | else 411 | ty = ty_int; 412 | } 413 | 414 | tok->kind = TK_NUM; 415 | tok->val = val; 416 | tok->ty = ty; 417 | return true; 418 | } 419 | 420 | // The definition of the numeric literal at the preprocessing stage 421 | // is more relaxed than the definition of that at the later stages. 422 | // In order to handle that, a numeric literal is tokenized as a 423 | // "pp-number" token first and then converted to a regular number 424 | // token after preprocessing. 425 | // 426 | // This function converts a pp-number token to a regular number token. 427 | static void convert_pp_number(Token *tok) { 428 | // Try to parse as an integer constant. 429 | if (convert_pp_int(tok)) 430 | return; 431 | 432 | // If it's not an integer, it must be a floating point constant. 433 | char *end; 434 | long double val = strtold(tok->loc, &end); 435 | 436 | Type *ty; 437 | if (*end == 'f' || *end == 'F') { 438 | ty = ty_float; 439 | end++; 440 | } else if (*end == 'l' || *end == 'L') { 441 | ty = ty_ldouble; 442 | end++; 443 | } else { 444 | ty = ty_double; 445 | } 446 | 447 | if (tok->loc + tok->len != end) 448 | error_tok(tok, "invalid numeric constant"); 449 | 450 | tok->kind = TK_NUM; 451 | tok->fval = val; 452 | tok->ty = ty; 453 | } 454 | 455 | void convert_pp_tokens(Token *tok) { 456 | for (Token *t = tok; t->kind != TK_EOF; t = t->next) { 457 | if (is_keyword(t)) 458 | t->kind = TK_KEYWORD; 459 | else if (t->kind == TK_PP_NUM) 460 | convert_pp_number(t); 461 | } 462 | } 463 | 464 | // Initialize line info for all tokens. 465 | static void add_line_numbers(Token *tok) { 466 | char *p = current_file->contents; 467 | int n = 1; 468 | 469 | do { 470 | if (p == tok->loc) { 471 | tok->line_no = n; 472 | tok = tok->next; 473 | } 474 | if (*p == '\n') 475 | n++; 476 | } while (*p++); 477 | } 478 | 479 | Token *tokenize_string_literal(Token *tok, Type *basety) { 480 | Token *t; 481 | if (basety->size == 2) 482 | t = read_utf16_string_literal(tok->loc, tok->loc); 483 | else 484 | t = read_utf32_string_literal(tok->loc, tok->loc, basety); 485 | t->next = tok->next; 486 | return t; 487 | } 488 | 489 | // Tokenize a given string and returns new tokens. 490 | Token *tokenize(File *file) { 491 | current_file = file; 492 | 493 | char *p = file->contents; 494 | Token head = {}; 495 | Token *cur = &head; 496 | 497 | at_bol = true; 498 | has_space = false; 499 | 500 | while (*p) { 501 | // Skip line comments. 502 | if (startswith(p, "//")) { 503 | p += 2; 504 | while (*p != '\n') 505 | p++; 506 | has_space = true; 507 | continue; 508 | } 509 | 510 | // Skip block comments. 511 | if (startswith(p, "/*")) { 512 | char *q = strstr(p + 2, "*/"); 513 | if (!q) 514 | error_at(p, "unclosed block comment"); 515 | p = q + 2; 516 | has_space = true; 517 | continue; 518 | } 519 | 520 | // Skip newline. 521 | if (*p == '\n') { 522 | p++; 523 | at_bol = true; 524 | has_space = false; 525 | continue; 526 | } 527 | 528 | // Skip whitespace characters. 529 | if (isspace(*p)) { 530 | p++; 531 | has_space = true; 532 | continue; 533 | } 534 | 535 | // Numeric literal 536 | if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) { 537 | char *q = p++; 538 | for (;;) { 539 | if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) 540 | p += 2; 541 | else if (isalnum(*p) || *p == '.') 542 | p++; 543 | else 544 | break; 545 | } 546 | cur = cur->next = new_token(TK_PP_NUM, q, p); 547 | continue; 548 | } 549 | 550 | // String literal 551 | if (*p == '"') { 552 | cur = cur->next = read_string_literal(p, p); 553 | p += cur->len; 554 | continue; 555 | } 556 | 557 | // UTF-8 string literal 558 | if (startswith(p, "u8\"")) { 559 | cur = cur->next = read_string_literal(p, p + 2); 560 | p += cur->len; 561 | continue; 562 | } 563 | 564 | // UTF-16 string literal 565 | if (startswith(p, "u\"")) { 566 | cur = cur->next = read_utf16_string_literal(p, p + 1); 567 | p += cur->len; 568 | continue; 569 | } 570 | 571 | // Wide string literal 572 | if (startswith(p, "L\"")) { 573 | cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int); 574 | p += cur->len; 575 | continue; 576 | } 577 | 578 | // UTF-32 string literal 579 | if (startswith(p, "U\"")) { 580 | cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint); 581 | p += cur->len; 582 | continue; 583 | } 584 | 585 | // Character literal 586 | if (*p == '\'') { 587 | cur = cur->next = read_char_literal(p, p, ty_int); 588 | cur->val = (char)cur->val; 589 | p += cur->len; 590 | continue; 591 | } 592 | 593 | // UTF-16 character literal 594 | if (startswith(p, "u'")) { 595 | cur = cur->next = read_char_literal(p, p + 1, ty_ushort); 596 | cur->val &= 0xffff; 597 | p += cur->len; 598 | continue; 599 | } 600 | 601 | // Wide character literal 602 | if (startswith(p, "L'")) { 603 | cur = cur->next = read_char_literal(p, p + 1, ty_int); 604 | p += cur->len; 605 | continue; 606 | } 607 | 608 | // UTF-32 character literal 609 | if (startswith(p, "U'")) { 610 | cur = cur->next = read_char_literal(p, p + 1, ty_uint); 611 | p += cur->len; 612 | continue; 613 | } 614 | 615 | // Identifier or keyword 616 | int ident_len = read_ident(p); 617 | if (ident_len) { 618 | cur = cur->next = new_token(TK_IDENT, p, p + ident_len); 619 | p += cur->len; 620 | continue; 621 | } 622 | 623 | // Punctuators 624 | int punct_len = read_punct(p); 625 | if (punct_len) { 626 | cur = cur->next = new_token(TK_PUNCT, p, p + punct_len); 627 | p += cur->len; 628 | continue; 629 | } 630 | 631 | error_at(p, "invalid token"); 632 | } 633 | 634 | cur = cur->next = new_token(TK_EOF, p, p); 635 | add_line_numbers(head.next); 636 | return head.next; 637 | } 638 | 639 | // Returns the contents of a given file. 640 | static char *read_file(char *path) { 641 | FILE *fp; 642 | 643 | if (strcmp(path, "-") == 0) { 644 | // By convention, read from stdin if a given filename is "-". 645 | fp = stdin; 646 | } else { 647 | fp = fopen(path, "r"); 648 | if (!fp) 649 | return NULL; 650 | } 651 | 652 | char *buf; 653 | size_t buflen; 654 | FILE *out = open_memstream(&buf, &buflen); 655 | 656 | // Read the entire file. 657 | for (;;) { 658 | char buf2[4096]; 659 | int n = fread(buf2, 1, sizeof(buf2), fp); 660 | if (n == 0) 661 | break; 662 | fwrite(buf2, 1, n, out); 663 | } 664 | 665 | if (fp != stdin) 666 | fclose(fp); 667 | 668 | // Make sure that the last line is properly terminated with '\n'. 669 | fflush(out); 670 | if (buflen == 0 || buf[buflen - 1] != '\n') 671 | fputc('\n', out); 672 | fputc('\0', out); 673 | fclose(out); 674 | return buf; 675 | } 676 | 677 | File **get_input_files(void) { 678 | return input_files; 679 | } 680 | 681 | File *new_file(char *name, int file_no, char *contents) { 682 | File *file = calloc(1, sizeof(File)); 683 | file->name = name; 684 | file->display_name = name; 685 | file->file_no = file_no; 686 | file->contents = contents; 687 | return file; 688 | } 689 | 690 | // Replaces \r or \r\n with \n. 691 | static void canonicalize_newline(char *p) { 692 | int i = 0, j = 0; 693 | 694 | while (p[i]) { 695 | if (p[i] == '\r' && p[i + 1] == '\n') { 696 | i += 2; 697 | p[j++] = '\n'; 698 | } else if (p[i] == '\r') { 699 | i++; 700 | p[j++] = '\n'; 701 | } else { 702 | p[j++] = p[i++]; 703 | } 704 | } 705 | 706 | p[j] = '\0'; 707 | } 708 | 709 | // Removes backslashes followed by a newline. 710 | static void remove_backslash_newline(char *p) { 711 | int i = 0, j = 0; 712 | 713 | // We want to keep the number of newline characters so that 714 | // the logical line number matches the physical one. 715 | // This counter maintain the number of newlines we have removed. 716 | int n = 0; 717 | 718 | while (p[i]) { 719 | if (p[i] == '\\' && p[i + 1] == '\n') { 720 | i += 2; 721 | n++; 722 | } else if (p[i] == '\n') { 723 | p[j++] = p[i++]; 724 | for (; n > 0; n--) 725 | p[j++] = '\n'; 726 | } else { 727 | p[j++] = p[i++]; 728 | } 729 | } 730 | 731 | for (; n > 0; n--) 732 | p[j++] = '\n'; 733 | p[j] = '\0'; 734 | } 735 | 736 | static uint32_t read_universal_char(char *p, int len) { 737 | uint32_t c = 0; 738 | for (int i = 0; i < len; i++) { 739 | if (!isxdigit(p[i])) 740 | return 0; 741 | c = (c << 4) | from_hex(p[i]); 742 | } 743 | return c; 744 | } 745 | 746 | // Replace \u or \U escape sequences with corresponding UTF-8 bytes. 747 | static void convert_universal_chars(char *p) { 748 | char *q = p; 749 | 750 | while (*p) { 751 | if (startswith(p, "\\u")) { 752 | uint32_t c = read_universal_char(p + 2, 4); 753 | if (c) { 754 | p += 6; 755 | q += encode_utf8(q, c); 756 | } else { 757 | *q++ = *p++; 758 | } 759 | } else if (startswith(p, "\\U")) { 760 | uint32_t c = read_universal_char(p + 2, 8); 761 | if (c) { 762 | p += 10; 763 | q += encode_utf8(q, c); 764 | } else { 765 | *q++ = *p++; 766 | } 767 | } else if (p[0] == '\\') { 768 | *q++ = *p++; 769 | *q++ = *p++; 770 | } else { 771 | *q++ = *p++; 772 | } 773 | } 774 | 775 | *q = '\0'; 776 | } 777 | 778 | Token *tokenize_file(char *path) { 779 | char *p = read_file(path); 780 | if (!p) 781 | return NULL; 782 | 783 | // UTF-8 texts may start with a 3-byte "BOM" marker sequence. 784 | // If exists, just skip them because they are useless bytes. 785 | // (It is actually not recommended to add BOM markers to UTF-8 786 | // texts, but it's not uncommon particularly on Windows.) 787 | if (!memcmp(p, "\xef\xbb\xbf", 3)) 788 | p += 3; 789 | 790 | canonicalize_newline(p); 791 | remove_backslash_newline(p); 792 | convert_universal_chars(p); 793 | 794 | // Save the filename for assembler .file directive. 795 | static int file_no; 796 | File *file = new_file(path, file_no + 1, p); 797 | 798 | // Save the filename for assembler .file directive. 799 | input_files = realloc(input_files, sizeof(char *) * (file_no + 2)); 800 | input_files[file_no] = file; 801 | input_files[file_no + 1] = NULL; 802 | file_no++; 803 | 804 | return tokenize(file); 805 | } 806 | -------------------------------------------------------------------------------- /type.c: -------------------------------------------------------------------------------- 1 | #include "chibicc.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 | -------------------------------------------------------------------------------- /unicode.c: -------------------------------------------------------------------------------- 1 | #include "chibicc.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 | --------------------------------------------------------------------------------