The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .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 <assert.h>
  7 | #include <inttypes.h>
  8 | #include <stdarg.h>
  9 | #include <stdbool.h>
 10 | #include <stdio.h>
 11 | #include <stdnoreturn.h>
 12 | #include <time.h>
 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 <rui314@gmail.com>
 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 
lt;
18 | 
19 | test/%.bin: test/%.o test/testmain.o
20 | 	cc -o $@ 
lt; 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 <rui314@gmail.com>
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 <ctype.h>
  4 | #include <stdarg.h>
  5 | #include <stdlib.h>
  6 | #include <string.h>
  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 <stdlib.h>
 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 <stdarg.h>
 4 | #include <stdlib.h>
 5 | #include <unistd.h>
 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 <errno.h>
 20 | #include <stdlib.h>
 21 | #include <string.h>
 22 | #include <sys/stat.h>
 23 | #include <sys/types.h>
 24 | #include <unistd.h>
 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 <ctype.h>
 25 | #include <errno.h>
 26 | #include <stdlib.h>
 27 | #include <string.h>
 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 == '
#39; || 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 == '
#39;) {
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 '
#39;:
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 <libgen.h>
  4 | #include <stdlib.h>
  5 | #include <string.h>
  6 | #include <sys/types.h>
  7 | #include <sys/wait.h>
  8 | #include <unistd.h>
  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 ] <file>\n\n"
 24 |             "\n"
 25 |             "  -I<path>          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<number>        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 <stdlib.h>
  6 | #include <string.h>
  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 <errno.h>
 4 | #include <limits.h>
 5 | #include <string.h>
 6 | #include <unistd.h>
 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 <stdlib.h>
17 | #include <string.h>
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 <stdalign.h>
 5 | #include <stddef.h>
 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 <float.h>
  4 | #include <stdarg.h>
  5 | #include <stdint.h>
  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 <stdbool.h>
  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 <stdbool.h>
  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 <iso646.h>
 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 <string.h>
 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('
#39;, L'\u0024');
 93 |     expect('
#39;, L'\U00000024');
 94 |     expect_string("
quot;, "\u0024");
 95 |     expect_string("
quot;, "\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 <locale.h>
  4 | #include <stddef.h>
  5 | #include <string.h>
  6 | #include <sys/stat.h>
  7 | #include <sys/types.h>
  8 | #include <time.h>
  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 <stdbool.h>
 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 <foo
119 | #include x
120 | 
121 | ! 1:1: cannot find header file: /no-such-file\or-directory
122 | #include </no-such-file\or-directory>
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 <stdnoreturn.h>
 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 <stdbool.h>
 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 <stddef.h>
  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 <stdbool.h>
 4 | #include <stdio.h>
 5 | #include <stdlib.h>
 6 | #include <string.h>
 7 | #include <unistd.h>
 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 <stdbool.h>
  5 | #include <stddef.h>
  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 <stdbool.h>
 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 <stdarg.h>
 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 <string.h>
  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 <stdlib.h>
  8 | #include <string.h>
  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 | 


--------------------------------------------------------------------------------