├── .gitignore ├── 8cc.h ├── HACKING.md ├── LICENSE ├── Makefile ├── README.md ├── buffer.c ├── cpp.c ├── debug.c ├── dict.c ├── encoding.c ├── error.c ├── file.c ├── gen.c ├── include ├── 8cc.h ├── float.h ├── iso646.h ├── stdalign.h ├── stdarg.h ├── stdbool.h ├── stddef.h └── stdnoreturn.h ├── keyword.inc ├── lex.c ├── main.c ├── map.c ├── parse.c ├── path.c ├── set.c ├── test ├── align.c ├── arith.c ├── array.c ├── assign.c ├── ast.sh ├── bitop.c ├── builtin.c ├── cast.c ├── comp.c ├── constexpr.c ├── control.c ├── conversion.c ├── decl.c ├── enum.c ├── extern.c ├── float.c ├── funcargs.c ├── function.c ├── generic.c ├── global.c ├── import.c ├── import.h ├── includeguard.c ├── includeguard1.h ├── includeguard2.h ├── includeguard3.h ├── includeguard4.h ├── includeguard5.h ├── includeguard6.h ├── includeguard7.h ├── initializer.c ├── int.c ├── iso646.c ├── lex.c ├── line.c ├── literal.c ├── macro.c ├── macro1.h ├── macro2.h ├── negative.py ├── noreturn.c ├── number.c ├── oldstyle.c ├── once.h ├── pointer.c ├── scope.c ├── sizeof.c ├── staticassert.c ├── stmtexpr.c ├── struct.c ├── test.h ├── testmain.c ├── type.c ├── typeof.c ├── union.c ├── usualconv.c └── varargs.c ├── utiltest.c └── vector.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.o 3 | *.s 4 | *~ 5 | 8cc 6 | stage? 7 | utiltest 8 | -------------------------------------------------------------------------------- /8cc.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef EIGHTCC_H 4 | #define EIGHTCC_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | enum { 15 | TIDENT, 16 | TKEYWORD, 17 | TNUMBER, 18 | TCHAR, 19 | TSTRING, 20 | TEOF, 21 | TINVALID, 22 | // Only in CPP 23 | MIN_CPP_TOKEN, 24 | TNEWLINE, 25 | TSPACE, 26 | TMACRO_PARAM, 27 | }; 28 | 29 | enum { 30 | ENC_NONE, 31 | ENC_CHAR16, 32 | ENC_CHAR32, 33 | ENC_UTF8, 34 | ENC_WCHAR, 35 | }; 36 | 37 | typedef struct Map { 38 | struct Map *parent; 39 | char **key; 40 | void **val; 41 | int size; 42 | int nelem; 43 | int nused; 44 | } Map; 45 | 46 | typedef struct { 47 | void **body; 48 | int len; 49 | int nalloc; 50 | } Vector; 51 | 52 | typedef struct { 53 | struct Map *map; 54 | Vector *key; 55 | } Dict; 56 | 57 | typedef struct Set { 58 | char *v; 59 | struct Set *next; 60 | } Set; 61 | 62 | typedef struct { 63 | char *body; 64 | int nalloc; 65 | int len; 66 | } Buffer; 67 | 68 | typedef struct { 69 | FILE *file; // stream backed by FILE * 70 | char *p; // stream backed by string 71 | char *name; 72 | int line; 73 | int column; 74 | int ntok; // token counter 75 | int last; // the last character read from file 76 | int buf[3]; // push-back buffer for unread operations 77 | int buflen; // push-back buffer size 78 | time_t mtime; // last modified time. 0 if string-backed file 79 | } File; 80 | 81 | typedef struct { 82 | int kind; 83 | File *file; 84 | int line; 85 | int column; 86 | bool space; // true if the token has a leading space 87 | bool bol; // true if the token is at the beginning of a line 88 | int count; // token number in a file, counting from 0. 89 | Set *hideset; // used by the preprocessor for macro expansion 90 | union { 91 | // TKEYWORD 92 | int id; 93 | // TSTRING or TCHAR 94 | struct { 95 | char *sval; 96 | int slen; 97 | int c; 98 | int enc; 99 | }; 100 | // TMACRO_PARAM 101 | struct { 102 | bool is_vararg; 103 | int position; 104 | }; 105 | }; 106 | } Token; 107 | 108 | enum { 109 | AST_LITERAL = 256, 110 | AST_LVAR, 111 | AST_GVAR, 112 | AST_TYPEDEF, 113 | AST_FUNCALL, 114 | AST_FUNCPTR_CALL, 115 | AST_FUNCDESG, 116 | AST_FUNC, 117 | AST_DECL, 118 | AST_INIT, 119 | AST_CONV, 120 | AST_ADDR, 121 | AST_DEREF, 122 | AST_IF, 123 | AST_TERNARY, 124 | AST_DEFAULT, 125 | AST_RETURN, 126 | AST_COMPOUND_STMT, 127 | AST_STRUCT_REF, 128 | AST_GOTO, 129 | AST_COMPUTED_GOTO, 130 | AST_LABEL, 131 | OP_SIZEOF, 132 | OP_CAST, 133 | OP_SHR, 134 | OP_SHL, 135 | OP_A_SHR, 136 | OP_A_SHL, 137 | OP_PRE_INC, 138 | OP_PRE_DEC, 139 | OP_POST_INC, 140 | OP_POST_DEC, 141 | OP_LABEL_ADDR, 142 | #define op(name, _) name, 143 | #define keyword(name, x, y) name, 144 | #include "keyword.inc" 145 | #undef keyword 146 | #undef op 147 | }; 148 | 149 | enum { 150 | KIND_VOID, 151 | KIND_BOOL, 152 | KIND_CHAR, 153 | KIND_SHORT, 154 | KIND_INT, 155 | KIND_LONG, 156 | KIND_LLONG, 157 | KIND_FLOAT, 158 | KIND_DOUBLE, 159 | KIND_LDOUBLE, 160 | KIND_ARRAY, 161 | KIND_ENUM, 162 | KIND_PTR, 163 | KIND_STRUCT, 164 | KIND_FUNC, 165 | // used only in parser 166 | KIND_STUB, 167 | }; 168 | 169 | typedef struct Type { 170 | int kind; 171 | int size; 172 | int align; 173 | bool usig; // true if unsigned 174 | bool isstatic; 175 | // pointer or array 176 | struct Type *ptr; 177 | // array length 178 | int len; 179 | // struct 180 | Dict *fields; 181 | int offset; 182 | bool is_struct; // true if struct, false if union 183 | // bitfield 184 | int bitoff; 185 | int bitsize; 186 | // function 187 | struct Type *rettype; 188 | Vector *params; 189 | bool hasva; 190 | bool oldstyle; 191 | } Type; 192 | 193 | typedef struct { 194 | char *file; 195 | int line; 196 | } SourceLoc; 197 | 198 | typedef struct Node { 199 | int kind; 200 | Type *ty; 201 | SourceLoc *sourceLoc; 202 | union { 203 | // Char, int, or long 204 | long ival; 205 | // Float or double 206 | struct { 207 | double fval; 208 | char *flabel; 209 | }; 210 | // String 211 | struct { 212 | char *sval; 213 | char *slabel; 214 | }; 215 | // Local/global variable 216 | struct { 217 | char *varname; 218 | // local 219 | int loff; 220 | Vector *lvarinit; 221 | // global 222 | char *glabel; 223 | }; 224 | // Binary operator 225 | struct { 226 | struct Node *left; 227 | struct Node *right; 228 | }; 229 | // Unary operator 230 | struct { 231 | struct Node *operand; 232 | }; 233 | // Function call or function declaration 234 | struct { 235 | char *fname; 236 | // Function call 237 | Vector *args; 238 | struct Type *ftype; 239 | // Function pointer or function designator 240 | struct Node *fptr; 241 | // Function declaration 242 | Vector *params; 243 | Vector *localvars; 244 | struct Node *body; 245 | }; 246 | // Declaration 247 | struct { 248 | struct Node *declvar; 249 | Vector *declinit; 250 | }; 251 | // Initializer 252 | struct { 253 | struct Node *initval; 254 | int initoff; 255 | Type *totype; 256 | }; 257 | // If statement or ternary operator 258 | struct { 259 | struct Node *cond; 260 | struct Node *then; 261 | struct Node *els; 262 | }; 263 | // Goto and label 264 | struct { 265 | char *label; 266 | char *newlabel; 267 | }; 268 | // Return statement 269 | struct Node *retval; 270 | // Compound statement 271 | Vector *stmts; 272 | // Struct reference 273 | struct { 274 | struct Node *struc; 275 | char *field; 276 | Type *fieldtype; 277 | }; 278 | }; 279 | } Node; 280 | 281 | extern Type *type_void; 282 | extern Type *type_bool; 283 | extern Type *type_char; 284 | extern Type *type_short; 285 | extern Type *type_int; 286 | extern Type *type_long; 287 | extern Type *type_llong; 288 | extern Type *type_uchar; 289 | extern Type *type_ushort; 290 | extern Type *type_uint; 291 | extern Type *type_ulong; 292 | extern Type *type_ullong; 293 | extern Type *type_float; 294 | extern Type *type_double; 295 | extern Type *type_ldouble; 296 | 297 | #define EMPTY_MAP ((Map){}) 298 | #define EMPTY_VECTOR ((Vector){}) 299 | 300 | // encoding.c 301 | Buffer *to_utf16(char *p, int len); 302 | Buffer *to_utf32(char *p, int len); 303 | void write_utf8(Buffer *b, uint32_t rune); 304 | 305 | // buffer.c 306 | Buffer *make_buffer(void); 307 | char *buf_body(Buffer *b); 308 | int buf_len(Buffer *b); 309 | void buf_write(Buffer *b, char c); 310 | void buf_append(Buffer *b, char *s, int len); 311 | void buf_printf(Buffer *b, char *fmt, ...); 312 | char *vformat(char *fmt, va_list ap); 313 | char *format(char *fmt, ...); 314 | char *quote_cstring(char *p); 315 | char *quote_cstring_len(char *p, int len); 316 | char *quote_char(char c); 317 | 318 | // cpp.c 319 | void read_from_string(char *buf); 320 | bool is_ident(Token *tok, char *s); 321 | void expect_newline(void); 322 | void add_include_path(char *path); 323 | void init_now(void); 324 | void cpp_init(void); 325 | Token *peek_token(void); 326 | Token *read_token(void); 327 | 328 | // debug.c 329 | char *ty2s(Type *ty); 330 | char *node2s(Node *node); 331 | char *tok2s(Token *tok); 332 | 333 | // dict.c 334 | Dict *make_dict(void); 335 | void *dict_get(Dict *dict, char *key); 336 | void dict_put(Dict *dict, char *key, void *val); 337 | Vector *dict_keys(Dict *dict); 338 | 339 | // error.c 340 | extern bool enable_warning; 341 | extern bool dumpstack; 342 | extern bool dumpsource; 343 | extern bool warning_is_error; 344 | 345 | #define STR2(x) #x 346 | #define STR(x) STR2(x) 347 | #define error(...) errorf(__FILE__ ":" STR(__LINE__), NULL, __VA_ARGS__) 348 | #define errort(tok, ...) errorf(__FILE__ ":" STR(__LINE__), token_pos(tok), __VA_ARGS__) 349 | #define warn(...) warnf(__FILE__ ":" STR(__LINE__), NULL, __VA_ARGS__) 350 | #define warnt(tok, ...) warnf(__FILE__ ":" STR(__LINE__), token_pos(tok), __VA_ARGS__) 351 | 352 | noreturn void errorf(char *line, char *pos, char *fmt, ...); 353 | void warnf(char *line, char *pos, char *fmt, ...); 354 | char *token_pos(Token *tok); 355 | 356 | // file.c 357 | File *make_file(FILE *file, char *name); 358 | File *make_file_string(char *s); 359 | int readc(void); 360 | void unreadc(int c); 361 | File *current_file(void); 362 | void stream_push(File *file); 363 | int stream_depth(void); 364 | char *input_position(void); 365 | void stream_stash(File *f); 366 | void stream_unstash(void); 367 | 368 | // gen.c 369 | void set_output_file(FILE *fp); 370 | void close_output_file(void); 371 | void emit_toplevel(Node *v); 372 | 373 | // lex.c 374 | void lex_init(char *filename); 375 | char *get_base_file(void); 376 | void skip_cond_incl(void); 377 | char *read_header_file_name(bool *std); 378 | bool is_keyword(Token *tok, int c); 379 | void token_buffer_stash(Vector *buf); 380 | void token_buffer_unstash(); 381 | void unget_token(Token *tok); 382 | Token *lex_string(char *s); 383 | Token *lex(void); 384 | 385 | // map.c 386 | Map *make_map(void); 387 | Map *make_map_parent(Map *parent); 388 | void *map_get(Map *m, char *key); 389 | void map_put(Map *m, char *key, void *val); 390 | void map_remove(Map *m, char *key); 391 | size_t map_len(Map *m); 392 | 393 | // parse.c 394 | char *make_tempname(void); 395 | char *make_label(void); 396 | bool is_inttype(Type *ty); 397 | bool is_flotype(Type *ty); 398 | void *make_pair(void *first, void *second); 399 | int eval_intexpr(Node *node, Node **addr); 400 | Node *read_expr(void); 401 | Vector *read_toplevels(void); 402 | void parse_init(void); 403 | char *fullpath(char *path); 404 | 405 | // set.c 406 | Set *set_add(Set *s, char *v); 407 | bool set_has(Set *s, char *v); 408 | Set *set_union(Set *a, Set *b); 409 | Set *set_intersection(Set *a, Set *b); 410 | 411 | // vector.c 412 | Vector *make_vector(void); 413 | Vector *make_vector1(void *e); 414 | Vector *vec_copy(Vector *src); 415 | void vec_push(Vector *vec, void *elem); 416 | void vec_append(Vector *a, Vector *b); 417 | void *vec_pop(Vector *vec); 418 | void *vec_get(Vector *vec, int index); 419 | void vec_set(Vector *vec, int index, void *val); 420 | void *vec_head(Vector *vec); 421 | void *vec_tail(Vector *vec); 422 | Vector *vec_reverse(Vector *vec); 423 | void *vec_body(Vector *vec); 424 | int vec_len(Vector *vec); 425 | 426 | #endif 427 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | I accept small patches, but because this is my hobby project to 2 | learn about compilers, it's unlikely to accept large patches. 3 | That's in practice not going to be an issue, because 4 | if you are writing a large patch, that is your hobby project. 5 | You want to hack in your forked repository rather than 6 | taking time to send pull requests. 7 | 8 | # Memory management 9 | 10 | No memory management is a memory management scheme in 8cc. 11 | Memory regions allocated using malloc are never freed 12 | until the process terminates. That has greatly simplified 13 | the code and the APIs because 1) you can write code as if 14 | garbage collector were present, and 2) that design 15 | decision has eliminated use-after-free bugs entirely. 16 | 17 | Modern computers have gigs of memory. 8cc consumes 18 | only about 100MB to compile 10K lines of C source file. 19 | Compiler is not a long-running process. 20 | It will never run out of memory unless you give an 21 | unrealistically large source file. 22 | 23 | If we really need to free memory, we could use Boehm garbage 24 | collector. I don't see that need at this moment though. 25 | 26 | # Backend 27 | 28 | Backend is being rewritten. Once it's done, the current backend 29 | code will be discarded. The new backend models after the LLVM IR 30 | because the IR looks to be designed well. That's not going to be 31 | the same, though. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rui Ueyama 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -Wno-strict-aliasing -std=gnu11 -g -I. -O0 2 | OBJS=cpp.o debug.o dict.o gen.o lex.o vector.o parse.o buffer.o map.o \ 3 | error.o path.o file.o set.o encoding.o 4 | TESTS := $(patsubst %.c,%.bin,$(filter-out test/testmain.c,$(wildcard test/*.c))) 5 | ECC=./8cc 6 | override CFLAGS += -DBUILD_DIR='"$(shell pwd)"' 7 | 8 | 8cc: 8cc.h main.o $(OBJS) 9 | cc -o $@ main.o $(OBJS) $(LDFLAGS) 10 | 11 | $(OBJS) utiltest.o main.o: 8cc.h keyword.inc 12 | 13 | utiltest: 8cc.h utiltest.o $(OBJS) 14 | cc -o $@ utiltest.o $(OBJS) $(LDFLAGS) 15 | 16 | test/%.o: test/%.c $(ECC) 17 | $(ECC) -w -o $@ -c $< 18 | 19 | test/%.bin: test/%.o test/testmain.o 20 | cc -o $@ $< test/testmain.o $(LDFLAGS) 21 | 22 | self: 8cc cleanobj 23 | $(MAKE) CC=$(ECC) CFLAGS= 8cc 24 | 25 | test: 8cc $(TESTS) 26 | $(MAKE) CC=$(ECC) CFLAGS= utiltest 27 | ./utiltest 28 | ./test/ast.sh 29 | ./test/negative.py 30 | $(MAKE) runtests 31 | 32 | runtests: 33 | @for test in $(TESTS); do \ 34 | ./$$test || exit; \ 35 | done 36 | 37 | stage1: 38 | $(MAKE) cleanobj 39 | [ -f 8cc ] || $(MAKE) 8cc 40 | mv 8cc stage1 41 | 42 | stage2: stage1 43 | $(MAKE) cleanobj 44 | $(MAKE) CC=./stage1 ECC=./stage1 CFLAGS= 8cc 45 | mv 8cc stage2 46 | 47 | stage3: stage2 48 | $(MAKE) cleanobj 49 | $(MAKE) CC=./stage2 ECC=./stage2 CFLAGS= 8cc 50 | mv 8cc stage3 51 | 52 | # Compile and run the tests with the default compiler. 53 | testtest: 54 | $(MAKE) clean 55 | $(MAKE) $(TESTS) 56 | $(MAKE) runtests 57 | 58 | fulltest: testtest 59 | $(MAKE) stage1 60 | $(MAKE) CC=./stage1 ECC=./stage1 CFLAGS= test 61 | $(MAKE) stage2 62 | $(MAKE) CC=./stage2 ECC=./stage2 CFLAGS= test 63 | $(MAKE) stage3 64 | cmp stage2 stage3 65 | 66 | clean: cleanobj 67 | rm -f 8cc stage? 68 | 69 | cleanobj: 70 | rm -f *.o *.s test/*.o test/*.bin utiltest 71 | 72 | all: 8cc 73 | 74 | .PHONY: clean cleanobj test runtests fulltest self all 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 8cc C Compiler 2 | ============== 3 | 4 | Note: 8cc is no longer an active project. The successor is 5 | [chibicc](https://github.com/rui314/chibicc). 6 | 7 | 8cc is a compiler for the C programming language. 8 | It's intended to support all C11 language features 9 | while keeping the code as small and simple as possible. 10 | 11 | The compiler is able to compile itself. 12 | You can see its code both as an implementation of the C language 13 | and as an example of what this compiler is able to compile. 14 | 15 | 8cc's source code is carefully written to be as concise and easy-to-read 16 | as possible, so that the source code becomes good study material 17 | to learn about various techniques used in compilers. 18 | You may find the lexer, the preprocessor and the parser are 19 | already useful to learn how C source code is processed at each stage. 20 | 21 | It's not an optimizing compiler. 22 | Generated code is usually 2x or more slower than GCC. 23 | I plan to implement a reasonable level of optimization in the future. 24 | 25 | 8cc supports x86-64 Linux only. I have no plan to make it portable until 26 | I fix all known miscompilations and implement an optimization pass. 27 | As of 2015, I'm using Ubuntu 14 as my development platform. 28 | It should work on other x86-64 Linux distributions though. 29 | 30 | Note: Do not have high expectations on this compiler. 31 | If you try to compile a program other than the compiler itself, 32 | there's a good chance to see compile errors or miscompilations. 33 | This is basically a one-man project, and I have spent only a few 34 | months of my spare time so far. 35 | 36 | Build 37 | ----- 38 | 39 | Run make to build: 40 | 41 | make 42 | 43 | 8cc comes with unit tests. To run the tests, give "test" as an argument: 44 | 45 | make test 46 | 47 | The following target builds 8cc three times to verify that 48 | stage1 compiler can build stage2, and stage2 can build stage3. 49 | It then compares stage2 and stage3 binaries byte-by-byte to verify 50 | that we reach a fixed point. 51 | 52 | make fulltest 53 | 54 | Author 55 | ------ 56 | 57 | Rui Ueyama 58 | 59 | 60 | Links for C compiler development 61 | -------------------------------- 62 | 63 | Besides popular books about compiler, such as the Dragon Book, 64 | I found the following books/documents are very useful 65 | to develop a C compiler. 66 | Note that the standard draft versions are very close to the ratified versions. 67 | You can practically use them as the standard documents. 68 | 69 | - LCC: A Retargetable C Compiler: Design and Implementation 70 | http://www.amazon.com/dp/0805316701, 71 | https://github.com/drh/lcc 72 | 73 | - TCC: Tiny C Compiler 74 | http://bellard.org/tcc/, 75 | http://repo.or.cz/w/tinycc.git/tree 76 | 77 | - C99 standard final draft 78 | http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf 79 | 80 | - C11 standard final draft 81 | http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 82 | 83 | - Dave Prosser's C Preprocessing Algorithm 84 | http://www.spinellis.gr/blog/20060626/ 85 | 86 | - The x86-64 ABI 87 | http://www.x86-64.org/documentation/abi.pdf 88 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "8cc.h" 8 | 9 | #define INIT_SIZE 8 10 | 11 | Buffer *make_buffer() { 12 | Buffer *r = malloc(sizeof(Buffer)); 13 | r->body = malloc(INIT_SIZE); 14 | r->nalloc = INIT_SIZE; 15 | r->len = 0; 16 | return r; 17 | } 18 | 19 | static void realloc_body(Buffer *b) { 20 | int newsize = b->nalloc * 2; 21 | char *body = malloc(newsize); 22 | memcpy(body, b->body, b->len); 23 | b->body = body; 24 | b->nalloc = newsize; 25 | } 26 | 27 | char *buf_body(Buffer *b) { 28 | return b->body; 29 | } 30 | 31 | int buf_len(Buffer *b) { 32 | return b->len; 33 | } 34 | 35 | void buf_write(Buffer *b, char c) { 36 | if (b->nalloc == (b->len + 1)) 37 | realloc_body(b); 38 | b->body[b->len++] = c; 39 | } 40 | 41 | void buf_append(Buffer *b, char *s, int len) { 42 | for (int i = 0; i < len; i++) 43 | buf_write(b, s[i]); 44 | } 45 | 46 | void buf_printf(Buffer *b, char *fmt, ...) { 47 | va_list args; 48 | for (;;) { 49 | int avail = b->nalloc - b->len; 50 | va_start(args, fmt); 51 | int written = vsnprintf(b->body + b->len, avail, fmt, args); 52 | va_end(args); 53 | if (avail <= written) { 54 | realloc_body(b); 55 | continue; 56 | } 57 | b->len += written; 58 | return; 59 | } 60 | } 61 | 62 | char *vformat(char *fmt, va_list ap) { 63 | Buffer *b = make_buffer(); 64 | va_list aq; 65 | for (;;) { 66 | int avail = b->nalloc - b->len; 67 | va_copy(aq, ap); 68 | int written = vsnprintf(b->body + b->len, avail, fmt, aq); 69 | va_end(aq); 70 | if (avail <= written) { 71 | realloc_body(b); 72 | continue; 73 | } 74 | b->len += written; 75 | return buf_body(b); 76 | } 77 | } 78 | 79 | char *format(char *fmt, ...) { 80 | va_list ap; 81 | va_start(ap, fmt); 82 | char *r = vformat(fmt, ap); 83 | va_end(ap); 84 | return r; 85 | } 86 | 87 | static char *quote(char c) { 88 | switch (c) { 89 | case '"': return "\\\""; 90 | case '\\': return "\\\\"; 91 | case '\b': return "\\b"; 92 | case '\f': return "\\f"; 93 | case '\n': return "\\n"; 94 | case '\r': return "\\r"; 95 | case '\t': return "\\t"; 96 | } 97 | return NULL; 98 | } 99 | 100 | static void print(Buffer *b, char c) { 101 | char *q = quote(c); 102 | if (q) { 103 | buf_printf(b, "%s", q); 104 | } else if (isprint(c)) { 105 | buf_printf(b, "%c", c); 106 | } else { 107 | buf_printf(b, "\\x%02x", c); 108 | } 109 | } 110 | 111 | char *quote_cstring(char *p) { 112 | Buffer *b = make_buffer(); 113 | while (*p) 114 | print(b, *p++); 115 | return buf_body(b); 116 | } 117 | 118 | char *quote_cstring_len(char *p, int len) { 119 | Buffer *b = make_buffer(); 120 | for (int i = 0; i < len; i++) 121 | print(b, p[i]); 122 | return buf_body(b); 123 | } 124 | 125 | char *quote_char(char c) { 126 | if (c == '\\') return "\\\\"; 127 | if (c == '\'') return "\\'"; 128 | return format("%c", c); 129 | } 130 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "8cc.h" 4 | 5 | static char *decorate_int(char *name, Type *ty) { 6 | char *u = (ty->usig) ? "u" : ""; 7 | if (ty->bitsize > 0) 8 | return format("%s%s:%d:%d", u, name, ty->bitoff, ty->bitoff + ty->bitsize); 9 | return format("%s%s", u, name); 10 | } 11 | 12 | static char *do_ty2s(Dict *dict, Type *ty) { 13 | if (!ty) 14 | return "(nil)"; 15 | switch (ty->kind) { 16 | case KIND_VOID: return "void"; 17 | case KIND_BOOL: return "_Bool"; 18 | case KIND_CHAR: return decorate_int("char", ty); 19 | case KIND_SHORT: return decorate_int("short", ty); 20 | case KIND_INT: return decorate_int("int", ty); 21 | case KIND_LONG: return decorate_int("long", ty); 22 | case KIND_LLONG: return decorate_int("llong", ty); 23 | case KIND_FLOAT: return "float"; 24 | case KIND_DOUBLE: return "double"; 25 | case KIND_LDOUBLE: return "long double"; 26 | case KIND_PTR: 27 | return format("*%s", do_ty2s(dict, ty->ptr)); 28 | case KIND_ARRAY: 29 | return format("[%d]%s", ty->len, do_ty2s(dict, ty->ptr)); 30 | case KIND_STRUCT: { 31 | char *kind = ty->is_struct ? "struct" : "union"; 32 | if (dict_get(dict, format("%p", ty))) 33 | return format("(%s)", kind); 34 | dict_put(dict, format("%p", ty), (void *)1); 35 | if (ty->fields) { 36 | Buffer *b = make_buffer(); 37 | buf_printf(b, "(%s", kind); 38 | Vector *keys = dict_keys(ty->fields); 39 | for (int i = 0; i < vec_len(keys); i++) { 40 | char *key = vec_get(keys, i); 41 | Type *fieldtype = dict_get(ty->fields, key); 42 | buf_printf(b, " (%s)", do_ty2s(dict, fieldtype)); 43 | } 44 | buf_printf(b, ")"); 45 | return buf_body(b); 46 | } 47 | } 48 | case KIND_FUNC: { 49 | Buffer *b = make_buffer(); 50 | buf_printf(b, "("); 51 | if (ty->params) { 52 | for (int i = 0; i < vec_len(ty->params); i++) { 53 | if (i > 0) 54 | buf_printf(b, ","); 55 | Type *t = vec_get(ty->params, i); 56 | buf_printf(b, "%s", do_ty2s(dict, t)); 57 | } 58 | } 59 | buf_printf(b, ")=>%s", do_ty2s(dict, ty->rettype)); 60 | return buf_body(b); 61 | } 62 | default: 63 | return format("(Unknown ty: %d)", ty->kind); 64 | } 65 | } 66 | 67 | char *ty2s(Type *ty) { 68 | return do_ty2s(make_dict(), ty); 69 | } 70 | 71 | static void uop_to_string(Buffer *b, char *op, Node *node) { 72 | buf_printf(b, "(%s %s)", op, node2s(node->operand)); 73 | } 74 | 75 | static void binop_to_string(Buffer *b, char *op, Node *node) { 76 | buf_printf(b, "(%s %s %s)", op, node2s(node->left), node2s(node->right)); 77 | } 78 | 79 | static void a2s_declinit(Buffer *b, Vector *initlist) { 80 | for (int i = 0; i < vec_len(initlist); i++) { 81 | if (i > 0) 82 | buf_printf(b, " "); 83 | Node *init = vec_get(initlist, i); 84 | buf_printf(b, "%s", node2s(init)); 85 | } 86 | } 87 | 88 | static void do_node2s(Buffer *b, Node *node) { 89 | if (!node) { 90 | buf_printf(b, "(nil)"); 91 | return; 92 | } 93 | switch (node->kind) { 94 | case AST_LITERAL: 95 | switch (node->ty->kind) { 96 | case KIND_CHAR: 97 | if (node->ival == '\n') buf_printf(b, "'\n'"); 98 | else if (node->ival == '\\') buf_printf(b, "'\\\\'"); 99 | else if (node->ival == '\0') buf_printf(b, "'\\0'"); 100 | else buf_printf(b, "'%c'", node->ival); 101 | break; 102 | case KIND_INT: 103 | buf_printf(b, "%d", node->ival); 104 | break; 105 | case KIND_LONG: 106 | buf_printf(b, "%ldL", node->ival); 107 | break; 108 | case KIND_LLONG: 109 | buf_printf(b, "%lldL", node->ival); 110 | break; 111 | case KIND_FLOAT: 112 | case KIND_DOUBLE: 113 | case KIND_LDOUBLE: 114 | buf_printf(b, "%f", node->fval); 115 | break; 116 | case KIND_ARRAY: 117 | buf_printf(b, "\"%s\"", quote_cstring(node->sval)); 118 | break; 119 | default: 120 | error("internal error"); 121 | } 122 | break; 123 | case AST_LABEL: 124 | buf_printf(b, "%s:", node->label); 125 | break; 126 | case AST_LVAR: 127 | buf_printf(b, "lv=%s", node->varname); 128 | if (node->lvarinit) { 129 | buf_printf(b, "("); 130 | a2s_declinit(b, node->lvarinit); 131 | buf_printf(b, ")"); 132 | } 133 | break; 134 | case AST_GVAR: 135 | buf_printf(b, "gv=%s", node->varname); 136 | break; 137 | case AST_FUNCALL: 138 | case AST_FUNCPTR_CALL: { 139 | buf_printf(b, "(%s)%s(", ty2s(node->ty), 140 | node->kind == AST_FUNCALL ? node->fname : node2s(node)); 141 | for (int i = 0; i < vec_len(node->args); i++) { 142 | if (i > 0) 143 | buf_printf(b, ","); 144 | buf_printf(b, "%s", node2s(vec_get(node->args, i))); 145 | } 146 | buf_printf(b, ")"); 147 | break; 148 | } 149 | case AST_FUNCDESG: { 150 | buf_printf(b, "(funcdesg %s)", node->fname); 151 | break; 152 | } 153 | case AST_FUNC: { 154 | buf_printf(b, "(%s)%s(", ty2s(node->ty), node->fname); 155 | for (int i = 0; i < vec_len(node->params); i++) { 156 | if (i > 0) 157 | buf_printf(b, ","); 158 | Node *param = vec_get(node->params, i); 159 | buf_printf(b, "%s %s", ty2s(param->ty), node2s(param)); 160 | } 161 | buf_printf(b, ")"); 162 | do_node2s(b, node->body); 163 | break; 164 | } 165 | case AST_GOTO: 166 | buf_printf(b, "goto(%s)", node->label); 167 | break; 168 | case AST_DECL: 169 | buf_printf(b, "(decl %s %s", 170 | ty2s(node->declvar->ty), 171 | node->declvar->varname); 172 | if (node->declinit) { 173 | buf_printf(b, " "); 174 | a2s_declinit(b, node->declinit); 175 | } 176 | buf_printf(b, ")"); 177 | break; 178 | case AST_INIT: 179 | buf_printf(b, "%s@%d", node2s(node->initval), node->initoff, ty2s(node->totype)); 180 | break; 181 | case AST_CONV: 182 | buf_printf(b, "(conv %s=>%s)", node2s(node->operand), ty2s(node->ty)); 183 | break; 184 | case AST_IF: 185 | buf_printf(b, "(if %s %s", 186 | node2s(node->cond), 187 | node2s(node->then)); 188 | if (node->els) 189 | buf_printf(b, " %s", node2s(node->els)); 190 | buf_printf(b, ")"); 191 | break; 192 | case AST_TERNARY: 193 | buf_printf(b, "(? %s %s %s)", 194 | node2s(node->cond), 195 | node2s(node->then), 196 | node2s(node->els)); 197 | break; 198 | case AST_RETURN: 199 | buf_printf(b, "(return %s)", node2s(node->retval)); 200 | break; 201 | case AST_COMPOUND_STMT: { 202 | buf_printf(b, "{"); 203 | for (int i = 0; i < vec_len(node->stmts); i++) { 204 | do_node2s(b, vec_get(node->stmts, i)); 205 | buf_printf(b, ";"); 206 | } 207 | buf_printf(b, "}"); 208 | break; 209 | } 210 | case AST_STRUCT_REF: 211 | do_node2s(b, node->struc); 212 | buf_printf(b, "."); 213 | buf_printf(b, node->field); 214 | break; 215 | case AST_ADDR: uop_to_string(b, "addr", node); break; 216 | case AST_DEREF: uop_to_string(b, "deref", node); break; 217 | case OP_SAL: binop_to_string(b, "<<", node); break; 218 | case OP_SAR: 219 | case OP_SHR: binop_to_string(b, ">>", node); break; 220 | case OP_GE: binop_to_string(b, ">=", node); break; 221 | case OP_LE: binop_to_string(b, "<=", node); break; 222 | case OP_NE: binop_to_string(b, "!=", node); break; 223 | case OP_PRE_INC: uop_to_string(b, "pre++", node); break; 224 | case OP_PRE_DEC: uop_to_string(b, "pre--", node); break; 225 | case OP_POST_INC: uop_to_string(b, "post++", node); break; 226 | case OP_POST_DEC: uop_to_string(b, "post--", node); break; 227 | case OP_LOGAND: binop_to_string(b, "and", node); break; 228 | case OP_LOGOR: binop_to_string(b, "or", node); break; 229 | case OP_A_ADD: binop_to_string(b, "+=", node); break; 230 | case OP_A_SUB: binop_to_string(b, "-=", node); break; 231 | case OP_A_MUL: binop_to_string(b, "*=", node); break; 232 | case OP_A_DIV: binop_to_string(b, "/=", node); break; 233 | case OP_A_MOD: binop_to_string(b, "%=", node); break; 234 | case OP_A_AND: binop_to_string(b, "&=", node); break; 235 | case OP_A_OR: binop_to_string(b, "|=", node); break; 236 | case OP_A_XOR: binop_to_string(b, "^=", node); break; 237 | case OP_A_SAL: binop_to_string(b, "<<=", node); break; 238 | case OP_A_SAR: 239 | case OP_A_SHR: binop_to_string(b, ">>=", node); break; 240 | case '!': uop_to_string(b, "!", node); break; 241 | case '&': binop_to_string(b, "&", node); break; 242 | case '|': binop_to_string(b, "|", node); break; 243 | case OP_CAST: { 244 | buf_printf(b, "((%s)=>(%s) %s)", 245 | ty2s(node->operand->ty), 246 | ty2s(node->ty), 247 | node2s(node->operand)); 248 | break; 249 | } 250 | case OP_LABEL_ADDR: 251 | buf_printf(b, "&&%s", node->label); 252 | break; 253 | default: { 254 | char *left = node2s(node->left); 255 | char *right = node2s(node->right); 256 | if (node->kind == OP_EQ) 257 | buf_printf(b, "(== "); 258 | else 259 | buf_printf(b, "(%c ", node->kind); 260 | buf_printf(b, "%s %s)", left, right); 261 | } 262 | } 263 | } 264 | 265 | char *node2s(Node *node) { 266 | Buffer *b = make_buffer(); 267 | do_node2s(b, node); 268 | return buf_body(b); 269 | } 270 | 271 | static char *encoding_prefix(int enc) { 272 | switch (enc) { 273 | case ENC_CHAR16: return "u"; 274 | case ENC_CHAR32: return "U"; 275 | case ENC_UTF8: return "u8"; 276 | case ENC_WCHAR: return "L"; 277 | } 278 | return ""; 279 | } 280 | 281 | char *tok2s(Token *tok) { 282 | if (!tok) 283 | return "(null)"; 284 | switch (tok->kind) { 285 | case TIDENT: 286 | return tok->sval; 287 | case TKEYWORD: 288 | switch (tok->id) { 289 | #define op(id, str) case id: return str; 290 | #define keyword(id, str, _) case id: return str; 291 | #include "keyword.inc" 292 | #undef keyword 293 | #undef op 294 | default: return format("%c", tok->id); 295 | } 296 | case TCHAR: 297 | return format("%s'%s'", 298 | encoding_prefix(tok->enc), 299 | quote_char(tok->c)); 300 | case TNUMBER: 301 | return tok->sval; 302 | case TSTRING: 303 | return format("%s\"%s\"", 304 | encoding_prefix(tok->enc), 305 | quote_cstring(tok->sval)); 306 | case TEOF: 307 | return "(eof)"; 308 | case TINVALID: 309 | return format("%c", tok->c); 310 | case TNEWLINE: 311 | return "(newline)"; 312 | case TSPACE: 313 | return "(space)"; 314 | case TMACRO_PARAM: 315 | return "(macro-param)"; 316 | } 317 | error("internal error: unknown token kind: %d", tok->kind); 318 | } 319 | -------------------------------------------------------------------------------- /dict.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "8cc.h" 5 | 6 | Dict *make_dict() { 7 | Dict *r = malloc(sizeof(Dict)); 8 | r->map = make_map(); 9 | r->key = make_vector(); 10 | return r; 11 | } 12 | 13 | void *dict_get(Dict *dict, char *key) { 14 | return map_get(dict->map, key); 15 | } 16 | 17 | void dict_put(Dict *dict, char *key, void *val) { 18 | map_put(dict->map, key, val); 19 | vec_push(dict->key, key); 20 | } 21 | 22 | Vector *dict_keys(Dict *dict) { 23 | return dict->key; 24 | } 25 | -------------------------------------------------------------------------------- /encoding.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Rui Ueyama. Released under the MIT license. 2 | 3 | // This file defines functions to convert UTF-8 strings to UTF-16 or UTF-32. 4 | // 5 | // 8cc uses UTF-16 for string literals prefixed with u (char16_t strings). 6 | // UTF-32 is used for string literals prefixed with L or U 7 | // (wchar_t or char32_t strings). 8 | // Unprefixed or u8 strings are supposed to be in UTF-8 endcoding. 9 | // Source files are supposed to be written in UTF-8. 10 | 11 | #include "8cc.h" 12 | 13 | static int count_leading_ones(char c) { 14 | for (int i = 7; i >= 0; i--) 15 | if ((c & (1 << i)) == 0) 16 | return 7 - i; 17 | return 8; 18 | } 19 | 20 | static int read_rune(uint32_t *r, char *s, char *end) { 21 | int len = count_leading_ones(s[0]); 22 | if (len == 0) { 23 | *r = s[0]; 24 | return 1; 25 | } 26 | if (s + len > end) 27 | error("invalid UTF-8 sequence"); 28 | for (int i = 1; i < len; i++) 29 | if ((s[i] & 0xC0) != 0x80) 30 | error("invalid UTF-8 continuation byte"); 31 | switch (len) { 32 | case 2: 33 | *r = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F); 34 | return 2; 35 | case 3: 36 | *r = ((s[0] & 0xF) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); 37 | return 3; 38 | case 4: 39 | *r = ((s[0] & 0x7) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F); 40 | return 4; 41 | } 42 | error("invalid UTF-8 sequence"); 43 | } 44 | 45 | static void write16(Buffer *b, uint16_t x) { 46 | buf_write(b, x & 0xFF); 47 | buf_write(b, x >> 8); 48 | } 49 | 50 | static void write32(Buffer *b, uint32_t x) { 51 | write16(b, x & 0xFFFF); 52 | write16(b, x >> 16); 53 | } 54 | 55 | Buffer *to_utf16(char *p, int len) { 56 | Buffer *b = make_buffer(); 57 | char *end = p + len; 58 | while (p != end) { 59 | uint32_t rune; 60 | p += read_rune(&rune, p, end); 61 | if (rune < 0x10000) { 62 | write16(b, rune); 63 | } else { 64 | write16(b, (rune >> 10) + 0xD7C0); 65 | write16(b, (rune & 0x3FF) + 0xDC00); 66 | } 67 | } 68 | return b; 69 | } 70 | 71 | Buffer *to_utf32(char *p, int len) { 72 | Buffer *b = make_buffer(); 73 | char *end = p + len; 74 | while (p != end) { 75 | uint32_t rune; 76 | p += read_rune(&rune, p, end); 77 | write32(b, rune); 78 | } 79 | return b; 80 | } 81 | 82 | void write_utf8(Buffer *b, uint32_t rune) { 83 | if (rune < 0x80) { 84 | buf_write(b, rune); 85 | return; 86 | } 87 | if (rune < 0x800) { 88 | buf_write(b, 0xC0 | (rune >> 6)); 89 | buf_write(b, 0x80 | (rune & 0x3F)); 90 | return; 91 | } 92 | if (rune < 0x10000) { 93 | buf_write(b, 0xE0 | (rune >> 12)); 94 | buf_write(b, 0x80 | ((rune >> 6) & 0x3F)); 95 | buf_write(b, 0x80 | (rune & 0x3F)); 96 | return; 97 | } 98 | if (rune < 0x200000) { 99 | buf_write(b, 0xF0 | (rune >> 18)); 100 | buf_write(b, 0x80 | ((rune >> 12) & 0x3F)); 101 | buf_write(b, 0x80 | ((rune >> 6) & 0x3F)); 102 | buf_write(b, 0x80 | (rune & 0x3F)); 103 | return; 104 | } 105 | error("invalid UCS character: \\U%08x", rune); 106 | } 107 | -------------------------------------------------------------------------------- /error.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include "8cc.h" 7 | 8 | bool enable_warning = true; 9 | bool warning_is_error = false; 10 | 11 | static void print_error(char *line, char *pos, char *label, char *fmt, va_list args) { 12 | fprintf(stderr, isatty(fileno(stderr)) ? "\e[1;31m[%s]\e[0m " : "[%s] ", label); 13 | fprintf(stderr, "%s: %s: ", line, pos); 14 | vfprintf(stderr, fmt, args); 15 | fprintf(stderr, "\n"); 16 | } 17 | 18 | void errorf(char *line, char *pos, char *fmt, ...) { 19 | va_list args; 20 | va_start(args, fmt); 21 | print_error(line, pos, "ERROR", fmt, args); 22 | va_end(args); 23 | exit(1); 24 | } 25 | 26 | void warnf(char *line, char *pos, char *fmt, ...) { 27 | if (!enable_warning) 28 | return; 29 | char *label = warning_is_error ? "ERROR" : "WARN"; 30 | va_list args; 31 | va_start(args, fmt); 32 | print_error(line, pos, label, fmt, args); 33 | va_end(args); 34 | if (warning_is_error) 35 | exit(1); 36 | } 37 | 38 | char *token_pos(Token *tok) { 39 | File *f = tok->file; 40 | if (!f) 41 | return "(unknown)"; 42 | char *name = f->name ? f->name : "(unknown)"; 43 | return format("%s:%d:%d", name, tok->line, tok->column); 44 | } 45 | -------------------------------------------------------------------------------- /file.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | /* 4 | * This file provides character input stream for C source code. 5 | * An input stream is either backed by stdio's FILE * or 6 | * backed by a string. 7 | * The following input processing is done at this stage. 8 | * 9 | * - C11 5.1.1.2p1: "\r\n" or "\r" are canonicalized to "\n". 10 | * - C11 5.1.1.2p2: A sequence of backslash and newline is removed. 11 | * - EOF not immediately following a newline is converted to 12 | * a sequence of newline and EOF. (The C spec requires source 13 | * files end in a newline character (5.1.1.2p2). Thus, if all 14 | * source files are comforming, this step wouldn't be needed.) 15 | * 16 | * Trigraphs are not supported by design. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "8cc.h" 26 | 27 | static Vector *files = &EMPTY_VECTOR; 28 | static Vector *stashed = &EMPTY_VECTOR; 29 | 30 | File *make_file(FILE *file, char *name) { 31 | File *r = calloc(1, sizeof(File)); 32 | r->file = file; 33 | r->name = name; 34 | r->line = 1; 35 | r->column = 1; 36 | struct stat st; 37 | if (fstat(fileno(file), &st) == -1) 38 | error("fstat failed: %s", strerror(errno)); 39 | r->mtime = st.st_mtime; 40 | return r; 41 | } 42 | 43 | File *make_file_string(char *s) { 44 | File *r = calloc(1, sizeof(File)); 45 | r->line = 1; 46 | r->column = 1; 47 | r->p = s; 48 | return r; 49 | } 50 | 51 | static void close_file(File *f) { 52 | if (f->file) 53 | fclose(f->file); 54 | } 55 | 56 | static int readc_file(File *f) { 57 | int c = getc(f->file); 58 | if (c == EOF) { 59 | c = (f->last == '\n' || f->last == EOF) ? EOF : '\n'; 60 | } else if (c == '\r') { 61 | int c2 = getc(f->file); 62 | if (c2 != '\n') 63 | ungetc(c2, f->file); 64 | c = '\n'; 65 | } 66 | f->last = c; 67 | return c; 68 | } 69 | 70 | static int readc_string(File *f) { 71 | int c; 72 | if (*f->p == '\0') { 73 | c = (f->last == '\n' || f->last == EOF) ? EOF : '\n'; 74 | } else if (*f->p == '\r') { 75 | f->p++; 76 | if (*f->p == '\n') 77 | f->p++; 78 | c = '\n'; 79 | } else { 80 | c = *f->p++; 81 | } 82 | f->last = c; 83 | return c; 84 | } 85 | 86 | static int get() { 87 | File *f = vec_tail(files); 88 | int c; 89 | if (f->buflen > 0) { 90 | c = f->buf[--f->buflen]; 91 | } else if (f->file) { 92 | c = readc_file(f); 93 | } else { 94 | c = readc_string(f); 95 | } 96 | if (c == '\n') { 97 | f->line++; 98 | f->column = 1; 99 | } else if (c != EOF) { 100 | f->column++; 101 | } 102 | return c; 103 | } 104 | 105 | int readc() { 106 | for (;;) { 107 | int c = get(); 108 | if (c == EOF) { 109 | if (vec_len(files) == 1) 110 | return c; 111 | close_file(vec_pop(files)); 112 | continue; 113 | } 114 | if (c != '\\') 115 | return c; 116 | int c2 = get(); 117 | if (c2 == '\n') 118 | continue; 119 | unreadc(c2); 120 | return c; 121 | } 122 | } 123 | 124 | void unreadc(int c) { 125 | if (c == EOF) 126 | return; 127 | File *f = vec_tail(files); 128 | assert(f->buflen < sizeof(f->buf) / sizeof(f->buf[0])); 129 | f->buf[f->buflen++] = c; 130 | if (c == '\n') { 131 | f->column = 1; 132 | f->line--; 133 | } else { 134 | f->column--; 135 | } 136 | } 137 | 138 | File *current_file() { 139 | return vec_tail(files); 140 | } 141 | 142 | void stream_push(File *f) { 143 | vec_push(files, f); 144 | } 145 | 146 | int stream_depth() { 147 | return vec_len(files); 148 | } 149 | 150 | char *input_position() { 151 | if (vec_len(files) == 0) 152 | return "(unknown)"; 153 | File *f = vec_tail(files); 154 | return format("%s:%d:%d", f->name, f->line, f->column); 155 | } 156 | 157 | void stream_stash(File *f) { 158 | vec_push(stashed, files); 159 | files = make_vector1(f); 160 | } 161 | 162 | void stream_unstash() { 163 | files = vec_pop(stashed); 164 | } 165 | -------------------------------------------------------------------------------- /include/8cc.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #define _LP64 1 4 | #define __8cc__ 1 5 | #define __ELF__ 1 6 | #define __LP64__ 1 7 | #define __SIZEOF_DOUBLE__ 8 8 | #define __SIZEOF_FLOAT__ 4 9 | #define __SIZEOF_INT__ 4 10 | #define __SIZEOF_LONG_DOUBLE__ 8 11 | #define __SIZEOF_LONG_LONG__ 8 12 | #define __SIZEOF_LONG__ 8 13 | #define __SIZEOF_POINTER__ 8 14 | #define __SIZEOF_PTRDIFF_T__ 8 15 | #define __SIZEOF_SHORT__ 2 16 | #define __SIZEOF_SIZE_T__ 8 17 | #define __STDC_HOSTED__ 1 18 | #define __STDC_ISO_10646__ 201103L 19 | #define __STDC_NO_ATOMICS__ 1 20 | #define __STDC_NO_COMPLEX__ 1 21 | #define __STDC_NO_THREADS__ 1 22 | #define __STDC_NO_VLA__ 1 23 | #define __STDC_UTF_16__ 1 24 | #define __STDC_UTF_32__ 1 25 | #define __STDC_VERSION__ 201112L 26 | #define __STDC__ 1 27 | #define __amd64 1 28 | #define __amd64__ 1 29 | #define __gnu_linux__ 1 30 | #define __linux 1 31 | #define __linux__ 1 32 | #define __unix 1 33 | #define __unix__ 1 34 | #define __x86_64 1 35 | #define __x86_64__ 1 36 | #define linux 1 37 | 38 | #define __alignof__ alignof 39 | #define __const__ const 40 | #define __inline__ inline 41 | #define __restrict restrict 42 | #define __restrict__ restrict 43 | #define __signed__ signed 44 | #define __typeof__ typeof 45 | #define __volatile__ volatile 46 | 47 | typedef unsigned short char16_t; 48 | typedef unsigned int char32_t; 49 | -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDFLOAT_H 4 | #define __STDFLOAT_H 5 | 6 | #define DECIMAL_DIG 21 7 | #define FLT_EVAL_METHOD 0 // C11 5.2.4.2.2p9 8 | #define FLT_RADIX 2 9 | #define FLT_ROUNDS 1 // C11 5.2.4.2.2p8: to nearest 10 | 11 | #define FLT_DIG 6 12 | #define FLT_EPSILON 0x1p-23 13 | #define FLT_MANT_DIG 24 14 | #define FLT_MAX 0x1.fffffep+127 15 | #define FLT_MAX_10_EXP 38 16 | #define FLT_MAX_EXP 128 17 | #define FLT_MIN 0x1p-126 18 | #define FLT_MIN_10_EXP -37 19 | #define FLT_MIN_EXP -125 20 | #define FLT_TRUE_MIN 0x1p-149 21 | 22 | #define DBL_DIG 15 23 | #define DBL_EPSILON 0x1p-52 24 | #define DBL_MANT_DIG 53 25 | #define DBL_MAX 0x1.fffffffffffffp+1023 26 | #define DBL_MAX_10_EXP 308 27 | #define DBL_MAX_EXP 1024 28 | #define DBL_MIN 0x1p-1022 29 | #define DBL_MIN_10_EXP -307 30 | #define DBL_MIN_EXP -1021 31 | #define DBL_TRUE_MIN 0x0.0000000000001p-1022 32 | 33 | #define LDBL_DIG 15 34 | #define LDBL_EPSILON 0x1p-52 35 | #define LDBL_MANT_DIG 53 36 | #define LDBL_MAX 0x1.fffffffffffffp+1023 37 | #define LDBL_MAX_10_EXP 308 38 | #define LDBL_MAX_EXP 1024 39 | #define LDBL_MIN 0x1p-1022 40 | #define LDBL_MIN_10_EXP -307 41 | #define LDBL_MIN_EXP -1021 42 | #define LDBL_TRUE_MIN 0x0.0000000000001p-1022 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/iso646.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | // C11 7.9 Alternative Spellings 4 | 5 | #ifndef __ISO646_H 6 | #define __ISO646_H 7 | 8 | #define and && 9 | #define and_eq &= 10 | #define bitand & 11 | #define bitor | 12 | #define compl ~ 13 | #define not ! 14 | #define not_eq != 15 | #define or || 16 | #define or_eq |= 17 | #define xor ^ 18 | #define xor_eq ^= 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/stdalign.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDALIGN_H 4 | #define __STDALIGN_H 5 | 6 | #define alignas _Alignas 7 | #define alignof _Alignof 8 | #define __alignas_is_defined 1 9 | #define __alignof_is_defined 1 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDARG_H 4 | #define __STDARG_H 5 | 6 | /** 7 | * Refer this document for the x86-64 ABI. 8 | * http://www.x86-64.org/documentation/abi.pdf 9 | */ 10 | 11 | typedef struct { 12 | unsigned int gp_offset; 13 | unsigned int fp_offset; 14 | void *overflow_arg_area; 15 | void *reg_save_area; 16 | } __va_elem; 17 | 18 | typedef __va_elem va_list[1]; 19 | 20 | static void *__va_arg_gp(__va_elem *ap) { 21 | void *r = (char *)ap->reg_save_area + ap->gp_offset; 22 | ap->gp_offset += 8; 23 | return r; 24 | } 25 | 26 | static void *__va_arg_fp(__va_elem *ap) { 27 | void *r = (char *)ap->reg_save_area + ap->fp_offset; 28 | ap->fp_offset += 16; 29 | return r; 30 | } 31 | 32 | static void *__va_arg_mem(__va_elem *ap) { 33 | 1 / 0; // unimplemented 34 | } 35 | 36 | #define va_start(ap, last) __builtin_va_start(ap) 37 | #define va_arg(ap, type) \ 38 | ({ \ 39 | int klass = __builtin_reg_class((type *)0); \ 40 | *(type *)(klass == 0 ? __va_arg_gp(ap) : \ 41 | klass == 1 ? __va_arg_fp(ap) : \ 42 | __va_arg_mem(ap)); \ 43 | }) 44 | 45 | #define va_end(ap) 1 46 | #define va_copy(dest, src) ((dest)[0] = (src)[0]) 47 | 48 | // Workaround to load stdio.h properly 49 | #define __GNUC_VA_LIST 1 50 | typedef va_list __gnuc_va_list; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDBOOL_H 4 | #define __STDBOOL_H 5 | 6 | #define bool _Bool 7 | #define true 1 8 | #define false 0 9 | #define __bool_true_false_are_defined 1 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDDEF_H 4 | #define __STDDEF_H 5 | 6 | #define NULL ((void *)0) 7 | 8 | typedef unsigned long size_t; 9 | typedef long ptrdiff_t; 10 | typedef unsigned int wchar_t; 11 | typedef long double max_align_t; 12 | 13 | #define offsetof(type, member) ((size_t)&(((type *)0)->member)) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef __STDNORETURN_H 4 | #define __STDNORETURN_H 5 | 6 | #define noreturn _Noreturn 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /keyword.inc: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | op(OP_ARROW, "->") 4 | op(OP_A_ADD, "+=") 5 | op(OP_A_AND, "&=") 6 | op(OP_A_DIV, "/=") 7 | op(OP_A_MOD, "%=") 8 | op(OP_A_MUL, "*=") 9 | op(OP_A_OR, "|=") 10 | op(OP_A_SAL, "<<=") 11 | op(OP_A_SAR, ">>=") 12 | op(OP_A_SUB, "-=") 13 | op(OP_A_XOR, "^=") 14 | op(OP_DEC, "--") 15 | op(OP_EQ, "==") 16 | op(OP_GE, ">=") 17 | op(OP_INC, "++") 18 | op(OP_LE, "<=") 19 | op(OP_LOGAND, "&&") 20 | op(OP_LOGOR, "||") 21 | op(OP_NE, "!=") 22 | op(OP_SAL, "<<") 23 | op(OP_SAR, ">>") 24 | 25 | keyword(KALIGNAS, "_Alignas", true) 26 | keyword(KALIGNOF, "_Alignof", false) 27 | keyword(KAUTO, "auto", true) 28 | keyword(KBOOL, "_Bool", true) 29 | keyword(KBREAK, "break", false) 30 | keyword(KCASE, "case", false) 31 | keyword(KCHAR, "char", true) 32 | keyword(KCOMPLEX, "_Complex", true) 33 | keyword(KCONST, "const", true) 34 | keyword(KCONTINUE, "continue", false) 35 | keyword(KDEFAULT, "default", false) 36 | keyword(KDO, "do", false) 37 | keyword(KDOUBLE, "double", true) 38 | keyword(KELSE, "else", false) 39 | keyword(KENUM, "enum", true) 40 | keyword(KEXTERN, "extern", true) 41 | keyword(KFLOAT, "float", true) 42 | keyword(KFOR, "for", false) 43 | keyword(KGENERIC, "_Generic", false) 44 | keyword(KGOTO, "goto", false) 45 | keyword(KIF, "if", false) 46 | keyword(KIMAGINARY, "_Imaginary", true) 47 | keyword(KINLINE, "inline", true) 48 | keyword(KINT, "int", true) 49 | keyword(KLONG, "long", true) 50 | keyword(KNORETURN, "_Noreturn", true) 51 | keyword(KREGISTER, "register", true) 52 | keyword(KRESTRICT, "restrict", true) 53 | keyword(KRETURN, "return", false) 54 | keyword(KHASHHASH, "##", false) 55 | keyword(KSHORT, "short", true) 56 | keyword(KSIGNED, "signed", true) 57 | keyword(KSIZEOF, "sizeof", false) 58 | keyword(KSTATIC, "static", true) 59 | keyword(KSTATIC_ASSERT, "_Static_assert", false) 60 | keyword(KSTRUCT, "struct", true) 61 | keyword(KSWITCH, "switch", false) 62 | keyword(KELLIPSIS, "...", false) 63 | keyword(KTYPEDEF, "typedef", true) 64 | keyword(KTYPEOF, "typeof", true) 65 | keyword(KUNION, "union", true) 66 | keyword(KUNSIGNED, "unsigned", true) 67 | keyword(KVOID, "void", true) 68 | keyword(KVOLATILE, "volatile", true) 69 | keyword(KWHILE, "while", false) 70 | -------------------------------------------------------------------------------- /lex.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | /* 4 | * Tokenizer 5 | * 6 | * This is a translation phase after the phase 1 and 2 in file.c. 7 | * In this phase, the source code is decomposed into preprocessing tokens. 8 | * 9 | * Each comment is treated as if it were a space character. 10 | * Space characters are removed, but the presence of the characters is 11 | * recorded to the token that immediately follows the spaces as a boolean flag. 12 | * Newlines are converted to newline tokens. 13 | * 14 | * Note that the pp-token is different from the regular token. 15 | * A keyword, such as "if", is just an identifier at this stage. 16 | * The definition of the pp-token is usually more relaxed than 17 | * the regular one. For example, ".32e." is a valid pp-number. 18 | * Pp-tokens are converted to regular tokens by the C preprocesor 19 | * (and invalid tokens are rejected by that). 20 | * Some tokens are removed by the preprocessor (e.g. newline). 21 | * For more information about pp-tokens, see C11 6.4 "Lexical Elements". 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "8cc.h" 29 | 30 | static Vector *buffers = &EMPTY_VECTOR; 31 | static Token *space_token = &(Token){ TSPACE }; 32 | static Token *newline_token = &(Token){ TNEWLINE }; 33 | static Token *eof_token = &(Token){ TEOF }; 34 | 35 | typedef struct { 36 | int line; 37 | int column; 38 | } Pos; 39 | 40 | static Pos pos; 41 | 42 | static char *pos_string(Pos *p) { 43 | File *f = current_file(); 44 | return format("%s:%d:%d", f ? f->name : "(unknown)", p->line, p->column); 45 | } 46 | 47 | #define errorp(p, ...) errorf(__FILE__ ":" STR(__LINE__), pos_string(&p), __VA_ARGS__) 48 | #define warnp(p, ...) warnf(__FILE__ ":" STR(__LINE__), pos_string(&p), __VA_ARGS__) 49 | 50 | static void skip_block_comment(void); 51 | 52 | void lex_init(char *filename) { 53 | vec_push(buffers, make_vector()); 54 | if (!strcmp(filename, "-")) { 55 | stream_push(make_file(stdin, "-")); 56 | return; 57 | } 58 | FILE *fp = fopen(filename, "r"); 59 | if (!fp) 60 | error("Cannot open %s: %s", filename, strerror(errno)); 61 | stream_push(make_file(fp, filename)); 62 | } 63 | 64 | static Pos get_pos(int delta) { 65 | File *f = current_file(); 66 | return (Pos){ f->line, f->column + delta }; 67 | } 68 | 69 | static void mark() { 70 | pos = get_pos(0); 71 | } 72 | 73 | static Token *make_token(Token *tmpl) { 74 | Token *r = malloc(sizeof(Token)); 75 | *r = *tmpl; 76 | r->hideset = NULL; 77 | File *f = current_file(); 78 | r->file = f; 79 | r->line = pos.line; 80 | r->column = pos.column; 81 | r->count = f->ntok++; 82 | return r; 83 | } 84 | 85 | static Token *make_ident(char *p) { 86 | return make_token(&(Token){ TIDENT, .sval = p }); 87 | } 88 | 89 | static Token *make_strtok(char *s, int len, int enc) { 90 | return make_token(&(Token){ TSTRING, .sval = s, .slen = len, .enc = enc }); 91 | } 92 | 93 | static Token *make_keyword(int id) { 94 | return make_token(&(Token){ TKEYWORD, .id = id }); 95 | } 96 | 97 | static Token *make_number(char *s) { 98 | return make_token(&(Token){ TNUMBER, .sval = s }); 99 | } 100 | 101 | static Token *make_invalid(char c) { 102 | return make_token(&(Token){ TINVALID, .c = c }); 103 | } 104 | 105 | static Token *make_char(int c, int enc) { 106 | return make_token(&(Token){ TCHAR, .c = c, .enc = enc }); 107 | } 108 | 109 | static bool iswhitespace(int c) { 110 | return c == ' ' || c == '\t' || c == '\f' || c == '\v'; 111 | } 112 | 113 | static int peek() { 114 | int r = readc(); 115 | unreadc(r); 116 | return r; 117 | } 118 | 119 | static bool next(int expect) { 120 | int c = readc(); 121 | if (c == expect) 122 | return true; 123 | unreadc(c); 124 | return false; 125 | } 126 | 127 | static void skip_line() { 128 | for (;;) { 129 | int c = readc(); 130 | if (c == EOF) 131 | return; 132 | if (c == '\n') { 133 | unreadc(c); 134 | return; 135 | } 136 | } 137 | } 138 | 139 | static bool do_skip_space() { 140 | int c = readc(); 141 | if (c == EOF) 142 | return false; 143 | if (iswhitespace(c)) 144 | return true; 145 | if (c == '/') { 146 | if (next('*')) { 147 | skip_block_comment(); 148 | return true; 149 | } 150 | if (next('/')) { 151 | skip_line(); 152 | return true; 153 | } 154 | } 155 | unreadc(c); 156 | return false; 157 | } 158 | 159 | // Skips spaces including comments. 160 | // Returns true if at least one space is skipped. 161 | static bool skip_space() { 162 | if (!do_skip_space()) 163 | return false; 164 | while (do_skip_space()); 165 | return true; 166 | } 167 | 168 | static void skip_char() { 169 | if (readc() == '\\') 170 | readc(); 171 | int c = readc(); 172 | while (c != EOF && c != '\'') 173 | c = readc(); 174 | } 175 | 176 | static void skip_string() { 177 | for (int c = readc(); c != EOF && c != '"'; c = readc()) 178 | if (c == '\\') 179 | readc(); 180 | } 181 | 182 | // Skips a block of code excluded from input by #if, #ifdef and the like. 183 | // C11 6.10 says that code within #if and #endif needs to be a sequence of 184 | // valid tokens even if skipped. However, in reality, most compilers don't 185 | // tokenize nor validate contents. We don't do that, too. 186 | // This function is to skip code until matching #endif as fast as we can. 187 | void skip_cond_incl() { 188 | int nest = 0; 189 | for (;;) { 190 | bool bol = (current_file()->column == 1); 191 | skip_space(); 192 | int c = readc(); 193 | if (c == EOF) 194 | return; 195 | if (c == '\'') { 196 | skip_char(); 197 | continue; 198 | } 199 | if (c == '\"') { 200 | skip_string(); 201 | continue; 202 | } 203 | if (c != '#' || !bol) 204 | continue; 205 | int column = current_file()->column - 1; 206 | Token *tok = lex(); 207 | if (tok->kind != TIDENT) 208 | continue; 209 | if (!nest && (is_ident(tok, "else") || is_ident(tok, "elif") || is_ident(tok, "endif"))) { 210 | unget_token(tok); 211 | Token *hash = make_keyword('#'); 212 | hash->bol = true; 213 | hash->column = column; 214 | unget_token(hash); 215 | return; 216 | } 217 | if (is_ident(tok, "if") || is_ident(tok, "ifdef") || is_ident(tok, "ifndef")) 218 | nest++; 219 | else if (nest && is_ident(tok, "endif")) 220 | nest--; 221 | skip_line(); 222 | } 223 | } 224 | 225 | // Reads a number literal. Lexer's grammar on numbers is not strict. 226 | // Integers and floating point numbers and different base numbers are not distinguished. 227 | static Token *read_number(char c) { 228 | Buffer *b = make_buffer(); 229 | buf_write(b, c); 230 | char last = c; 231 | for (;;) { 232 | int c = readc(); 233 | bool flonum = strchr("eEpP", last) && strchr("+-", c); 234 | if (!isdigit(c) && !isalpha(c) && c != '.' && !flonum) { 235 | unreadc(c); 236 | buf_write(b, '\0'); 237 | return make_number(buf_body(b)); 238 | } 239 | buf_write(b, c); 240 | last = c; 241 | } 242 | } 243 | 244 | static bool nextoct() { 245 | int c = peek(); 246 | return '0' <= c && c <= '7'; 247 | } 248 | 249 | // Reads an octal escape sequence. 250 | static int read_octal_char(int c) { 251 | int r = c - '0'; 252 | if (!nextoct()) 253 | return r; 254 | r = (r << 3) | (readc() - '0'); 255 | if (!nextoct()) 256 | return r; 257 | return (r << 3) | (readc() - '0'); 258 | } 259 | 260 | // Reads a \x escape sequence. 261 | static int read_hex_char() { 262 | Pos p = get_pos(-2); 263 | int c = readc(); 264 | if (!isxdigit(c)) 265 | errorp(p, "\\x is not followed by a hexadecimal character: %c", c); 266 | int r = 0; 267 | for (;; c = readc()) { 268 | switch (c) { 269 | case '0' ... '9': r = (r << 4) | (c - '0'); continue; 270 | case 'a' ... 'f': r = (r << 4) | (c - 'a' + 10); continue; 271 | case 'A' ... 'F': r = (r << 4) | (c - 'A' + 10); continue; 272 | default: unreadc(c); return r; 273 | } 274 | } 275 | } 276 | 277 | static bool is_valid_ucn(unsigned int c) { 278 | // C11 6.4.3p2: U+D800 to U+DFFF are reserved for surrogate pairs. 279 | // A codepoint within the range cannot be a valid character. 280 | if (0xD800 <= c && c <= 0xDFFF) 281 | return false; 282 | // It's not allowed to encode ASCII characters using \U or \u. 283 | // Some characters not in the basic character set (C11 5.2.1p3) 284 | // are allowed as exceptions. 285 | return 0xA0 <= c || c == '$' || c == '@' || c == '`'; 286 | } 287 | 288 | // Reads \u or \U escape sequences. len is 4 or 8, respecitvely. 289 | static int read_universal_char(int len) { 290 | Pos p = get_pos(-2); 291 | unsigned int r = 0; 292 | for (int i = 0; i < len; i++) { 293 | char c = readc(); 294 | switch (c) { 295 | case '0' ... '9': r = (r << 4) | (c - '0'); continue; 296 | case 'a' ... 'f': r = (r << 4) | (c - 'a' + 10); continue; 297 | case 'A' ... 'F': r = (r << 4) | (c - 'A' + 10); continue; 298 | default: errorp(p, "invalid universal character: %c", c); 299 | } 300 | } 301 | if (!is_valid_ucn(r)) 302 | errorp(p, "invalid universal character: \\%c%0*x", (len == 4) ? 'u' : 'U', len, r); 303 | return r; 304 | } 305 | 306 | static int read_escaped_char() { 307 | Pos p = get_pos(-1); 308 | int c = readc(); 309 | // This switch-cases is an interesting example of magical aspects 310 | // of self-hosting compilers. Here, we teach the compiler about 311 | // escaped sequences using escaped sequences themselves. 312 | // This is a tautology. The information about their real character 313 | // codes is not present in the source code but propagated from 314 | // a compiler compiling the source code. 315 | // See "Reflections on Trusting Trust" by Ken Thompson for more info. 316 | // http://cm.bell-labs.com/who/ken/trust.html 317 | switch (c) { 318 | case '\'': case '"': case '?': case '\\': 319 | return c; 320 | case 'a': return '\a'; 321 | case 'b': return '\b'; 322 | case 'f': return '\f'; 323 | case 'n': return '\n'; 324 | case 'r': return '\r'; 325 | case 't': return '\t'; 326 | case 'v': return '\v'; 327 | case 'e': return '\033'; // '\e' is GNU extension 328 | case 'x': return read_hex_char(); 329 | case 'u': return read_universal_char(4); 330 | case 'U': return read_universal_char(8); 331 | case '0' ... '7': return read_octal_char(c); 332 | } 333 | warnp(p, "unknown escape character: \\%c", c); 334 | return c; 335 | } 336 | 337 | static Token *read_char(int enc) { 338 | int c = readc(); 339 | int r = (c == '\\') ? read_escaped_char() : c; 340 | c = readc(); 341 | if (c != '\'') 342 | errorp(pos, "unterminated char"); 343 | if (enc == ENC_NONE) 344 | return make_char((char)r, enc); 345 | return make_char(r, enc); 346 | } 347 | 348 | // Reads a string literal. 349 | static Token *read_string(int enc) { 350 | Buffer *b = make_buffer(); 351 | for (;;) { 352 | int c = readc(); 353 | if (c == EOF) 354 | errorp(pos, "unterminated string"); 355 | if (c == '"') 356 | break; 357 | if (c != '\\') { 358 | buf_write(b, c); 359 | continue; 360 | } 361 | bool isucs = (peek() == 'u' || peek() == 'U'); 362 | c = read_escaped_char(); 363 | if (isucs) { 364 | write_utf8(b, c); 365 | continue; 366 | } 367 | buf_write(b, c); 368 | } 369 | buf_write(b, '\0'); 370 | return make_strtok(buf_body(b), buf_len(b), enc); 371 | } 372 | 373 | static Token *read_ident(char c) { 374 | Buffer *b = make_buffer(); 375 | buf_write(b, c); 376 | for (;;) { 377 | c = readc(); 378 | if (isalnum(c) || (c & 0x80) || c == '_' || c == '$') { 379 | buf_write(b, c); 380 | continue; 381 | } 382 | // C11 6.4.2.1: \u or \U characters (universal-character-name) 383 | // are allowed to be part of identifiers. 384 | if (c == '\\' && (peek() == 'u' || peek() == 'U')) { 385 | write_utf8(b, read_escaped_char()); 386 | continue; 387 | } 388 | unreadc(c); 389 | buf_write(b, '\0'); 390 | return make_ident(buf_body(b)); 391 | } 392 | } 393 | 394 | static void skip_block_comment() { 395 | Pos p = get_pos(-2); 396 | bool maybe_end = false; 397 | for (;;) { 398 | int c = readc(); 399 | if (c == EOF) 400 | errorp(p, "premature end of block comment"); 401 | if (c == '/' && maybe_end) 402 | return; 403 | maybe_end = (c == '*'); 404 | } 405 | } 406 | 407 | // Reads a digraph starting with '%'. Digraphs are alternative spellings 408 | // for some punctuation characters. They are useless in ASCII. 409 | // We implement this just for the standard compliance. 410 | // See C11 6.4.6p3 for the spec. 411 | static Token *read_hash_digraph() { 412 | if (next('>')) 413 | return make_keyword('}'); 414 | if (next(':')) { 415 | if (next('%')) { 416 | if (next(':')) 417 | return make_keyword(KHASHHASH); 418 | unreadc('%'); 419 | } 420 | return make_keyword('#'); 421 | } 422 | return NULL; 423 | } 424 | 425 | static Token *read_rep(char expect, int t1, int els) { 426 | return make_keyword(next(expect) ? t1 : els); 427 | } 428 | 429 | static Token *read_rep2(char expect1, int t1, char expect2, int t2, char els) { 430 | if (next(expect1)) 431 | return make_keyword(t1); 432 | return make_keyword(next(expect2) ? t2 : els); 433 | } 434 | 435 | static Token *do_read_token() { 436 | if (skip_space()) 437 | return space_token; 438 | mark(); 439 | int c = readc(); 440 | switch (c) { 441 | case '\n': return newline_token; 442 | case ':': return make_keyword(next('>') ? ']' : ':'); 443 | case '#': return make_keyword(next('#') ? KHASHHASH : '#'); 444 | case '+': return read_rep2('+', OP_INC, '=', OP_A_ADD, '+'); 445 | case '*': return read_rep('=', OP_A_MUL, '*'); 446 | case '=': return read_rep('=', OP_EQ, '='); 447 | case '!': return read_rep('=', OP_NE, '!'); 448 | case '&': return read_rep2('&', OP_LOGAND, '=', OP_A_AND, '&'); 449 | case '|': return read_rep2('|', OP_LOGOR, '=', OP_A_OR, '|'); 450 | case '^': return read_rep('=', OP_A_XOR, '^'); 451 | case '"': return read_string(ENC_NONE); 452 | case '\'': return read_char(ENC_NONE); 453 | case '/': return make_keyword(next('=') ? OP_A_DIV : '/'); 454 | case 'a' ... 't': case 'v' ... 'z': case 'A' ... 'K': 455 | case 'M' ... 'T': case 'V' ... 'Z': case '_': case '$': 456 | case 0x80 ... 0xFD: 457 | return read_ident(c); 458 | case '0' ... '9': 459 | return read_number(c); 460 | case 'L': case 'U': { 461 | // Wide/char32_t character/string literal 462 | int enc = (c == 'L') ? ENC_WCHAR : ENC_CHAR32; 463 | if (next('"')) return read_string(enc); 464 | if (next('\'')) return read_char(enc); 465 | return read_ident(c); 466 | } 467 | case 'u': 468 | if (next('"')) return read_string(ENC_CHAR16); 469 | if (next('\'')) return read_char(ENC_CHAR16); 470 | // C11 6.4.5: UTF-8 string literal 471 | if (next('8')) { 472 | if (next('"')) 473 | return read_string(ENC_UTF8); 474 | unreadc('8'); 475 | } 476 | return read_ident(c); 477 | case '.': 478 | if (isdigit(peek())) 479 | return read_number(c); 480 | if (next('.')) { 481 | if (next('.')) 482 | return make_keyword(KELLIPSIS); 483 | return make_ident(".."); 484 | } 485 | return make_keyword('.'); 486 | case '(': case ')': case ',': case ';': case '[': case ']': case '{': 487 | case '}': case '?': case '~': 488 | return make_keyword(c); 489 | case '-': 490 | if (next('-')) return make_keyword(OP_DEC); 491 | if (next('>')) return make_keyword(OP_ARROW); 492 | if (next('=')) return make_keyword(OP_A_SUB); 493 | return make_keyword('-'); 494 | case '<': 495 | if (next('<')) return read_rep('=', OP_A_SAL, OP_SAL); 496 | if (next('=')) return make_keyword(OP_LE); 497 | if (next(':')) return make_keyword('['); 498 | if (next('%')) return make_keyword('{'); 499 | return make_keyword('<'); 500 | case '>': 501 | if (next('=')) return make_keyword(OP_GE); 502 | if (next('>')) return read_rep('=', OP_A_SAR, OP_SAR); 503 | return make_keyword('>'); 504 | case '%': { 505 | Token *tok = read_hash_digraph(); 506 | if (tok) 507 | return tok; 508 | return read_rep('=', OP_A_MOD, '%'); 509 | } 510 | case EOF: 511 | return eof_token; 512 | default: return make_invalid(c); 513 | } 514 | } 515 | 516 | static bool buffer_empty() { 517 | return vec_len(buffers) == 1 && vec_len(vec_head(buffers)) == 0; 518 | } 519 | 520 | // Reads a header file name for #include. 521 | // 522 | // Filenames after #include need a special tokenization treatment. 523 | // A filename string may be quoted by < and > instead of "". 524 | // Even if it's quoted by "", it's still different from a regular string token. 525 | // For example, \ in this context is not interpreted as a quote. 526 | // Thus, we cannot use lex() to read a filename. 527 | // 528 | // That the C preprocessor requires a special lexer behavior only for 529 | // #include is a violation of layering. Ideally, the lexer should be 530 | // agnostic about higher layers status. But we need this for the C grammar. 531 | char *read_header_file_name(bool *std) { 532 | if (!buffer_empty()) 533 | return NULL; 534 | skip_space(); 535 | Pos p = get_pos(0); 536 | char close; 537 | if (next('"')) { 538 | *std = false; 539 | close = '"'; 540 | } else if (next('<')) { 541 | *std = true; 542 | close = '>'; 543 | } else { 544 | return NULL; 545 | } 546 | Buffer *b = make_buffer(); 547 | while (!next(close)) { 548 | int c = readc(); 549 | if (c == EOF || c == '\n') 550 | errorp(p, "premature end of header name"); 551 | buf_write(b, c); 552 | } 553 | if (buf_len(b) == 0) 554 | errorp(p, "header name should not be empty"); 555 | buf_write(b, '\0'); 556 | return buf_body(b); 557 | } 558 | 559 | bool is_keyword(Token *tok, int c) { 560 | return (tok->kind == TKEYWORD) && (tok->id == c); 561 | } 562 | 563 | // Temporarily switches the input token stream to given list of tokens, 564 | // so that you can get the tokens as return values of lex() again. 565 | // After the tokens are exhausted, EOF is returned from lex() until 566 | // "unstash" is called to restore the original state. 567 | void token_buffer_stash(Vector *buf) { 568 | vec_push(buffers, buf); 569 | } 570 | 571 | void token_buffer_unstash() { 572 | vec_pop(buffers); 573 | } 574 | 575 | void unget_token(Token *tok) { 576 | if (tok->kind == TEOF) 577 | return; 578 | Vector *buf = vec_tail(buffers); 579 | vec_push(buf, tok); 580 | } 581 | 582 | // Reads a token from a given string. 583 | // This function temporarily switches the main input stream to 584 | // a given string and reads one token. 585 | Token *lex_string(char *s) { 586 | stream_stash(make_file_string(s)); 587 | Token *r = do_read_token(); 588 | next('\n'); 589 | Pos p = get_pos(0); 590 | if (peek() != EOF) 591 | errorp(p, "unconsumed input: %s", s); 592 | stream_unstash(); 593 | return r; 594 | } 595 | 596 | Token *lex() { 597 | Vector *buf = vec_tail(buffers); 598 | if (vec_len(buf) > 0) 599 | return vec_pop(buf); 600 | if (vec_len(buffers) > 1) 601 | return eof_token; 602 | bool bol = (current_file()->column == 1); 603 | Token *tok = do_read_token(); 604 | while (tok->kind == TSPACE) { 605 | tok = do_read_token(); 606 | tok->space = true; 607 | } 608 | tok->bol = bol; 609 | return tok; 610 | } 611 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "8cc.h" 10 | 11 | static char *infile; 12 | static char *outfile; 13 | static char *asmfile; 14 | static bool dumpast; 15 | static bool cpponly; 16 | static bool dumpasm; 17 | static bool dontlink; 18 | static Buffer *cppdefs; 19 | static Vector *tmpfiles = &EMPTY_VECTOR; 20 | 21 | static void usage(int exitcode) { 22 | fprintf(exitcode ? stderr : stdout, 23 | "Usage: 8cc [ -E ][ -a ] [ -h ] \n\n" 24 | "\n" 25 | " -I add to include path\n" 26 | " -E print preprocessed source code\n" 27 | " -D name Predefine name as a macro\n" 28 | " -D name=def\n" 29 | " -S Stop before assembly (default)\n" 30 | " -c Do not run linker (default)\n" 31 | " -U name Undefine name\n" 32 | " -fdump-ast print AST\n" 33 | " -fdump-stack Print stacktrace\n" 34 | " -fno-dump-source Do not emit source code as assembly comment\n" 35 | " -o filename Output to the specified file\n" 36 | " -g Do nothing at this moment\n" 37 | " -Wall Enable all warnings\n" 38 | " -Werror Make all warnings into errors\n" 39 | " -O Does nothing at this moment\n" 40 | " -m64 Output 64-bit code (default)\n" 41 | " -w Disable all warnings\n" 42 | " -h print this help\n" 43 | "\n" 44 | "One of -a, -c, -E or -S must be specified.\n\n"); 45 | exit(exitcode); 46 | } 47 | 48 | static void delete_temp_files() { 49 | for (int i = 0; i < vec_len(tmpfiles); i++) 50 | unlink(vec_get(tmpfiles, i)); 51 | } 52 | 53 | static char *base(char *path) { 54 | return basename(strdup(path)); 55 | } 56 | 57 | static char *replace_suffix(char *filename, char suffix) { 58 | char *r = format("%s", filename); 59 | char *p = r + strlen(r) - 1; 60 | if (*p != 'c') 61 | error("filename suffix is not .c"); 62 | *p = suffix; 63 | return r; 64 | } 65 | 66 | static FILE *open_asmfile() { 67 | if (dumpasm) { 68 | asmfile = outfile ? outfile : replace_suffix(base(infile), 's'); 69 | } else { 70 | asmfile = format("/tmp/8ccXXXXXX.s"); 71 | if (!mkstemps(asmfile, 2)) 72 | perror("mkstemps"); 73 | vec_push(tmpfiles, asmfile); 74 | } 75 | if (!strcmp(asmfile, "-")) 76 | return stdout; 77 | FILE *fp = fopen(asmfile, "w"); 78 | if (!fp) 79 | perror("fopen"); 80 | return fp; 81 | } 82 | 83 | static void parse_warnings_arg(char *s) { 84 | if (!strcmp(s, "error")) 85 | warning_is_error = true; 86 | else if (strcmp(s, "all")) 87 | error("unknown -W option: %s", s); 88 | } 89 | 90 | static void parse_f_arg(char *s) { 91 | if (!strcmp(s, "dump-ast")) 92 | dumpast = true; 93 | else if (!strcmp(s, "dump-stack")) 94 | dumpstack = true; 95 | else if (!strcmp(s, "no-dump-source")) 96 | dumpsource = false; 97 | else 98 | usage(1); 99 | } 100 | 101 | static void parse_m_arg(char *s) { 102 | if (strcmp(s, "64")) 103 | error("Only 64 is allowed for -m, but got %s", s); 104 | } 105 | 106 | static void parseopt(int argc, char **argv) { 107 | cppdefs = make_buffer(); 108 | for (;;) { 109 | int opt = getopt(argc, argv, "I:ED:O:SU:W:acd:f:gm:o:hw"); 110 | if (opt == -1) 111 | break; 112 | switch (opt) { 113 | case 'I': add_include_path(optarg); break; 114 | case 'E': cpponly = true; break; 115 | case 'D': { 116 | char *p = strchr(optarg, '='); 117 | if (p) 118 | *p = ' '; 119 | buf_printf(cppdefs, "#define %s\n", optarg); 120 | break; 121 | } 122 | case 'O': break; 123 | case 'S': dumpasm = true; break; 124 | case 'U': 125 | buf_printf(cppdefs, "#undef %s\n", optarg); 126 | break; 127 | case 'W': parse_warnings_arg(optarg); break; 128 | case 'c': dontlink = true; break; 129 | case 'f': parse_f_arg(optarg); break; 130 | case 'm': parse_m_arg(optarg); break; 131 | case 'g': break; 132 | case 'o': outfile = optarg; break; 133 | case 'w': enable_warning = false; break; 134 | case 'h': 135 | usage(0); 136 | default: 137 | usage(1); 138 | } 139 | } 140 | if (optind != argc - 1) 141 | usage(1); 142 | 143 | if (!dumpast && !cpponly && !dumpasm && !dontlink) 144 | error("One of -a, -c, -E or -S must be specified"); 145 | infile = argv[optind]; 146 | } 147 | 148 | char *get_base_file() { 149 | return infile; 150 | } 151 | 152 | static void preprocess() { 153 | for (;;) { 154 | Token *tok = read_token(); 155 | if (tok->kind == TEOF) 156 | break; 157 | if (tok->bol) 158 | printf("\n"); 159 | if (tok->space) 160 | printf(" "); 161 | printf("%s", tok2s(tok)); 162 | } 163 | printf("\n"); 164 | exit(0); 165 | } 166 | 167 | int main(int argc, char **argv) { 168 | setbuf(stdout, NULL); 169 | if (atexit(delete_temp_files)) 170 | perror("atexit"); 171 | parseopt(argc, argv); 172 | lex_init(infile); 173 | cpp_init(); 174 | parse_init(); 175 | set_output_file(open_asmfile()); 176 | if (buf_len(cppdefs) > 0) 177 | read_from_string(buf_body(cppdefs)); 178 | 179 | if (cpponly) 180 | preprocess(); 181 | 182 | Vector *toplevels = read_toplevels(); 183 | for (int i = 0; i < vec_len(toplevels); i++) { 184 | Node *v = vec_get(toplevels, i); 185 | if (dumpast) 186 | printf("%s", node2s(v)); 187 | else 188 | emit_toplevel(v); 189 | } 190 | 191 | close_output_file(); 192 | 193 | if (!dumpast && !dumpasm) { 194 | if (!outfile) 195 | outfile = replace_suffix(base(infile), 'o'); 196 | pid_t pid = fork(); 197 | if (pid < 0) perror("fork"); 198 | if (pid == 0) { 199 | execlp("as", "as", "-o", outfile, "-c", asmfile, (char *)NULL); 200 | perror("execl failed"); 201 | } 202 | int status; 203 | waitpid(pid, &status, 0); 204 | if (status < 0) 205 | error("as failed"); 206 | } 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /map.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | // This is an implementation of hash table. 4 | 5 | #include 6 | #include 7 | #include "8cc.h" 8 | 9 | #define INIT_SIZE 16 10 | #define TOMBSTONE ((void *)-1) 11 | 12 | static uint32_t hash(char *p) { 13 | // FNV hash 14 | uint32_t r = 2166136261; 15 | for (; *p; p++) { 16 | r ^= *p; 17 | r *= 16777619; 18 | } 19 | return r; 20 | } 21 | 22 | static Map *do_make_map(Map *parent, int size) { 23 | Map *r = malloc(sizeof(Map)); 24 | r->parent = parent; 25 | r->key = calloc(size, sizeof(char *)); 26 | r->val = calloc(size, sizeof(void *)); 27 | r->size = size; 28 | r->nelem = 0; 29 | r->nused = 0; 30 | return r; 31 | } 32 | 33 | static void maybe_rehash(Map *m) { 34 | if (!m->key) { 35 | m->key = calloc(INIT_SIZE, sizeof(char *)); 36 | m->val = calloc(INIT_SIZE, sizeof(void *)); 37 | m->size = INIT_SIZE; 38 | return; 39 | } 40 | if (m->nused < m->size * 0.7) 41 | return; 42 | int newsize = (m->nelem < m->size * 0.35) ? m->size : m->size * 2; 43 | char **k = calloc(newsize, sizeof(char *)); 44 | void **v = calloc(newsize, sizeof(void *)); 45 | int mask = newsize - 1; 46 | for (int i = 0; i < m->size; i++) { 47 | if (m->key[i] == NULL || m->key[i] == TOMBSTONE) 48 | continue; 49 | int j = hash(m->key[i]) & mask; 50 | for (;; j = (j + 1) & mask) { 51 | if (k[j] != NULL) 52 | continue; 53 | k[j] = m->key[i]; 54 | v[j] = m->val[i]; 55 | break; 56 | } 57 | } 58 | m->key = k; 59 | m->val = v; 60 | m->size = newsize; 61 | m->nused = m->nelem; 62 | } 63 | 64 | Map *make_map() { 65 | return do_make_map(NULL, INIT_SIZE); 66 | } 67 | 68 | Map *make_map_parent(Map *parent) { 69 | return do_make_map(parent, INIT_SIZE); 70 | } 71 | 72 | static void *map_get_nostack(Map *m, char *key) { 73 | if (!m->key) 74 | return NULL; 75 | int mask = m->size - 1; 76 | int i = hash(key) & mask; 77 | for (; m->key[i] != NULL; i = (i + 1) & mask) 78 | if (m->key[i] != TOMBSTONE && !strcmp(m->key[i], key)) 79 | return m->val[i]; 80 | return NULL; 81 | } 82 | 83 | void *map_get(Map *m, char *key) { 84 | void *r = map_get_nostack(m, key); 85 | if (r) 86 | return r; 87 | // Map is stackable. If no value is found, 88 | // continue searching from the parent. 89 | if (m->parent) 90 | return map_get(m->parent, key); 91 | return NULL; 92 | } 93 | 94 | void map_put(Map *m, char *key, void *val) { 95 | maybe_rehash(m); 96 | int mask = m->size - 1; 97 | int i = hash(key) & mask; 98 | for (;; i = (i + 1) & mask) { 99 | char *k = m->key[i]; 100 | if (k == NULL || k == TOMBSTONE) { 101 | m->key[i] = key; 102 | m->val[i] = val; 103 | m->nelem++; 104 | if (k == NULL) 105 | m->nused++; 106 | return; 107 | } 108 | if (!strcmp(k, key)) { 109 | m->val[i] = val; 110 | return; 111 | } 112 | } 113 | } 114 | 115 | void map_remove(Map *m, char *key) { 116 | if (!m->key) 117 | return; 118 | int mask = m->size - 1; 119 | int i = hash(key) & mask; 120 | for (; m->key[i] != NULL; i = (i + 1) & mask) { 121 | if (m->key[i] == TOMBSTONE || strcmp(m->key[i], key)) 122 | continue; 123 | m->key[i] = TOMBSTONE; 124 | m->val[i] = NULL; 125 | m->nelem--; 126 | return; 127 | } 128 | } 129 | 130 | size_t map_len(Map *m) { 131 | return m->nelem; 132 | } 133 | -------------------------------------------------------------------------------- /path.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "8cc.h" 8 | 9 | // Returns the shortest path for the given full path to a file. 10 | static char *clean(char *p) { 11 | assert(*p == '/'); 12 | char buf[PATH_MAX]; 13 | char *q = buf; 14 | *q++ = '/'; 15 | for (;;) { 16 | if (*p == '/') { 17 | p++; 18 | continue; 19 | } 20 | if (!memcmp("./", p, 2)) { 21 | p += 2; 22 | continue; 23 | } 24 | if (!memcmp("../", p, 3)) { 25 | p += 3; 26 | if (q == buf + 1) 27 | continue; 28 | for (q--; q[-1] != '/'; q--); 29 | continue; 30 | } 31 | while (*p != '/' && *p != '\0') 32 | *q++ = *p++; 33 | if (*p == '/') { 34 | *q++ = *p++; 35 | continue; 36 | } 37 | *q = '\0'; 38 | return strdup(buf); 39 | } 40 | } 41 | 42 | // Returns the shortest absolute path for the given path. 43 | char *fullpath(char *path) { 44 | static char cwd[PATH_MAX]; 45 | if (path[0] == '/') 46 | return clean(path); 47 | if (*cwd == '\0' && !getcwd(cwd, PATH_MAX)) 48 | error("getcwd failed: %s", strerror(errno)); 49 | return clean(format("%s/%s", cwd, path)); 50 | } 51 | -------------------------------------------------------------------------------- /set.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | // Sets are containers that store unique strings. 4 | // 5 | // The data structure is functional. Because no destructive 6 | // operation is defined, it's guranteed that a set will never 7 | // change once it's created. 8 | // 9 | // A null pointer represents an empty set. 10 | // 11 | // Set is designed with simplicity in mind. 12 | // It should be very fast for small number of items. 13 | // However, if you plan to add a lot of items to a set, 14 | // you should consider using Map as a set. 15 | 16 | #include 17 | #include 18 | #include "8cc.h" 19 | 20 | Set *set_add(Set *s, char *v) { 21 | Set *r = malloc(sizeof(Set)); 22 | r->next = s; 23 | r->v = v; 24 | return r; 25 | } 26 | 27 | bool set_has(Set *s, char *v) { 28 | for (; s; s = s->next) 29 | if (!strcmp(s->v, v)) 30 | return true; 31 | return false; 32 | } 33 | 34 | Set *set_union(Set *a, Set *b) { 35 | Set *r = b; 36 | for (; a; a = a->next) 37 | if (!set_has(b, a->v)) 38 | r = set_add(r, a->v); 39 | return r; 40 | } 41 | 42 | Set *set_intersection(Set *a, Set *b) { 43 | Set *r = NULL; 44 | for (; a; a = a->next) 45 | if (set_has(b, a->v)) 46 | r = set_add(r, a->v); 47 | return r; 48 | } 49 | -------------------------------------------------------------------------------- /test/align.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | static void test_alignas() { 8 | expect(1, offsetof(struct { char x; char y; }, y)); 9 | expect(4, offsetof(struct { char x; _Alignas(4) char y; }, y)); 10 | expect(4, offsetof(struct { char x; _Alignas(int) char y; }, y)); 11 | expect(1, offsetof(struct { char x; alignas(0) char y; }, y)); 12 | } 13 | 14 | static void test_alignof() { 15 | expect(1, __alignof_is_defined); 16 | expect(1, _Alignof(char)); 17 | expect(1, __alignof__(char)); 18 | expect(1, alignof(char)); 19 | expect(2, alignof(short)); 20 | expect(4, alignof(int)); 21 | expect(8, alignof(double)); 22 | expect(1, alignof(char[10])); 23 | expect(8, alignof(double[10])); 24 | expect(1, _Alignof(struct {})); 25 | expect(4, alignof(struct {char a; int b; })); 26 | #ifdef __8cc__ 27 | expect(8, alignof(struct {int a; long double b; })); 28 | expect(8, alignof(long double)); 29 | #endif 30 | 31 | // The type of the result is size_t. 32 | expect(1, alignof(char) - 2 > 0); 33 | } 34 | 35 | static void test_constexpr() { 36 | char a[alignof(int)]; 37 | expect(4, sizeof(a)); 38 | } 39 | 40 | void testmain() { 41 | print("alignment"); 42 | test_alignas(); 43 | test_alignof(); 44 | test_constexpr(); 45 | } 46 | -------------------------------------------------------------------------------- /test/arith.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void test_basic() { 6 | expect(0, 0); 7 | expect(3, 1 + 2); 8 | expect(3, 1 + 2); 9 | expect(10, 1 + 2 + 3 + 4); 10 | expect(11, 1 + 2 * 3 + 4); 11 | expect(14, 1 * 2 + 3 * 4); 12 | expect(4, 4 / 2 + 6 / 3); 13 | expect(4, 24 / 2 / 3); 14 | expect(3, 24 % 7); 15 | expect(0, 24 % 3); 16 | expect(98, 'a' + 1); 17 | int a = 0 - 1; 18 | expect(0 - 1, a); 19 | expect(-1, a); 20 | expect(0, a + 1); 21 | expect(1, +1); 22 | expect(1, (unsigned)4000000001 % 2); 23 | } 24 | 25 | static void test_relative() { 26 | expect(1, 1 > 0); 27 | expect(1, 0 < 1); 28 | expect(0, 1 < 0); 29 | expect(0, 0 > 1); 30 | expect(0, 1 > 1); 31 | expect(0, 1 < 1); 32 | expect(1, 1 >= 0); 33 | expect(1, 0 <= 1); 34 | expect(0, 1 <= 0); 35 | expect(0, 0 >= 1); 36 | expect(1, 1 >= 1); 37 | expect(1, 1 <= 1); 38 | expect(1, 0xFFFFFFFFU > 1); 39 | expect(1, 1 < 0xFFFFFFFFU); 40 | expect(1, 0xFFFFFFFFU >= 1); 41 | expect(1, 1 <= 0xFFFFFFFFU); 42 | expect(1, -1 > 1U); 43 | expect(1, -1 >= 1U); 44 | expect(0, -1L > 1U); 45 | expect(0, -1L >= 1U); 46 | expect(0, 1.0 < 0.0); 47 | expect(1, 0.0 < 1.0); 48 | } 49 | 50 | static void test_inc_dec() { 51 | int a = 15; 52 | expect(15, a++); 53 | expect(16, a); 54 | expect(16, a--); 55 | expect(15, a); 56 | expect(14, --a); 57 | expect(14, a); 58 | expect(15, ++a); 59 | expect(15, a); 60 | } 61 | 62 | static void test_bool() { 63 | expect(0, !1); 64 | expect(1 ,!0); 65 | } 66 | 67 | static void test_ternary() { 68 | expect(51, (1 + 2) ? 51 : 52); 69 | expect(52, (1 - 1) ? 51 : 52); 70 | expect(26, (1 - 1) ? 51 : 52 / 2); 71 | expect(17, (1 - 0) ? 51 / 3 : 52); 72 | // GNU extension 73 | expect(52, 0 ?: 52); 74 | expect(3, (1 + 2) ?: 52); 75 | } 76 | 77 | static void test_unary() { 78 | char x = 2; 79 | short y = 2; 80 | int z = 2; 81 | expect(-2, -x); 82 | expect(-2, -y); 83 | expect(-2, -z); 84 | } 85 | 86 | static void test_comma() { 87 | expect(3, (1, 3)); 88 | expectf(7.0, (1, 3, 5, 7.0)); 89 | } 90 | 91 | void testmain() { 92 | print("basic arithmetic"); 93 | test_basic(); 94 | test_relative(); 95 | test_inc_dec(); 96 | test_bool(); 97 | test_unary(); 98 | test_ternary(); 99 | test_comma(); 100 | } 101 | -------------------------------------------------------------------------------- /test/array.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void t1() { 6 | int a[2][3]; 7 | int *p = a; 8 | *p = 1; 9 | expect(1, *p); 10 | } 11 | 12 | static void t2() { 13 | int a[2][3]; 14 | int *p = a + 1; 15 | *p = 1; 16 | int *q = a; 17 | *p = 32; 18 | expect(32, *(q + 3)); 19 | } 20 | 21 | static void t3() { 22 | int a[4][5]; 23 | int *p = a; 24 | *(*(a + 1) + 2) = 62; 25 | expect(62, *(p + 7)); 26 | } 27 | 28 | static void t4() { 29 | int a[3] = { 1, 2, 3 }; 30 | expect(1, a[0]); 31 | expect(2, a[1]); 32 | expect(3, a[2]); 33 | } 34 | 35 | static void t5() { 36 | int a[2][3]; 37 | a[0][1] = 1; 38 | a[1][1] = 2; 39 | int *p = a; 40 | expect(1, p[1]); 41 | expect(2, p[4]); 42 | } 43 | 44 | static void t6a(int e, int x[][3]) { 45 | expect(e, *(*(x + 1) + 1)); 46 | } 47 | 48 | static void t6() { 49 | int a[2][3]; 50 | int *p = a; 51 | *(p + 4) = 65; 52 | t6a(65, a); 53 | } 54 | 55 | static void t7() { 56 | int a[3*3]; // integer constant expression 57 | a[8] = 68; 58 | expect(68, a[8]); 59 | } 60 | 61 | void testmain() { 62 | print("array"); 63 | t1(); 64 | t2(); 65 | t3(); 66 | t4(); 67 | t5(); 68 | t6(); 69 | t7(); 70 | } 71 | -------------------------------------------------------------------------------- /test/assign.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("compound assignment"); 7 | 8 | int a = 0; 9 | a += 5; 10 | expect(5, a); 11 | a -= 2; 12 | expect(3, a); 13 | a *= 10; 14 | expect(30, a); 15 | a /= 2; 16 | expect(15, a); 17 | a %= 6; 18 | expect(3, a); 19 | 20 | a = 14; 21 | a &= 7; 22 | expect(6, a); 23 | a |= 8; 24 | expect(14, a); 25 | a ^= 3; 26 | expect(13, a); 27 | a <<= 2; 28 | expect(52, a); 29 | a >>= 2; 30 | expect(13, a); 31 | 32 | char b = 0; 33 | b += 5; 34 | expect(5, b); 35 | b -= 2; 36 | expect(3, b); 37 | b *= 10; 38 | expect(30, b); 39 | b /= 2; 40 | expect(15, b); 41 | b %= 6; 42 | expect(3, b); 43 | 44 | b = 14; 45 | b &= 7; 46 | expect(6, b); 47 | b |= 8; 48 | expect(14, b); 49 | b ^= 3; 50 | expect(13, b); 51 | b <<= 2; 52 | expect(52, b); 53 | b >>= 2; 54 | expect(13, b); 55 | } 56 | -------------------------------------------------------------------------------- /test/ast.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2012 Rui Ueyama. Released under the MIT license. 3 | 4 | function fail { 5 | echo -n -e '\e[1;31m[ERROR]\e[0m ' 6 | echo "$1" 7 | exit 1 8 | } 9 | 10 | function compile { 11 | echo "$1" | ./8cc -o tmp.s - || fail "Failed to compile $1" 12 | gcc -o tmp.out tmp.s 13 | [ $? -ne 0 ] && fail "GCC failed: $1" 14 | } 15 | 16 | function assertequal { 17 | [ "$1" != "$2" ] && fail "Test failed: $2 expected but got $1" 18 | } 19 | 20 | function testastf { 21 | result="$(echo "$2" | ./8cc -o - -fdump-ast -w -)" 22 | [ $? -ne 0 ] && fail "Failed to compile $2" 23 | assertequal "$result" "$1" 24 | } 25 | 26 | function testast { 27 | testastf "$1" "int f(){$2}" 28 | } 29 | 30 | function testm { 31 | compile "$2" 32 | assertequal "$(./tmp.out)" "$1" 33 | } 34 | 35 | function testcpp { 36 | echo "$2" | ./8cc -o - -E $3 - > tmp.s || fail "Failed to compile $1" 37 | assertequal "$(cat tmp.s)" "$1" 38 | } 39 | 40 | 41 | function testfail { 42 | echo "$expr" | ./8cc -o /dev/null - 2> /dev/null 43 | expr="int f(){$1}" 44 | echo "$expr" | ./8cc -o /dev/null $OPTION - 2> /dev/null 45 | [ $? -eq 0 ] && fail "Should fail to compile, but succeded: $expr" 46 | } 47 | 48 | # Parser 49 | testast '(()=>int)f(){1;}' '1;' 50 | testast '(()=>int)f(){1L;}' '1L;' 51 | # testast '(()=>int)f(){1152921504606846976L;}' '1152921504606846976;' 52 | testast '(()=>int)f(){(+ (- (+ 1 2) 3) 4);}' '1+2-3+4;' 53 | testast '(()=>int)f(){(+ (+ 1 (* 2 3)) 4);}' '1+2*3+4;' 54 | testast '(()=>int)f(){(+ (* 1 2) (* 3 4));}' '1*2+3*4;' 55 | testast '(()=>int)f(){(+ (/ 4 2) (/ 6 3));}' '4/2+6/3;' 56 | testast '(()=>int)f(){(/ (/ 24 2) 4);}' '24/2/4;' 57 | testast '(()=>int)f(){(decl int a 3@0);}' 'int a=3;' 58 | testast "(()=>int)f(){(decl char c (conv 97=>char)@0);}" "char c='a';" 59 | testast '(()=>int)f(){(decl *char s (conv "abcd"=>*char)@0);}' 'char *s="abcd";' 60 | #testast "(()=>int)f(){(decl [5]char s 'a'@0 's'@1 'd'@2 'f'@3 '\0'@4);}" 'char s[5]="asdf";' 61 | testast "(()=>int)f(){(decl [5]char s 'a'@0 's'@1 'd'@2 'f'@3 '\0'@4);}" 'char s[]="asdf";' 62 | testast '(()=>int)f(){(decl [3]int a 1@0 2@4 3@8);}' 'int a[3]={1,2,3};' 63 | testast '(()=>int)f(){(decl [3]int a 1@0 2@4 3@8);}' 'int a[]={1,2,3};' 64 | testast '(()=>int)f(){(decl [3][5]int a);}' 'int a[3][5];' 65 | testast '(()=>int)f(){(decl [5]*int a);}' 'int *a[5];' 66 | testast '(()=>int)f(){(decl int a 1@0);(decl int b 2@0);(= lv=a (= lv=b 3));}' 'int a=1;int b=2;a=b=3;' 67 | testast '(()=>int)f(){(decl int a 3@0);(addr lv=a);}' 'int a=3;&a;' 68 | testast '(()=>int)f(){(decl int a 3@0);(deref (addr lv=a));}' 'int a=3;*&a;' 69 | testast '(()=>int)f(){(decl int a 3@0);(decl *int b (addr lv=a)@0);(deref lv=b);}' 'int a=3;int *b=&a;*b;' 70 | testast '(()=>int)f(){(if 1 {2;});}' 'if(1){2;}' 71 | testast '(()=>int)f(){(if 1 {2;} {3;});}' 'if(1){2;}else{3;}' 72 | testast '(()=>int)f(){{{(decl int a 1@0);};.L0:;(if 3 (nil) goto(.L2));{5;};.L1:;7;goto(.L0);.L2:;};}' 'for(int a=1;3;7){5;}' 73 | testast '(()=>int)f(){"abcd";}' '"abcd";' 74 | testast "(()=>int)f(){99;}" "'c';" 75 | testast '(()=>int)f(){(int)a();}' 'a();' 76 | testast '(()=>int)f(){(int)a(1,2,3,4,5,6);}' 'a(1,2,3,4,5,6);' 77 | testast '(()=>int)f(){(return (conv 1=>int));}' 'return 1;' 78 | testast '(()=>int)f(){(< 1 2);}' '1<2;' 79 | testast '(()=>int)f(){(< 2 1);}' '1>2;' 80 | testast '(()=>int)f(){(== 1 2);}' '1==2;' 81 | # testast '(()=>int)f(){(deref (+ 1 2));}' '1[2];' 82 | testast '(()=>int)f(){(decl int a 1@0);(post++ lv=a);}' 'int a=1;a++;' 83 | testast '(()=>int)f(){(decl int a 1@0);(post-- lv=a);}' 'int a=1;a--;' 84 | testast '(()=>int)f(){(! 1);}' '!1;' 85 | testast '(()=>int)f(){(? 1 2 3);}' '1?2:3;' 86 | testast '(()=>int)f(){(and 1 2);}' '1&&2;' 87 | testast '(()=>int)f(){(or 1 2);}' '1||2;' 88 | testast '(()=>int)f(){(& 1 2);}' '1&2;' 89 | testast '(()=>int)f(){(| 1 2);}' '1|2;' 90 | testast '(()=>int)f(){1.200000;}' '1.2;' 91 | testast '(()=>int)f(){(+ 1.200000 (conv 1=>double));}' '1.2+1;' 92 | 93 | testastf '((int)=>int)f(int lv=c){lv=c;}' 'int f(int c){c;}' 94 | testastf '((int)=>int)f(int lv=c){lv=c;}((int)=>int)g(int lv=d){lv=d;}' 'int f(int c){c;} int g(int d){d;}' 95 | testastf '(decl int a 3@0)' 'int a=3;' 96 | 97 | testastf '(decl (struct) a)' 'struct {} a;' 98 | testastf '(decl (struct (int) (char)) a)' 'struct {int x; char y;} a;' 99 | testastf '(decl (struct ([3]int)) a)' 'struct {int x[3];} a;' 100 | testast '(()=>int)f(){(decl (struct (int)) a);(decl *(struct (int)) p);(deref lv=p).x;}' 'struct tag {int x;} a; struct tag *p; p->x;' 101 | testast '(()=>int)f(){(decl (struct (int)) a);lv=a.x;}' 'struct {int x;} a; a.x;' 102 | testast '(()=>int)f(){(decl (struct (int:0:5) (int:5:13)) x);}' 'struct { int a:5; int b:8; } x;' 103 | 104 | testfail '0abc;' 105 | # testfail '1+;' 106 | testfail '1=2;' 107 | 108 | # & is only applicable to an lvalue 109 | testfail '&"a";' 110 | testfail '&1;' 111 | testfail '&a();' 112 | 113 | # -D command line options 114 | testcpp '77' 'foo' '-Dfoo=77' 115 | 116 | echo "All tests passed" 117 | -------------------------------------------------------------------------------- /test/bitop.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void test_or() { 6 | expect(3, 1 | 2); 7 | expect(7, 2 | 5); 8 | expect(7, 2 | 7); 9 | } 10 | 11 | static void test_and() { 12 | expect(0, 1 & 2); 13 | expect(2, 2 & 7); 14 | } 15 | 16 | static void test_not() { 17 | expect(-1, ~0); 18 | expect(-3, ~2); 19 | expect(0, ~-1); 20 | } 21 | 22 | static void test_xor() { 23 | expect(10, 15 ^ 5); 24 | } 25 | 26 | static void test_shift() { 27 | expect(16, 1 << 4); 28 | expect(48, 3 << 4); 29 | 30 | expect(1, 15 >> 3); 31 | expect(2, 8 >> 2); 32 | 33 | expect(1, ((unsigned)-1) >> 31); 34 | } 35 | 36 | void testmain() { 37 | print("bitwise operators"); 38 | test_or(); 39 | test_and(); 40 | test_not(); 41 | test_xor(); 42 | test_shift(); 43 | } 44 | -------------------------------------------------------------------------------- /test/builtin.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | // This test depends on the stack frame and code layout and does not 4 | // run with gcc -O2. 5 | 6 | #include "test.h" 7 | 8 | #ifdef __8cc__ 9 | 10 | static void *test_return_address_sub2() { 11 | return __builtin_return_address(1); 12 | } 13 | 14 | static void *test_return_address_sub1() { 15 | expect((long)__builtin_return_address(0), (long)test_return_address_sub2()); 16 | return __builtin_return_address(0); 17 | } 18 | 19 | static void test_return_address() { 20 | void *ptr; 21 | L1: 22 | ptr = test_return_address_sub1(); 23 | L2: 24 | expect(1, &&L1 < ptr && ptr <= &&L2); 25 | } 26 | 27 | #else 28 | static void test_return_address() {} 29 | #endif 30 | 31 | void testmain() { 32 | print("builtin"); 33 | test_return_address(); 34 | } 35 | -------------------------------------------------------------------------------- /test/cast.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void test_signedcast() { 6 | unsigned char c = -1; 7 | int i = (signed char) c; 8 | 9 | expect(i, -1); 10 | } 11 | 12 | static void test_unsignedcast() { 13 | signed char c = -1; 14 | int i = (unsigned char) c; 15 | 16 | expect(1, i > 0); 17 | } 18 | 19 | void testmain() { 20 | print("cast"); 21 | expectf(1, (int)1); 22 | expectf(1.0, (float)1); 23 | expectd(2.0, (double)2); 24 | 25 | int a[3]; 26 | *(int *)(a + 2) = 5; 27 | expect(5, a[2]); 28 | 29 | test_signedcast(); 30 | test_unsignedcast(); 31 | } 32 | -------------------------------------------------------------------------------- /test/comp.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("comparison operators"); 7 | expect(1, 1 < 2); 8 | expect(0, 2 < 1); 9 | expect(1, 1 == 1); 10 | expect(0, 1 == 2); 11 | expect(0, 1 != 1); 12 | expect(1, 1 != 2); 13 | 14 | expect(1, 1 <= 2); 15 | expect(1, 2 <= 2); 16 | expect(0, 2 <= 1); 17 | 18 | expect(0, 1 >= 2); 19 | expect(1, 2 >= 2); 20 | expect(1, 2 >= 1); 21 | 22 | int i = -1; 23 | expect(0, i >= 0); 24 | 25 | expect(1, 10.0 == 10.0); 26 | expect(0, 10.0 == 20.0); 27 | expect(0, 10.0 != 10.0); 28 | expect(1, 10.0 != 20.0); 29 | 30 | expect(1, 10.0f == 10.0f); 31 | expect(0, 10.0f == 20.0f); 32 | expect(0, 10.0f != 10.0f); 33 | expect(1, 10.0f != 20.0f); 34 | 35 | expect(1, 10.0f == 10.0); 36 | expect(0, 10.0f == 20.0); 37 | expect(0, 10.0f != 10.0); 38 | expect(1, 10.0f != 20.0); 39 | } 40 | -------------------------------------------------------------------------------- /test/constexpr.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | int x1[] = { 1, 2, 3, 4, 5 }; 6 | int *p1 = x1; 7 | int *q1 = x1 + 2; 8 | 9 | int x2 = 7; 10 | int *p2 = &x2 + 1; 11 | 12 | void testmain() { 13 | print("constexpr"); 14 | expect(1, *p1); 15 | expect(3, *q1); 16 | expect(7, p2[-1]); 17 | } 18 | -------------------------------------------------------------------------------- /test/control.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | int test_if1(void) { if (1) { return 'a';} return 0; } 6 | int test_if2(void) { if (0) { return 0;} return 'b'; } 7 | int test_if3(void) { if (1) { return 'c';} else { return 0; } return 0; } 8 | int test_if4(void) { if (0) { return 0;} else { return 'd'; } return 0; } 9 | int test_if5(void) { if (1) return 'e'; return 0; } 10 | int test_if6(void) { if (0) return 0; return 'f'; } 11 | int test_if7(void) { if (1) return 'g'; else return 0; return 0; } 12 | int test_if8(void) { if (0) return 0; else return 'h'; return 0; } 13 | int test_if9(void) { if (0+1) return 'i'; return 0; } 14 | int test_if10(void) { if (1-1) return 0; return 'j'; } 15 | int test_if11(void) { if (0.5) return 'k'; return 0; } 16 | 17 | static void test_if() { 18 | expect('a', test_if1()); 19 | expect('b', test_if2()); 20 | expect('c', test_if3()); 21 | expect('d', test_if4()); 22 | expect('e', test_if5()); 23 | expect('f', test_if6()); 24 | expect('g', test_if7()); 25 | expect('h', test_if8()); 26 | expect('i', test_if9()); 27 | expect('j', test_if10()); 28 | expect('k', test_if11()); 29 | } 30 | 31 | static void test_for() { 32 | int i; 33 | int acc = 0; 34 | for (i = 0; i < 5; i++) { 35 | acc = acc + i; 36 | } 37 | expect(10, acc); 38 | 39 | acc = 0; 40 | for (i = 0; i < 5; i++) { 41 | acc = acc + i; 42 | } 43 | expect(10, acc); 44 | 45 | acc = 0; 46 | for (i = 0; i < 100; i++) { 47 | if (i < 5) continue; 48 | if (i == 9) break; 49 | acc += i; 50 | } 51 | expect(5 + 6 + 7 + 8, acc); 52 | 53 | for (int x = 3, y = 5, z = 8; x < 100; x++, y++, z+=2) 54 | expect(z, x + y); 55 | 56 | for (;;) 57 | break; 58 | for (i = 0; i < 100; i++) 59 | ; 60 | 61 | i = 0; 62 | for (; 0.5;) { 63 | i = 68; 64 | break; 65 | } 66 | expect(68, i); 67 | } 68 | 69 | static void test_while() { 70 | int acc = 0; 71 | int i = 0; 72 | while (i <= 100) 73 | acc = acc + i++; 74 | expect(5050, acc); 75 | 76 | acc = 1; 77 | i = 0; 78 | while (i <= 100) { 79 | acc = acc + i++; 80 | } 81 | expect(5051, acc); 82 | 83 | acc = 0; 84 | i = 0; 85 | while (i < 10) { 86 | if (i++ < 5) continue; 87 | acc += i; 88 | if (i == 9) break; 89 | } 90 | expect(6 + 7 + 8 + 9, acc); 91 | 92 | i = 0; 93 | while (i++ < 100) 94 | ; 95 | 96 | i = 0; 97 | while (0.5) { 98 | i = 67; 99 | break; 100 | } 101 | expect(67, i); 102 | } 103 | 104 | static void test_do() { 105 | int acc = 0; 106 | int i = 0; 107 | do { 108 | acc = acc + i++; 109 | } while (i <= 100); 110 | expect(5050, acc); 111 | 112 | i = 0; 113 | do { i = 37; } while (0); 114 | expect(37, i); 115 | 116 | acc = 0; 117 | i = 0; 118 | do { 119 | if (i++ < 5) continue; 120 | acc += i; 121 | if (i == 9) break; 122 | } while (i < 10); 123 | expect(6 + 7 + 8 + 9, acc); 124 | 125 | i = 0; 126 | do {} while (i++ < 100); 127 | 128 | i = 0; 129 | do; while (i++ < 100); 130 | 131 | float v = 1; 132 | i = 70; 133 | do i++; while (v -= 0.5); 134 | expect(72, i); 135 | } 136 | 137 | static void test_switch() { 138 | int a = 0; 139 | switch (1+2) { 140 | case 0: fail("0"); 141 | case 3: a = 3; break; 142 | case 1: fail("1"); 143 | } 144 | expect(a, 3); 145 | 146 | a = 0; 147 | switch (1) { 148 | case 0: a++; 149 | case 1: a++; 150 | case 2: a++; 151 | case 3: a++; 152 | } 153 | a = 3; 154 | 155 | a = 0; 156 | switch (100) { 157 | case 0: a++; 158 | default: a = 55; 159 | } 160 | expect(a, 55); 161 | 162 | a = 0; 163 | switch (100) { 164 | case 0: a++; 165 | } 166 | expect(a, 0); 167 | 168 | a = 5; 169 | switch (3) { 170 | a++; 171 | } 172 | expect(a, 5); 173 | 174 | switch (7) { 175 | case 1 ... 2: fail("switch"); 176 | case 3: fail("switch"); 177 | case 5 ... 10: break; 178 | default: fail("switch"); 179 | } 180 | 181 | a = 0; 182 | int count = 27; 183 | switch (count % 8) { 184 | case 0: do { a++; 185 | case 7: a++; 186 | case 6: a++; 187 | case 5: a++; 188 | case 4: a++; 189 | case 3: a++; 190 | case 2: a++; 191 | case 1: a++; 192 | } while ((count -= 8) > 0); 193 | } 194 | expect(27, a); 195 | 196 | switch (1) 197 | ; 198 | } 199 | 200 | static void test_goto() { 201 | int acc = 0; 202 | goto x; 203 | acc = 5; 204 | x: expect(0, acc); 205 | 206 | int i = 0; 207 | acc = 0; 208 | y: if (i > 10) goto z; 209 | acc += i++; 210 | goto y; 211 | z: if (i > 11) goto a; 212 | expect(55, acc); 213 | i++; 214 | goto y; 215 | a: 216 | ; 217 | } 218 | 219 | static void test_label() { 220 | int x = 0; 221 | if (1) 222 | L1: x++; 223 | expect(1, x); 224 | 225 | int y = 0; 226 | if (0) 227 | L2: y++; 228 | expect(0, y); 229 | 230 | int z = 0; 231 | switch (7) { 232 | if (1) 233 | case 5: z += 2; 234 | if (0) 235 | case 7: z += 3; 236 | if (1) 237 | case 6: z += 5; 238 | } 239 | expect(8, z); 240 | } 241 | 242 | static void test_computed_goto() { 243 | struct { void *x, *y, *z, *a; } t = { &&x, &&y, &&z, &&a }; 244 | int acc = 0; 245 | goto *t.x; 246 | acc = 5; 247 | x: expect(0, acc); 248 | 249 | int i = 0; 250 | acc = 0; 251 | y: if (i > 10) goto *t.z; 252 | acc += i++; 253 | goto *t.y; 254 | z: if (i > 11) goto *t.a; 255 | expect(55, acc); 256 | i++; 257 | goto *t.y; 258 | a: 259 | ; 260 | static void *p = &&L; 261 | goto *p; 262 | L: 263 | ; 264 | } 265 | 266 | static void test_logor() { 267 | expect(1, 0 || 3); 268 | expect(1, 5 || 0); 269 | expect(0, 0 || 0); 270 | } 271 | 272 | void testmain() { 273 | print("control flow"); 274 | test_if(); 275 | test_for(); 276 | test_while(); 277 | test_do(); 278 | test_switch(); 279 | test_goto(); 280 | test_label(); 281 | test_computed_goto(); 282 | test_logor(); 283 | } 284 | -------------------------------------------------------------------------------- /test/conversion.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void test_bool() { 6 | _Bool v = 3; 7 | expect(1, v); 8 | v = 5; 9 | expect(1, v); 10 | v = 0.5; 11 | expect(1, v); 12 | v = 0.0; 13 | expect(0, v); 14 | } 15 | 16 | static void test_float() { 17 | double a = 4.0; 18 | float b = a; 19 | expectf(4, b); 20 | } 21 | 22 | void testmain() { 23 | print("type conversion"); 24 | test_bool(); 25 | test_float(); 26 | } 27 | -------------------------------------------------------------------------------- /test/decl.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void t1() { 6 | int a = 1; 7 | expect(3, a + 2); 8 | } 9 | 10 | static void t2() { 11 | int a = 1; 12 | int b = 48 + 2; 13 | int c = a + b; 14 | expect(102, c * 2); 15 | } 16 | 17 | static void t3() { 18 | int a[] = { 55 }; 19 | int *b = a; 20 | expect(55, *b); 21 | } 22 | 23 | static void t4() { 24 | int a[] = { 55, 67 }; 25 | int *b = a + 1; 26 | expect(67, *b); 27 | } 28 | 29 | static void t5() { 30 | int a[] = { 20, 30, 40 }; 31 | int *b = a + 1; 32 | expect(30, *b); 33 | } 34 | 35 | static void t6() { 36 | int a[] = { 20, 30, 40 }; 37 | expect(20, *a); 38 | } 39 | 40 | static int ((t7))(); 41 | static int ((*t8))(); 42 | static int ((*(**t9))(int*(), int(*), int())); 43 | 44 | void testmain() { 45 | print("declaration"); 46 | t1(); 47 | t2(); 48 | t3(); 49 | t4(); 50 | t5(); 51 | t6(); 52 | } 53 | -------------------------------------------------------------------------------- /test/enum.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | enum { g1, g2, g3 } global1; 6 | 7 | void testmain() { 8 | print("enum"); 9 | 10 | expect(0, g1); 11 | expect(2, g3); 12 | 13 | enum { x } v; 14 | expect(0, x); 15 | 16 | enum { y }; 17 | expect(0, y); 18 | 19 | enum tag { z }; 20 | enum tag a = z; 21 | expect(0, z); 22 | expect(0, a); 23 | } 24 | -------------------------------------------------------------------------------- /test/extern.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | extern int externvar1; 6 | int extern externvar2; 7 | 8 | void testmain() { 9 | print("extern"); 10 | expect(98, externvar1); 11 | expect(99, externvar2); 12 | } 13 | -------------------------------------------------------------------------------- /test/float.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include "test.h" 7 | 8 | float tf1(float a) { return a; } 9 | float tf2(double a) { return a; } 10 | float tf3(int a) { return a; } 11 | 12 | double td1(float a) { return a; } 13 | double td2(double a) { return a; } 14 | double td3(int a) { return a; } 15 | 16 | double recursive(double a) { 17 | if (a < 10) return a; 18 | return recursive(3.33); 19 | } 20 | 21 | char *fmt(char *fmt, ...) { 22 | static char buf[128]; 23 | va_list args; 24 | va_start(args, fmt); 25 | vsnprintf(buf, sizeof(buf), fmt, args); 26 | va_end(args); 27 | return buf; 28 | } 29 | 30 | char *fmtint(int x) { return fmt("%d", x); } 31 | char *fmtdbl(double x) { return fmt("%a", x); } 32 | 33 | void std() { 34 | expect_string("21", fmtint(DECIMAL_DIG)); 35 | expect_string("0", fmtint(FLT_EVAL_METHOD)); 36 | expect_string("2", fmtint(FLT_RADIX)); 37 | expect_string("1", fmtint(FLT_ROUNDS)); 38 | 39 | expect_string("6", fmtint(FLT_DIG)); 40 | expect_string("0x1p-23", fmtdbl(FLT_EPSILON)); 41 | expect_string("24", fmtint(FLT_MANT_DIG)); 42 | expect_string("0x1.fffffep+127", fmtdbl(FLT_MAX)); 43 | expect_string("38", fmtint(FLT_MAX_10_EXP)); 44 | expect_string("128", fmtint(FLT_MAX_EXP)); 45 | expect_string("0x1p-126", fmtdbl(FLT_MIN)); 46 | expect_string("-37", fmtint(FLT_MIN_10_EXP)); 47 | expect_string("-125", fmtint(FLT_MIN_EXP)); 48 | expectd(*(float *)&(uint32_t){1}, FLT_TRUE_MIN); 49 | expect_string("0x1p-149", fmtdbl(FLT_TRUE_MIN)); 50 | 51 | expect_string("15", fmtint(DBL_DIG)); 52 | expect_string("0x1p-52", fmtdbl(DBL_EPSILON)); 53 | expect_string("53", fmtint(DBL_MANT_DIG)); 54 | expect_string("0x1.fffffffffffffp+1023", fmtdbl(DBL_MAX)); 55 | expect_string("308", fmtint(DBL_MAX_10_EXP)); 56 | expect_string("1024", fmtint(DBL_MAX_EXP)); 57 | expect_string("0x1p-1022", fmtdbl(DBL_MIN)); 58 | expect_string("-307", fmtint(DBL_MIN_10_EXP)); 59 | expect_string("-1021", fmtint(DBL_MIN_EXP)); 60 | expectd(*(double *)&(uint64_t){1}, DBL_TRUE_MIN); 61 | expect_string("0x0.0000000000001p-1022", fmtdbl(DBL_TRUE_MIN)); 62 | 63 | #ifdef __8cc__ 64 | expect_string("15", fmtint(LDBL_DIG)); 65 | expect_string("0x1p-52", fmtdbl(LDBL_EPSILON)); 66 | expect_string("53", fmtint(LDBL_MANT_DIG)); 67 | expect_string("0x1.fffffffffffffp+1023", fmtdbl(LDBL_MAX)); 68 | expect_string("308", fmtint(LDBL_MAX_10_EXP)); 69 | expect_string("1024", fmtint(LDBL_MAX_EXP)); 70 | expect_string("0x1p-1022", fmtdbl(LDBL_MIN)); 71 | expect_string("-307", fmtint(LDBL_MIN_10_EXP)); 72 | expect_string("-1021", fmtint(LDBL_MIN_EXP)); 73 | expectd(*(double *)&(uint64_t){1}, LDBL_TRUE_MIN); 74 | expect_string("0x0.0000000000001p-1022", fmtdbl(LDBL_TRUE_MIN)); 75 | #endif 76 | } 77 | 78 | void testmain() { 79 | print("float"); 80 | std(); 81 | 82 | expect(0.7, .7); 83 | float v1 = 10.0; 84 | float v2 = v1; 85 | expectf(10.0, v1); 86 | expectf(10.0, v2); 87 | return; 88 | double v3 = 20.0; 89 | double v4 = v3; 90 | expectd(20.0, v3); 91 | expectd(20.0, v4); 92 | 93 | expectf(1.0, 1.0); 94 | expectf(1.5, 1.0 + 0.5); 95 | expectf(0.5, 1.0 - 0.5); 96 | expectf(2.0, 1.0 * 2.0); 97 | expectf(0.25, 1.0 / 4.0); 98 | 99 | expectf(3.0, 1.0 + 2); 100 | expectf(2.5, 5 - 2.5); 101 | expectf(2.0, 1.0 * 2); 102 | expectf(0.25, 1.0 / 4); 103 | 104 | expectf(10.5, tf1(10.5)); 105 | expectf(10.0, tf1(10)); 106 | expectf(10.6, tf2(10.6)); 107 | expectf(10.0, tf2(10)); 108 | expectf(10.0, tf3(10.7)); 109 | expectf(10.0, tf3(10)); 110 | 111 | expectd(1.0, tf1(1.0)); 112 | expectd(10.0, tf1(10)); 113 | expectd(2.0, tf2(2.0)); 114 | expectd(10.0, tf2(10)); 115 | expectd(11.0, tf3(11.5)); 116 | expectd(10.0, tf3(10)); 117 | 118 | expectd(3.33, recursive(100)); 119 | } 120 | -------------------------------------------------------------------------------- /test/funcargs.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void many_ints(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9) { 6 | expect(1, v1); expect(2, v2); expect(3, v3); expect(4, v4); 7 | expect(5, v5); expect(6, v6); expect(7, v7); expect(8, v8); 8 | expect(9, v9); 9 | } 10 | 11 | static void many_floats(float v01, float v02, float v03, float v04, float v05, 12 | float v06, float v07, float v08, float v09, float v10, 13 | float v11, float v12, float v13, float v14, float v15, 14 | float v16, float v17) { 15 | expectf(1, v01); expectf(2, v02); expectf(3, v03); expectf(4, v04); 16 | expectf(5, v05); expectf(6, v06); expectf(7, v07); expectf(8, v08); 17 | expectf(9, v09); expectf(10, v10); expectf(11, v11); expectf(12, v12); 18 | expectf(13, v13); expectf(14, v14); expectf(15, v15); expectf(16, v16); 19 | expectf(17, v17); 20 | } 21 | 22 | static void mixed(float v01, int v02, float v03, int v04, float v05, int v06, float v07, int v08, 23 | float v09, int v10, float v11, int v12, float v13, int v14, float v15, int v16, 24 | float v17, int v18, float v19, int v20, float v21, int v22, float v23, int v24, 25 | float v25, int v26, float v27, int v28, float v29, int v30, float v31, int v32, 26 | float v33, int v34, float v35, int v36, float v37, int v38, float v39, int v40) { 27 | expectf(1.0, v01); expect(2, v02); expectf(3.0, v03); expect(4, v04); 28 | expectf(5.0, v05); expect(6, v06); expectf(7.0, v07); expect(8, v08); 29 | expectf(9.0, v09); expect(10, v10); expectf(11.0, v11); expect(12, v12); 30 | expectf(13.0, v13); expect(14, v14); expectf(15.0, v15); expect(16, v16); 31 | expectf(17.0, v17); expect(18, v18); expectf(19.0, v19); expect(20, v20); 32 | expectf(21.0, v21); expect(22, v22); expectf(23.0, v23); expect(24, v24); 33 | expectf(25.0, v25); expect(26, v26); expectf(27.0, v27); expect(28, v28); 34 | expectf(29.0, v29); expect(30, v30); expectf(31.0, v31); expect(32, v32); 35 | expectf(33.0, v33); expect(34, v34); expectf(35.0, v35); expect(36, v36); 36 | expectf(37.0, v37); expect(38, v38); expectf(39.0, v39); expect(40, v40); 37 | } 38 | 39 | void testmain() { 40 | print("function argument"); 41 | 42 | many_ints(1, 2, 3, 4, 5, 6, 7, 8, 9); 43 | 44 | many_floats(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 45 | 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 46 | 17.0); 47 | 48 | mixed(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 49 | 11.0, 12, 13.0, 14, 15.0, 16, 17.0, 18, 19.0, 20, 50 | 21.0, 22, 23.0, 24, 25.0, 26, 27.0, 28, 29.0, 30, 51 | 31.0, 32, 33.0, 34, 35.0, 36, 37.0, 38, 39.0, 40); 52 | } 53 | -------------------------------------------------------------------------------- /test/function.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | 6 | int t1() { 7 | return 77; 8 | } 9 | 10 | static void t2(int a) { 11 | expect(79, a); 12 | } 13 | 14 | static void t3(int a, int b, int c, int d, int e, int f) { 15 | expect(1, a); 16 | expect(2, b); 17 | expect(3, c); 18 | expect(4, d); 19 | expect(5, e); 20 | expect(6, f); 21 | } 22 | 23 | int t4a(int *p) { 24 | return *p; 25 | } 26 | 27 | static void t4() { 28 | int a[] = { 98 }; 29 | expect(98, t4a(a)); 30 | } 31 | 32 | static void t5a(int *p) { 33 | expect(99, *p); p=p+1; 34 | expect(98, *p); p=p+1; 35 | expect(97, *p); 36 | } 37 | 38 | static void t5b(int p[]) { 39 | expect(99, *p); p=p+1; 40 | expect(98, *p); p=p+1; 41 | expect(97, *p); 42 | } 43 | 44 | static void t5() { 45 | int a[] = {1, 2, 3}; 46 | int *p = a; 47 | *p = 99; p = p + 1; 48 | *p = 98; p = p + 1; 49 | *p = 97; 50 | t5a(a); 51 | t5b(a); 52 | } 53 | 54 | int t6(); 55 | int t6() { 56 | return 3; 57 | } 58 | 59 | int t7(int a, int b); 60 | int t7(int a, int b) { 61 | return a * b; 62 | } 63 | 64 | int t8(int a, ...) { 65 | expect(23, a); 66 | } 67 | 68 | static void t9() { 69 | return; 70 | } 71 | 72 | int t10(int a, double b) { 73 | return a + b; 74 | } 75 | 76 | int ptrtest1() { 77 | return 55; 78 | } 79 | 80 | int ptrtest2(int a) { 81 | return a * 2; 82 | } 83 | 84 | float ptrtest3(float a) { 85 | return a * 2; 86 | } 87 | 88 | int ptrtest4(int (f)(int), int x) { 89 | return f(x); 90 | } 91 | 92 | static void func_ptr_call() { 93 | expectf(4, ptrtest3(2)); 94 | int (*p1)(void) = ptrtest1; 95 | expect(55, p1()); 96 | int (*p2)(int) = ptrtest2; 97 | expect(110, p2(55)); 98 | float (*p3)(float) = ptrtest3; 99 | expectf(4, p3(2)); 100 | int (*p4)(void) = &ptrtest1; 101 | expect(55, (**p4)()); 102 | expect(10, ptrtest4(ptrtest2, 5)); 103 | } 104 | 105 | static void func_name() { 106 | expect_string("func_name", __func__); 107 | expect_string("func_name", __FUNCTION__); 108 | } 109 | 110 | static int local_static2() { 111 | static int x = 1; 112 | static char y[] = "2"; 113 | static int z; 114 | z = 3; 115 | return x++ + (y[0] - '0') + z; 116 | } 117 | 118 | static void local_static3() { 119 | static int x = 5; 120 | static char y[] = "8"; 121 | static int z; 122 | z = 100; 123 | } 124 | 125 | static void local_static() { 126 | expect(6, local_static2()); 127 | expect(7, local_static2()); 128 | local_static3(); 129 | expect(8, local_static2()); 130 | } 131 | 132 | static void empty() { 133 | } 134 | 135 | static void empty2() { 136 | ;;; 137 | } 138 | 139 | int booltest1(int x); 140 | 141 | bool booltest2(int x) { 142 | return x; 143 | } 144 | 145 | static void test_bool() { 146 | expect(0, booltest1(256)); 147 | expect(1, booltest1(257)); 148 | expect(1, booltest2(512)); 149 | expect(1, booltest2(513)); 150 | } 151 | 152 | typedef struct { int a, b, c, d; } MyType; 153 | 154 | int sum(MyType x) { 155 | return x.a + x.b + x.c + x.d; 156 | } 157 | 158 | static void test_struct() { 159 | expect(14, sum((MyType){ 2, 3, 4, 5 })); 160 | } 161 | 162 | static void test_funcdesg() { 163 | test_funcdesg; 164 | } 165 | 166 | typedef int (*t6_t)(void); 167 | 168 | static t6_t retfunc() { 169 | return &t6; 170 | } 171 | 172 | static t6_t retfunc2() { 173 | return t6; 174 | } 175 | 176 | // _Alignas is a declaration specifier containing parentheses. 177 | // Make sure the compiler doesn't interpret it as a function definition. 178 | static _Alignas(32) char char32; 179 | 180 | void testmain() { 181 | print("function"); 182 | 183 | expect(77, t1()); 184 | t2(79); 185 | t3(1, 2, 3, 4, 5, 6); 186 | t4(); 187 | t5(); 188 | expect(3, t6()); 189 | expect(12, t7(3, 4)); 190 | expect(77, (1 ? t1 : t6)()); 191 | expect(3, (0 ? t1 : t6)()); 192 | t8(23); 193 | t9(); 194 | expect(7, t10(3, 4.0)); 195 | func_ptr_call(); 196 | func_name(); 197 | local_static(); 198 | empty(); 199 | empty2(); 200 | test_bool(); 201 | test_struct(); 202 | test_funcdesg(); 203 | expect(3, retfunc()()); 204 | expect(3, retfunc2()()); 205 | } 206 | -------------------------------------------------------------------------------- /test/generic.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "test.h" 5 | 6 | #ifdef __8cc__ 7 | 8 | static void test_basic() { 9 | expect(1, _Generic(5, int: 1, float: 2)); 10 | expectd(3.0, _Generic(5.0, int: 1, float: 2.0, double: 3.0)); 11 | } 12 | 13 | static void test_arith() { 14 | typedef signed char schar; 15 | typedef unsigned char uchar; 16 | typedef unsigned short ushort; 17 | typedef unsigned int uint; 18 | typedef unsigned long ulong; 19 | typedef long long llong; 20 | typedef unsigned long long ullong; 21 | typedef long double ldouble; 22 | 23 | enum { B, SC, UC, S, US, I, U, L, UL, LL, ULL, F, D, LD }; 24 | 25 | #define T(x) \ 26 | _Generic(x, bool:B, schar:SC, uchar:UC, short:S, ushort:US, \ 27 | int:I, uint:U, long:L, ulong:UL, llong:LL, ullong:ULL, \ 28 | float:F, double:D, ldouble:LD) 29 | expect(B, T((bool)0)); 30 | expect(SC, T((schar)0)); 31 | expect(UC, T((uchar)0)); 32 | expect(I, T('a')); 33 | expect(US, T(u'a')); 34 | expect(U, T(U'a')); 35 | expect(I, T(0)); 36 | expect(U, T(0U)); 37 | expect(L, T(0L)); 38 | expect(UL, T(0UL)); 39 | expect(LL, T(0LL)); 40 | expect(ULL, T(0ULL)); 41 | expect(F, T(0.0F)); 42 | expect(D, T(0.0)); 43 | expect(LD, T(0.0L)); 44 | 45 | expect(I, T((bool)0 + (bool)0)); 46 | expect(I, T((char)0 + (char)0)); 47 | expect(I, T((char)0 + (uchar)0)); 48 | expect(I, T(0 + (char)0)); 49 | expect(U, T(0 + 0U)); 50 | expect(L, T(0 + 0L)); 51 | expect(LL, T(0LL + 0)); 52 | expect(LL, T(0L + 0LL)); 53 | expect(LL, T(0LL + 0U)); 54 | expect(UL, T(0UL + 0)); 55 | expect(UL, T(0L + 0UL)); 56 | expect(LL, T(0LL + 0U)); 57 | expect(ULL, T(0LU + 0LL)); 58 | expect(ULL, T(0ULL + 0U)); 59 | expect(ULL, T(0ULL + 0U)); 60 | expect(D, T(0 + 0.0)); 61 | expect(LD, T(0.0L + 0)); 62 | 63 | expect(I, T(0 << 0L)); 64 | expect(I, T(0 << 0LL)); 65 | expect(UL, T(0UL << 0)); 66 | expect(LL, T(0LL << 0)); 67 | expect(LL, T(0 ? 0LL : 0L)); 68 | expect(LL, T(0 ? 0L : 0LL)); 69 | 70 | expect(L, T(4000000000)); 71 | expect(L, T(1000000000000000000)); 72 | expect(I, T(0x7FFFFFFF)); 73 | expect(U, T(0x80000000)); 74 | expect(U, T(0xFFFFFFFF)); 75 | expect(L, T(0x100000000)); 76 | expect(L, T(0x7FFFFFFFFFFFFFFF)); 77 | expect(UL, T(0x8000000000000000)); 78 | expect(UL, T(0xFFFFFFFFFFFFFFFF)); 79 | expect(I, T(017777777777)); 80 | expect(U, T(020000000000)); 81 | expect(U, T(037777777777)); 82 | expect(L, T(040000000000)); 83 | expect(L, T(0777777777777777777777)); 84 | expect(UL, T(01000000000000000000000)); 85 | expect(UL, T(01777777777777777777777)); 86 | #undef T 87 | } 88 | 89 | static void test_default() { 90 | expect(1, _Generic(5, default: 1, float: 2)); 91 | expectd(3.0, _Generic(5.0, int: 1, float: 2.0, default: 3.0)); 92 | } 93 | 94 | static void test_struct() { 95 | struct t1 { int x, y; } v1; 96 | struct t2 { int x, y, z; } v2; 97 | expect(10, _Generic(v1, struct t1: 10, struct t2: 11, default: 12)); 98 | expect(11, _Generic(v2, struct t1: 10, struct t2: 11, default: 12)); 99 | expect(12, _Generic(99, struct t1: 10, struct t2: 11, default: 12)); 100 | } 101 | 102 | static void test_array() { 103 | expect(20, _Generic("abc", char[4]: 20, default: 21)); 104 | expect(22, _Generic((int*)NULL, int *: 22, default: 23)); 105 | expect(23, _Generic((int*)NULL, int[1]: 22, default: 23)); 106 | } 107 | 108 | void testmain() { 109 | print("_Generic"); 110 | test_basic(); 111 | test_arith(); 112 | test_default(); 113 | test_struct(); 114 | test_array(); 115 | } 116 | 117 | #else 118 | 119 | void testmain() { 120 | print("_Generic"); 121 | } 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /test/global.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | defaultint; 6 | 7 | int val = 21; 8 | int *p1 = &val; 9 | 10 | int a1[3]; 11 | int a2[3] = { 24, 25, 26 }; 12 | int x1, x2; 13 | int x3, x4 = 4; 14 | int x5 = 5, x6; 15 | 16 | char s1[] = "abcd"; 17 | char *s2 = "ABCD"; 18 | long l1 = 8; 19 | int *intp = &(int){ 9 }; 20 | 21 | void testmain() { 22 | print("global variable"); 23 | 24 | defaultint = 3; 25 | expect(3, defaultint); 26 | 27 | expect(21, val); 28 | val = 22; 29 | expect(22, val); 30 | expect(22, *p1); 31 | 32 | a1[1] = 23; 33 | expect(23, a1[1]); 34 | expect(25, a2[1]); 35 | 36 | x1 = 1; 37 | x2 = 2; 38 | expect(1, x1); 39 | expect(2, x2); 40 | x3 = 3; 41 | expect(3, x3); 42 | expect(4, x4); 43 | expect(5, x5); 44 | x6 = 6; 45 | expect(6, x6); 46 | 47 | expect_string("abcd", s1); 48 | expect_string("ABCD", s2); 49 | 50 | expectl(8, l1); 51 | expectl(9, *intp); 52 | } 53 | -------------------------------------------------------------------------------- /test/import.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | // import.h would raise an error if read twice. 6 | #import "import.h" 7 | #import "import.h" 8 | #include "import.h" 9 | #import "../test/import.h" 10 | 11 | // once.h would raise an error if read twice 12 | #include "once.h" 13 | #include "once.h" 14 | #import "once.h" 15 | #include "../test/once.h" 16 | 17 | void testmain() { 18 | print("import"); 19 | } 20 | -------------------------------------------------------------------------------- /test/import.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifdef IMPORT_H 4 | #error "#import directive bug" 5 | #endif 6 | 7 | #define IMPORT_H 1 8 | -------------------------------------------------------------------------------- /test/includeguard.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | #if __8cc__ 6 | 7 | #include "includeguard1.h" 8 | #if __8cc_include_guard == 1 9 | # error "include guard" 10 | #endif 11 | #include "includeguard1.h" 12 | #if __8cc_include_guard == 0 13 | # error "include guard" 14 | #endif 15 | 16 | #include "includeguard2.h" 17 | #if __8cc_include_guard == 1 18 | # error "include guard" 19 | #endif 20 | #include "includeguard2.h" 21 | #if __8cc_include_guard == 1 22 | # error "include guard" 23 | #endif 24 | 25 | #include "includeguard3.h" 26 | #if __8cc_include_guard == 1 27 | # error "include guard" 28 | #endif 29 | #include "includeguard3.h" 30 | #if __8cc_include_guard == 1 31 | # error "include guard" 32 | #endif 33 | 34 | #include "includeguard4.h" 35 | #if __8cc_include_guard == 1 36 | # error "include guard" 37 | #endif 38 | #include "includeguard4.h" 39 | #if __8cc_include_guard == 1 40 | # error "include guard" 41 | #endif 42 | 43 | #include "includeguard5.h" 44 | #if __8cc_include_guard == 1 45 | # error "include guard" 46 | #endif 47 | #include "includeguard5.h" 48 | #if __8cc_include_guard == 1 49 | # error "include guard" 50 | #endif 51 | 52 | #include "includeguard6.h" 53 | #if __8cc_include_guard == 1 54 | # error "include guard" 55 | #endif 56 | #include "includeguard6.h" 57 | #if __8cc_include_guard == 1 58 | # error "include guard" 59 | #endif 60 | 61 | #endif 62 | 63 | void testmain() { 64 | print("include guard"); 65 | } 66 | -------------------------------------------------------------------------------- /test/includeguard1.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef INCLUDEGUARD1_H 4 | #define INCLUDEGUARD1_H 5 | #endif 6 | -------------------------------------------------------------------------------- /test/includeguard2.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef INCLUDEGUARD2_H 4 | #endif 5 | -------------------------------------------------------------------------------- /test/includeguard3.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef INCLUDEGUARD3_H 4 | #define INCLUDEGUARD3_H 5 | #endif 6 | 7 | #define FOO 1 8 | -------------------------------------------------------------------------------- /test/includeguard4.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef INCLUDEGUARD4_H 4 | #define INCLUDEGUARD4_H 5 | #else 6 | #endif 7 | -------------------------------------------------------------------------------- /test/includeguard5.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #define FOO 4 | #ifndef INCLUDEGUARD5_H 5 | #define INCLUDEGUARD5_H 6 | #endif 7 | -------------------------------------------------------------------------------- /test/includeguard6.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifndef INCLUDEGUARD6_H 4 | #define INCLUDEGUARD6_H 5 | #include "includeguard7.h" 6 | -------------------------------------------------------------------------------- /test/includeguard7.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #endif 4 | -------------------------------------------------------------------------------- /test/initializer.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void verify(int *expected, int *got, int len) { 6 | for (int i = 0; i < len; i++) 7 | expect(expected[i], got[i]); 8 | } 9 | 10 | static void verify_short(short *expected, short *got, int len) { 11 | for (int i = 0; i < len; i++) 12 | expect(expected[i], got[i]); 13 | } 14 | 15 | static void test_array() { 16 | int x[] = { 1, 3, 5 }; 17 | expect(1, x[0]); 18 | expect(3, x[1]); 19 | expect(5, x[2]); 20 | 21 | int ye[] = { 1, 3, 5, 2, 4, 6, 3, 5, 7, 0, 0, 0 }; 22 | int y1[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, }; 23 | verify(ye, y1, 12); 24 | int y2[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; 25 | verify(ye, y2, 12); 26 | 27 | int ze[] = { 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0 }; 28 | int z[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; 29 | verify(ze, z, 12); 30 | 31 | short qe[24] = { 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6 }; 32 | short q[4][3][2] = { { 1 }, { 2, 3 }, { 4, 5, 6 } }; 33 | verify_short(qe, q, 24); 34 | 35 | int a[] = {{{ 3 }}}; 36 | expect(3, a[0]); 37 | } 38 | 39 | static void test_string() { 40 | char s[] = "abc"; 41 | expect_string("abc", s); 42 | char t[] = { "def" }; 43 | expect_string("def", t); 44 | } 45 | 46 | static void test_struct() { 47 | int we[] = { 1, 0, 0, 0, 2, 0, 0, 0 }; 48 | struct { int a[3]; int b; } w[] = { { 1 }, 2 }; 49 | verify(we, &w, 8); 50 | } 51 | 52 | static void test_primitive() { 53 | int a = { 59 }; 54 | expect(59, a); 55 | } 56 | 57 | static void test_nested() { 58 | struct { 59 | struct { 60 | struct { int a; int b; } x; 61 | struct { char c[8]; } y; 62 | } w; 63 | } v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, }; 64 | expect(1, v.w.x.a); 65 | expect(2, v.w.x.b); 66 | expect(3, v.w.y.c[0]); 67 | expect(10, v.w.y.c[7]); 68 | } 69 | 70 | static void test_array_designator() { 71 | int v[3] = { [1] = 5 }; 72 | expect(0, v[0]); 73 | expect(5, v[1]); 74 | expect(0, v[2]); 75 | 76 | struct { int a, b; } x[2] = { [1] = { 1, 2 } }; 77 | expect(0, x[0].a); 78 | expect(0, x[0].b); 79 | expect(1, x[1].a); 80 | expect(2, x[1].b); 81 | 82 | struct { int a, b; } x2[3] = { [1] = 1, 2, 3, 4 }; 83 | expect(0, x2[0].a); 84 | expect(0, x2[0].b); 85 | expect(1, x2[1].a); 86 | expect(2, x2[1].b); 87 | expect(3, x2[2].a); 88 | expect(4, x2[2].b); 89 | 90 | int x3[] = { [2] = 3, [0] = 1, 2 }; 91 | expect(1, x3[0]); 92 | expect(2, x3[1]); 93 | expect(3, x3[2]); 94 | } 95 | 96 | static void test_struct_designator() { 97 | struct { int x; int y; } v1 = { .y = 1, .x = 5 }; 98 | expect(5, v1.x); 99 | expect(1, v1.y); 100 | 101 | struct { int x; int y; } v2 = { .y = 7 }; 102 | expect(7, v2.y); 103 | 104 | struct { int x; int y; int z; } v3 = { .y = 12, 17 }; 105 | expect(12, v3.y); 106 | expect(17, v3.z); 107 | } 108 | 109 | static void test_complex_designator() { 110 | struct { struct { int a, b; } x[3]; } y[] = { 111 | [1].x[0].b = 5, 6, 7, 8, 9, 112 | [0].x[2].b = 10, 11 113 | }; 114 | expect(0, y[0].x[0].a); 115 | expect(0, y[0].x[0].b); 116 | expect(0, y[0].x[1].a); 117 | expect(0, y[0].x[1].b); 118 | expect(0, y[0].x[2].a); 119 | expect(10, y[0].x[2].b); 120 | expect(11, y[1].x[0].a); 121 | expect(5, y[1].x[0].b); 122 | expect(6, y[1].x[1].a); 123 | expect(7, y[1].x[1].b); 124 | expect(8, y[1].x[2].a); 125 | expect(9, y[1].x[2].b); 126 | 127 | int y2[][3] = { [0][0] = 1, [1][0] = 3 }; 128 | expect(1, y2[0][0]); 129 | expect(3, y2[1][0]); 130 | 131 | struct { int a, b[3]; } y3 = { .a = 1, .b[0] = 10, .b[1] = 11 }; 132 | expect(1, y3.a); 133 | expect(10, y3.b[0]); 134 | expect(11, y3.b[1]); 135 | expect(0, y3.b[2]); 136 | } 137 | 138 | static void test_zero() { 139 | struct tag { int x, y; }; 140 | struct tag v0 = (struct tag){ 6 }; 141 | expect(6, v0.x); 142 | expect(0, v0.y); 143 | 144 | struct { int x; int y; } v1 = { 6 }; 145 | expect(6, v1.x); 146 | expect(0, v1.y); 147 | 148 | struct { int x; int y; } v2 = { .y = 3 }; 149 | expect(0, v2.x); 150 | expect(3, v2.y); 151 | 152 | struct { union { int x, y; }; } v3 = { .x = 61 }; 153 | expect(61, v3.x); 154 | } 155 | 156 | 157 | static void test_typedef() { 158 | typedef int A[]; 159 | A a = { 1, 2 }; 160 | A b = { 3, 4, 5 }; 161 | expect(2, sizeof(a) / sizeof(*a)); 162 | expect(3, sizeof(b) / sizeof(*b)); 163 | } 164 | 165 | static void test_excessive() { 166 | #ifdef __8cc__ 167 | #pragma disable_warning 168 | #endif 169 | 170 | char x1[3] = { 1, 2, 3, 4, 5 }; 171 | expect(3, sizeof(x1)); 172 | 173 | char x2[3] = "abcdefg"; 174 | expect(3, sizeof(x2)); 175 | expect(0, strncmp("abc", x2, 3)); 176 | 177 | #ifdef __8cc__ 178 | #pragma disable_warning 179 | #endif 180 | } 181 | 182 | void testmain() { 183 | print("initializer"); 184 | 185 | test_array(); 186 | test_string(); 187 | test_struct(); 188 | test_primitive(); 189 | test_nested(); 190 | test_array_designator(); 191 | test_struct_designator(); 192 | test_complex_designator(); 193 | test_zero(); 194 | test_typedef(); 195 | test_excessive(); 196 | } 197 | -------------------------------------------------------------------------------- /test/int.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void expects(short a, short b) { 6 | if (!(a == b)) { 7 | printf("Failed\n"); 8 | printf(" %d expected, but got %d\n", a, b); 9 | exit(1); 10 | } 11 | } 12 | 13 | void testmain() { 14 | print("long"); 15 | 16 | short a = 10; 17 | short int b = 15; 18 | expects(25, a + b); 19 | expects(20, a + 10); 20 | 21 | long x = 67; 22 | long int y = 69; 23 | expectl(67, x); 24 | expectl(136, x + y); 25 | expectl(10L, 10L); 26 | expectl(4294967295L, 4294967295); 27 | expectl(1152921504606846976, 1152921504606846976); 28 | expectl(1152921504606846977, 1152921504606846976 + 1); 29 | } 30 | -------------------------------------------------------------------------------- /test/iso646.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "test.h" 5 | 6 | #define SS(x) #x 7 | #define S(x) SS(x) 8 | 9 | void testmain() { 10 | print("iso646"); 11 | expect_string("&&", S(and)); 12 | expect_string("&=", S(and_eq)); 13 | expect_string("&", S(bitand)); 14 | expect_string("|", S(bitor)); 15 | expect_string("~", S(compl)); 16 | expect_string("!", S(not)); 17 | expect_string("!=", S(not_eq)); 18 | expect_string("||", S(or)); 19 | expect_string("|=", S(or_eq)); 20 | expect_string("^", S(xor)); 21 | expect_string("^=", S(xor_eq)); 22 | } 23 | -------------------------------------------------------------------------------- /test/lex.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | #define stringify(x) %:x 6 | #define paste(x, y) x%:%:y 7 | 8 | static void digraph() { 9 | // These tests don't conform to the C standard. 10 | // N1570 6.4.6.3 says that the digraphs behave the same 11 | // as the corresponding tokens except for their spellings. 12 | // That implies the compiler should preserve the original 13 | // spelling instead of replacing digraphs with regular tokens. 14 | // I intentionally leave this bug because that's really a minor 15 | // bug which doesn't worth the complexity to be handled correctly. 16 | #ifdef __8cc__ 17 | expect_string("[", stringify(<:)); 18 | expect_string("]", stringify(:>)); 19 | expect_string("{", stringify(<%)); 20 | expect_string("}", stringify(%>)); 21 | expect_string("#", stringify(%:)); 22 | expect_string("% :", stringify(% :)); 23 | expect_string("##", stringify(%:%:)); 24 | expect_string("#%", stringify(%:%)); 25 | expect(12, paste(1, 2)); 26 | #endif 27 | } 28 | 29 | static void escape() { 30 | int value = 10; 31 | expect(10, val\ 32 | ue); 33 | expect_string("a bc", "a\ bc"); 34 | } 35 | 36 | static void whitespace() { 37 | expect_string("x y", stringify( x y )); 38 | } 39 | 40 | static void newline() { 41 | 42 | # 43 | } 44 | 45 | static void dollar() { 46 | int $ = 1; 47 | expect(1, $); 48 | int $2 = 2; 49 | expect(2, $2); 50 | int a$ = 3; 51 | expect(3, a$); 52 | } 53 | 54 | void testmain() { 55 | print("lexer"); 56 | digraph(); 57 | escape(); 58 | whitespace(); 59 | newline(); 60 | dollar(); 61 | } 62 | -------------------------------------------------------------------------------- /test/line.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "test.h" 5 | 6 | void testmain() { 7 | print("#line"); 8 | 9 | #line 99 10 | expect(99, __LINE__); 11 | 12 | #line 199 "foo" 13 | expect(199, __LINE__); 14 | expect_string("foo", __FILE__); 15 | 16 | #define X 3 17 | #line X 18 | expect(3, __LINE__); 19 | 20 | #define Y 5 "bar" 21 | #line Y 22 | expect(5, __LINE__); 23 | expect_string("bar", __FILE__); 24 | 25 | # 1 "xyz" 26 | expect(1, __LINE__); 27 | expect_string("xyz", __FILE__); 28 | 29 | # 2 "XYZ" 1 3 4 30 | expect(2, __LINE__); 31 | expect_string("XYZ", __FILE__); 32 | } 33 | -------------------------------------------------------------------------------- /test/literal.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include "string.h" 5 | 6 | static void test_char() { 7 | expect(65, 'A'); 8 | expect(97, 'a'); 9 | expect(7, '\a'); 10 | expect(8, '\b'); 11 | expect(12, '\f'); 12 | expect(10, '\n'); 13 | expect(13, '\r'); 14 | expect(9, '\t'); 15 | expect(11, '\v'); 16 | expect(27, '\e'); 17 | 18 | expect(0, '\0'); 19 | expect(7, '\7'); 20 | expect(15, '\17'); 21 | expect(-99, '\235'); 22 | 23 | expect(0, '\x0'); 24 | expect(-1, '\xff'); 25 | expect(15, '\xF'); 26 | expect(18, '\x012'); 27 | } 28 | 29 | static void test_string() { 30 | expect_string("abc", "abc"); 31 | expect_string("abc", u8"abc"); 32 | expect('a', "abc"[0]); 33 | expect(0, "abc"[3]); 34 | expect_string("abcd", "ab" "cd"); 35 | expect_string("abcdef", "ab" "cd" "ef"); 36 | 37 | char expected[] = { 65, 97, 7, 8, 12, 10, 13, 9, 11, 27, 7, 15, -99, -1, 18, 0 }; 38 | expect_string(expected, "Aa\a\b\f\n\r\t\v\e\7\17\235\xff\x012"); 39 | expect('c', L'c'); 40 | expect(0x3042, L'\u3042'); 41 | expect(0x3042, u'\u3042'); 42 | expect(0x3042, U'\u3042'); 43 | 44 | // Make sure we can handle an identifier starting with "L", "u", "U" or "u8". 45 | int L = 1, u = 2, U = 3, u8 = 4; 46 | expect(10, L + u + U + u8); 47 | int Lx = 1, ux = 2, Ux = 3, u8x = 4; 48 | expect(10, Lx + ux + Ux + u8x); 49 | } 50 | 51 | static void test_mbstring() { 52 | expect(2, sizeof(u"")); 53 | expect(8, sizeof(u"abc")); 54 | expect(8, sizeof("ab" u"c")); 55 | expect(8, sizeof(u"ab" u"c")); 56 | expect(1, sizeof(u8"")); 57 | expect(4, sizeof(u8"abc")); 58 | expect(4, sizeof("ab" u8"c")); 59 | expect(4, sizeof(u8"ab" u8"c")); 60 | expect(4, sizeof(L"")); 61 | expect(16, sizeof(L"abc")); 62 | expect(16, sizeof(L"ab" L"c")); 63 | expect(4, sizeof(U"")); 64 | expect(16, sizeof(U"abc")); 65 | expect(16, sizeof("ab" U"c")); 66 | expect(16, sizeof(U"ab" U"c")); 67 | expect(0, memcmp("x\0\0\0y\0\0\0z\0\0\0\0\0\0", L"xyz", 16)); 68 | expect(0, memcmp("x\0\0\0y\0\0\0z\0\0\0\0\0\0", U"xyz", 16)); 69 | expect(0, memcmp("\x78\0\x79\0\x7A\0\0\0", u"xyz", 8)); 70 | 71 | expect(4, sizeof("\u3042")); 72 | expect(0, memcmp("\xE3\x81\x82\0", "\u3042", 4)); 73 | expect(12, sizeof("\u3042" L"x")); 74 | expect(0, memcmp("\x42\x30\0\0\x78\0\0\0\0\0\0\0", "\u3042" L"x", 12)); 75 | 76 | // GCC 5 allows UTF-8 strings as identifiers. 77 | #ifdef __8cc__ 78 | int 日本語 = 3; 79 | expect(3, 日本語); 80 | expect(3, 日\u672C\U00008A9E); 81 | #endif 82 | } 83 | 84 | static void test_float() { 85 | expectf(1.0, 1.0); 86 | expectd(1.0, 1.0L); 87 | expectf(1.0, 0x1p+0); 88 | expectf(1.0, 0x1p-0); 89 | } 90 | 91 | static void test_ucn() { 92 | expect('$', L'\u0024'); 93 | expect('$', L'\U00000024'); 94 | expect_string("$", "\u0024"); 95 | expect_string("$", "\U00000024"); 96 | expect('X', L'X'); 97 | expect('X', U'X'); 98 | expect('X', u'X'); 99 | } 100 | 101 | int g1 = 80; 102 | int *g2 = &(int){ 81 }; 103 | struct g3 { int x; } *g3 = &(struct g3){ 82 }; 104 | struct g4 { char x; struct g4a { int y[2]; } *z; } *g4 = &(struct g4){ 83, &(struct g4a){ 84, 85 } }; 105 | 106 | static void test_compound() { 107 | expect(1, (int){ 1 }); 108 | expect(3, ((int[]){ 1, 2, 3 }[2])); 109 | expect(12, sizeof((int[]){ 1, 2, 3 })); 110 | expect(6, ((struct { int x[3]; }){ 5, 6, 7 }.x[1])); 111 | 112 | expect(80, g1); 113 | expect(81, *g2); 114 | expect(82, g3->x); 115 | expect(83, g4->x); 116 | expect(84, g4->z->y[0]); 117 | expect(85, g4->z->y[1]); 118 | } 119 | 120 | void testmain() { 121 | print("literal"); 122 | test_char(); 123 | test_string(); 124 | test_mbstring(); 125 | test_float(); 126 | test_ucn(); 127 | test_compound(); 128 | } 129 | -------------------------------------------------------------------------------- /test/macro.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "test.h" 10 | 11 | static char *get_timestamp() { 12 | static char buf[30]; 13 | struct stat s; 14 | stat(__FILE__, &s); 15 | setlocale(LC_ALL, "C"); 16 | strftime(buf, 30, "%a %b %e %T %Y", localtime(&s.st_mtime)); 17 | return buf; 18 | } 19 | 20 | static void special() { 21 | expect_string("test/macro.c", __FILE__); 22 | expect(22, __LINE__); 23 | expect(11, strlen(__DATE__)); 24 | expect(8, strlen(__TIME__)); 25 | expect(24, strlen(__TIMESTAMP__)); 26 | expect(0, __INCLUDE_LEVEL__); 27 | expect_string("test/macro.c", __BASE_FILE__); 28 | expect_string(get_timestamp(), __TIMESTAMP__); 29 | } 30 | 31 | static void include() { 32 | #include "macro1.h" 33 | expect_string("macro1", MACRO_1); 34 | 35 | #define MACRO_2_FILE "macro2.h" 36 | #include MACRO_2_FILE 37 | expect_string("macro2", MACRO_2); 38 | 39 | #define STDBOOL_H_FILE 40 | #ifdef __STDBOOL_H 41 | # error test failed 42 | #endif 43 | #include STDBOOL_H_FILE 44 | #ifndef __bool_true_false_are_defined 45 | # error test failed 46 | #endif 47 | } 48 | 49 | static void predefined() { 50 | #ifdef __8cc__ 51 | expect(1, __8cc__); 52 | expect(1, __STDC_NO_ATOMICS__); 53 | expect(1, __STDC_NO_COMPLEX__); 54 | expect(1, __STDC_NO_THREADS__); 55 | expect(1, __STDC_NO_VLA__); 56 | #endif 57 | expect(1, __amd64); 58 | expect(1, __amd64__); 59 | expect(1, __x86_64); 60 | expect(1, __x86_64__); 61 | expect(1, linux); 62 | expect(1, __linux); 63 | expect(1, __linux__); 64 | expect(1, __gnu_linux__); 65 | expect(1, __unix); 66 | expect(1, __unix__); 67 | expect(1, _LP64); 68 | expect(1, __LP64__); 69 | expect(1, __ELF__); 70 | expect(1, __STDC__); 71 | expect(1, __STDC_HOSTED__); 72 | expect(1, __STDC_UTF_16__); 73 | expect(1, __STDC_UTF_32__); 74 | expect(201112, __STDC_VERSION__); 75 | 76 | expect(2, __SIZEOF_SHORT__); 77 | expect(4, __SIZEOF_INT__); 78 | expect(8, __SIZEOF_LONG__); 79 | expect(8, __SIZEOF_LONG_LONG__); 80 | expect(4, __SIZEOF_FLOAT__); 81 | expect(8, __SIZEOF_DOUBLE__); 82 | expect(8, __SIZEOF_POINTER__); 83 | expect(8, __SIZEOF_PTRDIFF_T__); 84 | expect(8, __SIZEOF_SIZE_T__); 85 | #ifdef __8cc__ 86 | expect(8, __SIZEOF_LONG_DOUBLE__); 87 | #endif 88 | 89 | expect(sizeof(short), __SIZEOF_SHORT__); 90 | expect(sizeof(int), __SIZEOF_INT__); 91 | expect(sizeof(long), __SIZEOF_LONG__); 92 | expect(sizeof(long long), __SIZEOF_LONG_LONG__); 93 | expect(sizeof(float), __SIZEOF_FLOAT__); 94 | expect(sizeof(double), __SIZEOF_DOUBLE__); 95 | expect(sizeof(void *), __SIZEOF_POINTER__); 96 | expect(sizeof(ptrdiff_t), __SIZEOF_PTRDIFF_T__); 97 | expect(sizeof(size_t), __SIZEOF_SIZE_T__); 98 | expect(sizeof(long double), __SIZEOF_LONG_DOUBLE__); 99 | } 100 | 101 | #define ZERO 0 102 | #define ONE 1 103 | #define TWO ONE + ONE 104 | #define LOOP LOOP 105 | 106 | static void simple() { 107 | expect(1, ONE); 108 | expect(2, TWO); 109 | } 110 | 111 | #define VAR1 VAR2 112 | #define VAR2 VAR1 113 | 114 | static void loop() { 115 | int VAR1 = 1; 116 | int VAR2 = 2; 117 | expect(1, VAR1); 118 | expect(2, VAR2); 119 | } 120 | 121 | static void undef() { 122 | int a = 3; 123 | #define a 10 124 | expect(10, a); 125 | #undef a 126 | expect(3, a); 127 | #define a 16 128 | expect(16, a); 129 | #undef a 130 | } 131 | 132 | static void cond_incl() { 133 | int a = 1; 134 | #if 0 135 | a = 2; 136 | #endif 137 | expect(1, a); 138 | 139 | #if 0 140 | fail("if 0"); 141 | xyz /* 142 | #else 143 | abc */ 144 | fail("if 0"); 145 | #endif 146 | 147 | /* 148 | */#if 0 149 | fail("if 0"); 150 | xyz "\"/*" '\'/*' 151 | #else 152 | a = 5; 153 | #endif 154 | expect(a, 5); 155 | 156 | #if 0 157 | #elif 1 158 | a = 2; 159 | #endif 160 | expect(2, a); 161 | 162 | #if 1 163 | a = 3; 164 | #elif 1 165 | a = 4; 166 | #endif 167 | expect(3, a); 168 | 169 | #if 1 170 | a = 5; 171 | #endif 172 | expect(5, a); 173 | 174 | #if 1 175 | a = 10; 176 | #else 177 | a = 12; 178 | #endif 179 | expect(10, a); 180 | 181 | #if 0 182 | a = 11; 183 | #else 184 | a = 12; 185 | #endif 186 | expect(12, a); 187 | 188 | #if 0 189 | # if 1 190 | # endif 191 | #else 192 | a = 150; 193 | #endif 194 | expect(150, a); 195 | } 196 | 197 | static void const_expr() { 198 | int a = 1; 199 | #if 0 + 1 200 | a = 2; 201 | #else 202 | a = 3; 203 | #endif 204 | expect(2, a); 205 | 206 | #if 0 + 1 * 2 + 4 / 2 ^ 3 & ~1 % 5 207 | a = 4; 208 | #else 209 | a = 5; 210 | #endif 211 | expect(4, a); 212 | 213 | #if 1 && 0 214 | #else 215 | a = 100; 216 | #endif 217 | expect(100, a); 218 | 219 | #if 1 && 1 220 | a = 101; 221 | #else 222 | #endif 223 | expect(101, a); 224 | 225 | #if 1 || 0 226 | a = 102; 227 | #else 228 | #endif 229 | expect(102, a); 230 | 231 | #if 0 || 0 232 | #else 233 | a = 103; 234 | #endif 235 | expect(103, a); 236 | 237 | #if 0 238 | #elif !0 239 | a = 104; 240 | #endif 241 | expect(104, a); 242 | 243 | #if 0 244 | fail("#if"); 245 | #elif 0 246 | fail("#elif"); 247 | #endif 248 | 249 | #if 0 + 0 250 | a = 6; 251 | #else 252 | a = 7; 253 | #endif 254 | expect(7, a); 255 | 256 | #if ZERO 257 | a = 8; 258 | #else 259 | a = 9; 260 | #endif 261 | expect(9, a); 262 | 263 | #if NO_SUCH_MACRO 264 | a = 14; 265 | #else 266 | a = 15; 267 | #endif 268 | expect(15, a); 269 | 270 | #if LOOP 271 | a = 10; 272 | #else 273 | a = 11; 274 | #endif 275 | expect(11, a); 276 | 277 | #if LOOP - 1 278 | a = 12; 279 | #else 280 | a = 13; 281 | #endif 282 | expect(12, a); 283 | } 284 | 285 | static void defined() { 286 | int a = 0; 287 | #if defined ZERO 288 | a = 1; 289 | #endif 290 | expect(1, a); 291 | #if defined(ZERO) 292 | a = 2; 293 | #endif 294 | expect(2, a); 295 | #if defined(NO_SUCH_MACRO) 296 | a = 3; 297 | #else 298 | a = 4; 299 | #endif 300 | expect(4, a); 301 | } 302 | 303 | static void ifdef() { 304 | int a = 0; 305 | #ifdef ONE 306 | a = 1; 307 | #else 308 | a = 2; 309 | # 310 | #1234 311 | #endif 312 | expect(a, 1); 313 | 314 | #ifdef NO_SUCH_MACRO 315 | a = 3; 316 | #else 317 | a = 4; 318 | #endif 319 | expect(a, 4); 320 | 321 | #ifndef ONE 322 | a = 5; 323 | #else 324 | a = 6; 325 | #endif 326 | expect(a, 6); 327 | 328 | #ifndef NO_SUCH_MACRO 329 | a = 7; 330 | #else 331 | a = 8; 332 | #endif 333 | expect(a, 7); 334 | } 335 | 336 | int plus(int a, int b) { 337 | return a + b; 338 | } 339 | 340 | int minus(int a, int b) { 341 | return a - b; 342 | } 343 | 344 | static void funclike() { 345 | #define stringify(x) #x 346 | expect_string("5", stringify(5)); 347 | expect_string("x", stringify(x)); 348 | expect_string("x y", stringify(x y)); 349 | expect_string("x y", stringify( x y )); 350 | expect_string("x + y", stringify( x + y )); 351 | expect_string("x + y", stringify(/**/x/**/+/**//**/ /**/y/**/)); 352 | expect_string("x+y", stringify( x+y )); 353 | expect_string("'a'", stringify('a')); 354 | expect_string("'\\''", stringify('\'')); 355 | expect_string("L'a'", stringify(L'a')); 356 | expect_string("U'a'", stringify(U'a')); 357 | expect_string("u'a'", stringify(u'a')); 358 | expect_string("\"abc\"", stringify("abc")); 359 | expect_string("L\"abc\"", stringify(L"abc")); 360 | expect_string("U\"abc\"", stringify(U"abc")); 361 | expect_string("u\"abc\"", stringify(u"abc")); 362 | expect_string("u8\"abc\"", stringify(u8"abc")); 363 | expect_string("ZERO", stringify(ZERO)); 364 | expect_string("1 2", stringify(1 365 | 2)); 366 | 367 | #define m1(x) x 368 | expect(5, m1(5)); 369 | expect(7, m1((5 + 2))); 370 | expect(8, m1(plus(5, 3))); 371 | expect(10, m1() 10); 372 | expect(14, m1(2 + 373 | 2 +) 10); 374 | 375 | #define m2(x) x + x 376 | expect(10, m2(5)); 377 | 378 | #define m3(x, y) x * y 379 | expect(50, m3(5, 10)); 380 | expect(11, m3(2 + 2, 3 + 3)); 381 | 382 | #define m4(x, y) x + y + TWO 383 | expect(17, m4(5, 10)); 384 | 385 | #define m6(x, ...) x + __VA_ARGS__ 386 | expect(20, m6(2, 18)); 387 | expect(25, plus(m6(2, 18, 5))); 388 | 389 | #define plus(x, y) x * y + plus(x, y) 390 | expect(11, plus(2, 3)); 391 | #undef plus 392 | 393 | #define plus(x, y) minus(x, y) 394 | #define minus(x, y) plus(x, y) 395 | expect(31, plus(30, 1)); 396 | expect(29, minus(30, 1)); 397 | 398 | // This is not a function-like macro. 399 | #define m7 (0) + 1 400 | expect(1, m7); 401 | 402 | #define m8(x, y) x ## y 403 | expect(2, m8(TW, O)); 404 | expect(0, m8(ZERO,)); 405 | expect(8, 1 m8(<, <) 3); 406 | expectf(.123, m8(., 123)); 407 | expect('a', m8(L, 'a')); 408 | expect('a', m8(U, 'a')); 409 | expect('a', m8(u, 'a')); 410 | expect_string(L"abc", m8(L, "abc")); 411 | expect_string(U"abc", m8(U, "abc")); 412 | expect_string(u"abc", m8(u, "abc")); 413 | expect_string(u8"abc", m8(u8, "abc")); 414 | 415 | #define m9(x, y, z) x y + z 416 | expect(8, m9(1,, 7)); 417 | 418 | #define m10(x) x ## x 419 | expect_string("a", "a" m10()); 420 | 421 | #define hash_hash # ## # 422 | #define mkstr(a) # a 423 | #define in_between(a) mkstr(a) 424 | #define join(c, d) in_between(c hash_hash d) 425 | expect_string("x ## y", join(x, y)); 426 | 427 | int m14 = 67; 428 | #define m14(x) x 429 | expect(67, m14); 430 | expect(67, m14(m14)); 431 | 432 | int a = 68; 433 | #define glue(x, y) x ## y 434 | glue(a+, +); 435 | expect(69, a); 436 | 437 | #define identity(x) stringify(x) 438 | expect_string("aa A B aa C", identity(m10(a) A B m10(a) C)); 439 | 440 | #define identity2(x) stringify(z ## x) 441 | expect_string("zA m10(a) A B m10(a) C", identity2(A m10(a) A B m10(a) C)); 442 | 443 | #define m15(x) x x 444 | expect_string("a a", identity(m15(a))); 445 | 446 | #define m16(x) (x,x) 447 | expect_string("(a,a)", identity(m16(a))); 448 | 449 | #define m17(x) stringify(.x . x) 450 | expect_string(".3 . 3", m17(3)); 451 | } 452 | 453 | static void empty() { 454 | #define EMPTY 455 | expect(1, 1 EMPTY); 456 | #define EMPTY2(x) 457 | expect(2, 2 EMPTY2(foo)); 458 | expect(2, 2 EMPTY2(foo bar)); 459 | expect(2, 2 EMPTY2(((())))); 460 | } 461 | 462 | static void noarg() { 463 | #define NOARG() 55 464 | expect(55, NOARG()); 465 | } 466 | 467 | static void null() { 468 | # 469 | } 470 | 471 | static void counter() { 472 | expect(0, __COUNTER__); 473 | expect(1, __COUNTER__); 474 | expect(2, __COUNTER__); 475 | } 476 | 477 | static void gnuext() { 478 | #define m11(x, y...) stringify(x + y) 479 | expect_string("2 + 18", m11(2, 18)); 480 | expect_string("2 +", m11(2)); 481 | 482 | #define m12(x, y...) stringify((x, ## y)) 483 | expect_string("(1)", m12(1)); 484 | expect_string("(1, 2)", m12(1, 2)); 485 | 486 | #define m13(x, y) stringify([x y]) 487 | #define m14 1 488 | expect_string("[2 2]", m13(m14, 489 | #undef m14 490 | #define m14 2 491 | m14)); 492 | } 493 | 494 | void testmain() { 495 | print("macros"); 496 | special(); 497 | include(); 498 | predefined(); 499 | simple(); 500 | loop(); 501 | undef(); 502 | cond_incl(); 503 | const_expr(); 504 | defined(); 505 | ifdef(); 506 | funclike(); 507 | empty(); 508 | noarg(); 509 | null(); 510 | counter(); 511 | gnuext(); 512 | } 513 | -------------------------------------------------------------------------------- /test/macro1.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #define MACRO_1 "macro1" 4 | #if __INCLUDE_LEVEL__ != 1 5 | # error "include level" 6 | #endif 7 | -------------------------------------------------------------------------------- /test/macro2.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #define MACRO_2 "macro2" 4 | -------------------------------------------------------------------------------- /test/negative.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | # Copyright 2015 Rui Ueyama. Released under the MIT license. 3 | 4 | # This file contains negative tests. 5 | # All tests in this file are not valid C code and thus cause 6 | # the compiler to print out error messages. 7 | # We verify that the compiler actually detects these errors and 8 | # prints out correct error messages. 9 | 10 | from multiprocessing import Pool 11 | from subprocess import Popen, PIPE, STDOUT 12 | import re 13 | 14 | # These are lists of expected error messages and compiler inputs. 15 | lex_tests = r""" 16 | ! 1:10: \x is not followed by a hexadecimal character: z 17 | int i = '\xz' 18 | 19 | ! 1:12: invalid universal character: @ 20 | char *p = "\u123@"; 21 | 22 | ! 1:12: invalid universal character: \u0097 23 | char *p = "\u0097"; 24 | 25 | ! 1:12: unknown escape character: \y 26 | char *p = "\y"; 27 | 28 | ! 1:10: unterminated char 29 | char x = ' 30 | 31 | ! 1:11: unterminated string 32 | char *p = " 33 | 34 | ! 1:1: premature end of block comment 35 | /* 36 | 37 | ! 1:10: header name should not be empty 38 | #include <> 39 | 40 | ! 1:10: header name should not be empty 41 | #include "" 42 | """ 43 | 44 | cpp_tests = r""" 45 | ! 2:1: unterminated macro argument list 46 | #define x() 47 | x( 48 | 49 | ! 2:1: macro argument number does not match 50 | #define x(_) 51 | x(1, 2) 52 | 53 | ! 1:13: , expected, but got b 54 | #define x(a b) 55 | 56 | ! 1:9: missing ')' in macro parameter list 57 | #define x(a, 58 | 59 | ! 1:11: identifier expected, but got 123 60 | #define x(123) 61 | 62 | ! 1:17: ) expected, but got , 63 | #define x(x, ..., y) 64 | 65 | ! 1:11: '##' cannot appear at start of macro expansion 66 | #define x ## 67 | 68 | ! 1:14: '##' cannot appear at start of macro expansion 69 | #define x(y) ## x 70 | 71 | ! 1:16: '##' cannot appear at end of macro expansion 72 | #define x(y) x ## 73 | 74 | ! 1:13: identifier expected, but got "abc" 75 | #if defined("abc") 76 | 77 | ! 1:8: identifier expected, but got "abc" 78 | #ifdef "abc" 79 | 80 | ! 1:9: identifier expected, but got "abc" 81 | #ifndef "abc" 82 | 83 | ! 1:1: stray #else 84 | #else 85 | 86 | ! 3:1: #else appears in #else 87 | #if 0 88 | #else 89 | #else 90 | #endif 91 | 92 | ! 1:1: stray #elif 93 | #elif 94 | 95 | ! 3:1: #elif after #else 96 | #if 1 97 | #else 98 | #elif 1 99 | #end 100 | 101 | ! 1:1: stray #endif 102 | #endif 103 | 104 | ! 1:1: #warning: foobar 105 | #warning foobar 106 | 107 | ! 1:1: #error: foobar 108 | #error foobar 109 | 110 | ! 1:1: expected filename, but got newline 111 | #include 112 | 113 | ! < expected, but got * 114 | #define x *foo* 115 | #include x 116 | 117 | ! 2:1: premature end of header name 118 | #define x 123 | 124 | ! 1:1: cannot find header file: /no-such-file\or-directory 125 | #include "/no-such-file\or-directory" 126 | 127 | ! 1:9: unknown #pragma: foo 128 | #pragma foo 129 | 130 | ! 1:7: number expected after #line, but got "abc" 131 | #line "abc" "def" 132 | 133 | ! 1:11: newline or a source name are expected, but got 456 134 | #line 123 456 135 | 136 | ! 1:3: line number expected, but got 123.4 137 | # 123.4 138 | 139 | ! 1:5: filename expected, but got 2 140 | # 1 2 141 | 142 | ! 1:1: unsupported preprocessor directive: foo 143 | #foo 144 | 145 | ! 1:9: _Pragma takes a string literal, but got 1 146 | _Pragma(1) 147 | """ 148 | 149 | encoding_tests = r""" 150 | ! 1:8: unsupported non-standard concatenation of string literals: L"bar" 151 | u"foo" L"bar"; 152 | 153 | ! invalid UTF-8 sequence 154 | void *p = U"\xff"; 155 | 156 | ! invalid UTF-8 continuation byte 157 | void *p = U"\xE3\x94"; 158 | 159 | ! invalid UCS character: \U10000000 160 | void *p = "\U10000000"; 161 | """ 162 | 163 | parser_tests = r""" 164 | ! lvalue expected, but got 1 165 | int f() { 1++; } 166 | 167 | ! lvalue expected, but got 1 168 | int f() { &1; } 169 | 170 | ! lvalue expected, but got 1 171 | int f() { 1 = 3; } 172 | 173 | ! integer type expected, but got 1.5 174 | int f() { 1.5 << 2; } 175 | 176 | ! integer type expected, but got 3.0 177 | int f() { 1 << 3.0; } 178 | 179 | ! integer type expected, but got 4.0 180 | int f() { switch (4.0); } 181 | 182 | ! void is not allowed 183 | struct { void i; } 184 | 185 | ! void is not allowed 186 | int f(void v); 187 | 188 | ! void is not allowed 189 | void x; 190 | 191 | ! '(' expected, but got long 192 | int x = _Alignof long; 193 | 194 | ! ',' expected, but got foo 195 | int x; 196 | int f() { _Static_assert(_Generic(x foo)) } 197 | 198 | ! type name expected, but got foo 199 | int x; 200 | int f() { _Static_assert(_Generic(x, foo)) } 201 | 202 | ! default expression specified twice 203 | int x; 204 | int f() { _Static_assert(_Generic(x, default: x, default: x)) } 205 | 206 | ! no matching generic selection 207 | int x; 208 | struct { _Static_assert(_Generic(x, float: x)) }; 209 | 210 | ! 1:9: invalid character 'x': 0x1x 211 | int x = 0x1x; 212 | 213 | ! 1:9: invalid character 'x': 0.2x 214 | int x = 0.2x; 215 | 216 | ! undefined variable: x 217 | int f() { return x; } 218 | 219 | ! function expected, but got 1 220 | int f() { 1(2); } 221 | 222 | ! pointer type expected, but got int 1 223 | int f() { 1->x; } 224 | 225 | ! 1:11: label name expected after &&, but got 1 226 | int f() { &&1; } 227 | 228 | ! 1:11: pointer type expected, but got 1 229 | int f() { *1; } 230 | 231 | ! 1:11: invalid use of ~: 3.0 232 | int f() { ~3.0; } 233 | 234 | ! expression expected 235 | int f() { switch(); } 236 | 237 | ! struct expected, but got 97 238 | int f() { 'a'.x; } 239 | 240 | ! pointer type expected, but got 241 | int f() { f->x; } 242 | 243 | ! struct has no such field: z 244 | struct { int x; } y; 245 | int f() { y.z; } 246 | 247 | ! non-integer type cannot be a bitfield: float 248 | struct { float x:3; }; 249 | 250 | ! invalid bitfield size for char: 9 251 | struct { char x:9; }; 252 | 253 | ! invalid bitfield size for int: 33 254 | struct { int x:33; }; 255 | 256 | ! zero-width bitfield needs to be unnamed: x 257 | struct { int x:0; }; 258 | 259 | ! missing ';' at the end of field list 260 | struct { int x }; 261 | 262 | ! flexible member may only appear as the last member 263 | struct { int x[]; int y; }; 264 | 265 | ! flexible member with no other fields 266 | struct { int x[]; }; 267 | 268 | ! declarations of T does not match 269 | struct T { int y; }; 270 | union T x; 271 | 272 | ! declarations of T does not match 273 | struct T { int y; }; 274 | enum T x; 275 | 276 | ! enum tag T is not defined 277 | enum T x; 278 | 279 | ! identifier expected, but got int 280 | enum { int }; 281 | 282 | ! ',' or '}' expected, but got y 283 | enum { x y }; 284 | 285 | ! excessive initializer: 4 286 | int x[3] = { 1, 2, 3, 4 }; 287 | 288 | ! malformed desginated initializer: 'a' 289 | struct { int x; } x = { .'a' = 3 }; 290 | 291 | ! field does not exist: y 292 | struct { int x; } x = { .y = 3 }; 293 | 294 | ! array designator exceeds array bounds: 4 295 | int x[3] = { [4] = 1; }; 296 | 297 | ! at least one parameter is required before "..." 298 | int f(...); 299 | 300 | ! comma expected, but got y 301 | int f(int x y); 302 | 303 | ! identifier expected, but got 1 304 | int f(x, 1) {} 305 | 306 | ! comma expected, but got 1 307 | int f(x 1) {} 308 | 309 | ! at least one parameter is required before "..." 310 | int f(...) {} 311 | 312 | ! array of functions 313 | int x[3](); 314 | 315 | ! function returning a function 316 | typedef T(void); 317 | T f(); 318 | 319 | ! function returning an array 320 | typedef T[3]; 321 | T f(); 322 | 323 | ! identifier is not expected, but got y 324 | int x = sizeof(int y); 325 | 326 | ! identifier, ( or * are expected, but got 1 327 | int 1; 328 | 329 | ! premature end of input 330 | int x = sizeof(int 331 | 332 | ! negative alignment: -1 333 | int _Alignas(-1) x; 334 | 335 | ! alignment must be power of 2, but got 3 336 | int _Alignas(3) x; 337 | 338 | ! type mismatch: double 339 | int double x; 340 | 341 | ! type mismatch: double 342 | struct { int x; } double y; 343 | 344 | ! type specifier missing, assuming int 345 | f(); 346 | 347 | ! invalid function definition 348 | int f(x, y) z {} 349 | 350 | ! missing parameter: z 351 | int f(x, y) int z; {} 352 | 353 | ! premature end of input 354 | int f( 355 | 356 | ! stray goto: x 357 | int f() { goto x; } 358 | 359 | ! stray unary &&: x 360 | int f() { &&x; } 361 | 362 | ! 'while' is expected, but got 1 363 | int f() { do; 1; } 364 | 365 | ! duplicate case value: 1 366 | int f() { switch(1) { case 1: case 1:; }; } 367 | 368 | ! duplicate case value: 3 ... 5 369 | int f() { switch(1) { case 1 ... 4: case 3 ... 5:; }; } 370 | 371 | ! case region is not in correct order: 5 ... 3 372 | int f() { switch(1) { case 5 ... 3:; }; } 373 | 374 | ! duplicate default 375 | int f() { switch(1) { default: default:; }; } 376 | 377 | ! stray break statement 378 | int f() { break; } 379 | 380 | ! stray continue statement 381 | int f() { continue; } 382 | 383 | ! pointer expected for computed goto, but got 1 384 | int f() { goto *1; } 385 | 386 | ! identifier expected, but got 1 387 | int f() { goto 1; } 388 | 389 | ! duplicate label: x 390 | int f() { x: x:; } 391 | 392 | ! stray character in program: '\' 393 | \ x 394 | """ 395 | 396 | def run(args): 397 | expect, code = args 398 | p = Popen(["./8cc", "-c", "-o", "/dev/null", "-"], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 399 | out, err = p.communicate(code) 400 | if out == None: 401 | return "expected error, but it didn't fail: %s" % expect 402 | if out.find(expect) == -1: 403 | return "expected: %s\ngot: %s" % (expect, out.rstrip("\n")) 404 | return None 405 | 406 | def parseTests(s): 407 | return map(lambda t: t.split("\n", 1), re.split("\n! ", s)[1:]) 408 | 409 | if __name__ == '__main__': 410 | # Run tests in parallel using process pool 411 | tests = lex_tests + cpp_tests + encoding_tests + parser_tests 412 | p = Pool(None) 413 | for res in p.imap_unordered(run, parseTests(tests)): 414 | if res != None: 415 | print res 416 | exit(1) 417 | exit(0) 418 | -------------------------------------------------------------------------------- /test/noreturn.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | 6 | // _Noreturn is ignored 7 | _Noreturn void f1(); 8 | noreturn void f2(); 9 | inline void f3() {} 10 | 11 | void testmain() { 12 | print("noreturn"); 13 | } 14 | -------------------------------------------------------------------------------- /test/number.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("numeric constants"); 7 | 8 | expect(1, 0x1); 9 | expect(1, 0X1); 10 | expect(17, 0x11); 11 | expect(17, 0X11); 12 | expect(511, 0777); 13 | expect(11, 0b1011); // GNU extension 14 | expect(11, 0B1011); // GNU extension 15 | 16 | expect(3, 3L); 17 | expect(3, 3LL); 18 | expect(3, 3UL); 19 | expect(3, 3LU); 20 | expect(3, 3ULL); 21 | expect(3, 3LU); 22 | expect(3, 3LLU); 23 | 24 | expectd(55.3, 55.3); 25 | expectd(200, 2e2); 26 | expectd(0x0.DE488631p8, 0xDE.488631p0); 27 | 28 | expect(4, sizeof(5)); 29 | expect(8, sizeof(5L)); 30 | expect(4, sizeof(3.0f)); 31 | expect(8, sizeof(3.0)); 32 | expect(4, sizeof(0xe0)); 33 | } 34 | -------------------------------------------------------------------------------- /test/oldstyle.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | #ifdef __8cc__ 6 | #pragma disable_warning 7 | #endif 8 | 9 | // Defined in main/testmain.c 10 | int oldstyle1(); 11 | 12 | oldstyle2() { 13 | return 4; 14 | } 15 | 16 | oldstyle3(a) { 17 | return a; 18 | } 19 | 20 | oldstyle4(a, b) 21 | double b; 22 | { 23 | return a + b; 24 | } 25 | 26 | void testmain() { 27 | print("K&R"); 28 | expect(3, no_declaration()); 29 | expect(7, oldstyle1(3, 4)); 30 | expect(4, oldstyle2()); 31 | expect(5, oldstyle3(5)); 32 | expect(9, oldstyle4(5, 4.0)); 33 | } 34 | 35 | int no_declaration() { 36 | return 3; 37 | } 38 | -------------------------------------------------------------------------------- /test/once.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #ifdef ONCE_H 4 | #error "#pragma once bug" 5 | #endif 6 | 7 | #pragma once 8 | #define ONCE_H 1 9 | -------------------------------------------------------------------------------- /test/pointer.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void t1() { 6 | int a = 61; 7 | int *b = &a; 8 | expect(61, *b); 9 | } 10 | 11 | static void t2() { 12 | char *c = "ab"; 13 | expect(97, *c); 14 | } 15 | 16 | static void t3() { 17 | char *c = "ab" + 1; 18 | expect(98, *c); 19 | } 20 | 21 | static void t4() { 22 | char s[] = "xyz"; 23 | char *c = s + 2; 24 | expect(122, *c); 25 | } 26 | 27 | static void t5() { 28 | char s[] = "xyz"; 29 | *s = 65; 30 | expect(65, *s); 31 | } 32 | 33 | static void t6() { 34 | struct tag { 35 | int val; 36 | struct tag *next; 37 | }; 38 | struct tag node1 = { 1, NULL }; 39 | struct tag node2 = { 2, &node1 }; 40 | struct tag node3 = { 3, &node2 }; 41 | struct tag *p = &node3; 42 | expect(3, p->val); 43 | expect(2, p->next->val); 44 | expect(1, p->next->next->val); 45 | p->next = p->next->next; 46 | expect(1, p->next->val); 47 | } 48 | 49 | static void t7() { 50 | int a; 51 | int *p1 = &a + 1; 52 | int *p2 = 1 + &a; 53 | expect(0, p1 - p2); 54 | } 55 | 56 | static void subtract() { 57 | char *p = "abcdefg"; 58 | char *q = p + 5; 59 | expect(8, sizeof(q - p)); 60 | expect(5, q - p); 61 | } 62 | 63 | static void compare() { 64 | char *p = "abcdefg"; 65 | expect(0, p == p + 1); 66 | expect(1, p == p); 67 | expect(0, p != p); 68 | expect(1, p != p + 1); 69 | expect(0, p < p); 70 | expect(1, p < p + 1); 71 | expect(0, p > p); 72 | expect(1, p + 1 > p); 73 | expect(1, p >= p); 74 | expect(1, p + 1 >= p); 75 | expect(0, p >= p + 1); 76 | expect(1, p <= p); 77 | expect(1, p <= p + 1); 78 | expect(0, p + 1 <= p); 79 | expect(4, sizeof(p == p + 1)); 80 | expect(4, sizeof(p != p + 1)); 81 | expect(4, sizeof(p < p + 1)); 82 | expect(4, sizeof(p > p + 1)); 83 | expect(4, sizeof(p <= p + 1)); 84 | expect(4, sizeof(p >= p + 1)); 85 | } 86 | 87 | void testmain() { 88 | print("pointer"); 89 | t1(); 90 | t2(); 91 | t3(); 92 | t4(); 93 | t5(); 94 | t6(); 95 | t7(); 96 | subtract(); 97 | compare(); 98 | } 99 | -------------------------------------------------------------------------------- /test/scope.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("scope"); 7 | 8 | int a = 31; 9 | { int a = 64; } 10 | expect(31, a); 11 | { 12 | int a = 64; 13 | expect(64, a); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/sizeof.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | 6 | static void test_primitives() { 7 | expect(1, sizeof(void)); 8 | expect(1, sizeof(test_primitives)); 9 | expect(1, sizeof(char)); 10 | expect(1, sizeof(_Bool)); 11 | expect(1, sizeof(bool)); 12 | expect(2, sizeof(short)); 13 | expect(4, sizeof(int)); 14 | expect(8, sizeof(long)); 15 | } 16 | 17 | static void test_pointers() { 18 | expect(8, sizeof(char *)); 19 | expect(8, sizeof(short *)); 20 | expect(8, sizeof(int *)); 21 | expect(8, sizeof(long *)); 22 | } 23 | 24 | static void test_unsigned() { 25 | expect(1, sizeof(unsigned char)); 26 | expect(2, sizeof(unsigned short)); 27 | expect(4, sizeof(unsigned int)); 28 | expect(8, sizeof(unsigned long)); 29 | } 30 | 31 | static void test_literals() { 32 | expect(4, sizeof 1); 33 | expect(4, sizeof('a')); 34 | expect(4, sizeof(1.0f)); 35 | expect(8, sizeof 1L); 36 | expect(8, sizeof 1.0); 37 | expect(8, sizeof(1.0)); 38 | } 39 | 40 | static void test_arrays() { 41 | expect(1, sizeof(char[1])); 42 | expect(7, sizeof(char[7])); 43 | expect(30, sizeof(char[3][10])); 44 | expect(32, sizeof(int[4][2])); 45 | } 46 | 47 | static void test_vars() { 48 | char a[] = { 1, 2, 3 }; 49 | expect(3, sizeof(a)); 50 | char b[] = "abc"; 51 | expect(4, sizeof(b)); 52 | expect(1, sizeof(b[0])); 53 | expect(1, sizeof((b[0]))); 54 | expect(1, sizeof((b)[0])); 55 | char *c[5]; 56 | expect(40, sizeof(c)); 57 | char *(*d)[3]; 58 | expect(8, sizeof(d)); 59 | expect(24, sizeof(*d)); 60 | expect(8, sizeof(**d)); 61 | expect(1, sizeof(***d)); 62 | expect(4, sizeof((int)a)); 63 | } 64 | 65 | static void test_struct() { 66 | expect(1, sizeof(struct { char a; })); 67 | expect(3, sizeof(struct { char a[3]; })); 68 | expect(5, sizeof(struct { char a[5]; })); 69 | expect(8, sizeof(struct { int a; char b; })); 70 | expect(12, sizeof(struct { char a; int b; char c; })); 71 | expect(24, sizeof(struct { char a; double b; char c; })); 72 | expect(24, sizeof(struct { struct { char a; double b; } x; char c; })); 73 | } 74 | 75 | static void test_constexpr() { 76 | char a[sizeof(char[4])]; 77 | expect(4, sizeof(a)); 78 | } 79 | 80 | void testmain() { 81 | print("sizeof"); 82 | test_primitives(); 83 | test_pointers(); 84 | test_unsigned(); 85 | test_literals(); 86 | test_arrays(); 87 | test_vars(); 88 | test_struct(); 89 | test_constexpr(); 90 | } 91 | -------------------------------------------------------------------------------- /test/staticassert.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("static assert"); 7 | _Static_assert(1, "fail"); 8 | 9 | struct { 10 | _Static_assert(1, "fail"); 11 | } x; 12 | } 13 | -------------------------------------------------------------------------------- /test/stmtexpr.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | void testmain() { 6 | print("statement expression"); 7 | 8 | expect(3, ({ 1; 2; 3; })); 9 | expectf(3.0, ({ 1; 2; 3.0; })); 10 | expect(5, ({ int a = 5; a; })); 11 | } 12 | -------------------------------------------------------------------------------- /test/struct.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "test.h" 5 | 6 | static void t1() { 7 | struct { int a; } x; 8 | x.a = 61; 9 | expect(61, x.a); 10 | } 11 | 12 | static void t2() { 13 | struct { int a; int b; } x; 14 | x.a = 61; 15 | x.b = 2; 16 | expect(63, x.a + x.b); 17 | } 18 | 19 | static void t3() { 20 | struct { int a; struct { char b; int c; } y; } x; 21 | x.a = 61; 22 | x.y.b = 3; 23 | x.y.c = 3; 24 | expect(67, x.a + x.y.b + x.y.c); 25 | } 26 | 27 | static void t4() { 28 | struct tag4 { int a; struct { char b; int c; } y; } x; 29 | struct tag4 s; 30 | s.a = 61; 31 | s.y.b = 3; 32 | s.y.c = 3; 33 | expect(67, s.a + s.y.b + s.y.c); 34 | } 35 | 36 | static void t5() { 37 | struct tag5 { int a; } x; 38 | struct tag5 *p = &x; 39 | x.a = 68; 40 | expect(68, (*p).a); 41 | } 42 | 43 | static void t6() { 44 | struct tag6 { int a; } x; 45 | struct tag6 *p = &x; 46 | (*p).a = 69; 47 | expect(69, x.a); 48 | } 49 | 50 | static void t7() { 51 | struct tag7 { int a; int b; } x; 52 | struct tag7 *p = &x; 53 | x.b = 71; 54 | expect(71, (*p).b); 55 | } 56 | 57 | static void t8() { 58 | struct tag8 { int a; int b; } x; 59 | struct tag8 *p = &x; 60 | (*p).b = 72; 61 | expect(72, x.b); 62 | } 63 | 64 | static void t9() { 65 | struct tag9 { int a[3]; int b[3]; } x; 66 | x.a[0] = 73; 67 | expect(73, x.a[0]); 68 | x.b[1] = 74; 69 | expect(74, x.b[1]); 70 | expect(74, x.a[4]); 71 | } 72 | 73 | struct tag10 { 74 | int a; 75 | struct tag10a { 76 | char b; 77 | int c; 78 | } y; 79 | } v10; 80 | static void t10() { 81 | v10.a = 71; 82 | v10.y.b = 3; 83 | v10.y.c = 3; 84 | expect(77, v10.a + v10.y.b + v10.y.c); 85 | } 86 | 87 | struct tag11 { int a; } v11; 88 | static void t11() { 89 | struct tag11 *p = &v11; 90 | v11.a = 78; 91 | expect(78, (*p).a); 92 | expect(78, v11.a); 93 | expect(78, p->a); 94 | p->a = 79; 95 | expect(79, (*p).a); 96 | expect(79, v11.a); 97 | expect(79, p->a); 98 | } 99 | 100 | struct tag12 { 101 | int a; 102 | int b; 103 | } x; 104 | static void t12() { 105 | struct tag12 a[3]; 106 | a[0].a = 83; 107 | expect(83, a[0].a); 108 | a[0].b = 84; 109 | expect(84, a[0].b); 110 | a[1].b = 85; 111 | expect(85, a[1].b); 112 | int *p = (int *)a; 113 | expect(85, p[3]); 114 | } 115 | 116 | static void t13() { 117 | struct { char c; } v = { 'a' }; 118 | expect('a', v.c); 119 | } 120 | 121 | static void t14() { 122 | struct { int a[3]; } v = { { 1, 2, 3 } }; 123 | expect(2, v.a[1]); 124 | } 125 | 126 | static void unnamed() { 127 | struct { 128 | union { 129 | struct { int x; int y; }; 130 | struct { char c[8]; }; 131 | }; 132 | } v; 133 | v.x = 1; 134 | v.y = 7; 135 | expect(1, v.c[0]); 136 | expect(7, v.c[4]); 137 | } 138 | 139 | static void assign() { 140 | struct { int a, b, c; short d; char f; } v1, v2; 141 | v1.a = 3; 142 | v1.b = 5; 143 | v1.c = 7; 144 | v1.d = 9; 145 | v1.f = 11; 146 | v2 = v1; 147 | expect(3, v2.a); 148 | expect(5, v2.b); 149 | expect(7, v2.c); 150 | expect(9, v2.d); 151 | expect(11, v2.f); 152 | } 153 | 154 | static void arrow() { 155 | struct cell { int val; struct cell *next; }; 156 | struct cell v1 = { 5, NULL }; 157 | struct cell v2 = { 6, &v1 }; 158 | struct cell v3 = { 7, &v2 }; 159 | struct cell *p = &v3; 160 | expect(7, v3.val); 161 | expect(7, p->val); 162 | expect(6, p->next->val); 163 | expect(5, p->next->next->val); 164 | 165 | p->val = 10; 166 | p->next->val = 11; 167 | p->next->next->val = 12; 168 | expect(10, p->val); 169 | expect(11, p->next->val); 170 | expect(12, p->next->next->val); 171 | } 172 | 173 | static void address() { 174 | struct tag { int a; struct { int b; } y; } x = { 6, 7 }; 175 | int *p1 = &x.a; 176 | int *p2 = &x.y.b; 177 | expect(6, *p1); 178 | expect(7, *p2); 179 | expect(6, *&x.a); 180 | expect(7, *&x.y.b); 181 | 182 | struct tag *xp = &x; 183 | int *p3 = &xp->a; 184 | int *p4 = &xp->y.b; 185 | expect(6, *p3); 186 | expect(7, *p4); 187 | expect(6, *&xp->a); 188 | expect(7, *&xp->y.b); 189 | } 190 | 191 | static void incomplete() { 192 | struct tag1; 193 | struct tag2 { struct tag1 *p; }; 194 | struct tag1 { int x; }; 195 | 196 | struct tag1 v1 = { 3 }; 197 | struct tag2 v2 = { &v1 }; 198 | expect(3, v2.p->x); 199 | } 200 | 201 | static void bitfield_basic() { 202 | union { 203 | int i; 204 | struct { int a:5; int b:5; }; 205 | } x; 206 | x.i = 0; 207 | x.a = 10; 208 | x.b = 11; 209 | expect(10, x.a); 210 | expect(11, x.b); 211 | expect(362, x.i); // 11 << 5 + 10 == 362 212 | } 213 | 214 | static void bitfield_mix() { 215 | union { 216 | int i; 217 | struct { char a:5; int b:5; }; 218 | } x; 219 | x.a = 10; 220 | x.b = 11; 221 | expect(10, x.a); 222 | expect(11, x.b); 223 | expect(362, x.i); 224 | } 225 | 226 | static void bitfield_union() { 227 | union { int a : 10; char b: 5; char c: 5; } x; 228 | x.a = 2; 229 | expect(2, x.a); 230 | expect(2, x.b); 231 | expect(2, x.c); 232 | } 233 | 234 | static void bitfield_unnamed() { 235 | union { 236 | int i; 237 | struct { char a:4; char b:4; char : 8; }; 238 | } x = { 0 }; 239 | x.i = 0; 240 | x.a = 2; 241 | x.b = 4; 242 | expect(2, x.a); 243 | expect(4, x.b); 244 | expect(66, x.i); 245 | 246 | union { 247 | int i; 248 | struct { char a:4; char :0; char b:4; }; 249 | } y = { 0 }; 250 | y.a = 2; 251 | y.b = 4; 252 | expect(2, y.a); 253 | expect(4, y.b); 254 | expect(1026, y.i); 255 | } 256 | 257 | struct { char a:4; char b:4; } inittest = { 2, 4 }; 258 | 259 | static void bitfield_initializer() { 260 | expect(2, inittest.a); 261 | expect(4, inittest.b); 262 | 263 | struct { char a:4; char b:4; } x = { 2, 4 }; 264 | expect(2, x.a); 265 | expect(4, x.b); 266 | } 267 | 268 | static void test_offsetof() { 269 | struct tag10 { int a, b; }; 270 | expect(0, offsetof(struct tag10, a)); 271 | expect(4, offsetof(struct tag10, b)); 272 | int x[offsetof(struct tag10, b)]; 273 | expect(4, sizeof(x) / sizeof(x[0])); 274 | 275 | expect(4, offsetof(struct { char a; struct { int b; }; }, b)); 276 | expect(6, offsetof(struct { char a[3]; int : 10; char c; }, c)); 277 | expect(6, offsetof(struct { char a[3]; int : 16; char c; }, c)); 278 | expect(7, offsetof(struct { char a[3]; int : 17; char c; }, c)); 279 | expect(2, offsetof(struct { char : 7; int : 7; char a; }, a)); 280 | expect(0, offsetof(struct { char : 0; char a; }, a)); 281 | 282 | expect(1, _Alignof(struct { int : 32; })); 283 | expect(2, _Alignof(struct { int : 32; short x; })); 284 | expect(4, _Alignof(struct { int x; int : 32; })); 285 | } 286 | 287 | static void flexible_member() { 288 | struct { int a, b[]; } x; 289 | expect(4, sizeof(x)); 290 | struct { int a, b[0]; } y; 291 | expect(4, sizeof(y)); 292 | struct { int a[0]; } z; 293 | expect(0, sizeof(z)); 294 | 295 | #ifdef __8cc__ // BUG 296 | struct t { int a, b[]; }; 297 | struct t x2 = { 1, 2, 3 }; 298 | struct t x3 = { 1, 2, 3, 4, 5 }; 299 | expect(2, x3.b[0]); 300 | expect(3, x3.b[1]); 301 | expect(4, x3.b[2]); 302 | expect(5, x3.b[3]); 303 | #endif 304 | } 305 | 306 | static void empty_struct() { 307 | struct tag15 {}; 308 | expect(0, sizeof(struct tag15)); 309 | union tag16 {}; 310 | expect(0, sizeof(union tag16)); 311 | } 312 | 313 | static void incdec_struct() { 314 | struct incdec { 315 | int x, y; 316 | } a[] = { { 1, 2 }, { 3, 4 } }, *p = a; 317 | expect(1, p->x); 318 | expect(2, p->y); 319 | p++; 320 | expect(3, p->x); 321 | expect(4, p->y); 322 | p--; 323 | expect(1, p->x); 324 | expect(2, p->y); 325 | ++p; 326 | expect(3, p->x); 327 | expect(4, p->y); 328 | --p; 329 | expect(1, p->x); 330 | expect(2, p->y); 331 | } 332 | 333 | void testmain() { 334 | print("struct"); 335 | t1(); 336 | t2(); 337 | t3(); 338 | t4(); 339 | t5(); 340 | t6(); 341 | t7(); 342 | t8(); 343 | t9(); 344 | t10(); 345 | t11(); 346 | t12(); 347 | t13(); 348 | t14(); 349 | unnamed(); 350 | assign(); 351 | arrow(); 352 | incomplete(); 353 | bitfield_basic(); 354 | bitfield_mix(); 355 | bitfield_union(); 356 | bitfield_unnamed(); 357 | bitfield_initializer(); 358 | test_offsetof(); 359 | flexible_member(); 360 | empty_struct(); 361 | } 362 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "stdio.h" 4 | 5 | void exit(int); 6 | size_t strlen(const char *); 7 | 8 | extern int externvar1; 9 | extern int externvar2; 10 | 11 | extern void print(char *s); 12 | extern void ffail(char *file, int line, char *msg); 13 | extern void fexpect(char *file, int line, int a, int b); 14 | extern void fexpect_string(char *file, int line, char *a, char *b); 15 | extern void fexpectf(char *file, int line, float a, float b); 16 | extern void fexpectd(char *file, int line, double a, double b); 17 | extern void fexpectl(char *file, int line, long a, long b); 18 | 19 | #define fail(msg) ffail(__FILE__, __LINE__, msg) 20 | #define expect(a, b) fexpect(__FILE__, __LINE__, a, b); 21 | #define expect_string(a, b) fexpect_string(__FILE__, __LINE__, a, b); 22 | #define expectf(a, b) fexpectf(__FILE__, __LINE__, a, b); 23 | #define expectd(a, b) fexpectd(__FILE__, __LINE__, a, b); 24 | #define expectl(a, b) fexpectl(__FILE__, __LINE__, a, b); 25 | -------------------------------------------------------------------------------- /test/testmain.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void testmain(void); 10 | 11 | // For test/extern.c 12 | int externvar1 = 98; 13 | int externvar2 = 99; 14 | 15 | // For test/function.c 16 | int booltest1(bool x) { 17 | return x; 18 | } 19 | 20 | int oldstyle1(int x, int y) { 21 | return x + y; 22 | } 23 | 24 | void print(char *s) { 25 | printf("Testing %s ... ", s); 26 | fflush(stdout); 27 | } 28 | 29 | void printfail() { 30 | printf(isatty(fileno(stdout)) ? "\e[1;31mFailed\e[0m\n" : "Failed\n"); 31 | } 32 | 33 | void ffail(char *file, int line, char *msg) { 34 | printfail(); 35 | printf("%s:%d: %s\n", file, line, msg); 36 | exit(1); 37 | } 38 | 39 | void fexpect(char *file, int line, int a, int b) { 40 | if (a == b) 41 | return; 42 | printfail(); 43 | printf("%s:%d: %d expected, but got %d\n", file, line, a, b); 44 | exit(1); 45 | } 46 | 47 | void fexpect_string(char *file, int line, char *a, char *b) { 48 | if (!strcmp(a, b)) 49 | return; 50 | printfail(); 51 | printf("%s:%d: \"%s\" expected, but got \"%s\"\n", file, line, a, b); 52 | exit(1); 53 | } 54 | 55 | void fexpectf(char *file, int line, float a, float b) { 56 | if (a == b) 57 | return; 58 | printfail(); 59 | printf("%s:%d: %f expected, but got %f\n", file, line, a, b); 60 | exit(1); 61 | } 62 | 63 | void fexpectd(char *file, int line, double a, double b) { 64 | if (a == b) 65 | return; 66 | printfail(); 67 | printf("%s:%d: %lf expected, but got %lf\n", file, line, a, b); 68 | exit(1); 69 | } 70 | 71 | void fexpectl(char *file, int line, long a, long b) { 72 | if (a == b) 73 | return; 74 | printfail(); 75 | printf("%s:%d: %ld expected, but got %ld\n", file, line, a, b); 76 | exit(1); 77 | } 78 | 79 | int main() { 80 | testmain(); 81 | printf(isatty(fileno(stdout)) ? "\e[32mOK\e[0m\n" : "OK\n"); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /test/type.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | static void test_type() { 8 | char a; 9 | short b; 10 | int c; 11 | long d; 12 | long long e; 13 | short int f; 14 | long int g; 15 | long long int h; 16 | long int long i; 17 | float j; 18 | double k; 19 | long double l; 20 | _Bool m; 21 | bool n; 22 | } 23 | 24 | static void test_signed() { 25 | signed char a; 26 | signed short b; 27 | signed int c; 28 | signed long d; 29 | signed long long e; 30 | signed short int f; 31 | signed long int g; 32 | signed long long int h; 33 | } 34 | 35 | static void test_unsigned() { 36 | unsigned char a; 37 | unsigned short b; 38 | unsigned int c; 39 | unsigned long d; 40 | unsigned long long e; 41 | unsigned short int f; 42 | unsigned long int g; 43 | unsigned long long int h; 44 | } 45 | 46 | static void test_storage_class() { 47 | static a; 48 | auto b; 49 | register c; 50 | static int d; 51 | auto int e; 52 | register int f; 53 | } 54 | 55 | static void test_pointer() { 56 | int *a; 57 | expect(8, sizeof(a)); 58 | int *b[5]; 59 | expect(40, sizeof(b)); 60 | int (*c)[5]; 61 | expect(8, sizeof(c)); 62 | } 63 | 64 | static void test_unusual_order() { 65 | int unsigned auto * const * const a; 66 | } 67 | 68 | static void test_typedef() { 69 | typedef int integer; 70 | integer a = 5; 71 | expect(5, a); 72 | 73 | typedef int array[3]; 74 | array b = { 1, 2, 3 }; 75 | expect(2, b[1]); 76 | 77 | typedef struct tag { int x; } strtype; 78 | strtype c; 79 | c.x = 5; 80 | expect(5, c.x); 81 | 82 | typedef char x; 83 | { 84 | int x = 3; 85 | expect(3, x); 86 | } 87 | { 88 | int a = sizeof(x), x = 5, c = sizeof(x); 89 | expect(1, a); 90 | expect(5, x); 91 | expect(4, c); 92 | } 93 | } 94 | 95 | static void test_align() { 96 | #ifdef __8cc__ 97 | expect(8, sizeof(max_align_t)); 98 | #endif 99 | } 100 | 101 | void testmain() { 102 | print("type system"); 103 | test_type(); 104 | test_signed(); 105 | test_unsigned(); 106 | test_storage_class(); 107 | test_pointer(); 108 | test_unusual_order(); 109 | test_typedef(); 110 | test_align(); 111 | } 112 | -------------------------------------------------------------------------------- /test/typeof.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void test_basic() { 6 | typeof(int) a = 5; 7 | expect(5, a); 8 | typeof(a) b = 6; 9 | expect(6, b); 10 | } 11 | 12 | static void test_array() { 13 | char a[] = "abc"; 14 | typeof(a) b = "de"; 15 | expect_string("de", b); 16 | expect(4, sizeof(b)); 17 | 18 | typeof(typeof (char *)[4]) y; 19 | expect(4, sizeof(y) / sizeof(*y)); 20 | 21 | typedef typeof(a[0]) CHAR; 22 | CHAR z = 'z'; 23 | expect('z', z); 24 | } 25 | 26 | static void test_alt() { 27 | __typeof__(int) a = 10; 28 | expect(10, a); 29 | } 30 | 31 | void testmain() { 32 | print("typeof"); 33 | test_basic(); 34 | test_array(); 35 | test_alt(); 36 | } 37 | -------------------------------------------------------------------------------- /test/union.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | 5 | static void t1() { 6 | union { int a; int b; } x; 7 | x.a = 90; 8 | expect(90, x.b); 9 | } 10 | 11 | static void t2() { 12 | union { char a[4]; int b; } x; 13 | x.b = 0; 14 | x.a[1] = 1; 15 | expect(256, x.b); 16 | } 17 | 18 | static void t3() { 19 | union { char a[4]; int b; } x; 20 | x.a[0] = x.a[1] = x.a[2] = x.a[3] = 0; 21 | x.a[1]=1; 22 | expect(256, x.b); 23 | } 24 | 25 | static test_sizeof() { 26 | expect(4, sizeof(union { char a; int b; })); 27 | expect(8, sizeof(union { double a; int b; })); 28 | expect(8, sizeof(union { _Alignas(8) char a; int b; })); 29 | } 30 | 31 | void testmain() { 32 | print("union"); 33 | t1(); 34 | t2(); 35 | t3(); 36 | test_sizeof(); 37 | } 38 | -------------------------------------------------------------------------------- /test/usualconv.c: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Rui Ueyama. Released under the MIT license. 2 | 3 | #include "test.h" 4 | #include 5 | 6 | static void test_usual_conv() { 7 | expect(1, sizeof(bool)); 8 | expect(1, sizeof((char)0)); 9 | 10 | expect(4, sizeof((bool)0 + (bool)0)); 11 | expect(4, sizeof((char)0 + (char)0)); 12 | expect(4, sizeof((char)0 + (bool)0)); 13 | expect(4, sizeof((char)0 + (int)0)); 14 | expect(8, sizeof((char)0 + (long)0)); 15 | expect(8, sizeof((char)0 + (double)0)); 16 | } 17 | 18 | void testmain() { 19 | print("usual conversion"); 20 | test_usual_conv(); 21 | } 22 | -------------------------------------------------------------------------------- /test/varargs.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "test.h" 5 | 6 | static void test_builtin() { 7 | #ifdef __8cc__ 8 | expect(0, __builtin_reg_class((int *)0)); 9 | expect(1, __builtin_reg_class((float *)0)); 10 | expect(2, __builtin_reg_class((struct{ int x; }*)0)); 11 | #endif 12 | } 13 | 14 | static void test_int(int a, ...) { 15 | va_list ap; 16 | va_start(ap, a); 17 | expect(1, a); 18 | expect(2, va_arg(ap, int)); 19 | expect(3, va_arg(ap, int)); 20 | expect(5, va_arg(ap, int)); 21 | expect(8, va_arg(ap, int)); 22 | va_end(ap); 23 | } 24 | 25 | static void test_float(float a, ...) { 26 | va_list ap; 27 | va_start(ap, a); 28 | expectf(1.0, a); 29 | expectd(2.0, va_arg(ap, double)); 30 | expectd(4.0, va_arg(ap, double)); 31 | expectd(8.0, va_arg(ap, double)); 32 | va_end(ap); 33 | } 34 | 35 | static void test_mix(char *p, ...) { 36 | va_list ap; 37 | va_start(ap, p); 38 | expect_string("abc", p); 39 | expectd(2.0, va_arg(ap, double)); 40 | expect(4, va_arg(ap, int)); 41 | expect_string("d", va_arg(ap, char *)); 42 | expect(5, va_arg(ap, int)); 43 | va_end(ap); 44 | } 45 | 46 | char *fmt(char *fmt, ...) { 47 | static char buf[100]; 48 | va_list ap; 49 | va_start(ap, fmt); 50 | vsprintf(buf, fmt, ap); 51 | va_end(ap); 52 | return buf; 53 | } 54 | 55 | static void test_va_list() { 56 | expect_string("", fmt("")); 57 | expect_string("3", fmt("%d", 3)); 58 | expect_string("3,1.0,6,2.0,abc", fmt("%d,%.1f,%d,%.1f,%s", 3, 1.0, 6, 2.0, "abc")); 59 | } 60 | 61 | void testmain() { 62 | print("varargs"); 63 | test_builtin(); 64 | test_int(1, 2, 3, 5, 8); 65 | test_float(1.0, 2.0, 4.0, 8.0); 66 | test_mix("abc", 2.0, 4, "d", 5); 67 | test_va_list(); 68 | } 69 | -------------------------------------------------------------------------------- /utiltest.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | #include 4 | #include "8cc.h" 5 | 6 | char *get_base_file(void) { return NULL; } 7 | 8 | #define assert_true(expr) assert_true2(__LINE__, #expr, (expr)) 9 | #define assert_null(...) assert_null2(__LINE__, __VA_ARGS__) 10 | #define assert_string(...) assert_string2(__LINE__, __VA_ARGS__) 11 | #define assert_int(...) assert_int2(__LINE__, __VA_ARGS__) 12 | 13 | static void assert_true2(int line, char *expr, int result) { 14 | if (!result) 15 | error("%d: assert_true: %s", line, expr); 16 | } 17 | 18 | static void assert_null2(int line, void *p) { 19 | if (p) 20 | error("%d: Null expected", line); 21 | } 22 | 23 | static void assert_string2(int line, char *s, char *t) { 24 | if (strcmp(s, t)) 25 | error("%d: Expected \"%s\" but got \"%s\"", line, s, t); 26 | } 27 | 28 | static void assert_int2(int line, long a, long b) { 29 | if (a != b) 30 | error("%d: Expected %ld but got %ld", line, a, b); 31 | } 32 | 33 | static void test_buf() { 34 | Buffer *b = make_buffer(); 35 | buf_write(b, 'a'); 36 | buf_write(b, 'b'); 37 | buf_write(b, '\0'); 38 | assert_string("ab", buf_body(b)); 39 | 40 | Buffer *b2 = make_buffer(); 41 | buf_write(b2, '.'); 42 | buf_printf(b2, "%s", "0123456789"); 43 | assert_string(".0123456789", buf_body(b2)); 44 | } 45 | 46 | static void test_list() { 47 | Vector *list = make_vector(); 48 | assert_int(0, vec_len(list)); 49 | vec_push(list, (void *)1); 50 | assert_int(1, vec_len(list)); 51 | vec_push(list, (void *)2); 52 | assert_int(2, vec_len(list)); 53 | 54 | Vector *copy = vec_copy(list); 55 | assert_int(2, vec_len(copy)); 56 | assert_int(1, (long)vec_get(copy, 0)); 57 | assert_int(2, (long)vec_get(copy, 1)); 58 | 59 | Vector *rev = vec_reverse(list); 60 | assert_int(2, vec_len(rev)); 61 | assert_int(1, (long)vec_pop(rev)); 62 | assert_int(1, vec_len(rev)); 63 | assert_int(2, (long)vec_pop(rev)); 64 | assert_int(0, vec_len(rev)); 65 | 66 | Vector *list3 = make_vector(); 67 | vec_push(list3, (void *)1); 68 | assert_int(1, (long)vec_head(list3)); 69 | assert_int(1, (long)vec_tail(list3)); 70 | vec_push(list3, (void *)2); 71 | assert_int(1, (long)vec_head(list3)); 72 | assert_int(2, (long)vec_tail(list3)); 73 | 74 | Vector *list4 = make_vector(); 75 | vec_push(list4, (void *)1); 76 | vec_push(list4, (void *)2); 77 | assert_int(1, (long)vec_get(list4, 0)); 78 | assert_int(2, (long)vec_get(list4, 1)); 79 | } 80 | 81 | static void test_map() { 82 | Map *m = make_map(); 83 | assert_null(map_get(m, "abc")); 84 | 85 | // Insert 10000 values 86 | for (int i = 0; i < 10000; i++) { 87 | char *k = format("%d", i); 88 | map_put(m, k, (void *)(intptr_t)i); 89 | assert_int(i, (int)(intptr_t)map_get(m, k)); 90 | } 91 | 92 | // Insert again 93 | for (int i = 0; i < 1000; i++) { 94 | char *k = format("%d", i); 95 | map_put(m, k, (void *)(intptr_t)i); 96 | assert_int(i, (int)(intptr_t)map_get(m, k)); 97 | } 98 | 99 | // Remove them 100 | for (int i = 0; i < 10000; i++) { 101 | char *k = format("%d", i); 102 | assert_int(i, (intptr_t)map_get(m, k)); 103 | map_remove(m, k); 104 | assert_null(map_get(m, k)); 105 | } 106 | } 107 | 108 | static void test_map_stack() { 109 | Map *m1 = make_map(); 110 | map_put(m1, "x", (void *)1); 111 | map_put(m1, "y", (void *)2); 112 | assert_int(1, (int)(intptr_t)map_get(m1, "x")); 113 | 114 | Map *m2 = make_map_parent(m1); 115 | assert_int(1, (int)(intptr_t)map_get(m2, "x")); 116 | map_put(m2, "x", (void *)3); 117 | assert_int(3, (int)(intptr_t)map_get(m2, "x")); 118 | assert_int(1, (int)(intptr_t)map_get(m1, "x")); 119 | } 120 | 121 | static void test_dict() { 122 | Dict *dict = make_dict(); 123 | assert_null(dict_get(dict, "abc")); 124 | dict_put(dict, "abc", (void *)50); 125 | dict_put(dict, "xyz", (void *)70); 126 | assert_int(50, (long)dict_get(dict, "abc")); 127 | assert_int(70, (long)dict_get(dict, "xyz")); 128 | assert_int(2, vec_len(dict_keys(dict))); 129 | } 130 | 131 | static void test_set() { 132 | Set *s = NULL; 133 | assert_int(0, set_has(s, "abc")); 134 | s = set_add(s, "abc"); 135 | s = set_add(s, "def"); 136 | assert_int(1, set_has(s, "abc")); 137 | assert_int(1, set_has(s, "def")); 138 | assert_int(0, set_has(s, "xyz")); 139 | Set *t = NULL; 140 | t = set_add(t, "abc"); 141 | t = set_add(t, "DEF"); 142 | assert_int(1, set_has(set_union(s, t), "abc")); 143 | assert_int(1, set_has(set_union(s, t), "def")); 144 | assert_int(1, set_has(set_union(s, t), "DEF")); 145 | assert_int(1, set_has(set_intersection(s, t), "abc")); 146 | assert_int(0, set_has(set_intersection(s, t), "def")); 147 | assert_int(0, set_has(set_intersection(s, t), "DEF")); 148 | } 149 | 150 | static void test_path() { 151 | assert_string("/abc", fullpath("/abc")); 152 | assert_string("/abc/def", fullpath("/abc/def")); 153 | assert_string("/abc/def", fullpath("/abc///def")); 154 | assert_string("/abc/def", fullpath("//abc///def")); 155 | assert_string("/abc/xyz", fullpath("/abc/def/../xyz")); 156 | assert_string("/xyz", fullpath("/abc/def/../../../xyz")); 157 | assert_string("/xyz", fullpath("/abc/def/../../../../xyz")); 158 | } 159 | 160 | static void test_file() { 161 | stream_push(make_file_string("abc")); 162 | assert_int('a', readc()); 163 | assert_int('b', readc()); 164 | unreadc('b'); 165 | unreadc('a'); 166 | assert_int('a', readc()); 167 | assert_int('b', readc()); 168 | assert_int('c', readc()); 169 | assert_int('\n', readc()); 170 | unreadc('\n'); 171 | assert_int('\n', readc()); 172 | assert_true(readc() < 0); 173 | } 174 | 175 | int main(int argc, char **argv) { 176 | test_buf(); 177 | test_list(); 178 | test_map(); 179 | test_map_stack(); 180 | test_dict(); 181 | test_set(); 182 | test_path(); 183 | test_file(); 184 | printf("Passed\n"); 185 | return 0; 186 | } 187 | -------------------------------------------------------------------------------- /vector.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Rui Ueyama. Released under the MIT license. 2 | 3 | /* 4 | * Vectors are containers of void pointers that can change in size. 5 | */ 6 | 7 | #include 8 | #include 9 | #include "8cc.h" 10 | 11 | #define MIN_SIZE 8 12 | 13 | static int max(int a, int b) { 14 | return a > b ? a : b; 15 | } 16 | 17 | static int roundup(int n) { 18 | if (n == 0) 19 | return 0; 20 | int r = 1; 21 | while (n > r) 22 | r *= 2; 23 | return r; 24 | } 25 | 26 | static Vector *do_make_vector(int size) { 27 | Vector *r = malloc(sizeof(Vector)); 28 | size = roundup(size); 29 | if (size > 0) 30 | r->body = malloc(sizeof(void *) * size); 31 | r->len = 0; 32 | r->nalloc = size; 33 | return r; 34 | } 35 | 36 | Vector *make_vector() { 37 | return do_make_vector(0); 38 | } 39 | 40 | static void extend(Vector *vec, int delta) { 41 | if (vec->len + delta <= vec->nalloc) 42 | return; 43 | int nelem = max(roundup(vec->len + delta), MIN_SIZE); 44 | void *newbody = malloc(sizeof(void *) * nelem); 45 | memcpy(newbody, vec->body, sizeof(void *) * vec->len); 46 | vec->body = newbody; 47 | vec->nalloc = nelem; 48 | } 49 | 50 | Vector *make_vector1(void *e) { 51 | Vector *r = do_make_vector(0); 52 | vec_push(r, e); 53 | return r; 54 | } 55 | 56 | Vector *vec_copy(Vector *src) { 57 | Vector *r = do_make_vector(src->len); 58 | memcpy(r->body, src->body, sizeof(void *) * src->len); 59 | r->len = src->len; 60 | return r; 61 | } 62 | 63 | void vec_push(Vector *vec, void *elem) { 64 | extend(vec, 1); 65 | vec->body[vec->len++] = elem; 66 | } 67 | 68 | void vec_append(Vector *a, Vector *b) { 69 | extend(a, b->len); 70 | memcpy(a->body + a->len, b->body, sizeof(void *) * b->len); 71 | a->len += b->len; 72 | } 73 | 74 | void *vec_pop(Vector *vec) { 75 | assert(vec->len > 0); 76 | return vec->body[--vec->len]; 77 | } 78 | 79 | void *vec_get(Vector *vec, int index) { 80 | assert(0 <= index && index < vec->len); 81 | return vec->body[index]; 82 | } 83 | 84 | void vec_set(Vector *vec, int index, void *val) { 85 | assert(0 <= index && index < vec->len); 86 | vec->body[index] = val; 87 | } 88 | 89 | void *vec_head(Vector *vec) { 90 | assert(vec->len > 0); 91 | return vec->body[0]; 92 | } 93 | 94 | void *vec_tail(Vector *vec) { 95 | assert(vec->len > 0); 96 | return vec->body[vec->len - 1]; 97 | } 98 | 99 | Vector *vec_reverse(Vector *vec) { 100 | Vector *r = do_make_vector(vec->len); 101 | for (int i = 0; i < vec->len; i++) 102 | r->body[i] = vec->body[vec->len - i - 1]; 103 | r->len = vec->len; 104 | return r; 105 | } 106 | 107 | void *vec_body(Vector *vec) { 108 | return vec->body; 109 | } 110 | 111 | int vec_len(Vector *vec) { 112 | return vec->len; 113 | } 114 | --------------------------------------------------------------------------------