├── .gitignore ├── LICENCE ├── Makefile ├── README.md ├── codegen.c ├── configure ├── constexpr.c ├── cpp.c ├── error.c ├── functions.c ├── graph.c ├── include ├── limits.h ├── stdarg.h └── stddef.h ├── instrgen.c ├── instrrules.c ├── instrsel.c ├── instrutil.c ├── internals.h ├── ir.c ├── lexer.c ├── list.c ├── longmap.c ├── longset.c ├── main.c ├── make-internals.c ├── memory.c ├── parser.c ├── regalloc.c ├── scopes.c ├── set.c ├── ssa.c ├── stack.c ├── strmap.c ├── strset.c ├── tests ├── Makefile ├── cpp │ ├── .gitignore │ ├── Makefile │ ├── backslash-newlines-output.c │ ├── backslash-newlines.c │ ├── c99-examples-output.c │ ├── c99-examples.c │ ├── comments-output.c │ ├── comments.c │ ├── conditional-includes-output.c │ ├── conditional-includes.c │ ├── empty-line-output.c │ ├── empty-line-spacing-18-38-lines-output.c │ ├── empty-line-spacing-18-38-lines.c │ ├── empty-line-spacing-42-lines-output.c │ ├── empty-line-spacing-42-lines.c │ ├── empty-line-spacing-7-lines-output.c │ ├── empty-line-spacing-7-lines.c │ ├── empty-line-spacing-8-lines-output.c │ ├── empty-line-spacing-8-lines.c │ ├── empty-line-spacing-9-lines-output.c │ ├── empty-line-spacing-9-lines.c │ ├── empty-line-spacing-output.c │ ├── empty-line-spacing.c │ ├── empty-line.c │ ├── empty-output.c │ ├── empty.c │ ├── function-like-macros-output.c │ ├── function-like-macros.c │ ├── hashes-output.c │ ├── hashes.c │ ├── inception1-output.c │ ├── inception1.c │ ├── inception1.c-output.c │ ├── inception2.h │ ├── inception3.h │ ├── include.h │ ├── include1.h │ ├── includes-output.c │ ├── includes.c │ ├── line-output.c │ ├── line.c │ ├── newlines-and-macros-output.c │ ├── newlines-and-macros.c │ ├── null-output.c │ ├── null.c │ ├── object-like-macros-output.c │ ├── object-like-macros.c │ ├── one-empty-line-output.c │ ├── one-empty-line.c │ ├── one-line-output.c │ ├── one-line.c │ ├── pragma-output.c │ ├── pragma.c │ ├── string-literals-output.c │ ├── string-literals.c │ ├── stringizing-operator-output.c │ ├── stringizing-operator.c │ ├── token-paste-operator-output.c │ ├── token-paste-operator.c │ ├── token-spacing-output.c │ ├── token-spacing.c │ ├── whitespace-output.c │ └── whitespace.c ├── e2e │ ├── .gitignore │ ├── Makefile │ ├── gen-test-arithmetic-torture.c │ ├── gen-test-arithmetic-types-move-torture.c │ ├── stack-check.c │ ├── test-abi-function-callee.c │ ├── test-abi-function-caller.c │ ├── test-abi.h │ ├── test-arrays.c │ ├── test-character-and-string-literals.c │ ├── test-comma.c │ ├── test-conditionals.c │ ├── test-enums.c │ ├── test-expr.c │ ├── test-floats-and-doubles.c │ ├── test-func-calls.c │ ├── test-function-call-args.c │ ├── test-ifdef.c │ ├── test-inc-dec.c │ ├── test-include │ │ ├── foo.c │ │ ├── include.h │ │ └── main.c │ ├── test-initializers.c │ ├── test-long-doubles.c │ ├── test-loops.c │ ├── test-memory-functions.c │ ├── test-pointer-arithmetic.c │ ├── test-pointers.c │ ├── test-regressions.c │ ├── test-shlib-lib.c │ ├── test-shlib-main.c │ ├── test-shlib.h │ ├── test-structs.c │ ├── test-switch.c │ ├── test-typedefs.c │ └── test-varargs.c ├── integration │ ├── .gitignore │ ├── Makefile │ ├── test-debug.c │ ├── test-errors.c │ └── test-instrsel.c ├── test-lib.c ├── test-lib.h ├── test-utils.c └── unit │ ├── .gitignore │ ├── Makefile │ ├── test-cpp.c │ ├── test-functions.c │ ├── test-graph.c │ ├── test-lexer.c │ ├── test-list.c │ ├── test-longmap.c │ ├── test-longset.c │ ├── test-parser.c │ ├── test-set.c │ ├── test-ssa.c │ ├── test-strmap.c │ ├── test-strset.c │ └── test-types.c ├── tools ├── .gitignore ├── Makefile ├── benchmark.c └── make-rule-coverage-report.c ├── types.c ├── utils.c ├── wcc.c └── wcc.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.s 3 | config.h 4 | make-internals 5 | internals.c 6 | instrgen 7 | instrrules-generated.c 8 | libwcc.a 9 | wcc 10 | wcc2 11 | wcc3 12 | benchmark 13 | test.c 14 | test1.c 15 | test2.c 16 | test.h 17 | test 18 | test1 19 | test2 20 | core 21 | a.out 22 | build 23 | gmon.out 24 | print-rule-coverage-report 25 | wcc2.rulecov 26 | *.gcda 27 | *.gcno 28 | *.gcov 29 | main_coverage.info 30 | prof_output 31 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Will Angenent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: wcc 2 | 3 | SOURCES = \ 4 | wcc.c \ 5 | lexer.c \ 6 | parser.c \ 7 | constexpr.c \ 8 | scopes.c \ 9 | types.c \ 10 | ir.c \ 11 | functions.c \ 12 | ssa.c \ 13 | regalloc.c \ 14 | instrsel.c \ 15 | instrutil.c \ 16 | instrrules-generated.c \ 17 | codegen.c \ 18 | utils.c \ 19 | memory.c \ 20 | error.c \ 21 | set.c \ 22 | stack.c \ 23 | strmap.c \ 24 | strset.c \ 25 | longset.c \ 26 | longmap.c \ 27 | list.c \ 28 | graph.c \ 29 | internals.c \ 30 | cpp.c 31 | 32 | ASSEMBLIES := ${SOURCES:c=s} 33 | OBJECTS := ${SOURCES:c=o} 34 | 35 | BUILD_DIR = "$(shell pwd)" 36 | 37 | build: 38 | @mkdir -p build/wcc2 39 | @mkdir -p build/wcc3 40 | 41 | make-internals: make-internals.c 42 | gcc make-internals.c -o make-internals 43 | 44 | internals.c: internals.h make-internals 45 | ./make-internals > internals.c 46 | 47 | instrgen: instrgen.c instrgen.c instrrules.c instrutil.c utils.c memory.c longmap.c types.c scopes.c list.c set.c strmap.c error.c cpp.c strset.c lexer.c constexpr.c parser.c functions.c ir.c codegen.c longset.c instrsel.c graph.c ssa.c stack.c config.h wcc.h 48 | gcc -o instrgen instrgen.c instrrules.c instrutil.c utils.c memory.c longmap.c types.c scopes.c list.c set.c strmap.c error.c cpp.c strset.c lexer.c constexpr.c parser.c functions.c ir.c codegen.c longset.c instrsel.c graph.c ssa.c stack.c -Wno-return-type -D BUILD_DIR='${BUILD_DIR}' 49 | 50 | instrrules-generated.c: instrgen 51 | ./instrgen > instrrules-generated.c 52 | 53 | %.o: %.c config.h wcc.h build 54 | gcc -g ${GCC_OPTS} -Wunused -c $< -o $@ -D BUILD_DIR='${BUILD_DIR}' 55 | 56 | libwcc.a: ${OBJECTS} 57 | ar rcs libwcc.a ${OBJECTS} 58 | 59 | wcc: libwcc.a main.c config.h wcc.h 60 | gcc ${GCC_OPTS} -Wunused main.c libwcc.a -o wcc -g -Wno-return-type 61 | 62 | # wcc2 63 | WCC2_SOURCES := ${SOURCES:%=build/wcc2/%} 64 | WCC2_ASSEMBLIES := ${WCC2_SOURCES:.c=.s} 65 | 66 | build/wcc2/%.s: %.c wcc 67 | ./wcc ${WCC_OPTS} --fail-on-leaked-memory --rule-coverage-file wcc2.rulecov -c $< -S -o $@ -D BUILD_DIR='${BUILD_DIR}' 68 | 69 | wcc2: ${WCC2_ASSEMBLIES} build/wcc2/main.s wcc 70 | ./wcc ${GCC_OPTS} ${WCC2_ASSEMBLIES} build/wcc2/main.s -o wcc2 71 | 72 | # wcc3 73 | WCC3_SOURCES := ${SOURCES:%=build/wcc3/%} 74 | WCC3_ASSEMBLIES := ${WCC3_SOURCES:.c=.s} 75 | 76 | build/wcc3/%.s: %.c wcc2 77 | ./wcc2 ${WCC_OPTS} --fail-on-leaked-memory -c $< -S -o $@ -D BUILD_DIR='${BUILD_DIR}' 78 | 79 | wcc3: ${WCC3_ASSEMBLIES} build/wcc3/main.s wcc2 80 | ./wcc2 ${GCC_OPTS} ${WCC3_ASSEMBLIES} build/wcc3/main.s -o wcc3 81 | 82 | .PHONY: test-self-compilation 83 | test-self-compilation: ${WCC2_ASSEMBLIES} build/wcc2/main.s ${WCC3_ASSEMBLIES} build/wcc3/main.s 84 | cat build/wcc2/*.s > build/wcc2/all-s 85 | cat build/wcc3/*.s > build/wcc3/all-s 86 | diff build/wcc2/all-s build/wcc3/all-s 87 | @echo self compilation test passed 88 | 89 | .PHONY: test-all 90 | test-all: wcc internals.c utils.c memory.c include/stdarg.h 91 | cd tests && ${MAKE} all 92 | 93 | .PHONY: test 94 | test: test-self-compilation test-all 95 | @echo All tests passed 96 | 97 | .PHONY: test-unit 98 | test-unit: libwcc.a strmap.c longmap.c 99 | cd tests && ${MAKE} test-unit 100 | 101 | .PHONY: test-unit-parser 102 | test-unit-parser: libwcc.a 103 | cd tests && ${MAKE} test-unit-parser 104 | 105 | .PHONY: test-unit-ssa 106 | test-unit-ssa: libwcc.a 107 | cd tests && ${MAKE} test-unit-ssa 108 | 109 | .PHONY: test-unit-cpp 110 | test-unit-cpp: libwcc.a 111 | cd tests && ${MAKE} test-unit-cpp 112 | 113 | .PHONY: regen-cpp-tests-output 114 | regen-cpp-tests-output: wcc 115 | cd tests && ${MAKE} regen-cpp-tests-output 116 | 117 | .PHONY: test-unit-types 118 | test-unit-types: libwcc.a 119 | cd tests && ${MAKE} test-unit-types 120 | 121 | .PHONY: test-integration 122 | test-integration: libwcc.a wcc 123 | cd tests && ${MAKE} test-integration 124 | 125 | .PHONY: test-e2e 126 | test-e2e: wcc 127 | cd tests && ${MAKE} test-e2e 128 | 129 | .PHONY: test-cpp 130 | test-cpp: wcc 131 | cd tests && ${MAKE} test-cpp 132 | 133 | .PHONY: run-benchmark 134 | run-benchmark: wcc wcc2 135 | cd tools && ${MAKE} run-benchmark 136 | 137 | .PHONY: rule-coverage-report 138 | rule-coverage-report: wcc wcc2 test 139 | cd tools && ${MAKE} rule-coverage-report 140 | 141 | clean: 142 | cd tests && ${MAKE} clean 143 | cd tools && ${MAKE} clean 144 | 145 | @rm -f make-internals 146 | @rm -f internals.c 147 | @rm -f instrgen 148 | @rm -f instrrules-generated.c 149 | @rm -f libwcc.a 150 | @rm -f wcc 151 | @rm -f wcc2 152 | @rm -f wcc3 153 | @rm -f *.s 154 | @rm -f *.o 155 | @rm -f core 156 | @rm -f a.out 157 | @rm -Rf build 158 | @rm -f wcc-tests.rulecov 159 | @rm -f wcc2.rulecov 160 | @rm -f gmon.out 161 | @rm -f *.gcda 162 | @rm -f *.gcno 163 | @rm -f *.gcov 164 | @rm -f main_coverage.info 165 | @rm -f prof_output 166 | 167 | distclean: clean 168 | @rm -f config.h 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WCC C Compiler for x86_64 Linux 2 | 3 | This project is an implementation of the full C89/C90 C specification for `x86-64` linux. It's mostly based on [Engineering a Compiler 2nd Edition](https://www.amazon.com/Engineering-Compiler-Keith-Cooper/dp/012088478X). The compiler is self hosting. It's just a hobby, it won't be big and professional like gcc. All of the [C89/C90 specification](https://port70.net/~nsz/c/c89/c89-draft.html) has been implemented. All tests in [SQLite](https://www.sqlite.org/index.html)'s `tcltest` pass. The [was assembler](https://github.com/freewilll/was?tab=readme-ov-file) can be used to produce object files by either running `configure` with `--as` or setting the `AS` environment variable. 4 | 5 | The compiler has only been built and tested on Ubuntu focal 20.04.3 LTS. It will almost certainly not build or function normally anywhere else. This compiler is a hobby project and even close to be ready for production use. 6 | 7 | # Usage 8 | ``` 9 | $ ./configure 10 | $ make wcc 11 | $ ./wcc test.c -o test 12 | ``` 13 | 14 | # Implementation 15 | The compiler goes through the following phases: 16 | 17 | - C Preprocessor 18 | - Hand rolled lexer 19 | - Precedence climbing parser 20 | - Simple arithmetic transformations 21 | - Transformation into [SSA](https://en.wikipedia.org/wiki/Static_single_assignment_form) 22 | - Data flow analysis and replacement of variables with live ranges 23 | - Live range coalescing 24 | - Some more arithmetic optimizations while converting out of a linear IR into a tree IR 25 | - Instruction selection using tree pattern matching 26 | - Live range coalescing (again) 27 | - Register allocation using top-down graph coloring 28 | - Code generation using tree tiling 29 | 30 | # Running the tests 31 | Run all tests 32 | ``` 33 | $ make test 34 | ``` 35 | 36 | Test 3 stage self compilation 37 | ``` 38 | $ make test-self-compilation 39 | ``` 40 | 41 | Run benchmarks 42 | ``` 43 | $ make run-benchmark 44 | ``` 45 | 46 | Compile and test `sqlite3` 47 | ``` 48 | $ CC=.../wcc ./configure 49 | $ make tcltest 50 | ``` 51 | 52 | # Example compilation 53 | ``` 54 | #include 55 | 56 | typedef struct s1 { 57 | int i, j; 58 | } S1; 59 | 60 | typedef struct s2 { 61 | S1 *s1; 62 | } S2; 63 | 64 | void main() { 65 | S2 *s2; 66 | 67 | s2 = malloc(sizeof(S2)); 68 | s2->s1 = malloc(sizeof(S1)); 69 | s2->s1->j = 1; 70 | printf("%d\n", s2->s1->j); 71 | } 72 | ``` 73 | 74 | ``` 75 | main: 76 | push %rbp # Function prologue 77 | mov %rsp, %rbp 78 | push %rbx 79 | subq $8, %rsp 80 | movq $8, %rdi # s2 = malloc(sizeof(S2)); 81 | callq malloc@PLT 82 | movq %rax, %rbx # rbx = s2 83 | movq $8, %rdi # s2->s1 = malloc(sizeof(S1)); 84 | callq malloc@PLT 85 | movq %rax, %rcx 86 | addq $8, %rsp 87 | movq %rcx, %rax 88 | movq %rax, (%rbx) 89 | movq %rbx, %rax # s2->s1->j = 1; 90 | movq (%rax), %rax 91 | movl $1, 4(%rax) 92 | subq $8, %rsp # printf("%d\n", s2->s1->j); 93 | movq %rbx, %rax 94 | movq (%rax), %rax 95 | movl 4(%rax), %esi 96 | leaq .SL0(%rip), %rdi 97 | movb $0, %al # printf is variadic, 0 is the number of floating point arguments 98 | callq printf@PLT 99 | addq $8, %rsp 100 | movq $0, %rax # Function exit code zero 101 | popq %rbx # Function epilogue 102 | leaveq 103 | retq 104 | ``` 105 | 106 | # History 107 | The project started out as a clone of [c4](https://github.com/rswier/c4) to teach myself to write it from scratch. I then went down a route based on [TCC](https://bellard.org/tcc/) where I wrote a code generator that outputted an object (`.o`) file. It then quickly became clear that generating object code without using an assembler is a waste of time, so I adapted it to produce `.s` files and compiled them with gcc. I then proceeded implemeting [Sebastian Falbesoner's](https://www.complang.tuwien.ac.at/Diplomarbeiten/falbesoner14.pdf) approach to register allocation. At this point I went academic and started reading [Engineering a Compiler 2nd Edition](https://www.amazon.com/Engineering-Compiler-Keith-Cooper/dp/012088478X). First SSA transformation, then graph coloring register allocation, then finally instruction selection using tree pattern matching. 108 | 109 | After a hiatus I resumed work and fixed a ton of bugs in the instruction selection. I then decided to implement the full C89/C90 specification, starting with the non-preprocessor parts, then the preprocessor. 110 | 111 | To validate the compiler can compile something other than itself correctly, I fixed enough bugs to get `sqlite3` to compile and pass the `tcltest` tests. 112 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Configure: 6 | # - C library: musl or glibc 7 | # - as binary 8 | # - ld binary 9 | # 10 | # The results are written to config.h 11 | 12 | USE_MUSL=0 13 | 14 | DEFAULT_AS_COMMAND="${AS:-$(command -v as || true)}" # Default assembler. 15 | DEFAULT_LD_COMMAND="${LD:-$(command -v ld || true)}" # Default linker. 16 | 17 | # Show the help 18 | help() { 19 | cat <&2; exit 1 ;; 39 | esac 40 | shift || true 41 | done 42 | 43 | # gcc C runtime files 44 | GCC_LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9 45 | GCC_CRTBEGIN=/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o 46 | GCC_CRTEND=/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o 47 | 48 | # Configure libc 49 | if [ $USE_MUSL -eq 0 ] 50 | then 51 | echo Using glibc 52 | 53 | DYNAMIC_LINKER=/lib64/ld-linux-x86-64.so.2 54 | LIBC_LIBRARY_PATH=/usr/lib 55 | STARTFILES="/usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o $GCC_CRTBEGIN" 56 | ENDFILES="$GCC_CRTEND /usr/lib/x86_64-linux-gnu/crtn.o" 57 | 58 | else 59 | echo Using musl libc 60 | 61 | DYNAMIC_LINKER=/lib/ld-musl-x86_64.so.1 62 | LIBC_LIBRARY_PATH=/usr/lib/x86_64-linux-musl 63 | STARTFILES="/usr/lib/x86_64-linux-musl/Scrt1.o /usr/lib/x86_64-linux-musl/crti.o $GCC_CRTBEGIN" 64 | ENDFILES="$GCC_CRTEND /usr/lib/x86_64-linux-musl/crtn.o" 65 | 66 | fi 67 | 68 | echo Using assembler $DEFAULT_AS_COMMAND 69 | echo Using linker $DEFAULT_LD_COMMAND 70 | 71 | # Write out config.h 72 | CONFIG_H_PATH=config.h 73 | 74 | cat > $CONFIG_H_PATH < 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wcc.h" 7 | 8 | // ANSI color codes 9 | #define LOCUS "\e[0;01m" // Bold 10 | #define BRED "\e[1;31m" // Bright red 11 | #define BMAG "\e[1;35m" // Bright magenta 12 | #define RESET "\e[0m" // Reset 13 | 14 | static void print_filename_and_linenumber(int is_tty) { 15 | if (is_tty) fprintf(stderr, LOCUS); 16 | fprintf(stderr, "%s:%d: ", cur_filename, cur_line); 17 | if (is_tty) fprintf(stderr, RESET); 18 | } 19 | 20 | void panic_with_line_number(char *format, ...) { 21 | va_list ap; 22 | va_start(ap, format); 23 | 24 | int is_tty = isatty(2); 25 | print_filename_and_linenumber(is_tty); 26 | if (is_tty) fprintf(stderr, BRED); 27 | fprintf(stderr, "internal error: "); 28 | if (is_tty) fprintf(stderr, RESET); 29 | vfprintf(stderr, format, ap); 30 | fprintf(stderr, "\n"); 31 | va_end(ap); 32 | exit(1); 33 | } 34 | 35 | 36 | // Report an error by itself (no filename or line number) and exit 37 | void simple_error(char *format, ...) { 38 | va_list ap; 39 | va_start(ap, format); 40 | 41 | int is_tty = isatty(2); 42 | if (is_tty) fprintf(stderr, BRED); 43 | fprintf(stderr, "error: "); 44 | if (is_tty) fprintf(stderr, RESET); 45 | vfprintf(stderr, format, ap); 46 | fprintf(stderr, "\n"); 47 | va_end(ap); 48 | exit(1); 49 | } 50 | 51 | // Report an error with a filename and line number and exit 52 | void _error(char *format, va_list ap) { 53 | if (compile_phase == CP_PREPROCESSING) get_cpp_filename_and_line(); 54 | 55 | int is_tty = isatty(2); 56 | print_filename_and_linenumber(is_tty); 57 | if (is_tty) fprintf(stderr, BRED); 58 | fprintf(stderr, "error: "); 59 | if (is_tty) fprintf(stderr, RESET); 60 | vfprintf(stderr, format, ap); 61 | fprintf(stderr, "\n"); 62 | va_end(ap); 63 | exit(1); 64 | } 65 | 66 | void error(char *format, ...) { 67 | va_list ap; 68 | va_start(ap, format); 69 | _error(format, ap); 70 | } 71 | 72 | // Report a warning with a filename and line number 73 | void warning(char *format, ...) { 74 | va_list ap; 75 | va_start(ap, format); 76 | 77 | if (opt_warnings_are_errors) _error(format, ap); 78 | 79 | if (compile_phase == CP_PREPROCESSING) get_cpp_filename_and_line(); 80 | 81 | int is_tty = isatty(2); 82 | print_filename_and_linenumber(is_tty); 83 | if (is_tty) fprintf(stderr, BMAG); 84 | fprintf(stderr, "warning: "); 85 | if (is_tty) fprintf(stderr, RESET); 86 | vfprintf(stderr, format, ap); 87 | fprintf(stderr, "\n"); 88 | va_end(ap); 89 | } 90 | -------------------------------------------------------------------------------- /graph.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wcc.h" 7 | 8 | static void allocate_graph_storage(Graph *g) { 9 | g->nodes = wcalloc(g->node_count, sizeof(GraphNode)); 10 | g->edges = wcalloc(g->max_edge_count, sizeof(GraphEdge)); 11 | } 12 | 13 | static void init_graph(Graph *g, int node_count, int edge_count) { 14 | g->node_count = node_count; 15 | g->max_edge_count = edge_count ? edge_count : MAX_GRAPH_EDGE_COUNT; 16 | allocate_graph_storage(g); 17 | 18 | for (int i = 0; i < node_count; i++) g->nodes[i].id = i; 19 | } 20 | 21 | Graph *new_graph(int node_count, int edge_count) { 22 | Graph *g = wcalloc(1, sizeof(Graph)); 23 | init_graph(g, node_count, edge_count); 24 | 25 | return g; 26 | } 27 | 28 | void free_graph(Graph *g) { 29 | wfree(g->nodes); 30 | wfree(g->edges); 31 | wfree(g); 32 | } 33 | 34 | void dump_graph(Graph *g) { 35 | printf("Nodes:\n"); 36 | for (int i = 0; i < g->node_count; i++) { 37 | GraphNode *n = &g->nodes[i]; 38 | printf("n%-3d", n->id); 39 | if (n->succ) printf("e%-3d ", n->succ->id); else printf(" "); 40 | if (n->pred) printf("e%-3d ", n->pred->id); else printf(" "); 41 | printf("\n"); 42 | } 43 | 44 | printf("\nEdges:\n"); 45 | for (int i = 0; i < g->edge_count; i++) { 46 | GraphEdge *e = &g->edges[i]; 47 | printf("e%-3d n%-3d n%-3d ", e->id, e->from->id, e->to->id); 48 | if (e->next_succ) printf("e%-3d ", e->next_succ->id); else printf(" "); 49 | if (e->next_pred) printf("e%-3d ", e->next_pred->id); else printf(" "); 50 | printf("\n"); 51 | } 52 | 53 | printf("\n"); 54 | } 55 | 56 | GraphEdge *add_graph_edge(Graph *g, int from, int to) { 57 | if (g->edge_count == g->max_edge_count) panic("Exceeded max graph edge count %d", g->max_edge_count); 58 | if (to < 0 || to >= g->node_count) panic("Node %d out of range %d", to, g->node_count); 59 | if (from < 0 || from >= g->node_count) panic("Node %d out of range %d", from, g->node_count); 60 | 61 | GraphEdge *e = &g->edges[g->edge_count]; 62 | e->id = g->edge_count; 63 | e->from = &g->nodes[from]; 64 | e->to = &g->nodes[to]; 65 | 66 | if (!g->nodes[from].succ) 67 | g->nodes[from].succ = e; 68 | else { 69 | GraphEdge *t = g->nodes[from].succ; 70 | while (t->next_succ) t = t->next_succ; 71 | t->next_succ = e; 72 | } 73 | 74 | if (!g->nodes[to].pred) 75 | g->nodes[to].pred = e; 76 | else { 77 | GraphEdge *t = g->nodes[to].pred; 78 | while (t->next_pred) t = t->next_pred; 79 | t->next_pred = e; 80 | } 81 | 82 | g->edge_count++; 83 | 84 | return e; 85 | } 86 | -------------------------------------------------------------------------------- /include/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIMITS_H 2 | #define _LIMITS_H 3 | 4 | #define CHAR_BIT 8 5 | #define SCHAR_MIN -127 6 | #define SCHAR_MAX +127 7 | #define UCHAR_MAX 255 8 | #define CHAR_MIN 0 9 | #define CHAR_MAX 127 10 | #define MB_LEN_MAX 1 11 | #define SHRT_MIN -32767 12 | #define SHRT_MAX +32767 13 | #define USHRT_MAX 65535 14 | #define INT_MIN -32767 15 | #define INT_MAX +32767 16 | #define UINT_MAX 65535 17 | #define LONG_MIN -2147483647 18 | #define LONG_MAX +2147483647 19 | #define ULONG_MAX 4294967295 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDARG_H 2 | #define _STDARG_H 3 | 4 | typedef struct __va_list { 5 | unsigned int gp_offset; 6 | unsigned int fp_offset; 7 | void *overflow_arg_area; 8 | void *reg_save_area; 9 | } va_list[1]; 10 | 11 | #define va_copy(dst, src) *dst = *src 12 | 13 | #define va_end(ap) 14 | 15 | typedef va_list __gnuc_va_list; 16 | 17 | #endif /* _STDARG_H */ 18 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDDEF_H 2 | #define _STDDEF_H 3 | 4 | typedef long ptrdiff_t; 5 | 6 | typedef unsigned long size_t; 7 | 8 | typedef int wchar_t; 9 | 10 | #ifndef NULL 11 | #define NULL ((void *)0) 12 | #endif 13 | 14 | #define offsetof(type, field) ((size_t)&((type *)0)->field) 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /instrgen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "wcc.h" 5 | 6 | // Dynamically defined rules in instrrules.c and dump the result out to a .c file with 7 | // global declarations. That file is then compiled & linked into compiler. 8 | int main(int argc, char **argv) { 9 | define_rules(); 10 | 11 | printf("// Auto generated by %s\n\n", argv[0]); 12 | 13 | printf("#include \"wcc.h\"\n\n"); 14 | 15 | LongMap *operation_counts = new_longmap(); 16 | 17 | for (int i = 0; i < instr_rule_count; i++) { 18 | Rule *r = &(instr_rules[i]); 19 | 20 | int count = r->x86_operation_count; 21 | 22 | if (count) { 23 | printf("static X86Operation rule_%d_operations[] = {\n", i); 24 | for (int j = 0; j < r->x86_operation_count; j++) { 25 | X86Operation *op = &r->x86_operations[j]; 26 | 27 | printf(" { %d, %d, %d, %d, ", op->operation, op->dst, op->v1, op->v2); 28 | if (op->template) 29 | printf("\"%s\", ", op->template); 30 | else 31 | printf("NULL, "); 32 | 33 | if (op->save_value_in_slot + op->allocate_stack_index_in_slot + 34 | op->allocate_register_in_slot + op->allocate_label_in_slot + 35 | op->allocated_type + op->arg != 0) { 36 | printf("%d, %d, %d, %d, %d, %d },\n", 37 | op->save_value_in_slot, op->allocate_stack_index_in_slot, 38 | op->allocate_register_in_slot, op->allocate_label_in_slot, 39 | op->allocated_type, op->arg /*, next */); 40 | } 41 | else 42 | printf("},\n"); 43 | } 44 | 45 | printf("};\n\n"); 46 | } 47 | 48 | longmap_put(operation_counts, i, (void *) (long) count); 49 | } 50 | 51 | printf("\n"); 52 | printf("static Rule local_instr_rules[%d] = {\n", instr_rule_count); 53 | 54 | for (int i = 0; i < instr_rule_count; i++) { 55 | Rule *r = &(instr_rules[i]); 56 | printf(" { "); 57 | printf("%d, ", r->index); 58 | printf("%d, ", r->operation); 59 | printf("%d, ", r->dst); 60 | printf("%d, ", r->src1); 61 | printf("%d, ", r->src2); 62 | printf("%d, ", r->cost); 63 | 64 | int operation_count = (long) longmap_get(operation_counts, i); 65 | if (operation_count) 66 | printf("rule_%d_operations, ", i); 67 | else 68 | printf("NULL, "); 69 | 70 | printf("%d, ", operation_count); 71 | 72 | printf("},\n"); 73 | } 74 | printf("};\n\n"); 75 | 76 | printf("void init_generated_instruction_selection_rules(void) {\n"); 77 | printf(" instr_rule_count = %d;\n", instr_rule_count); 78 | printf(" instr_rules = local_instr_rules;\n"); 79 | printf("}\n"); 80 | 81 | free_longmap(operation_counts); 82 | } 83 | -------------------------------------------------------------------------------- /internals.h: -------------------------------------------------------------------------------- 1 | struct __wcc_fp_register_save_area { 2 | long elements[2]; 3 | }; 4 | 5 | struct __wcc_register_save_area { 6 | long gp[8]; 7 | struct __wcc_fp_register_save_area f8[8]; 8 | }; 9 | 10 | extern void *memcpy(void *s1, const void *s2, unsigned long n); 11 | extern void *memset(void *str, int c, unsigned long n); 12 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wcc.h" 4 | 5 | void free_circular_linked_list(CircularLinkedList *cll) { 6 | if (!cll) return; 7 | 8 | CircularLinkedList *head = cll->next; 9 | CircularLinkedList *l = head; 10 | do { 11 | CircularLinkedList *next = l->next; 12 | wfree(l); 13 | l = next; 14 | } while (l != head); 15 | } 16 | 17 | #define MIN_SIZE 0 18 | 19 | static void resize_list(List* l, int new_length); 20 | 21 | List *new_list(int initial_allocation) { 22 | List *l = wmalloc(sizeof(List)); 23 | 24 | l->length = 0; 25 | l->allocated = 0; 26 | l->elements = NULL; 27 | 28 | if (initial_allocation) { 29 | l->allocated = initial_allocation; 30 | l->elements = wmalloc(sizeof(void *) * initial_allocation); 31 | } 32 | 33 | return l; 34 | } 35 | 36 | void free_list(List *l) { 37 | wfree(l->elements); 38 | wfree(l); 39 | } 40 | 41 | static int round_up(int length) { 42 | if (length == 0) return 0; 43 | int result = 1; 44 | while (result < length) result *= 2; 45 | return result; 46 | } 47 | 48 | static void resize_list(List* l, int new_length) { 49 | if (new_length < l->allocated) { 50 | l->length = new_length; 51 | return; 52 | } 53 | 54 | int new_allocated = round_up(new_length); 55 | if (new_allocated < MIN_SIZE) new_allocated = MIN_SIZE; 56 | if (new_length > l->length) { 57 | l->elements = wrealloc(l->elements, sizeof(void *) * new_allocated); 58 | if (!l->elements) panic("Realloc failed"); 59 | } 60 | l->length = new_length; 61 | l->allocated = new_allocated; 62 | } 63 | 64 | void append_to_list(List *l, void *element) { 65 | resize_list(l, l->length + 1); 66 | l->elements[l->length - 1] = element; 67 | } 68 | -------------------------------------------------------------------------------- /longmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "wcc.h" 5 | 6 | enum { 7 | STATUS_EMPTY, 8 | STATUS_USED, 9 | STATUS_TOMBSTONE 10 | }; 11 | 12 | enum { 13 | DEFAULT_SIZE = 16, 14 | MAX_LOAD_FACTOR = 666, // 0.666 * 1000 15 | EXPANSION_FACTOR = 333, // 0.333 * 1000 16 | }; 17 | 18 | 19 | // Default hash function 20 | static long hash(long l) { 21 | return l; 22 | } 23 | 24 | static void maybe_rehash(LongMap *map) { 25 | if (map->used_count * 1000 < map->size * MAX_LOAD_FACTOR) return; 26 | 27 | int new_size; 28 | if (map->element_count * 1000 < map->size * EXPANSION_FACTOR) 29 | new_size = map->size; 30 | else 31 | new_size = map->size * 2; 32 | 33 | int mask = new_size - 1; 34 | long *keys = wcalloc(new_size, sizeof(long)); 35 | void **values = wcalloc(new_size, sizeof(void *)); 36 | char *status = wcalloc(new_size, sizeof(char)); 37 | 38 | for (int i = 0; i < map->size; i++) { 39 | if (map->status[i] != STATUS_USED) continue; 40 | long key = map->keys[i]; 41 | long pos = map->hashfunc(key) & mask; 42 | while (1) { 43 | if (status[pos] == STATUS_EMPTY) { 44 | keys[pos] = key; 45 | values[pos] = map->values[i]; 46 | status[pos] = STATUS_USED; 47 | break; 48 | } 49 | pos = (pos + 1) & mask; 50 | } 51 | } 52 | 53 | wfree(map->keys); 54 | wfree(map->values); 55 | wfree(map->status); 56 | map->keys = keys; 57 | map->values = values; 58 | map->status = status; 59 | map->size = new_size; 60 | map->used_count = map->element_count; 61 | } 62 | 63 | void longmap_put(LongMap *map, long key, void *value) { 64 | maybe_rehash(map); 65 | 66 | long mask = map->size - 1; 67 | long pos = map->hashfunc(key) & mask; 68 | 69 | while (1) { 70 | char status = map->status[pos]; 71 | if (status != STATUS_USED) { 72 | map->keys[pos] = key; 73 | map->values[pos] = value; 74 | map->status[pos] = STATUS_USED; 75 | map->element_count++; 76 | if (status == STATUS_EMPTY) map->used_count++; 77 | return; 78 | } 79 | 80 | if (map->keys[pos] == key) { 81 | map->values[pos] = value; 82 | return; 83 | } 84 | pos = (pos + 1) & mask; 85 | } 86 | } 87 | 88 | void *longmap_get(LongMap *map, long key) { 89 | long mask = map->size - 1; 90 | long pos = map->hashfunc(key) & mask; 91 | 92 | char status = map->status[pos]; 93 | while (status != STATUS_EMPTY) { 94 | long k = map->keys[pos]; 95 | if (status != STATUS_TOMBSTONE && k == key) return map->values[pos]; 96 | pos = (pos + 1) & mask; 97 | status = map->status[pos]; 98 | } 99 | return 0; 100 | } 101 | 102 | void longmap_delete(LongMap *map, long key) { 103 | long mask = map->size - 1; 104 | long pos = map->hashfunc(key) & mask; 105 | 106 | char status = map->status[pos]; 107 | while (status != STATUS_EMPTY) { 108 | long k = map->keys[pos]; 109 | if (status != STATUS_TOMBSTONE && k == key) { 110 | map->status[pos] = STATUS_TOMBSTONE; 111 | map->element_count--; 112 | return; 113 | } 114 | pos = (pos + 1) & mask; 115 | status = map->status[pos]; 116 | } 117 | } 118 | 119 | // Populate keys with the keys in the map & return the count. Memory for keys is 120 | // allocated, the caller is expected to free it. 121 | int longmap_keys(LongMap *map, int **keys) { 122 | *keys = wmalloc(map->size * sizeof(int)); 123 | int count = 0; 124 | 125 | longmap_foreach(map, it) (*keys)[count++] = longmap_iterator_key(&it); 126 | 127 | return count; 128 | } 129 | 130 | void longmap_empty(LongMap *map) { 131 | memset(map->status, 0, map->size * sizeof(char)); 132 | map->used_count = 0; 133 | map->element_count = 0; 134 | } 135 | 136 | LongMap *longmap_copy(LongMap *map) { 137 | LongMap *result = wcalloc(1, sizeof(LongMap)); 138 | result->keys = wmalloc(map->size * sizeof(long)); 139 | result->values = wmalloc(map->size * sizeof(void *)); 140 | result->status = wmalloc(map->size * sizeof(char)); 141 | memcpy(result->keys, map->keys, map->size * sizeof(long)); 142 | memcpy(result->values, map->values, map->size * sizeof(void *)); 143 | memcpy(result->status, map->status, map->size * sizeof(char)); 144 | result->size = map->size; 145 | result->used_count = map->used_count; 146 | result->element_count = map->element_count; 147 | result->hashfunc = map->hashfunc; 148 | 149 | return result; 150 | } 151 | 152 | void longmap_iterator_next(LongMapIterator *iterator) { 153 | LongMap *map = iterator->map; 154 | char *status = iterator->map->status; 155 | int size = map->size; 156 | 157 | if (iterator->original_size != map->size) panic("longmap size changed during iteration"); 158 | 159 | iterator->pos++; 160 | 161 | while (iterator->pos < size && status[iterator->pos] != STATUS_USED) 162 | iterator->pos++; 163 | 164 | if (iterator->pos == size || status[iterator->pos] != STATUS_USED) 165 | iterator->pos = -1; 166 | } 167 | 168 | LongMapIterator longmap_iterator(LongMap *map) { 169 | LongMapIterator result; 170 | result.map = map; 171 | result.pos = -1; 172 | result.original_size = map->size; 173 | longmap_iterator_next(&result); 174 | 175 | return result; 176 | } 177 | 178 | LongMap *new_longmap(void) { 179 | LongMap *map = wcalloc(1, sizeof(LongMap)); 180 | map->size = DEFAULT_SIZE; 181 | map->keys = wcalloc(DEFAULT_SIZE, sizeof(long)); 182 | map->values = wcalloc(DEFAULT_SIZE, sizeof(void *)); 183 | map->status = wcalloc(DEFAULT_SIZE, sizeof(char)); 184 | map->hashfunc = hash; 185 | return map; 186 | } 187 | 188 | void free_longmap(LongMap *map) { 189 | wfree(map->keys); 190 | wfree(map->values); 191 | wfree(map->status); 192 | wfree(map); 193 | } 194 | -------------------------------------------------------------------------------- /longset.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wcc.h" 4 | 5 | LongSet *new_longset(void) { 6 | LongSet *ls = wmalloc(sizeof(LongSet)); 7 | ls->longmap = new_longmap(); 8 | 9 | return ls; 10 | } 11 | 12 | void free_longset(LongSet *ls) { 13 | free_longmap(ls->longmap); 14 | wfree(ls); 15 | } 16 | 17 | void longset_add(LongSet *ls, long element) { 18 | longmap_put(ls->longmap, element, (void *) 1); 19 | } 20 | 21 | void longset_delete(LongSet *ls, long element) { 22 | longmap_delete(ls->longmap, element); 23 | } 24 | 25 | void longset_empty(LongSet *ls) { 26 | longmap_empty(ls->longmap); 27 | } 28 | 29 | int longset_in(LongSet *ls, long element) { 30 | return !!longmap_get(ls->longmap, element); 31 | } 32 | 33 | int longset_eq(LongSet *ls1, LongSet *ls2) { 34 | int count1 = 0; 35 | 36 | longmap_foreach(ls1->longmap, it) { 37 | count1++; 38 | if (!longmap_get(ls2->longmap, longmap_iterator_key(&it))) return 0; 39 | } 40 | 41 | int count2 = 0; 42 | longmap_foreach(ls2->longmap, it) count2++; 43 | 44 | return (count1 == count2); 45 | 46 | return 1; 47 | } 48 | 49 | int longset_len(LongSet *ls) { 50 | int count = 0; 51 | 52 | longmap_foreach(ls->longmap, it) 53 | count++; 54 | 55 | return count; 56 | } 57 | 58 | LongSet *longset_copy(LongSet *ls) { 59 | LongSet *result = wmalloc(sizeof(LongSet)); 60 | result->longmap = longmap_copy(ls->longmap); 61 | 62 | return result; 63 | } 64 | 65 | 66 | LongSet *longset_union(LongSet *ls1, LongSet *ls2) { 67 | LongSet *result = new_longset(); 68 | 69 | longmap_foreach(ls1->longmap, it) 70 | longmap_put(result->longmap, longmap_iterator_key(&it), (void *) 1); 71 | 72 | longmap_foreach(ls2->longmap, it) 73 | longmap_put(result->longmap, longmap_iterator_key(&it), (void *) 1); 74 | 75 | return result; 76 | } 77 | 78 | LongSet *longset_intersection(LongSet *ls1, LongSet *ls2) { 79 | LongSet *result = new_longset(); 80 | 81 | longmap_foreach(ls1->longmap, it) { 82 | long key = longmap_iterator_key(&it); 83 | if (longmap_get(ls2->longmap, key)) longmap_put(result->longmap, longmap_iterator_key(&it), (void *) 1); 84 | } 85 | 86 | return result; 87 | } 88 | 89 | void longset_iterator_next(LongSetIterator *iterator) { 90 | longmap_iterator_next(&iterator->longmap_iterator); 91 | } 92 | 93 | LongSetIterator longset_iterator(LongSet *ls) { 94 | LongSetIterator result; 95 | result.longmap_iterator = longmap_iterator(ls->longmap); 96 | 97 | return result; 98 | } 99 | 100 | void print_longset(LongSet *ls) { 101 | if (!ls) { 102 | printf("{}"); 103 | return; 104 | } 105 | 106 | int first = 1; 107 | printf("{"); 108 | for (LongSetIterator it = longset_iterator(ls); !longset_iterator_finished(&it); longset_iterator_next(&it)) { 109 | long element = longset_iterator_element(&it); 110 | if (!first) { printf(", "); } 111 | printf("%ld", element); 112 | first = 0; 113 | } 114 | printf("}"); 115 | } 116 | -------------------------------------------------------------------------------- /make-internals.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void die(char *message) { 5 | puts(message); 6 | exit(1); 7 | } 8 | 9 | int main() { 10 | FILE *f = fopen("internals.h", "r"); 11 | if (!f) die("Opening internals.h"); 12 | 13 | char *buffer = malloc(1024 * 1024); 14 | int count = fread(buffer, 1024 * 1024, 1, f); 15 | if (count < 0) die("Reading internals.h"); 16 | 17 | printf("char *internals(void) {\n"); 18 | printf(" return \""); 19 | 20 | char *p = buffer; 21 | while (*p) { 22 | if (*p == '\n') 23 | printf("\\n"); 24 | else 25 | putchar(*p); 26 | 27 | p++; 28 | } 29 | 30 | printf("\";\n}\n"); 31 | 32 | fclose(f); 33 | } 34 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __linux__ 6 | #include 7 | #endif 8 | #include "wcc.h" 9 | 10 | static long total_allocation = 0; 11 | static long peak_allocation = 0; 12 | static long current_allocation = 0; 13 | static int allocation_count = 0; 14 | static int free_count = 0; 15 | 16 | #ifndef __linux__ 17 | // malloc_usable_size is linux specific 18 | size_t malloc_usable_size(void * ptr) { 19 | return 0; 20 | } 21 | 22 | #endif 23 | 24 | static void add_to_allocation(size_t size) { 25 | current_allocation += size; 26 | total_allocation += size; 27 | if (current_allocation > peak_allocation) peak_allocation = current_allocation; 28 | allocation_count++; 29 | } 30 | 31 | static void remove_from_allocation(size_t size) { 32 | current_allocation -= size; 33 | free_count++; 34 | } 35 | 36 | // Wrapper around malloc that exits if malloc fails 37 | void *wmalloc(size_t size) { 38 | if (!size) return NULL; 39 | 40 | void *result = malloc(size); 41 | 42 | if (!result) { 43 | printf("Failed to malloc %ld bytes\n", size); 44 | exit(1); 45 | } 46 | 47 | add_to_allocation(malloc_usable_size(result)); 48 | 49 | return result; 50 | } 51 | 52 | // Wrapper around realloc that exits if realloc fails 53 | void *wrealloc(void *ptr, size_t size) { 54 | remove_from_allocation(malloc_usable_size(ptr)); 55 | void *result = realloc(ptr, size); 56 | 57 | if (!result) { 58 | printf("Failed to realloc %ld bytes\n", size); 59 | exit(1); 60 | } 61 | 62 | add_to_allocation(malloc_usable_size(result)); 63 | 64 | return result; 65 | } 66 | 67 | // Wrapper around calloc that exits if calloc fails 68 | void *wcalloc(size_t nitems, size_t size) { 69 | if (!size || !nitems) return NULL; 70 | 71 | void *result = calloc(nitems, size); 72 | 73 | if (!result) { 74 | printf("Failed to calloc %ld items of %ld bytes\n", nitems, size); 75 | exit(1); 76 | } 77 | add_to_allocation(malloc_usable_size(result)); 78 | 79 | return result; 80 | } 81 | 82 | // Wrapper around strdup that exits if strdup fails 83 | char *wstrdup(const char *str) { 84 | char *ptr = strdup(str); 85 | 86 | if (!ptr) { 87 | printf("Failed to strdup %s\n", str); 88 | exit(1); 89 | } 90 | 91 | add_to_allocation(malloc_usable_size(ptr)); 92 | 93 | return ptr; 94 | } 95 | 96 | // Wrapper around free 97 | void wfree(void *ptr) { 98 | if (!ptr) return; 99 | 100 | remove_from_allocation(malloc_usable_size(ptr)); 101 | 102 | free(ptr); 103 | } 104 | 105 | static void print_human_readable_value(long value) { 106 | if (value < 0) { 107 | printf("-"); 108 | value = -value; 109 | } 110 | 111 | char buffer[128]; 112 | sprintf(buffer, "%ld", value); 113 | int len = strlen(buffer); 114 | for (int i = 0; i < len; i++) { 115 | printf("%d", buffer[i] - '0'); 116 | int remaining = len - i; 117 | if (remaining >= 3 && ((remaining - 1) % 3 == 0)) printf(","); 118 | } 119 | } 120 | 121 | void process_memory_allocation_stats(void) { 122 | if (print_heap_usage || (fail_on_leaked_memory && current_allocation)) { 123 | printf("In use at exit: "); 124 | print_human_readable_value(current_allocation); printf(" bytes\n"); 125 | 126 | printf("Total heap usage: "); 127 | print_human_readable_value(allocation_count); printf(" allocs, "); 128 | print_human_readable_value(free_count); printf(" frees, "); 129 | print_human_readable_value(total_allocation); printf(" bytes allocated, "); 130 | print_human_readable_value(peak_allocation); printf(" bytes peak usage\n"); 131 | } 132 | 133 | if (fail_on_leaked_memory && current_allocation) { 134 | printf("Memory has been leaked.\n"); 135 | exit(1); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /scopes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "wcc.h" 6 | 7 | Scope *global_scope; 8 | 9 | static List *allocated_scopes; 10 | static List *allocated_tags; 11 | 12 | // Initialize the global scope 13 | void init_scopes(void) { 14 | allocated_scopes = new_list(128); 15 | allocated_tags = new_list(32); 16 | 17 | global_scope = wcalloc(1, sizeof(Scope)); 18 | append_to_list(allocated_scopes, global_scope); 19 | global_scope->symbol_list = new_list(128); 20 | global_scope->symbols = new_strmap(); 21 | global_scope->tags = new_strmap(); 22 | global_scope->parent = 0; 23 | 24 | cur_scope = global_scope; 25 | } 26 | 27 | void free_scopes(void) { 28 | for (int i = 0; i < allocated_scopes->length; i++) { 29 | Scope *scope = allocated_scopes->elements[i]; 30 | 31 | for (int j = 0; j < scope->symbol_list->length; j++) { 32 | Symbol *symbol = scope->symbol_list->elements[j]; 33 | 34 | List *initializers = symbol->initializers; 35 | if (initializers) { 36 | for (int j = 0; j < initializers->length; j++) { 37 | Initializer *in = initializers->elements[j]; 38 | if (in->data) wfree(in->data); 39 | wfree(in); 40 | } 41 | 42 | free_list(initializers); 43 | } 44 | 45 | wfree(symbol); 46 | } 47 | 48 | free_list(scope->symbol_list); 49 | free_strmap(scope->symbols); 50 | free_strmap(scope->tags); 51 | 52 | wfree(scope); 53 | } 54 | 55 | free_list(allocated_scopes); 56 | 57 | for (int i = 0; i < allocated_tags->length; i++) wfree(allocated_tags->elements[i]); 58 | free_list(allocated_tags); 59 | } 60 | 61 | // Initialize a local scope and set cur_scope as the parent 62 | void enter_scope(void) { 63 | Scope *scope = wcalloc(1, sizeof(Scope)); 64 | append_to_list(allocated_scopes, scope); 65 | scope->symbol_list = new_list(128); 66 | scope->symbols = new_strmap(); 67 | scope->tags = new_strmap(); 68 | scope->parent = cur_scope; 69 | 70 | cur_scope = scope; 71 | } 72 | 73 | // Leave the current scope and go back up to the parent scope 74 | void exit_scope(void) { 75 | cur_scope = cur_scope->parent; 76 | if (!cur_scope) panic("Attempt to exit the global scope"); 77 | } 78 | 79 | // Add a symbol to the current scope 80 | Symbol *new_symbol(char *identifier) { 81 | Symbol *symbol = wcalloc(1, sizeof(Symbol)); 82 | symbol->identifier = identifier; 83 | append_to_list(cur_scope->symbol_list, symbol); 84 | strmap_put(cur_scope->symbols, identifier, symbol); 85 | symbol->scope = cur_scope; 86 | 87 | return symbol; 88 | } 89 | 90 | // Search for a symbol in a scope and recurse to parents if not found. 91 | // Returns zero if not found in any parents 92 | Symbol *lookup_symbol(char *name, Scope *scope, int recurse) { 93 | Symbol *symbol = strmap_get(scope->symbols, name); 94 | if (symbol) return symbol; 95 | else if (recurse && scope->parent) return lookup_symbol(name, scope->parent, recurse); 96 | else return 0; 97 | } 98 | 99 | Tag *new_tag(char *identifier) { 100 | Tag *tag = wcalloc(1, sizeof(Tag)); 101 | append_to_list(allocated_tags, tag); 102 | tag->identifier = identifier; 103 | strmap_put(cur_scope->tags, identifier, tag); 104 | 105 | return tag; 106 | } 107 | 108 | // Search for a tag in a scope and recurse to parents if not found. 109 | // Returns zero if not found in any parents 110 | Tag *lookup_tag(char *name, Scope *scope, int recurse) { 111 | Tag *tag = strmap_get(scope->tags, name); 112 | if (tag) return tag; 113 | else if (recurse && scope->parent) return lookup_tag(name, scope->parent, recurse); 114 | else return 0; 115 | } 116 | -------------------------------------------------------------------------------- /set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "wcc.h" 6 | 7 | Set *new_set(int max_value) { 8 | Set *result = wmalloc(sizeof(Set)); 9 | result->max_value = max_value; 10 | result->elements = wcalloc(max_value + 1, sizeof(char)); 11 | result->cached_element_count = 0; 12 | result->cached_elements = 0; 13 | 14 | return result; 15 | } 16 | 17 | void free_set(Set *s) { 18 | if (s->cached_elements) wfree(s->cached_elements); 19 | wfree(s->elements); 20 | wfree(s); 21 | } 22 | 23 | void empty_set(Set *s) { 24 | memset(s->elements, 0, (s->max_value + 1) * sizeof(char)); 25 | } 26 | 27 | Set *copy_set(Set *s) { 28 | Set *result = new_set(s->max_value); 29 | memcpy(result->elements, s->elements, (s->max_value + 1) * sizeof(char)); 30 | 31 | return result; 32 | } 33 | 34 | void copy_set_to(Set *dst, Set *src) { 35 | memcpy(dst->elements, src->elements, (src->max_value + 1) * sizeof(char)); 36 | } 37 | 38 | void cache_set_elements(Set *s) { 39 | if (!s->cached_elements) s->cached_elements = wmalloc((s->max_value + 1) * sizeof(int)); 40 | int *cached_elements = s->cached_elements; 41 | 42 | int count = 0; 43 | for (int i = 0; i <= s->max_value; i++) 44 | if (s->elements[i]) cached_elements[count++] = i; 45 | 46 | s->cached_element_count = count; 47 | } 48 | 49 | int set_len(Set *s) { 50 | int max_value = s->max_value; 51 | char *elements = s->elements; 52 | int result = 0; 53 | for (int i = 0; i <= max_value; i++) result += elements[i]; 54 | 55 | return result; 56 | } 57 | 58 | void print_set(Set *s) { 59 | int first = 1; 60 | printf("{"); 61 | for (int i = 0; i <= s->max_value; i++) { 62 | if (s->elements[i]) { 63 | if (!first) { printf(", "); } 64 | printf("%d", i); 65 | first = 0; 66 | } 67 | } 68 | printf("}"); 69 | } 70 | 71 | void *delete_from_set(Set *s, int value) { 72 | if (value > s->max_value) panic("Max set value of %d exceeded with %d in delete_from_set", s->max_value, value); 73 | s->elements[value] = 0; 74 | } 75 | 76 | int in_set(Set *s, int value) { 77 | if (value > s->max_value) panic("Max set value of %d exceeded with %d in in_set", s->max_value, value); 78 | return s->elements[value] == 1; 79 | } 80 | 81 | int set_eq(Set *s1, Set *s2) { 82 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_eq"); 83 | 84 | return memcmp(s1->elements, s2->elements, (s1->max_value + 1) * sizeof(char)) ? 0 : 1; 85 | } 86 | 87 | Set *set_intersection(Set *s1, Set *s2) { 88 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_intersection"); 89 | 90 | Set *result = new_set(s1->max_value); 91 | for (int i = 0; i <= s1->max_value; i++) 92 | result->elements[i] = s1->elements[i] && s2->elements[i]; 93 | 94 | return result; 95 | } 96 | 97 | void set_intersection_to(Set *dst, Set *s1, Set *s2) { 98 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_intersection_to"); 99 | if (s1->max_value != dst->max_value) panic("Unequal set sizes in set_intersection_to"); 100 | 101 | for (int i = 0; i <= s1->max_value; i++) 102 | dst->elements[i] = s1->elements[i] && s2->elements[i]; 103 | } 104 | 105 | Set *set_union(Set *s1, Set *s2) { 106 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_union"); 107 | 108 | Set *result = new_set(s1->max_value); 109 | for (int i = 0; i <= s1->max_value; i++) 110 | result->elements[i] = s1->elements[i] || s2->elements[i]; 111 | 112 | return result; 113 | } 114 | 115 | 116 | void set_union_to(Set *dst, Set *s1, Set *s2) { 117 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_union_to"); 118 | if (s1->max_value != dst->max_value) panic("Unequal set sizes in set_union_to"); 119 | 120 | for (int i = 0; i <= s1->max_value; i++) 121 | dst->elements[i] = s1->elements[i] || s2->elements[i]; 122 | } 123 | 124 | Set *set_difference(Set *s1, Set *s2) { 125 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_difference"); 126 | 127 | Set *result = new_set(s1->max_value); 128 | for (int i = 0; i <= s1->max_value; i++) 129 | result->elements[i] = s1->elements[i] && !s2->elements[i]; 130 | 131 | return result; 132 | } 133 | 134 | void set_difference_to(Set *dst, Set *s1, Set *s2) { 135 | if (s1->max_value != s2->max_value) panic("Unequal set sizes in set_difference_to"); 136 | if (s1->max_value != dst->max_value) panic("Unequal set sizes in set_difference_to"); 137 | 138 | for (int i = 0; i <= s1->max_value; i++) 139 | dst->elements[i] = s1->elements[i] && !s2->elements[i]; 140 | } 141 | -------------------------------------------------------------------------------- /stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wcc.h" 4 | 5 | Stack *new_stack(void) { 6 | Stack *result = wmalloc(sizeof(Stack)); 7 | result->elements = wmalloc(MAX_STACK_SIZE * sizeof(int)); 8 | result->pos = MAX_STACK_SIZE; 9 | 10 | return result; 11 | } 12 | 13 | void free_stack(Stack *s) { 14 | wfree(s->elements); 15 | wfree(s); 16 | } 17 | 18 | int stack_top(Stack *s) { 19 | if (s->pos == MAX_STACK_SIZE) panic("Attempt to read top of an empty stack"); 20 | return s->elements[s->pos]; 21 | } 22 | 23 | void push_onto_stack(Stack *s, int v) { 24 | if (s->pos == 0) panic("Ran out of stack space"); 25 | s->pos--; 26 | s->elements[s->pos] = v; 27 | } 28 | 29 | int pop_from_stack(Stack *s) { 30 | if (s->pos == MAX_STACK_SIZE) panic("Attempt to pop off of an empty stack"); 31 | return s->elements[s->pos++]; 32 | } 33 | -------------------------------------------------------------------------------- /strmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "wcc.h" 5 | 6 | enum { 7 | TOMBSTONE = -1, 8 | DEFAULT_SIZE = 16, 9 | MAX_LOAD_FACTOR = 666, // 0.666 * 1000 10 | EXPANSION_FACTOR = 333, // 0.333 * 1000 11 | }; 12 | 13 | 14 | static unsigned int hash(char *str) { 15 | // FNV hash function 16 | unsigned int result = 2166136261; 17 | char *p = str; 18 | while (*p) { 19 | result = (result ^ (*p)) * 16777619; 20 | p++; 21 | } 22 | return result; 23 | } 24 | 25 | static void maybe_rehash(StrMap *map) { 26 | if (map->used_count * 1000 < map->size * MAX_LOAD_FACTOR) return; 27 | 28 | int new_size; 29 | if (map->element_count * 1000 < map->size * EXPANSION_FACTOR) 30 | new_size = map->size; 31 | else 32 | new_size = map->size * 2; 33 | 34 | int mask = new_size - 1; 35 | char **keys = wcalloc(new_size, sizeof(char *)); 36 | void **values = wcalloc(new_size, sizeof(void *)); 37 | 38 | for (int i = 0; i < map->size; i++) { 39 | char *key; 40 | if (!(key = map->keys[i]) || key == (char *) TOMBSTONE) continue; 41 | unsigned int pos = hash(key) & mask; 42 | while (1) { 43 | if (!keys[pos]) { 44 | keys[pos] = key; 45 | values[pos] = map->values[i]; 46 | break; 47 | } 48 | pos = (pos + 1) & mask; 49 | } 50 | } 51 | 52 | wfree(map->keys); 53 | wfree(map->values); 54 | map->keys = keys; 55 | map->values = values; 56 | map->size = new_size; 57 | map->used_count = map->element_count; 58 | } 59 | 60 | void strmap_put(StrMap *map, char *key, void *value) { 61 | maybe_rehash(map); 62 | 63 | unsigned int mask = map->size - 1; 64 | unsigned int pos = hash(key) & mask; 65 | 66 | char *k; 67 | while (1) { 68 | k = map->keys[pos]; 69 | if (!k || k == (char *) TOMBSTONE) { 70 | map->keys[pos] = key; 71 | map->values[pos] = value; 72 | map->element_count++; 73 | if (!k) map->used_count++; 74 | return; 75 | } 76 | 77 | if (!strcmp(k, key)) { 78 | map->values[pos] = value; 79 | return; 80 | } 81 | pos = (pos + 1) & mask; 82 | } 83 | } 84 | 85 | void *strmap_get(StrMap *map, char *key) { 86 | unsigned int mask = map->size - 1; 87 | unsigned int pos = hash(key) & mask; 88 | 89 | char *k; 90 | while ((k = map->keys[pos])) { 91 | if (k != (char *) TOMBSTONE && !strcmp(k, key)) return map->values[pos]; 92 | pos = (pos + 1) & mask; 93 | } 94 | return 0; 95 | } 96 | 97 | void strmap_delete(StrMap *map, char *key) { 98 | unsigned int mask = map->size - 1; 99 | unsigned int pos = hash(key) & mask; 100 | 101 | char *k; 102 | while ((k = map->keys[pos])) { 103 | if (k != (char *) TOMBSTONE && !strcmp(k, key)) { 104 | map->keys[pos] = (char *) TOMBSTONE; 105 | map->values[pos] = 0; 106 | map->element_count--; 107 | return; 108 | } 109 | pos = (pos + 1) & mask; 110 | } 111 | } 112 | 113 | int strmap_iterator_finished(StrMapIterator *iterator) { 114 | return iterator->pos == -1; 115 | } 116 | 117 | void strmap_iterator_next(StrMapIterator *iterator) { 118 | if (iterator->original_size != iterator->map->size) panic("longset size changed during iteration"); 119 | 120 | iterator->pos++; 121 | 122 | while (iterator->pos < iterator->map->size && (!iterator->map->keys[iterator->pos] || iterator->map->keys[iterator->pos] == (char *) TOMBSTONE)) 123 | iterator->pos++; 124 | 125 | if (iterator->pos == iterator->map->size || (!iterator->map->keys[iterator->pos] || iterator->map->keys[iterator->pos] == (char *) TOMBSTONE)) 126 | iterator->pos = -1; 127 | } 128 | 129 | char *strmap_iterator_key(StrMapIterator *iterator) { 130 | if (iterator->pos == -1) panic("Attempt to iterate beyond the end of the iterator"); 131 | return iterator->map->keys[iterator->pos]; 132 | } 133 | 134 | StrMapIterator strmap_iterator(StrMap *map) { 135 | StrMapIterator result; 136 | result.map = map; 137 | result.pos = -1; 138 | result.original_size = map->size; 139 | strmap_iterator_next(&result); 140 | 141 | return result; 142 | } 143 | 144 | StrMap *new_strmap(void) { 145 | StrMap *map = wcalloc(1, sizeof(StrMap)); 146 | map->size = DEFAULT_SIZE; 147 | map->keys = wcalloc(DEFAULT_SIZE, sizeof(void *)); 148 | map->values = wcalloc(DEFAULT_SIZE, sizeof(char *)); 149 | return map; 150 | } 151 | 152 | void free_strmap(StrMap *map) { 153 | wfree(map->keys); 154 | wfree(map->values); 155 | wfree(map); 156 | } 157 | -------------------------------------------------------------------------------- /strset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "wcc.h" 5 | 6 | StrSet *new_strset(void) { 7 | StrSet *ss = wmalloc(sizeof(StrSet)); 8 | ss->strmap = new_strmap(); 9 | 10 | return ss; 11 | } 12 | 13 | void free_strset(StrSet *ss) { 14 | free_strmap(ss->strmap); 15 | wfree(ss); 16 | } 17 | 18 | void strset_add(StrSet *ss, char *element) { 19 | strmap_put(ss->strmap, element, (void *) 1); 20 | } 21 | 22 | int strset_in(StrSet *ss, char *element) { 23 | return !!strmap_get(ss->strmap, element); 24 | } 25 | 26 | StrSet *dup_strset(StrSet *ss) { 27 | StrSet *result = new_strset(); 28 | 29 | for (StrMapIterator it = strmap_iterator(ss->strmap); !strmap_iterator_finished(&it); strmap_iterator_next(&it)) 30 | strmap_put(result->strmap, strmap_iterator_key(&it), (void *) 1); 31 | 32 | return result; 33 | } 34 | 35 | StrSet *strset_union(StrSet *ss1, StrSet *ss2) { 36 | StrSet *result = new_strset(); 37 | 38 | for (StrMapIterator it = strmap_iterator(ss1->strmap); !strmap_iterator_finished(&it); strmap_iterator_next(&it)) 39 | strmap_put(result->strmap, strmap_iterator_key(&it), (void *) 1); 40 | 41 | for (StrMapIterator it = strmap_iterator(ss2->strmap); !strmap_iterator_finished(&it); strmap_iterator_next(&it)) 42 | strmap_put(result->strmap, strmap_iterator_key(&it), (void *) 1); 43 | 44 | return result; 45 | } 46 | 47 | StrSet *strset_intersection(StrSet *ss1, StrSet *ss2) { 48 | StrSet *result = new_strset(); 49 | 50 | for (StrMapIterator it = strmap_iterator(ss1->strmap); !strmap_iterator_finished(&it); strmap_iterator_next(&it)) { 51 | char *key = strmap_iterator_key(&it); 52 | if (strmap_get(ss2->strmap, key)) strmap_put(result->strmap, strmap_iterator_key(&it), (void *) 1); 53 | } 54 | 55 | return result; 56 | } 57 | 58 | void print_strset(StrSet *s) { 59 | if (!s) { 60 | printf("{}"); 61 | return; 62 | } 63 | 64 | int first = 1; 65 | printf("{"); 66 | for (StrMapIterator it = strmap_iterator(s->strmap); !strmap_iterator_finished(&it); strmap_iterator_next(&it)) { 67 | char *key = strmap_iterator_key(&it); 68 | if (!first) { printf(", "); } 69 | printf("%s", key); 70 | first = 0; 71 | } 72 | printf("}"); 73 | } 74 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | all: test-unit test-integration test-e2e test-cpp 2 | 3 | utils.o: ../utils.c 4 | gcc ${GCC_OPTS} -c ../utils.c -o utils.o 5 | 6 | memory.o: ../memory.c 7 | gcc ${GCC_OPTS} -c ../memory.c -o memory.o 8 | 9 | .PHONY: 10 | test-unit: test-utils.s test-lib.o 11 | cd unit && ${MAKE} all 12 | 13 | .PHONY: 14 | test-unit-parser: test-utils.s test-lib.o 15 | cd unit && ${MAKE} run-test-parser 16 | 17 | .PHONY: 18 | test-unit-ssa: test-utils.s test-lib.o 19 | cd unit && ${MAKE} run-test-ssa 20 | 21 | .PHONY: 22 | test-unit-cpp: test-utils.s test-lib.o 23 | cd unit && ${MAKE} run-test-cpp 24 | 25 | .PHONY: 26 | test-unit-types: test-utils.s test-lib.o 27 | cd unit && ${MAKE} run-test-types 28 | 29 | .PHONY: 30 | test-integration: test-utils.s test-lib.o 31 | cd integration && ${MAKE} all 32 | 33 | .PHONY: 34 | test-cpp: 35 | cd cpp && ${MAKE} all 36 | 37 | .PHONY: regen-cpp-tests-output 38 | regen-cpp-tests-output: 39 | cd cpp && ${MAKE} regen-cpp-tests-output 40 | 41 | .PHONY: 42 | test-e2e: test-lib.o utils.o memory.o 43 | cd e2e && ${MAKE} all 44 | 45 | test-lib.o: test-lib.c 46 | gcc ${GCC_OPTS} test-lib.c -c 47 | 48 | test-utils.s: test-utils.c 49 | gcc ${GCC_OPTS} -c -S test-utils.c -o test-utils.s 50 | 51 | clean: 52 | cd unit && ${MAKE} clean 53 | cd integration && ${MAKE} clean 54 | cd e2e && ${MAKE} clean 55 | 56 | @rm -f *.s 57 | @rm -f *.o 58 | @rm -f core 59 | -------------------------------------------------------------------------------- /tests/cpp/.gitignore: -------------------------------------------------------------------------------- 1 | *-result.c 2 | *-result2.c 3 | *-ok 4 | -------------------------------------------------------------------------------- /tests/cpp/Makefile: -------------------------------------------------------------------------------- 1 | CPP_TESTS = \ 2 | empty \ 3 | empty-line \ 4 | one-line \ 5 | backslash-newlines \ 6 | string-literals \ 7 | whitespace \ 8 | hashes \ 9 | one-empty-line \ 10 | empty-line-spacing \ 11 | empty-line-spacing-7-lines \ 12 | empty-line-spacing-8-lines \ 13 | empty-line-spacing-9-lines \ 14 | empty-line-spacing-18-38-lines \ 15 | empty-line-spacing-42-lines \ 16 | token-spacing \ 17 | object-like-macros \ 18 | function-like-macros \ 19 | newlines-and-macros \ 20 | stringizing-operator \ 21 | token-paste-operator \ 22 | conditional-includes \ 23 | comments \ 24 | inception1 \ 25 | includes \ 26 | line \ 27 | c99-examples \ 28 | null \ 29 | pragma 30 | 31 | 32 | CPP_TESTS_INCLUDES = \ 33 | include.h \ 34 | inception2.h \ 35 | inception3.h 36 | 37 | OK_FILENAMES := $(addsuffix -ok, ${CPP_TESTS}) 38 | RESULT_FILENAMES := $(addsuffix -result.c, ${CPP_TESTS}) 39 | 40 | 41 | all: ${OK_FILENAMES} 42 | 43 | %-ok: %.c %-output.c ../../wcc ${CPP_TESTS_INCLUDES} 44 | @# Run preprocessor & diff with expected result 45 | ../../wcc -E $< -o $*-result.c 46 | diff $*-output.c $*-result.c 47 | 48 | @# check re-preprocessing produces the same result 49 | ../../wcc -E $*-result.c -o $*-result2.c 50 | diff -I '^#' $*-result.c $*-result2.c 51 | 52 | touch $*-ok 53 | 54 | .PHONY: regen-cpp-tests-output 55 | regen-cpp-tests-output: 56 | $(foreach var,$(CPP_TESTS),../../wcc -E $(var).c -o $(var)-output.c;) 57 | 58 | clean: 59 | @rm -f *-result*.c 60 | @rm -f *-ok 61 | -------------------------------------------------------------------------------- /tests/cpp/backslash-newlines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "backslash-newlines.c" 2 | 3 | 4 | 5 | 6 | somethingbackslashed 7 | 8 | 9 | 10 | something backslashed 11 | 12 | 13 | 14 | something backslashed 15 | 16 | 17 | 18 | something backslashed 19 | 20 | 21 | 22 | something backslashed 23 | 24 | 25 | 26 | 27 | something backslashed again 28 | 29 | 30 | 31 | 32 | somethingbackslashed again 33 | 34 | 35 | 36 | 37 | 38 | something backslashed again 39 | 40 | 41 | 42 | 43 | 44 | 1 45 | 46 | 47 | 48 | 49 | 50 | 1 51 | 52 | 53 | 54 | FOO8 55 | 56 | 57 | 58 | somethingbackslashed 59 | 60 | something backslashed 61 | 62 | 63 | something backslashed 64 | 65 | 66 | something backslashed 67 | 68 | 69 | something backslashed 70 | 71 | 72 | something backslashed 73 | 74 | 75 | something backslashed 76 | 77 | 78 | something 79 | 80 | backslashed 81 | 82 | something 83 | 84 | backslashed 85 | 86 | 87 | 88 | something2backslashed 89 | 90 | something2 backslashed 91 | 92 | 93 | 94 | something2 backslashed 95 | 96 | 97 | 98 | something2 backslashed 99 | 100 | 101 | 102 | 103 | 104 | 105 | abcd 106 | 107 | "foo\\bar" 108 | 109 | 110 | "somethingbackslashed" 111 | 112 | 113 | "something backslashed" 114 | 115 | 116 | "something backslashed" 117 | -------------------------------------------------------------------------------- /tests/cpp/backslash-newlines.c: -------------------------------------------------------------------------------- 1 | // Backslash-newlines in directives 2 | 3 | #define FOO1 something\ 4 | backslashed 5 | FOO1 6 | 7 | #define FOO2 something\ 8 | backslashed 9 | FOO2 10 | 11 | #define FOO3 something \ 12 | backslashed 13 | FOO3 14 | 15 | #define FOO4 something \ 16 | backslashed 17 | FOO4 18 | 19 | #define FOO5 something \ 20 | backslashed 21 | FOO5 22 | 23 | #define FOO6 something \ 24 | backslashed \ 25 | again 26 | FOO6 27 | 28 | #define FOO7 something\ 29 | backslashed \ 30 | again 31 | FOO7 32 | 33 | #define FOO8 \ 34 | something \ 35 | backslashed \ 36 | again 37 | FOO8 38 | 39 | #\ 40 | define\ 41 | FOO9\ 42 | 1 43 | FOO9 44 | 45 | #\ 46 | define \ 47 | FOO10 \ 48 | 1 49 | FOO10 50 | 51 | #\ 52 | undef FOO8 53 | FOO8 54 | 55 | // Backslash-newlines in non-directives 56 | something\ 57 | backslashed 58 | 59 | something \ 60 | backslashed 61 | 62 | something\ 63 | backslashed 64 | 65 | something \ 66 | backslashed 67 | 68 | something \ 69 | backslashed 70 | 71 | something \ 72 | backslashed 73 | 74 | something \ 75 | backslashed 76 | 77 | something \ 78 | 79 | backslashed 80 | 81 | something \ 82 | 83 | backslashed 84 | 85 | something2\ 86 | \ 87 | backslashed 88 | 89 | something2\ 90 | \ 91 | backslashed 92 | 93 | something2\ 94 | \ 95 | backslashed 96 | 97 | something2\ 98 | \ 99 | backslashed 100 | 101 | a\ 102 | b\ 103 | c\ 104 | d 105 | 106 | "foo\\bar" 107 | 108 | "something\ 109 | backslashed" 110 | 111 | "something \ 112 | backslashed" 113 | 114 | "something \ 115 | backslashed" 116 | -------------------------------------------------------------------------------- /tests/cpp/c99-examples-output.c: -------------------------------------------------------------------------------- 1 | # 1 "c99-examples.c" 2 | 3 | 4 | 5 | 6 | 7 | char p[] = "x ## y"; 8 | # 24 "c99-examples.c" 9 | f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); 10 | f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); 11 | int i[] = { 1, 23, 4, 5, }; 12 | char c[2][6] = { "hello", "" }; 13 | # 38 "c99-examples.c" 14 | printf("x" "1" "= %d, x" "2" "= %s", x1, x2); 15 | fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); 16 | 17 | "hello"; 18 | "hello" ", world" 19 | 20 | 21 | 22 | int j[] = { 123, 45, 67, 89, 23 | 10, 11, 12, }; 24 | -------------------------------------------------------------------------------- /tests/cpp/c99-examples.c: -------------------------------------------------------------------------------- 1 | // 6.10.3.3.4 2 | #define hash_hash # ## # 3 | #define mkstr(a) # a 4 | #define in_between(a) mkstr(a) 5 | #define join(c, d) in_between(c hash_hash d) 6 | char p[] = join(x, y); 7 | 8 | // 6.10.3.4.5 9 | #define x 3 10 | #define f(a) f(x * (a)) 11 | #undef x 12 | #define x 2 13 | #define g f 14 | #define z z[0] 15 | #define h g(~ 16 | #define m(a) a(w) 17 | #define w 0,1 18 | #define t(a) a 19 | #define p() int 20 | #define q(x) x 21 | #define r(x,y) x ## y 22 | #define str(x) # x 23 | 24 | f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); 25 | g(x+(3,4)-w) | h 5) & m(f)^m(m); 26 | p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; 27 | char c[2][6] = { str(hello), str() }; 28 | 29 | // 6.10.3.5.6 30 | #define xstr(s) str(s) 31 | #define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ 32 | x ## s, x ## t) 33 | #define INCFILE(n) vers ## n 34 | #define glue(a, b) a ## b 35 | #define xglue(a, b) glue(a, b) 36 | #define HIGHLOW "hello" 37 | #define LOW LOW ", world" 38 | debug(1, 2); 39 | fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away 40 | == 0) str(: @\n), s); 41 | glue(HIGH, LOW); 42 | xglue(HIGH, LOW) 43 | 44 | // 6.10.3.4.7 45 | #define t2(x,y,z) x ## y ## z 46 | int j[] = { t2(1,2,3), t2(,4,5), t2(6,,7), t2(8,9,), 47 | t2(10,,), t2(,11,), t2(,,12), t2(,,) }; 48 | -------------------------------------------------------------------------------- /tests/cpp/comments-output.c: -------------------------------------------------------------------------------- 1 | # 1 "comments.c" 2 | 3 | 4 | 5 | 1 6 | 1 7 | 8 | 9 | 10 | y 11 | 12 | 13 | z 14 | 15 | 16 | 17 | 18 | 19 | y 20 | 21 | y 22 | 23 | y 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | y bar 32 | y bar 33 | y bar 34 | y bar 35 | y bar 36 | y bar 37 | 38 | y bar 39 | 40 | y bar 41 | 42 | y bar 43 | 44 | y bar 45 | 46 | 47 | y bar 48 | 49 | y bar 50 | 51 | y bar 52 | 53 | y bar 54 | 55 | 56 | y bar 57 | 58 | y bar 59 | 60 | y bar 61 | 62 | y bar 63 | 64 | y bar 65 | 66 | 67 | 68 | 69 | foobar 70 | 71 | 72 | 73 | foobar 74 | 75 | This line is to check line numbers are still correct after the last BSNL 76 | 77 | 78 | y bar 79 | 80 | y bar 81 | 82 | y bar 83 | 84 | y bar 85 | 86 | 87 | 88 | y bar 89 | 90 | 91 | y bar 92 | 93 | 94 | y bar 95 | 96 | 97 | y bar 98 | 99 | y bar 100 | # 109 "comments.c" 101 | 2 + 3 102 | ; 103 | 104 | 2 + 3; 105 | 106 | 107 | 2 + 3 108 | 109 | 110 | ; 111 | 112 | 2 + 3; 113 | 114 | 115 | 116 | 117 | 2 + 3; 118 | 119 | 120 | bar1 121 | 122 | 123 | 124 | bar2 125 | 126 | 127 | 1 + 1 128 | 129 | a b 130 | # 148 "comments.c" 131 | 1020 132 | -------------------------------------------------------------------------------- /tests/cpp/comments.c: -------------------------------------------------------------------------------- 1 | // Single line comments 2 | 3 | #define func(x) x // a comment 4 | func(1) 5 | func(1 // a comment 6 | ) 7 | 8 | #define foo y // a comment 9 | foo 10 | 11 | #define foo2 z// a comment 12 | foo2 13 | 14 | #undef NULL /* a comment */ 15 | #undef NULL // a comment 16 | 17 | 18 | foo // a comment 19 | 20 | foo // a comment with as BSNL \ 21 | x 22 | y 23 | 24 | // Multiline comments 25 | 26 | /* 27 | Goodbye world 28 | */ 29 | 30 | foo/* x */bar 31 | foo /* x */bar 32 | foo/* x */ bar 33 | foo /* x */ bar 34 | foo /* x */ bar 35 | foo /* x */ bar 36 | 37 | foo/* x 38 | */bar 39 | foo /* x 40 | */bar 41 | foo/* x 42 | */ bar 43 | foo /* x 44 | */ bar 45 | 46 | foo/* x 47 | */bar 48 | foo /* x 49 | */bar 50 | foo/* x 51 | */ bar 52 | foo /* x 53 | */ bar 54 | 55 | foo/* x \ 56 | */bar 57 | foo /* x \ 58 | */bar 59 | foo/* x \ 60 | */ bar 61 | foo /* x \ 62 | */ bar 63 | foo /* x *\ 64 | / bar 65 | 66 | // Check backslash-newlines are working ok after the above 67 | foo\ 68 | bar 69 | 70 | // Check backslash-newlines are working ok after the above 71 | foo\ 72 | bar 73 | 74 | This line is to check line numbers are still correct after the last BSNL 75 | 76 | #define foobar1 foo/* foo */bar 77 | foobar1 78 | #define foobar2 foo /* foo */bar 79 | foobar2 80 | #define foobar3 foo/* foo */ bar 81 | foobar3 82 | #define foobar4 foo /* foo */ bar 83 | foobar4 84 | 85 | #define foobar4 foo/* foo 86 | */bar 87 | foobar4 88 | #define foobar5 foo /* foo 89 | */bar 90 | foobar5 91 | #define foobar6 foo/* foo 92 | */ bar 93 | foobar6 94 | #define foobar7 foo /* foo 95 | */ bar 96 | foobar7 97 | 98 | foo/* foo 99 | // single line comment 100 | */bar 101 | 102 | /* 103 | Test handling of # token 104 | # 105 | */ 106 | 107 | // Test comments inside macro invocations 108 | #define func2(x,y) x + y 109 | func2(2, 3 // some comments 110 | ); 111 | 112 | func2(2, 3/* 113 | */); 114 | 115 | func2(2, 3 /* 116 | some multiline 117 | comments */ 118 | ); 119 | 120 | func2(2, 3 /* 121 | some multiline 122 | comments 123 | */ ); 124 | 125 | func2(2, /* some comments */ 3); 126 | 127 | #define mlcfoo1 bar1 /* */ 128 | mlcfoo1 129 | 130 | #define mlcfoo2 bar2 /* 131 | */ 132 | mlcfoo2 133 | 134 | #define mlcfoo3(x) x + 1 /* */ 135 | mlcfoo3(1) 136 | 137 | a /* */ /* */ b 138 | 139 | // The convoluted example from https://gcc.gnu.org/onlinedocs/cpp/Initial-processing.html#Initial-processing 140 | // This "code" is masochistically intentionally unreadable. 141 | /\ 142 | * 143 | */ # /* 144 | */ defi\ 145 | ne FO\ 146 | O 10\ 147 | 20 148 | FOO 149 | -------------------------------------------------------------------------------- /tests/cpp/conditional-includes-output.c: -------------------------------------------------------------------------------- 1 | # 1 "conditional-includes.c" 2 | # 26 "conditional-includes.c" 3 | foo 4 | # 37 "conditional-includes.c" 5 | foo 6 | 7 | 8 | 9 | 10 | 11 | foo 12 | # 55 "conditional-includes.c" 13 | foo 14 | 15 | 16 | 17 | 18 | longs are ok 19 | 20 | 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | true 32 | 33 | x 34 | 35 | 36 | 37 | 38 | 39 | foo 40 | # 90 "conditional-includes.c" 41 | foo 42 | 43 | 44 | 45 | 46 | 47 | 48 | foo 49 | # 107 "conditional-includes.c" 50 | bar 51 | 52 | 53 | 54 | 55 | 56 | foo 57 | # 125 "conditional-includes.c" 58 | baz 59 | # 150 "conditional-includes.c" 60 | baz 61 | # 162 "conditional-includes.c" 62 | OBJ 63 | FUNC(1) 64 | 1 65 | # 173 "conditional-includes.c" 66 | foo 67 | 68 | 69 | 70 | 71 | foo 72 | # 188 "conditional-includes.c" 73 | def 74 | 75 | 76 | 77 | 78 | 79 | 80 | def 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | def 89 | 90 | 91 | 92 | def 93 | 94 | 95 | 96 | def 97 | 98 | 99 | 100 | def 101 | 102 | 103 | 104 | def 105 | 106 | 107 | 108 | def 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | !defined undef 117 | # 1 "include.h" 1 118 | Hello from include.h in "include.h" 1 119 | # 100 "include-override" 120 | Hello from include.h again in "include-override" 100 121 | # 259 "conditional-includes.c" 2 122 | # 1 "include.h" 1 123 | Hello from include.h in "include.h" 1 124 | # 100 "include-override" 125 | Hello from include.h again in "include-override" 100 126 | # 262 "conditional-includes.c" 2 127 | -------------------------------------------------------------------------------- /tests/cpp/conditional-includes.c: -------------------------------------------------------------------------------- 1 | // Check keywords work fine as pp-tokens too. 2 | #define TOKEN_TEST1 define 3 | #define TOKEN_TEST2 undef 4 | #define TOKEN_TEST3 if 5 | #define TOKEN_TEST4 ifdef 6 | #define TOKEN_TEST5 ifdnef 7 | #define TOKEN_TEST6 elif 8 | #define TOKEN_TEST7 else 9 | #define TOKEN_TEST8 endif 10 | 11 | // Not defined 12 | #if FOO 13 | foo 14 | #endif 15 | 16 | // Defined & zero 17 | #define FOO 0 18 | #if FOO 19 | foo 20 | #endif 21 | 22 | // Defined & non-zero 23 | #undef FOO 24 | #define FOO 1 25 | #if FOO 26 | foo 27 | 28 | #endif 29 | 30 | // Arithmetic with undef BAR 31 | #if !FOO 32 | notfoo 33 | #endif 34 | 35 | // Arithmetic with undef BAR 36 | #if FOO + BAR 37 | foo 38 | #endif 39 | 40 | // Arithmetic with defined BAR 41 | #define BAR 1 42 | #if FOO + BAR 43 | foo 44 | #endif 45 | 46 | #undef BAR 47 | #define BAR 0 48 | #if FOO * BAR 49 | foo 50 | #endif 51 | 52 | #undef BAR 53 | #define BAR 1 + 'a' 54 | #if BAR 55 | foo 56 | #endif 57 | 58 | // Ensure all integer constants are interpreted as longs 59 | #if 1073741824 * 4 == 4294967296 60 | longs are ok 61 | #endif 62 | 63 | // Nesting with true in the middle 64 | #if FOO 65 | true 66 | #if 0 67 | x 68 | #endif 69 | #endif 70 | 71 | // Nesting with false in the middle 72 | #if FOO 73 | true 74 | #if 1 75 | x 76 | #endif 77 | #endif 78 | 79 | // if/else with FOO 0 80 | #if FOO 81 | foo 82 | #else 83 | bar 84 | #endif 85 | 86 | // if/else with FOO 1 87 | #undef FOO 88 | #define FOO 1 89 | #if FOO 90 | foo 91 | #else 92 | bar 93 | #endif 94 | 95 | // A couple of combinations 96 | #if 1 97 | foo 98 | #elif 1 99 | bar 100 | #else 101 | baz 102 | #endif 103 | 104 | #if 0 105 | foo 106 | #elif 1 107 | bar 108 | #else 109 | baz 110 | #endif 111 | 112 | #if 1 113 | foo 114 | #elif 0 115 | bar 116 | #else 117 | baz 118 | #endif 119 | 120 | #if 0 121 | foo 122 | #elif 0 123 | bar 124 | #else 125 | baz 126 | #endif 127 | 128 | // Some nesting tests 129 | #if 0 130 | #if 1 131 | foo 132 | #elif 1 133 | foo 134 | #else 135 | foo 136 | #if 1 137 | foo 138 | #elif 1 139 | foo 140 | #else 141 | foo 142 | #endif 143 | #endif 144 | #elif 0 145 | bar 146 | #if 1 147 | foo 148 | #endif 149 | #else 150 | baz 151 | #if 0 152 | foo 153 | #endif 154 | #endif 155 | 156 | // Check # directives in a skipped section have no effect 157 | #if 0 158 | #define OBJ 1 159 | #define FUNC(x) x 160 | #undef FOO 161 | #endif 162 | OBJ 163 | FUNC(1) 164 | FOO 165 | 166 | #undef FOO 167 | #ifdef FOO 168 | foo 169 | #endif 170 | 171 | #undef FOO 172 | #ifndef FOO 173 | foo 174 | #endif 175 | 176 | #define FOO 177 | #ifdef FOO 178 | foo 179 | #endif 180 | 181 | #ifndef FOO 182 | foo 183 | #endif 184 | 185 | #undef FOO 186 | #define FOO(x) a 187 | #ifdef FOO 188 | def 189 | #endif 190 | 191 | // Use of defined and defined(...) 192 | #undef UNDEF 193 | #define DEF 194 | #if defined DEF 195 | def 196 | #endif 197 | 198 | #if defined UNDEF 199 | def 200 | #endif 201 | 202 | #if defined(DEF) 203 | def 204 | #endif 205 | 206 | #if defined (DEF) 207 | def 208 | #endif 209 | 210 | #if defined( DEF) 211 | def 212 | #endif 213 | 214 | #if defined(DEF ) 215 | def 216 | #endif 217 | 218 | #if defined ( DEF ) 219 | def 220 | #endif 221 | 222 | #if (defined(DEF)) 223 | def 224 | #endif 225 | 226 | #if defined(DEF) && 0 227 | foo 228 | #endif 229 | 230 | #if !defined UNDEF 231 | !defined undef 232 | #endif 233 | 234 | // defined in the middle of an expression 235 | #if defined(UNDEF) || FOO 236 | foo 237 | #endif 238 | 239 | #if defined UNDEF || FOO 240 | foo 241 | #endif 242 | 243 | #if FOO && defined(DEF) 244 | foo 245 | #endif 246 | 247 | // Ensure the error directive is skipped 248 | #if 0 249 | #error "error" 250 | #endif 251 | 252 | // Ensure the include directive is skipped 253 | #if 0 254 | #include "foo" 255 | #endif 256 | 257 | #define INC1(x) # x 258 | #include INC1(include.h) 259 | 260 | #define INC2 "include.h" 261 | #include INC2 262 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line.c" 2 | foo 3 | 4 | bar 5 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-18-38-lines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing-18-38-lines.c" 2 | a 3 | # 18 "empty-line-spacing-18-38-lines.c" 4 | b 5 | # 38 "empty-line-spacing-18-38-lines.c" 6 | c 7 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-18-38-lines.c: -------------------------------------------------------------------------------- 1 | a 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | b 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | c -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-42-lines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing-42-lines.c" 2 | # 43 "empty-line-spacing-42-lines.c" 3 | x 4 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-42-lines.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | x 44 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-7-lines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing-7-lines.c" 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | x 10 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-7-lines.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | x -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-8-lines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing-8-lines.c" 2 | # 9 "empty-line-spacing-8-lines.c" 3 | x 4 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-8-lines.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | x -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-9-lines-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing-9-lines.c" 2 | # 10 "empty-line-spacing-9-lines.c" 3 | x 4 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-9-lines.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | x 11 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty-line-spacing.c" 2 | 3 | a 4 | 5 | b 6 | 7 | 8 | c 9 | 10 | 11 | 12 | d 13 | 14 | 15 | 16 | 17 | e 18 | 19 | 20 | 21 | 22 | 23 | f 24 | 25 | 26 | 27 | 28 | 29 | 30 | g 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | h 39 | # 46 "empty-line-spacing.c" 40 | i 41 | # 56 "empty-line-spacing.c" 42 | j 43 | # 67 "empty-line-spacing.c" 44 | k 45 | # 79 "empty-line-spacing.c" 46 | l 47 | # 92 "empty-line-spacing.c" 48 | m 49 | 50 | 51 | 52 | 53 | 54 | 55 | 6 directives 56 | # 108 "empty-line-spacing.c" 57 | 7 directives 58 | # 118 "empty-line-spacing.c" 59 | 8 directives 60 | # 127 "empty-line-spacing.c" 61 | 4 directives and 4 white spaces 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 4 directives and 3 white spaces 70 | -------------------------------------------------------------------------------- /tests/cpp/empty-line-spacing.c: -------------------------------------------------------------------------------- 1 | // Test rolling up of newlines 2 | a 3 | 4 | b 5 | 6 | 7 | c 8 | 9 | 10 | 11 | d 12 | 13 | 14 | 15 | 16 | e 17 | 18 | 19 | 20 | 21 | 22 | f 23 | 24 | 25 | 26 | 27 | 28 | 29 | g 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | h 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | i 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | j 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | k 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | l 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | m 93 | #define a 1 94 | #undef a 95 | #define a 1 96 | #undef a 97 | #define a 1 98 | #undef a 99 | 6 directives 100 | 101 | #define a 1 102 | #undef a 103 | #define a 1 104 | #undef a 105 | #define a 1 106 | #undef a 107 | #define a 1 108 | 7 directives 109 | 110 | #undef a 111 | #define a 1 112 | #undef a 113 | #define a 1 114 | #undef a 115 | #define a 1 116 | #undef a 117 | #define a 1 118 | 8 directives 119 | #undef a 120 | 121 | #define a 1 122 | 123 | #undef a 124 | 125 | #define a 1 126 | 127 | 4 directives and 4 white spaces 128 | #undef a 129 | 130 | #define a 1 131 | 132 | #undef a 133 | 134 | #define a 1 135 | 4 directives and 3 white spaces 136 | -------------------------------------------------------------------------------- /tests/cpp/empty-line.c: -------------------------------------------------------------------------------- 1 | foo 2 | 3 | bar 4 | -------------------------------------------------------------------------------- /tests/cpp/empty-output.c: -------------------------------------------------------------------------------- 1 | # 1 "empty.c" 2 | -------------------------------------------------------------------------------- /tests/cpp/empty.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freewilll/wcc/af42c7f73e0852b1a8903ddec241b3896e6bcbfe/tests/cpp/empty.c -------------------------------------------------------------------------------- /tests/cpp/function-like-macros-output.c: -------------------------------------------------------------------------------- 1 | # 1 "function-like-macros.c" 2 | 3 | bar 4 | 5 | 6 | 1 + 1 7 | 1 + 1 8 | 1 + 1 9 | 1 + 1 10 | + 1 11 | 12 | 13 | 1 + 2 14 | + 1 15 | 1 + 16 | + 17 | (,) + 18 | 19 | 20 | 1 + 2 21 | 22 | 23 | 1 + 2 24 | 25 | 26 | 1 + 2 27 | 28 | 29 | 1 + 2 30 | 31 | 32 | 33 | 1 + 2 + z 34 | 35 | 36 | 1 + 2 + 1 * 2 + 1 37 | 38 | 39 | (1, 2) + 3 40 | (1, 2) + ((3)) 41 | ((1, 2)) + ((3)) 42 | ((1, (2))) + ((3)) 43 | 44 | 45 | param2a 46 | param2a+ 47 | param2a + 48 | 49 | 50 | 1 + rec(1) 51 | 52 | 53 | afunc(x) 54 | 55 | 1 + 1 56 | 57 | afunc(1) 58 | 59 | 1 + 2 60 | 61 | afunc(1) 62 | 63 | 64 | 65 | x x 66 | 67 | 68 | x x 69 | x x x 70 | 71 | 72 | x x y x 73 | 74 | 75 | 76 | z * z 77 | 78 | 79 | 80 | 1 + 1 81 | -------------------------------------------------------------------------------- /tests/cpp/function-like-macros.c: -------------------------------------------------------------------------------- 1 | #define noparams() bar 2 | noparams() 3 | 4 | #define param1(x) x + 1 5 | param1(1) 6 | param1 (1) 7 | param1 (1) 8 | param1 (1) 9 | param1() 10 | 11 | #define param2a(x,y) x + y 12 | param2a(1, 2) 13 | param2a(,1) 14 | param2a(1,) 15 | param2a(,) 16 | param2a((,),) 17 | 18 | #define param2b( x,y) x + y 19 | param2b(1, 2) 20 | 21 | #define param2c(x,y ) x + y 22 | param2c(1, 2) 23 | 24 | #define param2d(x ,y ) x + y 25 | param2d(1, 2) 26 | 27 | #define param2e(x, y) x + y 28 | param2e(1, 2) 29 | 30 | #define Z z 31 | #define param2f(x, y) x + y + Z 32 | param2f(1, 2) 33 | 34 | #define param2g(x, y) x + y + param1(x * y) 35 | param2g(1, 2) 36 | 37 | // Test parentheses and command handling in the replacement list 38 | param2a((1, 2), 3) 39 | param2a((1, 2), ((3))) 40 | param2a(((1, 2)), ((3))) 41 | param2a(((1, (2))), ((3))) 42 | 43 | // Test just using the macro without an opening parenthesis leads to no expansion 44 | param2a 45 | param2a+ 46 | param2a + 47 | 48 | #define rec(x) x + rec(x) 49 | rec(1) 50 | 51 | // Test undefs 52 | afunc(x) 53 | #define afunc(x) x + 1 54 | afunc(1) 55 | #undef afunc 56 | afunc(1) 57 | #define afunc(x) x + 2 58 | afunc(1) 59 | #undef afunc 60 | afunc(1) 61 | 62 | // Empty replacement lists 63 | #define erlfoo() 64 | x erlfoo() x 65 | 66 | #define erlfoox(x) x 67 | x erlfoox() x 68 | x erlfoox(x) x 69 | 70 | #define erlfooxy(x, y) x y 71 | x erlfooxy(x, y) x 72 | 73 | // Same formal parameter used twice, combined with an actual parameter which is a macro 74 | #define param_twice(x) x * x 75 | param_twice(Z) 76 | 77 | // Using a CPP keyword as function parameter name 78 | #define foo(line) line + line 79 | foo(1) 80 | -------------------------------------------------------------------------------- /tests/cpp/hashes-output.c: -------------------------------------------------------------------------------- 1 | # 1 "hashes.c" 2 | 3 | char *s = '#x'; 4 | -------------------------------------------------------------------------------- /tests/cpp/hashes.c: -------------------------------------------------------------------------------- 1 | // # x 2 | char *s = '#x'; 3 | -------------------------------------------------------------------------------- /tests/cpp/inception1-output.c: -------------------------------------------------------------------------------- 1 | # 1 "inception1.c" 2 | In inception 1a 3 | # 1 "inception2.h" 1 4 | In inception 2a 5 | # 1 "inception3.h" 1 6 | In inception 3 7 | # 3 "inception2.h" 2 8 | In inception 2b 9 | # 3 "inception1.c" 2 10 | In inception 1b 11 | -------------------------------------------------------------------------------- /tests/cpp/inception1.c: -------------------------------------------------------------------------------- 1 | In inception 1a 2 | #include "inception2.h" 3 | In inception 1b 4 | -------------------------------------------------------------------------------- /tests/cpp/inception1.c-output.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freewilll/wcc/af42c7f73e0852b1a8903ddec241b3896e6bcbfe/tests/cpp/inception1.c-output.c -------------------------------------------------------------------------------- /tests/cpp/inception2.h: -------------------------------------------------------------------------------- 1 | In inception 2a 2 | #include "inception3.h" 3 | In inception 2b 4 | -------------------------------------------------------------------------------- /tests/cpp/inception3.h: -------------------------------------------------------------------------------- 1 | In inception 3 2 | -------------------------------------------------------------------------------- /tests/cpp/include.h: -------------------------------------------------------------------------------- 1 | Hello from include.h in __FILE__ __LINE__ 2 | #line 100 "include-override" 3 | Hello from include.h again in __FILE__ __LINE__ 4 | -------------------------------------------------------------------------------- /tests/cpp/include1.h: -------------------------------------------------------------------------------- 1 | include1 start 2 | __FILE__ __LINE__ 3 | include1 end 4 | -------------------------------------------------------------------------------- /tests/cpp/includes-output.c: -------------------------------------------------------------------------------- 1 | # 1 "includes.c" 2 | "includes.c" 1 3 | before include 4 | # 1 "include1.h" 1 5 | include1 start 6 | "include1.h" 2 7 | include1 end 8 | # 4 "includes.c" 2 9 | after include 10 | "includes.c" 5 11 | 12 | "includes.c" 7 13 | before include again 14 | # 1 "include1.h" 1 15 | include1 start 16 | "include1.h" 2 17 | include1 end 18 | # 10 "includes.c" 2 19 | after include again 20 | "includes.c" 11 21 | # 1 "include1.h" 1 22 | include1 start 23 | "include1.h" 2 24 | include1 end 25 | # 17 "includes.c" 2 26 | -------------------------------------------------------------------------------- /tests/cpp/includes.c: -------------------------------------------------------------------------------- 1 | __FILE__ __LINE__ 2 | before include 3 | #include "include1.h" 4 | after include 5 | __FILE__ __LINE__ 6 | 7 | __FILE__ __LINE__ 8 | before include again 9 | #include "include1.h" 10 | after include again 11 | __FILE__ __LINE__ 12 | 13 | // Test conditional include with a sub-include 14 | #ifndef FOO 15 | #define FOO 16 | #include "include1.h" 17 | #endif 18 | -------------------------------------------------------------------------------- /tests/cpp/line-output.c: -------------------------------------------------------------------------------- 1 | # 1 "line.c" 2 | 1 "line.c" 3 | # 10 "line.c" 4 | 10 "line.c" 5 | # 1 "include.h" 1 6 | Hello from include.h in "include.h" 1 7 | # 100 "include-override" 8 | Hello from include.h again in "include-override" 100 9 | # 12 "line.c" 2 10 | 12 "line.c" 11 | 12 | # 10 "line-renamed.c" 13 | 10 "line-renamed.c" 14 | # 1 "include.h" 1 15 | Hello from include.h in "include.h" 1 16 | # 100 "include-override" 17 | Hello from include.h again in "include-override" 100 18 | # 12 "line-renamed.c" 2 19 | 12 "line-renamed.c" 20 | 21 | 22 | 23 | 24 | 25 | 18 26 | 27 | 28 | # 42 "line-renamed.c" 29 | "line-renamed.c" 42 30 | 31 | 32 | 33 | # 420 "renamed" 34 | "renamed" 420 35 | 36 | 37 | 38 | 1000 39 | # 1000 "renamed" 40 | -------------------------------------------------------------------------------- /tests/cpp/line.c: -------------------------------------------------------------------------------- 1 | __LINE__ __FILE__ 2 | #line 10 3 | __LINE__ __FILE__ 4 | #include "include.h" 5 | __LINE__ __FILE__ 6 | 7 | #line 10 "line-renamed.c" 8 | __LINE__ __FILE__ 9 | #include "include.h" 10 | __LINE__ __FILE__ 11 | 12 | // Ensure skipped directive doesn't change the line 13 | #if 0 14 | #line 10000 15 | #endif 16 | __LINE__ 17 | 18 | #define FOO 42 19 | #line FOO 20 | __FILE__ __LINE__ 21 | 22 | #undef FOO 23 | #define FOO 420 "renamed" 24 | #line FOO 25 | __FILE__ __LINE__ 26 | 27 | #undef line 28 | #define line 1000 29 | line 30 | #line line 31 | #if 1000 != __LINE__ 32 | " # line line" not working 33 | #endif 34 | -------------------------------------------------------------------------------- /tests/cpp/newlines-and-macros-output.c: -------------------------------------------------------------------------------- 1 | # 1 "newlines-and-macros.c" 2 | 3 | 2 * 3; 4 | 5 | 2 * 3; 6 | 7 | 8 | 9 | 2 * 3; 10 | 11 | 2 * 12 | 3; 13 | 14 | 2 15 | * 3; 16 | 17 | 2 18 | * 3; 19 | 20 | 2 * 3 21 | ; 22 | 23 | 2 * 3 24 | ; 25 | 26 | 2 * 3 27 | ; 28 | 29 | 2 * 3 30 | ; 31 | 32 | 2 * 3 33 | ; 34 | 35 | 2 * 3 36 | ; 37 | 38 | 2 * 3 39 | ; 40 | 41 | 42 | 2 43 | * 44 | 3 45 | 46 | ; 47 | 48 | 2 * 3 49 | ; 50 | -------------------------------------------------------------------------------- /tests/cpp/newlines-and-macros.c: -------------------------------------------------------------------------------- 1 | #define foo(x, y) x * y 2 | foo(2, 3); 3 | 4 | foo 5 | (2, 3); 6 | 7 | foo( 8 | 2, 3); 9 | 10 | foo(2, 11 | 3); 12 | 13 | foo(2 14 | , 3); 15 | 16 | foo(2 17 | , 3); 18 | 19 | foo(2,3 20 | ); 21 | 22 | foo(2, 3 23 | ); 24 | 25 | foo(2,3 26 | ); 27 | 28 | foo(2, 3 29 | ); 30 | 31 | foo(2, 3 32 | ); 33 | 34 | foo(2, 3 35 | ) ; 36 | 37 | foo(2, 3 38 | ) ; 39 | 40 | foo 41 | ( 42 | 2 43 | , 44 | 3 45 | ); 46 | 47 | foo(2, 3 48 | ); 49 | -------------------------------------------------------------------------------- /tests/cpp/null-output.c: -------------------------------------------------------------------------------- 1 | # 1 "null.c" 2 | foo 3 | 4 | bar 5 | -------------------------------------------------------------------------------- /tests/cpp/null.c: -------------------------------------------------------------------------------- 1 | foo 2 | # 3 | bar 4 | -------------------------------------------------------------------------------- /tests/cpp/object-like-macros-output.c: -------------------------------------------------------------------------------- 1 | # 1 "object-like-macros.c" 2 | 3 | foo bar 4 | 5 | FOO 6 | 7 | foo2 bar2 8 | 9 | FOO 10 | 11 | 12 | 1 13 | 14 | 15 | 2 16 | 17 | 18 | "string" 19 | 20 | 21 | string2 22 | 23 | 24 | 'c' 25 | 26 | 27 | 'c' + 1 28 | 29 | 30 | "lots" 'o' f tokens 31 | 32 | 33 | SELF1 34 | 35 | 36 | 37 | x 38 | y 39 | 40 | 41 | 1 2 'c' 'c' + 1 42 | 43 | 44 | 1 2 'c' 'c' + 1 SELF1 45 | 46 | 47 | a b 48 | a b 49 | a b 50 | a b 51 | a b 52 | a b 53 | a 54 | a 55 | a 56 | 57 | A # in the middle of a line 58 | 59 | 60 | 61 | (stuff in parentheses) 62 | (stuff in parentheses)() 63 | (stuff in parentheses)(a) 64 | 65 | 66 | 1 67 | "object-like-macros.c" 68 | 67 69 | 1 70 | 1 71 | 1 72 | 2 73 | -------------------------------------------------------------------------------- /tests/cpp/object-like-macros.c: -------------------------------------------------------------------------------- 1 | #define FOO foo bar 2 | FOO 3 | #undef FOO 4 | FOO 5 | #define FOO foo2 bar2 6 | FOO 7 | #undef FOO with more tokens 8 | FOO 9 | 10 | #define INT1 1 11 | INT1 12 | 13 | #define INT2 2 14 | INT2 15 | 16 | #define STR1 "string" 17 | STR1 18 | 19 | #define STR2 string2 20 | string2 21 | 22 | #define CHR1 'c' 23 | 'c' 24 | 25 | #define CHR2 'c' + 1 26 | CHR2 27 | 28 | #define LOTS_OF_TOKENS1 "lots" 'o' f tokens 29 | LOTS_OF_TOKENS1 30 | 31 | #define SELF1 SELF1 32 | SELF1 33 | 34 | #define x y 35 | #define y x 36 | x 37 | y 38 | 39 | #define COMBO INT1 INT2 CHR1 CHR2 40 | COMBO 41 | 42 | #define COMBO2 COMBO SELF1 43 | COMBO2 44 | 45 | #define EMPTY 46 | a EMPTY b 47 | a EMPTY b 48 | a EMPTY EMPTY b 49 | a EMPTY EMPTY b 50 | a EMPTY EMPTY b 51 | a EMPTY EMPTY b 52 | EMPTY a 53 | EMPTY EMPTY a 54 | EMPTY EMPTY a 55 | 56 | A # in the middle of a line 57 | 58 | // Check an object like macro can be defined with a replacement list staring with a ( 59 | #define OBJ (stuff in parentheses) 60 | OBJ 61 | OBJ() 62 | OBJ(a) 63 | 64 | // Builtin macros 65 | __STDC__ 66 | __FILE__ 67 | __LINE__ 68 | __x86_64__ 69 | __LP64__ 70 | __linux__ 71 | __GNUC__ 72 | __USER_LABEL_PREFIX__ 73 | -------------------------------------------------------------------------------- /tests/cpp/one-empty-line-output.c: -------------------------------------------------------------------------------- 1 | # 1 "one-empty-line.c" 2 | -------------------------------------------------------------------------------- /tests/cpp/one-empty-line.c: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/cpp/one-line-output.c: -------------------------------------------------------------------------------- 1 | # 1 "one-line.c" 2 | int main() {} 3 | -------------------------------------------------------------------------------- /tests/cpp/one-line.c: -------------------------------------------------------------------------------- 1 | int main() {} -------------------------------------------------------------------------------- /tests/cpp/pragma-output.c: -------------------------------------------------------------------------------- 1 | # 1 "pragma.c" 2 | foo 3 | 4 | 5 | bar 6 | -------------------------------------------------------------------------------- /tests/cpp/pragma.c: -------------------------------------------------------------------------------- 1 | foo 2 | #pragma 3 | #pragma goo 4 | bar 5 | -------------------------------------------------------------------------------- /tests/cpp/string-literals-output.c: -------------------------------------------------------------------------------- 1 | # 1 "string-literals.c" 2 | "foo bar" 3 | "foo ' bar" 4 | "foo \" bar" 5 | "foo // bar" 6 | "foo /* */ bar" 7 | "foo/bar" 8 | "foo" "bar" 9 | "foo\\bar" 10 | L"foo\\bar" 11 | 'a' 12 | '\'' 13 | 'a//b' 14 | 'a/* */b' 15 | 'a\\b' 16 | L'a' 17 | -------------------------------------------------------------------------------- /tests/cpp/string-literals.c: -------------------------------------------------------------------------------- 1 | "foo bar" 2 | "foo ' bar" 3 | "foo \" bar" 4 | "foo // bar" 5 | "foo /* */ bar" 6 | "foo/bar" 7 | "foo" "bar" 8 | "foo\\bar" 9 | L"foo\\bar" 10 | 'a' 11 | '\'' 12 | 'a//b' 13 | 'a/* */b' 14 | 'a\\b' 15 | L'a' 16 | -------------------------------------------------------------------------------- /tests/cpp/stringizing-operator-output.c: -------------------------------------------------------------------------------- 1 | # 1 "stringizing-operator.c" 2 | 3 | "1" 4 | "1 2" 5 | "1 \"foo\" 'c'" 6 | "1 'c'" 7 | 8 | 9 | 10 | "EMPTY" 11 | "foo" 12 | "foo bar" 13 | "foo bar" 14 | "foo bar" 15 | "foo bar" 16 | "\"foo\"" 17 | "\"foo\\\"\"" 18 | "" 19 | "||" 20 | "!&" 21 | "*^+" 22 | "* ^ +" 23 | "* ^ +" 24 | "* ^ +" 25 | "* ^ +" 26 | "\n" 27 | "\t" 28 | "\p" 29 | "\\" 30 | "\~" 31 | "\*" 32 | "\\*" 33 | "'\\n'" 34 | "\"\\n\"" 35 | "\"\\\\n\"" 36 | "\"'\\\\n'\"" 37 | "\"\\\"\\\\n\\\"\"" 38 | "\"\\\\n\"" 39 | "\"'\\\\n'\"" 40 | "\"\\\"\\\\n\\\"\"" 41 | "\"\\\"\\\\\\\\n\\\"\"" 42 | "\"\\\"'\\\\\\\\n'\\\"\"" 43 | "\"\\\"\\\\\\\"\\\\\\\\n\\\\\\\"\\\"\"" 44 | 45 | 46 | "foo" 47 | 48 | 49 | "EMPTY" "" 50 | 51 | 52 | 53 | printf_s("In quotes in the printf function call" "\n" ); 54 | printf_s("\"In quotes when printed to the screen\"" "\n" ); 55 | printf_s("\"This: \\\" prints an escaped double quote\"" "\n" ); 56 | 57 | 58 | 59 | 60 | 61 | "F B" 62 | "abc def" 63 | 64 | 65 | "x y" 66 | 67 | x 68 | 69 | 70 | "x y" 71 | 72 | x 73 | 74 | 75 | "1" 76 | -------------------------------------------------------------------------------- /tests/cpp/stringizing-operator.c: -------------------------------------------------------------------------------- 1 | #define FOO(x) # x 2 | FOO(1 ) 3 | FOO(1 2) 4 | FOO(1 "foo" 'c') 5 | FOO(1 'c') 6 | 7 | #define EMPTY 8 | #define str(x) # x 9 | str(EMPTY) 10 | str(foo) 11 | str(foo bar) 12 | str(foo bar) 13 | str(foo bar) 14 | str( foo bar ) 15 | str("foo") 16 | str("foo\"") 17 | str() 18 | str(||) 19 | str(!&) 20 | str(*^+) 21 | str(* ^ +) 22 | str( * ^ +) 23 | str(* ^ + ) 24 | str( * ^ + ) 25 | str(\n) 26 | str(\t) 27 | str(\p) 28 | str(\\) 29 | str(\~) 30 | str(\*) 31 | str(\\*) 32 | str('\n') 33 | str("\n") 34 | str("\\n") 35 | str("'\\n'") 36 | str("\"\\n\"") 37 | str("\\n") 38 | str("'\\n'") 39 | str("\"\\n\"") 40 | str("\"\\\\n\"") 41 | str("\"'\\\\n'\"") 42 | str("\"\\\"\\\\n\\\"\"") 43 | 44 | #define stre(x) EMPTY # x EMPTY 45 | stre(foo) 46 | 47 | #define str2(x, y) # x # y 48 | str2(EMPTY,) 49 | 50 | // From https://msdn.microsoft.com/en-us/library/7e3a913x.aspx 51 | #define stringer( x ) printf_s( #x "\n" ) 52 | stringer( In quotes in the printf function call ); 53 | stringer( "In quotes when printed to the screen" ); 54 | stringer( "This: \" prints an escaped double quote" ); 55 | 56 | #define F abc 57 | #define B def 58 | #define FB(arg) #arg 59 | #define FB1(arg) FB(arg) 60 | FB(F B) 61 | FB1(F B) 62 | 63 | #define str(x) # x 64 | str(x 65 | y) 66 | x 67 | 68 | #define str(x) # x 69 | str(x 70 | y) 71 | x 72 | 73 | #define stringify(x) #x 74 | stringify(1 75 | ) 76 | -------------------------------------------------------------------------------- /tests/cpp/token-paste-operator-output.c: -------------------------------------------------------------------------------- 1 | # 1 "token-paste-operator.c" 2 | 3 | 4 | a bc d 5 | e a bc d 6 | a bc d f 7 | e a bc d f 8 | 9 | 10 | a bc de f 11 | g a bc de f 12 | a bc de f h 13 | g a bc de f h 14 | # 24 "token-paste-operator.c" 15 | f # x 16 | 17 | 18 | f # 19 | 20 | foo bar f # x f # 21 | 22 | 23 | foo 24 | bar 25 | f # x 26 | f # 27 | 28 | 29 | 30 | 31 | a 32 | b 33 | ab 34 | 35 | c 36 | c a 37 | c b 38 | c ab 39 | 40 | d 41 | a d 42 | b d 43 | ab d 44 | 45 | 46 | 47 | a 48 | b 49 | c 50 | ab 51 | ac 52 | bc 53 | abc 54 | 55 | 56 | 57 | a 58 | b 59 | c 60 | ab 61 | ac 62 | bc 63 | abc 64 | 65 | 66 | a1 67 | 1 68 | 69 | 1a 70 | 1 71 | 72 | 1a2 73 | 74 | 75 | 76 | && || == != <= >= += -= *= /= %= &= |= ^= -> >>= <<= ... ++ -- << >> 77 | 78 | 79 | 80 | 81 | aa; 82 | 83 | 84 | 85 | 86 | xy 87 | -------------------------------------------------------------------------------- /tests/cpp/token-paste-operator.c: -------------------------------------------------------------------------------- 1 | // Object-like 2 | #define obj_paste a b ## c d 3 | obj_paste 4 | e obj_paste 5 | obj_paste f 6 | e obj_paste f 7 | 8 | #define obj_paste2 a b ## c d ## e f 9 | obj_paste2 10 | g obj_paste2 11 | obj_paste2 h 12 | g obj_paste2 h 13 | 14 | // Evil examples from cwcc. I disabled them since the output doesn't get reprocessed 15 | // idempotently. No sane person would do these things anyways since the output is 16 | // interpreted as directives. 17 | // #define foo # x 18 | // foo 19 | 20 | // #define bar # 21 | // bar 22 | 23 | #define foo2 f # x 24 | foo2 25 | 26 | #define bar2 f # 27 | bar2 28 | 29 | foo bar foo2 bar2 30 | 31 | #define EMPTY 32 | EMPTY foo 33 | EMPTY bar 34 | EMPTY foo2 35 | EMPTY bar2 36 | 37 | // Function-like 38 | #define func_paste(x, y) x ## y 39 | func_paste(,) 40 | func_paste(a,) 41 | func_paste(,b) 42 | func_paste(a,b) 43 | 44 | c func_paste(,) 45 | c func_paste(a,) 46 | c func_paste(,b) 47 | c func_paste(a,b) 48 | 49 | func_paste(,) d 50 | func_paste(a,) d 51 | func_paste(,b) d 52 | func_paste(a,b) d 53 | 54 | #define func_paste2(x, y, z) x ## y ## z 55 | func_paste2(,,) 56 | func_paste2(a,,) 57 | func_paste2(,b,) 58 | func_paste2(,,c) 59 | func_paste2(a,b,) 60 | func_paste2(a,,c) 61 | func_paste2(,b,c) 62 | func_paste2(a,b,c) 63 | 64 | #define func_paste3(x, y, z) EMPTY func_paste2(x, y, z) 65 | func_paste3(,,) 66 | func_paste3(a,,) 67 | func_paste3(,b,) 68 | func_paste3(,,c) 69 | func_paste3(a,b,) 70 | func_paste3(a,,c) 71 | func_paste3(,b,c) 72 | func_paste3(a,b,c) 73 | 74 | #define func_paste4a(x) x ## 1 75 | func_paste4a(a) 76 | func_paste4a() 77 | #define func_paste4b(x) 1 ## x 78 | func_paste4b(a) 79 | func_paste4b() 80 | #define func_paste4c(x, y) 1 ## x ## 2 81 | func_paste4c(a,b) 82 | 83 | // Ensure multi character tokens are lexed correctly 84 | #define OPS && || == != <= >= += -= *= /= %= &= |= ^= -> >>= <<= ... ++ -- << >> 85 | OPS 86 | 87 | // Bug where replacement list was turned into a circular linked list 88 | // love you baby Licious 89 | #define A(X) X ## X; 90 | A(a) 91 | 92 | // From c-testsuite 00201.c 93 | #define CAT(a,b) a##b 94 | #define AB(x) CAT(x,y) 95 | CAT(A,B)(x) 96 | -------------------------------------------------------------------------------- /tests/cpp/token-spacing-output.c: -------------------------------------------------------------------------------- 1 | # 1 "token-spacing.c" 2 | 3 | 4 | 5 | + + 6 | 7 | 8 | 9 | 10 | 11 | 12 | + + - - + + = = = 13 | 14 | 15 | sum = 1 + 2 +3;; 16 | 17 | 18 | 19 | [baz] 20 | 21 | 22 | 23 | 24 | [ baz]; 25 | 26 | 27 | baz 28 | baz 29 | 30 | 31 | baz 32 | 33 | 34 | 35 | foo3 36 | baz3 37 | 38 | 39 | = = 40 | = = 41 | = = = 42 | 43 | 44 | 45 | 46 | & & & & 47 | 48 | 49 | 50 | | | | | 51 | 52 | 53 | 54 | = = = = 55 | 56 | 57 | 58 | ! = 59 | 60 | 61 | 62 | < = 63 | 64 | 65 | 66 | > = 67 | 68 | 69 | 70 | + + 71 | 72 | 73 | 74 | - - 75 | 76 | 77 | 78 | + ++ 79 | 80 | 81 | 82 | - -- 83 | 84 | 85 | 86 | +++ 87 | 88 | 89 | 90 | --- 91 | 92 | 93 | 94 | + = 95 | 96 | 97 | 98 | - = 99 | 100 | 101 | 102 | * = 103 | 104 | 105 | 106 | / = 107 | 108 | 109 | 110 | % = 111 | 112 | 113 | 114 | & = 115 | 116 | 117 | 118 | | = 119 | 120 | 121 | 122 | ^ = 123 | 124 | 125 | 126 | - > 127 | 128 | 129 | 130 | > > 131 | 132 | 133 | 134 | < < 135 | 136 | 137 | 138 | ** 139 | 140 | 141 | 142 | 143 | 144 | . 1 145 | 146 | 147 | 148 | 149 | 150 | a b 151 | 152 | 153 | 154 | 155 | 156 | a 1 157 | 158 | 159 | 160 | 161 | 162 | a "foo" 163 | 164 | 165 | 166 | 167 | 168 | a 'f' 169 | 170 | 171 | 172 | 173 | 174 | 1 a 175 | 176 | 177 | 178 | 179 | 180 | 1 2 181 | 182 | 183 | 184 | 185 | 186 | / * 187 | 188 | 189 | 190 | 191 | 192 | "a" "b" 193 | -------------------------------------------------------------------------------- /tests/cpp/token-spacing.c: -------------------------------------------------------------------------------- 1 | // Test leading spaces are handled correctly when combined with macro substitution 2 | #define p + 3 | #define q + 4 | p q 5 | 6 | // From https://gcc.gnu.org/onlinedocs/cppinternals/Token-Spacing.html#Token-Spacing 7 | 8 | #define PLUS + 9 | #define EMPTY 10 | #define f(x) =x= 11 | +PLUS -EMPTY- PLUS+ f(=) 12 | 13 | #define add(x, y, z) x + y +z; 14 | sum = add (1,2, 3); 15 | 16 | #define foo bar 17 | #define bar baz 18 | [foo] 19 | 20 | #define foo2 bar2 21 | #define bar2 EMPTY baz 22 | #define EMPTY 23 | [foo2] EMPTY; 24 | 25 | #define empty_func(x) EMPTY x 26 | empty_func(foo) 27 | empty_func(foo) 28 | 29 | #define func(x) x 30 | func(foo) 31 | 32 | // From http://www.chiark.greenend.org.uk/doc/cpp-4.3-doc/cppinternals.html 33 | #define foo3() bar3 34 | foo3 35 | baz3 36 | 37 | #define T = 38 | T= 39 | =T 40 | =T= 41 | 42 | // Token paste avoidance 43 | #undef T 44 | #define T & 45 | &T T& 46 | 47 | #undef T 48 | #define T | 49 | |T T| 50 | 51 | #undef T 52 | #define T = 53 | =T T= 54 | 55 | #undef T 56 | #define T ! 57 | T= 58 | 59 | #undef T 60 | #define T < 61 | T= 62 | 63 | #undef T 64 | #define T > 65 | T= 66 | 67 | #undef T 68 | #define T + 69 | T+ 70 | 71 | #undef T 72 | #define T - 73 | T- 74 | 75 | #undef T 76 | #define T + 77 | T++ 78 | 79 | #undef T 80 | #define T - 81 | T-- 82 | 83 | #undef T 84 | #define T ++ 85 | T+ 86 | 87 | #undef T 88 | #define T -- 89 | T- 90 | 91 | #undef T 92 | #define T + 93 | T= 94 | 95 | #undef T 96 | #define T - 97 | T= 98 | 99 | #undef T 100 | #define T * 101 | T= 102 | 103 | #undef T 104 | #define T / 105 | T= 106 | 107 | #undef T 108 | #define T % 109 | T= 110 | 111 | #undef T 112 | #define T & 113 | T= 114 | 115 | #undef T 116 | #define T | 117 | T= 118 | 119 | #undef T 120 | #define T ^ 121 | T= 122 | 123 | #undef T 124 | #define T - 125 | T> 126 | 127 | #undef T 128 | #define T > 129 | T> 130 | 131 | #undef T 132 | #define T < 133 | T< 134 | 135 | #undef T 136 | #define T * 137 | T* 138 | 139 | #undef t 140 | #undef t2 141 | #define t() . 142 | #define t2 1 143 | t()t2 144 | 145 | #undef t 146 | #undef t2 147 | #define t() a 148 | #define t2 b 149 | t()t2 150 | 151 | #undef t 152 | #undef t2 153 | #define t() a 154 | #define t2 1 155 | t()t2 156 | 157 | #undef t 158 | #undef t2 159 | #define t() a 160 | #define t2 "foo" 161 | t()t2 162 | 163 | #undef t 164 | #undef t2 165 | #define t() a 166 | #define t2 'f' 167 | t()t2 168 | 169 | #undef t 170 | #undef t2 171 | #define t() 1 172 | #define t2 a 173 | t()t2 174 | 175 | #undef t 176 | #undef t2 177 | #define t() 1 178 | #define t2 2 179 | t()t2 180 | 181 | #undef t 182 | #undef t2 183 | #define t() / 184 | #define t2 * 185 | t()t2 186 | 187 | #undef t 188 | #undef t2 189 | #define t() "a" 190 | #define t2 "b" 191 | t()t2 192 | -------------------------------------------------------------------------------- /tests/cpp/whitespace-output.c: -------------------------------------------------------------------------------- 1 | # 1 "whitespace.c" 2 | int main() {} 3 | int main() {} 4 | int main() {} 5 | 6 | 7 | int main() {} 8 | int main() {} 9 | int main() {} 10 | int main() {} 11 | 12 | 13 | int main() {} 14 | int main() {} 15 | 16 | 17 | int main() {} 18 | int main() {} 19 | int main() {} 20 | int main() {} 21 | 22 | 23 | \f Form feed 24 | \v vertical tab 25 | -------------------------------------------------------------------------------- /tests/cpp/whitespace.c: -------------------------------------------------------------------------------- 1 | int main() {} 2 | int main() {} 3 | int main() {} 4 | 5 | // Leading spaces 6 | int main() {} 7 | int main() {} 8 | int main() {} 9 | int main() {} 10 | 11 | // Leading tabs 12 | int main() {} 13 | int main() {} 14 | 15 | // Leading spaces & tabs 16 | int main() {} 17 | int main() {} 18 | int main() {} 19 | int main() {} 20 | 21 | // \f and \v 22 | \f Form feed 23 | \v vertical tab 24 | -------------------------------------------------------------------------------- /tests/e2e/.gitignore: -------------------------------------------------------------------------------- 1 | run-test-*-wcc 2 | run-test-*-gcc 3 | run-test-abi 4 | run-test-shlib 5 | test-*-wcc 6 | test-*-gcc 7 | gen-test-arithmetic-types-move-torture 8 | test-arithmetic-types-move-torture.c 9 | gen-test-arithmetic-torture 10 | test-arithmetic-torture.c 11 | test-include/test-include 12 | wcc-tests.rulecov 13 | test-reg-move-torture.c 14 | test-abi-gcc-gcc 15 | test-abi-wcc-gcc 16 | test-abi-gcc-wcc 17 | test-abi-wcc-wcc 18 | libtest-shlib-lib-gcc.so 19 | libtest-shlib-lib-wcc.so 20 | test-shlib-gcc-gcc 21 | test-shlib-wcc-gcc 22 | test-shlib-gcc-wcc 23 | test-shlib-wcc-wcc 24 | -------------------------------------------------------------------------------- /tests/e2e/gen-test-arithmetic-torture.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Test arithmetic for all kinds of combinations 6 | 7 | char **vars; 8 | int *is_int; 9 | char **str_types; 10 | int *types; 11 | int *storage; 12 | char **str_storage; 13 | char **str_values; 14 | long double *ld_values; 15 | char **asserts; 16 | 17 | enum { 18 | COUNT = 12, 19 | }; 20 | 21 | enum { 22 | CONSTANT = 1, 23 | LOCAL = 2, 24 | GLOBAL = 3, 25 | }; 26 | 27 | enum { 28 | TYPE_INT = 0, 29 | TYPE_FLOAT, 30 | TYPE_DOUBLE, 31 | TYPE_LD, 32 | }; 33 | 34 | void output_value(void *f, int index) { 35 | if (storage[index] == CONSTANT) 36 | fprintf(f, "%s", str_values[index]); 37 | else 38 | fprintf(f, "%s", vars[index]); 39 | } 40 | 41 | int main() { 42 | void *f; 43 | 44 | types = malloc(sizeof(char *) * COUNT); 45 | vars = malloc(sizeof(char *) * COUNT); 46 | is_int = malloc(sizeof(int) * COUNT); 47 | str_types = malloc(sizeof(char *) * COUNT); 48 | storage = malloc(sizeof(int) * COUNT); 49 | str_storage = malloc(sizeof(char *) * 4); 50 | str_values = malloc(sizeof(char *) * COUNT); 51 | ld_values = malloc(sizeof(long double) * COUNT); 52 | types = malloc(sizeof(int) * COUNT); 53 | asserts = malloc(sizeof(char *) * 4); 54 | 55 | str_types[ 0] = "int"; vars[ 0] = "i"; types[ 0] = TYPE_INT; storage[ 0] = LOCAL; str_values[ 0] = "1"; ld_values[ 0] = 1; 56 | str_types[ 1] = "float"; vars[ 1] = "f"; types[ 1] = TYPE_FLOAT; storage[ 1] = LOCAL; str_values[ 1] = "2.1f"; ld_values[ 1] = 2.1; 57 | str_types[ 2] = "double"; vars[ 2] = "d"; types[ 2] = TYPE_DOUBLE; storage[ 2] = LOCAL; str_values[ 2] = "3.1"; ld_values[ 2] = 3.1; 58 | str_types[ 3] = "long double"; vars[ 3] = "ld"; types[ 3] = TYPE_LD; storage[ 3] = LOCAL; str_values[ 3] = "4.1l"; ld_values[ 3] = 4.1; 59 | str_types[ 4] = "int"; vars[ 4] = "gi"; types[ 4] = TYPE_INT; storage[ 4] = GLOBAL; str_values[ 4] = "5"; ld_values[ 4] = 5; 60 | str_types[ 5] = "float"; vars[ 5] = "gf"; types[ 5] = TYPE_FLOAT; storage[ 5] = GLOBAL; str_values[ 5] = "6.1f"; ld_values[ 5] = 6.1; 61 | str_types[ 6] = "double"; vars[ 6] = "gd"; types[ 6] = TYPE_DOUBLE; storage[ 6] = GLOBAL; str_values[ 6] = "7.1"; ld_values[ 6] = 7.1; 62 | str_types[ 7] = "long double"; vars[ 7] = "gld"; types[ 7] = TYPE_LD; storage[ 7] = GLOBAL; str_values[ 7] = "8.1l"; ld_values[ 7] = 8.1; 63 | str_types[ 8] = "int"; vars[ 8] = 0; types[ 8] = TYPE_INT; storage[ 8] = CONSTANT; str_values[ 8] = "9"; ld_values[ 8] = 9; 64 | str_types[ 9] = "float"; vars[ 9] = 0; types[ 9] = TYPE_FLOAT; storage[ 9] = CONSTANT; str_values[ 9] = "10.1f"; ld_values[ 9] = 10.1; 65 | str_types[10] = "double"; vars[10] = 0; types[10] = TYPE_DOUBLE; storage[10] = CONSTANT; str_values[10] = "11.1"; ld_values[10] = 11.1; 66 | str_types[11] = "long double"; vars[11] = 0; types[11] = TYPE_LD; storage[11] = CONSTANT; str_values[11] = "12.1l"; ld_values[11] = 12.1; 67 | 68 | asserts[ 0] = "assert_int"; 69 | asserts[ 1] = "assert_float"; 70 | asserts[ 2] = "assert_double"; 71 | asserts[ 3] = "assert_long_double"; 72 | 73 | str_storage[CONSTANT] = "constant"; 74 | str_storage[LOCAL] = "local"; 75 | str_storage[GLOBAL] = "global"; 76 | 77 | f = fopen("test-arithmetic-torture.c", "w"); 78 | 79 | fprintf(f, "#include \n"); 80 | fprintf(f, "#include \n"); 81 | fprintf(f, "\n"); 82 | fprintf(f, "#include \"../test-lib.h\"\n"); 83 | fprintf(f, "\n"); 84 | fprintf(f, "int failures;\n"); 85 | fprintf(f, "int passes;\n"); 86 | fprintf(f, "int verbose;\n"); 87 | fprintf(f, "\n"); 88 | 89 | // Global declarations 90 | for (int i = 0; i < COUNT; i++) 91 | if (storage[i] == GLOBAL) 92 | fprintf(f, "%s %s;\n", str_types[i], vars[i]); 93 | 94 | fprintf(f, "\n"); 95 | 96 | fprintf(f, "int main() {\n"); 97 | 98 | // Local declarations & assignments 99 | for (int i = 0; i < COUNT; i++) 100 | if (storage[i] == LOCAL) 101 | fprintf(f, " %s %s = %s;\n", str_types[i], vars[i], str_values[i]); 102 | 103 | // Global assignments 104 | for (int i = 0; i < COUNT; i++) 105 | if (storage[i] == GLOBAL) fprintf(f, " %s = %s;\n", vars[i], str_values[i]); 106 | 107 | fprintf(f, "\n"); 108 | fprintf(f, " failures = 0;\n"); 109 | fprintf(f, "\n"); 110 | 111 | for (int src = 0; src < COUNT; src++) // src 112 | for (int dst = 0; dst < COUNT; dst++) { // dst 113 | if (storage[dst] == CONSTANT) continue; 114 | 115 | int dst_type = types[dst]; 116 | int src_type = types[src]; 117 | int common_type = dst_type > src_type ? dst_type : src_type; 118 | fprintf(f, " %s(%s + %s, ", asserts[common_type], str_values[src], str_values[dst]); 119 | output_value(f, src); 120 | fprintf(f, " + "); 121 | output_value(f, dst); 122 | fprintf(f, ", \"%s %s + %s %s\");\n",str_storage[storage[src]], str_types[src], str_storage[storage[dst]], str_types[dst]); 123 | } 124 | 125 | fprintf(f, "\n"); 126 | fprintf(f, " if (failures) {\n"); 127 | fprintf(f, " printf(\"Failures: %%d\\n\", failures);\n"); 128 | fprintf(f, " exit(1);\n"); 129 | fprintf(f, " }\n"); 130 | fprintf(f, " else\n"); 131 | fprintf(f, " printf(\"Arithmetic torture tests passed\\n\");\n"); 132 | fprintf(f, "}\n"); 133 | 134 | fclose(f); 135 | } 136 | -------------------------------------------------------------------------------- /tests/e2e/stack-check.c: -------------------------------------------------------------------------------- 1 | int check_stack_alignment() { 2 | // Ensure that the stack pointer is aligned to 16 bytes 3 | 4 | long r0; 5 | 6 | __asm__ __volatile__("movq %%rsp, %%rax\n" : "=&a" (r0) ::); 7 | 8 | return r0 % 16 != 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/e2e/test-abi.h: -------------------------------------------------------------------------------- 1 | struct spf { float f1;}; 2 | struct spd { double d1;}; 3 | struct spdf { double d1; float f1; }; 4 | struct sff { float f1, f2; }; 5 | struct sdd { double d1, d2; }; 6 | struct sffff { float f1, f2, f3, f4; }; 7 | struct sffii { float f1, f2; int i1, i2; }; 8 | struct sffiii { float f1, f2; int i1, i2, i3; }; 9 | struct siiff { int i1, i2; float f1, f2; }; 10 | struct siifff { int i1, i2; float f1, f2, f3; }; 11 | struct sifif { int i1; float f1; int i2; float f2; }; 12 | 13 | struct sc1 { char c1; }; 14 | struct sc2 { char c1, c2; }; 15 | struct sc3 { char c1, c2, c3; }; 16 | struct sc4 { char c1, c2, c3, c4; }; 17 | struct sc5 { char c1, c2, c3, c4, c5; }; 18 | struct sc6 { char c1, c2, c3, c4, c5, c6; }; 19 | struct sc7 { char c1, c2, c3, c4, c5, c6, c7; }; 20 | struct sc8 { char c1, c2, c3, c4, c5, c6, c7, c8; }; 21 | struct sc9 { char c1, c2, c3, c4, c5, c6, c7, c8, c9; }; 22 | 23 | struct si1 { int i1; }; 24 | struct si2 { int i1, i2; }; 25 | struct si3 { int i1, i2, i3; }; 26 | struct si4 { int i1, i2, i3, i4; }; 27 | struct si5 { int i1, i2, i3, i4, i5; }; 28 | struct si6 { int i1, i2, i3, i4, i5, i6; }; 29 | struct si7 { int i1, i2, i3, i4, i5, i6, i7; }; 30 | struct si8 { int i1, i2, i3, i4, i5, i6, i7, i8; }; 31 | struct si9 { int i1, i2, i3, i4, i5, i6, i7, i8, i9; }; 32 | 33 | struct sld2 { long double ld1, ld2; }; 34 | 35 | struct sia2a2 { int i[2][2]; }; 36 | struct sia4 { int i[4]; }; 37 | struct sfa4 { float f[4]; }; 38 | 39 | struct ld3 { long double ld1, ld2, ld3; }; 40 | 41 | // Example from ABI doc v0.98 42 | typedef struct { int a, b; double d; } structparm; 43 | 44 | // An unaligned struct 45 | struct __attribute__ ((__packed__)) us { int i; char c; int j; }; 46 | 47 | void accept_spf(struct spf spf); 48 | void accept_spd(struct spd spd); 49 | void accept_spdf(struct spdf spdf); 50 | void accept_sff(struct sff sff); 51 | void accept_sdd(struct sdd sdd); 52 | void accept_sffff(struct sffff sffff); 53 | void accept_sffii(struct sffii sffii); 54 | void accept_sffiii(struct sffiii sffiii); 55 | void accept_siiff(struct siiff siiff); 56 | void accept_siifff(struct siifff siifff); 57 | void accept_sifif(struct sifif sifif); 58 | 59 | void accept_sc1(struct sc1 sc1); 60 | void accept_sc2(struct sc2 sc2); 61 | void accept_sc3(struct sc3 sc3); 62 | void accept_sc4(struct sc4 sc4); 63 | void accept_sc5(struct sc5 sc5); 64 | void accept_sc6(struct sc6 sc6); 65 | void accept_sc7(struct sc7 sc7); 66 | void accept_sc8(struct sc8 sc8); 67 | void accept_sc9(struct sc9 sc9); 68 | 69 | void accept_si5(struct si5 si5); 70 | void accept_si6(struct si6 si6); 71 | void accept_si7(struct si7 si7); 72 | void accept_si8(struct si8 si8); 73 | void accept_si9(struct si9 si9); 74 | 75 | void accept_i5si4(int i1, int i2, int i3, int i4, int i5, struct si4 si4); 76 | void accept_i5sia4(int i1, int i2, int i3, int i4, int i5, struct sia4 sia4); 77 | void accept_sia2a2(struct sia2a2 sia2a2); 78 | void accept_i5sia2a2(int i1, int i2, int i3, int i4, int i5, struct sia2a2 sia2a2); 79 | void accept_f5sffff(float f1, float f2, float f3, float f4, float f5, struct sffff sffff); 80 | void accept_f5sfa4(float f1, float f2, float f3, float f4, float f5, struct sfa4 sfa4); 81 | 82 | void accept_i7sld2(int i1, int i2, int i3, int i4, int i5, int i6, int i7, struct sld2 sld2); 83 | 84 | void accept_abi_example(int e, int f, structparm s, int g, int h, long double ld, double m, double n, int i, int j, int k); 85 | 86 | void accept_us(struct us us); 87 | 88 | struct spf return_spf(); 89 | struct spf return_spf_from_global(); 90 | struct spf return_spf_from_temp(); 91 | struct spf return_spf_with_params(int i); 92 | struct spd return_spd(); 93 | struct spdf return_spdf(); 94 | struct sff return_sff(); 95 | struct sdd return_sdd(); 96 | struct sffff return_sffff(); 97 | struct sffii return_sffii(); 98 | struct sffiii return_sffiii(); 99 | struct siiff return_siiff(); 100 | struct siifff return_siifff(); 101 | struct sifif return_sifif(); 102 | 103 | struct si1 return_si1(); 104 | struct si2 return_si2(); 105 | struct si3 return_si3(); 106 | struct si4 return_si4(); 107 | struct si5 return_si5(); 108 | 109 | struct si5 return_si5_with_params(int i, float f); 110 | 111 | struct ld3 return_ld3(); 112 | 113 | void accept_array(int a[4]); 114 | 115 | int get_linked_object(); 116 | int get_unlinked_object(); 117 | void set_linked_object(int i); 118 | void set_unlinked_object(int i); 119 | int get_sei(); 120 | void set_sei(int i); 121 | -------------------------------------------------------------------------------- /tests/e2e/test-arrays.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | 6 | int verbose; 7 | int passes; 8 | int failures; 9 | 10 | char gi[10]; 11 | 12 | struct { int i, j; } gastr[10]; 13 | 14 | static void test_sizeof() { 15 | assert_int(12, sizeof("Hello world"), "sizeof Hello world"); 16 | 17 | char *hw = "Hello world"; 18 | assert_string("ello world", hw + 1, "ello world"); 19 | } 20 | 21 | static void test_local_vars() { 22 | int ok; 23 | 24 | char ac[10]; 25 | for (int i = 0; i < 10; i++) ac[i] = (i + 1) * 10; 26 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && ac[i] == (i + 1) * 10; 27 | assert_int(1, ok, "Local char array assignment"); 28 | 29 | short as[10]; 30 | for (int i = 0; i < 10; i++) as[i] = (i + 1) * 10; 31 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && as[i] == (i + 1) * 10; 32 | assert_int(1, ok, "Local short array assignment"); 33 | 34 | int ai[10]; 35 | for (int i = 0; i < 10; i++) ai[i] = (i + 1) * 10; 36 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && ai[i] == (i + 1) * 10; 37 | assert_int(1, ok, "Local int array assignment"); 38 | 39 | long al[10]; 40 | for (int i = 0; i < 10; i++) al[i] = (i + 1) * 10; 41 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && al[i] == (i + 1) * 10; 42 | assert_int(1, ok, "Local long array assignment"); 43 | 44 | float af[10]; 45 | for (int i = 0; i < 10; i++) af[i] = (i + 1) * 10.1; 46 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && float_eq(af[i], (i + 1) * 10.1); 47 | assert_int(1, ok, "Local float array assignment"); 48 | 49 | double ad[10]; 50 | for (int i = 0; i < 10; i++) ad[i] = (i + 1) * 10.1; 51 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && float_eq(ad[i], (i + 1) * 10.1); 52 | assert_int(1, ok, "Local double array assignment"); 53 | 54 | long double ald[10]; 55 | for (int i = 0; i < 10; i++) ald[i] = (i + 1) * 10.1; 56 | ok = 1; for (int i = 0; i < 10; i++) ok = ok && float_eq(ald[i], (i + 1) * 10.1); 57 | assert_int(1, ok, "Local long double array assignment"); 58 | 59 | // Array of structs 60 | struct { int i, j; } astr[10]; 61 | for (int i = 0; i < 10; i++) { 62 | astr[i].i = (i + 1) * 10; 63 | astr[i].j = (i + 1) * 20; 64 | } 65 | ok = 1; 66 | for (int i = 0; i < 10; i++) ok = ok && float_eq(astr[i].i, (i + 1) * 10); 67 | for (int i = 0; i < 10; i++) ok = ok && float_eq(astr[i].j, (i + 1) * 20); 68 | assert_int(1, ok, "Local struct array assignment"); 69 | } 70 | 71 | static void test_global_vars() { 72 | // Array of ints 73 | int gai[10]; 74 | for (int i = 0; i < 10; i++) gai[i] = (i + 1) * 10; 75 | int ok = 1; for (int i = 0; i < 10; i++) ok = ok && gai[i] == (i + 1) * 10; 76 | assert_int(1, ok, "Global int array assignment"); 77 | 78 | // Array of structs 79 | struct { int i, j; } gastr[10]; 80 | for (int i = 0; i < 10; i++) { 81 | gastr[i].i = (i + 1) * 10; 82 | gastr[i].j = (i + 1) * 20; 83 | } 84 | ok = 1; 85 | for (int i = 0; i < 10; i++) ok = ok && float_eq(gastr[i].i, (i + 1) * 10); 86 | for (int i = 0; i < 10; i++) ok = ok && float_eq(gastr[i].j, (i + 1) * 20); 87 | assert_int(1, ok, "Global struct array assignment"); 88 | } 89 | 90 | static void test_address_of() { 91 | int i[10]; 92 | assert_int(40, sizeof(*&i), "Sizeof int i[10]"); 93 | } 94 | 95 | static void test_multiple_dimensions() { 96 | char a[4][2]; 97 | assert_int(8, sizeof(a), "sizeof char a[4][2]"); 98 | 99 | for (int i = 0; i < 4; i++) 100 | for (int j = 0; j < 2; j++) 101 | a[i][j] = i * 2 + j * 3; 102 | 103 | assert_long(0x5020300, *((long *) &a), "4x2 array"); 104 | } 105 | 106 | static void test_compound_assignment() { 107 | int a[2]; 108 | a[0] = 1; 109 | a[1] = 2; 110 | 111 | assert_int(1, a[0]++, "a[0]++"); assert_int(2, a[0], "a[0]++"); 112 | assert_int(2, a[0]--, "a[0]++"); assert_int(1, a[0], "a[0]--"); 113 | assert_int(2, ++a[0], "a[0]++"); assert_int(2, a[0], "++a[0]"); 114 | assert_int(1, --a[0], "a[0]++"); assert_int(1, a[0], "--a[0]"); 115 | 116 | assert_int(2, a[1]++, "a[1]++"); assert_int(3, a[1], "a[1]++"); 117 | assert_int(3, a[1]--, "a[1]++"); assert_int(2, a[1], "a[1]--"); 118 | assert_int(3, ++a[1], "a[1]++"); assert_int(3, a[1], "++a[1]"); 119 | assert_int(2, --a[1], "a[1]++"); assert_int(2, a[1], "--a[1]"); 120 | 121 | a[0] += 10; assert_int(11, a[0], "a[0] += 10"); 122 | a[1] += 10; assert_int(12, a[1], "a[1] += 10"); 123 | } 124 | 125 | static void test_arithmetic() { 126 | int a[3]; 127 | 128 | a[0] = 1; 129 | a[1] = 2; 130 | a[2] = 3; 131 | 132 | assert_int(1, *a, "a"); 133 | assert_int(1, *(a + 0), "(a + 0)"); 134 | assert_int(2, *(a + 1), "(a + 1)"); 135 | assert_int(3, *(a + 2), "(a + 2)"); 136 | 137 | assert_int(1, &(a[1]) - a, "&(a[1]) - a"); 138 | assert_int(2, &(a[2]) - a, "&(a[2]) - a"); 139 | } 140 | 141 | static void test_struct() { 142 | union { 143 | struct { char c[8]; } s1; 144 | long l; 145 | } u1; 146 | for (int i = 0; i < 8; i++) u1.s1.c[i] = i + 1; 147 | assert_int(0x4030201, u1.l, "char c[8] in struct 1"); 148 | 149 | union { 150 | struct { int i; char c[4]; } s1; 151 | long l; 152 | } u2; 153 | u2.s1.i = -1; 154 | for (int i = 0; i < 4; i++) u2.s1.c[i] = i + 1; 155 | assert_long(0x4030201ffffffff, u2.l, "int; char c[4] in struct 2"); 156 | } 157 | 158 | void accept_array_with_address_of(int a[2]) { 159 | &a; 160 | assert_int(1, a[0], "accept_array_with_address_of 1"); 161 | assert_int(2, a[1], "accept_array_with_address_of 2"); 162 | } 163 | 164 | void test_function_array_param_with_address_of() { 165 | int a[2]; 166 | a[0] = 1; 167 | a[1] = 2; 168 | 169 | accept_array_with_address_of(a); 170 | } 171 | 172 | void test_array_lvalues() { 173 | int arr[2]; 174 | assert_int(&arr, &arr[0], "& on an array 1"); 175 | assert_int(arr + 1, &arr[1], "& on an array 2"); 176 | assert_int(sizeof(arr[1]), (int) &arr[1] - (int) &arr, "& on an array 3"); 177 | } 178 | 179 | void test_negative_array_lookup() { 180 | // Negative lookup 181 | int i[3] = {1, 2, 3}; 182 | assert_int(1, i[0], "Negative array lookup 1"); 183 | assert_int(2, i[1], "Negative array lookup 2"); 184 | assert_int(3, i[2], "Negative array lookup 3"); 185 | int *pi = &i[3]; 186 | assert_int(3, pi[-1], "Negative array lookup 4"); 187 | assert_int(2, pi[-2], "Negative array lookup 5"); 188 | assert_int(1, pi[-3], "Negative array lookup 6"); 189 | } 190 | 191 | int main(int argc, char **argv) { 192 | 193 | passes = 0; 194 | failures = 0; 195 | 196 | parse_args(argc, argv, &verbose); 197 | 198 | test_sizeof(); 199 | test_local_vars(); 200 | test_global_vars(); 201 | test_address_of(); 202 | test_compound_assignment(); 203 | test_arithmetic(); 204 | test_struct(); 205 | test_function_array_param_with_address_of(); 206 | test_array_lvalues(); 207 | test_negative_array_lookup(); 208 | 209 | finalize(); 210 | } 211 | -------------------------------------------------------------------------------- /tests/e2e/test-comma.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | 6 | int verbose; 7 | int passes; 8 | int failures; 9 | 10 | static void test_comma_in_function(int i, int j, int k) { 11 | assert_int(2, i, "test_comma_in_function from C89 spec i"); 12 | assert_int(5, j, "test_comma_in_function from C89 spec j"); 13 | assert_int(4, k, "test_comma_in_function from C89 spec k"); 14 | } 15 | 16 | static void test_comma_operator() { 17 | int i = 1; 18 | int j = 2; 19 | int k = 3; 20 | 21 | assert_int(k, (j, k), "(j, k) as function call argument"); 22 | 23 | i++, j--; 24 | assert_int(2, i, "i++, j-- for i"); 25 | assert_int(1, j, "i++, j-- for j"); 26 | 27 | j = 10; k = 1; 28 | for (i = 1; i < 10; i++, j--) k++; 29 | 30 | assert_int(10, i, "i++, j-- in for loop i"); 31 | assert_int(1, j, "i++, j-- in for loop j"); 32 | assert_int(10, k, "i++, j-- in for loop k"); 33 | 34 | // From C89 spec 35 | int t; int a = 2; int c = 4; test_comma_in_function(a, (t=3, t+2), c); 36 | } 37 | 38 | // From https://en.wikipedia.org/wiki/Comma_operator 39 | void example1() { 40 | // Commas act as separators in this line, not as an operator. 41 | // Results: a=1, b=2, c=3, i=0 42 | int a=1, b=2, c=3, i=0; 43 | 44 | assert_int(1, a, "commas example 1 a"); 45 | assert_int(2, b, "commas example 1 b"); 46 | assert_int(3, c, "commas example 1 c"); 47 | assert_int(0, i, "commas example 1 i"); 48 | } 49 | 50 | void example2() { 51 | // Assigns value of b into i. 52 | // Commas act as separators in the first line and as an operator in the second line. 53 | // Results: a=1, b=2, c=3, i=2 54 | int a=1, b=2, c=3; 55 | int i = (a, b); 56 | 57 | assert_int(1, a, "commas example 2 a"); 58 | assert_int(2, b, "commas example 2 b"); 59 | assert_int(3, c, "commas example 2 c"); 60 | assert_int(2, i, "commas example 2 i"); 61 | } 62 | 63 | void example3() { 64 | // Assigns value of a into i. 65 | // Equivalent to: int i = a; int b; 66 | // Commas act as separators in both lines. 67 | // The braces on the second line avoid variable redeclaration in the same block, 68 | // which would cause a compilation error. 69 | // The second b declared is given no initial value. 70 | // Results: a=1, b=2, c=3, i=1 71 | int a=1, b=2, c=3; 72 | { 73 | int i = a, b; 74 | 75 | assert_int(1, a, "example 3 a"); 76 | assert_int(3, c, "example 3 c"); 77 | assert_int(1, i, "example 3 i"); 78 | } 79 | 80 | assert_int(1, a, "commas example 3 a"); 81 | assert_int(2, b, "commas example 3 b"); 82 | assert_int(3, c, "commas example 3 c"); 83 | } 84 | 85 | void example4() { 86 | // Increases value of a by 2, then assigns value of resulting operation a + b into i. 87 | // Commas act as separators in the first line and as an operator in the second line. 88 | // Results: a=3, b=2, c=3, i=5 89 | int a=1, b=2, c=3; 90 | int i = (a += 2, a + b); 91 | 92 | assert_int(3, a, "commas example 4 a"); 93 | assert_int(2, b, "commas example 4 b"); 94 | assert_int(3, c, "commas example 4 c"); 95 | assert_int(5, i, "commas example 4 i"); 96 | } 97 | 98 | void example5() { 99 | // Increases value of a by 2, then stores value of a to i, and discards unused 100 | // values of resulting operation a + b. 101 | // Equivalent to: (i = (a += 2)), a + b; 102 | // Commas act as separators in the first line and as an operator in the third line. 103 | // Results: a=3, b=2, c=3, i=3 104 | int a=1, b=2, c=3; 105 | int i; 106 | i = a += 2, a + b; 107 | 108 | assert_int(3, a, "commas example 5 a"); 109 | assert_int(2, b, "commas example 5 b"); 110 | assert_int(3, c, "commas example 5 c"); 111 | assert_int(3, i, "commas example 5 i"); 112 | } 113 | 114 | void example6() { 115 | // Assigns value of a into i. 116 | // Commas act as separators in both lines. 117 | // The braces on the second line avoid variable redeclaration in the same block, 118 | // which would cause a compilation error. 119 | // The second b and c declared are given no initial value. 120 | // Results: a=1, b=2, c=3, i=1 121 | int a=1, b=2, c=3; 122 | { 123 | int i = a, b, c; 124 | 125 | assert_int(1, a, "commas example 6 a"); 126 | assert_int(1, i, "commas example 6 i"); 127 | } 128 | 129 | assert_int(1, a, "commas example 6 a"); 130 | assert_int(2, b, "commas example 6 b"); 131 | assert_int(3, c, "commas example 6 c"); 132 | } 133 | 134 | int example7() { 135 | // Commas act as separators in the first line and as an operator in the second line. 136 | // Assigns value of c into i, discarding the unused a and b values. 137 | // Results: a=1, b=2, c=3, i=3 138 | int a=1, b=2, c=3; 139 | int i = (a, b, c); 140 | 141 | // Returns 6, not 4, since comma operator sequence points following the keyword 142 | // return are considered a single expression evaluating to rvalue of final 143 | // subexpression c=6. 144 | // Commas act as operators in this line. 145 | return a=4, b=5, c=6; 146 | } 147 | 148 | int example8() { 149 | // Returns 3, not 1, for same reason as previous example. 150 | // Commas act as operators in this line. 151 | return 1, 2, 3; 152 | } 153 | 154 | int example9() { 155 | // Returns 3, not 1, still for same reason as above. This example works as it does 156 | // because return is a keyword, not a function call. Even though compilers will 157 | // allow for the construct return(value), the parentheses are only relative to "value" 158 | // and have no special effect on the return keyword. 159 | // Return simply gets an expression and here the expression is "(1), 2, 3". 160 | // Commas act as operators in this line. 161 | return(1), 2, 3; 162 | } 163 | 164 | int test_comma_in_addition() { 165 | assert_int(3, 1 + (1, 2), "1 + (1, 2)"); 166 | } 167 | 168 | int main(int argc, char **argv) { 169 | passes = 0; 170 | failures = 0; 171 | 172 | test_comma_operator(); 173 | 174 | // From https://en.wikipedia.org/wiki/Comma_operator 175 | example1(); 176 | example2(); 177 | example3(); 178 | example4(); 179 | example5(); 180 | example6(); 181 | assert_int(6, example7(), "commas example 7"); 182 | assert_int(3, example8(), "commas example 8"); 183 | assert_int(3, example9(), "commas example 9"); 184 | test_comma_in_addition(); 185 | 186 | finalize(); 187 | } 188 | -------------------------------------------------------------------------------- /tests/e2e/test-enums.c: -------------------------------------------------------------------------------- 1 | #include "../test-lib.h" 2 | 3 | int verbose; 4 | int passes; 5 | int failures; 6 | 7 | // Global enums 8 | enum ge0 {GE0A, GE0B, GE0C}; 9 | enum ge1 {GE1A=1, GE1B, GE1C}; 10 | 11 | enum ge0 return_ge0(enum ge0 g) { return g; } 12 | 13 | void test_enums() { 14 | assert_int(0, GE0A, "Enums GE0 1"); 15 | assert_int(1, GE0B, "Enums GE0 2"); 16 | assert_int(2, GE0C, "Enums GE0 3"); 17 | 18 | assert_int(1, GE1A, "Enums GE1 1"); 19 | assert_int(2, GE1B, "Enums GE1 2"); 20 | assert_int(3, GE1C, "Enums GE1 3"); 21 | 22 | enum e0 {E0A, E0B, E0C}; // Intentional no trailing comma 23 | assert_int(0, E0A, "Enums E0 1"); 24 | assert_int(1, E0B, "Enums E0 2"); 25 | assert_int(2, E0C, "Enums E0 3"); 26 | 27 | enum e1 { 28 | E1A=1, 29 | E1B, 30 | E1C 31 | }; 32 | assert_int(1, E1A, "Enums E1 1"); 33 | assert_int(2, E1B, "Enums E1 2"); 34 | assert_int(3, E1C, "Enums E1 3"); 35 | 36 | enum e2 { 37 | E2A, 38 | E2B=2, 39 | E2C 40 | }; 41 | assert_int(0, E2A, "Enums E2 1"); 42 | assert_int(2, E2B, "Enums E2 2"); 43 | assert_int(3, E2C, "Enums E2 3"); 44 | 45 | enum e3 { 46 | E3A, 47 | E3B=2, 48 | E3C, 49 | E3D, 50 | E3E=3, 51 | E3F, // Intentional trailing comma 52 | }; 53 | assert_int(0, E3A, "Enums E3 1"); 54 | assert_int(2, E3B, "Enums E3 2"); 55 | assert_int(3, E3C, "Enums E3 3"); 56 | assert_int(4, E3D, "Enums E3 4"); 57 | assert_int(3, E3E, "Enums E3 5"); 58 | assert_int(4, E3F, "Enums E3 6"); 59 | 60 | enum e5 {E5A, E5B}; 61 | enum e5 v5; 62 | v5 = 100; assert_int(100, v5, "Enums E4 1"); 63 | v5 = E5A; assert_int(E5A, v5, "Enums E4 2"); 64 | v5 = E5B; assert_int(E5B, v5, "Enums E4 3"); 65 | 66 | enum {EA1A, EA1B} a1; 67 | enum {EA2A, EA2B,} a2; 68 | a1 = EA1A; assert_int(0, a1, "Enums EA1 1"); 69 | a1 = EA1B; assert_int(1, a1, "Enums EA1 2"); 70 | a2 = EA2A; assert_int(0, a2, "Enums EA2 1"); 71 | a2 = EA2B; assert_int(1, a2, "Enums EA2 2"); 72 | 73 | enum direct_decl3 {EA3A, EA3B} a3; 74 | enum direct_decl4 {EA4A, EA4B,} a4; 75 | a3 = EA3A; assert_int(0, a3, "Enums EA3 1"); 76 | a3 = EA3B; assert_int(1, a3, "Enums EA3 2"); 77 | a4 = EA4A; assert_int(0, a4, "Enums EA4 1"); 78 | a4 = EA4B; assert_int(1, a4, "Enums EA4 2"); 79 | 80 | assert_int(4, sizeof(enum {EA5A, EA5B}), "Sizeof enum 1"); 81 | assert_int(4, sizeof(enum e5), "Sizeof enum 2"); 82 | 83 | // Test separate declaration and var declaration works 84 | enum e6; 85 | enum e6 {E6A, E6B}; 86 | enum e6 v6; 87 | v6 = E6A; assert_int(0, v6, "Enums E6 1"); 88 | v6 = E6B; assert_int(1, v6, "Enums E6 2"); 89 | 90 | assert_int(4, sizeof(struct s {enum {A} v;}), "Sizeof struct of enum 1"); 91 | assert_int(4, sizeof(enum e6), "Sizeof struct of enum 2"); 92 | 93 | enum e7 { 94 | E7A=-2, 95 | E7B, 96 | E7C, 97 | E7D, 98 | }; 99 | assert_int(-2, E7A, "Enums E7 1"); 100 | assert_int(-1, E7B, "Enums E7 2"); 101 | assert_int(0, E7C, "Enums E7 3"); 102 | assert_int(1, E7D, "Enums E7 4"); 103 | 104 | assert_int(GE0A, return_ge0(GE0A), "Return GE0A"); 105 | assert_int(GE0B, return_ge0(GE0B), "Return GE0B"); 106 | assert_int(GE0C, return_ge0(GE0C), "Return GE0C"); 107 | 108 | // Declaration + initialization 109 | enum foo {FOO=1} f = FOO; 110 | assert_int(FOO, f, "Declaration + initialization"); 111 | 112 | // Test mixing pointers to enums and ints 113 | enum E { EA, EB } e, *pe; 114 | int i, *pi; 115 | 116 | pe = &e; 117 | pi = &e; 118 | pe = &i; 119 | } 120 | 121 | int main(int argc, char **argv) { 122 | passes = 0; 123 | failures = 0; 124 | 125 | parse_args(argc, argv, &verbose); 126 | 127 | test_enums(); 128 | 129 | finalize(); 130 | } 131 | -------------------------------------------------------------------------------- /tests/e2e/test-ifdef.c: -------------------------------------------------------------------------------- 1 | #include "../test-lib.h" 2 | 3 | int verbose; 4 | int passes; 5 | int failures; 6 | 7 | void test_ifdef() { 8 | int i = 0; 9 | 10 | #ifdef TEST 11 | i = 1; 12 | #endif 13 | assert_int(0, i, "ifdef/endif with directive undefined"); 14 | 15 | #define TEST 16 | #ifdef TEST 17 | i = 1; 18 | #endif 19 | assert_int(1, i, "ifdef/endif with directive defined"); 20 | 21 | #undef TEST 22 | #ifdef TEST 23 | i = 1; 24 | #endif 25 | assert_int(0, 0, "ifdef/endif with directive undefined"); 26 | 27 | #ifdef TEST 28 | i = 1; 29 | #else 30 | i = 2; 31 | #endif 32 | assert_int(2, i, "ifdef/else/endif with directive undefined"); 33 | 34 | #define TEST 35 | #ifdef TEST 36 | i = 1; 37 | #else 38 | i = 2; 39 | #endif 40 | assert_int(1, i, "ifdef/else/endif with directive defined"); 41 | 42 | #define TEST 43 | i = 1; 44 | #ifdef TEST 45 | if (1) i = 4; else i = 5; 46 | #else 47 | i += 2; 48 | #endif 49 | assert_int(4, i, "ifdef/else/endif with antagonistic non-CPP else 1"); 50 | 51 | #undef TEST 52 | i = 1; 53 | #ifdef TEST 54 | if (1) i = 4; else i = 5; 55 | #else 56 | i += 2; 57 | #endif 58 | assert_int(3, i, "ifdef/else/endif with antagonistic non-CPP else 2"); 59 | } 60 | 61 | int main(int argc, char **argv) { 62 | passes = 0; 63 | failures = 0; 64 | 65 | parse_args(argc, argv, &verbose); 66 | 67 | test_ifdef(); 68 | 69 | finalize(); 70 | } 71 | -------------------------------------------------------------------------------- /tests/e2e/test-inc-dec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | 6 | int verbose; 7 | int passes; 8 | int failures; 9 | 10 | void test_prefix_inc_dec() { 11 | int i; 12 | i = 0; 13 | assert_int(1, ++i, "prefix inc dec 1"); 14 | assert_int(2, ++i, "prefix inc dec 2"); 15 | assert_int(1, --i, "prefix inc dec 3"); 16 | assert_int(0, --i, "prefix inc dec 4"); 17 | } 18 | 19 | void test_postfix_inc_dec() { 20 | int i; 21 | i = 0; 22 | assert_int(0, i++, "postfix inc dec 1"); 23 | assert_int(1, i++, "postfix inc dec 2"); 24 | assert_int(2, i--, "postfix inc dec 3"); 25 | assert_int(1, i--, "postfix inc dec 4"); 26 | } 27 | 28 | void test_inc_dec_sizes() { 29 | char c, *pc, **ppc; 30 | short s, *ps, **pps; 31 | int i, *pi, **ppi; 32 | long l, *pl, **ppl; 33 | unsigned char uc, *upc, **uppc; 34 | unsigned short us, *ups, **upps; 35 | unsigned int ui, *upi, **uppi; 36 | unsigned long ul, *upl, **uppl; 37 | 38 | c = pc = ppc = uc = upc = uppc = 0;; 39 | s = ps = pps = us = ups = upps = 0;; 40 | i = pi = ppi = ui = upi = uppi = 0;; 41 | l = pl = ppl = ul = upl = uppl = 0;; 42 | 43 | c++; assert_int(1, c, "++- size 1a"); c--; assert_int(0, c, "++- size 1b"); ++c; assert_int(1, c, "++- size 1c"); c--; assert_int(0, c, "++- size 1d"); 44 | pc++; assert_int(1, pc, "++- size 2a"); pc--; assert_int(0, pc, "++- size 2b"); ++pc; assert_int(1, pc, "++- size 2c"); pc--; assert_int(0, pc, "++- size 2d"); 45 | ppc++; assert_int(8, ppc, "++- size 3a"); ppc--; assert_int(0, ppc, "++- size 3b"); ++ppc; assert_int(8, ppc, "++- size 3c"); ppc--; assert_int(0, ppc, "++- size 3d"); 46 | s++; assert_int(1, s, "++- size 4a"); s--; assert_int(0, s, "++- size 4b"); ++s; assert_int(1, s, "++- size 4c"); s--; assert_int(0, s, "++- size 4d"); 47 | ps++; assert_int(2, ps, "++- size 5a"); ps--; assert_int(0, ps, "++- size 5b"); ++ps; assert_int(2, ps, "++- size 5c"); ps--; assert_int(0, ps, "++- size 5d"); 48 | pps++; assert_int(8, pps, "++- size 6a"); pps--; assert_int(0, pps, "++- size 6b"); ++pps; assert_int(8, pps, "++- size 6c"); pps--; assert_int(0, pps, "++- size 6d"); 49 | i++; assert_int(1, i, "++- size 7a"); i--; assert_int(0, i, "++- size 7b"); ++i; assert_int(1, i, "++- size 7c"); i--; assert_int(0, i, "++- size 7d"); 50 | pi++; assert_int(4, pi, "++- size 8a"); pi--; assert_int(0, pi, "++- size 8b"); ++pi; assert_int(4, pi, "++- size 8c"); pi--; assert_int(0, pi, "++- size 8d"); 51 | ppi++; assert_int(8, ppi, "++- size 9a"); ppi--; assert_int(0, ppi, "++- size 9b"); ++ppi; assert_int(8, ppi, "++- size 9c"); ppi--; assert_int(0, ppi, "++- size 9d"); 52 | l++; assert_int(1, l, "++- size aa"); l--; assert_int(0, l, "++- size ab"); ++l; assert_int(1, l, "++- size ac"); l--; assert_int(0, l, "++- size ad"); 53 | pl++; assert_int(8, pl, "++- size ba"); pl--; assert_int(0, pl, "++- size bb"); ++pl; assert_int(8, pl, "++- size bc"); pl--; assert_int(0, pl, "++- size bd"); 54 | ppl++; assert_int(8, ppl, "++- size ca"); ppl--; assert_int(0, ppl, "++- size cb"); ++ppl; assert_int(8, ppl, "++- size cc"); ppl--; assert_int(0, ppl, "++- size cd"); 55 | 56 | uc++; assert_int(1, uc, "++- size u1a"); uc--; assert_int(0, uc, "++- size u1b"); ++uc; assert_int(1, uc, "++- size u1c"); uc--; assert_int(0, uc, "++- size u1d"); 57 | upc++; assert_int(1, upc, "++- size u2a"); upc--; assert_int(0, upc, "++- size u2b"); ++upc; assert_int(1, upc, "++- size u2c"); upc--; assert_int(0, upc, "++- size u2d"); 58 | uppc++; assert_int(8, uppc, "++- size u3a"); uppc--; assert_int(0, uppc, "++- size u3b"); ++uppc; assert_int(8, uppc, "++- size u3c"); uppc--; assert_int(0, uppc, "++- size u3d"); 59 | us++; assert_int(1, us, "++- size u4a"); us--; assert_int(0, us, "++- size u4b"); ++us; assert_int(1, us, "++- size u4c"); us--; assert_int(0, us, "++- size u4d"); 60 | ups++; assert_int(2, ups, "++- size u5a"); ups--; assert_int(0, ups, "++- size u5b"); ++ups; assert_int(2, ups, "++- size u5c"); ups--; assert_int(0, ups, "++- size u5d"); 61 | upps++; assert_int(8, upps, "++- size u6a"); upps--; assert_int(0, upps, "++- size u6b"); ++upps; assert_int(8, upps, "++- size u6c"); upps--; assert_int(0, upps, "++- size u6d"); 62 | ui++; assert_int(1, ui, "++- size u7a"); ui--; assert_int(0, ui, "++- size u7b"); ++ui; assert_int(1, ui, "++- size u7c"); ui--; assert_int(0, ui, "++- size u7d"); 63 | upi++; assert_int(4, upi, "++- size u8a"); upi--; assert_int(0, upi, "++- size u8b"); ++upi; assert_int(4, upi, "++- size u8c"); upi--; assert_int(0, upi, "++- size u8d"); 64 | uppi++; assert_int(8, uppi, "++- size u9a"); uppi--; assert_int(0, uppi, "++- size u9b"); ++uppi; assert_int(8, uppi, "++- size u9c"); uppi--; assert_int(0, uppi, "++- size u9d"); 65 | ul++; assert_int(1, ul, "++- size uaa"); ul--; assert_int(0, ul, "++- size uab"); ++ul; assert_int(1, ul, "++- size uac"); ul--; assert_int(0, ul, "++- size uad"); 66 | upl++; assert_int(8, upl, "++- size uba"); upl--; assert_int(0, upl, "++- size ubb"); ++upl; assert_int(8, upl, "++- size ubc"); upl--; assert_int(0, upl, "++- size ubd"); 67 | uppl++; assert_int(8, uppl, "++- size uca"); uppl--; assert_int(0, uppl, "++- size ucb"); ++uppl; assert_int(8, uppl, "++- size ucc"); uppl--; assert_int(0, uppl, "++- size ucd"); 68 | } 69 | 70 | int test_prefix_inc_bug() { 71 | unsigned char *puc; 72 | unsigned int i; 73 | 74 | puc = malloc(2 * sizeof(char)); 75 | 76 | i = 1; 77 | puc[0] = 0; 78 | puc[1] = 0x81; 79 | 80 | assert_int(129, (i << 7) | (*++puc & 0x7f), "Prefix ++ bug"); 81 | } 82 | 83 | int main(int argc, char **argv) { 84 | passes = 0; 85 | failures = 0; 86 | 87 | parse_args(argc, argv, &verbose); 88 | 89 | test_prefix_inc_dec(); 90 | test_postfix_inc_dec(); 91 | test_inc_dec_sizes(); 92 | test_prefix_inc_bug(); 93 | 94 | finalize(); 95 | } 96 | -------------------------------------------------------------------------------- /tests/e2e/test-include/foo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "include.h" 3 | 4 | void foo() {} 5 | -------------------------------------------------------------------------------- /tests/e2e/test-include/include.h: -------------------------------------------------------------------------------- 1 | void foo(); 2 | -------------------------------------------------------------------------------- /tests/e2e/test-include/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "include.h" 5 | 6 | void main() { 7 | foo(); 8 | exit(0); 9 | } -------------------------------------------------------------------------------- /tests/e2e/test-loops.c: -------------------------------------------------------------------------------- 1 | #include "../test-lib.h" 2 | 3 | int verbose; 4 | int passes; 5 | int failures; 6 | 7 | void test_while() { 8 | int i; 9 | int c1, c2; 10 | 11 | c1 = c2 = 0; 12 | i = 0; while (i < 3) { c1 = c1 * 10 + i; i++; } 13 | i = 0; while (i++ < 3) c2 = c2 * 10 + i; 14 | assert_int( 12, c1, "while 1"); 15 | assert_int(123, c2, "while 2"); 16 | } 17 | 18 | void test_for() { 19 | int i; 20 | int c1, c2; 21 | 22 | c1 = c2 = 0; 23 | 24 | for (i = 0; i < 10; i++) c1 = c1 * 10 + i; 25 | 26 | for (i = 0; i < 10; i++) { 27 | if (i == 5) continue; 28 | c2 = c2 * 10 + i; 29 | } 30 | 31 | assert_int(123456789, c1, "for 1"); 32 | assert_int(12346789, c2, "for 2"); 33 | } 34 | 35 | void test_for_statement_combinations() { 36 | int i; 37 | int c; 38 | 39 | i = 0; c = 0; for( ; ; ) { c++; if (i == 10) break; i++; } assert_int(10, i, "for combinations i 1"); assert_int(11, c, "for combinations c 1"); 40 | i = 0; c = 0; for( ; ; i++) { c++; if (i == 10) break; } assert_int(10, i, "for combinations i 2"); assert_int(11, c, "for combinations c 2"); 41 | i = 0; c = 0; for( ; i<10 ; ) { c++; i++; } assert_int(10, i, "for combinations i 3"); assert_int(10, c, "for combinations c 3"); 42 | i = 0; c = 0; for( ; i<10 ; i++) { c++; } assert_int(10, i, "for combinations i 4"); assert_int(10, c, "for combinations c 4"); 43 | c = 0; for(i=0 ; ; ) { c++; if (i == 10) break; i++; } assert_int(10, i, "for combinations i 5"); assert_int(11, c, "for combinations c 5"); 44 | c = 0; for(i=0 ; ; i++) { c++; if (i == 10) break; } assert_int(10, i, "for combinations i 6"); assert_int(11, c, "for combinations c 6"); 45 | c = 0; for(i=0 ; i<10 ; ) { c++; i++; } assert_int(10, i, "for combinations i 7"); assert_int(10, c, "for combinations c 7"); 46 | c = 0; for(i=0 ; i<10 ; i++) { c++; } assert_int(10, i, "for combinations i 8"); assert_int(10, c, "for combinations c 8"); 47 | } 48 | 49 | void test_while_continue() { 50 | int i, c1; 51 | 52 | c1 = i = 0; 53 | while (i++ < 5) { 54 | c1 = c1 * 10 + i; 55 | continue; 56 | c1 = c1 * 10 + 9; 57 | } 58 | assert_int(12345, c1, "while continue"); 59 | } 60 | 61 | void test_nested_while_continue() { 62 | int i, c1; 63 | char *s; 64 | 65 | i = c1 = 0; 66 | s = "foo"; 67 | 68 | while (s[i++] != 0) { 69 | c1 = c1 * 10 + i; 70 | while (0); 71 | continue; 72 | } 73 | 74 | assert_int(123, c1, "nested while/continue"); 75 | } 76 | 77 | void test_do_while() { 78 | int i = 1; 79 | int c1 = 0; 80 | int c2 = 0; 81 | 82 | do { 83 | c1++; 84 | i++; 85 | if (i == 5) continue; 86 | c2++; 87 | } while (i != 10); 88 | 89 | assert_int(9, c1, "do_while 1"); 90 | assert_int(8, c2, "do_while 2"); 91 | 92 | i = c1 = c2 = 0; 93 | do { 94 | c1++; 95 | i++; 96 | if (i == 5) break; 97 | c2++; 98 | } while (i != 10); 99 | 100 | assert_int(5, c1, "do_while 3"); 101 | assert_int(4, c2, "do_while 4"); 102 | } 103 | 104 | void test_single_goto() { 105 | int i = 0, c = 0; 106 | 107 | loop: 108 | i++; 109 | c = c * 10 + i; 110 | if (i < 10) goto loop; 111 | c--; 112 | goto done; 113 | 114 | c--; 115 | 116 | done:; 117 | assert_int(1234567899, c, "Goto"); 118 | } 119 | 120 | int _test_double_goto(int i) { 121 | int result; 122 | 123 | if (i == 1) { 124 | result = 1; 125 | goto foo; 126 | } 127 | 128 | if (i == 2) { 129 | result = 2; 130 | goto foo; 131 | } 132 | 133 | result = 3; 134 | goto foo; 135 | 136 | foo: return result; 137 | } 138 | 139 | void test_double_goto() { 140 | assert_int(1, _test_double_goto(1), "Double goto 1"); 141 | assert_int(2, _test_double_goto(2), "Double goto 2"); 142 | assert_int(3, _test_double_goto(3), "Double goto 3"); 143 | assert_int(3, _test_double_goto(4), "Double goto 4"); 144 | } 145 | 146 | int test_compilation_crash_on_unreachable_code() { 147 | // A bug in SSA caused this to fail to compile. 148 | do continue; while(1); 149 | } 150 | 151 | // Sick case of a goto and label of something that's also atypedef 152 | void test_goto_typedef(void) { 153 | typedef int s; 154 | 155 | goto s; 156 | 157 | assert_int(1, 0, "Goto typedef 1"); 158 | 159 | s: { 160 | assert_int(1, 1, "Goto typedef 1"); 161 | return; 162 | } 163 | } 164 | 165 | int main(int argc, char **argv) { 166 | passes = 0; 167 | failures = 0; 168 | 169 | parse_args(argc, argv, &verbose); 170 | 171 | test_while(); 172 | test_for(); 173 | test_for_statement_combinations(); 174 | test_while_continue(); 175 | test_nested_while_continue(); 176 | test_do_while(); 177 | test_single_goto(); 178 | test_double_goto(); 179 | test_goto_typedef(); 180 | 181 | finalize(); 182 | } 183 | -------------------------------------------------------------------------------- /tests/e2e/test-memory-functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | 6 | int verbose; 7 | int passes; 8 | int failures; 9 | 10 | void test_malloc() { 11 | int *pi; 12 | 13 | pi = malloc(32); 14 | *pi = 1; 15 | *++pi = 2; 16 | *++pi = -1; // Gets overwritten 17 | *pi++ = 3; 18 | *pi = 4; 19 | 20 | assert_int(1, *(pi - 3), "malloc 1"); 21 | assert_int(2, *(pi - 2), "malloc 2"); 22 | assert_int(3, *(pi - 1), "malloc 3"); 23 | assert_int(4, *pi, "malloc 4"); 24 | } 25 | 26 | 27 | void test_free() { 28 | int *pi; 29 | pi = malloc(17); 30 | free(pi); 31 | } 32 | 33 | void test_mem_functions() { 34 | long *pi1, *pi2; 35 | 36 | pi1 = malloc(32); 37 | pi2 = malloc(32); 38 | memset(pi1, 0, 32); 39 | assert_int(0, pi1[0], "memory functions 1"); 40 | assert_int(0, pi1[3], "memory functions 2"); 41 | memset(pi1, -1, 32); 42 | assert_int(-1, pi1[0], "memory functions 2"); 43 | assert_int(-1, pi1[3], "memory functions 3"); 44 | 45 | assert_int(255, memcmp(pi1, pi2, 32), "memory functions 4"); 46 | 47 | // gcc's strcmp is builtin and returns different numbers than the 48 | // std library's. Only the sign is the same. Hence, we have to use < 49 | // and > instead of ==. 50 | assert_int(1, strcmp("foo", "foo") == 0, "memory functions 5"); 51 | assert_int(1, strcmp("foo", "aaa") > 0, "memory functions 6"); 52 | assert_int(1, strcmp("foo", "ggg") < 0, "memory functions 7"); 53 | } 54 | 55 | int main(int argc, char **argv) { 56 | passes = 0; 57 | failures = 0; 58 | 59 | parse_args(argc, argv, &verbose); 60 | 61 | test_malloc(); 62 | test_free(); 63 | test_mem_functions(); 64 | 65 | finalize(); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /tests/e2e/test-shlib-lib.c: -------------------------------------------------------------------------------- 1 | #include "test-shlib.h" 2 | #include "../test-lib.h" 3 | 4 | char c = 1; 5 | short s = 2; 6 | int i = 3; 7 | long l = 4; 8 | 9 | unsigned char uc = 5; 10 | unsigned short us = 6; 11 | unsigned int ui = 7; 12 | unsigned long ul = 8; 13 | 14 | float f = 1.1; 15 | double d = 2.1; 16 | long double ld = 3.1; 17 | 18 | int *pi; 19 | 20 | struct st st = { 1, 2 }; 21 | 22 | char ca[2] = {1, 2}; 23 | short sa[2] = {1, 2}; 24 | int ia[2] = {1, 2}; 25 | long la[2] = {1, 2}; 26 | 27 | int inc_c() { c++; } 28 | int inc_s() { s++; } 29 | int inc_i() { i++; } 30 | int inc_l() { l++; } 31 | 32 | int inc_uc() { uc++; } 33 | int inc_us() { us++; } 34 | int inc_ui() { ui++; } 35 | int inc_ul() { ul++; } 36 | 37 | int inc_f() { f++; } 38 | int inc_d() { d++; } 39 | int inc_ld() { ld++; } 40 | 41 | int inc_pi() { pi++; } 42 | 43 | int inc_st() { st.i++; st.j++; } 44 | int inc_ia() { ia[0]++; ia[1]++; } 45 | 46 | int return_i() { return i; } 47 | int return_i_plus_one() { return i + 1; } 48 | 49 | FuncReturningInt fri = &return_i; 50 | 51 | // A struct of structs 52 | struct nss { 53 | struct {int a; int b; } s1; 54 | struct {int c; int d; } s2; 55 | } v1 = { 1, 2, 3, 4}; 56 | 57 | 58 | void test_address_of() { 59 | char *pc = &c; c = 1; assert_int(1, *pc, "&c"); (*pc)++; assert_int(2, c, "&c"); 60 | short *ps = &s; s = 1; assert_int(1, *ps, "&s"); (*ps)++; assert_int(2, s, "&s"); 61 | int *pi = &i; i = 1; assert_int(1, *pi, "&i"); (*pi)++; assert_int(2, i, "&i"); 62 | long *pl = &l; l = 1; assert_int(1, *pl, "&l"); (*pl)++; assert_int(2, l, "&l"); 63 | 64 | unsigned char *upc = &uc; uc = 1; assert_int(1, *upc, "&c"); (*upc)++; assert_int(2, uc, "&uc"); 65 | unsigned short *ups = &us; us = 1; assert_int(1, *ups, "&s"); (*ups)++; assert_int(2, us, "&us"); 66 | unsigned int *upi = &ui; ui = 1; assert_int(1, *upi, "&i"); (*upi)++; assert_int(2, ui, "&ui"); 67 | unsigned long *upl = &ul; ul = 1; assert_int(1, *upl, "&l"); (*upl)++; assert_int(2, ul, "&ul"); 68 | 69 | float *pf = &f; f = 1.1; assert_float( 1.1, *pf, "&f"); (*pf)++; assert_float( 2.1, f, "&f"); 70 | double *pd = &d; d = 1.1; assert_double(1.1, *pd, "&d"); (*pd)++; assert_double(2.1, d, "&d"); 71 | long double *pld = &ld; ld = 1.1; assert_long_double(1.1, *pld, "&ld"); (*pld)++; assert_long_double(2.1, ld, "&ld"); 72 | 73 | ca[0] = 10; ca[1] = 20; assert_int(10, ca[0], "&ca 1"); assert_int(20, ca[1], "&ca 2"); ca[1]++; assert_int(21, ca[1], "&ca 3"); 74 | sa[0] = 11; sa[1] = 21; assert_int(11, sa[0], "&sa 1"); assert_int(21, sa[1], "&sa 2"); sa[1]++; assert_int(22, sa[1], "&sa 3"); 75 | ia[0] = 12; ia[1] = 22; assert_int(12, ia[0], "&ia 1"); assert_int(22, ia[1], "&ia 2"); ia[1]++; assert_int(23, ia[1], "&ia 3"); 76 | la[0] = 13; la[1] = 23; assert_int(13, la[0], "&la 1"); assert_int(23, la[1], "&la 2"); la[1]++; assert_int(24, la[1], "&la 3"); 77 | 78 | fa[0] = 14.1; fa[1] = 24.1; assert_float( 14.1, fa[0], "&fa 1"); assert_float( 24.1, fa[1], "&fa 2"); fa[1]++; assert_float( 25.1, fa[1], "&fa 3"); 79 | da[0] = 15.1; da[1] = 25.1; assert_double(15.1, da[0], "&da 1"); assert_double(25.1, da[1], "&da 2"); da[1]++; assert_double(26.1, da[1], "&da 3"); 80 | 81 | lda[0] = 16.1; lda[1] = 26.1; assert_long_double(16.1, lda[0], "&lda 1"); assert_long_double(26.1, lda[1], "&lda 2"); lda[1]++; assert_long_double(27.1, lda[1], "&lda 3"); 82 | 83 | fri = &return_i; 84 | i = 1; assert_int(1, fri(), "& of function 1"); 85 | fri = &return_i_plus_one; assert_int(2, fri(), "& of function 2"); 86 | fri = 0; 87 | 88 | fri = 1 ? return_i : return_i; 89 | assert_int(1, fri(), "& of function 3"); 90 | 91 | // Nested structs 92 | assert_int(0, (void *) &v1.s1 - (void *) &v1, "Anonymous s/s 3"); 93 | assert_int(0, (void *) &v1.s1.a - (void *) &v1, "Anonymous s/s 4"); 94 | assert_int(4, (void *) &v1.s1.b - (void *) &v1, "Anonymous s/s 5"); 95 | assert_int(8, (void *) &v1.s2 - (void *) &v1, "Anonymous s/s 6"); 96 | assert_int(8, (void *) &v1.s2.c - (void *) &v1, "Anonymous s/s 7"); 97 | assert_int(12, (void *) &v1.s2.d - (void *) &v1, "Anonymous s/s 8"); 98 | } 99 | 100 | int add_one(int i) { 101 | return i + 1; 102 | } 103 | -------------------------------------------------------------------------------- /tests/e2e/test-shlib-main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | #include "test-shlib.h" 6 | 7 | int verbose; 8 | int passes; 9 | int failures; 10 | 11 | void test_direct_access() { 12 | assert_int(1, c, "Increment c 1"); inc_c(); assert_int(2, c, "Increment c 2"); 13 | assert_int(2, s, "Increment i 1"); inc_s(); assert_int(3, s, "Increment i 2"); 14 | assert_int(3, i, "Increment s 1"); inc_i(); assert_int(4, i, "Increment s 2"); 15 | assert_int(4, l, "Increment l 1"); inc_l(); assert_int(5, l, "Increment l 2"); 16 | assert_int(5, uc, "Increment uc 1"); inc_uc(); assert_int(6, uc, "Increment uc 2"); 17 | assert_int(6, us, "Increment ui 1"); inc_us(); assert_int(7, us, "Increment ui 2"); 18 | assert_int(7, ui, "Increment us 1"); inc_ui(); assert_int(8, ui, "Increment us 2"); 19 | assert_int(8, ul, "Increment ul 1"); inc_ul(); assert_int(9, ul, "Increment ul 2"); 20 | 21 | assert_float( 1.1, f, "Increment f 1"); inc_f(); assert_float( 2.1, f, "Increment f 2"); 22 | assert_double(2.1, d, "Increment d 1"); inc_d(); assert_double(3.1, d, "Increment d 2"); 23 | 24 | assert_long_double(3.1, ld, "Increment d 1"); inc_ld(); assert_long_double(4.1, ld, "Increment d 2"); 25 | 26 | pi = malloc(2 * sizeof(int)); 27 | pi[0] = 10; 28 | pi[1] = 20; 29 | 30 | // Pointer 31 | assert_int(10, *pi, "Increment pi1 1"); inc_pi(); assert_int(20, *pi, "Increment pi1 2"); 32 | 33 | // Struct 34 | assert_int(1, st.i, "Increment st.i 1"); 35 | assert_int(2, st.j, "Increment st.j 1"); 36 | inc_st(); 37 | assert_int(2, st.i, "Increment st.i 2"); 38 | assert_int(3, st.j, "Increment st.j 2"); 39 | 40 | // Array 41 | assert_int(1, ia[0], "Increment ia[0] 1"); 42 | assert_int(2, ia[1], "Increment ia[1] 1"); 43 | inc_ia(); 44 | assert_int(2, ia[0], "Increment ia[0] 2"); 45 | assert_int(3, ia[1], "Increment ia[1] 2"); 46 | 47 | i = 42; 48 | assert_int(42, fri(), "Pointer to function"); 49 | 50 | int (*f)(int) = add_one; 51 | assert_int(3, f(2), "&address in the shared library"); 52 | 53 | int (*x)(int); 54 | x = (int (*)(int)) add_one; 55 | assert_int(3, x(2), "&address in the shared library after a cast"); 56 | } 57 | 58 | int main(int argc, char **argv) { 59 | passes = 0; 60 | failures = 0; 61 | 62 | parse_args(argc, argv, &verbose); 63 | 64 | test_direct_access(); 65 | test_address_of(); 66 | 67 | finalize(); 68 | } 69 | -------------------------------------------------------------------------------- /tests/e2e/test-shlib.h: -------------------------------------------------------------------------------- 1 | char c; 2 | int i; 3 | short s; 4 | long l; 5 | 6 | unsigned char uc; 7 | unsigned int ui; 8 | unsigned short us; 9 | unsigned long ul; 10 | 11 | float f; 12 | double d; 13 | long double ld; 14 | 15 | int *pi; 16 | 17 | struct st { int i, j; } st; 18 | 19 | char ca[2]; 20 | short sa[2]; 21 | int ia[2]; 22 | long la[2]; 23 | float fa[2]; 24 | double da[2]; 25 | long double lda[2]; 26 | 27 | typedef int (*FuncReturningInt)(); 28 | 29 | FuncReturningInt fri; 30 | 31 | int inc_c(); 32 | int inc_s(); 33 | int inc_i(); 34 | int inc_l(); 35 | 36 | int inc_uc(); 37 | int inc_us(); 38 | int inc_ui(); 39 | int inc_ul(); 40 | 41 | int inc_f(); 42 | int inc_d(); 43 | int inc_ld(); 44 | 45 | int inc_pi(); 46 | 47 | int inc_st(); 48 | int inc_ia(); 49 | 50 | void test_address_of(); 51 | 52 | int add_one(int i); 53 | -------------------------------------------------------------------------------- /tests/e2e/test-typedefs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../test-lib.h" 5 | 6 | int verbose; 7 | int passes; 8 | int failures; 9 | 10 | typedef int altint, intarr[3], *intptr, *arrptrint[3]; 11 | typedef struct {int a;} s; 12 | typedef struct {int a, b;} args_t; 13 | 14 | static int altint_func(altint i) { return i; } 15 | static int intarr_func(intarr ia) { return ia[0]; } 16 | static int intptr_func(intptr ip) { return *ip; } 17 | static int sfunc(s v) { return v.a; } 18 | static int psfunc(s *v) { return v->a; } 19 | 20 | // Note: wcc will also allow (struct {int a, b;} args), but gcc won't accept 21 | // that, stating a type mismatch when the function is called. 22 | static int process_anonymous_struct(args_t args) { 23 | return args.a + args.b; 24 | } 25 | 26 | void *function_returning_void() {} 27 | 28 | static void test_typedef_functions() { 29 | altint i; 30 | i = 1; 31 | assert_int(1, altint_func(i), "Function with int typedef parameter"); 32 | 33 | intptr ip = &i; 34 | assert_int(1, intptr_func(ip), "Function with intptr typedef parameter"); 35 | 36 | intarr ia; 37 | ia[0] = 1; 38 | assert_int(1, intarr_func(ia), "Function with intarr typedef parameter"); 39 | 40 | s sv1; 41 | sv1.a = 1; 42 | assert_int(1, sfunc(sv1), "Function with typedef struct parameter"); 43 | 44 | s *psv = &sv1; 45 | assert_int(1, psv->a, "Dereference pointer to typedef struct"); 46 | assert_int(1, sfunc(*psv), "Function with typedef struct parameter"); 47 | assert_int(1, psfunc(psv), "Function with pointer to typedef struct parameter"); 48 | 49 | args_t x; 50 | x.a = 1; 51 | x.b = 2; 52 | assert_int(3, process_anonymous_struct(x), "Anonymous structs in function params"); 53 | 54 | // Test typedef of pointer to a function. 55 | typedef void (*f_t)(); 56 | f_t f = function_returning_void; 57 | f(); 58 | } 59 | 60 | static void test_arrays_of_typedefs() { 61 | altint ia2[3]; 62 | ia2[0] = 1; 63 | assert_int(1, ia2[0], "Array of typedef"); 64 | 65 | altint i = 1; 66 | arrptrint api; 67 | api[0] = &i; 68 | assert_int(1, *api[0], "Typedef of array of pointer to int"); 69 | 70 | arrptrint aapi[3]; 71 | aapi[0][0] = &i; 72 | assert_int(1, *aapi[0][0], "Array of typedef of array of pointer to int"); 73 | 74 | typedef int ia23_t[2][3]; 75 | ia23_t ia3; 76 | assert_int(24, sizeof(ia3), "ia3[2][3]"); 77 | } 78 | 79 | static void test_typedef_scopes() { 80 | assert_int(4, sizeof(altint), "Typedefs scopes 1"); 81 | typedef char altint; 82 | assert_int(1, sizeof(altint), "Typedefs scopes 2"); 83 | { 84 | typedef short altint; 85 | assert_int(2, sizeof(altint), "Typedefs scopes 3"); 86 | } 87 | assert_int(1, sizeof(altint), "Typedefs scopes 4"); 88 | } 89 | 90 | static void test_typedef_combinations() { 91 | typedef int *pi_t; 92 | typedef pi_t api_t[3]; 93 | api_t api; 94 | assert_int(24, sizeof(api), "Typedef combinations 1"); 95 | 96 | { 97 | // local redefinition 98 | typedef int *pi_t; 99 | typedef pi_t api_t[4]; 100 | api_t api; 101 | assert_int(32, sizeof(api), "Typedef combinations 2"); 102 | } 103 | 104 | typedef int ai_t[3]; 105 | typedef ai_t *pai_t; 106 | pai_t pai; 107 | assert_int(8, sizeof(pai), "Typedef combinations 3"); 108 | 109 | typedef int i3_t[3]; 110 | typedef int i3_t[3]; // A redefinition should be allowed 111 | assert_int(12, sizeof(i3_t), "Typedef combinations 4"); 112 | 113 | typedef i3_t i4_t; 114 | assert_int(12, sizeof(i4_t), "Typedef combinations 5"); 115 | { 116 | // A local redefinition should be allowed. This also tests the 117 | // lexing/parsing code that should identify i3_t as a typedef, but i4_t 118 | // as an identifier, used to redeclare typedef i4_t. 119 | typedef i3_t *i4_t; 120 | assert_int(8, sizeof(i4_t), "Typedef combinations 6"); 121 | } 122 | } 123 | 124 | static void test_typedef_structs() { 125 | // Typedef in a struct 126 | typedef int aint; 127 | struct s2 {aint i;}; 128 | struct s2 v2; 129 | v2.i = 1; 130 | assert_int(1, v2.i, "Typedef in a struct"); 131 | 132 | typedef struct s3 {aint i;} S3; 133 | S3 v3; 134 | v3.i = 1; 135 | assert_int(1, v3.i, "Typedef in a typedef struct"); 136 | } 137 | 138 | static void test_typedef_tags() { 139 | // Test typedef tag having same identifier as a struct tag 140 | typedef struct s4 {int i;} s4; 141 | struct s4 sv2; 142 | sv2.i = 1; 143 | assert_int(1, sv2.i, "Same typedef & struct tag 1"); 144 | 145 | s4 sv3; 146 | sv3.i = 1; 147 | assert_int(1, sv3.i, "Same typedef & struct tag 2"); 148 | 149 | // Test typedef tag having same identifier as a union tag 150 | typedef union u1 {int i;} u1; 151 | union u1 uv1; 152 | uv1.i = 1; 153 | assert_int(1, uv1.i, "Same typedef & union tag 1"); 154 | 155 | u1 uv2; 156 | uv2.i = 1; 157 | assert_int(1, uv2.i, "Same typedef & union tag 2"); 158 | 159 | // Test enum tag having same identifier as a struct tag 160 | typedef enum e {E} e; 161 | enum e ev1; 162 | ev1 = E; 163 | assert_int(E, ev1, "Same typedef & enum tag 1"); 164 | 165 | e ev2; 166 | ev2 = E; 167 | assert_int(E, ev2, "Same typedef & enum tag 2"); 168 | } 169 | 170 | static int test_typedef_forward_declaration() { 171 | // Test a typedef of an incompelte struct 172 | typedef struct s S; 173 | struct s {int i;}; 174 | S sv; 175 | sv.i = 1; 176 | assert_int(1, sv.i, "Forward declaration of struct typedef"); 177 | } 178 | 179 | // Not much can be tested here, but this verifies that this kind of function 180 | // definition can at least be dealt with without error. 181 | static void do_nothing_with_an_anonymous_struct(struct {int a;} v) {} 182 | 183 | typedef int foo; 184 | 185 | int test_typedef_redeclared_as_variable(void) { 186 | foo foo; 187 | foo = 1; 188 | assert_int(1, foo, "Typedef redeclared as variable"); 189 | { 190 | foo = 2; 191 | assert_int(2, foo, "Typedef redeclared as variable"); 192 | } 193 | assert_int(2, foo, "Typedef redeclared as variable"); 194 | } 195 | 196 | // C89 3.5.4.3 197 | // In a parameter declaration, a single typedef name in parentheses is taken to be an 198 | // abstract declarator that specifies a function with a single parameter, not as 199 | // redundant parentheses around the identifier for a declarator. 200 | typedef unsigned char u8; 201 | int fu8(u8); // function with a u8 as a parmeter; 202 | int fu8(u8 i) { return i + 1; } 203 | 204 | int test_typedef_as_single_function_parameter() { 205 | assert_int(2, fu8(1), "int fu8(u8);"); 206 | } 207 | 208 | typedef int (fri)(); 209 | 210 | int return_int() { return 1; } 211 | 212 | fri *function_that_returns_int = return_int; 213 | 214 | static void test_typedef_of_function_returning_int() { 215 | assert_int(1, function_that_returns_int(), "typedef int (fri)()"); 216 | } 217 | 218 | int main(int argc, char **argv) { 219 | parse_args(argc, argv, &verbose); 220 | 221 | test_typedef_functions(); 222 | test_arrays_of_typedefs(); 223 | test_typedef_scopes(); 224 | test_typedef_combinations(); 225 | test_typedef_structs(); 226 | test_typedef_tags(); 227 | test_typedef_forward_declaration(); 228 | test_typedef_redeclared_as_variable(); 229 | test_typedef_as_single_function_parameter(); 230 | test_typedef_of_function_returning_int(); 231 | 232 | finalize(); 233 | } 234 | -------------------------------------------------------------------------------- /tests/integration/.gitignore: -------------------------------------------------------------------------------- 1 | test-instrsel 2 | test-errors 3 | test-debug 4 | instrsel-tests.rulecov 5 | -------------------------------------------------------------------------------- /tests/integration/Makefile: -------------------------------------------------------------------------------- 1 | all: run-test-instrsel run-test-errors check-test-debug-headers 2 | 3 | test-instrsel: ../../libwcc.a ../test-utils.c test-instrsel.c 4 | gcc ${GCC_OPTS} -g -o test-instrsel test-instrsel.c ../test-utils.c ../../libwcc.a 5 | 6 | run-test-instrsel: test-instrsel 7 | ./test-instrsel 8 | 9 | test-errors: ../../wcc ../test-lib.o test-errors.c 10 | gcc ${GCC_OPTS} -g -o test-errors test-errors.c ../test-lib.o 11 | 12 | run-test-errors: test-errors 13 | ./test-errors 14 | 15 | test-debug: test-debug.c ../../wcc 16 | ../../wcc test-debug.c -o test-debug -g 17 | 18 | check-test-debug-headers: test-debug 19 | objdump -h test-debug | grep .debug_info > /dev/null 20 | objdump -h test-debug | grep .debug_line > /dev/null 21 | objdump -h test-debug | grep .debug_abbrev > /dev/null 22 | objdump -h test-debug | grep .debug_str > /dev/null 23 | 24 | objdump -g test-debug | grep -E 'DW_AT_producer.*wcc' > /dev/null 25 | objdump -g test-debug | grep 'Line Number Statements:' > /dev/null 26 | 27 | clean: 28 | @rm -f *.s 29 | @rm -f *.o 30 | @rm -f core 31 | @rm -f test-instrsel 32 | @rm -f test-errors 33 | @rm -f instrsel-tests.rulecov 34 | @rm -f test-debug 35 | -------------------------------------------------------------------------------- /tests/integration/test-debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int *pi = 0; *pi = 1; // seg fault 5 | } 6 | -------------------------------------------------------------------------------- /tests/test-lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern int verbose; 10 | extern int passes; 11 | extern int failures; 12 | 13 | void assert_int(int expected, int actual, char *message) { 14 | if (expected != actual) { 15 | failures++; 16 | printf("%-60s ", message); 17 | printf("failed, expected %d got %d\n", expected, actual); 18 | } 19 | else { 20 | passes++; 21 | if (verbose) { 22 | printf("%-60s ", message); 23 | printf("ok\n"); 24 | } 25 | } 26 | } 27 | 28 | void assert_long(long expected, long actual, char *message) { 29 | if (expected != actual) { 30 | failures++; 31 | printf("%-60s ", message); 32 | printf("failed, expected %ld got %ld\n", expected, actual); 33 | } 34 | else { 35 | passes++; 36 | if (verbose) { 37 | printf("%-60s ", message); 38 | printf("ok\n"); 39 | } 40 | } 41 | } 42 | 43 | int float_eq(float expected, float actual) { 44 | if (isnan(expected) != isnan(actual)) return 0; 45 | 46 | float diff = expected - actual; 47 | if (diff < 0) diff = -diff; 48 | return diff <= 0.0001; 49 | } 50 | 51 | void assert_float(float expected, float actual, char *message) { 52 | int eq = float_eq(expected, actual); 53 | 54 | if (!float_eq(expected, actual)) { 55 | failures++; 56 | printf("%-60s ", message); 57 | printf("failed, expected %f got %f\n", expected, actual); 58 | } 59 | else { 60 | passes++; 61 | if (verbose) { 62 | printf("%-60s ", message); 63 | printf("ok\n"); 64 | } 65 | } 66 | } 67 | 68 | void assert_double(double expected, double actual, char *message) { 69 | if (isnan(expected) != isnan(actual)) { 70 | failures++; 71 | printf("%-60s ", message); 72 | printf("failed, expected %f got %f\n", expected, actual); 73 | return; 74 | } 75 | 76 | double diff = expected - actual; 77 | if (diff < 0) diff = -diff; 78 | if (diff > 0.0001) { 79 | failures++; 80 | printf("%-60s ", message); 81 | printf("failed, expected %f got %f\n", expected, actual); 82 | } 83 | else { 84 | passes++; 85 | if (verbose) { 86 | printf("%-60s ", message); 87 | printf("ok\n"); 88 | } 89 | } 90 | } 91 | 92 | void assert_long_double(long double expected, long double actual, char *message) { 93 | if (isnan(expected) != isnan(actual)) { 94 | failures++; 95 | printf("%-60s ", message); 96 | printf("failed, expected %Lf got %Lf\n", expected, actual); 97 | return; 98 | } 99 | 100 | long double diff = expected - actual; 101 | if (diff < 0) diff = -diff; 102 | if (diff > 0.0001) { 103 | failures++; 104 | printf("%-60s ", message); 105 | printf("failed, expected %Lf got %Lf\n", expected, actual); 106 | } 107 | else { 108 | passes++; 109 | if (verbose) { 110 | printf("%-60s ", message); 111 | printf("ok\n"); 112 | } 113 | } 114 | } 115 | 116 | void assert_string(char *expected, char *actual, char *message) { 117 | if (strcmp(expected, actual)) { 118 | failures++; 119 | printf("%-60s ", message); 120 | printf("failed, expected \"%s\" got \"%s\"\n", expected, actual); 121 | } 122 | else { 123 | passes++; 124 | if (verbose) { 125 | printf("%-60s ", message); 126 | printf("ok\n"); 127 | } 128 | } 129 | } 130 | 131 | void finalize() { 132 | if (failures == 0) { 133 | printf("All %d tests passed\n", passes + failures); 134 | } 135 | else { 136 | printf("%d out of %d tests failed\n", failures, passes + failures); 137 | exit(1); 138 | } 139 | } 140 | 141 | void parse_args(int argc, char **argv, int *verbose) { 142 | int help; 143 | 144 | help = *verbose = 0; 145 | 146 | argc--; 147 | argv++; 148 | while (argc > 0 && *argv[0] == '-') { 149 | if (argc > 0 && !memcmp(argv[0], "-h", 3)) { help = 0; argc--; argv++; } 150 | else if (argc > 0 && !memcmp(argv[0], "-v", 2)) { *verbose = 1; argc--; argv++; } 151 | else { 152 | printf("Unknown parameter %s\n", argv[0]); 153 | exit(1); 154 | } 155 | } 156 | 157 | if (help) { 158 | printf("Usage: test-wcc [-v]\n\n"); 159 | printf("Flags\n"); 160 | printf("-v Verbose mode; show all tests\n"); 161 | printf("-h Help\n"); 162 | exit(1); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tests/test-lib.h: -------------------------------------------------------------------------------- 1 | void assert_int(int expected, int actual, char *message); 2 | void assert_long(long expected, long actual, char *message); 3 | int float_eq(float expected, float got); 4 | void assert_float(float expected, float got, char *message); 5 | void assert_double(double expected, double got, char *message); 6 | void assert_long_double(long double expected, long double got, char *message); 7 | void assert_string(char *expected, char *actual, char *message); 8 | void finalize(); 9 | void parse_args(int argc, char **argv, int *verbose); 10 | int wasprintf(char **ret, const char *format, ...); 11 | -------------------------------------------------------------------------------- /tests/unit/.gitignore: -------------------------------------------------------------------------------- 1 | test-lexer 2 | test-cpp 3 | test-set 4 | test-list 5 | test-strmap 6 | test-strset 7 | test-longmap 8 | test-longset 9 | test-graph 10 | test-ssa 11 | test-instrsel 12 | test-parser 13 | test-types 14 | test-functions 15 | -------------------------------------------------------------------------------- /tests/unit/Makefile: -------------------------------------------------------------------------------- 1 | all: run-test-lexer run-test-cpp run-test-set run-test-list run-test-strmap run-test-strset run-test-longmap run-test-longset run-test-ssa run-test-parser run-test-types run-test-graph run-test-functions 2 | 3 | test-lexer: ../../libwcc.a test-lexer.c 4 | gcc ${GCC_OPTS} -g -o test-lexer test-lexer.c ../../libwcc.a 5 | 6 | run-test-lexer: test-lexer 7 | ./test-lexer 8 | 9 | test-cpp: ../../libwcc.a ../test-lib.o test-cpp.c 10 | gcc ${GCC_OPTS} -g -o test-cpp test-cpp.c ../../libwcc.a ../test-lib.o 11 | 12 | run-test-cpp: test-cpp 13 | ./test-cpp 14 | 15 | test-set: ../../libwcc.a test-set.c 16 | gcc ${GCC_OPTS} -g -o test-set test-set.c ../../libwcc.a 17 | 18 | run-test-set: test-set 19 | ./test-set 20 | 21 | test-list: ../../libwcc.a test-list.c 22 | gcc ${GCC_OPTS} -g -o test-list test-list.c ../../libwcc.a 23 | 24 | run-test-list: test-list 25 | ./test-list 26 | 27 | test-strmap: test-strmap.c ../../strmap.c 28 | gcc ${GCC_OPTS} -g -o test-strmap test-strmap.c ../../libwcc.a 29 | 30 | run-test-strmap: test-strmap 31 | ./test-strmap 32 | 33 | test-strset: test-strset.c ../../strset.c 34 | gcc ${GCC_OPTS} -g -o test-strset test-strset.c ../../libwcc.a 35 | 36 | run-test-strset: test-strset 37 | ./test-strset 38 | 39 | test-longmap: test-longmap.c ../../longmap.c 40 | gcc ${GCC_OPTS} -g -o test-longmap test-longmap.c ../../libwcc.a 41 | 42 | run-test-longmap: test-longmap 43 | ./test-longmap 44 | 45 | test-longset: test-longset.c ../../longset.c 46 | gcc ${GCC_OPTS} -g -o test-longset test-longset.c ../../libwcc.a 47 | 48 | run-test-longset: test-longset 49 | ./test-longset 50 | 51 | test-ssa: ../../libwcc.a ../test-utils.c test-ssa.c 52 | gcc ${GCC_OPTS} -Wno-int-conversion -Wno-pointer-to-int-cast -g -o test-ssa test-ssa.c ../test-utils.c ../../libwcc.a 53 | 54 | run-test-ssa: test-ssa 55 | ./test-ssa 56 | 57 | test-graph: test-graph.c ../../graph.c ../../utils.c ../../memory.c 58 | gcc ${GCC_OPTS} test-graph.c ../../graph.c ../../utils.c ../../memory.c -o test-graph 59 | 60 | run-test-graph: test-graph 61 | ./test-graph 62 | 63 | test-parser: ../../libwcc.a test-parser.c 64 | gcc ${GCC_OPTS} -Wno-int-conversion -Wno-pointer-to-int-cast -g -o test-parser test-parser.c ../../libwcc.a ../test-lib.o 65 | 66 | run-test-parser: test-parser 67 | ./test-parser 68 | 69 | test-types: ../../libwcc.a test-types.c 70 | gcc ${GCC_OPTS} -Wno-int-conversion -Wno-pointer-to-int-cast -g -o test-types test-types.c ../../libwcc.a ../test-lib.o 71 | 72 | run-test-types: test-types 73 | ./test-types 74 | 75 | test-functions: ../../libwcc.a test-functions.c 76 | gcc ${GCC_OPTS} -Wno-int-conversion -Wno-pointer-to-int-cast -g -o test-functions test-functions.c ../../libwcc.a ../test-lib.o 77 | 78 | run-test-functions: test-functions 79 | ./test-functions 80 | 81 | clean: 82 | @rm -f *.s 83 | @rm -f *.o 84 | @rm -f core 85 | @rm -f test-lexer 86 | @rm -f test-cpp 87 | @rm -f test-set 88 | @rm -f test-list 89 | @rm -f test-strmap 90 | @rm -f test-strset 91 | @rm -f test-longmap 92 | @rm -f test-longset 93 | @rm -f test-ssa 94 | @rm -f test-graph 95 | @rm -f test-parser 96 | @rm -f test-types 97 | @rm -f test-functions 98 | -------------------------------------------------------------------------------- /tests/unit/test-cpp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../../wcc.h" 6 | #include "../test-lib.h" 7 | 8 | 9 | int verbose; 10 | int passes; 11 | int failures; 12 | 13 | typedef struct line_map_tuple { 14 | int position; 15 | int line_number; 16 | } LineMapTuple; 17 | 18 | static void test_transform_trigraphs() { 19 | init_cpp_from_string("?" "?" "="); transform_trigraphs(); assert_string("#", get_cpp_input(), "Trigraph #"); 20 | init_cpp_from_string("?" "?" "("); transform_trigraphs(); assert_string("[", get_cpp_input(), "Trigraph ["); 21 | init_cpp_from_string("?" "?" "/"); transform_trigraphs(); assert_string("\\", get_cpp_input(), "Trigraph \\"); 22 | init_cpp_from_string("?" "?" ")"); transform_trigraphs(); assert_string("]", get_cpp_input(), "Trigraph ]"); 23 | init_cpp_from_string("?" "?" "'"); transform_trigraphs(); assert_string("^", get_cpp_input(), "Trigraph ^"); 24 | init_cpp_from_string("?" "?" "<"); transform_trigraphs(); assert_string("{", get_cpp_input(), "Trigraph {"); 25 | init_cpp_from_string("?" "?" "!"); transform_trigraphs(); assert_string("|", get_cpp_input(), "Trigraph |"); 26 | init_cpp_from_string("?" "?" ">"); transform_trigraphs(); assert_string("}", get_cpp_input(), "Trigraph }"); 27 | init_cpp_from_string("?" "?" "-"); transform_trigraphs(); assert_string("~", get_cpp_input(), "Trigraph ~"); 28 | } 29 | 30 | static void test_strip_bsnl(char *input, char *expected_output, LineMapTuple expected_linemap[]) { 31 | init_cpp_from_string(strdup(input)); 32 | strip_backslash_newlines(); 33 | char *output = get_cpp_input(); 34 | if (strcmp(expected_output, output)) { 35 | printf("Failed in comparison ...\n"); 36 | printf("Input:\n%s\nExpected:\n%s\nGot:\n%s\n\n", input, expected_output, output); 37 | failures++; 38 | } 39 | 40 | LineMap *lm = get_cpp_linemap(); 41 | int elm_index = 0; 42 | while (lm) { 43 | if (!expected_linemap[elm_index].line_number) { 44 | printf("Failed in line map ...\n"); 45 | printf("Input:\n%s\nGot too many entries %d %d\n", 46 | input, lm->position, lm->line_number); 47 | failures++; 48 | } 49 | else { 50 | if (lm->position != expected_linemap[elm_index].position || lm->line_number != expected_linemap[elm_index].line_number) { 51 | printf("Failed in line map ...\n"); 52 | printf("Input:\n%s\nExpected: %d %d\n\nGot:%d %d\n\n", 53 | input, expected_linemap[elm_index].position, expected_linemap[elm_index].line_number, lm->position, lm->line_number); 54 | } 55 | } 56 | 57 | lm = lm->next; 58 | elm_index++; 59 | } 60 | 61 | if (expected_linemap[elm_index].line_number) { 62 | printf("Failed in line map ...\n"); 63 | printf("Input:\n%s\nGot trailing entry/entries %d %d\n", 64 | input, expected_linemap[elm_index].position, expected_linemap[elm_index].line_number); 65 | failures++; 66 | } 67 | } 68 | 69 | static void test_strip_backslash_newlines(void) { 70 | test_strip_bsnl("foo", "foo\n", (LineMapTuple[]) {0,1, 0,0}); 71 | test_strip_bsnl("foo\nbar", "foo\nbar\n", (LineMapTuple[]) {0,1, 4,2, 0,0}); 72 | test_strip_bsnl("foo\nbar\n", "foo\nbar\n", (LineMapTuple[]) {0,1, 4,2, 8,3, 0,0}); 73 | test_strip_bsnl("foo\\\nbar", "foobar\n", (LineMapTuple[]) {0,1, 3,2, 0,0}); 74 | test_strip_bsnl("foo\\\n bar", "foo bar\n", (LineMapTuple[]) {0,1, 3,2, 0,0}); 75 | test_strip_bsnl("foo \\\nbar", "foo bar\n", (LineMapTuple[]) {0,1, 4,2, 0,0}); 76 | test_strip_bsnl("a\\\nb\\\nc", "abc\n", (LineMapTuple[]) {0,1, 1,2, 2,3, 0,0}); 77 | test_strip_bsnl("a\\\n\\\nb", "ab\n", (LineMapTuple[]) {0,1, 1,3, 0,0}); 78 | } 79 | 80 | static void test_single_token(char *input, int kind, char *expected) { 81 | CppToken *token = parse_cli_define(input)->tokens; 82 | if (!token) panic("Expected token"); 83 | 84 | // Ensure there is one token, so the circular linked list's head == tail 85 | assert_long(1, token == token->next, input); 86 | 87 | token = token->next; // Go to the head of the CLL 88 | assert_int(kind, token->kind, input); 89 | assert_string(expected, token->str, input); 90 | } 91 | 92 | static void test_tokenization(void) { 93 | CppToken *tokens; 94 | 95 | init_cpp(); 96 | 97 | // Two identifiers 98 | tokens = parse_cli_define("foo bar")->tokens->next; 99 | assert_int(CPP_TOK_IDENTIFIER, tokens->kind, "foo kind"); 100 | assert_string("foo", tokens->str, "foo str"); 101 | tokens = tokens->next; 102 | assert_int(CPP_TOK_IDENTIFIER, tokens->kind, "bar kind"); 103 | assert_string("bar", tokens->str, "bar str"); 104 | 105 | // String & character literals 106 | test_single_token("\"foo\"", CPP_TOK_STRING_LITERAL, "\"foo\""); 107 | test_single_token("'a'", CPP_TOK_STRING_LITERAL, "'a'"); 108 | 109 | // Numbers 110 | test_single_token("12", CPP_TOK_NUMBER, "12"); 111 | test_single_token("99", CPP_TOK_NUMBER, "99"); 112 | test_single_token("1.21", CPP_TOK_NUMBER, "1.21"); 113 | test_single_token("123.456", CPP_TOK_NUMBER, "123.456"); 114 | test_single_token("1.21x", CPP_TOK_NUMBER, "1.21x"); 115 | test_single_token("1.21x_y_AZ", CPP_TOK_NUMBER, "1.21x_y_AZ"); 116 | test_single_token("1.21E+1", CPP_TOK_NUMBER, "1.21E+1"); 117 | test_single_token("1.21e-1", CPP_TOK_NUMBER, "1.21e-1"); 118 | test_single_token("1.", CPP_TOK_NUMBER, "1."); 119 | 120 | // Multi-character tokens 121 | test_single_token("&&", CPP_TOK_OTHER, "&&"); 122 | test_single_token("||", CPP_TOK_OTHER, "||"); 123 | test_single_token("==", CPP_TOK_OTHER, "=="); 124 | test_single_token("!=", CPP_TOK_OTHER, "!="); 125 | test_single_token("<=", CPP_TOK_OTHER, "<="); 126 | test_single_token(">=", CPP_TOK_OTHER, ">="); 127 | test_single_token("++", CPP_TOK_INC, "++"); 128 | test_single_token("--", CPP_TOK_DEC, "--"); 129 | test_single_token("+=", CPP_TOK_OTHER, "+="); 130 | test_single_token("-=", CPP_TOK_OTHER, "-="); 131 | test_single_token("*=", CPP_TOK_OTHER, "*="); 132 | test_single_token("/=", CPP_TOK_OTHER, "/="); 133 | test_single_token("%=", CPP_TOK_OTHER, "%="); 134 | test_single_token("&=", CPP_TOK_OTHER, "&="); 135 | test_single_token("|=", CPP_TOK_OTHER, "|="); 136 | test_single_token("^=", CPP_TOK_OTHER, "^="); 137 | test_single_token("->", CPP_TOK_OTHER, "->"); 138 | test_single_token(">>=", CPP_TOK_OTHER, ">>="); 139 | test_single_token("<<=", CPP_TOK_OTHER, "<<="); 140 | test_single_token("...", CPP_TOK_OTHER, "..."); 141 | } 142 | 143 | int main(int argc, char **argv) { 144 | passes = 0; 145 | failures = 0; 146 | 147 | parse_args(argc, argv, &verbose); 148 | 149 | test_transform_trigraphs(); 150 | test_strip_backslash_newlines(); 151 | test_tokenization(); 152 | 153 | finalize(); 154 | } 155 | -------------------------------------------------------------------------------- /tests/unit/test-graph.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../../wcc.h" 6 | 7 | void assert(int expected, int actual) { 8 | if (expected != actual) { 9 | printf("Expected %d, got %d\n", expected, actual); 10 | exit(1); 11 | } 12 | } 13 | 14 | int main() { 15 | GraphNode *n; 16 | Graph *g; 17 | 18 | int i; 19 | 20 | g = new_graph(10, 0); 21 | assert(10, g->node_count); 22 | assert(MAX_GRAPH_EDGE_COUNT, g->max_edge_count); 23 | 24 | g = new_graph(10, 20); 25 | assert(10, g->node_count); 26 | assert(20, g->max_edge_count); 27 | 28 | g = new_graph(3, 4); 29 | add_graph_edge(g, 0, 1); 30 | add_graph_edge(g, 0, 2); 31 | add_graph_edge(g, 1, 2); 32 | add_graph_edge(g, 2, 1); 33 | 34 | // Nodes: 35 | // n0 e0 36 | // n1 e2 e0 37 | // n2 e3 e1 38 | 39 | assert(0, g->nodes[0].succ->id); assert(0, (long) g->nodes[0].pred); 40 | assert(2, g->nodes[1].succ->id); assert(0, g->nodes[1].pred->id); 41 | assert(3, g->nodes[2].succ->id); assert(1, g->nodes[2].pred->id); 42 | 43 | assert(0, g->edges[0].from->id); assert(1, g->edges[0].to->id); 44 | assert(0, g->edges[1].from->id); assert(2, g->edges[1].to->id); 45 | assert(1, g->edges[2].from->id); assert(2, g->edges[2].to->id); 46 | assert(2, g->edges[3].from->id); assert(1, g->edges[3].to->id); 47 | 48 | // Edges: 49 | // e0 n0 n1 e1 e3 50 | // e1 n0 n2 e2 51 | // e2 n1 n2 52 | // e3 n2 n1 53 | 54 | assert(1, g->edges[0].next_succ->id); assert(3, g->edges[0].next_pred->id); 55 | assert(0, (long) g->edges[1].next_succ); assert(2, (long) g->edges[1].next_pred->id); 56 | assert(0, (long) g->edges[2].next_succ); assert(0, (long) g->edges[2].next_pred); 57 | assert(0, (long) g->edges[3].next_succ); assert(0, (long) g->edges[3].next_pred); 58 | } 59 | -------------------------------------------------------------------------------- /tests/unit/test-list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../wcc.h" 5 | 6 | void assert_int(int expected, int actual, char *message) { 7 | if (expected != actual) { 8 | printf("%s: expected %d, got %d\n", message, expected, actual); 9 | exit(1); 10 | } 11 | } 12 | 13 | int test_append(int initial_length) { 14 | List *l = new_list(initial_length); 15 | 16 | append_to_list(l, (void *) 1); 17 | assert_int(1, l->length, "Append 1a"); 18 | assert_int(1, (long) l->elements[0], "Append 1c"); 19 | 20 | append_to_list(l, (void *) 2); 21 | assert_int(2, l->length, "Append 2a"); 22 | assert_int(1, (long) l->elements[0], "Append 2c"); 23 | assert_int(2, (long) l->elements[1], "Append 2d"); 24 | 25 | append_to_list(l, (void *) 3); 26 | append_to_list(l, (void *) 4); 27 | 28 | assert_int(4, l->length, "Append 3a"); 29 | assert_int(1, (long) l->elements[0], "Append 2c"); 30 | assert_int(2, (long) l->elements[1], "Append 3d"); 31 | assert_int(3, (long) l->elements[2], "Append 3e"); 32 | assert_int(4, (long) l->elements[3], "Append 3f"); 33 | } 34 | 35 | int main() { 36 | test_append(0); 37 | test_append(2); 38 | test_append(4); 39 | test_append(8); 40 | } 41 | -------------------------------------------------------------------------------- /tests/unit/test-longmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../../wcc.h" 8 | 9 | long hashfunc(long l) { 10 | return ~l; 11 | } 12 | 13 | int main() { 14 | LongMap *map = new_longmap(); 15 | 16 | int COUNT = 10000; 17 | for (int i = -COUNT; i < COUNT; i++) { 18 | long key = i * 42; 19 | char *value = malloc(16); 20 | sprintf(value, "bar %d", i); 21 | longmap_put(map, key, value); 22 | } 23 | 24 | // Lookup the keys 25 | for (int i = -COUNT; i < COUNT; i++) { 26 | long key = i * 42; 27 | char *value = malloc(16); 28 | sprintf(value, "bar %d", i); 29 | char *got_value = longmap_get(map, key); 30 | if (!got_value) panic("Didn't get a match\n"); 31 | if (strcmp(value, got_value)) panic("Got something horrible 1"); 32 | 33 | got_value = longmap_get(map, 47); 34 | if (got_value) panic("Expected no match"); 35 | } 36 | 37 | // Test iteration 38 | int h = 0; 39 | longmap_foreach(map, it) 40 | h += 7 * h + longmap_iterator_key(&it); 41 | if (h != -46927138) panic("Iteration checksum ok"); 42 | 43 | // Test keys function 44 | int *keys; 45 | int count = longmap_keys(map, &keys); 46 | if (count != COUNT * 2) panic("Expected COUNT keys"); 47 | h = 0; 48 | for (int i = 0; i < count; i++) h += 7 * h + keys[i]; 49 | if (h != -46927138) panic("Iteration checksum ok for keys"); 50 | 51 | // Reassign the even numbered elements with baz %d 52 | for (int i = -COUNT + 1; i < COUNT; i += 2) { 53 | long key = i * 42; 54 | char *value = malloc(16); 55 | sprintf(value, "baz %d", i); 56 | longmap_put(map, key, value); 57 | } 58 | 59 | // Recheck the keys with alternating values 60 | for (int i = -COUNT + 1; i < COUNT; i++) { 61 | long key = i * 42; 62 | char *value = malloc(16); 63 | sprintf(value, i % 2 == 0 ? "bar %d" : "baz %d", i); 64 | 65 | char *got_value = longmap_get(map, key); 66 | if (!got_value) panic("Didn't get a match\n"); 67 | if (strcmp(value, got_value)) panic("Got something horrible 2"); 68 | got_value = longmap_get(map, 47); 69 | if (got_value) panic("Expected no match"); 70 | } 71 | 72 | // Delete half of the keys 73 | for (int i = -COUNT + 1; i < COUNT; i += 2) { 74 | long key = i * 42; 75 | longmap_delete(map, key); 76 | } 77 | 78 | // Check half of keys are gone 79 | for (int i = -COUNT + 1; i < COUNT; i++) { 80 | long key = i * 42; 81 | char *got_value = longmap_get(map, key); 82 | if ((!!got_value) == (!!(i % 2))) panic("Mismatch in key deletion"); 83 | } 84 | 85 | // Insert/deletion thrashing in a new map. This tests rehashing without 86 | // a resize. 87 | map = new_longmap(); 88 | for (int i = -COUNT; i < COUNT; i++) { 89 | long key = i * 42; 90 | char value[] = "foo"; 91 | longmap_put(map, key, value); 92 | char *got_value = longmap_get(map, key); 93 | if (!got_value) panic("Did not get a key"); 94 | longmap_delete(map, key); 95 | got_value = longmap_get(map, key); 96 | if (got_value) panic("Got a key"); 97 | } 98 | 99 | // Test emptying 100 | map = new_longmap(); 101 | longmap_put(map, 1, (void *) 1); 102 | if (!longmap_get(map, 1)) panic("Did not get 1"); 103 | longmap_empty(map); 104 | if (longmap_get(map, 1)) panic("Unexpectedly got 1"); 105 | 106 | // Test custom hashfunc 107 | map = new_longmap(); 108 | longmap_put(map, 1, (void *) 1); 109 | if (!longmap_get(map, 1)) panic("Did not get 1"); 110 | 111 | // Test custom hashfunc 112 | LongMap *copy = longmap_copy(map); 113 | if (!longmap_get(copy, 1)) panic("Did not get 1 in copy"); 114 | } 115 | -------------------------------------------------------------------------------- /tests/unit/test-longset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../../wcc.h" 6 | 7 | int main() { 8 | LongSet *ls1 = new_longset(); 9 | longset_add(ls1, 1); 10 | if (!longset_in(ls1, 1)) panic("Expected 1 in set"); 11 | if (longset_in(ls1, 2)) panic("Did not expect 2 in set"); 12 | 13 | LongSet *ls2 = new_longset(); 14 | longset_add(ls2, 2); 15 | 16 | // Unions 17 | LongSet *ls3 = longset_union(ls1, ls2); 18 | if (!longset_in(ls3, 1)) panic("Expected 1 in set"); 19 | if (!longset_in(ls3, 2)) panic("Expected 2 in set"); 20 | if (longset_in(ls3, 3)) panic("Did not expect 3 in set"); 21 | 22 | LongSet *ls4 = new_longset(); 23 | longset_add(ls4, 1); 24 | LongSet *ls5 = longset_union(ls3, ls4); 25 | if (!longset_in(ls5, 1)) panic("Expected 1 in set"); 26 | if (!longset_in(ls5, 2)) panic("Expected 2 in set"); 27 | if (longset_in(ls5, 3)) panic("Did not expect 3 in set"); 28 | 29 | // Intersections 30 | LongSet *lsi1 = longset_intersection(ls1, ls2); 31 | if (longset_in(lsi1, 1)) panic("Did not expect 1 in set"); 32 | if (longset_in(lsi1, 2)) panic("Did not expect 2 in set"); 33 | if (longset_in(lsi1, 3)) panic("Did not expect 3 in set"); 34 | 35 | LongSet *lsi2 = longset_intersection(ls1, ls3); 36 | if (!longset_in(lsi2, 1)) panic("Expected 1 in set"); 37 | if (longset_in(lsi2, 2)) panic("Did not expect 2 in set"); 38 | if (longset_in(lsi2, 3)) panic("Did not expect 3 in set"); 39 | 40 | LongSet *lsi3 = longset_intersection(new_longset(), new_longset()); 41 | if (longset_in(lsi3, 1)) panic("Did not expect 1 in set"); 42 | 43 | LongSet *lsi4 = longset_intersection(ls1, new_longset()); 44 | if (longset_in(lsi4, 1)) panic("Did not expect 1 in set"); 45 | 46 | LongSet *lsi5 = longset_intersection(new_longset(), ls1); 47 | if (longset_in(lsi5, 1)) panic("Did not expect 1 in set"); 48 | 49 | LongSet *ls6 = new_longset(); 50 | longset_add(ls6, 1); 51 | if (!longset_in(ls6, 1)) panic("Expected 1 in set"); 52 | longset_empty(ls6); 53 | if (longset_in(ls6, 1)) panic("Did not expect 1 in set"); 54 | 55 | LongSet *ls7 = new_longset(); 56 | longset_add(ls7, 1); 57 | longset_add(ls7, 2); 58 | longset_add(ls7, 3); 59 | int h = 0; 60 | longset_foreach(ls7, it) 61 | h += 7 * h + longset_iterator_element(&it); 62 | if (h != 83) panic("Longset iteratator"); 63 | 64 | LongSet *ls8 = new_longset(); 65 | LongSet *ls9 = new_longset(); 66 | if (!longset_eq(ls8, ls9)) panic("Longset eq 1"); 67 | longset_add(ls8, 1); 68 | if (longset_eq(ls8, ls9)) panic("Longset eq 2"); 69 | longset_empty(ls8); 70 | longset_add(ls9, 1); 71 | if (longset_eq(ls8, ls9)) panic("Longset eq 3"); 72 | longset_add(ls8, 1); 73 | if (!longset_eq(ls8, ls9)) panic("Longset eq 4"); 74 | longset_add(ls8, 2); 75 | longset_add(ls9, 2); 76 | if (!longset_eq(ls8, ls9)) panic("Longset eq 5"); 77 | 78 | LongSet* ls10 = longset_copy(ls9); 79 | if (!longset_eq(ls9, ls10)) panic("Longset copy"); 80 | 81 | LongSet *ls11 = new_longset(); 82 | if (longset_len(ls11) != 0) panic("longset len 1"); 83 | longset_add(ls11, 1); if (longset_len(ls11) != 1) panic("longset len 2"); 84 | longset_add(ls11, 1); if (longset_len(ls11) != 1) panic("longset len 3"); 85 | longset_add(ls11, 2); if (longset_len(ls11) != 2) panic("longset len 4"); 86 | longset_add(ls11, 3); if (longset_len(ls11) != 3) panic("longset len 5"); 87 | 88 | LongSet *ls12 = new_longset(); 89 | longset_add(ls12, 1); 90 | longset_add(ls12, 2); 91 | longset_add(ls12, 3); 92 | longset_delete(ls12, 1); 93 | if (longset_in(ls12, 1)) panic("Dit not expect 1 in set"); 94 | if (!longset_in(ls12, 2)) panic("Expected 2 in set"); 95 | if (!longset_in(ls12, 3)) panic("Expected 3 in set"); 96 | } 97 | -------------------------------------------------------------------------------- /tests/unit/test-set.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../wcc.h" 5 | 6 | void assert(int expected, int actual) { 7 | if (expected != actual) { 8 | printf("expected %d, got %d\n", expected, actual); 9 | exit(1); 10 | } 11 | } 12 | 13 | void test_add_delete() { 14 | Set *s; 15 | 16 | s = new_set(2); 17 | 18 | add_to_set(s, 1); 19 | assert(0, in_set(s, 0)); 20 | assert(1, in_set(s, 1)); 21 | assert(0, in_set(s, 2)); 22 | 23 | add_to_set(s, 2); 24 | assert(0, in_set(s, 0)); 25 | assert(1, in_set(s, 1)); 26 | assert(1, in_set(s, 2)); 27 | 28 | delete_from_set(s, 1); 29 | assert(0, in_set(s, 0)); 30 | assert(0, in_set(s, 1)); 31 | assert(1, in_set(s, 2)); 32 | } 33 | 34 | void test_merges() { 35 | Set *s1, *s2, *s3; 36 | 37 | s1 = new_set(3); add_to_set(s1, 1); add_to_set(s1, 2); 38 | s2 = new_set(3); add_to_set(s2, 1); add_to_set(s2, 3); 39 | 40 | s3 = set_intersection(s1, s2); 41 | assert(1, in_set(s3, 1)); 42 | assert(0, in_set(s3, 2)); 43 | assert(0, in_set(s3, 3)); 44 | 45 | s3 = set_union(s1, s2); 46 | assert(1, in_set(s3, 1)); 47 | assert(1, in_set(s3, 2)); 48 | assert(1, in_set(s3, 3)); 49 | 50 | s3 = set_difference(s1, s2); 51 | assert(0, in_set(s3, 1)); 52 | assert(1, in_set(s3, 2)); 53 | assert(0, in_set(s3, 3)); 54 | } 55 | 56 | void test_set_eq() { 57 | Set *s1, *s2, *s3; 58 | 59 | s1 = new_set(3); add_to_set(s1, 1); add_to_set(s1, 2); 60 | s2 = new_set(3); add_to_set(s2, 1); add_to_set(s2, 3); 61 | assert(0, set_eq(s1, s2)); 62 | 63 | s2 = new_set(3); add_to_set(s2, 1); add_to_set(s2, 2); 64 | assert(1, set_eq(s1, s2)); 65 | } 66 | 67 | void test_cache_elements() { 68 | Set *s; 69 | 70 | s = new_set(3); add_to_set(s, 1); add_to_set(s, 2); 71 | cache_set_elements(s); 72 | assert(2, s->cached_element_count); 73 | assert(1, s->cached_elements[0]); 74 | assert(2, s->cached_elements[1]); 75 | 76 | add_to_set(s, 3); 77 | cache_set_elements(s); 78 | assert(3, s->cached_element_count); 79 | assert(1, s->cached_elements[0]); 80 | assert(2, s->cached_elements[1]); 81 | assert(3, s->cached_elements[2]); 82 | 83 | delete_from_set(s, 2); 84 | cache_set_elements(s); 85 | assert(2, s->cached_element_count); 86 | assert(1, s->cached_elements[0]); 87 | assert(3, s->cached_elements[1]); 88 | } 89 | 90 | int main() { 91 | test_add_delete(); 92 | test_merges(); 93 | test_set_eq(); 94 | test_cache_elements(); 95 | } 96 | -------------------------------------------------------------------------------- /tests/unit/test-strmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../../wcc.h" 7 | 8 | int main() { 9 | StrMap *map = new_strmap(); 10 | 11 | int COUNT = 10000; 12 | for (int i = 0; i < COUNT; i++) { 13 | char *key = malloc(16); 14 | char *value = malloc(16); 15 | sprintf(key, "foo %d", i); 16 | sprintf(value, "bar %d", i); 17 | strmap_put(map, key, value); 18 | } 19 | 20 | // Lookup the keys 21 | for (int i = 0; i < COUNT; i++) { 22 | char *key = malloc(16); 23 | char *value = malloc(16); 24 | sprintf(key, "foo %d", i); 25 | sprintf(value, "bar %d", i); 26 | char *got_value = strmap_get(map, key); 27 | if (!got_value) panic("Didn't get a match\n"); 28 | if (strcmp(value, got_value)) panic("Got something horrible 1"); 29 | 30 | got_value = strmap_get(map, "nuttin"); 31 | if (got_value) panic("Expected no match"); 32 | } 33 | 34 | // Test iteration 35 | int i = 0, h = 0; 36 | for (StrMapIterator it = strmap_iterator(map); !strmap_iterator_finished(&it); strmap_iterator_next(&it), i++) { 37 | char *value = strmap_iterator_key(&it); 38 | h += 7 * atoi(&(value[4])); 39 | } 40 | if (h != 349965000) panic("Iteration checksum ok"); 41 | 42 | // Reassign the even numbered elements with baz %d 43 | for (int i = 1; i < COUNT; i += 2) { 44 | char *key = malloc(16); 45 | char *value = malloc(16); 46 | sprintf(key, "foo %d", i); 47 | sprintf(value, "baz %d", i); 48 | strmap_put(map, key, value); 49 | } 50 | 51 | // Recheck the keys with alternating values 52 | for (int i = 0; i < COUNT; i++) { 53 | char *key = malloc(16); 54 | char *value = malloc(16); 55 | sprintf(key, "foo %d", i); 56 | sprintf(value, i % 2 == 0 ? "bar %d" : "baz %d", i); 57 | 58 | char *got_value = strmap_get(map, key); 59 | if (!got_value) panic("Didn't get a match\n"); 60 | if (strcmp(value, got_value)) panic("Got something horrible 2"); 61 | got_value = strmap_get(map, "nuttin"); 62 | if (got_value) panic("Expected no match"); 63 | } 64 | 65 | // Delete half of the keys 66 | for (int i = 1; i < COUNT; i += 2) { 67 | char *key = malloc(16); 68 | sprintf(key, "foo %d", i); 69 | strmap_delete(map, key); 70 | } 71 | 72 | // Check half keys are gone 73 | for (int i = 0; i < COUNT; i++) { 74 | char *key = malloc(16); 75 | sprintf(key, "foo %d", i); 76 | char *got_value = strmap_get(map, key); 77 | if ((!!got_value) == (!!(i % 2))) panic("Mismatch in key deletion"); 78 | } 79 | 80 | // Test iteration again, now that the map has deleted values 81 | i = 0, h = 0; 82 | for (StrMapIterator it = strmap_iterator(map); !strmap_iterator_finished(&it); strmap_iterator_next(&it), i++) { 83 | char *value = strmap_iterator_key(&it); 84 | h += 7 * atoi(&(value[4])); 85 | } 86 | if (h != 174965000) panic("Iteration checksum ok"); 87 | 88 | // Insert/deletion thrashing in a new map. This tests rehashing without 89 | // a resize. 90 | map = new_strmap(); 91 | for (int i = 0; i < COUNT; i++) { 92 | char *key = malloc(16); 93 | char value[] = "foo"; 94 | sprintf(key, "foo %d", i); 95 | strmap_put(map, key, value); 96 | char *got_value = strmap_get(map, key); 97 | if (!got_value) panic("Did not get a key"); 98 | strmap_delete(map, key); 99 | got_value = strmap_get(map, key); 100 | if (got_value) panic("Got a key"); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/unit/test-strset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../../wcc.h" 7 | 8 | int main() { 9 | StrSet *ss1 = new_strset(); 10 | strset_add(ss1, "foo"); 11 | if (!strset_in(ss1, "foo")) panic("Expected foo in set"); 12 | if (strset_in(ss1, "bar")) panic("Did not expect bar in set"); 13 | 14 | StrSet *ss2 = new_strset(); 15 | strset_add(ss2, "bar"); 16 | 17 | // Unions 18 | StrSet *ss3 = strset_union(ss1, ss2); 19 | if (!strset_in(ss3, "foo")) panic("Expected foo in set"); 20 | if (!strset_in(ss3, "bar")) panic("Expected bar in set"); 21 | if (strset_in(ss3, "baz")) panic("Did not expect baz in set"); 22 | 23 | StrSet *ss4 = new_strset(); 24 | strset_add(ss4, "foo"); 25 | StrSet *ss5 = strset_union(ss3, ss4); 26 | if (!strset_in(ss5, "foo")) panic("Expected foo in set"); 27 | if (!strset_in(ss5, "bar")) panic("Expected bar in set"); 28 | if (strset_in(ss5, "baz")) panic("Did not expect baz in set"); 29 | 30 | // Intersections 31 | StrSet *ssi1 = strset_intersection(ss1, ss2); 32 | if (strset_in(ssi1, "foo")) panic("Did not expect foo in set"); 33 | if (strset_in(ssi1, "bar")) panic("Did not expect bar in set"); 34 | if (strset_in(ssi1, "baz")) panic("Did not expect baz in set"); 35 | 36 | StrSet *ssi2 = strset_intersection(ss1, ss3); 37 | if (!strset_in(ssi2, "foo")) panic("Expected foo in set"); 38 | if (strset_in(ssi2, "bar")) panic("Did not expect bar in set"); 39 | if (strset_in(ssi2, "baz")) panic("Did not expect baz in set"); 40 | 41 | StrSet *ssi3 = strset_intersection(new_strset(), new_strset()); 42 | if (strset_in(ssi3, "foo")) panic("Did not expect foo in set"); 43 | 44 | StrSet *ssi4 = strset_intersection(ss1, new_strset()); 45 | if (strset_in(ssi4, "foo")) panic("Did not expect foo in set"); 46 | 47 | StrSet *ssi5 = strset_intersection(new_strset(), ss1); 48 | if (strset_in(ssi5, "foo")) panic("Did not expect foo in set"); 49 | 50 | StrSet *ss6 = dup_strset(ss5); 51 | if (!strset_in(ss5, "foo")) panic("Expected foo in set"); 52 | if (!strset_in(ss5, "bar")) panic("Expected bar in set"); 53 | } 54 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | benchmark 2 | rulecov.html 3 | make-rule-coverage-report 4 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | benchmark: benchmark.c 2 | gcc ${GCC_OPTS} benchmark.c -o benchmark 3 | 4 | run-benchmark: benchmark 5 | ./benchmark 6 | 7 | make-rule-coverage-report.s: ../wcc make-rule-coverage-report.c 8 | ../wcc ${WCC_OPTS} -c -S make-rule-coverage-report.c -c -S -o make-rule-coverage-report.s 9 | 10 | make-rule-coverage-report: make-rule-coverage-report.s 11 | gcc ${GCC_OPTS} -D _GNU_SOURCE -g -o make-rule-coverage-report make-rule-coverage-report.s ../lexer.c ../parser.c ../types.c ../ir.c ../instrrules.c ../instrutil.c ../codegen.c ../utils.c ../set.c 12 | 13 | rule-coverage-report: make-rule-coverage-report 14 | ./make-rule-coverage-report 15 | 16 | clean: 17 | @rm -f benchmark 18 | @rm -f make-rule-coverage-report 19 | @rm -f rulecov.html 20 | @rm -f *.s 21 | @rm -f *.o 22 | @rm -f core 23 | @rm -f instrsel-tests.rulecov 24 | -------------------------------------------------------------------------------- /tools/benchmark.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int sort_array(long *a, int count) { 6 | int i, j; 7 | long t; 8 | 9 | for (i = 0; i < count; i++) 10 | for (j = i; j < count; j++) 11 | if (a[i] > a[j]) t = a[i], a[i] = a[j], a[j] = t; 12 | } 13 | 14 | int main(int argc, char **argv) { 15 | int i, j, command_count, run_count, result; 16 | char **commands, *command; 17 | struct timeval start, end; 18 | long secs_used,microseconds; 19 | long *times; 20 | long first_time; 21 | 22 | command_count = 2; 23 | commands = malloc(sizeof(char *) * command_count); 24 | commands[0] = "../wcc ../ssa.c -c -S -o /dev/null"; 25 | commands[1] = "../wcc2 ../ssa.c -c -S -o /dev/null"; 26 | 27 | run_count = 5; // Must be odd for the median to work correctly 28 | times = malloc(sizeof(long) * run_count); 29 | 30 | for (i = 0; i < command_count; i++) { 31 | command = commands[i]; 32 | printf("Executing %-70s ", command); 33 | 34 | for (j = 0; j < run_count; j++) { 35 | gettimeofday(&start, NULL); 36 | result = system(command); 37 | gettimeofday(&end, NULL); 38 | if (result) { 39 | printf("\nBad exit code %d\n", result >> 8); 40 | exit(1); 41 | } 42 | 43 | secs_used=(end.tv_sec - start.tv_sec); //avoid overflow by subtracting first 44 | microseconds= ((secs_used*1000000) + end.tv_usec) - (start.tv_usec); 45 | 46 | times[j] = microseconds; 47 | } 48 | 49 | sort_array(times, run_count); 50 | if (i == 0) first_time = times[run_count / 2]; 51 | printf("%ld us %0.2f%%\n", times[run_count / 2], 100.0 * (double) times[run_count / 2] / (double) first_time); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tools/make-rule-coverage-report.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../wcc.h" 5 | 6 | static void read_coverage_file(char *path, Set* coverage) { 7 | void *f; 8 | char *input; 9 | int rule; 10 | 11 | f = fopen(path, "r"); 12 | if (!f) { 13 | perror(path); 14 | exit(1); 15 | } 16 | 17 | input = malloc(10 * 1024 * 1024); 18 | input_size = fread(input, 1, 10 * 1024 * 1024, f); 19 | if (input_size < 0) { 20 | printf("Unable to read input file\n"); 21 | exit(1); 22 | } 23 | input[input_size] = 0; 24 | 25 | rule = 0; 26 | while (*input) { 27 | if (*input == '\n') { 28 | add_to_set(coverage, rule); 29 | rule = 0; 30 | } 31 | else 32 | rule = rule * 10 + (*input - '0'); 33 | 34 | input++; 35 | } 36 | 37 | fclose(f); 38 | } 39 | 40 | int main() { 41 | Set *wcc2_cov, *instrsel_tests_cov, *wcc_tests_cov; 42 | void *f; 43 | int i; 44 | int covered, covered_count; 45 | Rule *r; 46 | 47 | init_instruction_selection_rules(); 48 | 49 | wcc2_cov = new_set(instr_rule_count); 50 | instrsel_tests_cov = new_set(instr_rule_count); 51 | wcc_tests_cov = new_set(instr_rule_count); 52 | 53 | read_coverage_file("../tests/e2e/wcc-tests.rulecov", wcc2_cov); 54 | read_coverage_file("../tests/integration/instrsel-tests.rulecov", instrsel_tests_cov); 55 | read_coverage_file("../wcc2.rulecov", wcc_tests_cov); 56 | 57 | f = fopen("rulecov.html", "w"); 58 | 59 | fprintf(f, "\n"); 60 | fprintf(f, "\n"); 61 | 62 | fprintf(f, "\n"); 78 | 79 | fprintf(f, "\n"); 80 | fprintf(f, "\n"); 81 | fprintf(f, "

WCC Instruction Selection Rules Coverage

\n"); 82 | fprintf(f, "\n"); 83 | 84 | fprintf(f, ""); 85 | fprintf(f, "\n"); 86 | fprintf(f, "\n"); 87 | fprintf(f, "\n"); 88 | fprintf(f, "\n"); 89 | fprintf(f, "\n"); 90 | fprintf(f, "\n"); 91 | fprintf(f, "\n"); 92 | fprintf(f, "\n"); 93 | fprintf(f, "\n"); 94 | fprintf(f, ""); 95 | 96 | covered_count = 0; 97 | for (i = 0; i <= rule_coverage->max_value; i++) { 98 | covered = wcc2_cov->elements[i] || instrsel_tests_cov->elements[i] || wcc_tests_cov->elements[i]; 99 | if (covered) covered_count++; 100 | 101 | fprintf(f, ""); 102 | fprintf(f, "\n", i); 103 | fprintf(f, "", covered ? "inset" : "", operation_string(r->operation)); 109 | fprintf(f, "", covered ? "inset" : "", non_terminal_string(r->dst)); 110 | fprintf(f, "", covered ? "inset" : "", non_terminal_string(r->src1)); 111 | fprintf(f, "", covered ? "inset" : "", non_terminal_string(r->src2)); 112 | fprintf(f, "", covered ? "inset" : "", r->cost); 113 | 114 | fprintf(f, ""); 115 | 116 | fprintf(f, ""); 117 | } 118 | 119 | fprintf(f, "
RuleWCC testsInstrsel testsWCC2OperationDstSrc1Src2Cost
%d", wcc2_cov->elements[i] ? "inset" : ""); 104 | fprintf(f, "", instrsel_tests_cov->elements[i] ? "inset" : ""); 105 | fprintf(f, "", wcc_tests_cov->elements[i] ? "inset" : ""); 106 | 107 | r = &(instr_rules[i]); 108 | fprintf(f, "%s%s%s%s%d
\n"); 120 | fprintf(f, "\n"); 121 | fprintf(f, "\n"); 122 | 123 | fclose(f); 124 | 125 | printf("%d%% (%d / %d) of the rules are covered \n", covered_count * 100 / instr_rule_count, covered_count, instr_rule_count); 126 | } 127 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "wcc.h" 8 | 9 | static struct timeval debug_log_start; 10 | 11 | // Report an internal error and exit 12 | void panic(char *format, ...) { 13 | va_list ap; 14 | va_start(ap, format); 15 | fprintf(stderr, "Internal error: "); 16 | vfprintf(stderr, format, ap); 17 | fprintf(stderr, "\n"); 18 | va_end(ap); 19 | exit(1); 20 | } 21 | 22 | // Strip the filename component from a path 23 | char *base_path(char *path) { 24 | int end = strlen(path) - 1; 25 | char *result = wmalloc(strlen(path) + 1); 26 | while (end >= 0 && path[end] != '/') end--; 27 | if (end >= 0) result = memcpy(result, path, end + 1); 28 | result[end + 1] = 0; 29 | 30 | return result; 31 | } 32 | 33 | int wasprintf(char **ret, const char *format, ...) { 34 | va_list ap1; 35 | va_start(ap1, format); 36 | va_list ap2; 37 | va_copy(ap2, ap1); 38 | int size = vsnprintf(NULL, 0, format, ap1); 39 | va_end(ap1); 40 | *ret = wmalloc(size + 1); 41 | vsnprintf(*ret, size + 1, format, ap2); 42 | va_end(ap2); 43 | 44 | return size; 45 | } 46 | 47 | // Allocate data for a new string buffer, rounding initial_size up to a power of two. 48 | StringBuffer *new_string_buffer(int initial_size) { 49 | StringBuffer *sb = wmalloc(sizeof(StringBuffer)); 50 | sb->position = 0; 51 | 52 | int allocated = 1; 53 | while (allocated < initial_size * 2) allocated <<= 1; 54 | sb->allocated = allocated; 55 | sb->data = wmalloc(allocated); 56 | 57 | return sb; 58 | } 59 | 60 | void free_string_buffer(StringBuffer *sb, int free_data) { 61 | if (free_data) wfree(sb->data); 62 | wfree(sb); 63 | } 64 | 65 | // Append a string to the string buffer 66 | void append_to_string_buffer(StringBuffer *sb, char *str) { 67 | int len = strlen(str); 68 | int needed = sb->position + len + 1; 69 | if (sb->allocated < needed) { 70 | while (sb->allocated < needed) sb->allocated <<= 1; 71 | sb->data = wrealloc(sb->data, sb->allocated); 72 | } 73 | sprintf(sb->data + sb->position, "%s", str); 74 | sb->position += len; 75 | } 76 | 77 | // Null terminate the string in the string buffer 78 | void terminate_string_buffer(StringBuffer *sb) { 79 | sb->data[sb->position] = 0; 80 | } 81 | 82 | int set_debug_logging_start_time() { 83 | gettimeofday(&debug_log_start, NULL); 84 | } 85 | 86 | int debug_log(char *format, ...) { 87 | struct timeval end; 88 | 89 | va_list ap; 90 | va_start(ap, format); 91 | 92 | gettimeofday(&end, NULL); 93 | long secs_used=(end.tv_sec - debug_log_start.tv_sec); //avoid overflow by subtracting first 94 | long microseconds = ((secs_used*1000000) + end.tv_usec) - (debug_log_start.tv_usec); 95 | secs_used = microseconds / 1000000; 96 | microseconds = (microseconds % 1000000); 97 | microseconds /= 1000; 98 | 99 | int hr=(int)(secs_used/3600); 100 | int min=((int)(secs_used/60))%60; 101 | int sec=(int)(secs_used%60); 102 | 103 | printf("%02d:%02d:%02d.%03ld ", hr, min, sec, microseconds); 104 | vprintf(format, ap); 105 | printf("\n"); 106 | } 107 | -------------------------------------------------------------------------------- /wcc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wcc.h" 7 | 8 | void init_instruction_selection_rules(void) { 9 | init_generated_instruction_selection_rules(); 10 | 11 | init_rules_by_operation(); 12 | 13 | rule_coverage = new_set(instr_rule_count - 1); 14 | } 15 | 16 | void free_instruction_selection_rules(void) { 17 | free_set(rule_coverage); 18 | free_rules_by_operation(); 19 | } 20 | 21 | char init_memory_management_for_translation_unit(void) { 22 | init_type_allocations(); 23 | init_value_allocations(); 24 | init_function_allocations(); 25 | init_ir(); 26 | } 27 | 28 | char free_memory_for_translation_unit(void) { 29 | free_types(); 30 | free_values(); 31 | free_functions(); 32 | free_ir(); 33 | } 34 | 35 | char *make_temp_filename(char *template) { 36 | template = wstrdup(template); 37 | int fd = mkstemps(template, 2); 38 | if (fd == -1) { 39 | perror("in make_temp_filename"); 40 | exit(1); 41 | } 42 | close(fd); 43 | 44 | return template; 45 | } 46 | 47 | void run_compiler_phases(Function *function, char *function_name, int start_at, int stop_at) { 48 | if (log_compiler_phase_durations) set_debug_logging_start_time(); 49 | 50 | if (log_compiler_phase_durations) debug_log("Starting compiler phases for of %s", function_name); 51 | 52 | if (start_at == COMPILE_START_AT_BEGINNING) { 53 | convert_enums(function); 54 | process_struct_and_union_copies(function); 55 | reverse_function_argument_order(function); 56 | merge_consecutive_labels(function); 57 | renumber_labels(function); 58 | allocate_value_vregs(function); 59 | convert_long_doubles_jz_and_jnz(function); 60 | add_zero_memory_instructions(function); 61 | move_long_doubles_to_the_stack(function); 62 | allocate_value_stack_indexes(function); 63 | process_bit_fields(function); 64 | remove_unused_function_call_results(function); 65 | } 66 | 67 | // Prepare for SSA phi function insertion 68 | sanity_test_ir_linkage(function); 69 | if (log_compiler_phase_durations) debug_log("Optimizing arithmetic operations"); 70 | optimize_arithmetic_operations(function); 71 | if (log_compiler_phase_durations) debug_log("Function arg/param manipulation"); 72 | add_function_param_moves(function, function_name); 73 | add_function_return_moves(function, function_name); 74 | add_function_call_result_moves(function); 75 | process_function_varargs(function); 76 | add_function_call_arg_moves(function); 77 | 78 | if (log_compiler_phase_durations) debug_log("Adding PIC loads & saves"); 79 | add_PIC_load_and_saves(function); 80 | if (log_compiler_phase_durations) debug_log("Converting & functions to loads"); 81 | convert_functions_address_of(function); 82 | if (log_compiler_phase_durations) debug_log("Converting lvalue assignments"); 83 | rewrite_lvalue_reg_assignments(function); 84 | 85 | if (log_compiler_phase_durations) debug_log("Analyzing dominance"); 86 | analyze_dominance(function); 87 | if (stop_at == COMPILE_STOP_AFTER_ANALYZE_DOMINANCE) return; 88 | 89 | // Insert SSA phi functions 90 | sanity_test_ir_linkage(function); 91 | make_globals_and_var_blocks(function); 92 | insert_phi_functions(function); 93 | if (stop_at == COMPILE_STOP_AFTER_INSERT_PHI_FUNCTIONS) return; 94 | 95 | // Come out of SSA and coalesce live ranges 96 | free_globals_and_var_blocks(function); 97 | sanity_test_ir_linkage(function); 98 | rename_phi_function_variables(function); 99 | 100 | if (log_compiler_phase_durations) debug_log("Make live ranges"); 101 | make_live_ranges(function); 102 | blast_vregs_with_live_ranges(function); 103 | coalesce_live_ranges(function, 1); 104 | if (stop_at == COMPILE_STOP_AFTER_LIVE_RANGES) return; 105 | 106 | free_phi_functions(function); 107 | free_interference_graph(function); 108 | free_live_range_spill_cost(function); 109 | free_vreg_preg_classes(function); 110 | free_preferred_live_range_preg_indexes(function); 111 | 112 | // Instruction selection 113 | if (log_compiler_phase_durations) debug_log("Instruction Selection"); 114 | select_instructions(function); 115 | free_liveout(function); 116 | free_dominance(function); 117 | compress_vregs(function); 118 | if (log_compiler_phase_durations) debug_log("Analyzing dominance"); 119 | analyze_dominance(function); 120 | coalesce_live_ranges(function, 0); 121 | free_interference_graph(function); 122 | remove_vreg_self_moves(function); 123 | if (rule_coverage_file) write_rule_coverage_file(); 124 | 125 | if (stop_at == COMPILE_STOP_AFTER_INSTRUCTION_SELECTION) return; 126 | 127 | // Register allocation and spilling 128 | if (log_compiler_phase_durations) debug_log("Register allocation"); 129 | sanity_test_ir_linkage(function); 130 | make_interference_graph(function, 1, 0); 131 | free_liveout(function); 132 | free_dominance(function); 133 | allocate_registers(function); 134 | free_interference_graph(function); 135 | free_live_range_spill_cost(function); 136 | free_vreg_preg_classes(function); 137 | free_preferred_live_range_preg_indexes(function); 138 | remove_stack_self_moves(function); 139 | add_spill_code(function); 140 | 141 | if (stop_at == COMPILE_STOP_AFTER_ADD_SPILL_CODE) return; 142 | 143 | // Final x86_64 changes 144 | make_stack_offsets(function, function_name); 145 | add_final_x86_instructions(function, function_name); 146 | remove_nops(function); 147 | merge_rsp_func_call_add_subs(function); 148 | 149 | if (log_compiler_phase_durations) debug_log("Finished compilation"); 150 | } 151 | 152 | static void compile_internals(void) { 153 | init_lexer_from_string(internals()); 154 | parse(); 155 | free_lexer(); 156 | } 157 | 158 | void compile(char *input, char *original_input_filename, char *output_filename) { 159 | init_parser(); 160 | 161 | if (!debug_dont_compile_internals) compile_internals(); 162 | 163 | memcpy_symbol = lookup_symbol("memcpy", global_scope, 0); 164 | memset_symbol = lookup_symbol("memset", global_scope, 0); 165 | 166 | compile_phase = CP_PARSING; 167 | init_lexer_from_string(input); 168 | parse(); 169 | free_lexer(); 170 | 171 | if (debug_exit_after_parser) goto exit_compile; 172 | 173 | compile_phase = CP_POST_PARSING; 174 | 175 | init_instrsel(); 176 | init_codegen(); 177 | 178 | // Compile all functions 179 | for (int i = 0; i < global_scope->symbol_list->length; i++) { 180 | Symbol *symbol = global_scope->symbol_list->elements[i]; 181 | if (symbol->type->type == TYPE_FUNCTION && symbol->function->is_defined) { 182 | Function *function = symbol->function; 183 | if (print_ir1) print_ir(function, symbol->identifier, 0); 184 | 185 | run_compiler_phases(function, symbol->identifier, COMPILE_START_AT_BEGINNING, COMPILE_STOP_AT_END); 186 | if (print_ir2) print_ir(function, symbol->identifier, 0); 187 | } 188 | } 189 | 190 | output_code(original_input_filename, output_filename); 191 | 192 | for (int i = 0; i < global_scope->symbol_list->length; i++) { 193 | Symbol *symbol = global_scope->symbol_list->elements[i]; 194 | if (symbol->type->type == TYPE_FUNCTION && symbol->function->is_defined) 195 | free_function(symbol->function, 1); 196 | } 197 | 198 | free_instrsel(); 199 | free_codegen(); 200 | 201 | exit_compile:; 202 | free_parser(); 203 | } 204 | --------------------------------------------------------------------------------