├── .clang-format ├── .gitignore ├── Makefile ├── README.md ├── __.c ├── __.h ├── __va.c ├── alignment.c ├── analyzer.h ├── build_files.sh ├── codegen.c ├── codegen_expression.c ├── codegen_switch.c ├── compile2.sh ├── cpp.c ├── error.c ├── file_io.c ├── file_io.h ├── global_flags.h ├── header.h ├── ir └── .gitkeep ├── lexer.c ├── main.c ├── map.c ├── map.h ├── misc ├── assembly_sandbox.c ├── call_va.c ├── create_va.c ├── diary.md ├── digits_of_e.c ├── donut_donut.c ├── donut_verbose.c ├── game_of_life.c ├── linktest1.c ├── linktest2.c ├── pi.c ├── smallstruct.c ├── smallstruct2.c ├── supplement0.c ├── supplement1.c ├── todo.md ├── va.c ├── va_linux.s └── va_macos.s ├── out └── .gitkeep ├── parse_analyze_statement.c ├── parse_analyze_toplevel.c ├── parse_expression.c ├── parse_type.c ├── print_x86_64.c ├── print_x86_64.h ├── print_x86_64_unofficial.c ├── print_x86_64_unofficial.h ├── printerstate.h ├── s └── .gitkeep ├── self_compile_asm └── .gitkeep ├── std.c ├── std.h ├── std_io.h ├── test ├── call_va_.c ├── char_literal.c ├── duff.c ├── error_if_pedantic │ ├── backslash_e.c │ ├── binary_literal.c │ └── toplevel_semicolon.c ├── escape.c ├── link1.c ├── link2.c ├── nqueen2.c ├── nqueen3.c ├── nqueen4.c ├── nqueen5.c ├── nqueen6.c ├── nqueen7.c ├── nqueen8.c ├── preprocess.c ├── preprocess2.c ├── preprocess3.c ├── preprocess4.c ├── preprocess5.c ├── quine.c ├── quine2.c ├── quine2_res.c ├── quine_res.c ├── small_struct.c ├── vector_test.c ├── vector_test2.c ├── vector_test3.c └── vector_test4.c ├── test_cases.sh ├── test_cases_that_are_compile_error_only_if_pedantic.sh ├── test_compile_error.sh ├── toplevel.h ├── type.c ├── typecheck_expression.c ├── vector.c ├── vector.h └── verifier └── typeparse_checker.c /.clang-format: -------------------------------------------------------------------------------- 1 | TabWidth: 4 2 | IndentWidth: 4 3 | UseTab: ForIndentation 4 | BreakBeforeBraces: Linux 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Autogenerated 55 | s/*.s 56 | template/ 57 | 58 | self_compile_asm/*.s 59 | ir/_*.txt 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UNAME_S := $(shell uname -s) 2 | ifeq ($(UNAME_S),Linux) 3 | OSFLAG += -DLINUX 4 | endif 5 | ifeq ($(UNAME_S),Darwin) 6 | OSFLAG += -DOSX 7 | endif 8 | 9 | ifeq ($(UNAME_S),Linux) 10 | VAPATH = misc/va_linux.s 11 | endif 12 | ifeq ($(UNAME_S),Darwin) 13 | VAPATH = misc/va_macos.s 14 | endif 15 | 16 | 17 | SRC=std.c codegen.c alignment.c parse_analyze_toplevel.c parse_analyze_statement.c codegen_expression.c main.c vector.c typecheck_expression.c parse_expression.c error.c type.c parse_type.c map.c print_x86_64.c print_x86_64_unofficial.c lexer.c codegen_switch.c file_io.c cpp.c 18 | 19 | CLANG_WARN=-Wall -Wextra -Wimplicit-fallthrough -Weverything -Wno-documentation -Wno-padded -Wno-missing-prototypes -Wno-switch-enum -Wno-sign-conversion -Wno-format-nonliteral 20 | 21 | LINKER=gcc -no-pie -Wno-unused-command-line-argument 22 | 23 | TYPECHECKSRC=vector.c verifier/typeparse_checker.c lexer.c type.c parse_type.c error.c map.c file_io.c cpp.c 24 | 25 | 26 | # out/compiler.out is purely from clang/gcc 27 | 1stgen: 28 | gcc -Wall -Wextra -DOVERRIDE_STD -g $(SRC) $(OSFLAG) -o out/compiler.out 29 | cp -p out/compiler.out out/compiler_1stgen.out 30 | 31 | va: 32 | gcc -Wall -Wextra misc/create_va.c print_x86_64.c print_x86_64_unofficial.c $(OSFLAG) -o out/create_va.out 33 | ./out/create_va.out > $(VAPATH) 34 | $(LINKER) $(VAPATH) misc/call_va.c -o out/va.out 35 | ./out/va.out 36 | 37 | va2: 38 | make 1stgen 39 | ./out/compiler.out $(OSFLAG) -DOVERRIDE_STD __va.c > s/__va.s 40 | $(LINKER) s/__va.s test/call_va_.c -o out/va2.out 41 | ./out/va2.out 42 | 43 | va3: 44 | make 1stgen 45 | ./out/compiler.out $(OSFLAG) -DOVERRIDE_STD __va.c > s/__va.s 46 | ./out/compiler.out $(OSFLAG) -DOVERRIDE_STD test/call_va_.c > s/call_va_.s 47 | $(LINKER) s/__va.s s/call_va_.s -o out/va3.out 48 | ./out/va3.out 49 | 50 | 51 | test_include: 52 | make 1stgen 53 | ./compile2.sh map $(OSFLAG) 54 | ./out/compiler.out __.c > self_compile_asm/__.s 55 | $(LINKER) self_compile_asm/__.s self_compile_asm/map.s -o out/test_include.out 56 | ./out/test_include.out 57 | 58 | 2ndgen: 59 | make 1stgen 60 | ./compile2.sh vector $(OSFLAG) 61 | ./compile2.sh map $(OSFLAG) 62 | ./compile2.sh print_x86_64 $(OSFLAG) 63 | ./compile2.sh print_x86_64_unofficial $(OSFLAG) 64 | ./compile2.sh alignment $(OSFLAG) 65 | ./compile2.sh codegen_expression $(OSFLAG) 66 | ./compile2.sh std $(OSFLAG) 67 | ./compile2.sh error $(OSFLAG) 68 | ./compile2.sh codegen $(OSFLAG) 69 | ./compile2.sh codegen_switch $(OSFLAG) 70 | ./compile2.sh parse_analyze_statement $(OSFLAG) 71 | ./compile2.sh parse_analyze_toplevel $(OSFLAG) 72 | ./compile2.sh parse_expression $(OSFLAG) 73 | ./compile2.sh parse_type $(OSFLAG) 74 | ./compile2.sh type $(OSFLAG) 75 | ./compile2.sh typecheck_expression $(OSFLAG) 76 | ./compile2.sh file_io $(OSFLAG) 77 | ./compile2.sh main $(OSFLAG) 78 | ./compile2.sh lexer $(OSFLAG) 79 | ./compile2.sh cpp $(OSFLAG) 80 | $(LINKER) self_compile_asm/std.s self_compile_asm/codegen.s self_compile_asm/alignment.s self_compile_asm/parse_analyze_toplevel.s self_compile_asm/lexer.s self_compile_asm/codegen_expression.s self_compile_asm/main.s self_compile_asm/vector.s self_compile_asm/typecheck_expression.s self_compile_asm/parse_expression.s self_compile_asm/error.s self_compile_asm/type.s self_compile_asm/parse_type.s self_compile_asm/map.s self_compile_asm/print_x86_64.s self_compile_asm/print_x86_64_unofficial.s self_compile_asm/codegen_switch.s self_compile_asm/file_io.s $(OSFLAG) self_compile_asm/parse_analyze_statement.s self_compile_asm/cpp.s -o out/compiler.out 81 | cp -p out/compiler.out out/compiler_2ndgen.out 82 | 83 | test_2ndgen_compiler: 84 | make 2ndgen 85 | ./test_cases.sh 86 | ./test_compile_error.sh 87 | make compile_files 88 | ./compile2.sh vector $(OSFLAG) __with2nd 89 | ./compile2.sh map $(OSFLAG) __with2nd 90 | ./compile2.sh print_x86_64 $(OSFLAG) __with2nd 91 | ./compile2.sh print_x86_64_unofficial $(OSFLAG) __with2nd 92 | ./compile2.sh alignment $(OSFLAG) __with2nd 93 | ./compile2.sh codegen_expression $(OSFLAG) __with2nd 94 | ./compile2.sh std $(OSFLAG) __with2nd 95 | ./compile2.sh error $(OSFLAG) __with2nd 96 | ./compile2.sh codegen $(OSFLAG) __with2nd 97 | ./compile2.sh codegen_switch $(OSFLAG) __with2nd 98 | ./compile2.sh parse_analyze_statement $(OSFLAG) __with2nd 99 | ./compile2.sh parse_analyze_toplevel $(OSFLAG) __with2nd 100 | ./compile2.sh parse_expression $(OSFLAG) __with2nd 101 | ./compile2.sh parse_type $(OSFLAG) __with2nd 102 | ./compile2.sh type $(OSFLAG) __with2nd 103 | ./compile2.sh typecheck_expression $(OSFLAG) __with2nd 104 | ./compile2.sh file_io $(OSFLAG) __with2nd 105 | ./compile2.sh main $(OSFLAG) __with2nd 106 | ./compile2.sh lexer $(OSFLAG) __with2nd 107 | ./compile2.sh cpp $(OSFLAG) __with2nd 108 | $(LINKER) self_compile_asm/std__with2nd.s self_compile_asm/codegen__with2nd.s self_compile_asm/alignment__with2nd.s self_compile_asm/parse_analyze_toplevel__with2nd.s self_compile_asm/lexer.s self_compile_asm/codegen_expression__with2nd.s self_compile_asm/main__with2nd.s self_compile_asm/vector__with2nd.s self_compile_asm/typecheck_expression__with2nd.s self_compile_asm/parse_expression__with2nd.s self_compile_asm/error__with2nd.s self_compile_asm/type__with2nd.s self_compile_asm/parse_type__with2nd.s self_compile_asm/map__with2nd.s self_compile_asm/print_x86_64__with2nd.s self_compile_asm/print_x86_64_unofficial__with2nd.s self_compile_asm/codegen_switch__with2nd.s $(OSFLAG) self_compile_asm/parse_analyze_statement__with2nd.s self_compile_asm/file_io__with2nd.s self_compile_asm/cpp__with2nd.s -o out/compiler_gen3.out 109 | diff self_compile_asm/vector.s self_compile_asm/vector__with2nd.s 110 | diff self_compile_asm/map.s self_compile_asm/map__with2nd.s 111 | diff self_compile_asm/print_x86_64.s self_compile_asm/print_x86_64__with2nd.s 112 | diff self_compile_asm/print_x86_64_unofficial.s self_compile_asm/print_x86_64_unofficial__with2nd.s 113 | diff self_compile_asm/alignment.s self_compile_asm/alignment__with2nd.s 114 | diff self_compile_asm/codegen_expression.s self_compile_asm/codegen_expression__with2nd.s 115 | diff self_compile_asm/std.s self_compile_asm/std__with2nd.s 116 | diff self_compile_asm/error.s self_compile_asm/error__with2nd.s 117 | diff self_compile_asm/codegen.s self_compile_asm/codegen__with2nd.s 118 | diff self_compile_asm/codegen_switch.s self_compile_asm/codegen_switch__with2nd.s 119 | diff self_compile_asm/parse_analyze_statement.s self_compile_asm/parse_analyze_statement__with2nd.s 120 | diff self_compile_asm/parse_analyze_toplevel.s self_compile_asm/parse_analyze_toplevel__with2nd.s 121 | diff self_compile_asm/parse_expression.s self_compile_asm/parse_expression__with2nd.s 122 | diff self_compile_asm/parse_type.s self_compile_asm/parse_type__with2nd.s 123 | diff self_compile_asm/type.s self_compile_asm/type__with2nd.s 124 | diff self_compile_asm/typecheck_expression.s self_compile_asm/typecheck_expression__with2nd.s 125 | diff self_compile_asm/lexer.s self_compile_asm/lexer__with2nd.s 126 | diff self_compile_asm/file_io.s self_compile_asm/file_io__with2nd.s 127 | diff self_compile_asm/cpp.s self_compile_asm/cpp__with2nd.s 128 | 129 | test_all_: 130 | make assembly_sandbox 131 | make test_valid 132 | make verify_typeparse 133 | make check_error 134 | make test_2ndgen_compiler 135 | make test_include 136 | make struct_test 137 | make va2 138 | make va3 139 | 140 | struct_test: 141 | gcc -Wall -Wextra misc/smallstruct.c print_x86_64.c print_x86_64_unofficial.c $(OSFLAG) -o out/struct_codegen.out 142 | echo -e '' | ./out/struct_codegen.out > s/struct.s 143 | gcc s/struct.s misc/smallstruct2.c -o out/struct.out 144 | ./out/struct.out 145 | 146 | clean: 147 | rm out/*.out s/*.s self_compile_asm/*.s 148 | 149 | verify_typeparse: 150 | gcc -Wall -Wextra $(OSFLAG) $(TYPECHECKSRC) -o out/typeparse_check.out 151 | ./out/typeparse_check.out 152 | 153 | assembly_sandbox: 154 | gcc -Wall -Wextra misc/assembly_sandbox.c print_x86_64.c print_x86_64_unofficial.c $(OSFLAG) -o out/assembly_sandbox.out 155 | echo -e '' | ./out/assembly_sandbox.out > s/assembly_sandbox.s 156 | gcc misc/supplement1.c -S -o s/supplement1.s 157 | gcc s/assembly_sandbox.s s/supplement1.s -o out/sandbox.out 158 | ./out/sandbox.out || if [ $$? -ne 174 ]; then { echo "\n\033[31mFAIL\033[m"; exit 1; }; else echo "\n\033[32mPASS\033[m"; fi 159 | 160 | compile_files: 161 | make 1stgen 162 | ./build_files.sh 163 | cat test/quine.c | ./out/compiler.out > s/quine.s 164 | $(LINKER) s/quine.s -o out/quine.out 165 | ./out/quine.out > test/quine_res.c 166 | diff test/quine.c test/quine_res.c 167 | cat test/quine2.c | ./out/compiler.out > s/quine2.s 168 | $(LINKER) s/quine2.s -o out/quine2.out 169 | ./out/quine2.out > test/quine2_res.c 170 | diff test/quine2.c test/quine2_res.c 171 | cat test/vector_test.c | ./out/compiler.out > s/vector_test.s 172 | cat test/vector_test2.c | ./out/compiler.out > s/vector_test2.s 173 | cat test/vector_test3.c | ./out/compiler.out > s/vector_test3.s 174 | cat test/vector_test4.c | ./out/compiler.out > s/vector_test4.s 175 | gcc s/vector_test.s -c 176 | gcc s/vector_test2.s -c 177 | gcc s/vector_test3.s -c 178 | gcc s/vector_test4.s -c 179 | ./out/compiler.out test/link1.c > s/link1.s 180 | ./out/compiler.out test/link2.c > s/link2.s 181 | $(LINKER) s/link1.s s/link2.s -o out/link.out 182 | ./out/link.out; test $$? -eq 174 183 | 184 | 185 | test_valid: 186 | rm out/*.out 187 | make 1stgen 188 | make compile_files 189 | ./test_cases.sh 190 | 191 | check_error: 192 | make 1stgen 193 | ./test_compile_error.sh 194 | ./test_cases_that_are_compile_error_only_if_pedantic.sh 195 | 196 | # clang-format or clang 197 | notest: 198 | make format 199 | make 1stgen 200 | 201 | warn: 202 | make format 203 | clang $(CLANG_WARN) -DOVERRIDE_STD $(SRC) $(OSFLAG) -o out/compiler.out 204 | clang $(CLANG_WARN) misc/assembly_sandbox.c print_x86_64.c print_x86_64_unofficial.c $(OSFLAG) -o out/assembly_sandbox.out 205 | clang -Wall -Wextra -Wimplicit-fallthrough $(OSFLAG) $(TYPECHECKSRC) -o out/typeparse_check.out 206 | 207 | f: 208 | make format 209 | make test_all_ 210 | make test_sanitized_1stgen 211 | 212 | 213 | format: 214 | clang-format -i *.c *.h -style=file 215 | 216 | 1stgen_sanitized: 217 | clang -Wall -Wextra -DOVERRIDE_STD -g $(SRC) $(OSFLAG) -o out/compiler.out -fsanitize=address -fno-omit-frame-pointer 218 | cp -p out/compiler.out out/compiler_1stgen_sanitized.out 219 | 220 | test_sanitized_1stgen: 221 | make 1stgen_sanitized 222 | ./compile2.sh vector $(OSFLAG) 223 | ./compile2.sh map $(OSFLAG) 224 | ./compile2.sh print_x86_64 $(OSFLAG) 225 | ./compile2.sh print_x86_64_unofficial $(OSFLAG) 226 | ./compile2.sh alignment $(OSFLAG) 227 | ./compile2.sh codegen_expression $(OSFLAG) 228 | ./compile2.sh std $(OSFLAG) 229 | ./compile2.sh error $(OSFLAG) 230 | ./compile2.sh codegen $(OSFLAG) 231 | ./compile2.sh main $(OSFLAG) 232 | ./compile2.sh codegen_switch $(OSFLAG) 233 | ./compile2.sh parse_analyze_statement $(OSFLAG) 234 | ./compile2.sh parse_analyze_toplevel $(OSFLAG) 235 | ./compile2.sh parse_expression $(OSFLAG) 236 | ./compile2.sh parse_type $(OSFLAG) 237 | ./compile2.sh type $(OSFLAG) 238 | ./compile2.sh typecheck_expression $(OSFLAG) 239 | ./compile2.sh lexer $(OSFLAG) 240 | ./compile2.sh file_io $(OSFLAG) 241 | ./compile2.sh cpp $(OSFLAG) 242 | 243 | game_of_life: 244 | make 1stgen 245 | ./out/compiler.out misc/game_of_life.c > s/game_of_life.s 246 | gcc s/game_of_life.s -o out/game_of_life.out -no-pie -Wno-unused-command-line-argument 247 | ./out/game_of_life.out 248 | 249 | pi: 250 | make 1stgen 251 | ./out/compiler.out misc/pi.c > s/pi.s 252 | gcc s/pi.s -o out/pi.out -no-pie -Wno-unused-command-line-argument 253 | ./out/pi.out 254 | 255 | digits_of_e: 256 | make 1stgen 257 | ./out/compiler.out misc/digits_of_e.c > s/digits_of_e.s 258 | gcc s/digits_of_e.s -o out/digits_of_e.out -no-pie -Wno-unused-command-line-argument 259 | ./out/digits_of_e.out 260 | 261 | donut: 262 | make 1stgen 263 | ./out/compiler.out misc/donut_donut.c > s/donut_donut.s 264 | gcc s/donut_donut.s -o out/donut_donut.out -no-pie -Wno-unused-command-line-argument 265 | ./out/donut_donut.out -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # c-compiler 2 | seccamp2018 c compiler 3 | 4 | [日記](https://github.com/hsjoihs/c-compiler/blob/master/misc/diary.md) 5 | 6 | In case you are also making a toy C compiler, feel free to use [my test cases](./test_cases.sh) to test yours. I also have [negative test cases](./test_compile_error.sh), a list of inputs to which a C compiler should report an error. [test_cases_that_are_compile_error_only_if_pedantic.sh](./test_cases_that_are_compile_error_only_if_pedantic.sh) contains non-ISO extensions commonly implemented in many C compilers. hsjoihs-c-compiler reports an error with respect to those cases only when `-pedantic` is passed. 7 | 8 | ## Environment 9 | 10 | Tested on macOS (Catalina), Ubuntu (20.04.1 LTS) and Debian (10.5). 11 | 12 | ## How to run 13 | 14 | After cloning, run: 15 | 16 | ``` 17 | $ make 18 | ``` 19 | 20 | to compile. 21 | 22 | The compiler can be run as 23 | 24 | ``` 25 | $ cat input.c | ./out/compiler.out -DOSX -DOVERRIDE_STD > s/output.s 26 | ``` 27 | 28 | or as 29 | 30 | ``` 31 | $ ./out/compiler.out -DOSX -DOVERRIDE_STD input.c > s/output.s 32 | ``` 33 | 34 | for macOS; replace `-DOSX` with `-DLINUX` for Ubuntu. Note that, in Ubuntu, the generated assembly requires 35 | `-no-pie` to be passed to gcc in order for the linking to succeed. 36 | 37 | 38 | To self-compile, run 39 | 40 | ``` 41 | $ make 2ndgen 42 | ``` 43 | 44 | ; this will overwrite `./out/compiler.out`. 45 | 46 | ## How to test 47 | 48 | Run 49 | 50 | ``` 51 | $ make test_2ndgen_compiler 52 | ``` 53 | 54 | to test the self-compiled compiler. To test some more, run 55 | 56 | ``` 57 | $ make test_all_ 58 | ``` 59 | 60 | ## Fun samples 61 | 62 | ### Conway's game of life 63 | 64 | Based on https://gist.github.com/maekawatoshiki/8ea2f392e22698593d7ee8522aabbbd0 65 | 66 | ``` 67 | $ make game_of_life 68 | ``` 69 | 70 | ### Calculating digits of pi / e 71 | 72 | Based on https://xn--w6q13e505b.jp/program/spigot.html 73 | ``` 74 | $ make pi 75 | ``` 76 | 77 | ``` 78 | $ make digits_of_e 79 | ``` 80 | 81 | ### Donut 82 | 83 | ``` 84 | $ make donut 85 | ``` 86 | 87 | The following is the source code, which is greatly modified from [the original](https://www.a1k0n.net/2011/07/20/donut-math.html) to avoid floating-point calculations 88 | 89 | ```c 90 | int putchar();void* 91 | memset();int m(int a,int b) 92 | {return (a*b+5000)/10000;}void a( 93 | int*c,int*s,int d,int t){int k=m(*c,d 94 | )-m(*s,t);int l=m(*s,d)+m(*c,t);*c=k;*s=l 95 | ;}int usleep();int printf();int main(){int z[ 96 | 1760];char b[1760];printf("\e[2J");int s=10000; 97 | int q=s;int r=0;int u=s;int v=0;for(;;a(&q,&r,s-8 98 | ,400),a(&u,&v,s-2,200)){memset(b,32,1760);memset(z, 99 | 0,7040);int l=0;int p =s;for(int i=0;i<88;i 100 | ++,a(&p,&l,9974+i% 2,714)){int w=0;int 101 | e=s;for(int j=0;j< 314;j++,a(&e,&w,s- 102 | 2,200)){int f=p+2 *s;int g=s*s/(m(m 103 | (w,f),r)+m(l,q)+5* s);int t=m(m(w,q), 104 | f)-m(l,r);int x=40 +30*m(g,m(m(e,u),f 105 | )-m(t,v))/s;int y =12+15*m(g,m(m(e, 106 | v),f)+m(t,u))/s;int o=x+80*y;int N=8* 107 | (m(m(l,r)-m(m(w,q) ,p),u)-m(m(w,r),p)- 108 | m(l,q)-m(m(e,v),p))/s ;if(y>0&&g>z[o]&&y<22 109 | &&x>0&&80>x){z[o]=g;b[o]=".,-~:;=!*#$@"[N>=1?N:0]+0 110 | ;}}}printf("\e[H");for(int k=0;k<1761;k++)putchar 111 | (k%80?b[k]:10);printf("Author: @a1k0n. Rewritt" 112 | "en by @hsjoihs so that it works without flo" 113 | );https://github.com/hsjoihs/c-compiler/ 114 | printf("ating types.\nNote that roun" 115 | "ding errors gradually reduce th" 116 | "e donut's size.\n");usleep 117 | (50000);}return 0;} 118 | ``` 119 | -------------------------------------------------------------------------------- /__.c: -------------------------------------------------------------------------------- 1 | #include "__.h" 2 | #include "map.h" 3 | 4 | INT main() 5 | { 6 | struct Map2 *m = init_map(); 7 | int a = 3; 8 | int *p = &a; 9 | insert(m, "3", p); 10 | insert(m, "three", p); 11 | int *q = lookup(m, "3"); 12 | return *q - 3; 13 | } 14 | -------------------------------------------------------------------------------- /__.h: -------------------------------------------------------------------------------- 1 | #define main MAIN 2 | #define MAIN main 3 | #define INT int 4 | -------------------------------------------------------------------------------- /__va.c: -------------------------------------------------------------------------------- 1 | #include "std.h" 2 | #include "std_io.h" 3 | 4 | void debug_write(const char *fmt, ...) 5 | { 6 | struct va_list_tag ap[1]; 7 | 8 | va_start(ap, fmt); 9 | vfprintf(stderr, fmt, ap); 10 | va_end(ap); 11 | 12 | va_start(ap, fmt); 13 | vprintf(fmt, ap); 14 | va_end(ap); 15 | } 16 | -------------------------------------------------------------------------------- /alignment.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "std.h" 3 | 4 | struct SizeAndAlignment get_size_alignment_offsets_for_union( 5 | const struct SizeAndAlignment *inner_type_vec, int **ptr_offset_vec, 6 | int length) 7 | { 8 | struct SizeAndAlignment res; 9 | res.alignment = 1; 10 | 11 | /* union's alignment is the maximum of the members' alignments */ 12 | for (int i = 0; i < length; i++) { 13 | if (inner_type_vec[i].alignment > res.alignment) { 14 | res.alignment = inner_type_vec[i].alignment; 15 | } 16 | } 17 | 18 | int max_size_of_member = 1; 19 | 20 | /* union's size is AT LEAST the maximum of the members' sizes */ 21 | for (int i = 0; i < length; i++) { 22 | if (inner_type_vec[i].size > max_size_of_member) { 23 | max_size_of_member = inner_type_vec[i].size; 24 | } 25 | } 26 | 27 | if (max_size_of_member % res.alignment) { 28 | max_size_of_member += 29 | res.alignment - (max_size_of_member % res.alignment); 30 | } 31 | 32 | res.size = max_size_of_member; 33 | 34 | /* calloc; all is zero */ 35 | int *offset_vec = calloc(length, sizeof(int)); 36 | *ptr_offset_vec = offset_vec; 37 | return res; 38 | } 39 | 40 | struct SizeAndAlignment get_size_alignment_offsets_for_struct_not_union( 41 | const struct SizeAndAlignment *inner_type_vec, int **ptr_offset_vec, 42 | int length) 43 | { 44 | struct SizeAndAlignment res; 45 | res.alignment = 1; 46 | 47 | /* struct's alignment is the maximum of the members' alignments */ 48 | for (int i = 0; i < length; i++) { 49 | if (inner_type_vec[i].alignment > res.alignment) { 50 | res.alignment = inner_type_vec[i].alignment; 51 | } 52 | } 53 | 54 | int offset = 0; 55 | int *offset_vec = calloc(length, sizeof(int)); 56 | 57 | for (int i = 0; i < length; i++) { 58 | if (offset % inner_type_vec[i].alignment) { 59 | offset += inner_type_vec[i].alignment - 60 | (offset % inner_type_vec[i].alignment); 61 | } 62 | offset_vec[i] = offset; 63 | offset += inner_type_vec[i].size; 64 | } 65 | 66 | if (offset % res.alignment) { 67 | offset += res.alignment - (offset % res.alignment); 68 | } 69 | 70 | res.size = offset; 71 | *ptr_offset_vec = offset_vec; 72 | return res; 73 | } 74 | -------------------------------------------------------------------------------- /analyzer.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | struct LocalVarInfo { 4 | struct Type type; 5 | int offset; 6 | }; 7 | 8 | struct ScopeChain { 9 | struct Map2 * /**/ var_table; 10 | struct ScopeChain *outer; 11 | }; 12 | 13 | struct EnumeratorAndValue { 14 | const char *ident; 15 | int value; 16 | }; 17 | 18 | struct AnalyzerState { 19 | struct ScopeChain scope_chain; 20 | struct Map2 * /**/ global_vars_type_map; 21 | struct Map2 * /**/ func_info_map; 22 | struct Type func_ret_type; 23 | int newest_offset; 24 | struct Map2 * /**/ 25 | global_struct_or_union_tag_map; 26 | struct Map2 * /*>*/ global_enum_tag_map; 27 | struct Vector /**/ global_enumerator_list; 28 | const char *current_function_name; 29 | }; 30 | 31 | struct Expr typecheck_expression(struct AnalyzerState *ptr_ps, 32 | const struct UntypedExpr *ref_uexpr); 33 | 34 | struct Statement parse_statement(struct AnalyzerState *ptr_ps, 35 | const struct Token **ptr_tokvec); 36 | struct Statement parse_compound_statement(struct AnalyzerState *ptr_ps, 37 | const struct Token **ptr_tokvec); 38 | 39 | /* 40 | * Adjusts the newest_offset and add a local variable to the scope. 41 | * Returns the offset of the newly added variable. 42 | */ 43 | int add_local_var_to_scope(struct AnalyzerState *ptr_ps, 44 | const struct Type *ref_vartype, const char *str); 45 | 46 | int size_of(const struct AnalyzerState *ptr_ps, const struct Type *ref_type); 47 | int align_of(const struct AnalyzerState *ptr_ps, const struct Type *ref_type); 48 | 49 | void expect_type(const struct AnalyzerState *ptr_ps, 50 | const struct Type *ref_actual_type, 51 | const struct Type *ref_expected_type, const char *message); 52 | 53 | int typecheck_constant_integral_expression(struct AnalyzerState *ptr_ps, 54 | const struct UntypedExpr *ptr_uexpr, 55 | const char *context); 56 | 57 | enum SystemVAbiClass { INTEGER_CLASS, MEMORY_CLASS }; 58 | enum SystemVAbiClass system_v_abi_class_of(const struct AnalyzerState *ptr_ps, 59 | const struct Type *ref_type); 60 | 61 | void expect_scalar(const struct Type *ref_type, const char *context); 62 | void expect_integral(const struct Type *ref_actual_type, const char *message); 63 | 64 | void cast_to_null_pointer_if_possible(struct Expr *ref_e, 65 | const struct TypePair *ref_details); 66 | void if_function_cast_to_pointer(struct Expr *ptr_expr); 67 | -------------------------------------------------------------------------------- /build_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | build() { 3 | cat test/$1.c | ./out/compiler.out > s/$1.s 4 | gcc s/$1.s -o out/$1.out -no-pie -Wno-unused-command-line-argument 5 | ./out/$1.out || { echo -e "\033[31mFAIL\033[m, at test case" $1 ; exit 1; } 6 | } 7 | 8 | build2() { 9 | ./out/compiler.out test/$1.c > s/$1.s 10 | gcc s/$1.s -o out/$1.out -no-pie -Wno-unused-command-line-argument 11 | ./out/$1.out || { echo -e "\033[31mFAIL\033[m, at test case" $1 ; exit 1; } 12 | } 13 | 14 | build nqueen2 15 | build2 nqueen3 16 | build nqueen4 17 | build2 nqueen5 18 | build nqueen6 19 | build2 nqueen7 20 | build nqueen8 21 | build2 escape 22 | build duff 23 | build2 char_literal 24 | build2 preprocess 25 | build2 preprocess2 26 | build2 preprocess3 27 | build2 preprocess4 28 | build2 preprocess5 29 | build2 small_struct 30 | -------------------------------------------------------------------------------- /codegen.c: -------------------------------------------------------------------------------- 1 | #include "print_x86_64.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | #include "toplevel.h" 5 | 6 | static void print_toplevel_definition(struct PrinterState *ptr_prs, 7 | const struct Toplevel *ptr_def); 8 | 9 | int get_new_label_name(struct PrinterState *ptr_prs) 10 | { 11 | return ++(ptr_prs->final_label_name); 12 | } 13 | 14 | static int is_label_compatible(const struct SourceLabel *ptr_label1, 15 | const struct SourceLabel *ptr_label2) 16 | { 17 | if (ptr_label1->category == DEFAULT_LABEL && 18 | ptr_label2->category == DEFAULT_LABEL) { 19 | return 1; 20 | } else if (ptr_label1->category == CASE_LABEL && 21 | ptr_label2->category == CASE_LABEL && 22 | ptr_label1->case_int == ptr_label2->case_int) { 23 | return 1; 24 | } 25 | return 0; 26 | } 27 | 28 | void print_statement(struct PrinterState *ptr_prs, 29 | const struct Statement *ref_sta) 30 | { 31 | if (ref_sta->category != DECLARATION_STATEMENT) { 32 | for (int j = 0; j < ref_sta->labels.length; j++) { 33 | const struct SourceLabel *ptr_label = ref_sta->labels.vector[j]; 34 | 35 | if (ptr_label->category == IDENT_LABEL) { 36 | const struct SourceLabelAndAssemblyLabel *p = 37 | lookup(ptr_prs->source_label_to_assembly_label, 38 | ptr_label->ident_str); 39 | if (!p) { 40 | fprintf(stderr, 41 | "****************************\n" 42 | "* INTERNAL COMPILER ERROR @ %s\n" 43 | "* Lookup failed; cannot find an identifier `%s`\n" 44 | "****************************\n", 45 | __func__, ptr_label->ident_str); 46 | exit(EXIT_FAILURE); 47 | } 48 | gen_label(p->assembly_label); 49 | continue; 50 | } 51 | 52 | if (!ptr_prs->is_inside_switch) { 53 | simple_error( 54 | "`default` or `case` was detected, but is not inside " 55 | "`switch`.\n"); 56 | } 57 | for (int k = 0; k < ptr_prs->case_default_vec.length; k++) { 58 | const struct SourceLabelAndAssemblyLabel *ptr_ll = 59 | ptr_prs->case_default_vec.vector[k]; 60 | if (is_label_compatible(&ptr_ll->source_label, ptr_label)) { 61 | gen_label(ptr_ll->assembly_label); 62 | } 63 | } 64 | } 65 | } 66 | switch (ref_sta->category) { 67 | case DECLARATION_STATEMENT: { 68 | /* do nothing */ 69 | return; 70 | } 71 | case BREAK_STATEMENT: { 72 | if (ptr_prs->break_label_name == -1) { 73 | simple_error("invalid `break`; no loop, no switch\n"); 74 | } else { 75 | gen_jump(ptr_prs->break_label_name, "break"); 76 | } 77 | return; 78 | } 79 | case EXPRESSION_STATEMENT: { 80 | print_expression(ptr_prs, &ref_sta->expr1); 81 | gen_discard(); 82 | return; 83 | } 84 | case RETURN_STATEMENT: { 85 | 86 | print_expression_or_addr_of_struct_or_union(ptr_prs, &ref_sta->expr1, 87 | "returning a struct"); 88 | 89 | /* the first occurrence of return within a function */ 90 | if (ptr_prs->return_label_name == -1) { 91 | int ret_label = get_new_label_name(ptr_prs); 92 | ptr_prs->return_label_name = ret_label; 93 | gen_jump(ret_label, "return"); 94 | } else { 95 | gen_jump(ptr_prs->return_label_name, "return"); 96 | } 97 | 98 | return; 99 | } 100 | case GOTO_STATEMENT: { 101 | const char *destination = ref_sta->destination; 102 | const struct SourceLabelAndAssemblyLabel *p = 103 | lookup(ptr_prs->source_label_to_assembly_label, destination); 104 | if (!p) { 105 | fprintf(stderr, "undefined label `%s` used in `goto`\n", 106 | destination); 107 | exit(EXIT_FAILURE); 108 | } 109 | gen_jump(p->assembly_label, "goto"); 110 | return; 111 | } 112 | case CONTINUE_STATEMENT: { 113 | if (ptr_prs->continue_label_name == -1) { 114 | simple_error("invalid `continue`; no loop\n"); 115 | } else { 116 | gen_jump(ptr_prs->continue_label_name, "continue"); 117 | } 118 | return; 119 | } 120 | case COMPOUND_STATEMENT: { 121 | struct Vector /**/ vec = ref_sta->statement_vector; 122 | 123 | for (int counter = 0; counter != vec.length; ++counter) { 124 | const struct Statement *ptr_ith = vec.vector[counter]; 125 | print_statement(ptr_prs, ptr_ith); 126 | } 127 | return; 128 | } 129 | case IF_ELSE_STATEMENT: { 130 | int label1 = get_new_label_name(ptr_prs); 131 | int label2 = get_new_label_name(ptr_prs); 132 | const struct Expr expr = ref_sta->expr1; 133 | print_expression(ptr_prs, &expr); 134 | 135 | gen_if_zero_jmp_nbyte( 136 | size_of_basic(&expr.details.type, "condition of `if`"), label1, 0); 137 | gen_discard(); 138 | 139 | const struct Statement *ptr_inner_s = 140 | ref_sta->statement_vector.vector[0]; 141 | print_statement(ptr_prs, ptr_inner_s); 142 | 143 | gen_jump(label2, "if statement"); 144 | gen_label(label1); 145 | gen_discard(); 146 | 147 | const struct Statement *ptr_inner_s2 = 148 | ref_sta->statement_vector.vector[1]; 149 | print_statement(ptr_prs, ptr_inner_s2); 150 | gen_label(label2); 151 | 152 | return; 153 | } 154 | case SWITCH_STATEMENT: { 155 | codegen_switch(ptr_prs, ref_sta); 156 | return; 157 | } 158 | case IF_STATEMENT: { 159 | 160 | int label1 = get_new_label_name(ptr_prs); 161 | int label2 = get_new_label_name(ptr_prs); 162 | const struct Expr expr = ref_sta->expr1; 163 | print_expression(ptr_prs, &expr); 164 | 165 | gen_if_zero_jmp_nbyte( 166 | size_of_basic(&expr.details.type, "condition of `if`"), label1, 0); 167 | gen_discard(); 168 | 169 | print_statement(ptr_prs, ref_sta->inner_statement); 170 | 171 | gen_jump(label2, "if statement"); 172 | gen_label(label1); 173 | gen_discard(); 174 | 175 | gen_label(label2); 176 | 177 | return; 178 | } 179 | case DO_WHILE_STATEMENT: { 180 | int stashed_break_label = ptr_prs->break_label_name; 181 | int stashed_continue_label = ptr_prs->continue_label_name; 182 | int label1 = get_new_label_name(ptr_prs); 183 | int break_label = get_new_label_name(ptr_prs); 184 | int cont_label = get_new_label_name(ptr_prs); 185 | ptr_prs->break_label_name = break_label; 186 | ptr_prs->continue_label_name = cont_label; 187 | 188 | gen_label(label1); 189 | print_statement(ptr_prs, ref_sta->inner_statement); 190 | 191 | gen_label(cont_label); 192 | 193 | const struct Expr expr = ref_sta->expr1; 194 | print_expression(ptr_prs, &expr); 195 | 196 | gen_discard(); 197 | gen_if_nonzero_jmp_nbyte( 198 | size_of_basic(&expr.details.type, "condition of do-while"), label1, 199 | -8); 200 | gen_label(break_label); 201 | 202 | ptr_prs->break_label_name = stashed_break_label; 203 | ptr_prs->continue_label_name = stashed_continue_label; 204 | 205 | return; 206 | } 207 | 208 | case WHILE_STATEMENT: { 209 | const struct Expr expr = ref_sta->expr1; 210 | 211 | int stashed_break_label = ptr_prs->break_label_name; 212 | int stashed_continue_label = ptr_prs->continue_label_name; 213 | 214 | int label1 = get_new_label_name(ptr_prs); 215 | int break_label = get_new_label_name(ptr_prs); 216 | int cont_label = get_new_label_name(ptr_prs); 217 | ptr_prs->break_label_name = break_label; 218 | ptr_prs->continue_label_name = cont_label; 219 | 220 | gen_label(label1); 221 | 222 | print_expression(ptr_prs, &expr); 223 | 224 | gen_discard(); 225 | gen_if_zero_jmp_nbyte( 226 | size_of_basic(&expr.details.type, "condition of `while`"), 227 | break_label, -8); 228 | 229 | print_statement(ptr_prs, ref_sta->inner_statement); 230 | 231 | gen_label(cont_label); 232 | gen_jump(label1, "for(part4)"); 233 | gen_label(break_label); 234 | 235 | ptr_prs->break_label_name = stashed_break_label; 236 | ptr_prs->continue_label_name = stashed_continue_label; 237 | 238 | return; 239 | } 240 | case FOR_STATEMENT: { 241 | int stashed_break_label = ptr_prs->break_label_name; 242 | int stashed_continue_label = ptr_prs->continue_label_name; 243 | int label1 = get_new_label_name(ptr_prs); 244 | int break_label = get_new_label_name(ptr_prs); 245 | int cont_label = get_new_label_name(ptr_prs); 246 | ptr_prs->break_label_name = break_label; 247 | ptr_prs->continue_label_name = cont_label; 248 | 249 | print_expression(ptr_prs, &ref_sta->expr1); /* expression1 */ 250 | gen_discard(); 251 | gen_label(label1); 252 | print_expression(ptr_prs, &ref_sta->expr2); /* expression2 */ 253 | 254 | gen_discard(); 255 | gen_if_zero_jmp_nbyte( 256 | size_of_basic(&ref_sta->expr2.details.type, "condition of `for`"), 257 | break_label, -8); 258 | 259 | print_statement(ptr_prs, ref_sta->inner_statement); 260 | gen_label(cont_label); 261 | print_expression(ptr_prs, &ref_sta->expr3); 262 | gen_discard(); 263 | gen_jump(label1, "for(part4)"); 264 | gen_label(break_label); 265 | 266 | ptr_prs->break_label_name = stashed_break_label; 267 | ptr_prs->continue_label_name = stashed_continue_label; 268 | 269 | return; 270 | } 271 | } 272 | fprintf( 273 | stderr, 274 | "****************************\n" 275 | "* INTERNAL COMPILER ERROR @ %s\n" 276 | "* Unexpected value of StatementCategory: `ref_sta->category` is %d\n" 277 | "****************************\n", 278 | __func__, ref_sta->category); 279 | exit(EXIT_FAILURE); 280 | } 281 | 282 | static struct Vector /**/ 283 | collect_named_labels(const struct Statement *ptr_sta) 284 | { 285 | struct Statement sta = *ptr_sta; 286 | struct Vector /**/ ans = init_vector(); 287 | concat_vector(&ans, &sta.labels); 288 | switch (sta.category) { 289 | case RETURN_STATEMENT: 290 | case BREAK_STATEMENT: 291 | case CONTINUE_STATEMENT: 292 | case EXPRESSION_STATEMENT: 293 | case DECLARATION_STATEMENT: 294 | case GOTO_STATEMENT: 295 | /* nothing */ 296 | break; 297 | 298 | case SWITCH_STATEMENT: /* do peek labels */ 299 | case IF_STATEMENT: 300 | case FOR_STATEMENT: 301 | case WHILE_STATEMENT: 302 | case DO_WHILE_STATEMENT: { 303 | const struct Vector /**/ inner_vec = 304 | collect_named_labels(sta.inner_statement); 305 | concat_vector(&ans, &inner_vec); 306 | break; 307 | } 308 | 309 | case COMPOUND_STATEMENT: 310 | case IF_ELSE_STATEMENT: { 311 | struct Vector /**/ statement_vec = sta.statement_vector; 312 | for (int counter = 0; counter != statement_vec.length; ++counter) { 313 | const struct Statement *ptr_ith = statement_vec.vector[counter]; 314 | const struct Vector /**/ inner_vec = 315 | collect_named_labels(ptr_ith); 316 | concat_vector(&ans, &inner_vec); 317 | } 318 | break; 319 | } 320 | } 321 | return ans; 322 | } 323 | 324 | static void print_toplevel_definition(struct PrinterState *ptr_prs, 325 | const struct Toplevel *ref_def) 326 | { 327 | if (ref_def->category == TOPLEVEL_VAR_DEFINITION) { 328 | if (ref_def->declarator_name && !ref_def->is_extern_global_var) { 329 | gen_global_declaration(ref_def->declarator_name, 330 | ref_def->size_of_declarator_type); 331 | } 332 | return; 333 | } 334 | if (ref_def->category == TOPLEVEL_FUNCTION_DECLARATION) { 335 | return; 336 | } 337 | 338 | assert(ref_def->category == TOPLEVEL_FUNCTION_DEFINITION); 339 | 340 | const struct Statement sta = ref_def->func.sta; 341 | struct Vector /**/ offsets_and_types = 342 | ref_def->func.offsets_and_types; 343 | struct Type ret_type = ref_def->func.ret_type; 344 | const char *declarator_name = ref_def->declarator_name; 345 | 346 | ptr_prs->return_label_name = -1; /* -1 means invalid */ 347 | ptr_prs->break_label_name = -1; /* -1 means invalid */ 348 | ptr_prs->continue_label_name = -1; /* -1 means invalid */ 349 | ptr_prs->is_va = ref_def->func.is_va; 350 | if (ref_def->func.is_va) { 351 | ptr_prs->integral_explicit_arg_num = offsets_and_types.length; 352 | } 353 | // int label1; 354 | // int label2; 355 | // label1 = get_new_label_name(ptr_prs); 356 | // label2 = get_new_label_name(ptr_prs); 357 | 358 | int capacity = ref_def->func.capacity; 359 | if (ref_def->func.is_va) { 360 | capacity += 8 /* stack_check */ + 8 * 6 + 16 * 8 /* reg_save_area */ 361 | + 8; /* just to be safe */ 362 | } 363 | if (ref_def->func.is_static_function) { 364 | gen_prologue_static(capacity, declarator_name); 365 | } else { 366 | gen_prologue(capacity, declarator_name); 367 | } 368 | for (int counter = 0; counter < offsets_and_types.length; ++counter) { 369 | if (counter >= 6) { 370 | unsupported("7 or more args detected in function definition"); 371 | } 372 | const struct LocalVarInfo *ptr_info = offsets_and_types.vector[counter]; 373 | 374 | int offset = ptr_info->offset; 375 | const struct Type type = ptr_info->type; 376 | switch (size_of_basic(&type, "argument to be passed to function")) { 377 | case 1: 378 | gen_write_register_to_local_1byte( 379 | /* yes, the register is 4byte */ 380 | get_reg_name_from_arg_pos_4byte(counter), offset); 381 | break; 382 | case 4: 383 | gen_write_register_to_local_4byte( 384 | get_reg_name_from_arg_pos_4byte(counter), offset); 385 | break; 386 | case 8: 387 | gen_write_register_to_local_8byte( 388 | get_reg_name_from_arg_pos_8byte(counter), offset); 389 | break; 390 | default: 391 | unsupported("Unsupported width in function parameter"); 392 | } 393 | } 394 | 395 | if (ref_def->func.is_va) { 396 | int another_label = get_new_label_name(ptr_prs); 397 | ptr_prs->reg_save_area = -capacity + 8; 398 | ptr_prs->stack_chk_offset = -capacity; 399 | gen_store_regs_to_local(ptr_prs->reg_save_area, 1, another_label); 400 | gen_write_stack_chk_guard_to_local(ptr_prs->stack_chk_offset); 401 | } 402 | 403 | struct Vector /**/ source_labels = collect_named_labels(&sta); 404 | 405 | struct Map2 /**/ 406 | *source_label_to_assembly_label = init_map(); 407 | for (int i = 0; i < source_labels.length; i++) { 408 | const struct SourceLabel *ptr = source_labels.vector[i]; 409 | switch (ptr->category) { 410 | case DEFAULT_LABEL: 411 | case CASE_LABEL: 412 | continue; 413 | case IDENT_LABEL: { 414 | struct SourceLabelAndAssemblyLabel *p = 415 | calloc(1, sizeof(struct SourceLabelAndAssemblyLabel)); 416 | p->assembly_label = get_new_label_name(ptr_prs); 417 | p->source_label = *ptr; 418 | insert(source_label_to_assembly_label, ptr->ident_str, p); 419 | } 420 | } 421 | } 422 | 423 | ptr_prs->source_label_to_assembly_label = source_label_to_assembly_label; 424 | 425 | print_statement(ptr_prs, &sta); 426 | 427 | if (ret_type.type_category == VOID_) { 428 | if (ptr_prs->return_label_name != -1) { 429 | gen_label(ptr_prs->return_label_name); 430 | } 431 | gen_return_garbage(); 432 | return; 433 | } 434 | 435 | if (ptr_prs->return_label_name == -1) { 436 | simple_error("the return type is not void, but `return` is not found"); 437 | } 438 | if (is_struct_or_union(&ret_type)) { 439 | enum SystemVAbiClass abi_class = ref_def->func.abi_class; 440 | int ret_struct_or_union_size = ref_def->func.ret_struct_or_union_size; 441 | 442 | if (ref_def->func.is_va) { 443 | unsupported( 444 | "variable argument function that returns a struct/union"); 445 | } 446 | 447 | if (abi_class == INTEGER_CLASS) { 448 | gen_epilogue_returning_integerclass_struct_or_union( 449 | ret_struct_or_union_size, ptr_prs->return_label_name); 450 | } else { 451 | gen_label(ptr_prs->return_label_name); 452 | gen_push_from_local_nbyte(8, ref_def->func.hidden_var_offset); 453 | gen_copy_2nd_struct_or_union_to_1st_and_discard( 454 | ret_struct_or_union_size); 455 | gen_return_garbage(); 456 | } 457 | } else { 458 | if (ref_def->func.is_va) { 459 | int label = get_new_label_name(ptr_prs); 460 | gen_epilogue_nbyte_with_stack_check( 461 | size_of_basic(&ret_type, "return value"), 462 | ptr_prs->return_label_name, ptr_prs->stack_chk_offset, label); 463 | } else { 464 | gen_epilogue_nbyte(size_of_basic(&ret_type, "return value"), 465 | ptr_prs->return_label_name); 466 | } 467 | } 468 | } 469 | 470 | void generate(const struct Vector /**/ *ref_vec) 471 | { 472 | struct PrinterState prs; 473 | prs.final_label_name = 1; 474 | prs.return_label_name = -1; 475 | prs.string_constant_pool = init_vector(); 476 | prs.pool_largest_id = 0; 477 | prs.is_inside_switch = 0; 478 | 479 | for (int i = 0; i < ref_vec->length; i++) { 480 | const struct Toplevel *ptr = ref_vec->vector[i]; 481 | print_toplevel_definition(&prs, ptr); 482 | } 483 | 484 | for (int i = 0; i < prs.string_constant_pool.length; ++i) { 485 | const char *str = prs.string_constant_pool.vector[i]; 486 | gen_string_literal(i, escape(str)); 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /codegen_switch.c: -------------------------------------------------------------------------------- 1 | #include "print_x86_64.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | #include "toplevel.h" 5 | 6 | static struct Vector /**/ 7 | collect_labels_visible_from_switch(const struct Statement *ptr_sta) 8 | { 9 | struct Statement sta = *ptr_sta; 10 | struct Vector /**/ ans = init_vector(); 11 | concat_vector(&ans, &sta.labels); 12 | switch (sta.category) { 13 | case RETURN_STATEMENT: 14 | case BREAK_STATEMENT: 15 | case CONTINUE_STATEMENT: 16 | case GOTO_STATEMENT: 17 | case EXPRESSION_STATEMENT: 18 | case DECLARATION_STATEMENT: 19 | /* nothing */ 20 | break; 21 | case SWITCH_STATEMENT: 22 | /* do nothing; don't peek labels */ 23 | break; 24 | 25 | case IF_STATEMENT: 26 | case FOR_STATEMENT: 27 | case WHILE_STATEMENT: 28 | case DO_WHILE_STATEMENT: { 29 | const struct Vector /**/ inner_vec = 30 | collect_labels_visible_from_switch(sta.inner_statement); 31 | concat_vector(&ans, &inner_vec); 32 | break; 33 | } 34 | 35 | case COMPOUND_STATEMENT: 36 | case IF_ELSE_STATEMENT: { 37 | struct Vector /**/ statement_vec = sta.statement_vector; 38 | for (int counter = 0; counter != statement_vec.length; ++counter) { 39 | const struct Statement *ptr_ith = statement_vec.vector[counter]; 40 | const struct Vector /**/ inner_vec = 41 | collect_labels_visible_from_switch(ptr_ith); 42 | concat_vector(&ans, &inner_vec); 43 | } 44 | break; 45 | } 46 | } 47 | return ans; 48 | } 49 | 50 | void codegen_switch(struct PrinterState *ptr_prs, 51 | const struct Statement *ptr_sta) 52 | { 53 | const struct Statement sta = *ptr_sta; 54 | int stashed_break_label = ptr_prs->break_label_name; 55 | int stashed_is_inside_switch = ptr_prs->is_inside_switch; 56 | struct Vector /**/ stashed_case_default_vec = 57 | ptr_prs->case_default_vec; 58 | 59 | int break_label = get_new_label_name(ptr_prs); 60 | ptr_prs->break_label_name = break_label; 61 | ptr_prs->is_inside_switch = 1; 62 | struct Vector /**/ vec = 63 | collect_labels_visible_from_switch(sta.inner_statement); 64 | 65 | int default_label = -1; 66 | ptr_prs->case_default_vec = init_vector(); 67 | for (int i = 0; i < vec.length; i++) { 68 | const struct SourceLabel *ptr_vec_i = vec.vector[i]; 69 | if (ptr_vec_i->category == IDENT_LABEL) { 70 | continue; 71 | } 72 | 73 | int label = get_new_label_name(ptr_prs); 74 | if (ptr_vec_i->category == DEFAULT_LABEL) { 75 | if (default_label == -1) { 76 | default_label = label; 77 | } else { 78 | simple_error("duplicate `default` detected.\n"); 79 | } 80 | } 81 | struct SourceLabelAndAssemblyLabel ll; 82 | ll.assembly_label = label; 83 | ll.source_label = *ptr_vec_i; 84 | 85 | struct SourceLabelAndAssemblyLabel *ptr_ll = 86 | calloc(1, sizeof(struct SourceLabelAndAssemblyLabel)); 87 | *ptr_ll = ll; 88 | push_vector(&ptr_prs->case_default_vec, ptr_ll); 89 | } 90 | 91 | const struct Expr expr = sta.expr1; 92 | print_expression(ptr_prs, &expr); 93 | if (size_of_basic(&expr.details.type, "expression of switch") == 1) { 94 | gen_extend_to_4byte(); 95 | } 96 | 97 | if (default_label == -1) { /* default_label is not found */ 98 | default_label = break_label; 99 | } 100 | gen_discard(); 101 | 102 | for (int i = 0; i < ptr_prs->case_default_vec.length; 103 | i++) { /* for each case */ 104 | const struct SourceLabelAndAssemblyLabel *ptr_ll = 105 | ptr_prs->case_default_vec.vector[i]; 106 | if (ptr_ll->source_label.category != CASE_LABEL) { 107 | continue; 108 | } 109 | int constant1 = ptr_ll->source_label.case_int; 110 | int label1 = ptr_ll->assembly_label; 111 | gen_if_2nd_matches_int_jmp_4byte(constant1, label1); 112 | } 113 | gen_jump(default_label, "switch-default"); 114 | 115 | print_statement(ptr_prs, sta.inner_statement); 116 | gen_label(break_label); 117 | 118 | ptr_prs->break_label_name = stashed_break_label; 119 | ptr_prs->is_inside_switch = stashed_is_inside_switch; 120 | ptr_prs->case_default_vec = stashed_case_default_vec; 121 | return; 122 | } 123 | -------------------------------------------------------------------------------- /compile2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ASAN_OPTIONS=detect_leaks=0 ./out/compiler.out $1.c -DOVERRIDE_STD --ir=ir/_$1$3.txt $2 > self_compile_asm/$1$3.s 3 | -------------------------------------------------------------------------------- /cpp.c: -------------------------------------------------------------------------------- 1 | #include "file_io.h" 2 | #include "header.h" 3 | #include "std.h" 4 | #include "std_io.h" 5 | 6 | enum LineState { LINE_HAS_JUST_STARTED, AFTER_HASH, NOTHING_SPECIAL }; 7 | 8 | static void set_line_state(enum LineState *ps, enum TokenKind kind) 9 | { 10 | if (kind == NEWLINE || kind == BEGINNING) { 11 | *ps = LINE_HAS_JUST_STARTED; 12 | } else if (kind == SPACE) { 13 | /* keep the state as is */ 14 | } else { 15 | *ps = NOTHING_SPECIAL; 16 | } 17 | } 18 | 19 | static void 20 | replace_recursively(const struct Map2 /**/ *def_map, 21 | struct Map2 *used_map, const struct Token *ref_src, 22 | struct Token *ptr_dst); 23 | 24 | static void consume_spaces(const struct Token **ptr_src) 25 | { 26 | while ((*ptr_src)[0].kind == SPACE) { 27 | (*ptr_src)++; 28 | } 29 | } 30 | 31 | static void consume_the_rest_of_line(const struct Token **ptr_src) 32 | { 33 | while ((*ptr_src)[0].kind != NEWLINE) { 34 | (*ptr_src)++; 35 | } 36 | } 37 | 38 | static void skip_till_corresponding_endif(const struct Token **ptr_src) 39 | { 40 | const struct Token *src = *ptr_src; 41 | 42 | int ifdef_depth = 1; 43 | while (1) { 44 | for (enum LineState s = LINE_HAS_JUST_STARTED; 45 | s != LINE_HAS_JUST_STARTED || src[0].kind != HASH; src++) { 46 | set_line_state(&s, src[0].kind); 47 | 48 | if (src[0].kind == END) { 49 | fprintf(stderr, "insufficient number of `#endif`.\n"); 50 | exit(EXIT_FAILURE); 51 | } 52 | } 53 | 54 | src++; /* HASH */ 55 | 56 | consume_spaces(&src); 57 | 58 | if (src[0].kind == NEWLINE) { /* empty directive */ 59 | src++; 60 | continue; 61 | } 62 | 63 | expect_and_consume(&src, IDENT_OR_RESERVED, 64 | "identifier after `#` for preprocessor directive"); 65 | 66 | if (strcmp(src[-1].ident_str, "ifdef") == 0 || 67 | strcmp(src[-1].ident_str, "ifndef") == 0) { 68 | ifdef_depth++; 69 | consume_the_rest_of_line(&src); 70 | } else if (strcmp(src[-1].ident_str, "endif") == 0) { 71 | 72 | consume_spaces(&src); 73 | 74 | if (src[0].kind == END) { 75 | if (ifdef_depth != 1) { 76 | fprintf(stderr, "insufficient number of `#endif`.\n"); 77 | exit(EXIT_FAILURE); 78 | } 79 | *ptr_src = src; 80 | return; 81 | } 82 | 83 | if (src[0].kind != NEWLINE) { 84 | error_unexpected_token(src, "newline after `#endif`"); 85 | } 86 | 87 | if (ifdef_depth == 1) { 88 | *ptr_src = src; 89 | return; 90 | } 91 | ifdef_depth--; 92 | } else { 93 | consume_the_rest_of_line(&src); 94 | } 95 | src++; 96 | } 97 | } 98 | 99 | /* 100 | * ptr_src: 101 | * at the start, # followed by spaces are already consumed. 102 | * when returning, NEWLINE is consumed if it exists (return 1 => continue) 103 | * if nonexistent, it will return 0 and fallthru. 104 | */ 105 | static int handle_define(const struct Token **ptr_src, 106 | struct Map2 /**/ *def_map) 107 | { 108 | expect_and_consume(ptr_src, IDENT_OR_RESERVED, 109 | "macro name after `#define`"); 110 | const char *macro_name = (*ptr_src)[-1].ident_str; 111 | 112 | /* only when the identifier is IMMEDIATELY followed by 113 | * LEFT_PAREN */ 114 | if ((*ptr_src)[0].kind == LEFT_PAREN) { 115 | unsupported("function-style macro"); 116 | } 117 | 118 | /* that's why this must be here, not earlier */ 119 | consume_spaces(ptr_src); 120 | 121 | struct Token *ptr_token = calloc(1, sizeof(struct Token)); 122 | 123 | /* empty replacement */ 124 | if ((*ptr_src)[0].kind == NEWLINE) { 125 | (*ptr_src)++; 126 | ptr_token->kind = SPACE; 127 | struct Vector *p = init_vector_(); 128 | push_vector(p, ptr_token); 129 | insert(def_map, macro_name, p); /**/ 130 | return 1; 131 | } 132 | 133 | if ((*ptr_src)[1].kind != NEWLINE) { 134 | unsupported("`#define` directive that expands to multiple tokens"); 135 | } 136 | 137 | /* one-token replacement */ 138 | *ptr_token = **ptr_src; 139 | struct Vector *p = init_vector_(); 140 | push_vector(p, ptr_token); 141 | insert(def_map, macro_name, p); 142 | (*ptr_src)++; 143 | 144 | if ((*ptr_src)[0].kind == NEWLINE) { 145 | (*ptr_src)++; 146 | return 1; 147 | } 148 | return 0; 149 | } 150 | 151 | /* 152 | * ptr_src: 153 | * at the start, # followed by spaces are already consumed. 154 | * when returning, NEWLINE is consumed if it exists (return 1 => continue) 155 | * if nonexistent, it will throw an error. 156 | */ 157 | static void 158 | handle_include(struct Token **ptr_dst, const struct Token **ptr_src, 159 | int *ref_dst_offset, 160 | struct Map2 /**/ *def_map, 161 | int *ptr_total_token_num) 162 | { 163 | const struct Token *src = *ptr_src; 164 | int dst_offset = *ref_dst_offset; 165 | struct Token *dst_initial = *ptr_dst; 166 | 167 | if (src[0].kind == OP_LT) { 168 | unsupported("`#include <...>`"); 169 | } 170 | 171 | expect_and_consume(&src, LIT_STRING, "path after `#include`"); 172 | 173 | struct __FILE *fp = fopen(src[-1].literal_str, "r"); 174 | 175 | if (!fp) { 176 | fprintf(stderr, "failed to open file `%s` to be `#include`d.\n", 177 | src[-1].literal_str); 178 | exit(EXIT_FAILURE); 179 | } 180 | 181 | const char *imported = read_from_file(fp); 182 | const struct Tokvec new_vec = preprocess(imported, def_map); 183 | /* def_map will be modified, and that's how all the macros will 184 | * be obtained here */ 185 | 186 | *ptr_total_token_num += new_vec.tok_num - 2; /* BEGINNING and END gone */ 187 | 188 | dst_initial = realloc(dst_initial, 189 | *ptr_total_token_num * 190 | sizeof(struct Token)); /* realloc never fails */ 191 | 192 | int l = 1; /* skip BEGINNING */ 193 | while (1) { 194 | if (new_vec.v[l].kind == END) { 195 | break; 196 | } 197 | dst_initial[dst_offset] = new_vec.v[l]; 198 | dst_offset++; 199 | l++; 200 | } 201 | 202 | consume_spaces(&src); 203 | 204 | if (src[0].kind == NEWLINE) { 205 | src++; 206 | } else { 207 | error_unexpected_token( 208 | src, "newline or end of file after `#include (filepath)`"); 209 | } 210 | 211 | *ref_dst_offset = dst_offset; 212 | *ptr_src = src; 213 | *ptr_dst = dst_initial; 214 | } 215 | 216 | static int handle_ifdef(int is_ifdef, const struct Token **ptr_src, 217 | struct Map2 /**/ *def_map, 218 | int *ptr_ifdef_depth) 219 | { 220 | expect_and_consume(ptr_src, IDENT_OR_RESERVED, 221 | is_ifdef ? "identifier after `#ifdef`" 222 | : "identifier after `#ifndef`"); 223 | 224 | const char *macro_name = (*ptr_src)[-1].ident_str; 225 | consume_spaces(ptr_src); 226 | 227 | expect_and_consume(ptr_src, NEWLINE, 228 | is_ifdef ? "newline after `#ifdef (macro_name)`" 229 | : "newline after `#ifndef (macro_name)`"); 230 | (*ptr_src)--; /* ad hoc */ 231 | 232 | if (is_ifdef == isElem(def_map, macro_name)) { /* true branch */ 233 | (*ptr_ifdef_depth)++; 234 | } else { /* false branch */ 235 | skip_till_corresponding_endif(ptr_src); 236 | 237 | return 1; 238 | } 239 | return 0; 240 | } 241 | 242 | /* lexer inserts a NEWLINE before END; hence, END can mostly be ignored */ 243 | struct Tokvec preprocess(const char *str, 244 | struct Map2 /**/ *def_map) 245 | { 246 | const struct Tokvec t = read_all_tokens(str); 247 | const struct Token *src = t.v; 248 | 249 | int total_token_num = t.tok_num; 250 | int ifdef_depth = 0; 251 | 252 | struct Token *dst_initial = calloc(total_token_num, sizeof(struct Token)); 253 | 254 | int dst_offset = 0; 255 | 256 | int flag = 1; 257 | while (1) { 258 | for (enum LineState s = LINE_HAS_JUST_STARTED; 259 | flag == 0 || s != LINE_HAS_JUST_STARTED || src[0].kind != HASH; 260 | dst_offset++, src++) { 261 | flag = 1; 262 | 263 | set_line_state(&s, src[0].kind); 264 | 265 | struct Map2 *used_map = init_map(); 266 | replace_recursively(def_map, used_map, src, 267 | &dst_initial[dst_offset]); 268 | 269 | if (dst_initial[dst_offset].kind == END) { 270 | if (ifdef_depth) { 271 | fprintf(stderr, "insufficient number of `#endif`s.\n"); 272 | exit(EXIT_FAILURE); 273 | } 274 | 275 | struct Tokvec u; 276 | u.tok_num = dst_offset + 1; 277 | u.v = dst_initial; 278 | 279 | return u; 280 | } 281 | } 282 | 283 | src++; /* HASH */ 284 | 285 | consume_spaces(&src); 286 | 287 | if (src[0].kind == NEWLINE) { /* empty directive */ 288 | src++; 289 | continue; 290 | } 291 | expect_and_consume(&src, IDENT_OR_RESERVED, 292 | "identifier after `#` for preprocessor directive"); 293 | 294 | const char *directive = src[-1].ident_str; 295 | consume_spaces(&src); 296 | 297 | if (strcmp(directive, "define") == 0) { 298 | flag = handle_define(&src, def_map); 299 | } else if (strcmp(directive, "include") == 0) { 300 | /* dst_initial may be realloc'd; total_token_num could be modified 301 | */ 302 | handle_include(&dst_initial, &src, &dst_offset, def_map, 303 | &total_token_num); 304 | flag = 1; 305 | } else if (strcmp(directive, "ifdef") == 0 || 306 | strcmp(directive, "ifndef") == 0) { 307 | flag = handle_ifdef(strcmp(directive, "ifdef") == 0, &src, def_map, 308 | &ifdef_depth); 309 | } else if (strcmp(directive, "endif") == 310 | 0) { /* passes only when the #if(n)?def condition was 311 | true. If false, it will be handled in 312 | #if(n)?def.*/ 313 | if (ifdef_depth < 1) { 314 | fprintf(stderr, 315 | "mismatch of `#endif` directive was detected.\n"); 316 | exit(EXIT_FAILURE); 317 | } 318 | 319 | ifdef_depth--; 320 | expect_and_consume(&src, NEWLINE, "newline after `#endif`"); 321 | flag = 1; 322 | } else { 323 | unsupported("unknown directive"); 324 | } 325 | } 326 | } 327 | 328 | static void 329 | replace_recursively(const struct Map2 /**/ *def_map, 330 | struct Map2 *used_map, const struct Token *src, 331 | struct Token *ptr_dst) 332 | { 333 | if (src[0].kind == IDENT_OR_RESERVED && isElem(def_map, src[0].ident_str) && 334 | !isElem(used_map, src[0].ident_str)) { 335 | struct Vector /**/ *p = lookup(def_map, src[0].ident_str); 336 | 337 | #ifdef __STDC__ 338 | #warning only one token 339 | #endif 340 | 341 | const struct Token *replace_with = p->vector[0]; 342 | 343 | int u; 344 | insert(used_map, src[0].ident_str, 345 | &u /* this can be any arbitrary non-null pointer*/); 346 | 347 | replace_recursively(def_map, used_map, replace_with, ptr_dst); 348 | 349 | } else { 350 | *ptr_dst = src[0]; 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /error.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | 5 | _Noreturn void error_unexpected_token(const struct Token *tokvec, 6 | const char *str) 7 | { 8 | fprintf(stderr, "Unexpected token: `"); 9 | print_token_at(tokvec); 10 | fprintf(stderr, "` while expecting %s. \n", str); 11 | fprintf(stderr, "Next token: `"); 12 | print_token_at(tokvec + 1); 13 | fprintf(stderr, "`\n"); 14 | fprintf(stderr, "Previous token: `"); 15 | print_token_at(tokvec - 1); 16 | /* it does not fail if tokvec[0] was the 17 | first token, since there always is at least one token (BEGINNING) */ 18 | fprintf(stderr, "`\n"); 19 | exit(EXIT_FAILURE); 20 | } 21 | 22 | _Noreturn void simple_error(const char *str) 23 | { 24 | fprintf(stderr, "%s", str); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | void expect_and_consume(const struct Token **ptr_tokvec, enum TokenKind kind, 29 | const char *str) 30 | { 31 | const struct Token *tokvec = *ptr_tokvec; 32 | 33 | if (tokvec[0].kind != kind) { 34 | error_unexpected_token(tokvec, str); 35 | } 36 | ++tokvec; 37 | *ptr_tokvec = tokvec; 38 | } 39 | 40 | _Noreturn void unsupported(const char *str) 41 | { 42 | fprintf(stderr, "unsupported: %s\n", str); 43 | exit(EXIT_FAILURE); 44 | } 45 | -------------------------------------------------------------------------------- /file_io.c: -------------------------------------------------------------------------------- 1 | #include "file_io.h" 2 | #include "std.h" 3 | 4 | char *read_from_file(struct __FILE *fp) 5 | { 6 | int size = 1; 7 | int capacity = 50000; 8 | char *str = calloc(capacity, sizeof(char)); 9 | char buffer[1024]; 10 | 11 | while (fgets(buffer, 1024, fp)) { 12 | size += strlen(buffer); 13 | if (size > capacity) { 14 | capacity *= 2; 15 | str = realloc(str, capacity); 16 | } 17 | strcat(str, buffer); 18 | } 19 | 20 | return str; 21 | } 22 | -------------------------------------------------------------------------------- /file_io.h: -------------------------------------------------------------------------------- 1 | #include "std_io.h" 2 | 3 | char *read_from_file(struct __FILE *fp); 4 | -------------------------------------------------------------------------------- /global_flags.h: -------------------------------------------------------------------------------- 1 | extern int global_flag_pedantic; 2 | -------------------------------------------------------------------------------- /header.h: -------------------------------------------------------------------------------- 1 | #include "map.h" 2 | #include "vector.h" 3 | 4 | enum TokenKind { 5 | OP_PLUS, 6 | OP_MINUS, 7 | END, 8 | BEGINNING, 9 | LIT_DEC_INTEGER, 10 | OP_ASTERISK, 11 | LEFT_PAREN, 12 | RIGHT_PAREN, 13 | OP_SLASH, 14 | OP_PERCENT, 15 | OP_COMMA, 16 | OP_LSHIFT, 17 | OP_LT_EQ, 18 | OP_LT, 19 | OP_RSHIFT, 20 | OP_GT_EQ, 21 | OP_GT, 22 | OP_AND, 23 | OP_OR, 24 | OP_EQ_EQ, 25 | OP_NOT_EQ, 26 | OP_NOT, 27 | OP_TILDA, 28 | OP_EQ, 29 | IDENT_OR_RESERVED, 30 | RES_RETURN, 31 | SEMICOLON, 32 | OP_HAT, 33 | QUESTION, 34 | COLON, 35 | LEFT_BRACE, 36 | RIGHT_BRACE, 37 | OP_AND_AND, 38 | OP_OR_OR, 39 | OP_PLUS_EQ, 40 | OP_MINUS_EQ, 41 | OP_ASTERISK_EQ, 42 | OP_SLASH_EQ, 43 | OP_PERCENT_EQ, 44 | OP_LSHIFT_EQ, 45 | OP_RSHIFT_EQ, 46 | OP_AND_EQ, 47 | OP_HAT_EQ, 48 | OP_OR_EQ, 49 | RES_IF, 50 | RES_ELSE, 51 | RES_DO, 52 | RES_WHILE, 53 | RES_BREAK, 54 | RES_CONTINUE, 55 | OP_PLUS_PLUS, 56 | OP_MINUS_MINUS, 57 | RES_FOR, 58 | RES_INT, 59 | LEFT_BRACKET, 60 | RIGHT_BRACKET, 61 | RES_CHAR, 62 | LIT_STRING, 63 | RES_STRUCT, 64 | RES_SIZEOF, 65 | DOT, 66 | ARROW, 67 | RES_VOID, 68 | RES_SWITCH, 69 | RES_CASE, 70 | RES_DEFAULT, 71 | RES_ALIGNOF, 72 | RES_ENUM, 73 | RES_CONST, 74 | RES_NORETURN, 75 | RES_EXTERN, 76 | RES_STATIC, 77 | TRIPLE_DOT, 78 | RES_GOTO, 79 | RES_UNION, 80 | 81 | /* preprocessor */ 82 | HASH, 83 | NEWLINE, 84 | SPACE 85 | }; 86 | 87 | struct Token { 88 | enum TokenKind kind; 89 | int int_value; 90 | const char *ident_str; 91 | const char *literal_str; 92 | const char *token_begins_here; 93 | }; 94 | 95 | enum TypeCategory { 96 | INT_, 97 | PTR_, 98 | ARRAY, 99 | FN, 100 | CHAR_, 101 | STRUCT_NOT_UNION, 102 | UNION, 103 | VOID_, 104 | ENUM_ 105 | }; 106 | 107 | struct TypeAndIdent; 108 | 109 | struct StructInternalInfo { 110 | struct Vector /* */ *ptr_types_and_idents; /* nullable */ 111 | }; 112 | 113 | struct SizeAndAlignment { 114 | int size; 115 | int alignment; 116 | }; 117 | 118 | struct StructOrUnionInternalCompleteInfo { 119 | struct StructInternalInfo info; 120 | int *offset_vec; 121 | struct SizeAndAlignment s_and_a; 122 | }; 123 | 124 | struct Enumerators { 125 | struct Vector /**/ *ptr_enumerators; /* nullable */ 126 | }; 127 | 128 | struct StructTagAndInfo { 129 | const char *struct_or_union_tag; 130 | struct StructInternalInfo struct_or_union_info; 131 | }; 132 | 133 | struct EnumTagAndInfo { 134 | const char *enum_tag; 135 | struct Enumerators enum_info; 136 | }; 137 | 138 | enum ParamInfosValidity { 139 | INVALID, 140 | VALID, 141 | VA_ARGS, 142 | }; 143 | 144 | struct Type { 145 | enum TypeCategory type_category; 146 | struct Type *derived_from; 147 | int array_length; /* only when type_category is ARRAY */ 148 | struct Vector /**/ param_infos; 149 | enum ParamInfosValidity param_infos_validity; 150 | 151 | struct StructTagAndInfo s; 152 | struct EnumTagAndInfo e; 153 | }; 154 | 155 | struct TypeAndIdent { 156 | struct Type type; 157 | const char *ident_str; 158 | }; 159 | 160 | int is_struct_or_union(const struct Type *t); 161 | 162 | int size_of_basic(const struct Type *ref_type, const char *msg); 163 | 164 | struct Type INT_TYPE(void); 165 | 166 | struct Type deref_type(const struct Type *ref_t); 167 | 168 | void expect_and_consume(const struct Token **ptr_tokvec, enum TokenKind kind, 169 | const char *str); 170 | _Noreturn void error_unexpected_token(const struct Token *tokvec, 171 | const char *str); 172 | 173 | void debug_print_type(const struct Type *ref_type); 174 | 175 | int can_start_a_type(const struct Token *tokvec); 176 | 177 | struct Type parse_type_name(const struct Token **ptr_tokvec); 178 | 179 | _Noreturn void unsupported(const char *str); 180 | 181 | enum ExprCategory { 182 | SIMPLE_BINARY_EXPR, 183 | COMMA_EXPR, 184 | POINTER_PLUS_INT, 185 | POINTER_MINUS_INT, 186 | POINTER_MINUS_POINTER, 187 | CONDITIONAL_EXPR, 188 | UNARY_OP_EXPR, 189 | LOCAL_VAR_, 190 | GLOBAL_VAR_, 191 | INT_VALUE, 192 | POSTFIX_INCREMENT, 193 | POSTFIX_DECREMENT, 194 | FUNCCALL_EXPR, 195 | COMPOUND_ASSIGNMENT_EXPR, 196 | ASSIGNMENT_EXPR, 197 | LOGICAL_OR_EXPR, 198 | LOGICAL_AND_EXPR, 199 | STRING_LITERAL, 200 | NULLPTR, 201 | VOID_EXPR, 202 | STRUCT_OR_UNION_ASSIGNMENT_EXPR, 203 | FUNCCALL_EXPR_RETURNING_INTEGER_CLASS, 204 | FUNCCALL_EXPR_RETURNING_MEMORY_CLASS, 205 | FPCALL_EXPR, 206 | FPCALL_EXPR_RETURNING_INTEGER_CLASS, 207 | FPCALL_EXPR_RETURNING_MEMORY_CLASS, 208 | PTR_STRUCT_AND_OFFSET, 209 | BUILTIN_FUNCCALL_EXPR, 210 | }; 211 | 212 | enum UntypedExprCategory { 213 | BINARY_EXPR, 214 | UNARY_EXPR, 215 | CONDITIONAL, 216 | VAR, 217 | INT_LITERAL_, 218 | POSTFIX_EXPR, 219 | FUNCCALL, 220 | FUNC_PTR_CALL, 221 | STRING_LITERAL_, 222 | SIZEOF_TYPE, 223 | ALIGNOF_TYPE, 224 | AMPERSAND_DOT, 225 | BUILTIN_FUNCCALL, 226 | }; 227 | 228 | enum SimpleBinOp { 229 | SIMPLE_BIN_OP_PLUS, 230 | SIMPLE_BIN_OP_MINUS, 231 | SIMPLE_BIN_OP_ASTERISK, 232 | SIMPLE_BIN_OP_SLASH, 233 | SIMPLE_BIN_OP_PERCENT, 234 | SIMPLE_BIN_OP_LT, 235 | SIMPLE_BIN_OP_LT_EQ, 236 | SIMPLE_BIN_OP_LSHIFT, 237 | SIMPLE_BIN_OP_GT, 238 | SIMPLE_BIN_OP_GT_EQ, 239 | SIMPLE_BIN_OP_RSHIFT, 240 | SIMPLE_BIN_OP_AND, 241 | SIMPLE_BIN_OP_OR, 242 | SIMPLE_BIN_OP_EQ_EQ, 243 | SIMPLE_BIN_OP_NOT_EQ, 244 | SIMPLE_BIN_OP_HAT 245 | }; 246 | 247 | enum UnaryOp { 248 | UNARY_OP_NOT, 249 | UNARY_OP_TILDA, 250 | UNARY_OP_PLUS, 251 | UNARY_OP_MINUS, 252 | 253 | UNARY_OP_PLUS_PLUS, 254 | UNARY_OP_MINUS_MINUS, 255 | 256 | UNARY_OP_AND, 257 | 258 | UNARY_OP_ASTERISK 259 | }; 260 | 261 | struct UntypedExpr { 262 | enum TokenKind operator_; 263 | enum UntypedExprCategory category; 264 | struct UntypedExpr *ptr1; 265 | struct UntypedExpr *ptr2; 266 | struct UntypedExpr *ptr3; 267 | int int_value; 268 | const char *var_name; 269 | const char *literal_string; 270 | struct Vector /* */ arg_exprs_vec; 271 | struct Type operand_of_sizeof_or_alignof; 272 | const char *ident_after_dot; 273 | }; 274 | 275 | struct Type parse_declaration(const struct Token **ptr_tokvec, 276 | const char **ptr_to_ident_str, 277 | struct UntypedExpr **ptr_ptr_uexpr); 278 | 279 | struct TypePair { 280 | struct Type type; 281 | struct Type true_type; 282 | }; 283 | 284 | struct Expr { 285 | struct TypePair details; 286 | enum ExprCategory category; 287 | enum SimpleBinOp simple_binary_operator; 288 | enum UnaryOp unary_operator; 289 | struct Expr *ptr1; 290 | struct Expr *ptr2; 291 | struct Expr *ptr3; 292 | int int_value; 293 | const char *global_var_name; 294 | const char *literal_string; 295 | struct Vector /**/ args; 296 | int local_var_offset; 297 | 298 | /* used in POINTER_PLUS_INT, POINTER_MINUS_INT and POINTER_MINUS_POINTER */ 299 | int size_info_for_pointer_arith; 300 | 301 | /* used in STRUCT_OR_UNION_ASSIGNMENT_EXPR */ 302 | int size_info_for_struct_or_union_assign; 303 | 304 | int struct_offset; 305 | }; 306 | 307 | struct Type CHAR_TYPE(void); 308 | 309 | enum StatementCategory { 310 | COMPOUND_STATEMENT, 311 | IF_STATEMENT, 312 | IF_ELSE_STATEMENT, 313 | FOR_STATEMENT, 314 | WHILE_STATEMENT, 315 | DO_WHILE_STATEMENT, 316 | RETURN_STATEMENT, 317 | BREAK_STATEMENT, 318 | CONTINUE_STATEMENT, 319 | EXPRESSION_STATEMENT, 320 | DECLARATION_STATEMENT, 321 | SWITCH_STATEMENT, 322 | GOTO_STATEMENT 323 | }; 324 | 325 | enum SourceLabelCategory { DEFAULT_LABEL, CASE_LABEL, IDENT_LABEL }; 326 | 327 | struct SourceLabel { 328 | enum SourceLabelCategory category; 329 | int case_int; 330 | const char *ident_str; 331 | }; 332 | 333 | struct Statement { 334 | enum StatementCategory category; 335 | struct Vector /**/ statement_vector; 336 | struct Expr expr1; 337 | struct Expr expr2; 338 | struct Expr expr3; 339 | struct Statement *inner_statement; 340 | struct TypeAndIdent declaration; 341 | struct Vector /**/ labels; 342 | const char *destination; /* used solely for goto */ 343 | }; 344 | 345 | struct UntypedExpr parse_expression(const struct Token **ptr_tokvec); 346 | int isAssign(enum TokenKind opkind); 347 | struct Type *parse_type_specifier(const struct Token **ptr_tokvec); 348 | 349 | struct SizeAndAlignment get_size_alignment_offsets_for_struct_not_union( 350 | const struct SizeAndAlignment *inner_type_vec, int **ptr_offset_vec, 351 | int length); 352 | 353 | struct SizeAndAlignment get_size_alignment_offsets_for_union( 354 | const struct SizeAndAlignment *inner_type_vec, int **ptr_offset_vec, 355 | int length); 356 | 357 | struct Type * 358 | try_parse_type_specifier_and_semicolon(const struct Token **ptr_tokvec); 359 | 360 | struct UntypedExpr parse_constant_expression(const struct Token **ptr_tokvec); 361 | 362 | struct UntypedExpr parse_assignment_expression(const struct Token **ptr_tokvec); 363 | 364 | struct Type parse_struct_declaration(const struct Token **ptr_tokvec, 365 | const char **ptr_to_ident_str); 366 | 367 | struct UntypedExpr binary_op_untyped(const struct UntypedExpr *ref_expr, 368 | const struct UntypedExpr *ref_expr2, 369 | enum TokenKind kind); 370 | 371 | char *unescape(const char *str); 372 | char *escape(const char *str); 373 | 374 | struct Type parse_type_specifier_and_declarator(const struct Token **ptr_tokvec, 375 | const char **ptr_to_ident_str); 376 | 377 | _Noreturn void simple_error(const char *str); 378 | 379 | void if_array_convert_to_ptr_(struct Type *ptr_t); 380 | 381 | void print_token_at(const struct Token *tokvec); 382 | 383 | struct Type ptr_to_type(const struct Type *ref_type); 384 | 385 | struct Type arr_of_type(const struct Type *ref_type, int length); 386 | 387 | void print_token(const struct Token *ptr_tok, const char *next_token_begins); 388 | 389 | struct Token *read_and_preprocess(const char *str, 390 | struct Vector *ref_cmdline_macros); 391 | 392 | struct Tokvec { 393 | int tok_num; 394 | struct Token *v; 395 | }; 396 | 397 | struct Tokvec preprocess(const char *str, 398 | struct Map2 /**/ *def_map); 399 | 400 | struct Tokvec read_all_tokens(const char *str); 401 | -------------------------------------------------------------------------------- /ir/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsjoihs/c-compiler/17f53331a19e37594d07e69cc70bc71ae30eb6f4/ir/.gitkeep -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "file_io.h" 2 | #include "print_x86_64.h" 3 | #include "std.h" 4 | #include "std_io.h" 5 | #include "toplevel.h" 6 | #include "global_flags.h" 7 | 8 | int global_flag_pedantic; 9 | 10 | int main(int argc, char const **argv) 11 | { 12 | struct __FILE *fp = stdin; 13 | struct Vector macros = init_vector(); 14 | 15 | for (int i = 1; i < argc; i++) { 16 | if (strncmp(argv[i], "-D", 2) == 0) { 17 | push_vector(¯os, argv[i] + 2); 18 | } else if (strncmp(argv[i], "--ir=", 5) == 0) { 19 | const char *ir_filename = argv[i] + 5; 20 | global_ir = fopen(ir_filename, "w"); 21 | if (!global_ir) { 22 | fprintf(stderr, "failed to write to file `%s`.\n", ir_filename); 23 | exit(EXIT_FAILURE); 24 | } 25 | } else if (strcmp(argv[i], "-pedantic") == 0) { 26 | global_flag_pedantic = 1; 27 | } else { 28 | const char *filename = argv[i]; 29 | fp = fopen(filename, "r"); 30 | if (!fp) { 31 | fprintf(stderr, "failed to open file `%s`.\n", filename); 32 | exit(EXIT_FAILURE); 33 | } 34 | } 35 | } 36 | 37 | char *str = read_from_file(fp); 38 | const struct Token *tokvec = read_and_preprocess(str, ¯os); 39 | ++tokvec; /* skip the dummy token BEGINNING */ 40 | const struct Vector /**/ vec = parse(tokvec); 41 | generate(&vec); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /map.c: -------------------------------------------------------------------------------- 1 | #include "map.h" 2 | #include "std.h" 3 | 4 | struct Map2 { 5 | int _length; 6 | int _alloc; 7 | struct _mapchip *_vec; 8 | }; 9 | 10 | struct _mapchip { 11 | const char *ptr; 12 | void *value; 13 | }; 14 | 15 | /* it overrides; it does not overwrite. */ 16 | void insert(struct Map2 *map, const char *key, void *value) 17 | { 18 | struct _mapchip a; 19 | a.ptr = key; 20 | a.value = value; 21 | if (map->_alloc < map->_length + 1) { 22 | 23 | map->_vec = 24 | realloc(map->_vec, map->_alloc * 2 * sizeof(struct _mapchip)); 25 | 26 | map->_alloc *= 2; 27 | } 28 | 29 | map->_vec[map->_length] = a; 30 | ++(map->_length); 31 | } 32 | 33 | void *lookup(const struct Map2 *m, const char *key) 34 | { 35 | for (int i = (m->_length) - 1; i >= 0; --i) { 36 | if (strcmp(m->_vec[i].ptr, key) == 0) { 37 | return m->_vec[i].value; 38 | } 39 | } 40 | return 0; 41 | } 42 | 43 | int isElem(const struct Map2 *m, const char *key) 44 | { 45 | return lookup(m, key) != 0; 46 | } 47 | 48 | struct Map2 *init_map(void) 49 | { 50 | struct Map2 *res; 51 | res = calloc(1, sizeof(struct Map2)); 52 | res->_length = 0; 53 | res->_alloc = 256; 54 | res->_vec = calloc(res->_alloc, sizeof(struct _mapchip)); 55 | return res; 56 | } 57 | -------------------------------------------------------------------------------- /map.h: -------------------------------------------------------------------------------- 1 | struct Map2; 2 | 3 | void insert(struct Map2 *map, const char *key, void *value); 4 | void *lookup(const struct Map2 *map, const char *key); 5 | struct Map2 *init_map(void); 6 | int isElem(const struct Map2 *map, const char *key); 7 | -------------------------------------------------------------------------------- /misc/assembly_sandbox.c: -------------------------------------------------------------------------------- 1 | #include "../print_x86_64.h" 2 | #include "../print_x86_64_unofficial.h" 3 | #include 4 | 5 | void gen_write_to_local_8byte(int offset); 6 | 7 | int main() 8 | { 9 | gen_prologue_static(0, "divide_addr_diff_by_173"); 10 | gen_write_register_to_local_8byte("rdi", -8); 11 | gen_write_register_to_local_8byte("rsi", -16); 12 | 13 | gen_push_from_local_nbyte(8, -8); 14 | gen_push_from_local_nbyte(8, -16); 15 | gen_op_8byte("subq"); 16 | 17 | gen_div_by_const(173); 18 | gen_epilogue(32); 19 | 20 | /* 21 | int main() 22 | { 23 | char a[1000]; 24 | return divide_addr_diff_by_173(a + 173 * 3, a); 25 | } 26 | */ 27 | puts("\n//gen_prologue(1000, \"main\")" 28 | "\n.global " PREFIX "main" 29 | "\n" PREFIX "main:" 30 | "\n pushq %rbp" 31 | "\n movq %rsp, %rbp" 32 | "\n subq $1000, %rsp" 33 | "\n//gen_push_address_of_local(-1000);" 34 | "\n subq $8, %rsp" 35 | "\n leaq -1000(%rbp), %rax" 36 | "\n movq %rax, (%rsp)" 37 | "\n//gen_push_address_of_local(-1000);" 38 | "\n subq $8, %rsp" 39 | "\n leaq -1000(%rbp), %rax" 40 | "\n movq %rax, (%rsp)" 41 | "\n//gen_push_int(173)" 42 | "\n subq $8, %rsp" 43 | "\n movl $173, (%rsp)" 44 | "\n//gen_push_int(3)" 45 | "\n subq $8, %rsp" 46 | "\n movl $3, (%rsp)" 47 | "\n//gen_mul_ints()" 48 | "\n movl 8(%rsp), %eax" 49 | "\n imull (%rsp), %eax" 50 | "\n movl %eax, 8(%rsp)" 51 | "\n addq $8, %rsp" 52 | "\n//gen_cltq()" 53 | "\n movl (%rsp), %eax" 54 | "\n cltq" 55 | "\n movq %rax, (%rsp)" 56 | "\n//gen_mul_by_const(1)" 57 | "\n movq (%rsp), %rax" 58 | "\n leaq 0(,%rax,1), %rdx" 59 | "\n movq %rdx, (%rsp)" 60 | "\n//gen_op_8byte(\"addq\")" 61 | "\n movq (%rsp), %rax" 62 | "\n addq %rax, 8(%rsp)" 63 | "\n addq $8, %rsp" 64 | "\n//gen_pop_to_reg_8byte(rdi)" 65 | "\n movq (%rsp), %rdi" 66 | "\n addq $8, %rsp" 67 | "\n//gen_pop_to_reg_8byte(rsi)" 68 | "\n movq (%rsp), %rsi" 69 | "\n addq $8, %rsp" 70 | "\n//gen_push_ret_of_4byte(\"divide_addr_diff_by_173\")" 71 | "\n subq $8, %rsp" 72 | "\n movq %rsp, %rax" 73 | "\n andq $15, %rax" 74 | "\n subq %rax, %rsp" 75 | "\n movq %rax, (%rsp)" 76 | "\n movb $0, %al" 77 | "\n call " PREFIX "divide_addr_diff_by_173" 78 | "\n addq (%rsp), %rsp" 79 | "\n movl %eax, (%rsp)" 80 | "\n//comment: return" 81 | "\n jmp .L4" 82 | "\n//gen_epilogue(4)" 83 | "\n.L4: movl (%rsp), %eax" 84 | "\n addl $171, %eax" 85 | "\n leave" 86 | "\n ret"); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /misc/call_va.c: -------------------------------------------------------------------------------- 1 | void debug_write(const char *fmt, ...); 2 | 3 | int main() 4 | { 5 | debug_write("%s", "Hello, va_list!\n"); 6 | debug_write("%s", "Hello, va_list 2!\n"); 7 | debug_write("%s %s %d%c\n", "Hello,", "va_list", 3, '!'); 8 | debug_write("%s %s %f%c\n", "Hello,", "va_list", 4.0, '!'); 9 | debug_write("%f %f %f %f %f %f %f %f%c\n", 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, '!'); 10 | debug_write("%s%s%c %s%s%s%s %f%c\n", "He", "llo", ',', "va", "_", "li", "st", 13.0, '!'); 11 | } 12 | -------------------------------------------------------------------------------- /misc/create_va.c: -------------------------------------------------------------------------------- 1 | #include "../print_x86_64.h" 2 | #include "../print_x86_64_unofficial.h" 3 | #include 4 | /* 5 | 6 | void debug_write(const char *fmt, ...) 7 | { 8 | va_list ap; 9 | va_start(ap, fmt); 10 | vfprintf(stderr, fmt, ap); 11 | va_end(ap); 12 | 13 | va_start(ap, fmt); 14 | vprintf(fmt, ap); 15 | va_end(ap); 16 | } 17 | 18 | */ 19 | 20 | int main() 21 | { 22 | int fmt = -232; 23 | int reg_save_area = -192; 24 | int stack_check = -200; 25 | int ap = -224; 26 | 27 | gen_prologue(304, "debug_write"); 28 | 29 | gen_write_register_to_local_8byte("rdi", fmt); /* fmt */ 30 | gen_store_regs_to_local(reg_save_area, 1, 23); /* va_start(ap, fmt) */ 31 | gen_write_stack_chk_guard_to_local(stack_check); 32 | 33 | gen_push_address_of_local(ap); 34 | gen_va_start(8, 0x30, reg_save_area); /* va_list ap; va_start(ap, fmt) */ 35 | gen_discard(); 36 | 37 | gen_push_address_of_global( 38 | #ifdef OSX 39 | "__stderrp" 40 | #endif 41 | #ifdef LINUX 42 | "stderr" 43 | #endif 44 | ); 45 | gen_peek_and_dereference_nbyte(8); 46 | gen_pop_to_reg_8byte("rdi"); /* %rdi <- __stderrp */ 47 | 48 | gen_push_address_of_local(ap); 49 | gen_pop_to_reg_8byte("rdx"); /* %rdx <- ap */ 50 | 51 | gen_push_from_local_8byte(fmt); 52 | gen_pop_to_reg_8byte("rsi"); /* %rsi <- fmt */ 53 | 54 | puts(" call " PREFIX "vfprintf"); 55 | 56 | gen_push_address_of_local(ap); 57 | gen_va_start(8, 0x30, reg_save_area); /* va_list ap; va_start(ap, fmt) */ 58 | gen_discard(); 59 | 60 | gen_push_address_of_local(ap); 61 | gen_pop_to_reg_8byte("rsi"); /* %rsi <- ap */ 62 | 63 | gen_push_from_local_8byte(fmt); 64 | gen_pop_to_reg_8byte("rdi"); /* %rdi <- fmt */ 65 | 66 | puts(" call " PREFIX "vprintf"); 67 | gen_push_int(123); 68 | gen_epilogue_nbyte_with_stack_check(4, 5421, stack_check, 6); 69 | } 70 | -------------------------------------------------------------------------------- /misc/digits_of_e.c: -------------------------------------------------------------------------------- 1 | #include "std_io.h" 2 | // Taken from http://www.uranus.dti.ne.jp/~n-sasaki/toyprogs.html 3 | int *p; 4 | int w[2048]; 5 | int n; 6 | int x; 7 | int main() 8 | { 9 | printf("2."); 10 | n = 825; 11 | for (p = w; ++p - w >> 11 ? p = w, x = n-- : 1;) 12 | n ? x = x % n * 10 + *p, *p = x / n : printf("%d", *p); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /misc/donut_donut.c: -------------------------------------------------------------------------------- 1 | int putchar();void* 2 | memset();int m(int a,int b) 3 | {return (a*b+5000)/10000;}void a( 4 | int*c,int*s,int d,int t){int k=m(*c,d 5 | )-m(*s,t);int l=m(*s,d)+m(*c,t);*c=k;*s=l 6 | ;}int usleep();int printf();int main(){int z[ 7 | 1760];char b[1760];printf("\e[2J");int s=10000; 8 | int q=s;int r=0;int u=s;int v=0;for(;;a(&q,&r,s-8 9 | ,400),a(&u,&v,s-2,200)){memset(b,32,1760);memset(z, 10 | 0,7040);int l=0;int p =s;for(int i=0;i<88;i 11 | ++,a(&p,&l,9974+i% 2,714)){int w=0;int 12 | e=s;for(int j=0;j< 314;j++,a(&e,&w,s- 13 | 2,200)){int f=p+2 *s;int g=s*s/(m(m 14 | (w,f),r)+m(l,q)+5* s);int t=m(m(w,q), 15 | f)-m(l,r);int x=40 +30*m(g,m(m(e,u),f 16 | )-m(t,v))/s;int y =12+15*m(g,m(m(e, 17 | v),f)+m(t,u))/s;int o=x+80*y;int N=8* 18 | (m(m(l,r)-m(m(w,q) ,p),u)-m(m(w,r),p)- 19 | m(l,q)-m(m(e,v),p))/s ;if(y>0&&g>z[o]&&y<22 20 | &&x>0&&80>x){z[o]=g;b[o]=".,-~:;=!*#$@"[N>=1?N:0]+0 21 | ;}}}printf("\e[H");for(int k=0;k<1761;k++)putchar 22 | (k%80?b[k]:10);printf("Author: @a1k0n. Rewritt" 23 | "en by @hsjoihs so that it works without flo" 24 | );https://github.com/hsjoihs/c-compiler/ 25 | printf("ating types.\nNote that roun" 26 | "ding errors gradually reduce th" 27 | "e donut's size.\n");usleep 28 | (50000);}return 0;} 29 | -------------------------------------------------------------------------------- /misc/donut_verbose.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define FloatTimes10000 int 6 | 7 | FloatTimes10000 mul(FloatTimes10000 a, FloatTimes10000 b) { 8 | return (a * b + 5000) / 10000; 9 | } 10 | 11 | int k; 12 | 13 | void update2(FloatTimes10000 *cos, FloatTimes10000 *sin, FloatTimes10000 cos_delta, FloatTimes10000 sin_delta) { 14 | FloatTimes10000 new_cos = mul(*cos, cos_delta) - mul(*sin, sin_delta); 15 | FloatTimes10000 new_sin = mul(*sin, cos_delta) + mul(*cos, sin_delta); 16 | *cos = new_cos; 17 | *sin = new_sin; 18 | } 19 | 20 | int main() { 21 | FloatTimes10000 zTimes10000[1760]; 22 | char b[1760]; 23 | printf("\e[2J"); 24 | FloatTimes10000 cosATimes10000 = 10000; FloatTimes10000 sinATimes10000 = 0; 25 | FloatTimes10000 cosBTimes10000 = 10000; FloatTimes10000 sinBTimes10000 = 0; 26 | for (;;update2(&cosATimes10000, &sinATimes10000, 9992, 400), update2(&cosBTimes10000, &sinBTimes10000, 9998, 200), usleep(50000)) { 27 | memset(b, 32, 1760 * sizeof(char)); 28 | memset(zTimes10000, 0, 1760 * sizeof(FloatTimes10000)); 29 | FloatTimes10000 sinthetaTimes10000 = 0; FloatTimes10000 costhetaTimes10000 = 10000; 30 | for (int theta_times_14 = 0; theta_times_14 < 88; theta_times_14++, update2(&costhetaTimes10000, &sinthetaTimes10000, 9974 + theta_times_14 % 2, 714)){ 31 | FloatTimes10000 sinphiTimes10000 = 0; FloatTimes10000 cosphiTimes10000 = 10000; 32 | for (int phi_times_50 = 0; phi_times_50 < 314; phi_times_50++, update2(&cosphiTimes10000, &sinphiTimes10000, 9998, 200)) { 33 | FloatTimes10000 hTimes10000 = costhetaTimes10000 + 20000; 34 | FloatTimes10000 DTimes10000 = 100000000 / ( 35 | mul(mul(sinphiTimes10000, hTimes10000), sinATimes10000) 36 | + mul(sinthetaTimes10000, cosATimes10000) 37 | + 50000); 38 | FloatTimes10000 tTimes10000 = mul(mul(sinphiTimes10000, cosATimes10000), hTimes10000) - mul(sinthetaTimes10000, sinATimes10000); 39 | int x = 40 + 30 * mul(DTimes10000, mul(mul(cosphiTimes10000, cosBTimes10000), hTimes10000) - mul(tTimes10000 , sinBTimes10000)) / 10000, 40 | y = 12 + 15 * mul(DTimes10000, mul(mul(cosphiTimes10000, sinBTimes10000), hTimes10000) + mul(tTimes10000 , cosBTimes10000)) / 10000, 41 | o = x + 80 * y, 42 | N = 8 * ( 43 | mul(mul(sinthetaTimes10000, sinATimes10000) - mul(mul(sinphiTimes10000, cosATimes10000), costhetaTimes10000), cosBTimes10000) 44 | - mul(mul(sinphiTimes10000, sinATimes10000), costhetaTimes10000) 45 | - mul(sinthetaTimes10000, cosATimes10000) 46 | - mul(mul(cosphiTimes10000, sinBTimes10000), costhetaTimes10000) 47 | ) / 10000; 48 | if (22 > y && y > 0 && x > 0 && 80 > x && DTimes10000 > zTimes10000[o]) { 49 | zTimes10000[o] = DTimes10000; 50 | b[o] = ".,-~:;=!*#$@"[N >= 1 ? N : 0]; 51 | } 52 | } 53 | } 54 | printf("\e[H"); 55 | for (k = 0; 1761 > k; k++) 56 | putchar(k % 80 ? b[k] : 10); 57 | } 58 | } -------------------------------------------------------------------------------- /misc/game_of_life.c: -------------------------------------------------------------------------------- 1 | // Edited by uint256_t 2 | // Taken from: https://gist.github.com/maekawatoshiki/8ea2f392e22698593d7ee8522aabbbd0 3 | 4 | // #include 5 | // #include 6 | // #include 7 | 8 | #define SIZE 20 9 | 10 | int printf(char *msg); 11 | int usleep(int time); 12 | 13 | int count_nbr(int grid[SIZE][SIZE], int i, int j, int size); 14 | 15 | void init_grid(int grid[SIZE][SIZE], int grid_binaries[SIZE]) 16 | { 17 | for (int i = 0; i < SIZE; i++) { 18 | for (int j = 0; j < SIZE; j++) { 19 | grid[i][j] = (grid_binaries[i] >> (SIZE - 1 - j)) & 1; 20 | } 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | int neighbour_count[SIZE][SIZE]; 27 | int grid[SIZE][SIZE]; 28 | int grid_binaries[SIZE]; 29 | grid_binaries[0] = 0b00000000000000000000, 30 | grid_binaries[1] = 0b00000000000000000000, 31 | grid_binaries[2] = 0b00000000000000000000, 32 | grid_binaries[3] = 0b00000000000000000000, 33 | grid_binaries[4] = 0b00000000000000000000, 34 | grid_binaries[5] = 0b00000000000000000000, 35 | grid_binaries[6] = 0b00000000000000000000, 36 | grid_binaries[7] = 0b00000111111111100000, 37 | grid_binaries[8] = 0b00000000000000000000, 38 | grid_binaries[9] = 0b00000000000000000000, 39 | grid_binaries[10] = 0b00000000000000000000, 40 | grid_binaries[11] = 0b00000000000000000000, 41 | grid_binaries[12] = 0b00000000000000000000, 42 | grid_binaries[13] = 0b00000000000000000000, 43 | grid_binaries[14] = 0b00111100000000000000, 44 | grid_binaries[15] = 0b01000100000000000000, 45 | grid_binaries[16] = 0b00000100000000000000, 46 | grid_binaries[17] = 0b01001000000000000000, 47 | grid_binaries[18] = 0b00000000000000000000, 48 | grid_binaries[19] = 0b00000000000000000000; 49 | init_grid(grid, grid_binaries); 50 | int i; 51 | int j; 52 | int steps; 53 | 54 | for (steps = 0; steps < 50; ++steps) { 55 | printf("\e[0;0H"); 56 | for (i = 0; i < SIZE; ++i) { 57 | printf("\n"); 58 | for (j = 0; j < SIZE; ++j) { 59 | if (grid[i][j] == 1) 60 | printf("\e[42m \e[m"); 61 | else 62 | printf("\e[47m \e[m"); 63 | neighbour_count[i][j] = count_nbr(grid, i, j, SIZE); 64 | } 65 | } 66 | 67 | for (i = 0; i < SIZE; ++i) { 68 | for (j = 0; j < SIZE; ++j) { 69 | if (grid[i][j] >= 1) { 70 | if (neighbour_count[i][j] <= 1 || 71 | neighbour_count[i][j] >= 4) 72 | grid[i][j] = 0; 73 | } else if (neighbour_count[i][j] == 3) 74 | grid[i][j] = 1; 75 | } 76 | } 77 | 78 | usleep(100000); 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | int count_nbr(int grid[SIZE][SIZE], int i, int j, int size) 85 | { 86 | int n_count = 0; 87 | if (i - 1 >= 0 && j - 1 >= 0) { 88 | if (grid[i - 1][j - 1] >= 1) 89 | n_count++; 90 | } 91 | 92 | if (i - 1 >= 0) { 93 | if (grid[i - 1][j] >= 1) 94 | n_count++; 95 | } 96 | 97 | if (i - 1 >= 0 && j + 1 < size) { 98 | if (grid[i - 1][j + 1] >= 1) 99 | n_count++; 100 | } 101 | 102 | if (j - 1 >= 0) { 103 | if (grid[i][j - 1] >= 1) 104 | n_count++; 105 | } 106 | 107 | if (j + 1 < size) { 108 | if (grid[i][j + 1] >= 1) 109 | n_count++; 110 | } 111 | 112 | if (i + 1 < size && j - 1 >= 0) { 113 | if (grid[i + 1][j - 1] >= 1) 114 | n_count++; 115 | } 116 | 117 | if (i + 1 < size) { 118 | if (grid[i + 1][j] >= 1) 119 | n_count++; 120 | } 121 | 122 | if (i + 1 < size && j + 1 < size) { 123 | if (grid[i + 1][j + 1] >= 1) 124 | n_count++; 125 | } 126 | 127 | return n_count; 128 | } -------------------------------------------------------------------------------- /misc/linktest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | struct F { 3 | int k; 4 | int *a; 5 | int *b; 6 | char *c; 7 | char *d; 8 | int *e; 9 | }; 10 | 11 | void baz(struct F *ptr) 12 | { 13 | ptr->k = 3; 14 | int *q = calloc(3, sizeof(int)); 15 | q[0] = 4; 16 | q[1] = 5; 17 | q[2] = 6; 18 | ptr->a = q; 19 | ptr->b = q + 1; 20 | ptr->e = q + 2; 21 | } 22 | -------------------------------------------------------------------------------- /misc/linktest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | struct F { 4 | int k; 5 | int *a; 6 | int *b; 7 | char *c; 8 | char *d; 9 | int *e; 10 | }; 11 | struct F baz(void); 12 | 13 | int main() 14 | { 15 | struct F f = baz(); 16 | assert(f.k == 3); 17 | assert(*f.a == 4); 18 | assert(*f.b == 5); 19 | assert(*f.e == 6); 20 | printf("successful\n"); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /misc/pi.c: -------------------------------------------------------------------------------- 1 | #include "std_io.h" 2 | // Taken from https://xn--w6q13e505b.jp/program/spigot.html 3 | int nume[52514]; 4 | int i; 5 | int n; 6 | int carry; 7 | int digit; 8 | int base; 9 | int denom; 10 | int first; 11 | 12 | int main() { 13 | base = 10000; 14 | for (n = 52500; n > 0; n -= 14) { 15 | carry %= base; 16 | digit = carry; 17 | for (i = n - 1; i > 0; --i) { 18 | denom = 2 * i - 1; 19 | carry = carry * i + base * (first ? nume[i] : (base / 5)); 20 | nume[i] = carry % denom; 21 | carry /= denom; 22 | } 23 | first = printf("%04d", digit + carry / base); 24 | } 25 | return 0; 26 | } -------------------------------------------------------------------------------- /misc/smallstruct.c: -------------------------------------------------------------------------------- 1 | #include "../print_x86_64.h" 2 | #include "../print_x86_64_unofficial.h" 3 | #include 4 | 5 | int main() 6 | { 7 | 8 | /* 9 | struct A{ char a[n]; }; 10 | 11 | struct A derefn(struct A *p) 12 | { 13 | return *p; 14 | } 15 | 16 | */ 17 | 18 | for (int n = 1; n <= 16; n++) { 19 | char str[8]; 20 | sprintf(str, "deref%d", n); 21 | gen_prologue(8, str); 22 | gen_write_register_to_local_8byte("rdi", -8); 23 | gen_push_from_local_8byte(-8); 24 | gen_epilogue_returning_integerclass_struct_or_union(n, n+162); 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /misc/smallstruct2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct A1 {char a[1];}; struct A1 deref1(struct A1 *p); 7 | struct A2 {char a[2];}; struct A2 deref2(struct A2 *p); 8 | struct A3 {char a[3];}; struct A3 deref3(struct A3 *p); 9 | struct A4 {char a[4];}; struct A4 deref4(struct A4 *p); 10 | struct A5 {char a[5];}; struct A5 deref5(struct A5 *p); 11 | struct A6 {char a[6];}; struct A6 deref6(struct A6 *p); 12 | struct A7 {char a[7];}; struct A7 deref7(struct A7 *p); 13 | struct A8 {char a[8];}; struct A8 deref8(struct A8 *p); 14 | struct A9 {char a[9];}; struct A9 deref9(struct A9 *p); 15 | struct A10 {char a[10];}; struct A10 deref10(struct A10 *p); 16 | struct A11 {char a[11];}; struct A11 deref11(struct A11 *p); 17 | struct A12 {char a[12];}; struct A12 deref12(struct A12 *p); 18 | struct A13 {char a[13];}; struct A13 deref13(struct A13 *p); 19 | struct A14 {char a[14];}; struct A14 deref14(struct A14 *p); 20 | struct A15 {char a[15];}; struct A15 deref15(struct A15 *p); 21 | struct A16 {char a[16];}; struct A16 deref16(struct A16 *p); 22 | 23 | void garbge(void *p, int n){ 24 | for (int i = 0; i < n; i++) { 25 | i[(char*)p] = rand() % 37; 26 | } 27 | } 28 | 29 | int main() 30 | { 31 | srand(time(0)); 32 | {struct A1 q; garbge(&q, 1); struct A1 r = deref1(&q); if (memcmp(&q, &r, 1)) return 1;} 33 | {struct A2 q; garbge(&q, 2); struct A2 r = deref2(&q); if (memcmp(&q, &r, 2)) return 2;} 34 | {struct A3 q; garbge(&q, 3); struct A3 r = deref3(&q); if (memcmp(&q, &r, 3)) return 3;} 35 | {struct A4 q; garbge(&q, 4); struct A4 r = deref4(&q); if (memcmp(&q, &r, 4)) return 4;} 36 | {struct A5 q; garbge(&q, 5); struct A5 r = deref5(&q); if (memcmp(&q, &r, 5)) return 5;} 37 | {struct A6 q; garbge(&q, 6); struct A6 r = deref6(&q); if (memcmp(&q, &r, 6)) return 6;} 38 | {struct A7 q; garbge(&q, 7); struct A7 r = deref7(&q); if (memcmp(&q, &r, 7)) return 7;} 39 | {struct A8 q; garbge(&q, 8); struct A8 r = deref8(&q); if (memcmp(&q, &r, 8)) return 8;} 40 | {struct A9 q; garbge(&q, 9); struct A9 r = deref9(&q); if (memcmp(&q, &r, 9)) return 9;} 41 | {struct A10 q; garbge(&q, 10); struct A10 r = deref10(&q); if (memcmp(&q, &r, 10)) return 10;} 42 | {struct A11 q; garbge(&q, 11); struct A11 r = deref11(&q); if (memcmp(&q, &r, 11)) return 11;} 43 | {struct A12 q; garbge(&q, 12); struct A12 r = deref12(&q); if (memcmp(&q, &r, 12)) return 12;} 44 | {struct A13 q; garbge(&q, 13); struct A13 r = deref13(&q); if (memcmp(&q, &r, 13)) return 13;} 45 | {struct A14 q; garbge(&q, 14); struct A14 r = deref14(&q); if (memcmp(&q, &r, 14)) return 14;} 46 | {struct A15 q; garbge(&q, 15); struct A15 r = deref15(&q); if (memcmp(&q, &r, 15)) return 15;} 47 | {struct A16 q; garbge(&q, 16); struct A16 r = deref16(&q); if (memcmp(&q, &r, 16)) return 16;} 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /misc/supplement0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int GLOBAL_VAR = 3; 5 | 6 | int ptrdiff(void *p1, void *p2) { return (char *)p1 - (char *)p2; } 7 | 8 | int *alloc4(int a, int b, int c, int d) 9 | { 10 | int *p = calloc(4, sizeof(int)); 11 | p[0] = a; 12 | p[1] = b; 13 | p[2] = c; 14 | p[3] = d; 15 | return p; 16 | } 17 | 18 | int foobar(const char *str, int i, int j) 19 | { 20 | printf(str, i, j); 21 | return 0; 22 | } 23 | 24 | struct INT_CHAR_CHAR_INT { 25 | int a; 26 | char c; 27 | char d; 28 | int b; 29 | }; 30 | 31 | struct INT_CHAR_CHAR_INT *get_struct_pointer(int a, int b) 32 | { 33 | struct INT_CHAR_CHAR_INT *p = calloc(1, sizeof(struct INT_CHAR_CHAR_INT)); 34 | p->a = a; 35 | p->b = b; 36 | return p; 37 | } 38 | 39 | int add8(int a, int b, int c, int d, int e, int f, int g, int h) 40 | { 41 | return a + b + c + d + e + f + g + h; 42 | } 43 | 44 | struct INT_CHARS_INT { 45 | int a; 46 | char c[100]; 47 | int b; 48 | }; 49 | 50 | struct INT_CHARS_INT merge7(int a, int b, int c, int d, int e, int f, int g 51 | ) 52 | { 53 | struct INT_CHARS_INT st; 54 | st.a = a + b; 55 | st.b = c + d; 56 | st.c[0] = e + f; 57 | st.c[1] = g; 58 | return st; 59 | } 60 | -------------------------------------------------------------------------------- /misc/supplement1.c: -------------------------------------------------------------------------------- 1 | static int hidden() { return 0; } 2 | int always87() { return 87; } 3 | int always8() { return 8; } 4 | int add(int x, int y) { return x + y; } 5 | int subtract(int x, int y) { return x - y; } 6 | 7 | int qwerty(char a, char b) 8 | { 9 | int d; 10 | d = 3; 11 | char c; 12 | c = a + d; 13 | return c * 4; 14 | } 15 | int qwer(char a, char b) 16 | { 17 | int d; 18 | d = 3; 19 | char c; 20 | c = a + d; 21 | return c * b; 22 | } 23 | 24 | struct TWO_INTS { 25 | int a; 26 | int b; 27 | }; 28 | 29 | int add_two_ints(struct TWO_INTS *p) { return p->a + p->b; } 30 | 31 | struct INT_CHAR_CHAR_INT { 32 | int a; 33 | char c; 34 | char d; 35 | int b; 36 | }; 37 | 38 | int add_two_ints2(struct INT_CHAR_CHAR_INT *p) { return p->a + p->b; } 39 | 40 | int add6(int a, int b, int c, int d, int e, int f) 41 | { 42 | return a + b + c + d + e + f; 43 | } 44 | 45 | 46 | struct Q{int a; int b; int *p;}; 47 | 48 | struct Q q(void) {struct Q u; u.a = 100; u.b = 74; u.p = 0; return u;} 49 | 50 | int r(struct Q *p) {return p->a + p->b;} 51 | 52 | 53 | struct Test{int a; int b; int *p; int *q; int *r; int *s;}; 54 | 55 | struct Test test_(int *s) 56 | { 57 | struct Test u; 58 | u.a = 74; 59 | u.s = s; 60 | return u; 61 | } 62 | 63 | int add_3(int a){return 3 + a;} 64 | 65 | void *return_fp(void){return add_3;} 66 | 67 | int call_fp(void* q){int (*p)(int) = q;return (*p)(171);} 68 | -------------------------------------------------------------------------------- /misc/todo.md: -------------------------------------------------------------------------------- 1 | # To do 2 | 3 | ## Features used within the code 4 | 5 | 6 | ## Features not used within the code 7 | 8 | - defining `struct`s, `enum`s and `union`s locally 9 | - `short` 10 | - `enum Foo {Bar = 1, Baz};` 11 | - `unsigned`, (`long long` or `uint64_t`) (required to correctly support `size_t`) 12 | - `int array[] = {0, 1, 2, 3};` 13 | - `for(...) ;` 14 | - `typedef` (`stderr` is `FILE *`, though it seems to be `struct __sFILE *` or something internally. Also needed for `va_list`.) 15 | - 7 or more arguments 16 | - passing structs to a function 17 | - function-style macros 18 | - `#define` that expands to multiple tokens 19 | 20 | ## others 21 | 22 | - faster testing 23 | -------------------------------------------------------------------------------- /misc/va.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void debug_write(const char *fmt, ...) 5 | { 6 | va_list ap; 7 | va_start(ap, fmt); 8 | vfprintf(stderr, fmt, ap); 9 | va_end(ap); 10 | 11 | va_start(ap, fmt); 12 | vprintf(fmt, ap); 13 | va_end(ap); 14 | } 15 | -------------------------------------------------------------------------------- /misc/va_linux.s: -------------------------------------------------------------------------------- 1 | //gen_prologue(304, "debug_write"); 2 | .global debug_write 3 | debug_write: 4 | pushq %rbp 5 | movq %rsp, %rbp 6 | subq $304, %rsp 7 | //gen_write_register_to_local_8byte("rdi", -232); 8 | movq %rdi, -232(%rbp) 9 | //gen_store_regs_to_local(-192, 1, 23); 10 | testb %al, %al 11 | movq %rsi, -184(%rbp) 12 | movq %rdx, -176(%rbp) 13 | movq %rcx, -168(%rbp) 14 | movq %r8, -160(%rbp) 15 | movq %r9, -152(%rbp) 16 | je .L23 17 | movaps %xmm0, -144(%rbp) 18 | movaps %xmm1, -128(%rbp) 19 | movaps %xmm2, -112(%rbp) 20 | movaps %xmm3, -96(%rbp) 21 | movaps %xmm4, -80(%rbp) 22 | movaps %xmm5, -64(%rbp) 23 | movaps %xmm6, -48(%rbp) 24 | movaps %xmm7, -32(%rbp) 25 | .L23: 26 | //gen_write_stack_chk_guard_to_local(-200); 27 | movq %fs:40, %rax 28 | movq %rax, -200(%rbp) 29 | //gen_push_address_of_local(-224); 30 | subq $8, %rsp 31 | leaq -224(%rbp), %rax 32 | movq %rax, (%rsp) 33 | //gen_va_start(8, 48, -192); 34 | movq (%rsp), %rdx 35 | movl $8, (%rdx) 36 | movl $48, 4(%rdx) 37 | leaq 16(%rbp), %rax 38 | movq %rax, 8(%rdx) 39 | leaq -192(%rbp), %rax 40 | movq %rax, 16(%rdx) 41 | //gen_discard(); 42 | addq $8, %rsp 43 | //gen_push_address_of_global("stderr"); 44 | subq $8, %rsp 45 | leaq stderr(%rip), %rax 46 | movq %rax, (%rsp) 47 | //gen_peek_and_dereference_nbyte(8); 48 | //gen_peek_and_dereference_8byte() 49 | movq (%rsp), %rax 50 | movq (%rax), %rax 51 | movq %rax, (%rsp) 52 | //gen_pop_to_reg_8byte("rdi"); 53 | movq (%rsp), %rdi 54 | addq $8, %rsp 55 | //gen_push_address_of_local(-224); 56 | subq $8, %rsp 57 | leaq -224(%rbp), %rax 58 | movq %rax, (%rsp) 59 | //gen_pop_to_reg_8byte("rdx"); 60 | movq (%rsp), %rdx 61 | addq $8, %rsp 62 | //gen_push_from_local_8byte(-232) 63 | subq $8, %rsp 64 | movq -232(%rbp), %rax 65 | movq %rax, (%rsp) 66 | //gen_pop_to_reg_8byte("rsi"); 67 | movq (%rsp), %rsi 68 | addq $8, %rsp 69 | call vfprintf 70 | //gen_push_address_of_local(-224); 71 | subq $8, %rsp 72 | leaq -224(%rbp), %rax 73 | movq %rax, (%rsp) 74 | //gen_va_start(8, 48, -192); 75 | movq (%rsp), %rdx 76 | movl $8, (%rdx) 77 | movl $48, 4(%rdx) 78 | leaq 16(%rbp), %rax 79 | movq %rax, 8(%rdx) 80 | leaq -192(%rbp), %rax 81 | movq %rax, 16(%rdx) 82 | //gen_discard(); 83 | addq $8, %rsp 84 | //gen_push_address_of_local(-224); 85 | subq $8, %rsp 86 | leaq -224(%rbp), %rax 87 | movq %rax, (%rsp) 88 | //gen_pop_to_reg_8byte("rsi"); 89 | movq (%rsp), %rsi 90 | addq $8, %rsp 91 | //gen_push_from_local_8byte(-232) 92 | subq $8, %rsp 93 | movq -232(%rbp), %rax 94 | movq %rax, (%rsp) 95 | //gen_pop_to_reg_8byte("rdi"); 96 | movq (%rsp), %rdi 97 | addq $8, %rsp 98 | call vprintf 99 | //gen_push_int(123); 100 | subq $8, %rsp 101 | movl $123, (%rsp) 102 | //gen_epilogue_nbyte_with_stack_check(4, 5421, -200, 6); 103 | movq -200(%rbp), %rax 104 | cmpq %fs:40, %rax 105 | jne .L6 106 | //gen_epilogue_nbyte(4, 5421); 107 | //gen_epilogue(5421) 108 | .L5421: movl (%rsp), %eax 109 | leave 110 | ret 111 | .L6: 112 | call __stack_chk_fail 113 | -------------------------------------------------------------------------------- /misc/va_macos.s: -------------------------------------------------------------------------------- 1 | //gen_prologue(304, "debug_write") 2 | .global _debug_write 3 | _debug_write: 4 | pushq %rbp 5 | movq %rsp, %rbp 6 | subq $304, %rsp 7 | //gen_write_register_to_local_8byte("rdi", -232) 8 | movq %rdi, -232(%rbp) 9 | //gen_store_regs_to_local(-192, 1, 23) 10 | testb %al, %al 11 | movq %rsi, -184(%rbp) 12 | movq %rdx, -176(%rbp) 13 | movq %rcx, -168(%rbp) 14 | movq %r8, -160(%rbp) 15 | movq %r9, -152(%rbp) 16 | je .L23 17 | movaps %xmm0, -144(%rbp) 18 | movaps %xmm1, -128(%rbp) 19 | movaps %xmm2, -112(%rbp) 20 | movaps %xmm3, -96(%rbp) 21 | movaps %xmm4, -80(%rbp) 22 | movaps %xmm5, -64(%rbp) 23 | movaps %xmm6, -48(%rbp) 24 | movaps %xmm7, -32(%rbp) 25 | .L23: 26 | //gen_write_stack_chk_guard_to_local(-200) 27 | movq ___stack_chk_guard@GOTPCREL(%rip), %rax 28 | movq (%rax), %rax 29 | movq %rax, -200(%rbp) 30 | //gen_push_address_of_local(-224); 31 | subq $8, %rsp 32 | leaq -224(%rbp), %rax 33 | movq %rax, (%rsp) 34 | //gen_va_start(8, 48, -192) 35 | movq (%rsp), %rdx 36 | movl $8, (%rdx) 37 | movl $48, 4(%rdx) 38 | leaq 16(%rbp), %rax 39 | movq %rax, 8(%rdx) 40 | leaq -192(%rbp), %rax 41 | movq %rax, 16(%rdx) 42 | //gen_discard() 43 | addq $8, %rsp 44 | //gen_push_address_of_global("__stderrp"); 45 | subq $8, %rsp 46 | movq ___stderrp@GOTPCREL(%rip), %rax 47 | movq %rax, (%rsp) 48 | //gen_peek_and_dereference_8byte() 49 | movq (%rsp), %rax 50 | movq (%rax), %rax 51 | movq %rax, (%rsp) 52 | //gen_pop_to_reg_8byte("rdi") 53 | movq (%rsp), %rdi 54 | addq $8, %rsp 55 | //gen_push_address_of_local(-224); 56 | subq $8, %rsp 57 | leaq -224(%rbp), %rax 58 | movq %rax, (%rsp) 59 | //gen_pop_to_reg_8byte("rdx") 60 | movq (%rsp), %rdx 61 | addq $8, %rsp 62 | //gen_push_from_local_8byte(-232) 63 | subq $8, %rsp 64 | movq -232(%rbp), %rax 65 | movq %rax, (%rsp) 66 | //gen_pop_to_reg_8byte("rsi") 67 | movq (%rsp), %rsi 68 | addq $8, %rsp 69 | call _vfprintf 70 | //gen_push_address_of_local(-224); 71 | subq $8, %rsp 72 | leaq -224(%rbp), %rax 73 | movq %rax, (%rsp) 74 | //gen_va_start(8, 48, -192) 75 | movq (%rsp), %rdx 76 | movl $8, (%rdx) 77 | movl $48, 4(%rdx) 78 | leaq 16(%rbp), %rax 79 | movq %rax, 8(%rdx) 80 | leaq -192(%rbp), %rax 81 | movq %rax, 16(%rdx) 82 | //gen_discard() 83 | addq $8, %rsp 84 | //gen_push_address_of_local(-224); 85 | subq $8, %rsp 86 | leaq -224(%rbp), %rax 87 | movq %rax, (%rsp) 88 | //gen_pop_to_reg_8byte("rsi") 89 | movq (%rsp), %rsi 90 | addq $8, %rsp 91 | //gen_push_from_local_8byte(-232) 92 | subq $8, %rsp 93 | movq -232(%rbp), %rax 94 | movq %rax, (%rsp) 95 | //gen_pop_to_reg_8byte("rdi") 96 | movq (%rsp), %rdi 97 | addq $8, %rsp 98 | call _vprintf 99 | //gen_push_int(123) 100 | subq $8, %rsp 101 | movl $123, (%rsp) 102 | //gen_epilogue_nbyte_with_stack_check(4, 5421, -200, 6) 103 | //gen_push_address_of_global("__stack_chk_guard"); 104 | subq $8, %rsp 105 | movq ___stack_chk_guard@GOTPCREL(%rip), %rax 106 | movq %rax, (%rsp) 107 | //gen_peek_and_dereference_8byte() 108 | movq (%rsp), %rax 109 | movq (%rax), %rax 110 | movq %rax, (%rsp) 111 | //gen_pop_to_reg_8byte("rax") 112 | movq (%rsp), %rax 113 | addq $8, %rsp 114 | cmpq -200(%rbp), %rax 115 | jne .L6 116 | //gen_epilogue(5421) 117 | .L5421: movl (%rsp), %eax 118 | leave 119 | ret 120 | .L6: 121 | call ___stack_chk_fail 122 | -------------------------------------------------------------------------------- /out/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsjoihs/c-compiler/17f53331a19e37594d07e69cc70bc71ae30eb6f4/out/.gitkeep -------------------------------------------------------------------------------- /parse_analyze_statement.c: -------------------------------------------------------------------------------- 1 | #include "analyzer.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | 5 | static struct Expr integer_1(void) 6 | { 7 | struct Expr expr; 8 | expr.details.type = INT_TYPE(); 9 | expr.int_value = 1; 10 | expr.category = INT_VALUE; 11 | 12 | return expr; 13 | } 14 | 15 | /* 16 | * Adjusts the newest_offset and add a local variable to the scope. 17 | * Returns the offset of the newly added variable. 18 | */ 19 | int add_local_var_to_scope(struct AnalyzerState *ptr_ps, 20 | const struct Type *ref_vartype, const char *str) 21 | { 22 | ptr_ps->newest_offset -= size_of(ptr_ps, ref_vartype); 23 | 24 | struct LocalVarInfo *ptr_varinfo = calloc(1, sizeof(struct LocalVarInfo)); 25 | ptr_varinfo->offset = ptr_ps->newest_offset; 26 | ptr_varinfo->type = *ref_vartype; 27 | insert(ptr_ps->scope_chain.var_table, str, ptr_varinfo); 28 | 29 | return ptr_varinfo->offset; 30 | } 31 | 32 | struct Statement parse_labeled_statement(struct AnalyzerState *ptr_ps, 33 | const struct Token **ptr_tokvec) 34 | { 35 | const struct Token *tokvec = *ptr_tokvec; 36 | enum TokenKind kind = tokvec[0].kind; 37 | 38 | struct SourceLabel l; 39 | if (kind == RES_DEFAULT) { 40 | ++tokvec; 41 | l.category = DEFAULT_LABEL; 42 | } else if (kind == RES_CASE) { 43 | ++tokvec; 44 | const struct UntypedExpr u = parse_constant_expression(&tokvec); 45 | int case_int = 46 | typecheck_constant_integral_expression(ptr_ps, &u, "case"); 47 | l.category = CASE_LABEL; 48 | l.case_int = case_int; 49 | } else { 50 | l.ident_str = tokvec[0].ident_str; 51 | ++tokvec; 52 | l.category = IDENT_LABEL; 53 | } 54 | expect_and_consume(&tokvec, COLON, 55 | "colon of `default:`, `case VALUE:`, or `ident:`"); 56 | 57 | struct Statement s = parse_statement(ptr_ps, &tokvec); 58 | 59 | struct SourceLabel *ptr_l = calloc(1, sizeof(struct SourceLabel)); 60 | *ptr_l = l; 61 | push_vector(&s.labels, ptr_l); 62 | *ptr_tokvec = tokvec; 63 | return s; 64 | } 65 | 66 | static struct Expr *declare_var_and_return_initializer( 67 | struct AnalyzerState *ptr_ps, const struct Type *ref_vartype, 68 | const char *str, const struct UntypedExpr *ptr_uexpr, 69 | struct Statement *ptr_statement); 70 | 71 | struct Statement parse_statement(struct AnalyzerState *ptr_ps, 72 | const struct Token **ptr_tokvec) 73 | { 74 | const struct Token *tokvec = *ptr_tokvec; 75 | if (tokvec[0].kind == RES_CASE || tokvec[0].kind == RES_DEFAULT || 76 | (tokvec[0].kind == IDENT_OR_RESERVED && tokvec[1].kind == COLON)) { 77 | return parse_labeled_statement(ptr_ps, ptr_tokvec); 78 | } 79 | 80 | switch (tokvec[0].kind) { 81 | case LEFT_BRACE: { 82 | return parse_compound_statement(ptr_ps, ptr_tokvec); 83 | } 84 | 85 | case RES_IF: { 86 | ++tokvec; 87 | expect_and_consume(&tokvec, LEFT_PAREN, 88 | "left parenthesis immediately after `if`"); 89 | 90 | const struct UntypedExpr u = parse_expression(&tokvec); 91 | struct Expr expr = typecheck_expression(ptr_ps, &u); 92 | expect_scalar(&expr.details.type, "`if` statement"); 93 | 94 | expect_and_consume(&tokvec, RIGHT_PAREN, "right parenthesis of `if`"); 95 | 96 | struct Statement *ptr_inner_s = calloc(1, sizeof(struct Statement)); 97 | *ptr_inner_s = parse_statement(ptr_ps, &tokvec); 98 | 99 | struct Statement s; 100 | s.labels = init_vector(); 101 | s.expr1 = expr; 102 | if (tokvec[0].kind == RES_ELSE) { /* must bind to the most inner one */ 103 | ++tokvec; 104 | struct Statement *ptr_inner_s2 = 105 | calloc(1, sizeof(struct Statement)); 106 | *ptr_inner_s2 = parse_statement(ptr_ps, &tokvec); 107 | 108 | *ptr_tokvec = tokvec; 109 | 110 | s.category = IF_ELSE_STATEMENT; 111 | s.statement_vector = init_vector(); 112 | push_vector(&s.statement_vector, ptr_inner_s); 113 | push_vector(&s.statement_vector, ptr_inner_s2); 114 | return s; 115 | } 116 | 117 | *ptr_tokvec = tokvec; 118 | s.category = IF_STATEMENT; 119 | s.inner_statement = ptr_inner_s; 120 | return s; 121 | } 122 | 123 | case RES_SWITCH: { 124 | ++tokvec; 125 | expect_and_consume(&tokvec, LEFT_PAREN, 126 | "left parenthesis immediately after `switch`"); 127 | 128 | const struct UntypedExpr u = parse_expression(&tokvec); 129 | 130 | struct Expr expr = typecheck_expression(ptr_ps, &u); 131 | expect_and_consume(&tokvec, RIGHT_PAREN, 132 | "right parenthesis of `switch`"); 133 | 134 | expect_integral( 135 | &expr.details.type, 136 | "controlling expression of `switch` must be integer type"); 137 | 138 | struct Statement *ptr_inner_s = calloc(1, sizeof(struct Statement)); 139 | *ptr_inner_s = parse_statement(ptr_ps, &tokvec); 140 | 141 | struct Statement s; 142 | s.labels = init_vector(); 143 | s.expr1 = expr; 144 | *ptr_tokvec = tokvec; 145 | s.category = SWITCH_STATEMENT; 146 | s.inner_statement = ptr_inner_s; 147 | return s; 148 | } 149 | 150 | case RES_RETURN: { 151 | ++tokvec; 152 | *ptr_tokvec = tokvec; 153 | struct Statement s; 154 | s.labels = init_vector(); 155 | s.category = RETURN_STATEMENT; 156 | 157 | if (tokvec[0].kind == SEMICOLON) { 158 | ++tokvec; 159 | s.expr1.category = VOID_EXPR; 160 | s.expr1.details.type.type_category = VOID_; 161 | s.expr1.details.true_type.type_category = VOID_; 162 | } else { 163 | const struct UntypedExpr u = parse_expression(&tokvec); 164 | struct Expr expr = typecheck_expression(ptr_ps, &u); 165 | 166 | if (ptr_ps->func_ret_type.type_category == PTR_) { 167 | struct TypePair details; 168 | details.type = ptr_ps->func_ret_type; 169 | details.true_type = ptr_ps->func_ret_type; 170 | cast_to_null_pointer_if_possible(&expr, &details); 171 | if_function_cast_to_pointer(&expr); 172 | } 173 | 174 | expect_type(ptr_ps, &expr.details.type, &ptr_ps->func_ret_type, 175 | "mismatched type in the return value"); 176 | expect_and_consume(&tokvec, SEMICOLON, 177 | "semicolon (after `return expr`)"); 178 | s.expr1 = expr; 179 | } 180 | 181 | *ptr_tokvec = tokvec; 182 | return s; 183 | } 184 | 185 | case RES_DO: { 186 | ++tokvec; 187 | 188 | struct Statement inner_s = parse_statement(ptr_ps, &tokvec); 189 | 190 | expect_and_consume(&tokvec, RES_WHILE, "`while` of do-while"); 191 | expect_and_consume(&tokvec, LEFT_PAREN, "left parenthesis of do-while"); 192 | 193 | const struct UntypedExpr u = parse_expression(&tokvec); 194 | 195 | struct Expr expr = typecheck_expression(ptr_ps, &u); 196 | expect_scalar(&expr.details.type, "`do-while` statement"); 197 | 198 | expect_and_consume(&tokvec, RIGHT_PAREN, 199 | "right parenthesis of do-while"); 200 | expect_and_consume(&tokvec, SEMICOLON, "semicolon after do-while"); 201 | *ptr_tokvec = tokvec; 202 | 203 | struct Statement s; 204 | s.labels = init_vector(); 205 | s.category = DO_WHILE_STATEMENT; 206 | s.expr1 = expr; 207 | 208 | struct Statement *ptr_inner_s = calloc(1, sizeof(struct Statement)); 209 | *ptr_inner_s = inner_s; 210 | s.inner_statement = ptr_inner_s; 211 | return s; 212 | } 213 | 214 | case RES_WHILE: { 215 | ++tokvec; 216 | 217 | expect_and_consume(&tokvec, LEFT_PAREN, "left parenthesis of while"); 218 | 219 | const struct UntypedExpr u = parse_expression(&tokvec); 220 | 221 | struct Expr expr = typecheck_expression(ptr_ps, &u); 222 | expect_scalar(&expr.details.type, "`while` statement"); 223 | 224 | expect_and_consume(&tokvec, RIGHT_PAREN, "left parenthesis of while"); 225 | 226 | struct Statement inner_s = parse_statement(ptr_ps, &tokvec); 227 | 228 | *ptr_tokvec = tokvec; 229 | 230 | struct Statement s; 231 | s.labels = init_vector(); 232 | s.category = WHILE_STATEMENT; 233 | s.expr1 = expr; 234 | 235 | struct Statement *ptr_inner_s = calloc(1, sizeof(struct Statement)); 236 | *ptr_inner_s = inner_s; 237 | s.inner_statement = ptr_inner_s; 238 | return s; 239 | } 240 | 241 | case RES_BREAK: { 242 | ++tokvec; 243 | expect_and_consume(&tokvec, SEMICOLON, "semicolon after `break`"); 244 | *ptr_tokvec = tokvec; 245 | 246 | struct Statement s; 247 | s.labels = init_vector(); 248 | s.category = BREAK_STATEMENT; 249 | return s; 250 | } 251 | 252 | case RES_CONTINUE: { 253 | ++tokvec; 254 | expect_and_consume(&tokvec, SEMICOLON, "semicolon after `continue`"); 255 | *ptr_tokvec = tokvec; 256 | 257 | struct Statement s; 258 | s.labels = init_vector(); 259 | s.category = CONTINUE_STATEMENT; 260 | return s; 261 | } 262 | 263 | case RES_GOTO: { 264 | ++tokvec; 265 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 266 | "identifier after `goto`"); 267 | const char *ident = tokvec[-1].ident_str; 268 | expect_and_consume(&tokvec, SEMICOLON, 269 | "semicolon after `goto identifier`"); 270 | *ptr_tokvec = tokvec; 271 | 272 | struct Statement s; 273 | s.labels = init_vector(); 274 | s.category = GOTO_STATEMENT; 275 | s.destination = ident; 276 | return s; 277 | } 278 | 279 | case RES_FOR: { 280 | 281 | ++tokvec; 282 | expect_and_consume(&tokvec, LEFT_PAREN, "left parenthesis of `for`"); 283 | 284 | /* make the whole thing into a block*/ 285 | struct Statement statement; 286 | statement.category = COMPOUND_STATEMENT; 287 | statement.labels = init_vector(); 288 | statement.statement_vector = init_vector(); 289 | 290 | /* block scope begins */ 291 | struct ScopeChain current_table = ptr_ps->scope_chain; 292 | struct ScopeChain new_table; 293 | new_table.var_table = init_map(); 294 | new_table.outer = ¤t_table; 295 | ptr_ps->scope_chain = new_table; 296 | 297 | struct Expr expr1; 298 | struct Expr expr2; 299 | struct Expr expr3; 300 | 301 | if (tokvec[0].kind == SEMICOLON) { /* expression1 is missing */ 302 | expr1 = integer_1(); 303 | ++tokvec; 304 | } else if (can_start_a_type(tokvec)) { 305 | const char *str; 306 | struct UntypedExpr *ptr_uexpr; 307 | const struct Type vartype = 308 | parse_declaration(&tokvec, &str, &ptr_uexpr); 309 | 310 | struct Expr *ptr_expr = declare_var_and_return_initializer( 311 | ptr_ps, &vartype, str, ptr_uexpr, &statement); 312 | 313 | expr1 = ptr_expr ? *ptr_expr : integer_1(); 314 | } else { 315 | const struct UntypedExpr u = parse_expression(&tokvec); 316 | expr1 = typecheck_expression(ptr_ps, &u); 317 | expect_and_consume(&tokvec, SEMICOLON, "first semicolon of `for`"); 318 | } 319 | 320 | if (tokvec[0].kind == SEMICOLON) { /* expression2 is missing */ 321 | expr2 = integer_1(); 322 | } else { 323 | const struct UntypedExpr u = parse_expression(&tokvec); 324 | expr2 = typecheck_expression(ptr_ps, &u); 325 | } 326 | expect_scalar(&expr2.details.type, "`for` statement"); 327 | expect_and_consume(&tokvec, SEMICOLON, "second semicolon of `for`"); 328 | 329 | if (tokvec[0].kind == RIGHT_PAREN) { /* expression3 is missing */ 330 | expr3 = integer_1(); 331 | } else { 332 | const struct UntypedExpr u = parse_expression(&tokvec); 333 | expr3 = typecheck_expression(ptr_ps, &u); 334 | } 335 | expect_and_consume(&tokvec, RIGHT_PAREN, "right parenthesis of `for`"); 336 | struct Statement s; 337 | s.labels = init_vector(); 338 | s.category = FOR_STATEMENT; 339 | s.expr1 = expr1; 340 | s.expr2 = expr2; 341 | s.expr3 = expr3; 342 | 343 | struct Statement inner_s = parse_statement(ptr_ps, &tokvec); 344 | *ptr_tokvec = tokvec; 345 | struct Statement *ptr_inner_s = calloc(1, sizeof(struct Statement)); 346 | *ptr_inner_s = inner_s; 347 | s.inner_statement = ptr_inner_s; 348 | 349 | struct Statement *ptr_s = calloc(1, sizeof(struct Statement)); 350 | *ptr_s = s; 351 | push_vector(&statement.statement_vector, ptr_s); 352 | 353 | /* block scope ends */ 354 | ptr_ps->scope_chain = current_table; 355 | return statement; 356 | } 357 | 358 | default: { 359 | const struct UntypedExpr uexpr = parse_expression(&tokvec); 360 | struct Expr expr = typecheck_expression(ptr_ps, &uexpr); 361 | 362 | expect_and_consume(&tokvec, SEMICOLON, "semicolon after an expression"); 363 | 364 | *ptr_tokvec = tokvec; 365 | 366 | struct Statement s; 367 | s.labels = init_vector(); 368 | s.category = EXPRESSION_STATEMENT; 369 | s.expr1 = expr; 370 | return s; 371 | } 372 | } 373 | } 374 | 375 | static struct Expr *declare_var_and_return_initializer( 376 | struct AnalyzerState *ptr_ps, const struct Type *ref_vartype, 377 | const char *str, const struct UntypedExpr *ptr_uexpr, 378 | struct Statement *ptr_statement) 379 | { 380 | const struct Type vartype = *ref_vartype; 381 | add_local_var_to_scope(ptr_ps, ref_vartype, str); 382 | 383 | struct Statement s; 384 | s.category = DECLARATION_STATEMENT; 385 | s.declaration.type = vartype; 386 | s.declaration.ident_str = str; 387 | s.labels = init_vector(); 388 | struct Statement *ptr_s = calloc(1, sizeof(struct Statement)); 389 | *ptr_s = s; 390 | push_vector(&ptr_statement->statement_vector, ptr_s); 391 | 392 | struct Expr *ptr_expr = 0; 393 | if (ptr_uexpr) { /* initializer exists */ 394 | struct UntypedExpr left_uexpr; 395 | left_uexpr.category = VAR; 396 | left_uexpr.var_name = str; 397 | 398 | struct UntypedExpr uexpr = 399 | binary_op_untyped(&left_uexpr, ptr_uexpr, OP_EQ); 400 | struct Expr expr = typecheck_expression(ptr_ps, &uexpr); 401 | ptr_expr = calloc(1, sizeof(struct Expr)); 402 | *ptr_expr = expr; 403 | } 404 | return ptr_expr; 405 | } 406 | 407 | struct Statement parse_compound_statement(struct AnalyzerState *ptr_ps, 408 | const struct Token **ptr_tokvec) 409 | { 410 | const struct Token *tokvec = *ptr_tokvec; 411 | struct Statement statement; 412 | statement.category = COMPOUND_STATEMENT; 413 | statement.labels = init_vector(); 414 | statement.statement_vector = init_vector(); 415 | if (tokvec[0].kind == LEFT_BRACE) { 416 | 417 | struct ScopeChain current_table = ptr_ps->scope_chain; 418 | 419 | struct ScopeChain new_table; 420 | new_table.var_table = init_map(); 421 | 422 | /* current_table disappears at the end of this function, 423 | but there is no problem because new_table itself gets overwritten at 424 | the end of this function. 425 | */ 426 | new_table.outer = ¤t_table; 427 | 428 | ptr_ps->scope_chain = new_table; 429 | 430 | ++tokvec; 431 | *ptr_tokvec = tokvec; 432 | while (1) { 433 | if (tokvec[0].kind == RIGHT_BRACE) { 434 | ++tokvec; 435 | *ptr_tokvec = tokvec; 436 | ptr_ps->scope_chain = current_table; 437 | 438 | return statement; 439 | } else if (can_start_a_type(tokvec)) { 440 | struct Type *optional_ptr_type = 441 | try_parse_type_specifier_and_semicolon(&tokvec); 442 | if (optional_ptr_type) { 443 | struct Statement s; 444 | s.category = DECLARATION_STATEMENT; 445 | s.declaration.type = *optional_ptr_type; 446 | s.declaration.ident_str = 0; 447 | s.labels = init_vector(); /* must initialize this, since it 448 | is used in goto traversal */ 449 | struct Statement *ptr_s = 450 | calloc(1, sizeof(struct Statement)); 451 | *ptr_s = s; 452 | push_vector(&statement.statement_vector, ptr_s); 453 | continue; 454 | } 455 | 456 | const char *str; 457 | struct UntypedExpr *ptr_uexpr; 458 | const struct Type vartype = 459 | parse_declaration(&tokvec, &str, &ptr_uexpr); 460 | 461 | /* while function prototypes are also allowed here in C, I will 462 | * not implement it here */ 463 | if (vartype.type_category == FN) { 464 | unsupported( 465 | "declaring a function inside a compound statement\n"); 466 | exit(EXIT_FAILURE); 467 | } 468 | 469 | struct Expr *ptr_expr = declare_var_and_return_initializer( 470 | ptr_ps, &vartype, str, ptr_uexpr, &statement); 471 | 472 | if (ptr_expr) { 473 | struct Statement assignment; 474 | assignment.category = EXPRESSION_STATEMENT; 475 | assignment.expr1 = *ptr_expr; 476 | assignment.labels = init_vector(); 477 | struct Statement *ptr_s = 478 | calloc(1, sizeof(struct Statement)); 479 | *ptr_s = assignment; 480 | push_vector(&statement.statement_vector, ptr_s); 481 | } 482 | 483 | } else { 484 | struct Statement s = parse_statement(ptr_ps, &tokvec); 485 | struct Statement *ptr_s = calloc(1, sizeof(struct Statement)); 486 | *ptr_s = s; 487 | push_vector(&statement.statement_vector, ptr_s); 488 | } 489 | } 490 | } else { 491 | fprintf(stderr, 492 | "****************************\n" 493 | "* INTERNAL COMPILER ERROR @ %s\n" 494 | "* Unexpected value: `tokvec[0].kind` != `LEFT_BRACE` (which " 495 | "is %d), and is instead %d\n\n" 496 | "****************************\n", 497 | __func__, LEFT_BRACE, tokvec[0].kind); 498 | exit(EXIT_FAILURE); 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /parse_analyze_toplevel.c: -------------------------------------------------------------------------------- 1 | #include "global_flags.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | #include "toplevel.h" 5 | 6 | int size_of(const struct AnalyzerState *ptr_ps, const struct Type *ref_type) 7 | { 8 | const struct Type type = *ref_type; 9 | switch (type.type_category) { 10 | case INT_: 11 | return 4; 12 | case PTR_: 13 | return 8; 14 | case CHAR_: 15 | return 1; 16 | case ARRAY: 17 | return type.array_length * size_of(ptr_ps, type.derived_from); 18 | case FN: 19 | fprintf(stderr, "function type does not have a size\n"); 20 | exit(EXIT_FAILURE); 21 | case STRUCT_NOT_UNION: 22 | case UNION: 23 | if ((0)) { /* is local struct/union */ 24 | unsupported("struct/union type declared locally"); 25 | } 26 | const char *tag = type.s.struct_or_union_tag; 27 | const struct StructOrUnionInternalCompleteInfo *ptr_info = 28 | lookup(ptr_ps->global_struct_or_union_tag_map, tag); 29 | if (!ptr_info) { 30 | fprintf(stderr, "tried to take the size of an incomplete type `"); 31 | debug_print_type(&type); 32 | fprintf(stderr, "`\n"); 33 | exit(EXIT_FAILURE); 34 | } 35 | return ptr_info->s_and_a.size; 36 | case VOID_: 37 | fprintf(stderr, "the size of type `void` is never known\n"); 38 | exit(EXIT_FAILURE); 39 | case ENUM_: 40 | return 4; 41 | } 42 | 43 | fprintf(stderr, 44 | "****************************\n" 45 | "* INTERNAL COMPILER ERROR @ %s\n" 46 | "* Unexpected value of TypeCategory: `type.type_category` is `%d`\n" 47 | "****************************\n", 48 | __func__, type.type_category); 49 | exit(EXIT_FAILURE); 50 | } 51 | 52 | int align_of(const struct AnalyzerState *ptr_ps, const struct Type *ref_type) 53 | { 54 | const struct Type type = *ref_type; 55 | switch (type.type_category) { 56 | case INT_: 57 | return 4; 58 | case PTR_: 59 | return 8; 60 | case CHAR_: 61 | return 1; 62 | case ARRAY: 63 | return align_of(ptr_ps, type.derived_from); 64 | case FN: 65 | fprintf(stderr, 66 | "a function type does not have a size or an alignment\n"); 67 | exit(EXIT_FAILURE); 68 | case STRUCT_NOT_UNION: 69 | case UNION: 70 | if ((0)) { /* is local struct/union */ 71 | unsupported("struct/union type declared locally"); 72 | } 73 | const char *tag = type.s.struct_or_union_tag; 74 | const struct StructOrUnionInternalCompleteInfo *ptr_info = 75 | lookup(ptr_ps->global_struct_or_union_tag_map, tag); 76 | if (!ptr_info) { 77 | fprintf(stderr, 78 | "tried to find the alignment of an incomplete type `"); 79 | debug_print_type(&type); 80 | fprintf(stderr, "`\n"); 81 | exit(EXIT_FAILURE); 82 | } 83 | return ptr_info->s_and_a.alignment; 84 | case VOID_: 85 | fprintf(stderr, "cannot get alignment of `void`\n"); 86 | exit(EXIT_FAILURE); 87 | case ENUM_: 88 | return 4; 89 | } 90 | 91 | fprintf(stderr, 92 | "****************************\n" 93 | "* INTERNAL COMPILER ERROR @ %s\n" 94 | "* Unexpected value of TypeCategory: `type.type_category` is `%d`\n" 95 | "****************************\n", 96 | __func__, type.type_category); 97 | exit(EXIT_FAILURE); 98 | } 99 | 100 | enum SystemVAbiClass system_v_abi_class_of(const struct AnalyzerState *ptr_ps, 101 | const struct Type *ref_type) 102 | { 103 | const struct Type type = *ref_type; 104 | switch (type.type_category) { 105 | case INT_: 106 | case PTR_: 107 | case CHAR_: 108 | case ARRAY: 109 | case ENUM_: 110 | return INTEGER_CLASS; 111 | case FN: 112 | fprintf(stderr, "function type does not have System V ABI class\n"); 113 | exit(EXIT_FAILURE); 114 | case VOID_: 115 | fprintf(stderr, "type `void` does not have System V ABI class\n"); 116 | exit(EXIT_FAILURE); 117 | case STRUCT_NOT_UNION: 118 | case UNION: 119 | if ((0)) { /* is local struct/union */ 120 | unsupported("struct/union type declared locally"); 121 | } 122 | const char *tag = type.s.struct_or_union_tag; 123 | const struct StructOrUnionInternalCompleteInfo *ptr_info = 124 | lookup(ptr_ps->global_struct_or_union_tag_map, tag); 125 | if (!ptr_info) { 126 | fprintf( 127 | stderr, 128 | "tried to find the System V ABI class of incomplete type `"); 129 | debug_print_type(&type); 130 | fprintf(stderr, "`\n"); 131 | exit(EXIT_FAILURE); 132 | } 133 | 134 | if (size_of(ptr_ps, &type) > 2 * 8) { 135 | return MEMORY_CLASS; 136 | } 137 | return INTEGER_CLASS; 138 | } 139 | 140 | fprintf(stderr, 141 | "****************************\n" 142 | "* INTERNAL COMPILER ERROR @ %s\n" 143 | "* Unexpected value of TypeCategory: `type.type_category` is `%d`\n" 144 | "****************************\n", 145 | __func__, type.type_category); 146 | exit(EXIT_FAILURE); 147 | } 148 | 149 | static void record_global_struct_or_union_declaration( 150 | struct AnalyzerState *ptr_ps, const struct Type *ref_struct_or_union_type) 151 | { 152 | const struct Type struct_or_union_type = *ref_struct_or_union_type; 153 | assert(is_struct_or_union(&struct_or_union_type)); 154 | struct StructInternalInfo info = 155 | struct_or_union_type.s.struct_or_union_info; 156 | if (!info.ptr_types_and_idents) { /* null; incomplete type */ 157 | return; 158 | } 159 | struct Vector /* */ types_and_idents = 160 | *info.ptr_types_and_idents; 161 | 162 | struct SizeAndAlignment *inner_type_vec = 163 | calloc(types_and_idents.length, sizeof(struct SizeAndAlignment)); 164 | 165 | int i = 0; 166 | for (; i < types_and_idents.length; i++) { 167 | const struct TypeAndIdent *ptr_vec_i = types_and_idents.vector[i]; 168 | inner_type_vec[i].size = size_of(ptr_ps, &ptr_vec_i->type); 169 | inner_type_vec[i].alignment = align_of(ptr_ps, &ptr_vec_i->type); 170 | } 171 | 172 | int *offset_vec; 173 | 174 | struct SizeAndAlignment (*f)(const struct SizeAndAlignment *inner_type_vec, 175 | int **ptr_offset_vec, int length) = 176 | struct_or_union_type.type_category == STRUCT_NOT_UNION 177 | ? get_size_alignment_offsets_for_struct_not_union 178 | : get_size_alignment_offsets_for_union; 179 | 180 | struct SizeAndAlignment outer_s_and_a = f(inner_type_vec, &offset_vec, i); 181 | 182 | struct StructOrUnionInternalCompleteInfo *ptr_complete = 183 | calloc(1, sizeof(struct StructOrUnionInternalCompleteInfo)); 184 | ptr_complete->info = info; 185 | ptr_complete->offset_vec = offset_vec; 186 | ptr_complete->s_and_a = outer_s_and_a; 187 | 188 | insert(ptr_ps->global_struct_or_union_tag_map, 189 | struct_or_union_type.s.struct_or_union_tag, ptr_complete); 190 | } 191 | 192 | static void record_global_enum_declaration(struct AnalyzerState *ptr_ps, 193 | const struct Type *ref_type) 194 | { 195 | const struct Type type = *ref_type; 196 | assert(type.type_category == ENUM_); 197 | 198 | struct Enumerators info = type.e.enum_info; 199 | if (!info.ptr_enumerators) { /* null; cannot record */ 200 | return; 201 | } 202 | struct Vector /* */ idents = *info.ptr_enumerators; 203 | 204 | struct Vector /**/ *ptr_e_and_v_vec = init_vector_(); 205 | for (int i = 0; i < idents.length; i++) { 206 | const char *vec_i = idents.vector[i]; 207 | struct EnumeratorAndValue *ptr_e_and_v = 208 | calloc(1, sizeof(struct EnumeratorAndValue)); 209 | ptr_e_and_v->ident = vec_i; 210 | ptr_e_and_v->value = i; 211 | push_vector(ptr_e_and_v_vec, ptr_e_and_v); 212 | } 213 | 214 | concat_vector(&ptr_ps->global_enumerator_list, ptr_e_and_v_vec); 215 | 216 | insert(ptr_ps->global_enum_tag_map, type.e.enum_tag, ptr_e_and_v_vec); 217 | } 218 | 219 | static void 220 | record_if_global_struct_or_enum_declaration(struct AnalyzerState *ptr_ps, 221 | const struct Type *ref_type) 222 | { 223 | switch (ref_type->type_category) { 224 | case ARRAY: 225 | case FN: 226 | case PTR_: 227 | record_if_global_struct_or_enum_declaration(ptr_ps, 228 | ref_type->derived_from); 229 | return; 230 | case VOID_: 231 | case INT_: 232 | case CHAR_: 233 | return; 234 | case STRUCT_NOT_UNION: 235 | case UNION: 236 | record_global_struct_or_union_declaration(ptr_ps, ref_type); 237 | return; 238 | case ENUM_: 239 | record_global_enum_declaration(ptr_ps, ref_type); 240 | return; 241 | } 242 | 243 | fprintf(stderr, 244 | "****************************\n" 245 | "* INTERNAL COMPILER ERROR @ %s\n" 246 | "* Unexpected value of TypeCategory: `ref_type->type_category` is " 247 | "`%d`\n" 248 | "****************************\n", 249 | __func__, ref_type->type_category); 250 | exit(EXIT_FAILURE); 251 | } 252 | 253 | static int 254 | push_offset_and_type(struct AnalyzerState *ptr_ps, const struct Type *ref_type, 255 | struct Vector /**/ *ptr_offsets_and_types, 256 | const char *ident_str); 257 | 258 | static struct Toplevel 259 | parse_toplevel_definition(struct AnalyzerState *ptr_ps, 260 | const struct Token **ptr_tokvec) 261 | { 262 | const struct Token *tokvec2 = *ptr_tokvec; 263 | 264 | int is_extern_global_var = 0; 265 | if (tokvec2[0].kind == RES_EXTERN) { 266 | tokvec2++; 267 | is_extern_global_var = 1; 268 | } 269 | 270 | int is_static_function = 0; 271 | if (tokvec2[0].kind == RES_STATIC) { 272 | tokvec2++; 273 | is_static_function = 1; 274 | } 275 | 276 | *ptr_tokvec = tokvec2; 277 | 278 | struct Type *optional_ptr_type = 279 | try_parse_type_specifier_and_semicolon(ptr_tokvec); 280 | 281 | if (optional_ptr_type) { 282 | struct Toplevel d; 283 | d.category = TOPLEVEL_VAR_DEFINITION; 284 | d.declarator_type = *optional_ptr_type; 285 | /* d.size_of_declarator_type need not be set; it is not a real variable 286 | */ 287 | 288 | record_if_global_struct_or_enum_declaration(ptr_ps, &d.declarator_type); 289 | d.declarator_name = 0; 290 | return d; 291 | } 292 | 293 | const char *declarator_name; 294 | struct Type declarator_type = 295 | parse_type_specifier_and_declarator(&tokvec2, &declarator_name); 296 | record_if_global_struct_or_enum_declaration(ptr_ps, &declarator_type); 297 | 298 | if (declarator_type.type_category != FN) { 299 | 300 | expect_and_consume(&tokvec2, SEMICOLON, 301 | "semicolon at the end of variable definition"); 302 | 303 | struct Type *ptr_type = calloc(1, sizeof(struct Type)); 304 | *ptr_type = declarator_type; 305 | insert(ptr_ps->global_vars_type_map, declarator_name, ptr_type); 306 | 307 | *ptr_tokvec = tokvec2; 308 | 309 | struct Toplevel d; 310 | d.category = TOPLEVEL_VAR_DEFINITION; 311 | d.declarator_name = declarator_name; 312 | d.declarator_type = declarator_type; 313 | d.size_of_declarator_type = size_of(ptr_ps, &declarator_type); 314 | d.is_extern_global_var = is_extern_global_var; 315 | return d; 316 | } 317 | 318 | struct Vector /**/ param_infos = declarator_type.param_infos; 319 | enum ParamInfosValidity param_infos_validity = 320 | declarator_type.param_infos_validity; 321 | struct Type *derived_from = declarator_type.derived_from; 322 | struct Type ret_type = *derived_from; 323 | 324 | ptr_ps->scope_chain.outer = 0; /* most outer scope */ 325 | ptr_ps->scope_chain.var_table = init_map(); 326 | ptr_ps->newest_offset = 0; 327 | ptr_ps->func_ret_type = ret_type; 328 | ptr_ps->current_function_name = declarator_name; 329 | 330 | const struct Type *ptr_old_func_info = 331 | lookup(ptr_ps->func_info_map, declarator_name); 332 | 333 | struct Type *ptr_func_info = calloc(1, sizeof(struct Type)); 334 | *ptr_func_info = declarator_type; 335 | 336 | if (!ptr_old_func_info) { 337 | insert(ptr_ps->func_info_map, declarator_name, ptr_func_info); 338 | } else { 339 | expect_type(ptr_ps, &declarator_type, ptr_old_func_info, 340 | "conflicting function definition"); 341 | if (ptr_old_func_info->param_infos_validity == INVALID && 342 | declarator_type.param_infos_validity != INVALID) { 343 | insert(ptr_ps->func_info_map, declarator_name, ptr_func_info); 344 | } 345 | } 346 | 347 | if (tokvec2[0].kind == SEMICOLON) { /* function prototype */ 348 | ++tokvec2; 349 | *ptr_tokvec = tokvec2; 350 | 351 | struct Toplevel def; 352 | def.category = TOPLEVEL_FUNCTION_DECLARATION; 353 | return def; 354 | } 355 | 356 | struct Vector /**/ offsets_and_types = init_vector(); 357 | 358 | struct Toplevel def; 359 | def.category = TOPLEVEL_FUNCTION_DEFINITION; 360 | def.declarator_name = declarator_name; 361 | def.func.is_static_function = is_static_function; 362 | def.func.ret_type = ret_type; 363 | if (is_struct_or_union(&ret_type)) { 364 | enum SystemVAbiClass abi_class = 365 | system_v_abi_class_of(ptr_ps, &ret_type); 366 | def.func.abi_class = abi_class; 367 | def.func.ret_struct_or_union_size = size_of(ptr_ps, &ret_type); 368 | if (abi_class == MEMORY_CLASS) { 369 | const struct Type type = ptr_to_type(&ret_type); 370 | int hidden_var_offset = push_offset_and_type( 371 | ptr_ps, &type, &offsets_and_types, "@hidden"); 372 | def.func.hidden_var_offset = hidden_var_offset; 373 | } 374 | } 375 | 376 | def.func.is_va = 0; 377 | switch (param_infos_validity) { 378 | case VALID: 379 | case VA_ARGS: { 380 | for (int counter = 0; counter < param_infos.length; ++counter) { 381 | 382 | const struct TypeAndIdent *ptr_param_info = 383 | param_infos.vector[counter]; 384 | struct TypeAndIdent param_info = *ptr_param_info; 385 | const struct Type type = param_info.type; 386 | 387 | if (counter > 5) { /* silently fails when there is 6 params and 388 | 1 implicit param*/ 389 | unsupported("7-or-more parameters"); 390 | } 391 | 392 | push_offset_and_type(ptr_ps, &type, &offsets_and_types, 393 | param_info.ident_str); 394 | } 395 | 396 | if (param_infos_validity == VA_ARGS) { 397 | def.func.is_va = 1; 398 | } 399 | break; 400 | } 401 | 402 | case INVALID: 403 | break; 404 | } 405 | 406 | struct Statement sta = parse_compound_statement(ptr_ps, &tokvec2); 407 | *ptr_tokvec = tokvec2; 408 | /* parse finished */ 409 | 410 | def.func.sta = sta; 411 | def.func.offsets_and_types = offsets_and_types; 412 | def.func.capacity = -ptr_ps->newest_offset; 413 | return def; 414 | } 415 | 416 | static int 417 | push_offset_and_type(struct AnalyzerState *ptr_ps, const struct Type *ref_type, 418 | struct Vector /**/ *ptr_offsets_and_types, 419 | const char *ident_str) 420 | { 421 | 422 | int offset = add_local_var_to_scope(ptr_ps, ref_type, ident_str); 423 | 424 | struct LocalVarInfo info; 425 | info.offset = offset; 426 | info.type = *ref_type; 427 | 428 | struct LocalVarInfo *ptr1 = calloc(1, sizeof(struct LocalVarInfo)); 429 | *ptr1 = info; 430 | push_vector(ptr_offsets_and_types, ptr1); 431 | 432 | return offset; 433 | } 434 | 435 | struct Vector /**/ parse(const struct Token *tokvec) 436 | { 437 | struct AnalyzerState ps; 438 | ps.func_info_map = init_map(); 439 | ps.global_vars_type_map = init_map(); 440 | ps.global_struct_or_union_tag_map = init_map(); 441 | ps.global_enum_tag_map = init_map(); 442 | ps.global_enumerator_list = init_vector(); 443 | 444 | struct Vector /**/ vec = init_vector(); 445 | while (1) { 446 | if (tokvec[0].kind == END) { 447 | expect_and_consume(&tokvec, END, "the end of file"); 448 | break; 449 | } else if (tokvec[0].kind == SEMICOLON) { 450 | if (global_flag_pedantic) { 451 | // gcc 12.1 with `-pedantic` flag gives out `warning: ISO C does 452 | // not allow extra ';' outside of a function`. 453 | fprintf(stderr, 454 | "ISO C forbids an extra ';' outside of a function\n"); 455 | exit(EXIT_FAILURE); 456 | } else { 457 | expect_and_consume(&tokvec, SEMICOLON, "extra ';' outside of a function\n"); 458 | } 459 | } else { 460 | struct Toplevel *ptr = calloc(1, sizeof(struct Toplevel)); 461 | *ptr = parse_toplevel_definition(&ps, &tokvec); 462 | push_vector(&vec, ptr); 463 | } 464 | } 465 | return vec; 466 | } 467 | -------------------------------------------------------------------------------- /parse_expression.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | static struct UntypedExpr 5 | parse_unary_expression(const struct Token **ptr_tokvec); 6 | static struct UntypedExpr 7 | parse_conditional_expression(const struct Token **ptr_tokvec); 8 | static struct UntypedExpr 9 | parse_logical_OR_expression(const struct Token **ptr_tokvec); 10 | static struct UntypedExpr parse_AND_expression(const struct Token **ptr_tokvec); 11 | static struct UntypedExpr 12 | parse_exclusive_OR_expression(const struct Token **ptr_tokvec); 13 | static struct UntypedExpr 14 | parse_equality_expression(const struct Token **ptr_tokvec); 15 | static struct UntypedExpr 16 | parse_postfix_expression(const struct Token **ptr_tokvec); 17 | static struct UntypedExpr 18 | parse_primary_expression(const struct Token **ptr_tokvec); 19 | 20 | struct UntypedExpr binary_op_untyped(const struct UntypedExpr *ref_expr, 21 | const struct UntypedExpr *ref_expr2, 22 | enum TokenKind kind) 23 | { 24 | struct UntypedExpr *ptr_expr1 = calloc(1, sizeof(struct UntypedExpr)); 25 | struct UntypedExpr *ptr_expr2 = calloc(1, sizeof(struct UntypedExpr)); 26 | *ptr_expr1 = *ref_expr; 27 | *ptr_expr2 = *ref_expr2; 28 | 29 | struct UntypedExpr new_expr; 30 | new_expr.category = BINARY_EXPR; 31 | new_expr.operator_ = kind; 32 | new_expr.ptr1 = ptr_expr1; 33 | new_expr.ptr2 = ptr_expr2; 34 | new_expr.ptr3 = 0; 35 | 36 | return new_expr; 37 | } 38 | 39 | static struct UntypedExpr 40 | parse_inclusive_OR_expression(const struct Token **ptr_tokvec) 41 | { 42 | const struct Token *tokvec = *ptr_tokvec; 43 | 44 | struct UntypedExpr expr = parse_exclusive_OR_expression(&tokvec); 45 | 46 | while (1) { 47 | enum TokenKind kind = tokvec[0].kind; 48 | if (kind != OP_OR) { 49 | break; 50 | } 51 | ++tokvec; 52 | 53 | const struct UntypedExpr expr2 = parse_exclusive_OR_expression(&tokvec); 54 | expr = binary_op_untyped(&expr, &expr2, kind); 55 | } 56 | *ptr_tokvec = tokvec; 57 | return expr; 58 | } 59 | 60 | static struct UntypedExpr 61 | parse_exclusive_OR_expression(const struct Token **ptr_tokvec) 62 | { 63 | const struct Token *tokvec = *ptr_tokvec; 64 | 65 | struct UntypedExpr expr = parse_AND_expression(&tokvec); 66 | 67 | while (1) { 68 | enum TokenKind kind = tokvec[0].kind; 69 | if (kind != OP_HAT) { 70 | break; 71 | } 72 | ++tokvec; 73 | 74 | const struct UntypedExpr expr2 = parse_AND_expression(&tokvec); 75 | expr = binary_op_untyped(&expr, &expr2, kind); 76 | } 77 | *ptr_tokvec = tokvec; 78 | 79 | return expr; 80 | } 81 | 82 | static struct UntypedExpr parse_AND_expression(const struct Token **ptr_tokvec) 83 | { 84 | const struct Token *tokvec = *ptr_tokvec; 85 | 86 | struct UntypedExpr expr = parse_equality_expression(&tokvec); 87 | 88 | while (1) { 89 | enum TokenKind kind = tokvec[0].kind; 90 | if (kind != OP_AND) { 91 | break; 92 | } 93 | ++tokvec; 94 | 95 | struct UntypedExpr expr2 = parse_equality_expression(&tokvec); 96 | expr = binary_op_untyped(&expr, &expr2, kind); 97 | } 98 | *ptr_tokvec = tokvec; 99 | 100 | return expr; 101 | } 102 | 103 | static struct UntypedExpr parse_cast_expression(const struct Token **ptr_tokvec) 104 | { 105 | return parse_unary_expression(ptr_tokvec); 106 | } 107 | 108 | static struct UntypedExpr 109 | parse_multiplicative_expression(const struct Token **ptr_tokvec) 110 | { 111 | const struct Token *tokvec = *ptr_tokvec; 112 | struct UntypedExpr expr = parse_cast_expression(&tokvec); 113 | 114 | while (1) { 115 | enum TokenKind kind = tokvec[0].kind; 116 | if (kind != OP_ASTERISK && kind != OP_SLASH && kind != OP_PERCENT) { 117 | break; 118 | } 119 | ++tokvec; 120 | 121 | struct UntypedExpr expr2 = parse_cast_expression(&tokvec); 122 | 123 | expr = binary_op_untyped(&expr, &expr2, kind); 124 | } 125 | *ptr_tokvec = tokvec; 126 | return expr; 127 | } 128 | 129 | static struct UntypedExpr 130 | parse_additive_expression(const struct Token **ptr_tokvec) 131 | { 132 | const struct Token *tokvec = *ptr_tokvec; 133 | struct UntypedExpr expr = parse_multiplicative_expression(&tokvec); 134 | 135 | while (1) { 136 | enum TokenKind kind = tokvec[0].kind; 137 | if (kind != OP_PLUS && kind != OP_MINUS) { 138 | break; 139 | } 140 | ++tokvec; 141 | 142 | struct UntypedExpr expr2 = parse_multiplicative_expression(&tokvec); 143 | expr = binary_op_untyped(&expr, &expr2, kind); 144 | } 145 | *ptr_tokvec = tokvec; 146 | return expr; 147 | } 148 | 149 | static struct UntypedExpr 150 | parse_shift_expression(const struct Token **ptr_tokvec) 151 | { 152 | const struct Token *tokvec = *ptr_tokvec; 153 | struct UntypedExpr expr = parse_additive_expression(&tokvec); 154 | 155 | while (1) { 156 | enum TokenKind kind = tokvec[0].kind; 157 | if (kind != OP_LSHIFT && kind != OP_RSHIFT) { 158 | break; 159 | } 160 | ++tokvec; 161 | 162 | struct UntypedExpr expr2 = parse_additive_expression(&tokvec); 163 | expr = binary_op_untyped(&expr, &expr2, kind); 164 | } 165 | *ptr_tokvec = tokvec; 166 | return expr; 167 | } 168 | 169 | static struct UntypedExpr 170 | parse_relational_expression(const struct Token **ptr_tokvec) 171 | { 172 | const struct Token *tokvec = *ptr_tokvec; 173 | 174 | struct UntypedExpr expr = parse_shift_expression(&tokvec); 175 | 176 | while (1) { 177 | enum TokenKind kind = tokvec[0].kind; 178 | if (kind != OP_GT && kind != OP_GT_EQ && kind != OP_LT && 179 | kind != OP_LT_EQ) { 180 | break; 181 | } 182 | ++tokvec; 183 | 184 | struct UntypedExpr expr2 = parse_shift_expression(&tokvec); 185 | expr = binary_op_untyped(&expr, &expr2, kind); 186 | } 187 | *ptr_tokvec = tokvec; 188 | return expr; 189 | } 190 | 191 | static struct UntypedExpr 192 | parse_equality_expression(const struct Token **ptr_tokvec) 193 | { 194 | const struct Token *tokvec = *ptr_tokvec; 195 | struct UntypedExpr expr = parse_relational_expression(&tokvec); 196 | 197 | while (1) { 198 | enum TokenKind kind = tokvec[0].kind; 199 | if (kind != OP_EQ_EQ && kind != OP_NOT_EQ) { 200 | break; 201 | } 202 | ++tokvec; 203 | 204 | struct UntypedExpr expr2 = parse_relational_expression(&tokvec); 205 | expr = binary_op_untyped(&expr, &expr2, kind); 206 | } 207 | *ptr_tokvec = tokvec; 208 | return expr; 209 | } 210 | 211 | static struct UntypedExpr 212 | parse_logical_AND_expression(const struct Token **ptr_tokvec) 213 | { 214 | const struct Token *tokvec = *ptr_tokvec; 215 | 216 | struct UntypedExpr first_expr = parse_inclusive_OR_expression(&tokvec); 217 | 218 | while (1) { 219 | enum TokenKind kind = tokvec[0].kind; 220 | if (kind != OP_AND_AND) { 221 | break; 222 | } 223 | 224 | ++tokvec; 225 | 226 | struct UntypedExpr expr2 = parse_inclusive_OR_expression(&tokvec); 227 | 228 | first_expr = binary_op_untyped(&first_expr, &expr2, OP_AND_AND); 229 | } 230 | 231 | *ptr_tokvec = tokvec; 232 | return first_expr; 233 | } 234 | 235 | static struct UntypedExpr 236 | parse_logical_OR_expression(const struct Token **ptr_tokvec) 237 | { 238 | const struct Token *tokvec = *ptr_tokvec; 239 | 240 | struct UntypedExpr expr = parse_logical_AND_expression(&tokvec); 241 | 242 | while (1) { 243 | enum TokenKind kind = tokvec[0].kind; 244 | if (kind != OP_OR_OR) { 245 | break; 246 | } 247 | 248 | ++tokvec; 249 | struct UntypedExpr expr2 = parse_logical_AND_expression(&tokvec); 250 | 251 | expr = binary_op_untyped(&expr, &expr2, OP_OR_OR); 252 | } 253 | 254 | *ptr_tokvec = tokvec; 255 | return expr; 256 | } 257 | 258 | static struct UntypedExpr unary_op_untyped(const struct UntypedExpr *ref_expr, 259 | enum TokenKind kind) 260 | { 261 | struct UntypedExpr *ptr_expr1 = calloc(1, sizeof(struct UntypedExpr)); 262 | *ptr_expr1 = *ref_expr; 263 | 264 | struct UntypedExpr new_expr; 265 | new_expr.category = UNARY_EXPR; 266 | new_expr.operator_ = kind; 267 | new_expr.ptr1 = ptr_expr1; 268 | new_expr.ptr2 = 0; 269 | new_expr.ptr3 = 0; 270 | 271 | return new_expr; 272 | } 273 | 274 | static struct UntypedExpr 275 | parse_unary_expression(const struct Token **ptr_tokvec) 276 | { 277 | const struct Token *tokvec = *ptr_tokvec; 278 | 279 | if (tokvec[0].kind == OP_NOT || tokvec[0].kind == OP_TILDA || 280 | tokvec[0].kind == OP_PLUS || tokvec[0].kind == OP_MINUS || 281 | tokvec[0].kind == OP_ASTERISK || tokvec[0].kind == OP_AND) { 282 | enum TokenKind kind = tokvec[0].kind; 283 | ++tokvec; 284 | 285 | const struct UntypedExpr expr = parse_cast_expression(&tokvec); 286 | 287 | const struct UntypedExpr new_expr = unary_op_untyped(&expr, kind); 288 | 289 | *ptr_tokvec = tokvec; 290 | return new_expr; 291 | } else if (tokvec[0].kind == RES_SIZEOF && tokvec[1].kind == LEFT_PAREN && 292 | can_start_a_type(tokvec + 2)) { 293 | tokvec += 2; 294 | struct Type type = parse_type_name(&tokvec); 295 | expect_and_consume(&tokvec, RIGHT_PAREN, 296 | "closing parenthesis of sizeof(typename)"); 297 | 298 | struct UntypedExpr expr; 299 | expr.category = SIZEOF_TYPE; 300 | expr.operand_of_sizeof_or_alignof = type; 301 | *ptr_tokvec = tokvec; 302 | return expr; 303 | } else if (tokvec[0].kind == OP_PLUS_PLUS || 304 | tokvec[0].kind == OP_MINUS_MINUS || 305 | tokvec[0].kind == RES_SIZEOF) { 306 | enum TokenKind opkind = tokvec[0].kind; 307 | ++tokvec; 308 | 309 | const struct UntypedExpr expr = parse_unary_expression(&tokvec); 310 | 311 | const struct UntypedExpr new_expr = unary_op_untyped(&expr, opkind); 312 | *ptr_tokvec = tokvec; 313 | return new_expr; 314 | } else if (tokvec[0].kind == RES_ALIGNOF && tokvec[1].kind == LEFT_PAREN) { 315 | tokvec += 2; 316 | if (!can_start_a_type(tokvec)) { 317 | fprintf(stderr, "_Alignof can only take type name\n"); 318 | exit(EXIT_FAILURE); 319 | } 320 | struct Type type = parse_type_name(&tokvec); 321 | expect_and_consume(&tokvec, RIGHT_PAREN, 322 | "closing parenthesis of _Alignof(typename)"); 323 | 324 | struct UntypedExpr expr; 325 | expr.category = ALIGNOF_TYPE; 326 | expr.operand_of_sizeof_or_alignof = type; 327 | *ptr_tokvec = tokvec; 328 | return expr; 329 | } else { 330 | 331 | struct UntypedExpr expr = parse_postfix_expression(&tokvec); 332 | *ptr_tokvec = tokvec; 333 | return expr; 334 | } 335 | } 336 | 337 | static struct UntypedExpr ampersand_dot(const struct UntypedExpr *ref_expr, 338 | const char *name); 339 | 340 | /* LPAREN is already consumed */ 341 | static struct Vector /**/ 342 | parse_arguments(const struct Token **ptr_tokvec) 343 | { 344 | const struct Token *tokvec = *ptr_tokvec; 345 | struct Vector /**/ arguments = init_vector(); 346 | 347 | if (tokvec[0].kind == RIGHT_PAREN) { 348 | tokvec++; 349 | } else { 350 | struct UntypedExpr e = parse_assignment_expression(&tokvec); 351 | struct UntypedExpr *ptr_e = calloc(1, sizeof(struct UntypedExpr)); 352 | *ptr_e = e; 353 | push_vector(&arguments, ptr_e); 354 | 355 | while (1) { 356 | enum TokenKind kind = tokvec[0].kind; 357 | if (kind != OP_COMMA) { 358 | break; 359 | } 360 | ++tokvec; 361 | 362 | struct UntypedExpr e2 = parse_assignment_expression(&tokvec); 363 | struct UntypedExpr *ptr_e2 = calloc(1, sizeof(struct UntypedExpr)); 364 | *ptr_e2 = e2; 365 | push_vector(&arguments, ptr_e2); 366 | } 367 | 368 | expect_and_consume(&tokvec, RIGHT_PAREN, 369 | "closing parenthesis of function call"); 370 | } 371 | *ptr_tokvec = tokvec; 372 | return arguments; 373 | } 374 | 375 | static struct UntypedExpr 376 | parse_postfix_expression(const struct Token **ptr_tokvec) 377 | { 378 | const struct Token *tokvec = *ptr_tokvec; 379 | 380 | struct UntypedExpr expr; 381 | if (tokvec[0].kind == IDENT_OR_RESERVED && tokvec[1].kind == LEFT_PAREN) { 382 | const char *ident_str = tokvec[0].ident_str; 383 | 384 | tokvec += 2; 385 | 386 | struct Vector /**/ arguments = parse_arguments(&tokvec); 387 | 388 | if (strncmp("__builtin", ident_str, strlen("__builtin")) == 0) { 389 | expr.category = BUILTIN_FUNCCALL; 390 | } else { 391 | expr.category = 392 | FUNCCALL; /* later gets treated as FUNC_PTR_CALL if fp */ 393 | } 394 | 395 | expr.arg_exprs_vec = arguments; 396 | expr.var_name = ident_str; 397 | } else { 398 | expr = parse_primary_expression(&tokvec); 399 | } 400 | 401 | while (1) { 402 | if (tokvec[0].kind == LEFT_PAREN) { 403 | tokvec++; 404 | 405 | /* this consumes the closing paren */ 406 | struct Vector /**/ arguments = 407 | parse_arguments(&tokvec); 408 | 409 | struct UntypedExpr *ptr_expr1 = 410 | calloc(1, sizeof(struct UntypedExpr)); 411 | *ptr_expr1 = expr; 412 | 413 | struct UntypedExpr new_expr; 414 | new_expr.category = FUNC_PTR_CALL; 415 | new_expr.arg_exprs_vec = arguments; 416 | new_expr.ptr1 = ptr_expr1; 417 | 418 | expr = new_expr; 419 | } else if (tokvec[0].kind == LEFT_BRACKET) { 420 | ++tokvec; 421 | const struct UntypedExpr expr2 = parse_expression(&tokvec); 422 | expect_and_consume(&tokvec, RIGHT_BRACKET, "right bracket ]"); 423 | 424 | const struct UntypedExpr e = 425 | binary_op_untyped(&expr, &expr2, OP_PLUS); 426 | expr = unary_op_untyped(&e, OP_ASTERISK); 427 | } else if (tokvec[0].kind == OP_PLUS_PLUS || 428 | tokvec[0].kind == OP_MINUS_MINUS) { 429 | enum TokenKind opkind = tokvec[0].kind; 430 | tokvec++; 431 | 432 | struct UntypedExpr *ptr_expr1 = 433 | calloc(1, sizeof(struct UntypedExpr)); 434 | *ptr_expr1 = expr; 435 | 436 | struct UntypedExpr new_expr; 437 | new_expr.operator_ = opkind; 438 | new_expr.category = POSTFIX_EXPR; 439 | new_expr.ptr1 = ptr_expr1; 440 | new_expr.ptr2 = 0; 441 | new_expr.ptr3 = 0; 442 | 443 | expr = new_expr; 444 | } else if (tokvec[0].kind == DOT) { 445 | ++tokvec; 446 | 447 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 448 | "identifier after a dot operator"); 449 | const char *name = tokvec[-1].ident_str; 450 | 451 | const struct UntypedExpr f = ampersand_dot(&expr, name); 452 | expr = unary_op_untyped(&f, OP_ASTERISK); 453 | } else if (tokvec[0].kind == ARROW) { 454 | ++tokvec; 455 | 456 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 457 | "identifier after an arrow operator"); 458 | const char *name = tokvec[-1].ident_str; 459 | 460 | const struct UntypedExpr e = unary_op_untyped(&expr, OP_ASTERISK); 461 | const struct UntypedExpr f = ampersand_dot(&e, name); 462 | expr = unary_op_untyped(&f, OP_ASTERISK); 463 | } else { 464 | break; 465 | } 466 | } 467 | *ptr_tokvec = tokvec; 468 | return expr; 469 | } 470 | 471 | /* generates `&s.a`. necessary to support an array as a member */ 472 | static struct UntypedExpr ampersand_dot(const struct UntypedExpr *ref_expr, 473 | const char *name) 474 | { 475 | struct UntypedExpr *ptr_expr1 = calloc(1, sizeof(struct UntypedExpr)); 476 | *ptr_expr1 = *ref_expr; 477 | 478 | struct UntypedExpr new_expr; 479 | new_expr.category = AMPERSAND_DOT; 480 | new_expr.ptr1 = ptr_expr1; 481 | new_expr.ptr2 = 0; 482 | new_expr.ptr3 = 0; 483 | new_expr.ident_after_dot = name; 484 | return new_expr; 485 | } 486 | 487 | static struct UntypedExpr 488 | parse_primary_expression(const struct Token **ptr_tokvec) 489 | { 490 | const struct Token *tokvec = *ptr_tokvec; 491 | if (tokvec[0].kind == LIT_DEC_INTEGER) { 492 | ++*ptr_tokvec; 493 | 494 | struct UntypedExpr expr; 495 | expr.int_value = tokvec[0].int_value; 496 | expr.category = INT_LITERAL_; 497 | 498 | return expr; 499 | 500 | } else if (tokvec[0].kind == IDENT_OR_RESERVED) { 501 | ++*ptr_tokvec; 502 | 503 | struct UntypedExpr expr; 504 | expr.category = VAR; 505 | expr.var_name = tokvec[0].ident_str; 506 | return expr; 507 | 508 | } else if (tokvec[0].kind == LEFT_PAREN) { 509 | ++tokvec; 510 | *ptr_tokvec = tokvec; 511 | struct UntypedExpr expr = parse_expression(&tokvec); 512 | expect_and_consume(&tokvec, RIGHT_PAREN, "right paren"); 513 | 514 | *ptr_tokvec = tokvec; 515 | return expr; 516 | } else if (tokvec[0].kind == LIT_STRING) { 517 | struct UntypedExpr expr; 518 | expr.category = STRING_LITERAL_; 519 | expr.literal_string = tokvec[0].literal_str; 520 | 521 | ++*ptr_tokvec; 522 | return expr; 523 | } 524 | 525 | error_unexpected_token( 526 | tokvec, "the beginning of parse_typecheck_primary_expression"); 527 | } 528 | 529 | struct UntypedExpr parse_assignment_expression(const struct Token **ptr_tokvec) 530 | { 531 | const struct Token *tokvec = *ptr_tokvec; 532 | 533 | const struct Token *tokvec2 = tokvec; 534 | struct UntypedExpr expr = parse_unary_expression(&tokvec2); 535 | 536 | /* parse failed */ 537 | if (!isAssign(tokvec2[0].kind)) { 538 | struct UntypedExpr expr_ = parse_conditional_expression(&tokvec); 539 | *ptr_tokvec = tokvec; 540 | return expr_; 541 | } 542 | 543 | tokvec = tokvec2; 544 | 545 | assert(isAssign(tokvec[0].kind)); 546 | enum TokenKind opkind = tokvec[0].kind; 547 | ++tokvec; 548 | 549 | const struct UntypedExpr expr2 = parse_assignment_expression(&tokvec); 550 | 551 | *ptr_tokvec = tokvec; 552 | return binary_op_untyped(&expr, &expr2, opkind); 553 | } 554 | 555 | static struct UntypedExpr 556 | parse_conditional_expression(const struct Token **ptr_tokvec) 557 | { 558 | const struct Token *tokvec = *ptr_tokvec; 559 | struct UntypedExpr expr = parse_logical_OR_expression(&tokvec); 560 | if (tokvec[0].kind == QUESTION) { 561 | 562 | ++tokvec; 563 | *ptr_tokvec = tokvec; 564 | struct UntypedExpr true_branch = parse_expression(&tokvec); 565 | 566 | expect_and_consume(&tokvec, COLON, "colon of the conditional operator"); 567 | 568 | *ptr_tokvec = tokvec; 569 | struct UntypedExpr false_branch = parse_conditional_expression(&tokvec); 570 | 571 | *ptr_tokvec = tokvec; 572 | 573 | struct UntypedExpr *ptr_expr1 = calloc(1, sizeof(struct UntypedExpr)); 574 | struct UntypedExpr *ptr_expr2 = calloc(1, sizeof(struct UntypedExpr)); 575 | struct UntypedExpr *ptr_expr3 = calloc(1, sizeof(struct UntypedExpr)); 576 | *ptr_expr1 = expr; 577 | *ptr_expr2 = true_branch; 578 | *ptr_expr3 = false_branch; 579 | 580 | struct UntypedExpr new_expr; 581 | new_expr.category = CONDITIONAL; 582 | new_expr.ptr1 = ptr_expr1; 583 | new_expr.ptr2 = ptr_expr2; 584 | new_expr.ptr3 = ptr_expr3; 585 | 586 | return new_expr; 587 | } 588 | *ptr_tokvec = tokvec; 589 | return expr; 590 | } 591 | 592 | struct UntypedExpr parse_constant_expression(const struct Token **ptr_tokvec) 593 | { 594 | return parse_conditional_expression(ptr_tokvec); 595 | } 596 | 597 | struct UntypedExpr parse_expression(const struct Token **ptr_tokvec) 598 | { 599 | const struct Token *tokvec = *ptr_tokvec; 600 | struct UntypedExpr expr = parse_assignment_expression(&tokvec); 601 | while (1) { 602 | enum TokenKind kind = tokvec[0].kind; 603 | if (kind != OP_COMMA) { 604 | break; 605 | } 606 | ++tokvec; 607 | 608 | const struct UntypedExpr expr2 = parse_assignment_expression(&tokvec); 609 | 610 | expr = binary_op_untyped(&expr, &expr2, kind); 611 | } 612 | *ptr_tokvec = tokvec; 613 | return expr; 614 | } 615 | -------------------------------------------------------------------------------- /parse_type.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | 5 | /*************************************** 6 | * pure parsers with respect to types. * 7 | ***************************************/ 8 | 9 | static void parse_declarator(const struct Token **ptr_tokvec, 10 | const char **ptr_to_ident_str, 11 | struct Vector /**/ *ptr_vec); 12 | 13 | static void skip_consts_or_noreturns(const struct Token **ptr_tokvec) 14 | { 15 | const struct Token *tokvec = *ptr_tokvec; 16 | while (tokvec[0].kind == RES_CONST || tokvec[0].kind == RES_NORETURN) { 17 | ++tokvec; 18 | } 19 | *ptr_tokvec = tokvec; 20 | return; 21 | } 22 | 23 | #define TypeNode Type 24 | /* struct TypeNode denotes that the link list is incomplete and should not be 25 | brought outside */ 26 | 27 | static struct Type from_type3_to_type(const void **type3) 28 | { 29 | struct Type type; 30 | const struct TypeNode *ptr_elem = type3[0]; 31 | struct TypeNode elem = *ptr_elem; 32 | type = elem; 33 | switch (elem.type_category) { 34 | case INT_: 35 | case CHAR_: 36 | case STRUCT_NOT_UNION: 37 | case UNION: 38 | case VOID_: 39 | case ENUM_: 40 | return type; 41 | 42 | case PTR_: 43 | case ARRAY: 44 | case FN: { 45 | struct Type *ptr_to_current_type = calloc(1, sizeof(struct Type)); 46 | *ptr_to_current_type = from_type3_to_type(type3 + 1); 47 | 48 | type.derived_from = ptr_to_current_type; 49 | 50 | if (type.type_category == ARRAY && 51 | type.derived_from->type_category == FN) { 52 | fprintf(stderr, "It is illegal to declare an array of functions\n"); 53 | exit(EXIT_FAILURE); 54 | } else if (type.type_category == FN && 55 | type.derived_from->type_category == FN) { 56 | fprintf(stderr, 57 | "It is illegal for a function to return a function type\n"); 58 | exit(EXIT_FAILURE); 59 | } else if (type.type_category == FN && 60 | type.derived_from->type_category == ARRAY) { 61 | fprintf(stderr, 62 | "It is illegal for a function to return an array type\n"); 63 | exit(EXIT_FAILURE); 64 | } 65 | return type; 66 | } 67 | } 68 | fprintf(stderr, 69 | "****************************\n" 70 | "* INTERNAL COMPILER ERROR @ %s\n" 71 | "* Unexpected value of TypeCategory: `elem.type_category` is `%d`\n" 72 | "****************************\n", 73 | __func__, elem.type_category); 74 | exit(EXIT_FAILURE); 75 | } 76 | 77 | /* 78 | parameter-declaration: 79 | declaration-specifiers declarator 80 | declaration-specifiers abstract-declarator_opt 81 | */ 82 | struct TypeAndIdent * 83 | parse_parameter_declaration(const struct Token **ptr_tokvec) 84 | { 85 | const char *ident_str = 0; /* null when abstract */ 86 | struct TypeAndIdent *ptr_param_info = 87 | calloc(1, sizeof(struct TypeAndIdent)); 88 | 89 | struct Type type; 90 | { 91 | struct Type *ptr_base_type = parse_type_specifier(ptr_tokvec); 92 | struct Vector /**/ *ptr_vec = init_vector_(); 93 | if ((*ptr_tokvec)[0].kind == OP_COMMA || 94 | (*ptr_tokvec)[0].kind == RIGHT_PAREN) { 95 | /* comma or right paren signifies the immediate end of 96 | * parameter_declaration */ 97 | } else { 98 | parse_declarator(ptr_tokvec, &ident_str, ptr_vec); 99 | if ((0)) { 100 | unsupported("abstract-declarator inside parameter declaration"); 101 | } 102 | } 103 | push_vector(ptr_vec, ptr_base_type); 104 | type = from_type3_to_type(ptr_vec->vector); 105 | } 106 | 107 | if (type.type_category == FN) { 108 | /* shall be adjusted to `pointer to func`, according to the spec */ 109 | ptr_param_info->type = ptr_to_type(&type); 110 | } else { 111 | /* convert to pointer */ 112 | if (type.type_category == ARRAY) { 113 | type.type_category = PTR_; 114 | } 115 | ptr_param_info->type = type; 116 | } 117 | ptr_param_info->ident_str = ident_str; 118 | return ptr_param_info; 119 | } 120 | 121 | struct Type * 122 | try_parse_type_specifier_and_semicolon(const struct Token **ptr_tokvec) 123 | { 124 | const struct Token *tokvec3 = *ptr_tokvec; 125 | struct Type *ptr_type = parse_type_specifier(&tokvec3); 126 | if (tokvec3[0].kind != SEMICOLON) { 127 | return 0; 128 | } 129 | ++tokvec3; 130 | *ptr_tokvec = tokvec3; 131 | return ptr_type; 132 | } 133 | 134 | struct Type *parse_type_specifier(const struct Token **ptr_tokvec) 135 | { 136 | const struct Token *tokvec = *ptr_tokvec; 137 | 138 | skip_consts_or_noreturns(&tokvec); 139 | 140 | enum TokenKind tok = tokvec[0].kind; 141 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 142 | 143 | if (tok == RES_CHAR) { 144 | ptr->type_category = CHAR_; 145 | ++tokvec; 146 | } else if (tok == RES_INT) { 147 | ptr->type_category = INT_; 148 | ++tokvec; 149 | } else if (tok == RES_VOID) { 150 | ptr->type_category = VOID_; 151 | ++tokvec; 152 | } else if (tok == RES_STRUCT || tok == RES_UNION) { 153 | ++tokvec; 154 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 155 | "identifier after `struct` or `union`"); 156 | const char *ident = tokvec[-1].ident_str; 157 | 158 | ptr->type_category = tok == RES_STRUCT ? STRUCT_NOT_UNION : UNION; 159 | ptr->s.struct_or_union_tag = ident; 160 | if (tokvec[0].kind != LEFT_BRACE) { 161 | ptr->s.struct_or_union_info.ptr_types_and_idents = 162 | 0; /* crucial; no info */ 163 | skip_consts_or_noreturns(&tokvec); 164 | *ptr_tokvec = tokvec; 165 | return ptr; 166 | } 167 | ++tokvec; 168 | ptr->s.struct_or_union_info.ptr_types_and_idents = init_vector_(); 169 | 170 | while (1) { 171 | if (tokvec[0].kind == RIGHT_BRACE) { 172 | ++tokvec; 173 | break; 174 | } 175 | const char *ident_str; 176 | struct Type t = parse_struct_declaration(&tokvec, &ident_str); 177 | expect_and_consume( 178 | &tokvec, SEMICOLON, 179 | "semicolon after the declarator inside struct or union"); 180 | struct TypeAndIdent *ptr_t_and_i = 181 | calloc(1, sizeof(struct TypeAndIdent)); 182 | ptr_t_and_i->type = t; 183 | ptr_t_and_i->ident_str = ident_str; 184 | 185 | push_vector(ptr->s.struct_or_union_info.ptr_types_and_idents, 186 | ptr_t_and_i); 187 | } 188 | } else if (tok == RES_ENUM) { 189 | ++tokvec; 190 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 191 | "identifier after `enum`"); 192 | const char *ident = tokvec[-1].ident_str; 193 | ptr->type_category = ENUM_; 194 | ptr->e.enum_tag = ident; 195 | if (tokvec[0].kind != LEFT_BRACE) { 196 | ptr->e.enum_info.ptr_enumerators = 0; /* crucial; no info */ 197 | skip_consts_or_noreturns(&tokvec); 198 | *ptr_tokvec = tokvec; 199 | return ptr; 200 | } 201 | ++tokvec; 202 | 203 | ptr->e.enum_info.ptr_enumerators = init_vector_(); 204 | 205 | do { /* at least one enumerator is needed */ 206 | expect_and_consume(&tokvec, IDENT_OR_RESERVED, 207 | "identifier as a declaration of an enumerator"); 208 | const char *ident_str = tokvec[-1].ident_str; 209 | push_vector(ptr->e.enum_info.ptr_enumerators, ident_str); 210 | 211 | /* ending without comma */ 212 | if (tokvec[0].kind == RIGHT_BRACE) { 213 | ++tokvec; 214 | break; 215 | } else if (tokvec[0].kind == OP_COMMA) { 216 | ++tokvec; 217 | if (tokvec[0].kind == RIGHT_BRACE) { 218 | ++tokvec; 219 | break; 220 | } 221 | } 222 | } while (1); 223 | 224 | 225 | 226 | } else { 227 | error_unexpected_token( 228 | tokvec, "type name `int`, `char`, `void`, `struct` or `enum`"); 229 | } 230 | 231 | skip_consts_or_noreturns(&tokvec); 232 | *ptr_tokvec = tokvec; 233 | return ptr; 234 | } 235 | 236 | static void 237 | parse_parameter_type_list(const struct Token **ptr_tokvec, 238 | struct Vector /**/ *ptr_vec) 239 | { 240 | assert((*ptr_tokvec)[-1].kind == LEFT_PAREN); 241 | const struct Token *tokvec = *ptr_tokvec; 242 | struct Vector vec = *ptr_vec; 243 | { 244 | 245 | if (tokvec[0].kind == RIGHT_PAREN) { /* NO INFO */ 246 | struct TypeNode f; 247 | f.type_category = FN; 248 | f.param_infos_validity = INVALID; 249 | f.param_infos = init_vector(); 250 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 251 | *ptr = f; 252 | push_vector(&vec, ptr); 253 | } else if (tokvec[0].kind == RES_VOID && 254 | tokvec[1].kind == RIGHT_PAREN) { /* EXPLICITLY EMPTY */ 255 | tokvec += 1; 256 | struct TypeNode f; 257 | f.type_category = FN; 258 | f.param_infos_validity = VALID; 259 | f.param_infos = init_vector(); 260 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 261 | *ptr = f; 262 | push_vector(&vec, ptr); 263 | } else if (can_start_a_type(tokvec)) { 264 | struct TypeNode f; 265 | f.type_category = FN; 266 | f.param_infos_validity = VALID; 267 | f.param_infos = init_vector(); 268 | 269 | push_vector(&f.param_infos, parse_parameter_declaration(&tokvec)); 270 | 271 | while (1) { 272 | enum TokenKind kind = tokvec[0].kind; 273 | if (kind != OP_COMMA) { 274 | break; 275 | } 276 | ++tokvec; 277 | 278 | if (tokvec[0].kind == TRIPLE_DOT) { 279 | f.param_infos_validity = VA_ARGS; 280 | ++tokvec; 281 | break; 282 | } else { 283 | push_vector(&f.param_infos, 284 | parse_parameter_declaration(&tokvec)); 285 | } 286 | } 287 | 288 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 289 | *ptr = f; 290 | push_vector(&vec, ptr); 291 | } else { 292 | error_unexpected_token(tokvec, 293 | "while parsing function parameter list"); 294 | } 295 | } 296 | *ptr_tokvec = tokvec; 297 | *ptr_vec = vec; 298 | } 299 | 300 | static void parse_dcl_postfixes(const struct Token **ptr_tokvec, 301 | struct Vector /**/ *ptr_vec) 302 | { 303 | const struct Token *tokvec = *ptr_tokvec; 304 | 305 | struct Vector vec = *ptr_vec; 306 | 307 | // The parser must handle cases like `int test()[3];` (which tries to define 308 | // an array of functions) or `int test()()` (which tries to define a 309 | // function returning a function). While these declarations are semantically 310 | // forbidden, they are syntactically legal. 311 | while (1) { 312 | if (tokvec[0].kind == LEFT_BRACKET) { 313 | ++tokvec; 314 | expect_and_consume(&tokvec, LIT_DEC_INTEGER, 315 | "an integer while parsing a declaration"); 316 | int length = tokvec[-1].int_value; 317 | expect_and_consume(&tokvec, RIGHT_BRACKET, 318 | "closing ] while parsing a declaration"); 319 | 320 | struct TypeNode a; 321 | a.type_category = ARRAY; 322 | a.array_length = length; 323 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 324 | *ptr = a; 325 | push_vector(&vec, ptr); 326 | continue; 327 | } else if (tokvec[0].kind == LEFT_PAREN && 328 | (can_start_a_type(&tokvec[1]) || 329 | tokvec[1].kind == RIGHT_PAREN)) { 330 | ++tokvec; 331 | parse_parameter_type_list(&tokvec, &vec); 332 | expect_and_consume(&tokvec, RIGHT_PAREN, 333 | "closing ) while parsing functional type"); 334 | continue; 335 | } else { 336 | break; 337 | } 338 | } 339 | 340 | *ptr_tokvec = tokvec; 341 | *ptr_vec = vec; 342 | } 343 | 344 | static void 345 | parse_direct_declarator(const struct Token **ptr_tokvec, 346 | const char **ptr_to_ident_str, 347 | struct Vector /**/ *ptr_vec) 348 | { 349 | const struct Token *tokvec = *ptr_tokvec; 350 | 351 | struct Vector vec = *ptr_vec; 352 | if (tokvec[0].kind == LEFT_PAREN) { 353 | ++tokvec; 354 | parse_declarator(&tokvec, ptr_to_ident_str, &vec); 355 | expect_and_consume(&tokvec, RIGHT_PAREN, 356 | "closing parenthesis inside direct declarator"); 357 | *ptr_tokvec = tokvec; 358 | } else if (tokvec[0].kind == IDENT_OR_RESERVED) { 359 | *ptr_to_ident_str = tokvec[0].ident_str; 360 | ++tokvec; 361 | } else { 362 | error_unexpected_token(tokvec, "an identifier in the declarator"); 363 | } 364 | 365 | parse_dcl_postfixes(&tokvec, &vec); 366 | 367 | *ptr_tokvec = tokvec; 368 | *ptr_vec = vec; 369 | } 370 | 371 | static void parse_declarator(const struct Token **ptr_tokvec, 372 | const char **ptr_to_ident_str, 373 | struct Vector /**/ *ptr_vec) 374 | { 375 | int asterisk_num = 0; 376 | for (; (*ptr_tokvec)[0].kind == OP_ASTERISK; 377 | ++*ptr_tokvec, skip_consts_or_noreturns(ptr_tokvec)) { 378 | asterisk_num++; 379 | } 380 | 381 | parse_direct_declarator(ptr_tokvec, ptr_to_ident_str, ptr_vec); 382 | 383 | while (asterisk_num-- > 0) { 384 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 385 | ptr->type_category = PTR_; 386 | push_vector(ptr_vec, ptr); 387 | } 388 | } 389 | 390 | struct UntypedExpr * 391 | parse_init_declarator(const struct Token **ptr_tokvec, 392 | const char **ptr_to_ident_str, 393 | struct Vector /**/ *ptr_vec) 394 | { 395 | struct UntypedExpr *ptr_expr = 0; 396 | parse_declarator(ptr_tokvec, ptr_to_ident_str, ptr_vec); 397 | if ((*ptr_tokvec)[0].kind == OP_EQ) { 398 | ++*ptr_tokvec; 399 | ptr_expr = calloc(1, sizeof(struct UntypedExpr)); 400 | *ptr_expr = parse_assignment_expression(ptr_tokvec); 401 | } 402 | return ptr_expr; 403 | } 404 | 405 | int can_start_a_type(const struct Token *tokvec) 406 | { 407 | return tokvec[0].kind == RES_INT || tokvec[0].kind == RES_CHAR || 408 | tokvec[0].kind == RES_STRUCT || tokvec[0].kind == RES_VOID || 409 | tokvec[0].kind == RES_ENUM || tokvec[0].kind == RES_CONST || 410 | tokvec[0].kind == RES_NORETURN || tokvec[0].kind == RES_UNION; 411 | } 412 | 413 | /* `int a`, `int *a` */ 414 | struct Type parse_struct_declaration(const struct Token **ptr_tokvec, 415 | const char **ptr_to_ident_str) 416 | { 417 | struct Type *ptr_base_type = parse_type_specifier(ptr_tokvec); 418 | struct Vector /**/ *ptr_vec = init_vector_(); 419 | parse_declarator(ptr_tokvec, ptr_to_ident_str, ptr_vec); 420 | push_vector(ptr_vec, ptr_base_type); 421 | return from_type3_to_type(ptr_vec->vector); 422 | } 423 | 424 | /* `int a;`, `int *a;`, `int a = 5;` */ 425 | struct Type parse_declaration(const struct Token **ptr_tokvec, 426 | const char **ptr_to_ident_str, 427 | struct UntypedExpr **ptr_ptr_uexpr) 428 | { 429 | struct Type *ptr_base_type = parse_type_specifier(ptr_tokvec); 430 | struct Vector /**/ *ptr_vec = init_vector_(); 431 | struct UntypedExpr *ptr_uexpr = parse_init_declarator( 432 | ptr_tokvec, ptr_to_ident_str, ptr_vec); /* nullable */ 433 | *ptr_ptr_uexpr = ptr_uexpr; 434 | push_vector(ptr_vec, ptr_base_type); 435 | expect_and_consume( 436 | ptr_tokvec, SEMICOLON, 437 | "semicolon at the end of variable definition/declaration"); 438 | return from_type3_to_type(ptr_vec->vector); 439 | } 440 | 441 | struct Type parse_type_specifier_and_declarator(const struct Token **ptr_tokvec, 442 | const char **ptr_to_ident_str) 443 | { 444 | struct Type *ptr_base_type = parse_type_specifier(ptr_tokvec); 445 | struct Vector /**/ *ptr_vec = init_vector_(); 446 | parse_declarator(ptr_tokvec, ptr_to_ident_str, ptr_vec); 447 | push_vector(ptr_vec, ptr_base_type); 448 | return from_type3_to_type(ptr_vec->vector); 449 | } 450 | 451 | /* 452 | 453 | type-name: 454 | type-specifier abstract-declarator_opt 455 | 456 | abstract-declarator: 457 | pointer 458 | pointer_opt direct-abstract-declarator 459 | 460 | direct-abstract-declarator: 461 | ( abstract-declarator ) 462 | direct-abstract-declarator_opt [ constant-expression_opt ] 463 | direct-abstract-declarator_opt ( parameter-type-list_opt ) 464 | 465 | */ 466 | 467 | static void 468 | parse_abstract_declarator(const struct Token **ptr_tokvec, 469 | struct Vector /**/ *ptr_vec); 470 | 471 | static void 472 | parse_direct_abstract_declarator(const struct Token **ptr_tokvec, 473 | struct Vector /**/ *ptr_vec) 474 | { 475 | const struct Token *tokvec = *ptr_tokvec; 476 | 477 | struct Vector vec = *ptr_vec; 478 | if (tokvec[0].kind == LEFT_PAREN && !can_start_a_type(&tokvec[1]) && 479 | tokvec[1].kind != 480 | RIGHT_PAREN) { /* an empty parenthesis must be of a function */ 481 | ++tokvec; 482 | parse_abstract_declarator(&tokvec, &vec); 483 | expect_and_consume(&tokvec, RIGHT_PAREN, 484 | "closing parenthesis inside direct declarator"); 485 | } 486 | 487 | parse_dcl_postfixes(&tokvec, &vec); 488 | 489 | *ptr_tokvec = tokvec; 490 | *ptr_vec = vec; 491 | } 492 | 493 | static void 494 | parse_abstract_declarator(const struct Token **ptr_tokvec, 495 | struct Vector /**/ *ptr_vec) 496 | { 497 | const struct Token *tokvec = *ptr_tokvec; 498 | 499 | if (tokvec[0].kind != OP_ASTERISK) { 500 | parse_direct_abstract_declarator(&tokvec, ptr_vec); 501 | *ptr_tokvec = tokvec; 502 | return; 503 | } 504 | 505 | int asterisk_num = 0; 506 | for (; tokvec[0].kind == OP_ASTERISK; 507 | ++tokvec, skip_consts_or_noreturns(&tokvec)) { 508 | asterisk_num++; 509 | } 510 | 511 | /* optional */ 512 | if (tokvec[0].kind == LEFT_PAREN || tokvec[0].kind == LEFT_BRACKET) { 513 | parse_direct_abstract_declarator(&tokvec, ptr_vec); 514 | } 515 | 516 | while (asterisk_num-- > 0) { 517 | struct TypeNode *ptr = calloc(1, sizeof(struct TypeNode)); 518 | ptr->type_category = PTR_; 519 | push_vector(ptr_vec, ptr); 520 | } 521 | 522 | *ptr_tokvec = tokvec; 523 | } 524 | 525 | /* `int `, `int *` */ 526 | struct Type parse_type_name(const struct Token **ptr_tokvec) 527 | { 528 | struct Type *ptr_base_type = parse_type_specifier(ptr_tokvec); 529 | struct Vector /**/ *ptr_vec = init_vector_(); 530 | 531 | const struct Token *tokvec = *ptr_tokvec; 532 | 533 | /* optional */ 534 | if (tokvec[0].kind == OP_ASTERISK || tokvec[0].kind == LEFT_PAREN || 535 | tokvec[0].kind == LEFT_BRACKET) { 536 | parse_abstract_declarator(&tokvec, ptr_vec); 537 | } 538 | push_vector(ptr_vec, ptr_base_type); 539 | 540 | *ptr_tokvec = tokvec; 541 | return from_type3_to_type(ptr_vec->vector); 542 | } 543 | -------------------------------------------------------------------------------- /print_x86_64.h: -------------------------------------------------------------------------------- 1 | /* prologue and epilogue */ 2 | void gen_prologue(int alloc_size, const char *fname); 3 | void gen_prologue_static(int alloc_size, const char *fname); 4 | void gen_epilogue_nbyte(int n, int label_name); 5 | void gen_epilogue_returning_integerclass_struct_or_union(int size, int label); 6 | void gen_return_garbage(void); 7 | 8 | /* push: decreases stack pointer by 8 */ 9 | void gen_push_int(int num); 10 | void gen_push_address_of_local(int offset); 11 | void gen_push_address_of_str(int strnum); 12 | void gen_push_from_local_nbyte(int n, int offset); 13 | void gen_push_address_of_global(const char *ident); 14 | void gen_push_ret_of_nbyte(int n, const char *ident_str, int arg_stacksize); 15 | void gen_push_nullptr(void); 16 | void gen_call_reg_and_push_ret_of_nbyte(int n, const char *reg); 17 | void gen_peek_deref_push_nbyte(int n); 18 | 19 | /* control: contains jump or is a label. does not tweak the stack pointer. */ 20 | void gen_jump(int label, const char *comment); 21 | void gen_if_zero_jmp_nbyte(int n, int label1, int offset); 22 | void gen_if_nonzero_jmp_nbyte(int n, int label1, int offset); 23 | void gen_if_2nd_matches_int_jmp_4byte(int constant1, int label1); 24 | void gen_label(int label1); 25 | 26 | /* binary operation: pops twice, does an operation and pushes the result */ 27 | void gen_op_ints(const char *str); 28 | void gen_compare_ints(const char *str); 29 | void gen_mul_ints(void); 30 | void gen_div_ints(void); 31 | void gen_rem_ints(void); 32 | void gen_shift_ints(const char *str); 33 | void gen_discard(void); 34 | void gen_discard2nd(void); 35 | void gen_compare_ptrs(const char *str); 36 | void gen_assign_nbyte(int n); 37 | void gen_op_8byte(const char *str); 38 | 39 | /* unary operation: pops once, does an operation and pushes the result */ 40 | void gen_cltq(void); 41 | void gen_unary_not(void); 42 | void gen_unary(const char *str); 43 | void gen_extend_to_4byte(void); 44 | void gen_mul_by_const(int mul); 45 | void gen_div_by_const(int num); 46 | void gen_logical_not_of_pointer(void); 47 | void gen_peek_and_dereference_nbyte(int n); 48 | 49 | /* declaration: declares something */ 50 | void gen_string_literal(int strnum, const char *str); 51 | void gen_global_declaration(const char *ident, int size); 52 | 53 | /* pop to reg: pops to a register. */ 54 | void gen_pop_to_reg_4byte(const char *str); 55 | void gen_pop_to_reg_8byte(const char *str); 56 | 57 | /* write to local: does not modify the stack */ 58 | void gen_write_register_to_local_1byte(const char *str, int offset); 59 | void gen_write_register_to_local_4byte(const char *str, int offset); 60 | void gen_write_register_to_local_8byte(const char *str, int offset); 61 | void gen_call_and_assign_integerclass_struct_or_union_to_local( 62 | const char *fname, int offset, int size); 63 | void gen_call_reg_and_assign_integerclass_struct_or_union_or_union_to_local( 64 | const char *regname, int offset, int size); 65 | 66 | /* memcpy: pops two pointers and does memcpy */ 67 | void gen_copy_2nd_struct_or_union_to_1st_and_discard(int size); 68 | void gen_copy_1st_struct_or_union_to_2nd_and_discard(int size); 69 | 70 | /* va_list */ 71 | void gen_write_stack_chk_guard_to_local(int offset); 72 | void gen_epilogue_nbyte_with_stack_check(int n, int return_label_name, 73 | int checksum_offset, 74 | int failing_label_name); 75 | void gen_store_regs_to_local(int offset, int start_from, int label_name); 76 | void gen_va_start(int gp_offset, int fp_offset, int reg_save_area_offset); 77 | 78 | /* regname */ 79 | const char *get_reg_name_from_arg_pos_4byte(int counter); 80 | const char *get_reg_name_from_arg_pos_8byte(int counter); 81 | 82 | /* error */ 83 | _Noreturn void poison_and_die(const char *msg); 84 | 85 | /* under construction */ 86 | void gen_raw_call_partA(void); 87 | 88 | extern struct __FILE *global_ir; 89 | 90 | #ifdef OSX 91 | #define PREFIX "_" 92 | #endif 93 | #ifndef OSX 94 | #define PREFIX "" 95 | #endif 96 | -------------------------------------------------------------------------------- /print_x86_64_unofficial.c: -------------------------------------------------------------------------------- 1 | #include "print_x86_64_unofficial.h" 2 | #include "print_x86_64.h" 3 | #include "std.h" 4 | #include "std_io.h" 5 | 6 | static void gen_raw_call_partC_with_stacksize(int arg_stacksize); 7 | 8 | /******************* 9 | * unofficial APIs * 10 | *******************/ 11 | 12 | /* write to local mem what's at the top of the stack. does not consume stack. */ 13 | void gen_write_to_local(int offset) 14 | { 15 | assert(offset < 0); 16 | printf("//gen_write_to_local(%d)\n", offset); 17 | printf(" movl (%%rsp), %%eax\n"); 18 | printf(" movl %%eax, %d(%%rbp)\n", offset); 19 | } 20 | 21 | /* write to local mem what's at the top of the stack. does not consume stack. */ 22 | void gen_write_to_local_8byte(int offset) 23 | { 24 | assert(offset < 0); 25 | printf("//gen_write_to_local_8byte(%d)\n", offset); 26 | printf(" movq (%%rsp), %%rax\n"); 27 | printf(" movq %%rax, %d(%%rbp)\n", offset); 28 | } 29 | 30 | void gen_write_to_local_1byte(int offset) 31 | { 32 | assert(offset < 0); 33 | printf("//gen_write_to_local_1byte(%d)\n", offset); 34 | printf(" movb (%%rsp), %%al\n"); 35 | printf(" movb %%al, %d(%%rbp)\n", offset); 36 | } 37 | 38 | /* push what's on local mem */ 39 | void gen_push_from_local_4byte(int offset) 40 | { 41 | assert(offset < 0); 42 | printf("//gen_push_from_local_4byte(%d)\n", offset); 43 | printf(" subq $8, %%rsp\n" 44 | " movl %d(%%rbp), %%eax\n" 45 | " movl %%eax, (%%rsp)\n", 46 | offset); 47 | } 48 | 49 | void gen_peek_deref_push_4byte(void) 50 | { 51 | printf("//gen_peek_deref_push_4byte()\n"); 52 | puts(" movq (%rsp), %rax \n" 53 | " movl (%rax), %edx\n" 54 | " subq $8, %rsp\n" 55 | " movq %rdx, (%rsp)"); 56 | } 57 | 58 | void gen_peek_and_dereference_4byte(void) 59 | { 60 | printf("//gen_peek_and_dereference_4byte()\n"); 61 | puts(" movq (%rsp), %rax \n" 62 | " movl (%rax), %eax\n" 63 | " movl %eax, (%rsp)"); 64 | } 65 | 66 | /* 67 | dereference what's at the top of the stack. 68 | */ 69 | void gen_peek_and_dereference_8byte(void) 70 | { 71 | printf("//gen_peek_and_dereference_8byte()\n"); 72 | puts(" movq (%rsp), %rax \n" 73 | " movq (%rax), %rax\n" 74 | " movq %rax, (%rsp)"); 75 | } 76 | 77 | void gen_peek_deref_push_8byte(void) 78 | { 79 | printf("//gen_peek_deref_push_8byte()\n"); 80 | puts(" movq (%rsp), %rax \n" 81 | " movq (%rax), %rdx\n" 82 | " subq $8, %rsp\n" 83 | " movq %rdx, (%rsp)"); 84 | } 85 | 86 | void gen_peek_and_dereference_1byte(void) 87 | { 88 | printf("//gen_peek_and_dereference_1byte()\n"); 89 | printf(" movq (%%rsp), %%rax\n" 90 | " movsbl (%%rax), %%eax\n" 91 | " movl %%eax, (%%rsp)\n"); 92 | } 93 | 94 | void gen_peek_deref_push_1byte(void) 95 | { 96 | printf("//gen_peek_deref_push_1byte()\n"); 97 | puts(" movq (%rsp), %rax \n" 98 | " movb (%rax), %dl\n" 99 | " subq $8, %rsp\n" 100 | " movb %dl, (%rsp)"); 101 | } 102 | 103 | /* push what's on local mem */ 104 | void gen_push_from_local_8byte(int offset) 105 | { 106 | assert(offset < 0); 107 | printf("//gen_push_from_local_8byte(%d)\n", offset); 108 | printf(" subq $8, %%rsp\n" 109 | " movq %d(%%rbp), %%rax\n" 110 | " movq %%rax, (%%rsp)\n", 111 | offset); 112 | } 113 | 114 | void gen_push_from_local_1byte(int offset) 115 | { 116 | assert(offset < 0); 117 | printf("//gen_push_from_local_1byte(%d)\n", offset); 118 | printf(" subq $8, %%rsp\n" 119 | " movsbl %d(%%rbp), %%eax\n" 120 | " movl %%eax, (%%rsp)\n", 121 | offset); 122 | } 123 | 124 | void gen_swap(void) 125 | { 126 | printf("//gen_swap()\n"); 127 | printf(" movq (%%rsp), %%rax\n" 128 | " movq 8(%%rsp), %%rdx\n" 129 | " movq %%rdx, (%%rsp)\n" 130 | " movq %%rax, 8(%%rsp)\n"); 131 | } 132 | 133 | void gen_push_ret_of_1byte(const char *fname, int arg_stacksize) 134 | { 135 | printf("//gen_push_ret_of_1byte(\"%s\")\n", fname); 136 | gen_raw_call_partB(PREFIX, fname); 137 | gen_raw_call_partC_with_stacksize(arg_stacksize); 138 | 139 | printf(" movsbl %%al, %%eax\n" 140 | " movl %%eax, (%%rsp)\n"); 141 | } 142 | 143 | void gen_push_ret_of_4byte(const char *fname, int arg_stacksize) 144 | { 145 | printf("//gen_push_ret_of_4byte(\"%s\")\n", fname); 146 | gen_raw_call_partB(PREFIX, fname); 147 | gen_raw_call_partC_with_stacksize(arg_stacksize); 148 | printf(" movl %%eax, (%%rsp)\n"); 149 | } 150 | 151 | void gen_push_ret_of_8byte(const char *fname, int arg_stacksize) 152 | { 153 | printf("//gen_push_ret_of_8byte(\"%s\")\n", fname); 154 | gen_raw_call_partB(PREFIX, fname); 155 | gen_raw_call_partC_with_stacksize(arg_stacksize); 156 | printf(" movq %%rax, (%%rsp)\n"); 157 | } 158 | 159 | void gen_call_reg_and_push_ret_of_1byte(const char *reg) 160 | { 161 | printf("//gen_call_reg_and_push_ret_of_1byte(\"%s\")\n", reg); 162 | gen_raw_call_partB("*%", reg); 163 | gen_raw_call_partC(); 164 | printf(" movsbl %%al, %%eax\n" 165 | " movl %%eax, (%%rsp)\n"); 166 | } 167 | 168 | void gen_call_reg_and_push_ret_of_4byte(const char *reg) 169 | { 170 | printf("//gen_call_reg_and_push_ret_of_4byte(\"%s\")\n", reg); 171 | gen_raw_call_partB("*%", reg); 172 | gen_raw_call_partC(); 173 | printf(" movl %%eax, (%%rsp)\n"); 174 | } 175 | 176 | void gen_call_reg_and_push_ret_of_8byte(const char *reg) 177 | { 178 | printf("//gen_call_reg_and_push_ret_of_8byte(\"%s\")\n", reg); 179 | gen_raw_call_partB("*%", reg); 180 | gen_raw_call_partC(); 181 | printf(" movq %%rax, (%%rsp)\n"); 182 | } 183 | 184 | void gen_raw_call_partA() 185 | { 186 | /* alignment */ 187 | 188 | /* 189 | if it is already aligned: 190 | `subq $8, %rsp` will de-align; mod 16 gives 8. 191 | Thus, `subq %rax, %rsp\n` subtracts another 8. 192 | `movq %rax, (%rsp)` puts 8 on top of the stack. 193 | */ 194 | 195 | /* 196 | if it is not aligned: 197 | `subq $8, %rsp` will align; mod 16 gives 0. 198 | Thus, `subq %rax, %rsp\n` will not subtract. 199 | `movq %rax, (%rsp)` puts 0 on top of the stack. 200 | */ 201 | printf(" subq $8, %%rsp\n" 202 | " movq %%rsp, %%rax\n" 203 | " andq $15, %%rax\n" 204 | " subq %%rax, %%rsp\n" 205 | " movq %%rax, (%%rsp)\n"); 206 | } 207 | 208 | void gen_raw_call_partB(const char *s1, const char *s2) 209 | { 210 | 211 | printf(" movb $0, %%al\n"); /* printf */ 212 | printf(" call %s%s\n", s1, s2); 213 | } 214 | 215 | static void gen_raw_call_partC_with_stacksize(int arg_stacksize) 216 | { 217 | printf(" addq $%d, %%rsp\n", arg_stacksize); 218 | 219 | /* 220 | if it was already aligned: 221 | the top contains 8, and you must add 16 to the stack in order to resume. 222 | Since this function is a `push`, you need to subtract 8 to push the 223 | returned value. Hence, you only need to add 8. 224 | */ 225 | /* 226 | if it was not aligned: 227 | the top contains 0, and you must add 8 to the stack in order to resume. 228 | Since this function is a `push`, you need to subtract 8 to push the 229 | returned value. Hence, you only need to add 0. 230 | */ 231 | printf(" addq (%%rsp), %%rsp\n"); 232 | } 233 | 234 | void gen_raw_call_partC() { gen_raw_call_partC_with_stacksize(0); } 235 | 236 | void gen_discard3rd(void) 237 | { 238 | printf("//gen_discard3rd()\n"); 239 | printf(" movq 8(%%rsp), %%rax\n" 240 | " movq %%rax, 16(%%rsp)\n" 241 | " movq (%%rsp), %%rax\n" 242 | " movq %%rax, 8(%%rsp)\n" 243 | " addq $8, %%rsp\n"); 244 | } 245 | 246 | /* for both 4byte and 1byte */ 247 | void gen_epilogue(int label) 248 | { 249 | printf("//gen_epilogue(%d)\n", label); 250 | printf(".L%d:" 251 | " movl (%%rsp), %%eax\n" 252 | " leave\n" 253 | " ret\n", 254 | label); 255 | } 256 | 257 | void gen_epilogue_8byte(int label) 258 | { 259 | printf("//gen_epilogue_8byte(%d)\n", label); 260 | printf(".L%d:" 261 | " movq (%%rsp), %%rax\n" 262 | " leave\n" 263 | " ret\n", 264 | label); 265 | } 266 | 267 | /* 268 | value = pop(); 269 | addr = pop(); 270 | *addr = value; 271 | push(value); 272 | */ 273 | void gen_assign_8byte(void) 274 | { 275 | printf("//gen_assign_8byte()\n"); 276 | printf(" movq (%%rsp), %%rax\n"); 277 | printf(" movq 8(%%rsp), %%rdx\n"); 278 | 279 | printf(" movq %%rax, (%%rdx)\n" 280 | " addq $8, %%rsp\n" 281 | " movq %%rax, (%%rsp)\n"); 282 | } 283 | 284 | /* 285 | value = pop(); 286 | addr = pop(); 287 | *addr = value; 288 | push(value); 289 | */ 290 | void gen_assign_4byte(void) 291 | { 292 | printf("//gen_assign_4byte()\n"); 293 | printf(" movl (%%rsp), %%eax\n"); 294 | printf(" movq 8(%%rsp), %%rdx\n"); 295 | 296 | printf(" movl %%eax, (%%rdx)\n" 297 | " addq $8, %%rsp\n" 298 | " movl %%eax, (%%rsp)\n"); 299 | } 300 | 301 | /* 302 | value = pop(); 303 | addr = pop(); 304 | *addr = value; 305 | push(value); 306 | */ 307 | void gen_assign_1byte(void) 308 | { 309 | printf("//gen_assign_1byte()\n"); 310 | printf(" movb (%%rsp), %%al\n"); 311 | printf(" movq 8(%%rsp), %%rdx\n"); 312 | 313 | printf(" movb %%al, (%%rdx)\n"); 314 | printf(" addq $8, %%rsp\n"); 315 | printf(" movb %%al, (%%rsp)\n"); 316 | } 317 | 318 | void gen_initialize_va_list(int dst_struct_offset, int gp_offset, int fp_offset, 319 | int reg_save_area_offset) 320 | { 321 | printf(" movl $%d, %d(%%rbp)\n", gp_offset, dst_struct_offset); 322 | printf(" movl $%d, %d(%%rbp)\n", fp_offset, dst_struct_offset + 4); 323 | 324 | printf(" leaq 16(%%rbp), %%rax\n" 325 | " movq %%rax, %d(%%rbp)\n", 326 | dst_struct_offset + 8); 327 | 328 | printf(" leaq %d(%%rbp), %%rax\n", reg_save_area_offset); 329 | printf(" movq %%rax, %d(%%rbp)\n", dst_struct_offset + 16); 330 | } 331 | -------------------------------------------------------------------------------- /print_x86_64_unofficial.h: -------------------------------------------------------------------------------- 1 | /* auxiliary functions to implement the API */ 2 | 3 | void gen_raw_call_partB(const char *s1, const char *s2); 4 | void gen_raw_call_partC(void); 5 | 6 | /* unofficial API */ 7 | void gen_epilogue(int label); 8 | void gen_epilogue_8byte(int label); 9 | void gen_push_from_local_1byte(int offset); 10 | void gen_push_from_local_4byte(int offset); 11 | void gen_push_from_local_8byte(int offset); 12 | void gen_push_ret_of_1byte(const char *fname, int arg_stacksize); 13 | void gen_push_ret_of_4byte(const char *fname, int arg_stacksize); 14 | void gen_push_ret_of_8byte(const char *fname, int arg_stacksize); 15 | void gen_assign_1byte(void); 16 | void gen_assign_4byte(void); 17 | void gen_assign_8byte(void); 18 | void gen_peek_and_dereference_1byte(void); 19 | void gen_peek_and_dereference_4byte(void); 20 | void gen_peek_and_dereference_8byte(void); 21 | void gen_call_reg_and_push_ret_of_1byte(const char *reg); 22 | void gen_call_reg_and_push_ret_of_4byte(const char *reg); 23 | void gen_call_reg_and_push_ret_of_8byte(const char *reg); 24 | void gen_peek_deref_push_1byte(void); 25 | void gen_peek_deref_push_4byte(void); 26 | void gen_peek_deref_push_8byte(void); 27 | void gen_swap(void); 28 | void gen_write_to_local(int offset); 29 | void gen_write_to_local_8byte(int offset); 30 | void gen_write_to_local_1byte(int offset); 31 | -------------------------------------------------------------------------------- /printerstate.h: -------------------------------------------------------------------------------- 1 | struct PrinterState { 2 | int final_label_name; 3 | int return_label_name; /* the label at the end of the function */ 4 | int break_label_name; /* the label at the end of the current loop */ 5 | int continue_label_name; /* the label at the beginning of the current loop 6 | */ 7 | struct Vector /**/ string_constant_pool; 8 | int pool_largest_id; 9 | int is_inside_switch; 10 | struct Vector /**/ case_default_vec; 11 | struct Map2 /**/ 12 | *source_label_to_assembly_label; 13 | 14 | int is_va; 15 | 16 | /* only valid when is_va is set */ 17 | int integral_explicit_arg_num; 18 | int reg_save_area; 19 | int stack_chk_offset; 20 | }; 21 | 22 | int get_new_label_name(struct PrinterState *ptr_prs); 23 | void print_expression(struct PrinterState *ptr_prs, 24 | const struct Expr *ref_expr); 25 | 26 | void print_address_of_lvalue_or_struct_or_union(struct PrinterState *ptr_prs, 27 | const struct Expr *ref_expr, 28 | const char *msg); 29 | 30 | void print_expression_or_addr_of_struct_or_union(struct PrinterState *ptr_prs, 31 | const struct Expr *ref_expr, 32 | const char *msg); 33 | -------------------------------------------------------------------------------- /s/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsjoihs/c-compiler/17f53331a19e37594d07e69cc70bc71ae30eb6f4/s/.gitkeep -------------------------------------------------------------------------------- /self_compile_asm/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hsjoihs/c-compiler/17f53331a19e37594d07e69cc70bc71ae30eb6f4/self_compile_asm/.gitkeep -------------------------------------------------------------------------------- /std.c: -------------------------------------------------------------------------------- 1 | #include "std.h" 2 | void assert(int i) 3 | { 4 | if (!i) { 5 | exit(EXIT_FAILURE); 6 | } 7 | } 8 | 9 | _Noreturn void assert0(int i) { exit(EXIT_FAILURE + i); } 10 | -------------------------------------------------------------------------------- /std.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER__STDH 2 | #define HEADER__STDH 3 | 4 | #ifndef OVERRIDE_STD 5 | #include 6 | #include 7 | #include 8 | #include 9 | #define assert0 assert 10 | #endif 11 | 12 | #ifdef OVERRIDE_STD 13 | 14 | #ifdef __STDC__ 15 | #define size_t2 unsigned long 16 | #endif 17 | #ifndef __STDC__ 18 | #define size_t2 int 19 | #endif 20 | 21 | void assert(); 22 | _Noreturn void assert0(int i); 23 | void *calloc(size_t2 nmemb, size_t2 size); 24 | void *realloc(void *ptr, size_t2 size); 25 | _Noreturn void exit(int status); 26 | 27 | size_t2 strlen(const char *s); 28 | int strcmp(const char *s1, const char *s2); 29 | char *strcpy(char *s1, const char *s2); 30 | char *strcat(char *s1, const char *s2); 31 | char *strchr(const char *s, int c); 32 | int strncmp(const char *s1, const char *s2, size_t2 n); 33 | char *strndup(const char *str, size_t2 size); 34 | 35 | #ifdef __STDC__ 36 | #undef va_start 37 | #undef va_end 38 | #endif 39 | 40 | #define va_start __builtin_va_start 41 | #define va_end __builtin_va_end 42 | 43 | #define EXIT_FAILURE 1 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /std_io.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER__STDIOH 2 | #define HEADER__STDIOH 3 | 4 | #ifdef OSX 5 | #define stderr __stderrp 6 | #define stdin __stdinp 7 | extern struct __FILE *stderr; 8 | extern struct __FILE *stdin; 9 | #endif 10 | #ifndef OSX 11 | extern struct __FILE *stderr; 12 | extern struct __FILE *stdin; 13 | #endif 14 | 15 | struct va_list_tag { 16 | /*unsigned*/ int gp_offset; 17 | /*unsigned*/ int fp_offset; 18 | void *overflow_arg_area; 19 | void *reg_save_area; 20 | }; 21 | 22 | #ifdef __STDC__ 23 | #include 24 | typedef struct __FILE FILE; 25 | int fprintf(FILE *restrict, const char *restrict, ...); 26 | int printf(const char *restrict, ...); 27 | int sprintf(char *restrict s, const char *restrict format, ...); 28 | int vfprintf(FILE *stream, const char *format, va_list arg); 29 | int vprintf(const char *format, va_list arg); 30 | #endif 31 | #ifndef __STDC__ 32 | int fprintf(); 33 | int printf(); 34 | int sprintf(); 35 | int vfprintf(struct __FILE *stream, const char *format, 36 | struct va_list_tag arg[1]); 37 | int vprintf(const char *format, struct va_list_tag arg[1]); 38 | #endif 39 | 40 | char *fgets(char *buf, int a, struct __FILE *fp); 41 | int puts(const char *str); 42 | struct __FILE *fopen(const char *filename, const char *mode); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /test/call_va_.c: -------------------------------------------------------------------------------- 1 | void debug_write(const char *fmt, ...); 2 | 3 | int main() 4 | { 5 | debug_write("Hello, va_list%c\n", '!'); 6 | debug_write("%s", "Hello, va_list!\n"); 7 | debug_write("%s", "Hello, va_list 2!\n"); 8 | debug_write("%s %s %d%c\n", "Hello,", "va_list", 3, '!'); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/char_literal.c: -------------------------------------------------------------------------------- 1 | int printf(); 2 | int main() 3 | { 4 | char a = 'a'; 5 | int a_ = 'a'; 6 | printf("%c %d", a, a_); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /test/duff.c: -------------------------------------------------------------------------------- 1 | int global; 2 | int printf(); 3 | 4 | void f(void) 5 | { 6 | global += 3; 7 | return; 8 | } 9 | 10 | void call_n_times(int count) 11 | { 12 | global = 0; 13 | { 14 | int n; n = (count + 7) / 8; 15 | switch (count % 8) { 16 | case 0: do { f(); 17 | case 7: f(); 18 | case 6: f(); 19 | case 5: f(); 20 | case 4: f(); 21 | case 3: f(); 22 | case 2: f(); 23 | case 1: f(); 24 | } while (--n > 0); 25 | } 26 | } 27 | return; 28 | } 29 | 30 | int main() 31 | { 32 | int i; 33 | for (i = 1; i < 300; i++) { 34 | call_n_times(i); 35 | if (global != 3 * i) { 36 | printf("FAILED at %d", i); 37 | return 1; 38 | } 39 | } 40 | return 0; 41 | } -------------------------------------------------------------------------------- /test/error_if_pedantic/backslash_e.c: -------------------------------------------------------------------------------- 1 | int main() { return "\e[32mPASS\e[m"[0]; } 2 | -------------------------------------------------------------------------------- /test/error_if_pedantic/binary_literal.c: -------------------------------------------------------------------------------- 1 | // Becomes compliant in C23 2 | int main() {return 0b11; } -------------------------------------------------------------------------------- /test/error_if_pedantic/toplevel_semicolon.c: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;; int main() { return 0; } 2 | -------------------------------------------------------------------------------- /test/escape.c: -------------------------------------------------------------------------------- 1 | int printf(); 2 | int main() 3 | { 4 | const char *str = "\t\n\v\f\r\"\'\\"; 5 | char str2[9]; 6 | str2[0] = '\t'; 7 | str2[1] = '\n'; 8 | str2[2] = '\v'; 9 | str2[3] = '\f'; 10 | str2[4] = '\r'; 11 | str2[5] = '\"'; 12 | str2[6] = '\''; 13 | str2[7] = '\\'; 14 | str2[8] = 0; 15 | int i = 0; 16 | for (; str[i]; i++) { 17 | int k = str[i]; 18 | int l = str2[i]; 19 | printf("%d %d\n", k, l); 20 | } 21 | return 0; 22 | } -------------------------------------------------------------------------------- /test/link1.c: -------------------------------------------------------------------------------- 1 | struct A {int a;}; int g_fnc(int a); struct A func_ (int u){ struct A s; s.a = u; return s;} int main(void){ return g_fnc(174); } -------------------------------------------------------------------------------- /test/link2.c: -------------------------------------------------------------------------------- 1 | struct A_2 {int a;}; 2 | struct A_2 func_ (int u); 3 | 4 | int g_fnc(int a) 5 | { 6 | struct A_2 u = func_(a); 7 | return u.a; 8 | } 9 | -------------------------------------------------------------------------------- /test/nqueen2.c: -------------------------------------------------------------------------------- 1 | /* http://www.cc.kyoto-su.ac.jp/~yamada/ap/backtrack.html */ 2 | int printf(); 3 | int puts(); 4 | int changeBoard(int board[30][30], int i, int j, int d, int N) 5 | { 6 | int k; 7 | for (k = 0; k < N; k++) { 8 | board[i][k] += d; 9 | board[k][j] += d; 10 | } 11 | if (i > j) { 12 | for (k = 0; k < N - (i - j); k++) { 13 | board[k + (i - j)][k] += d; 14 | } 15 | } else { 16 | for (k = 0; k < N - (j - i); k++) { 17 | board[k][k + (j - i)] += d; 18 | } 19 | } 20 | if (i + j < N) { 21 | for (k = 0; k <= i + j; k++) { 22 | board[i + j - k][k] += d; 23 | } 24 | } else { 25 | for (k = i + j - N + 1; k < N; k++) { 26 | board[i + j - k][k] += d; 27 | } 28 | } 29 | return 0; 30 | } 31 | int setQueen(int board[30][30], int num_placed, int *ptr_sol_num, int N) 32 | { 33 | int j; 34 | if (num_placed == N) { 35 | (*ptr_sol_num) += 1; 36 | return 0; 37 | } 38 | for (j = 0; j < N; j++) { 39 | if (board[num_placed][j] == 0) { 40 | changeBoard(board, num_placed, j, +1, N); 41 | setQueen(board, num_placed + 1, ptr_sol_num, N); 42 | changeBoard(board, num_placed, j, -1, N); 43 | } 44 | } 45 | return 0; 46 | } 47 | int board_[30][30]; 48 | int main() 49 | { 50 | int i; 51 | for (i = 1; i < 12; i++) { 52 | int sol_num; 53 | sol_num = 0; 54 | setQueen(board_, 0, &sol_num, i); 55 | printf("%d queen(s): ", i); 56 | printf("%d", sol_num); 57 | puts(""); 58 | } 59 | return 0; 60 | } -------------------------------------------------------------------------------- /test/nqueen3.c: -------------------------------------------------------------------------------- 1 | /* Based on https://twitter.com/0x19f/status/1025823053459017728 */ 2 | int printf(); 3 | int puts(); 4 | int A[200][200]; 5 | int dfs(int row, int N) 6 | { 7 | if (row == N) 8 | return 1; 9 | int ret; 10 | ret = 0; 11 | int col; 12 | for (col = 0; col < N; col++) { 13 | int ok; 14 | ok = 1; 15 | int i; 16 | for (i = 1; i < N; i++) { 17 | if (row - i >= 0 && col - i >= 0) { 18 | ok = ok && A[row - i][col - i] == 0; 19 | } 20 | if (row - i >= 0) { 21 | ok = ok && A[row - i][col] == 0; 22 | } 23 | if (row - i >= 0 && col + i < N) { 24 | ok = ok && A[row - i][col + i] == 0; 25 | } 26 | } 27 | if (ok) { 28 | A[row][col] = 1; 29 | ret += dfs(row + 1, N); 30 | A[row][col] = 0; 31 | } 32 | } 33 | return ret; 34 | } 35 | int main() 36 | { 37 | int i; 38 | for (i = 1; i < 11; i++) { 39 | int j; 40 | j = dfs(0, i); 41 | printf("%d queen: %d", i, j); 42 | puts(""); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/nqueen4.c: -------------------------------------------------------------------------------- 1 | /* https://rosettacode.org/wiki/N-queens_problem#C */ 2 | int printf(); 3 | int puts(); 4 | int count; 5 | int solve(int n, int col, int *hist) 6 | { 7 | if (col == n) { 8 | count += 1; 9 | return 0; 10 | } 11 | int i; 12 | int j; 13 | for (i = 0, j = 0; i < n; i++) { 14 | for (j = 0; j < col && hist[j] != i && (hist[j] - i) != col - j && 15 | (hist[j] - i) != j - col; 16 | j++) { 17 | } 18 | if (j < col) 19 | continue; 20 | 21 | hist[col] = i; 22 | solve(n, col + 1, hist); 23 | } 24 | return 0; 25 | } 26 | 27 | int main() 28 | { 29 | int hist[12]; 30 | int i; 31 | for (i = 1; i < 12; i++) { 32 | count = 0; 33 | solve(i, 0, hist); 34 | printf("%d queen(s): ", i); 35 | printf("%d", count); 36 | puts(""); 37 | } 38 | return 0; 39 | } -------------------------------------------------------------------------------- /test/nqueen5.c: -------------------------------------------------------------------------------- 1 | /* http://www.cc.kyoto-su.ac.jp/~yamada/ap/backtrack.html */ 2 | int printf(); 3 | int puts(); 4 | int changeBoard(int board[30][30], int i, int j, int d, int N) 5 | { 6 | int k; 7 | for (k = 0; k < N; k++) { 8 | board[i][k] += d; 9 | board[k][j] += d; 10 | } 11 | if (i > j) { 12 | for (k = 0; k < N - (i - j); k++) { 13 | board[k + (i - j)][k] += d; 14 | } 15 | } else { 16 | for (k = 0; k < N - (j - i); k++) { 17 | board[k][k + (j - i)] += d; 18 | } 19 | } 20 | if (i + j < N) { 21 | for (k = 0; k <= i + j; k++) { 22 | board[i + j - k][k] += d; 23 | } 24 | } else { 25 | for (k = i + j - N + 1; k < N; k++) { 26 | board[i + j - k][k] += d; 27 | } 28 | } 29 | return 0; 30 | } 31 | int setQueen(int board[30][30], int num_placed, int *ptr_sol_num, int N) 32 | { 33 | int j; 34 | if (num_placed == N) { 35 | ++*ptr_sol_num; 36 | return 0; 37 | } 38 | for (j = 0; j < N; j++) { 39 | if (board[num_placed][j] == 0) { 40 | changeBoard(board, num_placed, j, +1, N); 41 | setQueen(board, num_placed + 1, ptr_sol_num, N); 42 | changeBoard(board, num_placed, j, -1, N); 43 | } 44 | } 45 | return 0; 46 | } 47 | int board_[30][30]; 48 | int main() 49 | { 50 | int i; 51 | for (i = 1; i < 12; i++) { 52 | int sol_num; 53 | sol_num = 0; 54 | setQueen(board_, 0, &sol_num, i); 55 | printf("%d queen(s): ", i); 56 | printf("%d", sol_num); 57 | puts(""); 58 | } 59 | return 0; 60 | } -------------------------------------------------------------------------------- /test/nqueen6.c: -------------------------------------------------------------------------------- 1 | /* modified from https://rosettacode.org/wiki/N-queens_problem#C */ 2 | int printf(); int puts(); int count; 3 | int solve(int n, int col, int *hist) 4 | { 5 | if (col == n) { count++; return 0;} 6 | int i; int j; 7 | for (i = 0, j = 0; i < n; i++) { 8 | for (j = 0; j < col && hist[j] != i && (hist[j] - i) != col - j && 9 | (hist[j] - i) != j - col; j++) { 10 | } 11 | if (j < col) continue; 12 | hist[col] = i; solve(n, col + 1, hist); 13 | } 14 | return 0; 15 | } 16 | 17 | int main() 18 | { 19 | int hist[12]; int i; 20 | for (i = 1; i < 12; i++) { 21 | count = 0; solve(i, 0, hist); 22 | printf("%d queen%s: %d", i, i == 1 ? "" : "s", count); 23 | puts(""); 24 | } 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /test/nqueen7.c: -------------------------------------------------------------------------------- 1 | /* http://www.cc.kyoto-su.ac.jp/~yamada/ap/backtrack.html */ 2 | int printf(); int puts(); 3 | void changeBoard(int board[30][30], int i, int j, int d, int N) { 4 | int k; 5 | for (k = 0; k < N; k++) { board[i][k] += d; board[k][j] += d;} 6 | if (i > j) for (k = 0; k < N - (i - j); k++) 7 | board[k + (i - j)][k] += d; 8 | else for (k = 0; k < N - (j - i); k++) 9 | board[k][k + (j - i)] += d; 10 | if (i + j < N) for (k = 0; k <= i + j; k++) 11 | board[i + j - k][k] += d; 12 | else for (k = i + j - N + 1; k < N; k++) 13 | board[i + j - k][k] += d; 14 | return; 15 | } 16 | void setQueen(int board[30][30], int num_placed, int *ptr_sol_num, int N) { 17 | if (num_placed == N) { (*ptr_sol_num)++; return;} 18 | int j; for (j = 0; j < N; j++) 19 | if (board[num_placed][j] == 0) { 20 | changeBoard(board, num_placed, j, +1, N); 21 | setQueen(board, num_placed + 1, ptr_sol_num, N); 22 | changeBoard(board, num_placed, j, -1, N); 23 | } 24 | return; 25 | } 26 | int board_[30][30]; 27 | int main() { 28 | int i; for (i = 1; i < 12; i++) { 29 | int sol_num; sol_num = 0; setQueen(board_, 0, &sol_num, i); 30 | printf("%d queen(s): %d", i, sol_num); puts(""); 31 | } 32 | return 0; 33 | } -------------------------------------------------------------------------------- /test/nqueen8.c: -------------------------------------------------------------------------------- 1 | /* modified from https://rosettacode.org/wiki/N-queens_problem#C */ 2 | int printf(); int puts(); int count; 3 | int solve(int n, int col, int *hist) 4 | { 5 | if (col == n) { count += 1; return 0;} 6 | int i; int j; 7 | for (i = 0, j = 0; i < n; i++) { 8 | for (j = 0; j < col && hist[j] != i && (hist[j] - i) != col - j && 9 | (hist[j] - i) != j - col; j++) { 10 | } 11 | if (j < col) 12 | continue; 13 | hist[col] = i; solve(n, col + 1, hist); 14 | } 15 | return 0; 16 | } 17 | 18 | int main() 19 | { 20 | int hist[12]; int i; 21 | for (i = 1; i < 12; i++) { 22 | count = 0; solve(i, 0, hist); printf("%d queen(s): ", i); 23 | printf("%d", count); puts(""); 24 | } 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /test/preprocess.c: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | # 5 | # 6 | 7 | #define INT int 8 | 9 | INT main() 10 | { 11 | #define I INT 12 | #define main 13 | I k = 3; 14 | # 15 | main main main 16 | return main k - 3; 17 | #define k 18 | k main main k k main 19 | } 20 | # 21 | 22 | -------------------------------------------------------------------------------- /test/preprocess2.c: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | # 5 | # 6 | 7 | 8 | #define I INT 9 | #define INT int 10 | INT main() 11 | { 12 | #define main 13 | I k = 3; 14 | # 15 | main main main 16 | return main k - 3; 17 | #define k 18 | k main main k k main 19 | } 20 | # 21 | 22 | -------------------------------------------------------------------------------- /test/preprocess3.c: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | # 5 | # 6 | 7 | 8 | #define I INT 9 | #define INT int 10 | #define BEGIN { 11 | #define SEMICOLON ; 12 | #define PLUS + 13 | INT main() 14 | BEGIN 15 | #define main 16 | # define R 3 17 | # define Q R 18 | I k = Q SEMICOLON 19 | PLUS PLUS k SEMICOLON /* does not increment */ 20 | # 21 | main main main 22 | return main k - 3; 23 | #define k 24 | k main main k k main 25 | } 26 | # 27 | 28 | -------------------------------------------------------------------------------- /test/preprocess4.c: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | 4 | # 5 | # 6 | 7 | #define INT int 8 | 9 | #ifdef INT 10 | 11 | INT main() 12 | { 13 | #define I INT 14 | #define main 15 | #endif 16 | 17 | #ifndef BHUONJ 18 | I k = 3; 19 | # 20 | main main main 21 | return main k - 3; 22 | #define k 23 | k main main k k main 24 | } 25 | # 26 | #endif 27 | -------------------------------------------------------------------------------- /test/preprocess5.c: -------------------------------------------------------------------------------- 1 | #define A 2 | 3 | int main() 4 | { 5 | return 6 | #ifndef A 7 | 1 8 | #endif 9 | #ifdef A 10 | 0 11 | #endif 12 | ; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /test/quine.c: -------------------------------------------------------------------------------- 1 | int main() { char *s; s = "int main() { char *s; s = %c%s%c; printf(s, 34, s, 34); return 0;}"; printf(s, 34, s, 34); return 0;} -------------------------------------------------------------------------------- /test/quine2.c: -------------------------------------------------------------------------------- 1 | int main() { char *s = "int main() { char *s = %c%s%c; printf(s, 34, s, 34); return 0;}"; printf(s, 34, s, 34); return 0;} -------------------------------------------------------------------------------- /test/quine2_res.c: -------------------------------------------------------------------------------- 1 | int main() { char *s = "int main() { char *s = %c%s%c; printf(s, 34, s, 34); return 0;}"; printf(s, 34, s, 34); return 0;} -------------------------------------------------------------------------------- /test/quine_res.c: -------------------------------------------------------------------------------- 1 | int main() { char *s; s = "int main() { char *s; s = %c%s%c; printf(s, 34, s, 34); return 0;}"; printf(s, 34, s, 34); return 0;} -------------------------------------------------------------------------------- /test/small_struct.c: -------------------------------------------------------------------------------- 1 | int rand(void); 2 | int memcmp(); 3 | struct A1 {char a[1];}; struct A1 deref1(struct A1 *p){ return *p; } 4 | struct A2 {char a[2];}; struct A2 deref2(struct A2 *p){ return *p; } 5 | struct A3 {char a[3];}; struct A3 deref3(struct A3 *p){ return *p; } 6 | struct A4 {char a[4];}; struct A4 deref4(struct A4 *p){ return *p; } 7 | struct A5 {char a[5];}; struct A5 deref5(struct A5 *p){ return *p; } 8 | struct A6 {char a[6];}; struct A6 deref6(struct A6 *p){ return *p; } 9 | struct A7 {char a[7];}; struct A7 deref7(struct A7 *p){ return *p; } 10 | struct A8 {char a[8];}; struct A8 deref8(struct A8 *p){ return *p; } 11 | struct A9 {char a[9];}; struct A9 deref9(struct A9 *p){ return *p; } 12 | struct A10 {char a[10];}; struct A10 deref10(struct A10 *p) { return *p; } 13 | struct A11 {char a[11];}; struct A11 deref11(struct A11 *p) { return *p; } 14 | struct A12 {char a[12];}; struct A12 deref12(struct A12 *p) { return *p; } 15 | struct A13 {char a[13];}; struct A13 deref13(struct A13 *p) { return *p; } 16 | struct A14 {char a[14];}; struct A14 deref14(struct A14 *p) { return *p; } 17 | struct A15 {char a[15];}; struct A15 deref15(struct A15 *p) { return *p; } 18 | struct A16 {char a[16];}; struct A16 deref16(struct A16 *p) { return *p; } 19 | 20 | void garbge(void *p, int n){ 21 | char *q = p; 22 | for (int i = 0; i < n; i++) { 23 | q[i] = rand() % 37; 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | {struct A1 q; garbge(&q, 1); struct A1 r = deref1(&q); if (memcmp(&q, &r, 1)) return 1;} 30 | {struct A2 q; garbge(&q, 2); struct A2 r = deref2(&q); if (memcmp(&q, &r, 2)) return 2;} 31 | {struct A3 q; garbge(&q, 3); struct A3 r = deref3(&q); if (memcmp(&q, &r, 3)) return 3;} 32 | {struct A4 q; garbge(&q, 4); struct A4 r = deref4(&q); if (memcmp(&q, &r, 4)) return 4;} 33 | {struct A5 q; garbge(&q, 5); struct A5 r = deref5(&q); if (memcmp(&q, &r, 5)) return 5;} 34 | {struct A6 q; garbge(&q, 6); struct A6 r = deref6(&q); if (memcmp(&q, &r, 6)) return 6;} 35 | {struct A7 q; garbge(&q, 7); struct A7 r = deref7(&q); if (memcmp(&q, &r, 7)) return 7;} 36 | {struct A8 q; garbge(&q, 8); struct A8 r = deref8(&q); if (memcmp(&q, &r, 8)) return 8;} 37 | {struct A9 q; garbge(&q, 9); struct A9 r = deref9(&q); if (memcmp(&q, &r, 9)) return 9;} 38 | {struct A10 q; garbge(&q, 10); struct A10 r = deref10(&q); if (memcmp(&q, &r, 10)) return 10;} 39 | {struct A11 q; garbge(&q, 11); struct A11 r = deref11(&q); if (memcmp(&q, &r, 11)) return 11;} 40 | {struct A12 q; garbge(&q, 12); struct A12 r = deref12(&q); if (memcmp(&q, &r, 12)) return 12;} 41 | {struct A13 q; garbge(&q, 13); struct A13 r = deref13(&q); if (memcmp(&q, &r, 13)) return 13;} 42 | {struct A14 q; garbge(&q, 14); struct A14 r = deref14(&q); if (memcmp(&q, &r, 14)) return 14;} 43 | {struct A15 q; garbge(&q, 15); struct A15 r = deref15(&q); if (memcmp(&q, &r, 15)) return 15;} 44 | {struct A16 q; garbge(&q, 16); struct A16 r = deref16(&q); if (memcmp(&q, &r, 16)) return 16;} 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /test/vector_test.c: -------------------------------------------------------------------------------- 1 | struct Vector { 2 | int length; 3 | int capacity; 4 | void **vector; 5 | }; 6 | struct Vector *init_vector_(); 7 | void extend_vector(); 8 | void push_vector(); 9 | void *pop_vector(); 10 | struct Vector init_vector(); 11 | 12 | void *calloc(); 13 | void *realloc(); 14 | 15 | struct Vector *init_vector_(void) 16 | { 17 | struct Vector *ptr_res; 18 | ptr_res = calloc(1, sizeof(struct Vector)); 19 | ptr_res->length = 0; 20 | ptr_res->capacity = 256; 21 | ptr_res->vector = calloc(ptr_res->capacity, sizeof(void *)); 22 | return ptr_res; 23 | } 24 | 25 | void extend_vector(struct Vector *ptr) 26 | { 27 | if (ptr->capacity < ptr->length + 1) { 28 | ptr->vector = 29 | realloc(ptr->vector, ptr->capacity * 2 * sizeof(void *)); 30 | 31 | ptr->capacity *= 2; 32 | } 33 | } 34 | 35 | void push_vector(struct Vector *ptr, void *tok) 36 | { 37 | extend_vector(ptr); 38 | ptr->vector[ptr->length] = tok; 39 | ++(ptr->length); 40 | } 41 | 42 | void *pop_vector(struct Vector *ptr) 43 | { 44 | if (ptr->length == 0) { 45 | /*assert("tried to pop an empty vector of type `void*`" && 0);*/ 46 | } 47 | --(ptr->length); 48 | return ptr->vector[ptr->length]; /* safe, since it is not yet released or 49 | anything */ 50 | } 51 | -------------------------------------------------------------------------------- /test/vector_test2.c: -------------------------------------------------------------------------------- 1 | struct Vector { 2 | int length; 3 | int capacity; 4 | void **vector; 5 | }; 6 | struct Vector *init_vector_(); void extend_vector(); 7 | void push_vector(); void *pop_vector(); struct Vector init_vector(); 8 | void *calloc(); void *realloc(); 9 | 10 | struct Vector *init_vector_(void) 11 | { 12 | struct Vector *ptr_res; 13 | ptr_res = calloc(1, sizeof(struct Vector)); 14 | ptr_res->length = 0; 15 | ptr_res->capacity = 256; 16 | ptr_res->vector = calloc(ptr_res->capacity, sizeof(void *)); 17 | return ptr_res; 18 | } 19 | 20 | void extend_vector(struct Vector *ptr) 21 | { 22 | if (ptr->capacity < ptr->length + 1) { 23 | ptr->vector = 24 | realloc(ptr->vector, ptr->capacity * 2 * sizeof(void *)); 25 | ptr->capacity *= 2; 26 | } 27 | } 28 | void push_vector(struct Vector *ptr, void *tok) { 29 | extend_vector(ptr); ptr->vector[(ptr->length)++] = tok; 30 | } 31 | void *pop_vector(struct Vector *ptr) {return ptr->vector[--(ptr->length)]; } 32 | -------------------------------------------------------------------------------- /test/vector_test3.c: -------------------------------------------------------------------------------- 1 | struct Vector { 2 | int length; 3 | int capacity; 4 | const void **vector; 5 | }; 6 | struct Vector *init_vector_(); 7 | void extend_vector(); 8 | void push_vector(); 9 | const void *pop_vector(); 10 | 11 | void *calloc(); 12 | void *realloc(); 13 | 14 | struct Vector *init_vector_(void) 15 | { 16 | struct Vector *ptr_res; ptr_res = calloc(1, sizeof(struct Vector)); 17 | ptr_res->length = 0; 18 | ptr_res->capacity = 256; 19 | ptr_res->vector = calloc(ptr_res->capacity, sizeof(void *)); 20 | return ptr_res; 21 | } 22 | 23 | void extend_vector(struct Vector *ptr) 24 | { 25 | if (ptr->capacity < ptr->length + 1) { 26 | ptr->vector = 27 | realloc(ptr->vector, ptr->capacity * 2 * sizeof(void *)); 28 | 29 | ptr->capacity *= 2; 30 | } 31 | } 32 | 33 | void push_vector(struct Vector *ptr, const void *tok) 34 | { 35 | extend_vector(ptr); 36 | ptr->vector[ptr->length] = tok; 37 | ++(ptr->length); 38 | } 39 | 40 | const void *pop_vector(struct Vector *ptr) 41 | { 42 | if (ptr->length == 0) { 43 | /*assert("tried to pop an empty vector of type `void*`" && 0);*/ 44 | } 45 | --(ptr->length); 46 | return ptr->vector[ptr->length]; /* safe, since it is not yet released or 47 | anything */ 48 | } 49 | 50 | -------------------------------------------------------------------------------- /test/vector_test4.c: -------------------------------------------------------------------------------- 1 | struct Vector { 2 | int length; 3 | int capacity; 4 | const void **vector; 5 | }; 6 | struct Vector *init_vector_(); 7 | void extend_vector(); 8 | void push_vector(); 9 | const void *pop_vector(); 10 | 11 | void *calloc(); 12 | void *realloc(); 13 | 14 | struct Vector *init_vector_(void) 15 | { 16 | struct Vector *ptr_res = calloc(1, sizeof(struct Vector)); 17 | ptr_res->length = 0; 18 | ptr_res->capacity = 256; 19 | ptr_res->vector = calloc(ptr_res->capacity, sizeof(void *)); 20 | return ptr_res; 21 | } 22 | 23 | void extend_vector(struct Vector *ptr) 24 | { 25 | if (ptr->capacity < ptr->length + 1) { 26 | ptr->vector = 27 | realloc(ptr->vector, ptr->capacity * 2 * sizeof(void *)); 28 | 29 | ptr->capacity *= 2; 30 | } 31 | } 32 | 33 | void push_vector(struct Vector *ptr, const void *tok) 34 | { 35 | extend_vector(ptr); 36 | ptr->vector[ptr->length] = tok; 37 | ++(ptr->length); 38 | } 39 | 40 | const void *pop_vector(struct Vector *ptr) 41 | { 42 | if (ptr->length == 0) { 43 | /*assert("tried to pop an empty vector of type `void*`" && 0);*/ 44 | } 45 | --(ptr->length); 46 | return ptr->vector[ptr->length]; /* safe, since it is not yet released or 47 | anything */ 48 | } 49 | 50 | -------------------------------------------------------------------------------- /test_cases_that_are_compile_error_only_if_pedantic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | test_failure_when_pedantic() { 3 | ./out/compiler.out $1 -pedantic > /dev/null 4 | res=$? 5 | if [ $res -eq 0 ]; then { echo -e "\033[31mFAIL\033[m"; exit 1; }; else echo -e "\033[32mPASS\033[m"; fi 6 | } 7 | 8 | run_test_without_pedantic() { 9 | ./out/compiler.out $2 > s/full_compile$1.s 10 | gcc s/full_compile$1.s -o out/task$1.out -no-pie -Wno-unused-command-line-argument 11 | ./out/task$1.out 12 | res=$? 13 | if [ $res -ne $3 ]; then { echo "got:" $res; echo "expected:" $3; echo -e "\033[31mFAIL\033[m, at test case" $1: $2; exit 1; }; else echo -e "\033[32mPASS\033[m"; fi 14 | } 15 | 16 | test() { 17 | echo "With -pedantic:" 18 | test_failure_when_pedantic $2 19 | echo "Without -pedantic:" 20 | run_test_without_pedantic $1 $2 $3 21 | } 22 | 23 | test 5555 test/error_if_pedantic/toplevel_semicolon.c 0 24 | test 5556 test/error_if_pedantic/backslash_e.c 27 25 | test 5557 test/error_if_pedantic/binary_literal.c 3 -------------------------------------------------------------------------------- /test_compile_error.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | test() { 3 | echo -e $1 | ./out/compiler.out > /dev/null 4 | res=$? 5 | if [ $res -eq 0 ]; then { echo -e "\033[31mFAIL\033[m"; exit 1; }; else echo -e "\033[32mPASS\033[m"; fi 6 | } 7 | 8 | test 'int main(){int a; {int b;} return b;}' 9 | test 'int main(){main(1}' 10 | test 'int main(){return (123}' 11 | test 'int main(){return 123}' 12 | test 'int main(){if a}' 13 | test 'int main(){do {}}' 14 | test 'int main(){do {}while}' 15 | test 'int main(){do {}while(}' 16 | test 'int main(){do {}while(1}' 17 | test 'int main(){do {}while(1)}' 18 | test 'int main(){do {}while();}' 19 | test 'int main(){while}' 20 | test 'int main(){while(}' 21 | test 'int main(){while()}' 22 | test 'int main(){while(1}' 23 | test 'int main(){while(1)}' 24 | test 'int main(){while(1){break}}' 25 | test 'int main(){break;}' 26 | test 'int main(){while(1){continue}}' 27 | test 'int main(){continue;}' 28 | test 'int main(){for}' 29 | test 'int main(){for(}' 30 | test 'int main(){for(1)}' 31 | test 'int main(){for(1;1)}' 32 | test 'int main(){for(1;1;1)}' 33 | test 'int main(){for(1;1;1}' 34 | test 'int main(){1}' 35 | test 'int main(' 36 | test 'int main(int a' 37 | test 'int main(){int a; {int b;} return b;}' 38 | test 'int main() {int a; int *b; b = a; return a;}' 39 | test 'int main() {int a; int *b; 1? b : a; return a;}' 40 | test 'int main() {int a; *a;}' 41 | test 'int main(){int x; int *y; y = &x;int **z; z = y;}' 42 | test 'int main(){int x; int *y; y = &x; **y;}' 43 | test 'int main(){int x;int *y;*y = &x; return x;}' 44 | test 'int main(){int x; int *y; y = &x;int **z; *z = x;}' 45 | test 'int *foo(){return 1;}int main(){return 0;}' 46 | test 'int *foo(){int x; return x;}int main(){return 0;}' 47 | test 'int foo(){int *x; return x;}int main(){return 0;}' 48 | test 'int *foo(){int *x; return x;}int main(){return foo();}' 49 | test 'int *foo(){int *x; return x;}int main(){int x; x= foo();}' 50 | test 'int main(){int *x; int *y; x+y;}' 51 | test 'int main(){int *p; int a[4][1][2]; p = a;}' 52 | test 'int main(){int a[1]; int *b; a = b;}' 53 | test 'int main(){return 1[2];}' 54 | test 'int main(){ foo: int a; return a;}' 55 | test 'struct A{int a; int b;}; int main(){struct A a; if(a){return 12;} return 3;}' 56 | test 'struct A{int a; int b;}; int main(){struct A a; for(;a;){return 12;} return 3;}' 57 | test 'struct A{int a; int b;}; int main(){struct A a; while(a){return 12;} return 3;}' 58 | test 'struct A{int a; int b;}; int main(){struct A a; do{return 12;}while(a); return 3;}' 59 | test 'int main(){case 5: return 0;}' 60 | test 'int main(){default: return 0;}' 61 | test 'int main const(){return const 123 const; const} const' 62 | test 'int main(void){void *p = 0; p += 3;}' 63 | test 'int main(void){char a[5]; a[1] = 74; int *p = a + 3; p -= 2; return *p;}' 64 | test 'int a(); char *a(); int main(void){return 174;}' 65 | test 'int a(void); int a(int b); int main(void){return 174;}' 66 | test 'struct A{int a; int b;}; int main(){struct A a; struct A b; b *= a; return 3;}' 67 | test 'struct A{int a; int b;}; int main(){struct A a; struct A b; b || a; return 3;}' 68 | test 'int main(){3(); return 3;}' 69 | test 'int main(){int a; (a)(); return 3;}' 70 | test 'int main(){int *p = 0; (*p)(); return 3;}' 71 | test 'int main(){int *p = 0; (p)(); return 3;}' 72 | test 'int f(int a); int f(int a){return a;} int main(){int a; f(&a); return 3;}' 73 | test 'int main(){goto; return 3; }' 74 | test 'int main(){goto 3; return 3;}' 75 | test 'int main(){goto a; return 3;}' 76 | test 'int main(){goto a; return 3;} int f(){a: return 0;}' 77 | test 'struct A{int x; int y;}; struct B{int y; int x; }; int main(){struct A a; struct B b; (1? a : b).x; return 3;}' 78 | test 'int main(){ return sizeof(int()); }' 79 | test 'struct A; int main(){ return sizeof(struct A); }' 80 | test 'int main(){ return _Alignof(int()); }' 81 | test 'struct A; int main(){ return _Alignof(struct A); }' 82 | test 'struct A{int x; int y;}; int main() {struct A a; return 3 - a; }' 83 | test 'struct A{int a;}; int main() { struct A x; struct A y; struct A z; y.a = 100; z.a = 2; (x = y) = z; return 0; }' 84 | test 'struct A{int a;}; int main() { struct A x; struct A y; y.a = 100; &(x = y); return 0; }' 85 | test 'struct A{int a;}; int main() { struct A x; x.a = 20; struct A y; y.a = 100; &(1?x : y); return 0; }' 86 | test 'int a[2](void); int main() { return 0; }' 87 | test 'int(*a)[2](void); int main() { a; return 0; }' 88 | test 'int(test())(void); int main() { return 0; }' 89 | test 'int test()[3]; int main() { return 0; }' -------------------------------------------------------------------------------- /toplevel.h: -------------------------------------------------------------------------------- 1 | #include "analyzer.h" 2 | #include "printerstate.h" 3 | 4 | struct ToplevelFuncInfo { 5 | struct Statement sta; 6 | struct Vector /**/ offsets_and_types; 7 | struct Type ret_type; 8 | int capacity; 9 | int is_static_function; 10 | 11 | /* valid only when ret_type is a struct/union */ 12 | enum SystemVAbiClass abi_class; 13 | int ret_struct_or_union_size; 14 | 15 | /* valid only when ret_type is a struct/union of MEMORY_CLASS */ 16 | int hidden_var_offset; 17 | 18 | /* initialized if the function has variable args */ 19 | int is_va; 20 | }; 21 | 22 | enum ToplevelCategory { 23 | TOPLEVEL_VAR_DEFINITION, 24 | TOPLEVEL_FUNCTION_DEFINITION, 25 | TOPLEVEL_FUNCTION_DECLARATION, 26 | }; 27 | 28 | struct Toplevel { 29 | enum ToplevelCategory category; 30 | const char *declarator_name; 31 | /* NULL when TOPLEVEL_VAR_DEFINITION does not have an identifier */ 32 | 33 | struct Type declarator_type; 34 | /* used when it is TOPLEVEL_VAR_DEFINITION or TOPLEVEL_TYPE_DECLARATION */ 35 | 36 | struct ToplevelFuncInfo func; 37 | 38 | int size_of_declarator_type; 39 | int is_extern_global_var; 40 | }; 41 | 42 | void generate(const struct Vector /**/ *ref_vec); 43 | struct Vector /**/ parse(const struct Token *tokvec); 44 | 45 | struct SourceLabelAndAssemblyLabel { 46 | int assembly_label; 47 | struct SourceLabel source_label; 48 | }; 49 | void print_statement(struct PrinterState *ptr_prs, 50 | const struct Statement *ptr_sta); 51 | void codegen_switch(struct PrinterState *ptr_prs, 52 | const struct Statement *ptr_sta); 53 | 54 | void main2(const struct Token *tokvec); 55 | -------------------------------------------------------------------------------- /type.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | 5 | struct Type INT_TYPE() { 6 | struct Type t; 7 | t.type_category = INT_; 8 | return t; 9 | } 10 | 11 | struct Type 12 | CHAR_TYPE() { 13 | struct Type t; 14 | t.type_category = CHAR_; 15 | return t; 16 | } 17 | 18 | int is_struct_or_union(const struct Type *t) 19 | { 20 | return t->type_category == STRUCT_NOT_UNION || t->type_category == UNION; 21 | } 22 | 23 | int size_of_basic(const struct Type *ref_type, const char *msg) 24 | { 25 | switch (ref_type->type_category) { 26 | case INT_: 27 | case ENUM_: 28 | return 4; 29 | case PTR_: 30 | return 8; 31 | case CHAR_: 32 | return 1; 33 | case ARRAY: 34 | case FN: 35 | case STRUCT_NOT_UNION: 36 | case UNION: 37 | fprintf( 38 | stderr, 39 | "array, function, struct, or union type is not a basic type.\n"); 40 | fprintf(stderr, "context: %s\n", msg); 41 | exit(EXIT_FAILURE); 42 | case VOID_: 43 | fprintf(stderr, "size of `void` is never known\n"); 44 | fprintf(stderr, "context: %s\n", msg); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | fprintf(stderr, 49 | "****************************\n" 50 | "* INTERNAL COMPILER ERROR @ %s\n" 51 | "* Unexpected value of TypeCategory: `ref_type->type_category` is `%d`\n" 52 | "****************************\n", 53 | __func__, ref_type->type_category); 54 | exit(EXIT_FAILURE); 55 | } 56 | 57 | void debug_print_type(const struct Type *ref_type) 58 | { 59 | struct Type type = *ref_type; 60 | switch (type.type_category) { 61 | case PTR_: 62 | fprintf(stderr, "pointer to "); 63 | debug_print_type(type.derived_from); 64 | return; 65 | case VOID_: 66 | fprintf(stderr, "void"); 67 | return; 68 | case INT_: 69 | fprintf(stderr, "int"); 70 | return; 71 | case CHAR_: 72 | fprintf(stderr, "char"); 73 | return; 74 | case STRUCT_NOT_UNION: 75 | fprintf(stderr, "struct %s", type.s.struct_or_union_tag); 76 | return; 77 | case UNION: 78 | fprintf(stderr, "union %s", type.s.struct_or_union_tag); 79 | return; 80 | case ENUM_: 81 | fprintf(stderr, "enum %s", type.e.enum_tag); 82 | return; 83 | case ARRAY: 84 | fprintf(stderr, "array (length %d) of ", type.array_length); 85 | debug_print_type(type.derived_from); 86 | return; 87 | case FN: 88 | fprintf(stderr, "function ("); 89 | switch (type.param_infos_validity) { 90 | case INVALID: { 91 | fprintf(stderr, "param: no info"); 92 | break; 93 | } 94 | case VALID: { 95 | if (type.param_infos.length == 0) { 96 | fprintf(stderr, "no params"); 97 | } else if (type.param_infos.length < 2) { 98 | const struct TypeAndIdent *vec_0 = type.param_infos.vector[0]; 99 | fprintf(stderr, 100 | "%s: ", vec_0->ident_str ? vec_0->ident_str : "@anon"); 101 | debug_print_type(&vec_0->type); 102 | } else { 103 | fprintf(stderr, "params: \n"); 104 | for (int i = 0; i < type.param_infos.length; i++) { 105 | const struct TypeAndIdent *ptr_paraminfo = 106 | type.param_infos.vector[i]; 107 | fprintf(stderr, " %s: ", 108 | ptr_paraminfo->ident_str ? ptr_paraminfo->ident_str 109 | : "@anon"); 110 | debug_print_type(&ptr_paraminfo->type); 111 | fprintf(stderr, "\n"); 112 | } 113 | } 114 | break; 115 | } 116 | case VA_ARGS: { 117 | if (type.param_infos.length == 0) { 118 | fprintf(stderr, "no params varg"); 119 | } else { 120 | fprintf(stderr, "params: \n"); 121 | for (int i = 0; i < type.param_infos.length; i++) { 122 | const struct TypeAndIdent *ptr_paraminfo = 123 | type.param_infos.vector[i]; 124 | fprintf(stderr, " %s: ", 125 | ptr_paraminfo->ident_str ? ptr_paraminfo->ident_str 126 | : "@anon"); 127 | debug_print_type(&ptr_paraminfo->type); 128 | fprintf(stderr, "\n"); 129 | } 130 | fprintf(stderr, ", ..."); 131 | } 132 | break; 133 | } 134 | } 135 | fprintf(stderr, ") returning "); 136 | debug_print_type(type.derived_from); 137 | } 138 | } 139 | 140 | struct Type deref_type(const struct Type *ref_type) 141 | { 142 | if (ref_type->type_category == PTR_) { 143 | return *ref_type->derived_from; 144 | } 145 | 146 | fprintf(stderr, "Unmatched type: expected a pointer, but got `"); 147 | debug_print_type(ref_type); 148 | fprintf(stderr, "`.\n"); 149 | exit(EXIT_FAILURE); 150 | } 151 | 152 | void if_array_convert_to_ptr_(struct Type *ptr_type) 153 | { 154 | if (ptr_type->type_category == ARRAY) { 155 | ptr_type->type_category = PTR_; 156 | } 157 | } 158 | 159 | struct Type ptr_to_type(const struct Type *ref_type) 160 | { 161 | struct Type *ptr_type = calloc(1, sizeof(struct Type)); 162 | *ptr_type = *ref_type; 163 | struct Type type; 164 | type.type_category = PTR_; 165 | type.derived_from = ptr_type; 166 | return type; 167 | } 168 | 169 | struct Type arr_of_type(const struct Type *ref_type, int length) 170 | { 171 | struct Type *ptr_type = calloc(1, sizeof(struct Type)); 172 | *ptr_type = *ref_type; 173 | 174 | struct Type type; 175 | type.type_category = ARRAY; 176 | type.derived_from = ptr_type; 177 | type.array_length = length; 178 | return type; 179 | } 180 | -------------------------------------------------------------------------------- /vector.c: -------------------------------------------------------------------------------- 1 | #include "vector.h" 2 | #include "std.h" 3 | #include "std_io.h" 4 | 5 | struct Vector init_vector(void) { return *init_vector_(); } 6 | 7 | struct Vector *init_vector_(void) 8 | { 9 | struct Vector *ptr_res = calloc(1, sizeof(struct Vector)); 10 | ptr_res->length = 0; 11 | ptr_res->capacity = 256; 12 | ptr_res->vector = calloc(ptr_res->capacity, sizeof(void *)); 13 | return ptr_res; 14 | } 15 | 16 | void extend_vector(struct Vector *ptr) 17 | { 18 | if (ptr->capacity < ptr->length + 1) { 19 | ptr->vector = 20 | realloc(ptr->vector, ptr->capacity * 2 * sizeof(void *)); 21 | 22 | ptr->capacity *= 2; 23 | } 24 | } 25 | 26 | void push_vector(struct Vector *ptr, const void *tok) 27 | { 28 | extend_vector(ptr); 29 | ptr->vector[ptr->length] = tok; 30 | ++(ptr->length); 31 | } 32 | 33 | const void *pop_vector(struct Vector *ptr) 34 | { 35 | if (ptr->length == 0) { 36 | assert("tried to pop an empty vector" && 0); 37 | } 38 | --(ptr->length); 39 | return ptr->vector[ptr->length]; /* safe, since it is not yet released or 40 | anything */ 41 | } 42 | 43 | void concat_vector(struct Vector *ptr_ans, const struct Vector *ptr_vec) 44 | { 45 | if (!ptr_ans) { 46 | fprintf(stderr, "NULL POINTER IN THE FIRST ARGUMENT\n"); 47 | exit(1); 48 | } 49 | 50 | if (!ptr_vec) { 51 | fprintf(stderr, "NULL POINTER IN THE SECOND ARGUMENT\n"); 52 | exit(1); 53 | } 54 | 55 | if (!ptr_vec->vector) { 56 | fprintf(stderr, "OH MY GOD: INVALID VECTOR IN THE SECOND ARGUMENT\n"); 57 | exit(1); 58 | } 59 | 60 | for (int i = 0; i < ptr_vec->length; i++) { 61 | push_vector(ptr_ans, ptr_vec->vector[i]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vector.h: -------------------------------------------------------------------------------- 1 | struct Vector { 2 | int length; 3 | int capacity; 4 | const void **vector; 5 | }; 6 | struct Vector *init_vector_(void); 7 | void extend_vector(struct Vector *ptr); 8 | void push_vector(struct Vector *ptr, const void *tok); 9 | const void *pop_vector(struct Vector *ptr); 10 | struct Vector init_vector(void); 11 | void concat_vector(struct Vector *ptr_ans, const struct Vector *vec); 12 | -------------------------------------------------------------------------------- /verifier/typeparse_checker.c: -------------------------------------------------------------------------------- 1 | #include "../header.h" 2 | #include 3 | #include 4 | 5 | struct UntypedExpr parse_assignment_expression(const struct Token **ptr_tokvec) 6 | { 7 | exit(EXIT_FAILURE); 8 | } 9 | 10 | void check_declaration(const char *str) 11 | { 12 | fprintf(stderr, "Parsing: %s\n", str); 13 | struct Vector vec = init_vector(); 14 | const struct Token *tokvec = read_and_preprocess(str, &vec); 15 | 16 | ++tokvec; /* skip the dummy token BEGINNING */ 17 | 18 | const char *ident_str; 19 | struct Type type = parse_struct_declaration(&tokvec, &ident_str); 20 | 21 | fprintf(stderr, "%s: ", ident_str); 22 | debug_print_type(&type); 23 | fprintf(stderr, "\n\n"); 24 | return; 25 | } 26 | 27 | void check_typename(const char *str) 28 | { 29 | fprintf(stderr, "Parsing: %s\n", str); 30 | struct Vector vec = init_vector(); 31 | const struct Token *tokvec = read_and_preprocess(str, &vec); 32 | 33 | ++tokvec; /* skip the dummy token BEGINNING */ 34 | 35 | struct Type type = parse_type_name(&tokvec); 36 | 37 | fprintf(stderr, "typename: "); 38 | debug_print_type(&type); 39 | fprintf(stderr, "\n\n"); 40 | return; 41 | } 42 | 43 | int main() 44 | { 45 | check_declaration("int **argv"); 46 | check_declaration("int (*(*argv))"); 47 | check_declaration("int arr[13]"); 48 | check_declaration("int (*daytab)[13]"); 49 | check_declaration("int (*(*x[3])[2])[4]"); 50 | check_declaration("int (*(*x())[2])()"); 51 | check_declaration("int *comp()"); 52 | check_declaration("int (*comp)()"); 53 | check_declaration("int (*(*x())[2])()"); 54 | check_declaration("int atexit(int (*func)(int a))"); 55 | check_declaration("int (*signal(int sig, int (*func)(int a)))(int b)"); 56 | check_declaration("char **argv"); 57 | check_declaration("char (*(*argv))"); 58 | check_declaration("char arr[13]"); 59 | check_declaration("char (*daytab)[13]"); 60 | check_declaration("char (*(*x[3])[2])[4]"); 61 | check_declaration("int atexit(int (*func)(int))"); 62 | check_declaration("int (*signal(int, int (*func)(int)))(int)"); 63 | check_declaration("int *comp(int a, int b, ...)"); 64 | 65 | check_typename("int **"); 66 | check_typename("int [13]"); 67 | check_typename("int (*)[13]"); 68 | check_typename("int (*(*[3])[2])[4]"); 69 | check_typename("int (*(*())[2])()"); 70 | check_typename("int *()"); 71 | check_typename("int (*)()"); 72 | check_typename("int (*(*())[2])()"); 73 | check_typename("int (int (*func)(int a))"); 74 | check_typename("int (int (*func)(int))"); 75 | check_typename("int (*(int sig, int (*func)(int a)))(int b)"); 76 | check_typename("int (*(int, int (*func)(int)))(int)"); 77 | return 0; 78 | } 79 | --------------------------------------------------------------------------------