├── .clang-format ├── .gitignore ├── LICENSE ├── Makefile ├── README.ja.md ├── README.md ├── analysis.c ├── containers.c ├── cppsamples ├── Makefile ├── test1.cpp ├── test2.cpp ├── test3.cpp ├── test4.cpp ├── test5.cpp ├── test6.cpp └── test7.cpp ├── foo.c ├── gen_x64.c ├── main.c ├── main.h ├── preprocess.c ├── samples ├── 1.c ├── 10.c ├── 11.c ├── 11_min.c ├── 12.c ├── 13.c ├── 14.c ├── 15.c ├── 16.c ├── 18.c ├── 19.c ├── 2.c ├── 3.c ├── 31.c ├── 32.c ├── 33.c ├── 34.c ├── 35.bash ├── 35.c ├── 36.bash ├── 36.c ├── 37.c ├── 38.c ├── 39.c ├── 4.c ├── 41.c ├── 5.c ├── 6.c ├── 7.c ├── 8.c ├── 9.c └── Makefile ├── selfhost.h ├── stabs ├── 1.c └── 1.s ├── test.c ├── test.sh ├── testfdef.sh ├── testfunccall.sh ├── token.c └── util.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | IndentWidth: 3 3 | IndentCaseLabels: true 4 | SpacesInSquareBrackets: false 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 | # orginal 55 | tmp.s 56 | tmp 57 | hanando 58 | 59 | samples/*.s 60 | samples/1 61 | samples/2 62 | samples/3 63 | samples/4 64 | samples/5 65 | samples/6 66 | samples/7 67 | samples/8 68 | samples/9 69 | samples/10 70 | samples/11 71 | samples/12 72 | samples/13 73 | samples/15 74 | samples/14 75 | 76 | main 77 | main.s 78 | main2.s 79 | main2 80 | main3.s 81 | main3 82 | sample 83 | 84 | main2.c 85 | samples/17 86 | samples/17.c 87 | samples/18 88 | samples/19 89 | samples/31 90 | samples/41 91 | test.s 92 | test 93 | 94 | cppsamples/*.s 95 | cppsamples/test1 96 | cppsamples/test2 97 | cppsamples/test3 98 | cppsamples/test4 99 | cppsamples/test5 100 | cppsamples/test6 101 | samples/32 102 | samples/34 103 | samples/34.s 104 | samples/35_hanando 105 | samples/35_gcc 106 | samples/36_hanando 107 | samples/36_gcc 108 | samples/37 109 | samples/39 110 | samples/39*.s 111 | 112 | cppsamples/test5 113 | cppsamples/test7 114 | 115 | hanandoO0 116 | hanandoO1 117 | hanandoO3 118 | tmp.c 119 | tmp.cpp 120 | 121 | test.processed.c 122 | 123 | *2.s 124 | *3.s 125 | 126 | hanando2 127 | hanando3 128 | 129 | diff.diff 130 | hanandoold 131 | hanandonew 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 OR CC0-1.0 2 | 3 | CC = gcc 4 | CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g 5 | LDFLAGS = -lm 6 | 7 | #srcs = $(wildcard *.c) 8 | srcs = main.c preprocess.c token.c analysis.c gen_x64.c containers.c util.c 9 | # parse_c.c parse_cpp.c 10 | asms = $(srcs:.c=.s) 11 | asmself = $(srcs:.c=2.s) 12 | asmselfself = $(srcs:.c=3.s) 13 | objects = $(srcs:.c=.o) 14 | #objectself = $(srcs:.c=2.o) 15 | objectselfself = $(srcs:.c=3.o) 16 | target=hanando 17 | 18 | $(target): $(srcs) 19 | $(CC) $(CFLAGS) $(srcs) -o $(target) $(LDFLAGS) 20 | $(srcs): main.h 21 | 22 | self: $(asmself) 23 | $(CC) -g $(asmself) -o ./hanando2 24 | 25 | %2.s: %.c $(target) 26 | ./hanando -f $< > $@ 27 | 28 | %3.s: %.c self 29 | ./hanando2 -f $< > $@ 30 | 31 | selfself: $(asmselfself) 32 | $(CC) -g $(asmselfself) -o ./hanando3 33 | 34 | selftest: self selfself 35 | diff hanando2 hanando3 36 | 37 | ctest: 38 | clang -E test.c | sed -e "s/^#.*$///" > test.processed.c && ./hanando -f test.processed.c > test.s && gcc test.s -o test && ./test 39 | 40 | test: test1 test2 test3 test4 \ 41 | test5 test6 test7 test8 test9 \ 42 | test10 test11 test19 test12 test13 test14\ 43 | test15 test16 test17 test18 test20 test21\ 44 | test22 test23 test24 test25 test26 test27\ 45 | test28 test30 test29 test31 test34 test35\ 46 | test36 test32 test33 test37 test38 47 | + make -C samples/ 48 | + make -C cppsamples/ 49 | 50 | test1: 51 | sh testfdef.sh 'int main() {return 1;}' 1 52 | sh testfdef.sh 'int main() {return 1+9;}' 10 53 | sh testfdef.sh 'int main() {return 13-9;}' 4 54 | sh testfdef.sh 'int main() {return 0x1F;}' 31 55 | sh testfdef.sh 'int main() {return 0X04;}' 4 56 | sh testfdef.sh 'int main() {return 0Xff;}' 255 57 | sh testfdef.sh 'int main() {int; return 2;}' 2 58 | sh testfdef.sh 'int main() {1; 2; 3; 4; 5; 6; 7; 8; return 2;}' 2 59 | 60 | test2: 61 | sh testfdef.sh 'int main() {return 1*9;}' 9 62 | sh testfdef.sh 'int main() {return 18/9;}' 2 63 | sh testfdef.sh 'int main() {return (11-9)*34;}' 68 64 | sh testfdef.sh 'int main() {int a;a=3;return a;}' 3 65 | sh testfdef.sh 'int main() {int X;X=3;return X;}' 3 66 | sh testfdef.sh 'int main() {int ce;ce=3;return ce;}' 3 67 | sh testfdef.sh 'int main() {int DE;DE=2;return DE;}' 2 68 | 69 | test3: 70 | sh testfdef.sh "int main(){return 3==3;}" 1 71 | sh testfdef.sh "int main(){return 3==4;}" 0 72 | sh testfdef.sh "int main(){return 3!=3+8;}" 1 73 | sh testfdef.sh "int main(){{return 3;}}" 3 74 | sh testfdef.sh "int main(){return !(2==2);}" 0 75 | sh testfdef.sh "int main(){return 4==2;}" 0 76 | sh testfdef.sh "int main(){return !(4==2);}" 1 77 | 78 | test4: 79 | sh testfunccall.sh 'int main(){return func(4);}' OK4 4 80 | sh testfunccall.sh 'int main(){return foo(4,4);}' 8 0 81 | 82 | test5: 83 | # to avoid printf %% 84 | sh testfdef.sh 'int main(){return 6 %%3;}' 0 85 | sh testfdef.sh 'int main(){return 5 %%4;}' 1 86 | sh testfdef.sh 'int main(){return 1^0;}' 1 87 | sh testfdef.sh 'int main(){return 1^1;}' 0 88 | sh testfdef.sh 'int main(){return 3^2;}' 1 89 | 90 | test6: 91 | sh testfdef.sh 'int main(){return 6|3;}' 7 92 | sh testfdef.sh 'int main(){return 1|0;}' 1 93 | sh testfdef.sh 'int main(){return 1&0;}' 0 94 | sh testfdef.sh 'int main(){return 1<<1;}' 2 95 | sh testfdef.sh 'int main(){return 1<<0;}' 1 96 | sh testfdef.sh 'int main(){return 1>>1;}' 0 97 | 98 | test7: 99 | sh testfdef.sh "int main(){ int a;a=1;a-=1;return a ;}" 0 100 | sh testfdef.sh "int main(){ int a,b;a=2;b=3;return a==b;}" 0 101 | sh testfdef.sh "int main(){ int a;a=1;a+=1;return a ;}" 2 102 | sh testfdef.sh "int main(){ int a;a=1;a<<=1;return a;}" 2 103 | sh testfdef.sh "int main(){ int a;a=2;a>>=1;return a;}" 1 104 | sh testfdef.sh "int main(){ int a;a=3;a*=2;return a ;}" 6 105 | sh testfdef.sh "int main(){ int a;a=6;a/=2;return a ;}" 3 106 | sh testfdef.sh "int main(){ int a;a=3;a%%=2;return a ;}" 1 107 | 108 | test8: 109 | sh testfdef.sh 'int main(){int a;a=1;++a;return a;}' 2 110 | sh testfdef.sh 'int main(){int a;a=4;--a;return a;}' 3 111 | sh testfdef.sh 'int main(){int a;a=1;a++;return a;}' 2 112 | sh testfdef.sh 'int main(){int a;a=4;a--;return a;}' 3 113 | sh testfdef.sh 'int main(){int a;a=1;return a++;}' 1 114 | sh testfdef.sh 'int main(){int a;a=4;return a--;}' 4 115 | sh testfdef.sh 'int main(){int a;a=1;return ++a;}' 2 116 | sh testfdef.sh 'int main(){int a;a=4;return --a;}' 3 117 | 118 | test9: 119 | sh testfdef.sh 'int main(){return 2<0;}' 0 120 | sh testfdef.sh 'int main(){return 0<2;}' 1 121 | sh testfdef.sh 'int main(){return 2>0;}' 1 122 | sh testfdef.sh 'int main(){return 0>2;}' 0 123 | sh testfdef.sh 'int main(){return 3<3;}' 0 124 | sh testfdef.sh 'int main(){return 2>2;}' 0 125 | sh testfdef.sh 'int main(void){return 2>2;}' 0 126 | sh testfdef.sh 'int main(){return 2>(-1);}' 1 127 | sh testfdef.sh 'int main(){return 2<(-1);}' 0 128 | 129 | test10: 130 | sh testfdef.sh "int main(){if(1){return 3;} return 1;}" 3 131 | sh testfdef.sh "int main(){if(1){return 3;}else{return 4;}}" 3 132 | sh testfdef.sh "int main(){if(0){return 3;}else{return 4;}}" 4 133 | sh testfdef.sh "int main(){int a;a=0;while(a<3){a+=1;} return a;}" 3 134 | sh testfdef.sh "int main(){int a;a=0;do{a+=1;}while(a<3); return a;}" 3 135 | sh testfdef.sh "int main(){int a=0;do{a+=1;}while(a<0); return a;}" 1 136 | 137 | test11: 138 | sh testfdef.sh "int main(){return func()+2;} int func(){return 4;}" 6 139 | sh testfdef.sh "int main(){return func(1,2,3,4,5);} int func(int a,int b,int c,int d, int e){return a+b+c+d+e;}" 15 140 | sh testfdef.sh "int main(){return func(1,2,3,4,5,6);} int func(int a,int b,int c,int d, int e, int f){return a+b+c+d+e+f;}" 21 141 | sh testfdef.sh "int main(){return func()+2;} int func(){return 4;}" 6 142 | 143 | test19: 144 | sh testfdef.sh "int main(){return func(8)+2;} int func(int a){return a-4;}" 6 145 | sh testfdef.sh "int main(){return func(6+2)+2;} int func(int a){return a-4;}" 6 146 | sh testfdef.sh "int main(){return func(5); } int func(int a){ if (a==1){return 1;} return 2;}" 2 147 | 148 | test21: 149 | sh testfdef.sh "int main(){return func(3);} int func(int a){if (a==1) {return 1;} else {return func(a-1)*a;}}" 6 150 | sh testfdef.sh "int main(){return func(3,4);} int func(int a, int b){if (a==1) {return 1;} else {return func(a-1)*a+b-b;}}" 6 151 | sh testfdef.sh "int func(int a, int b); int main(){return func(3,4);} int func(int a, int b){if (a==1) {return 1;} else {return func(a-1)*a+b-b;}}" 6 152 | 153 | test12: 154 | sh testfdef.sh "int main() {int x;int y;x=1;y=2;return x+y;}" 3 155 | sh testfdef.sh "int main() {int* y;int x;x=3;y=&x;return *y;}" 3 156 | 157 | test13: 158 | sh testfdef.sh "int main(){ int x[10];return 1 ;}" 1 159 | sh testfdef.sh "int main(){ int x[10];*x=3; return *x ;}" 3 160 | sh testfdef.sh "int main(){ int x[10];*(x+1)=3;*x=2;return *x;}" 2 161 | sh testfdef.sh "int main(){ int x[10];x[1]=3; return x[1] ;}" 3 162 | sh testfdef.sh "int main(){ int x[10];x[0]=2;x[1]=3;return x[1] ;}" 3 163 | sh testfdef.sh "int main(){ int x[10];x[0]=2;x[1]=3;return x[0] ;}" 2 164 | 165 | test14: 166 | sh testfdef.sh "int a;int main(){a=1;return a;}" 1 167 | sh testfdef.sh "int a;int main(){return a;}" 0 168 | sh testfdef.sh "int a=2;int main(){return a;}" 2 169 | sh testfdef.sh "int a=2;int main(){a=3;return a;}" 3 170 | 171 | test15: 172 | sh testfdef.sh "int main(){char a;return a=1;}" 1 173 | sh testfdef.sh "int main(){return sizeof 3;}" 4 174 | sh testfdef.sh "int main(){int a; int b; return sizeof ab;}" 4 177 | sh testfdef.sh "int main(){return sizeof(int);}" 4 178 | sh testfdef.sh "int main(){int a=1;return a;}" 1 179 | sh testfdef.sh "int a=3*9+5;int main(){return a;}" 32 180 | 181 | test16: 182 | sh testfdef.sh "int main(){int i;int j=0;for(i=1;i<5;++i) { j+=i;} return j;}" 10 183 | sh testfdef.sh "int main(){int i;int j=0;for(i=1;i<5;++i) { break;} return i;}" 1 184 | sh testfdef.sh "int main(){int i;int j=0;for(i=1;i<5;++i) { j+=2;continue;} return j;}" 8 185 | sh testfdef.sh "int main(){return (1==2 || 2==3);}" 0 186 | sh testfdef.sh "int main(){return (1==1);}" 1 187 | sh testfdef.sh "int main(){return (1==2);}" 0 188 | 189 | test20: 190 | sh testfdef.sh "int main(){return ((1==1) || (2==2));}" 1 191 | sh testfdef.sh "int main(){return ((1==2) || (2==2));}" 1 192 | sh testfdef.sh "int main(){return ((1==1) || (1==2));}" 1 193 | sh testfdef.sh "int main(){return ((1==2) || (3==2));}" 0 194 | sh testfdef.sh "int main(){return ((1==1) && (2==2));}" 1 195 | sh testfdef.sh "int main(){return ((1==2) && (2==2));}" 0 196 | sh testfdef.sh "int main(){return ((1==1) && (1==2));}" 0 197 | sh testfdef.sh "int main(){return ((1==2) && (3==2));}" 0 198 | sh testfdef.sh "int main(){return (2 && 1);}" 1 199 | 200 | test17: 201 | sh testfdef.sh 'int main(){char a;return a=1;}' 1 202 | 203 | test18: 204 | sh testfdef.sh "int main(){char a='a';return a;}" 97 205 | sh testfdef.sh "int main(){char a='\n';return a;}" 10 206 | sh testfdef.sh 'int main(){return (3,4);}' 4 207 | sh testfdef.sh "int main(){puts(\"a\");return 0;}" 0 208 | sh testfdef.sh "int main(){puts(\"Test OK\");return 0;}" 0 209 | sh testfdef.sh "int main(){printf(\"Test OK\n\");return 0;}" 0 210 | 211 | test22: 212 | sh testfdef.sh "int main(){return 1 <= 2;}" 1 213 | sh testfdef.sh "int main(){return 1 <= 1;}" 1 214 | sh testfdef.sh "int main(){return 4 <= 1;}" 0 215 | sh testfdef.sh "int main(){return 1 >= 2;}" 0 216 | sh testfdef.sh "int main(){return 1 >= 1;}" 1 217 | sh testfdef.sh "int main(){return 4 >= 1;}" 1 218 | sh testfdef.sh "int main(){return -4 >= 1;}" 0 219 | sh testfdef.sh "int main(){return -4 <= 1;}" 1 220 | 221 | test23: 222 | sh testfdef.sh "int main(){if (2 <= 1) return 1; return 7;}" 7 223 | sh testfdef.sh "int main(){if (1 <= 2) return 1;}" 1 224 | sh testfdef.sh "int main(){return NULL;}" 0 225 | 226 | test24: 227 | sh testfdef.sh "int main(){return /* test */ 3;}" 3 228 | sh testfdef.sh "int main(){return -(-1);}" 1 229 | 230 | test25: 231 | sh testfdef.sh "int main(){return ((int*)3)+1;}" 7 232 | sh testfdef.sh "int main(){return ((int**)3)+1;}" 11 233 | sh testfdef.sh "int main(){return ((char*)3)+1;}" 4 234 | sh testfdef.sh "int main(){return ((int)3)+1;}" 4 235 | 236 | test26: 237 | sh testfdef.sh "int main(){switch(3){case 4: return 5; }}" 5 238 | sh testfdef.sh "int main(){switch(3){case 4: return 5; case 8: return 7; }}" 5 239 | sh testfdef.sh "int main(){switch(3){case 4: return 5; case 8: return 7; default: return 10;}}" 10 240 | sh testfdef.sh "int main(){return -1;}" 255 241 | sh testfdef.sh "int main(){return +1;}" 1 242 | sh testfdef.sh 'int main(){return __LINE__;}' 1 243 | 244 | test27: 245 | sh testfdef.sh "typedef struct { int a;int c;} Type; int main(){Type b;b.a = 2;b.c=4;return b.c;}" 4 246 | sh testfdef.sh "typedef struct { int a;int c;} Type; int main(){Type b;b.a = 2;b.c=4;return b.a;}" 2 247 | sh testfdef.sh "typedef struct { int a;int c;} Type; int main(){Type b;Type* e; e=&b;e->a = 2;e->c=4;return b.a;}" 2 248 | sh testfdef.sh "typedef struct { int a;int c;int d;} Type; int main(){Type b;Type* e; e=&b;e->a = 2;e->c=4;b.d=5;return e->d;}" 5 249 | 250 | test28: 251 | sh testfdef.sh "typedef enum {TY_INT, TY_CHAR} TypeConst; int main(){return TY_CHAR;}" 1 252 | sh testfdef.sh "typedef enum {TY_INT, TY_CHAR} TypeConst; int main(){return TY_INT;}" 0 253 | sh testfdef.sh "typedef int MetaInt[13]; int main(){MetaInt c; c[12] = 3;return c[12];}" 3 254 | 255 | test29: 256 | sh testfdef.sh "int func(char* a){ puts(a); return 1; }int main(){return func(\"aaa\");}" 1 257 | sh testfdef.sh "int main(){char a[3]; a[0]='a'; a[1]='b';a[2]='\\\0';puts(a);return printf(\"%%c%%c\n\", *a, *(a+1));}" 3 258 | sh testfdef.sh "int main(){int a[3]; a[0]=8; a[1]=2;a[2]=4;puts(a);return printf(\"%%d%%d\n\", *a, *(a+1));}" 3 259 | sh testfdef.sh "int main(){char a[12]; a[0]='a'; a[1]='c';a[2]='d';a[3]='g';a[4]='h';a[5]='f';a[6]='k';a[7]='p';a[8]='l';a[9]='\\\0';puts(a);return strcmp(a, \"acdghfkpl\");}" 0 260 | 261 | test30: 262 | sh testfdef.sh "int main(){char a;a='h';return ('a'<=a&&a<='z');}" 1 263 | sh testfdef.sh "int main(){char a;a='h';return ('a'<=a&&a<='z')||('0'<=a&&a<='9')||('A'<=a&&a<='Z')||a=='_';}" 1 264 | sh testfdef.sh "int main(){char a;a='h';return ('a'<=a&&a<='z')||('0'<=a&&a<='9');}" 1 265 | 266 | test31: 267 | sh testfdef.sh "int main(){return ((int)-1 == (long)(-1));}" 1 268 | sh testfdef.sh "int main(){return ((int)-1 == (long)(4));}" 0 269 | 270 | test32: 271 | sh testfdef.sh "int main(){ func(1, 2); func(3, 11,12,13); return 0; } int func(...){ int result; va_list ap; va_start(ap, NULL);int cnt; for (cnt = va_arg(ap, int);cnt >0;--cnt) { result = va_arg(ap, int); printf(\"%%d \", result);} putchar('\n'); va_end(ap); return 0;}" 0 272 | # test32: This should be seen as: 273 | # 2 274 | # 11 12 13 275 | sh testfdef.sh "int main(){ func(1, 2); func(3, 11,12,13); return 0; } int func(int cnt, ...){ int result; va_list ap; va_start(ap, NULL);for (4;cnt >0;--cnt) { result = va_arg(ap, int); printf(\"%%d \", result);} putchar('\n'); va_end(ap); return 0;}" 0 276 | # test32: This should be seen as: 277 | # 2 278 | # 11 12 13 279 | sh testfdef.sh "int main(){ func(1, \"a\"); func(3, \"b\",\"c\",\"d\"); return 0; } int func(int cnt, ...){ va_list ap; va_start(ap, NULL);for (4;cnt >0;--cnt) { puts(va_arg(ap, char*)); } putchar('\n'); va_end(ap); return 0;}" 0 280 | # test32: This should be seen as: 281 | # a 282 | # b c d 283 | 284 | test33: 285 | sh testfdef.sh "int main(){ func(\"%%d %%s\n\", 3, \"test\"); return 0;} int func(char* str, ...) { va_list ap; va_start(ap, str); vprintf(str, ap); va_end(ap); return 0;}" 0 286 | 287 | test34: 288 | sh testfdef.sh 'int main(){ int a; float b; b = 2.3f; printf("Is 2.3?: %%f\n", (double)b); return 0;}' 0 289 | sh testfdef.sh 'int main(){ int a; double b; b = 2432342343.5; printf("Is 2432342343.5?: %%f\n", b); return 0;}' 0 290 | echo "This should be 2.3" 291 | sh testfdef.sh 'int func(float c) {printf("Is 3.4?: %%f\n", (double)c); return 0; } int main(){float b; b = 3.4; func(b); return 0;}' 0 292 | echo "This should be 3.4" 293 | # TODO should add type conversation among TY_INT, TY_FLOAT, TY_DOUBLE 294 | sh testfdef.sh 'int main(){float b; b = 3.4; printf("It should be 3: %%d\n", (int)b); return 0;}' 0 295 | sh testfdef.sh 'float strtof(char* basestr, char* ocmpstr); int main(){int a;float b; b = strtof("3.4", NULL); printf("It should be 3.4: %%f\n", (double)b); return 0;}' 0 296 | 297 | test35: 298 | sh testfdef.sh 'int main(){float a,b; a = 8;b=9; printf("It should be 17: %%f\n", (double)(a+b)); return 0;}' 0 299 | sh testfdef.sh 'int main(){float a,b; a = 8;b=9; printf("It should be -1: %%f\n", (double)(a-b)); return 0;}' 0 300 | sh testfdef.sh 'int main(){float a,b; a = 11;b=9; printf("It should be 2: %%f\n", (double)(a-b)); return 0;}' 0 301 | sh testfdef.sh 'int main(){float a,b; a = 8;b=9; printf("It should be 72: %%f\n", (double)(a*b)); return 0;}' 0 302 | sh testfdef.sh 'int main(){float a,b; a = 12;b=8; printf("It should be 1.5: %%f\n", (double)(a/b)); return 0;}' 0 303 | sh testfdef.sh 'int main(){double a,b; a = 8;b=9; printf("It should be 17: %%f\n", (double)(a+b)); return 0;}' 0 304 | sh testfdef.sh 'int main(){double a,b; a = 8;b=9; printf("It should be -1: %%f\n", (double)(a-b)); return 0;}' 0 305 | sh testfdef.sh 'int main(){double a,b; a = 11;b=9; printf("It should be 2: %%f\n", (double)(a-b)); return 0;}' 0 306 | sh testfdef.sh 'int main(){double a,b; a = 8;b=9; printf("It should be 72: %%f\n", (double)(a*b)); return 0;}' 0 307 | sh testfdef.sh 'int main(){double a,b; a = 12;b=8; printf("It should be 1.5: %%f\n", (double)(a/b)); return 0;}' 0 308 | 309 | test36: 310 | sh testfdef.sh 'int main(){int a; float b; b = 3.4; printf("It should be 3: %%d\n", (int)b); return 0;}' 0 311 | 312 | test37: 313 | sh testfdef.sh 'auto func(int a, double b) { return a+b; } int main() { double c = func(3, 4.5); printf("It should be 7.5: %%f\n", c); return 0;}' 314 | sh testfdef.sh 'auto func(double a, double b) { return a+b; } int main() { double c = func(3.3, 4.5); printf("It should be 7.8: %%f\n", c); return 0;}' 315 | 316 | test38: 317 | sh testfdef.sh 'typedef struct A { int b; } C; int main() { struct A x; return 0; }' 0 318 | clean: 319 | $(RM) -f $(target) $(objects) main.s main2.s main3.s main2 main3 320 | 321 | .PHONY: clean test 322 | -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | # hanando-fukui 2 | 3 | セルフホスト C(/C++ の一部) サブセットコンパイラ: Version 3.1.5 (2020/01/04) 4 | 5 | ## ビルド 6 | ``` 7 | $ make 8 | ``` 9 | 10 | ## コンパイル 11 | ``` 12 | $ ./hanando -f file.c > file.s 13 | $ gcc -g file.s -o file 14 | $ ./file 15 | ``` 16 | 17 | C++ コードもどきなら `-cpp` をつける。 18 | Objective-C 用に `-objc` も存在するが未使用。 19 | 20 | ## セルフホスト 21 | 22 | 第1世代コンパイラから第2世代コンパイラを生成し、その差分がないことを示す。 23 | ``` 24 | $ make selftest 25 | ``` 26 | 27 | ## template もどき (多重展開できない) 28 | 29 | ```cpp 30 | #include 31 | template T add(T a, T b) { 32 | T c; 33 | c = a+b; 34 | return c; 35 | } 36 | 37 | int main() { 38 | printf("int: %d\n", add(234, 123)); 39 | printf("char: %d\n", add(234, 123)); 40 | return 0; 41 | } 42 | ``` 43 | 44 | このコードは `cppsamples/test3.cpp` にある。 45 | 46 | ``` 47 | $ ./hanando -cpp -f test3.cpp > test3.s 48 | $ gcc test3.s -o test3 49 | $ ./test3 50 | ``` 51 | 52 | すると、 char 型と int 型のサイズが異なることを利用して異なる結果になると分かる。 53 | 54 | ## class template もどき (関数宣言できない) 55 | 56 | `cppsamples/test5.cpp` にある。 `Vector` の定義 57 | 58 | ## float/double の実装 59 | 60 | * double 型の引数をとる箇所にint 型の引数をとるときにはキャスト必要 61 | * !=, == 未実装 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hanando-fukui 2 | Self-hostable C(+something) Compiler Prototype: Version 3.1.5 (2020/01/04) 3 | 4 | *Japanese README is avaliable on README.ja.md* 5 | 6 | ## How to install 7 | By just typing `$ make` will compile as `./hanando`. 8 | 9 | Then, you can use hanando and output assembly to standard output. 10 | ``` 11 | $ ./hanando "int main() {printf(\"Hello World!\");}" 12 | ``` 13 | Using escaping of quotation is needed to run inside bash. 14 | 15 | Alternatively, you can specify and compile a C file. 16 | ``` 17 | $ ./hanando -f bar.c 18 | ``` 19 | After outputting of assembly, you can compile to an executable with gcc or clang: 20 | ``` 21 | $ ./hanando -f bar.c > bar.s 22 | $ gcc bar.s -o bar 23 | $ ./bar 24 | ``` 25 | 26 | ## How to compile self-recursively 27 | ``` 28 | $ make selftest 29 | ``` 30 | -------------------------------------------------------------------------------- /analysis.c: -------------------------------------------------------------------------------- 1 | // analysis.c 2 | // SPDX-License-Identifier: Apache-2.0 3 | /* 4 | Copyright 2020 hiromi-mi 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include "main.h" 20 | #include "selfhost.h" 21 | #include 22 | 23 | extern Env *env; 24 | extern int lang; 25 | extern Map *typedb; 26 | extern Map *struct_typedb; 27 | extern Map *current_local_typedb; 28 | extern int neg_float_generate; 29 | extern int neg_double_generate; 30 | 31 | Node *new_long_num_node(long num_val); 32 | Node *implicit_althemic_type_conversion(Node *node); 33 | 34 | void update_rsp_offset(int size) { 35 | env->rsp_offset += size; 36 | if (*env->rsp_offset_max < env->rsp_offset) { 37 | *env->rsp_offset_max = env->rsp_offset; 38 | } 39 | } 40 | 41 | Node *analyzing(Node *node) { 42 | int j; 43 | Env *prev_env = env; 44 | if (node->ty == ND_BLOCK || node->ty == ND_FDEF) { 45 | env = node->env; 46 | LocalVariable *local_variable = NULL; 47 | // generate all size of nodes 48 | // preview all variables and setup offsets. 49 | if (prev_env) { 50 | // This is to update rsp_offset based on (it's based system). 51 | // Previously, this is called by new_env() but no longer supported. 52 | env->rsp_offset += prev_env->rsp_offset; 53 | } 54 | for (j = 0; j < env->idents->keys->len; j++) { 55 | local_variable = (LocalVariable *)env->idents->vals->data[j]; 56 | if (local_variable->lvar_offset != 0) { 57 | // For Example: STRUCT Passed Argumenets (use rsp+24 or so on) 58 | continue; 59 | } 60 | int size = cnt_size(local_variable->type); 61 | // should aligned as x86_64 62 | if (size % 8 != 0) { 63 | size += (8 - size % 8); 64 | } 65 | update_rsp_offset(size); 66 | local_variable->lvar_offset = env->rsp_offset; 67 | } 68 | } 69 | 70 | if (node->lhs) { 71 | node->lhs = analyzing(node->lhs); 72 | } 73 | if (node->rhs) { 74 | node->rhs = analyzing(node->rhs); 75 | } 76 | if (node->is_omiited) { 77 | node->is_omiited = analyzing(node->is_omiited); 78 | } 79 | for (j = 0; j < 3; j++) { 80 | if (node->conds[j]) { 81 | node->conds[j] = analyzing(node->conds[j]); 82 | } 83 | } 84 | if (node->argc > 0) { 85 | for (j = 0; j < node->argc; j++) { 86 | if (node->args[j]) { 87 | node->args[j] = analyzing(node->args[j]); 88 | } 89 | } 90 | } 91 | if (node->code) { 92 | for (j = 0; j < node->code->len && node->code->data[j]; j++) { 93 | node->code->data[j] = (Token *)analyzing((Node *)node->code->data[j]); 94 | } 95 | } 96 | 97 | switch (node->ty) { 98 | case ND_RETURN: 99 | if (env->ret == NULL) { 100 | error("try to Return to NULL: Unexpected behaviour\n"); 101 | } 102 | 103 | // treat TY_AUTO 104 | if (env->ret->ty == TY_AUTO) { 105 | copy_type(node->lhs->type, env->ret); 106 | } 107 | if (node->lhs) { 108 | node->type = node->lhs->type; 109 | } // if return to VOID, there is no lhs 110 | break; 111 | case ND_SIZEOF: 112 | if (node->conds[0]) { 113 | // evaluate node->conds[0] and return its type 114 | node = new_long_num_node(cnt_size(node->conds[0]->type)); 115 | 116 | } else { 117 | // ND_SIZEOF should generate its type information. 118 | // This is because: on parse, no (structured) type size are 119 | // avaliable 120 | node = new_long_num_node(cnt_size(node->sizeof_type)); 121 | } 122 | break; 123 | case ND_ADD: 124 | case ND_SUB: 125 | if (node->lhs->type->ty == TY_PTR || node->lhs->type->ty == TY_ARRAY) { 126 | node->rhs = new_node(ND_MULTIPLY_IMMUTABLE_VALUE, node->rhs, NULL); 127 | node->rhs->type = node->rhs->lhs->type; 128 | node->rhs->num_val = cnt_size(node->lhs->type->ptrof); 129 | node->type = node->lhs->type; 130 | } else if (node->rhs->type->ty == TY_PTR || 131 | node->rhs->type->ty == TY_ARRAY) { 132 | node->lhs = new_node(ND_MULTIPLY_IMMUTABLE_VALUE, node->lhs, NULL); 133 | node->lhs->type = node->rhs->lhs->type; 134 | node->lhs->num_val = cnt_size(node->rhs->type->ptrof); 135 | node->type = node->rhs->type; 136 | } else { 137 | node = implicit_althemic_type_conversion(node); 138 | node->type = node->lhs->type; 139 | break; 140 | } 141 | if (node->rhs->type->ty == TY_PTR || node->rhs->type->ty == TY_ARRAY) { 142 | node->type = node->rhs->type; 143 | // TY_PTR no matter when node->lhs->node->lhs is INT or PTR 144 | } else if (node->lhs->type->ty == TY_PTR || 145 | node->lhs->type->ty == TY_ARRAY) { 146 | node->type = node->lhs->type; 147 | // TY_PTR no matter when node->lhs->node->lhs is INT or PTR 148 | } 149 | break; 150 | case ND_MUL: 151 | node = implicit_althemic_type_conversion(node); 152 | node->type = node->lhs->type; 153 | break; 154 | case ND_ISEQ: 155 | case ND_ISNOTEQ: 156 | case ND_ISLESSEQ: 157 | case ND_ISMOREEQ: 158 | case ND_LESS: 159 | case ND_GREATER: 160 | node->type = find_typed_db("int", typedb); 161 | node = implicit_althemic_type_conversion(node); 162 | break; 163 | case ND_FPLUSPLUS: 164 | case ND_FSUBSUB: 165 | // Moved to analyzing process. 166 | if (node->lhs->type->ty == TY_PTR || node->lhs->type->ty == TY_ARRAY) { 167 | node->num_val = type2size(node->lhs->type->ptrof); 168 | } 169 | node->type = node->lhs->type; 170 | break; 171 | case ND_ADDRESS: 172 | node->type = new_type(); 173 | node->type->ty = TY_PTR; 174 | node->type->ptrof = node->lhs->type; 175 | break; 176 | case ND_DEREF: 177 | node->type = node->lhs->type->ptrof; 178 | if (!node->type) { 179 | error("Error: Dereference on NOT pointered."); 180 | } 181 | break; 182 | case ND_ASSIGN: 183 | if (node->lhs->type->is_const) { 184 | error("Error: Assign to constant value.\n"); 185 | } 186 | if (node->lhs->type->ty != node->rhs->type->ty) { 187 | node->rhs = new_node(ND_CAST, node->rhs, NULL); 188 | node->rhs->type = node->lhs->type; 189 | } 190 | node->type = node->lhs->type; 191 | break; 192 | case ND_DOT: 193 | if (node->lhs->type->ty != TY_STRUCT) { 194 | error("Error: dot operator to NOT struct\n"); 195 | } 196 | node->type = (Type *)map_get(node->lhs->type->structure, node->name); 197 | if (!node->type) { 198 | error("Error: structure not found: %s\n", node->name); 199 | } 200 | // Member Accesss Control p.231 201 | if ((lang & 1) && (node->type->memaccess == HIDED)) { 202 | error("Error: access to private item: %s\n", node->name); 203 | } 204 | if ((lang & 1) && ((node->type->memaccess == PRIVATE) || 205 | (node->type->memaccess == PROTECTED))) { 206 | if (!env->current_class || !env->current_class->var_name || 207 | (strcmp(env->current_class->var_name, "this"))) { 208 | // TODO 209 | //(strcmp(env->current_class->type_name, 210 | // node->type->type_name)))) { 211 | error("Error: access to private item: %s\n", node->name); 212 | } 213 | } 214 | break; 215 | case ND_NEG: 216 | node->type = node->lhs->type; 217 | if (node->type->ty == TY_DOUBLE) { 218 | neg_double_generate = 1; 219 | } 220 | if (node->type->ty == TY_FLOAT) { 221 | neg_float_generate = 1; 222 | } 223 | break; 224 | case ND_MULTIPLY_IMMUTABLE_VALUE: 225 | node->type = node->lhs->type; 226 | break; 227 | case ND_COMMA: 228 | node->type = node->rhs->type; 229 | break; 230 | case ND_FUNC: 231 | if (node->funcdef) { 232 | // there are new typedefs. { 233 | node->type = node->funcdef->type->ret; 234 | } else { 235 | node->type = find_typed_db("int", typedb); 236 | } 237 | break; 238 | case ND_VASTART: 239 | node->num_val = env->current_func->argc; 240 | node->type = node->lhs->type; 241 | break; 242 | case '?': 243 | /* arithmetic, arithmetic -> arithmetic 244 | * structure, structure -> structure 245 | * void, void -> void 246 | * pointer, pointer/NULL -> pointer 247 | * (differently qualified) compatible types 248 | * null or not -> other 249 | * coid -> pointer to qualified void 250 | */ 251 | /* TODO: Support NULL pointer & void */ 252 | node->type = node->lhs->type; 253 | if (node->type->ty != TY_STRUCT || node->type->ty != TY_PTR || 254 | node->type->ty != TY_ARRAY || node->type->ty != TY_VOID) { 255 | node = implicit_althemic_type_conversion(node); 256 | } 257 | break; 258 | default: 259 | if (node->type == NULL && node->lhs && node->lhs->type) { 260 | node->type = node->lhs->type; 261 | } 262 | break; 263 | } 264 | 265 | env = prev_env; 266 | return node; 267 | } 268 | 269 | Node *implicit_althemic_type_conversion(Node *node) { 270 | // See Section 6.3.1.8 271 | if (node->lhs->type->ty == node->rhs->type->ty) { 272 | return node; 273 | } 274 | if (node->lhs->type->ty == TY_DOUBLE) { 275 | node->rhs = new_node(ND_CAST, node->rhs, NULL); 276 | node->rhs->type = node->lhs->type; 277 | return node; 278 | } 279 | if (node->rhs->type->ty == TY_DOUBLE) { 280 | node->lhs = new_node(ND_CAST, node->lhs, NULL); 281 | node->lhs->type = node->rhs->type; 282 | return node; 283 | } 284 | if (node->lhs->type->ty == TY_FLOAT) { 285 | node->rhs = new_node(ND_CAST, node->rhs, NULL); 286 | node->rhs->type = node->lhs->type; 287 | return node; 288 | } 289 | if (node->rhs->type->ty == TY_FLOAT) { 290 | node->lhs = new_node(ND_CAST, node->lhs, NULL); 291 | node->lhs->type = node->rhs->type; 292 | return node; 293 | } 294 | if (type2size(node->lhs->type) < type2size(node->rhs->type)) { 295 | node->lhs = new_node(ND_CAST, node->lhs, NULL); 296 | node->lhs->type = node->rhs->type; 297 | return node; 298 | } 299 | if (type2size(node->lhs->type) > type2size(node->rhs->type)) { 300 | node->rhs = new_node(ND_CAST, node->rhs, NULL); 301 | node->rhs->type = node->lhs->type; 302 | return node; 303 | } 304 | return node; 305 | } 306 | -------------------------------------------------------------------------------- /containers.c: -------------------------------------------------------------------------------- 1 | // containers.c 2 | // SPDX-License-Identifier: Apache-2.0 3 | /* 4 | Copyright 2019, 2020 hiromi-mi 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | #include "main.h" 19 | #include "selfhost.h" 20 | #include 21 | #include 22 | 23 | // Vector 24 | Vector *new_vector(void) { 25 | Vector *vec = malloc(sizeof(Vector)); 26 | vec->capacity = 16; 27 | vec->data = malloc(sizeof(Token *) * vec->capacity); 28 | vec->len = 0; 29 | return vec; 30 | } 31 | 32 | int vec_push(Vector *vec, Token *element) { 33 | if (vec->capacity == vec->len) { 34 | vec->capacity *= 2; 35 | vec->data = realloc(vec->data, sizeof(Token *) * vec->capacity); 36 | if (!vec->data) { 37 | error("Error: Realloc failed: %ld\n", vec->capacity); 38 | } 39 | } 40 | vec->data[vec->len] = element; 41 | return vec->len++; 42 | } 43 | 44 | // Map 45 | Map *new_map(void) { 46 | Map *map = malloc(sizeof(Map)); 47 | map->keys = new_vector(); 48 | map->vals = new_vector(); 49 | return map; 50 | } 51 | 52 | int map_put(Map *map, const char *key, const void *val) { 53 | vec_push(map->keys, (void *)key); 54 | return vec_push(map->vals, (void *)val); 55 | } 56 | 57 | void *map_get(const Map *map, const char *key) { 58 | int i; 59 | for (i = map->keys->len - 1; i >= 0; i--) { 60 | if (strcmp((char *)map->keys->data[i], key) == 0) { 61 | return map->vals->data[i]; 62 | } 63 | } 64 | return NULL; 65 | } 66 | -------------------------------------------------------------------------------- /cppsamples/Makefile: -------------------------------------------------------------------------------- 1 | test: 1 2 3 4 5 6 7 2 | 1: 3 | ../hanando -f -cpp test1.cpp > test1.s 4 | gcc -g test1.s -o test1 5 | ./test1 6 | 2: 7 | ../hanando -f -cpp test2.cpp > test2.s 8 | gcc -g test2.s -o test2 9 | ./test2 10 | 3: 11 | ../hanando -f -cpp test3.cpp > test3.s 12 | gcc -g test3.s -o test3 13 | ./test3 14 | 4: 15 | ../hanando -f -cpp test4.cpp > test4.s 16 | gcc -g test4.s -o test4 17 | ./test4 18 | 5: 19 | ../hanando -f -cpp test5.cpp > test5.s 20 | gcc -g test5.s -o test5 21 | ./test5 22 | 6: 23 | ../hanando -f -cpp test6.cpp > test6.s 24 | gcc -g test6.s -o test6 25 | ./test6 26 | 7: 27 | ../hanando -f -cpp test7.cpp > test7.s 28 | gcc -g test7.s -o test7 29 | ./test7 30 | -------------------------------------------------------------------------------- /cppsamples/test1.cpp: -------------------------------------------------------------------------------- 1 | // $ ./hanando -r -f -cpp test.cpp > test.s && clang -g test.s -o test && ./test 2 | 3 | class Test { 4 | public: 5 | int a; 6 | char b; 7 | static int func(); 8 | static int Vim(int c); 9 | }; 10 | 11 | class Test2 : Test { 12 | }; 13 | 14 | int main() { 15 | Test c; 16 | c.a = 9; 17 | printf("%d (Should be 20)\n", Test::func()); 18 | Test::Vim(42); 19 | Test2 d; 20 | decltype(d) e; 21 | d.a = 10; 22 | e.a = 30; 23 | printf("%d (It must be 10)\n", d.a); 24 | return 0; 25 | } 26 | 27 | static int Test::func() { 28 | return 20; 29 | } 30 | static int Test::Vim(int c) { 31 | printf("From Test::Vim %d (Should be 42)\n", c); 32 | return 1; 33 | } 34 | -------------------------------------------------------------------------------- /cppsamples/test2.cpp: -------------------------------------------------------------------------------- 1 | // $ ./hanando -r -f -cpp test.cpp > test.s && clang -g test.s -o test && ./test 2 | 3 | class Test { 4 | int a; 5 | protected: 6 | int f; 7 | public: 8 | char b; 9 | static int Vim(int c); 10 | void SetA(int new_a); 11 | int Emacs(); 12 | }; 13 | 14 | class Test2 : Test { 15 | int SetF(int f); 16 | }; 17 | 18 | void Test::SetA(int new_a) { 19 | this->a = new_a; 20 | } 21 | 22 | int Test2::SetF(int f) { 23 | //return this->a; // this should be error 24 | this->f = f; 25 | return this->f; 26 | } 27 | 28 | int Test::Emacs() { 29 | printf("From Test::Emacs! %d (Should be 9)\n", this->a); 30 | return 8; 31 | } 32 | static int Test::Vim(int c) { 33 | printf("From Test::Vim %d\n", c); 34 | return 1; 35 | } 36 | 37 | int main() { 38 | Test c; 39 | // Should ERROR 40 | //c.a = 9; 41 | c.SetA(9); 42 | //Test::Vim(32); 43 | c.Emacs(); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /cppsamples/test3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | $ ./hanando -r -f -cpp test3.cpp > test3.s && gcc -g test3.s -o test3 && ./test3 3 | 4 | Output: 5 | int: 357 6 | char: 101 7 | */ 8 | 9 | #include 10 | template T add(T a, T b) { 11 | T c; 12 | c = a+b; 13 | return c; 14 | } 15 | 16 | int main() { 17 | printf("int: %d\n", add(234, 123)); 18 | printf("char: %d\n", add(234, 123)); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /cppsamples/test4.cpp: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | long num_val; 3 | char *input; 4 | int pos; 5 | int type_size; // to treat 'a' as char. only used in TK_NUM 6 | int pline; 7 | } Token; 8 | 9 | #include 10 | 11 | template T add(T a, U b) { 12 | T c; 13 | c = a+b; 14 | return c; 15 | } 16 | template int get(V a) { 17 | return a->pline; 18 | } 19 | 20 | int main() { 21 | printf("int: %d\n", add(234, 123)); 22 | printf("char: %d\n", add(234, 123)); 23 | Token d; 24 | d.pline = 8; 25 | printf("token: %d\n", get(&d)); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /cppsamples/test5.cpp: -------------------------------------------------------------------------------- 1 | template class Vector { 2 | public: 3 | Elem **data; 4 | long capacity; 5 | long len; 6 | //Elem get(long id); 7 | }; 8 | 9 | // does not work yet! 10 | /* 11 | template long Array::GetSize( ) 12 | { return this->len; } 13 | */ 14 | 15 | int intfunc() { 16 | Vector a; 17 | a.len = 0; 18 | a.capacity = 16; 19 | a.data = malloc(sizeof(int) * a.capacity); 20 | return 0; 21 | } 22 | 23 | int charfunc() { 24 | Vector a; 25 | a.len = 0; 26 | a.capacity = 16; 27 | a.data = malloc(sizeof(char) * a.capacity); 28 | return 1; 29 | } 30 | 31 | int main() { 32 | intfunc(); 33 | charfunc(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /cppsamples/test6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | auto func(int a) { 4 | int b; 5 | if (a <= 1) { 6 | return 1; 7 | } else { 8 | return a*func(a-1); 9 | } 10 | } 11 | 12 | int main() { 13 | printf("It must be 24: %d\n", func(4)); 14 | } 15 | -------------------------------------------------------------------------------- /cppsamples/test7.cpp: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | long num_val; 3 | char *input; 4 | int pos; 5 | int type_size; // to treat 'a' as char. only used in TK_NUM 6 | int pline; 7 | } Token; 8 | 9 | #include 10 | 11 | template auto add2(T a, U b) { 12 | T c; 13 | c = a+b; 14 | return c; 15 | } 16 | template int get(V a) { 17 | return a->pline; 18 | } 19 | 20 | int main() { 21 | printf("int: %d\n", add2(234, 123)); 22 | printf("char: %d\n", add2(234, 123)); 23 | Token d; 24 | d.pline = 8; 25 | printf("token: %d\n", get(&d)); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /foo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int func(int arg) { 4 | printf("OK%d\n", arg); 5 | return 4; 6 | } 7 | 8 | int foo(int x, int y) { 9 | printf("%d\n", x + y); 10 | return 0; 11 | } 12 | 13 | int *alloc2(int **p, int a, int b) { 14 | *p = malloc(sizeof(int *) * 2); 15 | **p = a; 16 | *(*p + 1) = b; 17 | return *p; 18 | } 19 | -------------------------------------------------------------------------------- /gen_x64.c: -------------------------------------------------------------------------------- 1 | // gen_x64.c 2 | /* 3 | Copyright 2020 hiromi-mi 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | #include "main.h" 19 | #include "selfhost.h" 20 | #include 21 | #include 22 | #include 23 | 24 | extern Vector *globalcode; 25 | extern Vector *strs; 26 | extern Vector *floats; 27 | extern Vector *float_doubles; 28 | extern Map *global_vars; 29 | extern Map *funcdefs_generated_template; 30 | extern Map *funcdefs; 31 | extern Map *consts; 32 | extern Map *typedb; 33 | extern Map *struct_typedb; 34 | extern Map *current_local_typedb; 35 | 36 | int reg_table[6]; 37 | int float_reg_table[8]; 38 | char *registers8[5]; 39 | char *registers16[5]; 40 | char *registers32[5]; 41 | char *registers64[5]; 42 | char *float_registers[8]; 43 | char *float_arg_registers[6]; 44 | char arg_registers[6][4]; 45 | 46 | int if_cnt = 0; 47 | int for_while_cnt = 0; 48 | int neg_float_generate = 0; 49 | int neg_double_generate = 0; 50 | 51 | int env_for_while = 0; 52 | int env_for_while_switch = 0; 53 | 54 | #define NO_REGISTER NULL 55 | 56 | Register *gen_register_rightval(Node *node, int unused_eval); 57 | void init_reg_table(void); 58 | char *node2reg(Node *node, Register *reg); 59 | void secure_mutable_with_type(Register *reg, Type *type); 60 | 61 | void globalvar_gen(void) { 62 | puts(".data"); 63 | int j; 64 | for (j = 0; j < global_vars->keys->len; j++) { 65 | GlobalVariable *valdataj = (GlobalVariable *)global_vars->vals->data[j]; 66 | char *keydataj = (char *)global_vars->keys->data[j]; 67 | if (valdataj->type->is_extern) { 68 | // Do not write externed values. 69 | continue; 70 | } 71 | int typesize = cnt_size(valdataj->type); 72 | printf(".type %s,@object\n", keydataj); 73 | printf(".global %s\n", keydataj); 74 | if (valdataj->inits) { 75 | printf(".size %s, %d\n", keydataj, typesize); 76 | printf("%s:\n", keydataj); 77 | int k; 78 | for (k = 0; k < valdataj->inits->len; k++) { 79 | Node *vark = (Node *)valdataj->inits->data[k]; 80 | if (vark->name) { 81 | printf(".quad %s\n", vark->name); 82 | } else { 83 | printf(".long %ld\n", vark->num_val); 84 | } 85 | } 86 | } else { 87 | printf(".comm %s, %d\n", keydataj, typesize); 88 | } 89 | } 90 | for (j = 0; j < strs->len; j++) { 91 | printf(".LC%d:\n", j); 92 | printf(".string \"%s\"\n", (char *)strs->data[j]); 93 | } 94 | for (j = 0; j < floats->len; j++) { 95 | printf(".LCF%d:\n", j); 96 | int *int_repr = (int *)floats->data[j]; 97 | printf(".long %d\n", *int_repr); 98 | } 99 | for (j = 0; j < float_doubles->len; j++) { 100 | printf(".LCD%d:\n", j); 101 | long *repr = (long *)float_doubles->data[j]; 102 | printf(".long %ld\n", *repr & 0xFFFFFFFF); 103 | printf(".long %ld\n", *repr >> 32); 104 | } 105 | 106 | // using in ND_NEG 107 | if (neg_double_generate) { 108 | printf(".LCDNEGDOUBLE:\n"); 109 | printf(".long 0\n"); 110 | printf(".long -2147483648\n"); 111 | } 112 | if (neg_float_generate) { 113 | printf(".LCDNEGFLOAT:\n"); 114 | printf(".long 2147483648\n"); 115 | } 116 | puts(".text"); 117 | } 118 | 119 | char *_rax(Node *node) { 120 | switch (type2size(node->type)) { 121 | case 1: 122 | return "al"; 123 | case 4: 124 | return "eax"; 125 | default: 126 | return "rax"; 127 | } 128 | } 129 | 130 | int cmp_regs(Node *node, Register *lhs_reg, Register *rhs_reg) { 131 | secure_mutable_with_type(lhs_reg, node->lhs->type); 132 | if (node->lhs->type->ty == TY_FLOAT) { 133 | return printf("comiss %s, %s\n", node2reg(node->lhs, lhs_reg), 134 | node2reg(node->rhs, rhs_reg)); 135 | } else if (node->lhs->type->ty == TY_DOUBLE) { 136 | return printf("comisd %s, %s\n", node2reg(node->lhs, lhs_reg), 137 | node2reg(node->rhs, rhs_reg)); 138 | } else if (type2size(node->lhs->type) < type2size(node->rhs->type)) { 139 | // rdi, rax 140 | return printf("cmp %s, %s\n", node2reg(node->rhs, lhs_reg), 141 | node2reg(node->rhs, rhs_reg)); 142 | } else { 143 | return printf("cmp %s, %s\n", node2reg(node->lhs, lhs_reg), 144 | node2reg(node->lhs, rhs_reg)); 145 | } 146 | } 147 | 148 | char *_rdi(Node *node) { 149 | switch (type2size(node->type)) { 150 | case 1: 151 | return "dil"; 152 | case 4: 153 | return "edi"; 154 | default: 155 | return "rdi"; 156 | } 157 | } 158 | 159 | char *_rdx(Node *node) { 160 | switch (type2size(node->type)) { 161 | case 1: 162 | return "dl"; 163 | case 4: 164 | return "edx"; 165 | default: 166 | return "rdx"; 167 | } 168 | } 169 | 170 | void gen_register_top(void) { 171 | init_reg_table(); 172 | init_reg_registers(); 173 | int j; 174 | for (j = 0; j < globalcode->len; j++) { 175 | gen_register_rightval((Node *)globalcode->data[j], 1); 176 | } 177 | } 178 | 179 | // These registers will be used to map into registers 180 | void init_reg_registers(void) { 181 | // This code is valid (and safe) because RHS is const ptr. lreg[7] -> on top 182 | // of "r10b" 183 | // "r15" will be used as rsp alignment register. 184 | strcpy(arg_registers[0], "rdi"); 185 | strcpy(arg_registers[1], "rsi"); 186 | strcpy(arg_registers[2], "rdx"); 187 | strcpy(arg_registers[3], "rcx"); 188 | strcpy(arg_registers[4], "r8"); 189 | strcpy(arg_registers[5], "r9"); 190 | 191 | registers8[0] = "r12b"; 192 | registers8[1] = "r13b"; 193 | registers8[2] = "r14b"; 194 | registers8[3] = "r11b"; 195 | registers8[4] = "r10b"; 196 | registers16[0] = "r12w"; 197 | registers16[1] = "r13w"; 198 | registers16[2] = "r14w"; 199 | registers16[3] = "r11w"; 200 | registers16[4] = "r10w"; 201 | registers32[0] = "r12d"; 202 | registers32[1] = "r13d"; 203 | registers32[2] = "r14d"; 204 | registers32[3] = "r11d"; 205 | registers32[4] = "r10d"; 206 | registers64[0] = "r12"; 207 | registers64[1] = "r13"; 208 | registers64[2] = "r14"; 209 | registers64[3] = "r11"; 210 | registers64[4] = "r10"; 211 | float_arg_registers[0] = "xmm0"; 212 | float_arg_registers[1] = "xmm1"; 213 | float_arg_registers[2] = "xmm2"; 214 | float_arg_registers[3] = "xmm3"; 215 | float_arg_registers[4] = "xmm4"; 216 | float_arg_registers[5] = "xmm5"; 217 | float_registers[0] = "xmm6"; 218 | float_registers[1] = "xmm7"; 219 | float_registers[2] = "xmm8"; 220 | float_registers[3] = "xmm9"; 221 | float_registers[4] = "xmm10"; 222 | float_registers[5] = "xmm11"; 223 | float_registers[6] = "xmm12"; 224 | float_registers[7] = "xmm13"; 225 | } 226 | 227 | char *id2reg8(int id) { return registers8[id]; } 228 | 229 | char *id2reg32(int id) { return registers32[id]; } 230 | 231 | char *id2reg64(int id) { return registers64[id]; } 232 | 233 | void init_reg_table(void) { 234 | int j; 235 | for (j = 0; j < 6; j++) { // j = 6 means r15 236 | reg_table[j] = -1; // NEVER_USED REGISTERS 237 | } 238 | } 239 | 240 | char *gvar_size2reg(int size, char *name) { 241 | char *_str = malloc(sizeof(char) * 256); 242 | if (size == 1) { 243 | snprintf(_str, 255, "byte ptr %s[rip]", name); 244 | } else if (size == 4) { 245 | snprintf(_str, 255, "dword ptr %s[rip]", name); 246 | } else { 247 | snprintf(_str, 255, "qword ptr %s[rip]", name); 248 | } 249 | return _str; 250 | } 251 | 252 | char *node2specifier(Node *node) { 253 | int size; 254 | size = type2size(node->type); 255 | if (size == 1) { 256 | return "byte ptr"; 257 | } else if (size == 4) { 258 | return "dword ptr"; 259 | } else { 260 | return "qword ptr"; 261 | } 262 | } 263 | 264 | char *type2mov(Type *type) { 265 | switch (type->ty) { 266 | case TY_FLOAT: 267 | return "movss"; 268 | case TY_DOUBLE: 269 | return "movsd"; 270 | /*case TY_CHAR: 271 | return "movzx";*/ 272 | default: 273 | return "mov"; 274 | } 275 | } 276 | 277 | char *gvar_node2reg(Node *node, char *name) { 278 | return gvar_size2reg(type2size(node->type), name); 279 | } 280 | 281 | char *size2reg(int size, Register *reg) { 282 | if (reg->kind == R_REGISTER) { 283 | if (size == 1) { 284 | return id2reg8(reg->id); 285 | } else if (size == 4) { 286 | return id2reg32(reg->id); 287 | } else { 288 | return id2reg64(reg->id); 289 | } 290 | // with type specifier. 291 | } else if (reg->kind == R_LVAR || reg->kind == R_REVERSED_LVAR) { 292 | char *_str = malloc(sizeof(char) * 256); 293 | if (size == 1) { 294 | snprintf(_str, 255, "byte ptr [rbp-%d]", reg->id); 295 | } else if (size == 4) { 296 | snprintf(_str, 255, "dword ptr [rbp-%d]", reg->id); 297 | } else { 298 | snprintf(_str, 255, "qword ptr [rbp-%d]", reg->id); 299 | } 300 | return _str; 301 | } else if (reg->kind == R_GVAR) { 302 | return gvar_size2reg(size, reg->name); 303 | } else if (reg->kind == R_XMM) { 304 | return float_registers[reg->id]; 305 | } 306 | error("Error: Cannot Have Register\n"); 307 | } 308 | char *node2reg(Node *node, Register *reg) { 309 | if (reg->kind == R_LVAR || reg->kind == R_REVERSED_LVAR) { 310 | return size2reg(reg->size, reg); 311 | } 312 | return size2reg(type2size(node->type), reg); 313 | } 314 | 315 | Register *float_retain_reg(void) { 316 | int j; 317 | for (j = 0; j < 8; j++) { 318 | if (float_reg_table[j] > 0) 319 | continue; 320 | float_reg_table[j] = 1; 321 | 322 | Register *reg = malloc(sizeof(Register)); 323 | reg->id = j; 324 | reg->name = NULL; 325 | reg->kind = R_XMM; 326 | return reg; 327 | } 328 | error("No more float registers are avaliable\n"); 329 | } 330 | 331 | Register *retain_reg(void) { 332 | int j; 333 | for (j = 0; j < 5; j++) { 334 | if (reg_table[j] > 0) 335 | continue; 336 | if (reg_table[j] < 0 && j < 3) { 337 | } 338 | reg_table[j] = 1; 339 | 340 | Register *reg = malloc(sizeof(Register)); 341 | reg->id = j; 342 | reg->name = NULL; 343 | reg->kind = R_REGISTER; 344 | reg->size = -1; 345 | return reg; 346 | } 347 | error("No more registers are avaliable\n"); 348 | } 349 | 350 | void release_reg(Register *reg) { 351 | if (!reg) { 352 | return; 353 | } 354 | if (reg->kind == R_REGISTER) { 355 | reg_table[reg->id] = 0; // USED REGISTER 356 | } else if (reg->kind == R_XMM) { 357 | float_reg_table[reg->id] = 0; 358 | } 359 | free(reg); 360 | } 361 | 362 | void release_all_reg(void) { 363 | int j; 364 | for (j = 0; j < 6; j++) { 365 | // j = 5 means r15 366 | reg_table[j] = -1; 367 | } 368 | for (j = 0; j < 8; j++) { 369 | float_reg_table[j] = -1; 370 | } 371 | } 372 | 373 | void secure_mutable_with_type(Register *reg, Type *type) { 374 | Register *new_reg; 375 | // to enable to change 376 | if (reg->kind != R_REGISTER && reg->kind != R_XMM) { 377 | if (type->ty == TY_FLOAT || type->ty == TY_DOUBLE) { 378 | new_reg = float_retain_reg(); 379 | printf("%s %s, %s\n", type2mov(type), 380 | size2reg(type2size(type), new_reg), size2reg(reg->size, reg)); 381 | } else { 382 | new_reg = retain_reg(); 383 | if (reg->size <= 0) { 384 | printf("mov %s, %s\n", size2reg(8, new_reg), size2reg(8, reg)); 385 | } else if (reg->size == 1) { 386 | printf("movzx %s, %s\n", size2reg(8, new_reg), 387 | size2reg(reg->size, reg)); 388 | } else { 389 | printf("mov %s, %s\n", size2reg(reg->size, new_reg), 390 | size2reg(reg->size, reg)); 391 | } 392 | } 393 | reg->id = new_reg->id; 394 | reg->kind = new_reg->kind; 395 | reg->name = new_reg->name; 396 | reg->size = new_reg->size; 397 | } 398 | } 399 | 400 | Register *gen_register_leftval(Node *node) { 401 | Register *temp_reg; 402 | Register *lhs_reg; 403 | // Treat as lvalue. 404 | if (!node) { 405 | return NO_REGISTER; 406 | } 407 | switch (node->ty) { 408 | case ND_IDENT: 409 | temp_reg = retain_reg(); 410 | if (node->local_variable->lvar_offset >= 0) { 411 | printf("lea %s, [rbp-%d]\n", id2reg64(temp_reg->id), 412 | node->local_variable->lvar_offset); 413 | } else { 414 | printf("lea %s, [rbp-%d]\n", id2reg64(temp_reg->id), 415 | -node->local_variable->lvar_offset); 416 | } 417 | return temp_reg; 418 | 419 | case ND_DEREF: 420 | lhs_reg = gen_register_rightval(node->lhs, 0); 421 | if (lhs_reg->kind != R_REGISTER && lhs_reg->kind != R_XMM) { 422 | temp_reg = retain_reg(); 423 | printf("mov %s, %s\n", size2reg(8, temp_reg), 424 | node2reg(node->lhs, lhs_reg)); 425 | release_reg(lhs_reg); 426 | lhs_reg = temp_reg; 427 | } 428 | return lhs_reg; 429 | 430 | case ND_GLOBAL_IDENT: 431 | case ND_STRING: 432 | case ND_SYMBOL: 433 | temp_reg = retain_reg(); 434 | printf("lea %s, %s\n", id2reg64(temp_reg->id), 435 | gvar_node2reg(node, node->name)); 436 | return temp_reg; 437 | 438 | case ND_DOT: 439 | lhs_reg = gen_register_leftval(node->lhs); 440 | if (node->type->offset > 0) { 441 | printf("add %s, %d\n", size2reg(8, lhs_reg), node->type->offset); 442 | } 443 | return lhs_reg; 444 | 445 | default: 446 | error("Error: NOT lvalue"); 447 | return NO_REGISTER; 448 | } 449 | } 450 | 451 | void extend_al_ifneeded(Node *node, Register *reg) { 452 | if (type2size(node->type) > 1) { 453 | printf("movzx %s, al\n", node2reg(node, reg)); 454 | } else { 455 | printf("mov %s, al\n", node2reg(node, reg)); 456 | } 457 | } 458 | 459 | void restore_callee_reg(void) { 460 | // stored in retain_reg() or 461 | // puts("mov r15, [rbp-24]");in ND_FUNC 462 | int j; 463 | // because r12,...are callee-savevd 464 | for (j = 2; j >= 0; j--) { 465 | // only registers already stored will be restoed 466 | if (reg_table[j] >= 0) { // used (>= 1) 467 | printf("mov %s, qword ptr [rbp-%d]\n", registers64[j], j * 8 + 8); 468 | } 469 | } 470 | if (reg_table[5] > 0) { // treat as r15 471 | printf("mov rsp, r15\n"); 472 | puts("mov r15, qword ptr [rbp-32]"); 473 | } 474 | } 475 | 476 | int save_reg(void) { 477 | int j; 478 | int stored_cnt = 0; 479 | // because only r10 and r11 are caller-saved 480 | for (j = 3; j < 5; j++) { 481 | if (reg_table[j] <= 0) 482 | continue; 483 | printf("push %s\n", registers64[j]); 484 | stored_cnt++; 485 | } 486 | return stored_cnt; 487 | } 488 | 489 | int restore_reg(void) { 490 | int j; 491 | int restored_cnt = 0; 492 | // 4 because only r10 and r11 are caller-saved 493 | for (j = 4; j >= 3; j--) { 494 | if (reg_table[j] <= 0) 495 | continue; 496 | printf("pop %s\n", registers64[j]); 497 | restored_cnt++; 498 | } 499 | return restored_cnt; 500 | } 501 | 502 | Register *gen_register_rightval(Node *node, int unused_eval) { 503 | Register *temp_reg; 504 | Register *lhs_reg; 505 | Register *rhs_reg; 506 | int j = 0; 507 | int cur_if_cnt; 508 | int func_call_float_cnt = 0; 509 | int func_call_should_sub_rsp = 0; 510 | 511 | if (!node) { 512 | return NO_REGISTER; 513 | } 514 | 515 | // Write down line number 516 | if (node->pline >= 0) { 517 | // 1 means the file number 518 | printf(".loc 1 %d\n", node->pline); 519 | } 520 | if (unused_eval && 521 | (node->ty == ND_NUM || node->ty == ND_FLOAT || node->ty == ND_STRING)) { 522 | // 未使用な式なので0 を返す 523 | return NO_REGISTER; 524 | } 525 | switch (node->ty) { 526 | case ND_NUM: 527 | temp_reg = retain_reg(); 528 | if (type2size(node->type) == 1) { 529 | // Delete previous value because of mov al, %ld will not delete all 530 | // value in rax 531 | printf("xor %s, %s\n", size2reg(8, temp_reg), 532 | size2reg(8, temp_reg)); 533 | } 534 | printf("mov %s, %ld\n", node2reg(node, temp_reg), node->num_val); 535 | return temp_reg; 536 | 537 | case ND_FLOAT: 538 | temp_reg = float_retain_reg(); 539 | printf("%s %s, %s[rip]\n", type2mov(node->type), 540 | node2reg(node, temp_reg), node->name); 541 | return temp_reg; 542 | 543 | case ND_STRING: 544 | case ND_SYMBOL: 545 | temp_reg = retain_reg(); 546 | printf("lea %s, qword ptr %s[rip]\n", size2reg(8, temp_reg), 547 | node->name); 548 | return temp_reg; 549 | // return with toplevel char ptr. 550 | 551 | case ND_EXTERN_SYMBOL: 552 | // TODO should delete 553 | temp_reg = retain_reg(); 554 | printf("mov %s, qword ptr [rip + %s@GOTPCREL]\n", 555 | size2reg(8, temp_reg), node->name); 556 | printf("mov %s, qword ptr [%s]\n", size2reg(8, temp_reg), 557 | size2reg(8, temp_reg)); 558 | return temp_reg; 559 | 560 | case ND_IDENT: 561 | if (node->type->ty == TY_ARRAY) { 562 | return gen_register_leftval(node); 563 | } else { 564 | temp_reg = malloc(sizeof(Register)); 565 | if (node->local_variable->lvar_offset < 0) { 566 | temp_reg->id = -node->local_variable->lvar_offset; 567 | temp_reg->kind = R_REVERSED_LVAR; 568 | } else { 569 | temp_reg->id = node->local_variable->lvar_offset; 570 | temp_reg->kind = R_LVAR; 571 | } 572 | temp_reg->name = NULL; 573 | temp_reg->size = type2size(node->type); 574 | return temp_reg; 575 | } 576 | 577 | case ND_GLOBAL_IDENT: 578 | if (node->type->ty == TY_ARRAY) { 579 | return gen_register_leftval(node); 580 | } else { 581 | temp_reg = malloc(sizeof(Register)); 582 | temp_reg->id = 0; 583 | temp_reg->kind = R_GVAR; 584 | temp_reg->name = node->name; 585 | temp_reg->size = type2size(node->type); 586 | return temp_reg; 587 | } 588 | 589 | case ND_DOT: 590 | lhs_reg = gen_register_leftval(node->lhs); 591 | switch (node->type->ty) { 592 | case TY_ARRAY: 593 | if (node->type->offset > 0) { 594 | printf("add %s, %d\n", size2reg(8, lhs_reg), 595 | node->type->offset); 596 | } 597 | break; 598 | case TY_FLOAT: 599 | case TY_DOUBLE: 600 | temp_reg = float_retain_reg(); 601 | printf("%s %s, [%s+%d]\n", type2mov(node->type), 602 | node2reg(node, temp_reg), id2reg64(lhs_reg->id), 603 | node->type->offset); 604 | release_reg(lhs_reg); 605 | return temp_reg; 606 | default: 607 | printf("mov %s, [%s+%d]\n", node2reg(node, lhs_reg), 608 | id2reg64(lhs_reg->id), node->type->offset); 609 | break; 610 | } 611 | return lhs_reg; 612 | case ND_ASSIGN: 613 | // This behaivour can be revised. like [rbp-8+2] 614 | if (node->lhs->ty == ND_IDENT || node->lhs->ty == ND_GLOBAL_IDENT) { 615 | lhs_reg = gen_register_rightval(node->lhs, 0); 616 | rhs_reg = gen_register_rightval(node->rhs, 0); 617 | secure_mutable_with_type(rhs_reg, node->lhs->type); 618 | if (node->lhs->type->ty == TY_FLOAT || 619 | node->lhs->type->ty == TY_DOUBLE) { 620 | printf("%s %s, %s\n", type2mov(node->rhs->type), 621 | node2reg(node->lhs, lhs_reg), 622 | node2reg(node->lhs, rhs_reg)); 623 | } else { 624 | // TODO 625 | printf("mov %s, %s\n", node2reg(node->lhs, lhs_reg), 626 | node2reg(node->lhs, rhs_reg)); 627 | } 628 | release_reg(rhs_reg); 629 | if (unused_eval) { 630 | release_reg(lhs_reg); 631 | } 632 | return lhs_reg; 633 | } else if (node->lhs->ty == ND_DOT && node->lhs->type->offset > 0) { 634 | /* 635 | add r12, 152 636 | mov qword ptr [r12], r13 637 | */ 638 | // can be written as 639 | /* 640 | mov qword ptr [r12+152], r13 641 | */ 642 | lhs_reg = gen_register_leftval(node->lhs->lhs); 643 | if (node->rhs->ty == ND_NUM) { 644 | rhs_reg = NULL; 645 | // can be written as immutable value 646 | printf("%s %s [%s+%d], %ld\n", type2mov(node->type), 647 | node2specifier(node), id2reg64(lhs_reg->id), 648 | node->lhs->type->offset, node->rhs->num_val); 649 | } else { 650 | rhs_reg = gen_register_rightval(node->rhs, 0); 651 | secure_mutable_with_type(rhs_reg, node->rhs->type); 652 | printf("%s %s [%s+%d], %s\n", type2mov(node->type), 653 | node2specifier(node), id2reg64(lhs_reg->id), 654 | node->lhs->type->offset, node2reg(node->lhs, rhs_reg)); 655 | } 656 | release_reg(lhs_reg); 657 | if (unused_eval) { 658 | release_reg(rhs_reg); 659 | } 660 | return rhs_reg; 661 | } else { 662 | lhs_reg = gen_register_leftval(node->lhs); 663 | rhs_reg = gen_register_rightval(node->rhs, 0); 664 | secure_mutable_with_type(rhs_reg, node->rhs->type); 665 | printf("%s %s [%s], %s\n", type2mov(node->type), 666 | node2specifier(node), id2reg64(lhs_reg->id), 667 | node2reg(node->lhs, rhs_reg)); 668 | release_reg(lhs_reg); 669 | if (unused_eval) { 670 | release_reg(rhs_reg); 671 | } 672 | return rhs_reg; 673 | } 674 | 675 | case ND_CAST: 676 | lhs_reg = gen_register_rightval(node->lhs, 0); 677 | if (node->type->ty == TY_FLOAT) { 678 | switch (node->lhs->type->ty) { 679 | case TY_INT: 680 | temp_reg = float_retain_reg(); 681 | printf("cvtsi2ss %s, %s\n", node2reg(node, temp_reg), 682 | node2reg(node->lhs, lhs_reg)); 683 | release_reg(lhs_reg); 684 | return temp_reg; 685 | case TY_DOUBLE: 686 | temp_reg = float_retain_reg(); 687 | printf("cvtsd2ss %s, %s\n", node2reg(node, temp_reg), 688 | node2reg(node->lhs, lhs_reg)); 689 | release_reg(lhs_reg); 690 | return temp_reg; 691 | default: 692 | break; 693 | } 694 | return lhs_reg; 695 | } 696 | if (node->type->ty == TY_DOUBLE) { 697 | switch (node->lhs->type->ty) { 698 | case TY_INT: 699 | temp_reg = float_retain_reg(); 700 | printf("cvtsi2sd %s, %s\n", node2reg(node, temp_reg), 701 | node2reg(node->lhs, lhs_reg)); 702 | release_reg(lhs_reg); 703 | return temp_reg; 704 | case TY_FLOAT: 705 | temp_reg = float_retain_reg(); 706 | printf("cvtss2sd %s, %s\n", node2reg(node, temp_reg), 707 | node2reg(node->lhs, lhs_reg)); 708 | release_reg(lhs_reg); 709 | return temp_reg; 710 | default: 711 | break; 712 | } 713 | return lhs_reg; 714 | } 715 | secure_mutable_with_type(lhs_reg, node->lhs->type); 716 | if (node->type->ty == node->lhs->type->ty) { 717 | return lhs_reg; 718 | } 719 | switch (node->lhs->type->ty) { 720 | case TY_CHAR: 721 | // TODO treat as unsigned char. 722 | // for signed char, use movsx instead of. 723 | printf("movzx %s, %s\n", node2reg(node, lhs_reg), 724 | id2reg8(lhs_reg->id)); 725 | break; 726 | case TY_FLOAT: 727 | temp_reg = retain_reg(); 728 | if (node->type->ty == TY_INT) { 729 | // TODO It it not supported yet: to convert float -> char is 730 | // not supported yet 731 | printf("cvttss2si %s, %s\n", node2reg(node->lhs, temp_reg), 732 | node2reg(node->lhs, lhs_reg)); 733 | } else if (node->type->ty == TY_LONG) { 734 | printf("cvttss2siq %s, %s\n", node2reg(node->lhs, temp_reg), 735 | node2reg(node->lhs, lhs_reg)); 736 | } else { 737 | error("Error: float -> unknown type convert: %d\n", 738 | node->type->ty); 739 | } 740 | release_reg(lhs_reg); 741 | return temp_reg; 742 | case TY_DOUBLE: 743 | temp_reg = retain_reg(); 744 | if (node->type->ty == TY_INT) { 745 | // TODO It it not supported yet: to convert float -> char is 746 | // not supported yet 747 | printf("cvttsd2si %s, %s\n", node2reg(node->lhs, temp_reg), 748 | node2reg(node->lhs, lhs_reg)); 749 | } else if (node->type->ty == TY_LONG) { 750 | printf("cvttsd2siq %s, %s\n", node2reg(node->lhs, temp_reg), 751 | node2reg(node->lhs, lhs_reg)); 752 | } else { 753 | error("Error: double -> unknown type convert: %d\n", 754 | node->type->ty); 755 | } 756 | release_reg(lhs_reg); 757 | return temp_reg; 758 | default: 759 | break; 760 | } 761 | return lhs_reg; 762 | 763 | case ND_QUESTION: 764 | // TODO Support double 765 | temp_reg = gen_register_rightval(node->conds[0], 0); 766 | printf("cmp %s, 0\n", node2reg(node->conds[0], temp_reg)); 767 | release_reg(temp_reg); 768 | 769 | cur_if_cnt = if_cnt++; 770 | printf("je .Lendif%d\n", cur_if_cnt); 771 | temp_reg = gen_register_rightval(node->lhs, 0); 772 | printf("jmp .Lelseend%d\n", cur_if_cnt); 773 | printf(".Lendif%d:\n", cur_if_cnt); 774 | // There are else 775 | // TODO この挙動は, retain_reg() 776 | // 直後に同一レジスタが確保されることに依存している 777 | release_reg(temp_reg); 778 | temp_reg = gen_register_rightval(node->rhs, 0); 779 | printf(".Lelseend%d:\n", cur_if_cnt); 780 | return temp_reg; 781 | 782 | case ND_COMMA: 783 | lhs_reg = gen_register_rightval(node->lhs, 0); 784 | rhs_reg = gen_register_rightval(node->rhs, 0); 785 | release_reg(lhs_reg); 786 | return rhs_reg; 787 | 788 | case ND_ADD: 789 | lhs_reg = gen_register_rightval(node->lhs, 0); 790 | rhs_reg = gen_register_rightval(node->rhs, 0); 791 | secure_mutable_with_type(lhs_reg, node->type); 792 | if (node->lhs->type->ty == TY_FLOAT) { 793 | printf("addss %s, %s\n", node2reg(node, lhs_reg), 794 | node2reg(node, rhs_reg)); 795 | } else if (node->lhs->type->ty == TY_DOUBLE) { 796 | printf("addsd %s, %s\n", node2reg(node, lhs_reg), 797 | node2reg(node, rhs_reg)); 798 | } else { 799 | printf("add %s, %s\n", node2reg(node, lhs_reg), 800 | node2reg(node, rhs_reg)); 801 | } 802 | release_reg(rhs_reg); 803 | if (unused_eval) { 804 | release_reg(lhs_reg); 805 | return NO_REGISTER; 806 | } else { 807 | return lhs_reg; 808 | } 809 | 810 | case ND_SUB: 811 | lhs_reg = gen_register_rightval(node->lhs, 0); 812 | rhs_reg = gen_register_rightval(node->rhs, 0); 813 | secure_mutable_with_type(lhs_reg, node->type); 814 | if (node->lhs->type->ty == TY_FLOAT) { 815 | printf("subss %s, %s\n", node2reg(node, lhs_reg), 816 | node2reg(node, rhs_reg)); 817 | } else if (node->lhs->type->ty == TY_DOUBLE) { 818 | printf("subsd %s, %s\n", node2reg(node, lhs_reg), 819 | node2reg(node, rhs_reg)); 820 | } else { 821 | printf("sub %s, %s\n", node2reg(node, lhs_reg), 822 | node2reg(node, rhs_reg)); 823 | } 824 | release_reg(rhs_reg); 825 | if (unused_eval) { 826 | release_reg(lhs_reg); 827 | return NO_REGISTER; 828 | } else { 829 | return lhs_reg; 830 | } 831 | 832 | case ND_MULTIPLY_IMMUTABLE_VALUE: 833 | // after optimizing, this will be deleted. 834 | lhs_reg = gen_register_rightval(node->lhs, 0); 835 | secure_mutable_with_type(lhs_reg, node->lhs->type); 836 | printf("imul %s, %ld\n", node2reg(node, lhs_reg), node->num_val); 837 | return lhs_reg; 838 | 839 | case ND_MUL: 840 | lhs_reg = gen_register_rightval(node->lhs, 0); 841 | rhs_reg = gen_register_rightval(node->rhs, 0); 842 | secure_mutable_with_type(lhs_reg, node->type); 843 | if (node->lhs->type->ty == TY_FLOAT) { 844 | printf("mulss %s, %s\n", node2reg(node, lhs_reg), 845 | node2reg(node, rhs_reg)); 846 | } else if (node->lhs->type->ty == TY_DOUBLE) { 847 | printf("mulsd %s, %s\n", node2reg(node, lhs_reg), 848 | node2reg(node, rhs_reg)); 849 | } else { 850 | printf("imul %s, %s\n", node2reg(node->lhs, lhs_reg), 851 | node2reg(node->rhs, rhs_reg)); 852 | } 853 | release_reg(rhs_reg); 854 | if (unused_eval) { 855 | release_reg(lhs_reg); 856 | return NO_REGISTER; 857 | } else { 858 | return lhs_reg; 859 | } 860 | 861 | case ND_DIV: 862 | lhs_reg = gen_register_rightval(node->lhs, 0); 863 | rhs_reg = gen_register_rightval(node->rhs, 0); 864 | if (node->lhs->type->ty == TY_FLOAT) { 865 | secure_mutable_with_type(lhs_reg, node->lhs->type); 866 | printf("divss %s, %s\n", node2reg(node->lhs, lhs_reg), 867 | node2reg(node->rhs, rhs_reg)); 868 | } else if (node->lhs->type->ty == TY_DOUBLE) { 869 | secure_mutable_with_type(lhs_reg, node->lhs->type); 870 | printf("divsd %s, %s\n", node2reg(node->lhs, lhs_reg), 871 | node2reg(node->rhs, rhs_reg)); 872 | } else { 873 | // TODO should support char 874 | printf("mov %s, %s\n", _rax(node->lhs), 875 | node2reg(node->lhs, lhs_reg)); 876 | puts("cqo"); 877 | printf("idiv %s\n", node2reg(node->rhs, rhs_reg)); 878 | secure_mutable_with_type(lhs_reg, node->lhs->type); 879 | printf("mov %s, %s\n", node2reg(node->lhs, lhs_reg), 880 | _rax(node->lhs)); 881 | } 882 | release_reg(rhs_reg); 883 | if (unused_eval) { 884 | release_reg(lhs_reg); 885 | return NO_REGISTER; 886 | } else { 887 | return lhs_reg; 888 | } 889 | 890 | case ND_MOD: 891 | lhs_reg = gen_register_rightval(node->lhs, 0); 892 | rhs_reg = gen_register_rightval(node->rhs, 0); 893 | // TODO should support char: idiv only support r32 or r64 894 | printf("mov %s, %s\n", _rax(node->lhs), node2reg(node->lhs, lhs_reg)); 895 | puts("cqo"); 896 | printf("idiv %s\n", node2reg(node->rhs, rhs_reg)); 897 | secure_mutable_with_type(lhs_reg, node->lhs->type); 898 | printf("mov %s, %s\n", node2reg(node, lhs_reg), _rdx(node->lhs)); 899 | release_reg(rhs_reg); 900 | if (unused_eval) { 901 | release_reg(lhs_reg); 902 | return NO_REGISTER; 903 | } else { 904 | return lhs_reg; 905 | } 906 | 907 | case ND_XOR: 908 | lhs_reg = gen_register_rightval(node->lhs, 0); 909 | rhs_reg = gen_register_rightval(node->rhs, 0); 910 | secure_mutable_with_type(lhs_reg, node->lhs->type); 911 | printf("xor %s, %s\n", node2reg(node, lhs_reg), 912 | node2reg(node, rhs_reg)); 913 | release_reg(rhs_reg); 914 | return lhs_reg; 915 | 916 | case ND_AND: 917 | lhs_reg = gen_register_rightval(node->lhs, 0); 918 | rhs_reg = gen_register_rightval(node->rhs, 0); 919 | secure_mutable_with_type(lhs_reg, node->lhs->type); 920 | printf("and %s, %s\n", node2reg(node, lhs_reg), 921 | node2reg(node, rhs_reg)); 922 | release_reg(rhs_reg); 923 | return lhs_reg; 924 | break; 925 | 926 | case ND_OR: 927 | lhs_reg = gen_register_rightval(node->lhs, 0); 928 | rhs_reg = gen_register_rightval(node->rhs, 0); 929 | secure_mutable_with_type(lhs_reg, node->lhs->type); 930 | printf("or %s, %s\n", node2reg(node, lhs_reg), 931 | node2reg(node, rhs_reg)); 932 | release_reg(rhs_reg); 933 | return lhs_reg; 934 | 935 | case ND_RSHIFT: 936 | // SHOULD be int 937 | lhs_reg = gen_register_rightval(node->lhs, 0); 938 | rhs_reg = gen_register_rightval(node->rhs, 0); 939 | // FIXME: for signed int (Arthmetric) 940 | // mov rdi[8] -> rax 941 | puts("xor rcx, rcx"); 942 | printf("mov cl, %s\n", size2reg(1, rhs_reg)); 943 | release_reg(rhs_reg); 944 | secure_mutable_with_type(lhs_reg, node->lhs->type); 945 | printf("sar %s, cl\n", node2reg(node->lhs, lhs_reg)); 946 | return lhs_reg; 947 | 948 | case ND_LSHIFT: 949 | // SHOULD be int 950 | lhs_reg = gen_register_rightval(node->lhs, 0); 951 | rhs_reg = gen_register_rightval(node->rhs, 0); 952 | // FIXME: for signed int (Arthmetric) 953 | // mov rdi[8] -> rax 954 | puts("xor rcx, rcx"); 955 | printf("mov cl, %s\n", size2reg(1, rhs_reg)); 956 | release_reg(rhs_reg); 957 | secure_mutable_with_type(lhs_reg, node->lhs->type); 958 | printf("sal %s, cl\n", node2reg(node->lhs, lhs_reg)); 959 | return lhs_reg; 960 | 961 | case ND_ISEQ: 962 | lhs_reg = gen_register_rightval(node->lhs, 0); 963 | rhs_reg = gen_register_rightval(node->rhs, 0); 964 | cmp_regs(node, lhs_reg, rhs_reg); 965 | puts("sete al"); 966 | release_reg(lhs_reg); 967 | release_reg(rhs_reg); 968 | 969 | temp_reg = retain_reg(); 970 | extend_al_ifneeded(node, temp_reg); 971 | return temp_reg; 972 | 973 | case ND_ISNOTEQ: 974 | lhs_reg = gen_register_rightval(node->lhs, 0); 975 | rhs_reg = gen_register_rightval(node->rhs, 0); 976 | cmp_regs(node, lhs_reg, rhs_reg); 977 | puts("setne al"); 978 | release_reg(lhs_reg); 979 | release_reg(rhs_reg); 980 | 981 | temp_reg = retain_reg(); 982 | extend_al_ifneeded(node, temp_reg); 983 | return temp_reg; 984 | 985 | case ND_GREATER: 986 | lhs_reg = gen_register_rightval(node->lhs, 0); 987 | rhs_reg = gen_register_rightval(node->rhs, 0); 988 | secure_mutable_with_type(lhs_reg, node->lhs->type); 989 | cmp_regs(node, lhs_reg, rhs_reg); 990 | if (node->lhs->type->ty == TY_FLOAT || 991 | node->lhs->type->ty == TY_DOUBLE) { 992 | puts("seta al"); 993 | } else { 994 | puts("setg al"); 995 | } 996 | release_reg(lhs_reg); 997 | release_reg(rhs_reg); 998 | 999 | temp_reg = retain_reg(); 1000 | extend_al_ifneeded(node, temp_reg); 1001 | return temp_reg; 1002 | 1003 | case ND_LESS: 1004 | lhs_reg = gen_register_rightval(node->lhs, 0); 1005 | rhs_reg = gen_register_rightval(node->rhs, 0); 1006 | 1007 | if (node->lhs->type->ty == TY_FLOAT || 1008 | node->lhs->type->ty == TY_DOUBLE) { 1009 | secure_mutable_with_type(rhs_reg, node->rhs->type); 1010 | // lhs_reg should be xmm, but rhs should be xmm or memory 1011 | // lhs_reg and rhs_reg are reversed because of comisd 1012 | cmp_regs(node, rhs_reg, lhs_reg); 1013 | puts("seta al"); 1014 | } else { 1015 | secure_mutable_with_type(rhs_reg, node->rhs->type); 1016 | cmp_regs(node, lhs_reg, rhs_reg); 1017 | puts("setl al"); 1018 | } 1019 | 1020 | release_reg(lhs_reg); 1021 | release_reg(rhs_reg); 1022 | 1023 | temp_reg = retain_reg(); 1024 | extend_al_ifneeded(node, temp_reg); 1025 | return temp_reg; 1026 | 1027 | case ND_ISMOREEQ: 1028 | lhs_reg = gen_register_rightval(node->lhs, 0); 1029 | rhs_reg = gen_register_rightval(node->rhs, 0); 1030 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1031 | cmp_regs(node, lhs_reg, rhs_reg); 1032 | if (node->lhs->type->ty == TY_FLOAT || 1033 | node->lhs->type->ty == TY_DOUBLE) { 1034 | puts("setnb al"); 1035 | } else { 1036 | puts("setge al"); 1037 | } 1038 | puts("and al, 1"); 1039 | release_reg(lhs_reg); 1040 | release_reg(rhs_reg); 1041 | 1042 | temp_reg = retain_reg(); 1043 | extend_al_ifneeded(node, temp_reg); 1044 | return temp_reg; 1045 | 1046 | case ND_ISLESSEQ: 1047 | lhs_reg = gen_register_rightval(node->lhs, 0); 1048 | rhs_reg = gen_register_rightval(node->rhs, 0); 1049 | if (node->lhs->type->ty == TY_FLOAT || 1050 | node->lhs->type->ty == TY_DOUBLE) { 1051 | // lhs_reg should be xmm, but rhs should be xmm or memory 1052 | // lhs_reg and rhs_reg are reversed because of comisd 1053 | secure_mutable_with_type(rhs_reg, node->rhs->type); 1054 | cmp_regs(node, rhs_reg, lhs_reg); 1055 | puts("setnb al"); 1056 | } else { 1057 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1058 | cmp_regs(node, lhs_reg, rhs_reg); 1059 | puts("setle al"); 1060 | } 1061 | puts("and al, 1"); 1062 | release_reg(lhs_reg); 1063 | release_reg(rhs_reg); 1064 | 1065 | temp_reg = retain_reg(); 1066 | extend_al_ifneeded(node, temp_reg); 1067 | return temp_reg; 1068 | 1069 | case ND_RETURN: 1070 | if (node->lhs) { 1071 | lhs_reg = gen_register_rightval(node->lhs, 0); 1072 | if (node->lhs->type->ty == TY_FLOAT || 1073 | node->lhs->type->ty == TY_DOUBLE) { 1074 | printf("%s xmm0, %s\n", type2mov(node->lhs->type), 1075 | node2reg(node->lhs, lhs_reg)); 1076 | } else { 1077 | printf("mov %s, %s\n", _rax(node->lhs), 1078 | node2reg(node->lhs, lhs_reg)); 1079 | } 1080 | release_reg(lhs_reg); 1081 | } 1082 | restore_callee_reg(); 1083 | puts("mov rsp, rbp"); 1084 | puts("pop rbp"); 1085 | puts("ret"); 1086 | return NO_REGISTER; 1087 | 1088 | case ND_ADDRESS: 1089 | if (node->lhs->ty == ND_IDENT || node->lhs->ty == ND_GLOBAL_IDENT) { 1090 | temp_reg = retain_reg(); 1091 | lhs_reg = gen_register_rightval(node->lhs, 0); 1092 | printf("lea %s, %s\n", id2reg64(temp_reg->id), 1093 | node2reg(node, lhs_reg)); 1094 | release_reg(lhs_reg); 1095 | return temp_reg; 1096 | } else { 1097 | return gen_register_leftval(node->lhs); 1098 | } 1099 | 1100 | case ND_NEG: 1101 | lhs_reg = gen_register_rightval(node->lhs, 0); 1102 | secure_mutable_with_type(lhs_reg, node->type); 1103 | switch (node->type->ty) { 1104 | case TY_FLOAT: 1105 | temp_reg = float_retain_reg(); 1106 | printf("movq %s, qword ptr .LCDNEGFLOAT[rip]\n", 1107 | node2reg(node, temp_reg)); 1108 | printf("xorps %s, %s\n", node2reg(node, lhs_reg), 1109 | node2reg(node, temp_reg)); 1110 | release_reg(temp_reg); 1111 | break; 1112 | case TY_DOUBLE: 1113 | temp_reg = float_retain_reg(); 1114 | printf("movq %s, qword ptr .LCDNEGDOUBLE[rip]\n", 1115 | node2reg(node, temp_reg)); 1116 | printf("xorpd %s, %s\n", node2reg(node, lhs_reg), 1117 | node2reg(node, temp_reg)); 1118 | release_reg(temp_reg); 1119 | break; 1120 | default: 1121 | printf("neg %s\n", node2reg(node, lhs_reg)); 1122 | break; 1123 | } 1124 | return lhs_reg; 1125 | 1126 | case ND_FPLUSPLUS: 1127 | lhs_reg = gen_register_leftval(node->lhs); 1128 | if (unused_eval) { 1129 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1130 | printf("add %s [%s], %ld\n", node2specifier(node), 1131 | id2reg64(lhs_reg->id), node->num_val); 1132 | release_reg(lhs_reg); 1133 | return NO_REGISTER; 1134 | } else { 1135 | temp_reg = retain_reg(); 1136 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1137 | 1138 | if (type2size(node->type) == 1) { 1139 | printf("movzx %s, [%s]\n", size2reg(4, temp_reg), 1140 | id2reg64(lhs_reg->id)); 1141 | } else { 1142 | printf("mov %s, [%s]\n", node2reg(node, temp_reg), 1143 | id2reg64(lhs_reg->id)); 1144 | } 1145 | printf("add %s [%s], %ld\n", node2specifier(node), 1146 | id2reg64(lhs_reg->id), node->num_val); 1147 | release_reg(lhs_reg); 1148 | return temp_reg; 1149 | } 1150 | 1151 | case ND_FSUBSUB: 1152 | lhs_reg = gen_register_leftval(node->lhs); 1153 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1154 | if (unused_eval) { 1155 | printf("sub %s [%s], %ld\n", node2specifier(node), 1156 | id2reg64(lhs_reg->id), node->num_val); 1157 | release_reg(lhs_reg); 1158 | return NO_REGISTER; 1159 | } else { 1160 | temp_reg = retain_reg(); 1161 | 1162 | printf("mov %s, [%s]\n", node2reg(node, temp_reg), 1163 | id2reg64(lhs_reg->id)); 1164 | printf("sub %s [%s], %ld\n", node2specifier(node), 1165 | id2reg64(lhs_reg->id), node->num_val); 1166 | release_reg(lhs_reg); 1167 | return temp_reg; 1168 | } 1169 | 1170 | case ND_APOS: 1171 | lhs_reg = gen_register_rightval(node->lhs, 0); 1172 | printf("cmp %s, 0\n", node2reg(node->lhs, lhs_reg)); 1173 | puts("sete al"); 1174 | release_reg(lhs_reg); 1175 | temp_reg = retain_reg(); 1176 | extend_al_ifneeded(node, temp_reg); 1177 | return temp_reg; 1178 | 1179 | case ND_DEREF: 1180 | lhs_reg = gen_register_rightval(node->lhs, 0); 1181 | // this is because we cannot [[lhs_reg]] (float deref) 1182 | secure_mutable_with_type(lhs_reg, node->lhs->type); 1183 | if (type2size(node->type) == 1) { 1184 | // when reading char, we should read just 1 byte 1185 | printf("movzx %s, byte ptr [%s]\n", size2reg(4, lhs_reg), 1186 | size2reg(8, lhs_reg)); 1187 | } else if (node->type->ty == TY_FLOAT || node->type->ty == TY_DOUBLE) { 1188 | temp_reg = float_retain_reg(); 1189 | printf("%s %s, [%s]\n", type2mov(node->type), 1190 | node2reg(node, temp_reg), size2reg(8, lhs_reg)); 1191 | release_reg(lhs_reg); 1192 | return temp_reg; 1193 | } else if (node->type->ty != TY_ARRAY) { 1194 | printf("mov %s, [%s]\n", node2reg(node, lhs_reg), 1195 | size2reg(8, lhs_reg)); 1196 | } 1197 | return lhs_reg; 1198 | 1199 | case ND_FDEF: 1200 | printf(".type %s,@function\n", node->gen_name); 1201 | printf(".global %s\n", node->gen_name); // to visible for ld 1202 | printf("%s:\n", node->gen_name); 1203 | puts("push rbp"); 1204 | puts("mov rbp, rsp"); 1205 | printf("sub rsp, %d\n", *node->env->rsp_offset_max); 1206 | int is_entrypoint = !(strncmp(node->gen_name, "main", 5)); 1207 | int fdef_int_arguments = 0; 1208 | int fdef_float_arguments = 0; 1209 | j = 0; 1210 | for (fdef_int_arguments = 0; 1211 | (fdef_int_arguments + fdef_float_arguments) < node->argc; j++) { 1212 | if (node->args[j]->type->ty == TY_FLOAT || 1213 | node->args[j]->type->ty == TY_DOUBLE) { 1214 | temp_reg = gen_register_rightval(node->args[j], 0); 1215 | printf("%s %s, %s\n", type2mov(node->args[j]->type), 1216 | node2reg(node->args[j], temp_reg), 1217 | float_arg_registers[fdef_float_arguments]); 1218 | fdef_float_arguments++; 1219 | } else { 1220 | temp_reg = gen_register_rightval(node->args[j], 0); 1221 | printf("mov %s, %s\n", size2reg(8, temp_reg), 1222 | arg_registers[fdef_int_arguments]); 1223 | fdef_int_arguments++; 1224 | } 1225 | } 1226 | if (node->is_omiited) { 1227 | for (j = 0; j < 6; j++) { 1228 | printf("mov [rbp-%d], %s\n", 1229 | node->is_omiited->local_variable->lvar_offset - j * 8, 1230 | arg_registers[j]); 1231 | } 1232 | for (j = 0; j < 8; j++) { 1233 | printf("movaps [rbp-%d], xmm%d\n", 1234 | node->is_omiited->local_variable->lvar_offset - 8 * 6 - 1235 | j * 16, 1236 | j); 1237 | } 1238 | } 1239 | printf("jmp .LFD%s\n", node->gen_name); 1240 | printf(".LFB%s:\n", node->gen_name); 1241 | for (j = 0; j < node->code->len; j++) { 1242 | // read inside functions. 1243 | gen_register_rightval((Node *)node->code->data[j], 1); 1244 | } 1245 | if (node->type->ret->ty == TY_VOID || is_entrypoint) { 1246 | if (!is_entrypoint) { 1247 | restore_callee_reg(); 1248 | } else { 1249 | puts("mov rax, 0"); // main() function will return 0 1250 | } 1251 | puts("mov rsp, rbp"); 1252 | puts("pop rbp"); 1253 | puts("ret"); 1254 | } 1255 | 1256 | printf(".LFD%s:\n", node->gen_name); 1257 | // r10, r11 are caller-saved so no need to consider 1258 | // store callee saved registers. will be restored in 1259 | // restore_callee_reg() r12 will be stored in [rbp-0] r13 will be 1260 | // stored in [rbp-8] r14 will be stored in [rbp-16] 1261 | for (j = 0; j < 3; j++) { 1262 | if (reg_table[j] >= 0) { // used (>= 1) 1263 | printf("mov qword ptr [rbp-%d], %s\n", j * 8 + 8, 1264 | registers64[j]); 1265 | } 1266 | } 1267 | if (reg_table[5] > 0) { // treat as r15 1268 | puts("mov qword ptr [rbp-32], r15"); // store r15 to [rbp-32] 1269 | } 1270 | printf("jmp .LFB%s\n", node->gen_name); 1271 | // Release All Registers. 1272 | release_all_reg(); 1273 | return NO_REGISTER; 1274 | 1275 | case ND_BLOCK: 1276 | for (j = 0; j < node->code->len && node->code->data[j]; j++) { 1277 | gen_register_rightval((Node *)node->code->data[j], 1); 1278 | } 1279 | return NO_REGISTER; 1280 | 1281 | case ND_EXPRESSION_BLOCK: 1282 | if (node->argc > 0) { 1283 | puts("mov rbp, rsp"); 1284 | printf("sub rsp, %d\n", *node->env->rsp_offset_max); 1285 | puts("#test begin expansion"); 1286 | for (j = 0; j < node->argc; j++) { 1287 | // temp_reg = gen_register_rightval(node->args[j], 0); 1288 | gen_register_rightval(node->args[j], 1); 1289 | puts("#test end expansion of args"); 1290 | } 1291 | } 1292 | for (j = 0; j < node->code->len && node->code->data[j]; j++) { 1293 | gen_register_rightval((Node *)node->code->data[j], 1); 1294 | } 1295 | if (node->argc > 0) { 1296 | puts("mov rsp, rbp"); 1297 | puts("#test end expansion "); 1298 | } 1299 | return NO_REGISTER; 1300 | 1301 | case ND_FUNC: 1302 | for (j = 0; j < node->argc; j++) { 1303 | temp_reg = gen_register_rightval(node->args[j], 0); 1304 | if (node->args[j]->type->ty == TY_FLOAT || 1305 | node->args[j]->type->ty == TY_DOUBLE) { 1306 | printf("%s %s, %s\n", type2mov(node->args[j]->type), 1307 | float_arg_registers[func_call_float_cnt], 1308 | node2reg(node->args[j], temp_reg)); 1309 | func_call_float_cnt++; 1310 | } else if (node->args[j]->type->ty == TY_STRUCT) { 1311 | int k = 0; 1312 | switch (temp_reg->kind) { 1313 | case R_GVAR: 1314 | func_call_should_sub_rsp += type2size(node->args[j]->type); 1315 | for (k = type2size(node->args[j]->type) - 8; k >= 0; 1316 | k -= 8) { 1317 | printf("push qword ptr %s[rip+%d]\n", temp_reg->name, 1318 | k); 1319 | } 1320 | break; 1321 | case R_LVAR: 1322 | func_call_should_sub_rsp += type2size(node->args[j]->type); 1323 | for (k = type2size(node->args[j]->type) - 8; k >= 0; 1324 | k -= 8) { 1325 | printf("push qword ptr [rbp-%d]\n", temp_reg->id - k); 1326 | } 1327 | break; 1328 | default: 1329 | error("Error: Not IMplemented On ND_FUNC w/ TY_STRUCT\n"); 1330 | } 1331 | // TODO This will create "mov eax, 1" even though no float 1332 | // arugments 1333 | func_call_float_cnt++; 1334 | } else { 1335 | secure_mutable_with_type(temp_reg, node->type); 1336 | printf("push %s\n", id2reg64(temp_reg->id)); 1337 | } 1338 | release_reg(temp_reg); 1339 | } 1340 | for (j = node->argc - 1 - func_call_float_cnt; j >= 0; j--) { 1341 | // because of function call will break these registers 1342 | printf("pop %s\n", arg_registers[j]); 1343 | } 1344 | 1345 | save_reg(); 1346 | printf("mov eax, %d\n", func_call_float_cnt); 1347 | 1348 | if (reg_table[5] < 0) { 1349 | reg_table[5] = 1; 1350 | } 1351 | puts("mov r15, rsp"); 1352 | puts("and rsp, -16"); 1353 | if (node->gen_name) { // ND_GLOBAL_IDENT, called from local vars. 1354 | printf("call %s\n", 1355 | node->gen_name); // rax should be aligned with the size 1356 | } else if (node->type->context->is_previous_class) { 1357 | char *buf = malloc(sizeof(char) * 256); 1358 | snprintf(buf, 255, "%s::%s", node->type->context->is_previous_class, 1359 | node->type->context->method_name); 1360 | printf("call %s\n", mangle_func_name(buf)); 1361 | } else { 1362 | temp_reg = gen_register_rightval(node->lhs, 0); 1363 | secure_mutable_with_type(temp_reg, node->lhs->type); 1364 | printf("call %s\n", size2reg(8, temp_reg)); 1365 | release_reg(temp_reg); 1366 | } 1367 | puts("mov rsp, r15"); 1368 | if (func_call_should_sub_rsp > 0) { 1369 | printf("sub rsp, -%d\n", func_call_should_sub_rsp); 1370 | } 1371 | restore_reg(); 1372 | 1373 | if (node->type->ty == TY_VOID || unused_eval == 1) { 1374 | return NO_REGISTER; 1375 | } else if (node->type->ty == TY_FLOAT || node->type->ty == TY_DOUBLE) { 1376 | temp_reg = float_retain_reg(); 1377 | // movaps just move all of xmmx 1378 | printf("movaps %s, xmm0\n", node2reg(node, temp_reg)); 1379 | return temp_reg; 1380 | } else { 1381 | temp_reg = retain_reg(); 1382 | printf("mov %s, %s\n", node2reg(node, temp_reg), _rax(node)); 1383 | return temp_reg; 1384 | } 1385 | 1386 | case ND_VAARG: 1387 | // SEE in AMD64 ABI Draft 0.99.7 p.53 (uglibc.org ) 1388 | lhs_reg = gen_register_leftval(node->lhs); // meaning ap 1389 | temp_reg = retain_reg(); 1390 | 1391 | // gp_offset 1392 | printf("mov eax, [%s]\n", id2reg64(lhs_reg->id)); // get gp_offset 1393 | printf("mov edx, eax\n"); 1394 | printf("add rdx, 8\n"); 1395 | printf("add rax, [%s+16]\n", id2reg64(lhs_reg->id)); 1396 | printf("mov [%s], edx\n", id2reg64(lhs_reg->id)); 1397 | // only supported register 1398 | printf("mov %s, [rax]\n", 1399 | node2reg(node, temp_reg)); // 1->reg_saved_area 1400 | release_reg(lhs_reg); 1401 | 1402 | return temp_reg; 1403 | 1404 | case ND_VASTART: 1405 | lhs_reg = gen_register_leftval(node->lhs); // meaning ap's address 1406 | // node->num_val means the first undefined argument No. 1407 | // from lval_offset: 1408 | // rbp-80 : r0 1409 | // rbp-72 : r1 1410 | // ... 1411 | // rbp-56: r6 1412 | printf("mov dword ptr [%s], %ld\n", id2reg64(lhs_reg->id), 1413 | // omitted_argc * 8 1414 | node->num_val * 8); 1415 | printf("mov dword ptr [%s+4], 304\n", id2reg64(lhs_reg->id)); 1416 | printf("lea rax, [rbp-%d]\n", node->rhs->local_variable->lvar_offset); 1417 | printf("mov qword ptr [%s+16], rax\n", id2reg64(lhs_reg->id)); 1418 | return NO_REGISTER; 1419 | 1420 | case ND_VAEND: 1421 | return NO_REGISTER; 1422 | 1423 | case ND_GOTO: 1424 | printf("jmp %s\n", node->name); 1425 | return NO_REGISTER; 1426 | 1427 | case ND_LOR: 1428 | lhs_reg = gen_register_rightval(node->lhs, 0); 1429 | printf("cmp %s, 0\n", node2reg(node->lhs, lhs_reg)); 1430 | release_reg(lhs_reg); 1431 | cur_if_cnt = if_cnt++; 1432 | printf("jne .Lorend%d\n", cur_if_cnt); 1433 | rhs_reg = gen_register_rightval(node->rhs, 0); 1434 | printf("cmp %s, 0\n", node2reg(node->rhs, rhs_reg)); 1435 | release_reg(rhs_reg); 1436 | printf(".Lorend%d:\n", cur_if_cnt); 1437 | puts("setne al"); 1438 | temp_reg = retain_reg(); 1439 | if (type2size(node->type) == 1) { 1440 | printf("mov %s, al\n", node2reg(node, temp_reg)); 1441 | } else { 1442 | printf("movzx %s, al\n", node2reg(node, temp_reg)); 1443 | } 1444 | return temp_reg; 1445 | 1446 | case ND_LAND: 1447 | lhs_reg = gen_register_rightval(node->lhs, 0); 1448 | printf("cmp %s, 0\n", node2reg(node->lhs, lhs_reg)); 1449 | release_reg(lhs_reg); 1450 | cur_if_cnt = if_cnt++; 1451 | printf("je .Lorend%d\n", cur_if_cnt); 1452 | rhs_reg = gen_register_rightval(node->rhs, 0); 1453 | printf("cmp %s, 0\n", node2reg(node->rhs, rhs_reg)); 1454 | release_reg(rhs_reg); 1455 | printf(".Lorend%d:\n", cur_if_cnt); 1456 | puts("setne al"); 1457 | temp_reg = retain_reg(); 1458 | if (type2size(node->type) == 1) { 1459 | printf("mov %s, al\n", node2reg(node, temp_reg)); 1460 | } else { 1461 | printf("movzx %s, al\n", node2reg(node, temp_reg)); 1462 | } 1463 | return temp_reg; 1464 | 1465 | case ND_IF: 1466 | temp_reg = gen_register_rightval(node->args[0], 0); 1467 | printf("cmp %s, 0\n", node2reg(node->args[0], temp_reg)); 1468 | release_reg(temp_reg); 1469 | cur_if_cnt = if_cnt++; 1470 | printf("je .Lendif%d\n", cur_if_cnt); 1471 | gen_register_rightval(node->lhs, 1); 1472 | if (node->rhs) { 1473 | printf("jmp .Lelseend%d\n", cur_if_cnt); 1474 | } 1475 | printf(".Lendif%d:\n", cur_if_cnt); 1476 | if (node->rhs) { 1477 | // There are else 1478 | gen_register_rightval(node->rhs, 1); 1479 | printf(".Lelseend%d:\n", cur_if_cnt); 1480 | } 1481 | return NO_REGISTER; 1482 | 1483 | case ND_SWITCH: 1484 | // TODO: quite dirty 1485 | cur_if_cnt = for_while_cnt++; 1486 | int prev_env_for_while_switch = env_for_while_switch; 1487 | env_for_while_switch = cur_if_cnt; 1488 | 1489 | lhs_reg = gen_register_rightval(node->lhs, 0); 1490 | // find CASE Labels and lookup into args[0]->code->data 1491 | for (j = 0; node->rhs->code->data[j]; j++) { 1492 | Node *curnode = (Node *)node->rhs->code->data[j]; 1493 | if (curnode->ty == ND_CASE) { 1494 | char *input = malloc(sizeof(char) * 256); 1495 | snprintf(input, 255, ".L%dC%d", cur_if_cnt, j); 1496 | curnode->name = input; // assign unique ID 1497 | 1498 | if (type2size(node->lhs->type) != 1499 | type2size(curnode->lhs->type)) { 1500 | curnode->lhs = new_node(ND_CAST, curnode->lhs, NULL); 1501 | curnode->lhs->type = node->lhs->type; 1502 | } 1503 | temp_reg = gen_register_rightval(curnode->lhs, 0); 1504 | printf("cmp %s, %s\n", node2reg(node->lhs, lhs_reg), 1505 | node2reg(curnode->lhs, temp_reg)); 1506 | release_reg(temp_reg); 1507 | printf("je %s\n", input); 1508 | } 1509 | if (curnode->ty == ND_DEFAULT) { 1510 | char *input = malloc(sizeof(char) * 256); 1511 | snprintf(input, 255, ".L%dC%d", cur_if_cnt, j); 1512 | curnode->name = input; 1513 | printf("jmp %s\n", input); 1514 | } 1515 | } 1516 | release_reg(lhs_reg); 1517 | // content 1518 | gen_register_rightval(node->rhs, 1); 1519 | printf(".Lend%d:\n", cur_if_cnt); 1520 | env_for_while_switch = prev_env_for_while_switch; 1521 | return NO_REGISTER; 1522 | 1523 | case ND_CASE: 1524 | case ND_DEFAULT: 1525 | // just an def. of goto 1526 | // saved with input 1527 | if (!node->name) { 1528 | error("Error: case statement without switch\n"); 1529 | } 1530 | printf("%s:\n", node->name); 1531 | return NO_REGISTER; 1532 | 1533 | case ND_FOR: 1534 | case ND_WHILE: 1535 | case ND_DOWHILE: 1536 | cur_if_cnt = for_while_cnt++; 1537 | int prev_env_for_while = env_for_while; 1538 | prev_env_for_while_switch = env_for_while_switch; 1539 | env_for_while = cur_if_cnt; 1540 | env_for_while_switch = cur_if_cnt; 1541 | 1542 | switch (node->ty) { 1543 | case ND_FOR: 1544 | gen_register_rightval(node->conds[0], 1); 1545 | printf("jmp .Lcondition%d\n", cur_if_cnt); 1546 | printf(".Lbeginwork%d:\n", cur_if_cnt); 1547 | gen_register_rightval(node->rhs, 1); 1548 | printf(".Lbegin%d:\n", cur_if_cnt); 1549 | gen_register_rightval(node->conds[2], 1); 1550 | printf(".Lcondition%d:\n", cur_if_cnt); 1551 | temp_reg = gen_register_rightval(node->conds[1], 0); 1552 | 1553 | printf("cmp %s, 0\n", node2reg(node->conds[1], temp_reg)); 1554 | release_reg(temp_reg); 1555 | printf("jne .Lbeginwork%d\n", cur_if_cnt); 1556 | printf(".Lend%d:\n", cur_if_cnt); 1557 | break; 1558 | 1559 | case ND_WHILE: 1560 | printf(".Lbegin%d:\n", cur_if_cnt); 1561 | lhs_reg = gen_register_rightval(node->lhs, 0); 1562 | printf("cmp %s, 0\n", node2reg(node->lhs, lhs_reg)); 1563 | release_reg(lhs_reg); 1564 | printf("je .Lend%d\n", cur_if_cnt); 1565 | gen_register_rightval(node->rhs, 1); 1566 | printf("jmp .Lbegin%d\n", cur_if_cnt); 1567 | printf(".Lend%d:\n", cur_if_cnt); 1568 | break; 1569 | 1570 | case ND_DOWHILE: 1571 | printf(".Lbegin%d:\n", cur_if_cnt); 1572 | gen_register_rightval(node->rhs, 1); 1573 | lhs_reg = gen_register_rightval(node->lhs, 0); 1574 | printf("cmp %s, 0\n", node2reg(node->lhs, lhs_reg)); 1575 | release_reg(lhs_reg); 1576 | printf("jne .Lbegin%d\n", cur_if_cnt); 1577 | printf(".Lend%d:\n", cur_if_cnt); 1578 | break; 1579 | default: 1580 | break; 1581 | } 1582 | 1583 | env_for_while = prev_env_for_while; 1584 | env_for_while_switch = prev_env_for_while_switch; 1585 | return NO_REGISTER; 1586 | 1587 | case ND_BREAK: 1588 | printf("jmp .Lend%d #break\n", env_for_while_switch); 1589 | return NO_REGISTER; 1590 | 1591 | case ND_CONTINUE: 1592 | printf("jmp .Lbegin%d\n", env_for_while); 1593 | return NO_REGISTER; 1594 | 1595 | default: 1596 | error("Error: Incorrect Registers %d.\n", node->ty); 1597 | } 1598 | return NO_REGISTER; 1599 | } 1600 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | // main.h 2 | /* 3 | Copyright 2019, 2020 hiromi-mi 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | #ifndef __HANANDO_FUKUI_MAIN__ 19 | #define __HANANDO_FUKUI_MAIN__ 20 | 21 | typedef enum { 22 | TK_ADD = '+', 23 | TK_SUB = '-', 24 | TK_EQUAL = '=', 25 | TK_BLOCKBEGIN = '{', 26 | TK_BLOCKEND = '}', 27 | TK_QUESTION = '?', 28 | TK_S = '#', 29 | TK_PLUSPLUS = 86, // '+' + '+', 30 | TK_SUBSUB = 90, // '-' + '-', 31 | TK_NUM = 256, 32 | TK_FLOAT, 33 | TK_DOUBLE, 34 | TK_IDENT, 35 | TK_EOF, 36 | TK_ISEQ, 37 | TK_ISNOTEQ, 38 | TK_IF, 39 | TK_WHILE, 40 | TK_FOR, 41 | TK_ELSE, 42 | TK_DO, 43 | TK_RSHIFT, 44 | TK_LSHIFT, 45 | TK_OPAS, 46 | TK_GOTO, 47 | TK_RETURN, 48 | TK_SIZEOF, 49 | TK_OR, 50 | TK_AND, 51 | TK_STRUCT, 52 | TK_CLASS, 53 | TK_TYPEDEF, 54 | TK_STRING, 55 | TK_SPACE, 56 | TK_NEWLINE, 57 | TK_ISLESSEQ, 58 | TK_ISMOREEQ, 59 | TK_BREAK, 60 | TK_CONTINUE, 61 | TK_NULL, 62 | TK_SWITCH, 63 | TK_CASE, 64 | TK_ENUM, 65 | TK_ARROW, 66 | TK_CONST, 67 | TK_DEFAULT, 68 | TK_EXTERN, 69 | TK_OMIITED, // ... 70 | TK_PUBLIC, 71 | TK_PRIVATE, 72 | TK_STATIC, 73 | TK_PROTECTED, 74 | TK_COLONCOLON, 75 | TK_TEMPLATE, 76 | TK_TYPENAME, 77 | TK_TRY, 78 | TK_CATCH, 79 | TK_THROW, 80 | TK_DECLTYPE, 81 | TK_NEW, 82 | } TokenConst; 83 | 84 | typedef enum { 85 | ND_ADD = '+', 86 | ND_SUB = '-', 87 | ND_MUL = '*', 88 | ND_ASSIGN = '=', 89 | ND_DIV = '/', 90 | ND_MOD = '%', 91 | ND_XOR = '^', 92 | ND_OR = '|', 93 | ND_AND = '&', 94 | ND_DOT = '.', 95 | ND_LESS = '<', 96 | ND_GREATER = '>', 97 | ND_COMMA = ',', 98 | ND_APOS = '!', 99 | ND_QUESTION = '?', 100 | ND_NUM = 256, 101 | ND_MULTIPLY_IMMUTABLE_VALUE, 102 | ND_FLOAT, 103 | ND_IDENT, 104 | ND_GLOBAL_IDENT, 105 | ND_ISEQ, 106 | ND_ISNOTEQ, 107 | ND_ISLESSEQ, 108 | ND_ISMOREEQ, 109 | ND_FUNC, 110 | ND_FDEF, 111 | ND_RSHIFT, 112 | ND_LSHIFT, 113 | ND_INC, 114 | ND_DEC, 115 | ND_BLOCK, 116 | ND_IF, 117 | ND_WHILE, 118 | ND_DOWHILE, 119 | ND_FOR, 120 | ND_RETURN, 121 | ND_ADDRESS, 122 | ND_DEREF, 123 | ND_GOTO, 124 | ND_LOR, 125 | ND_LAND, 126 | ND_FPLUSPLUS, 127 | ND_FSUBSUB, 128 | ND_STRING, 129 | ND_CONTINUE, 130 | ND_BREAK, 131 | ND_NEG, 132 | ND_CAST, 133 | ND_SWITCH, 134 | ND_CASE, 135 | ND_EXTERN_SYMBOL, 136 | ND_DEFAULT, 137 | ND_VAARG, 138 | ND_VASTART, 139 | ND_SYMBOL, 140 | ND_VAEND, 141 | ND_EXPRESSION_BLOCK, 142 | ND_SIZEOF, 143 | ND_TRY, 144 | ND_THROW, 145 | } NodeType; 146 | 147 | typedef struct { 148 | TokenConst ty; 149 | long num_val; 150 | double float_val; 151 | char *input; 152 | int pos; 153 | int type_size; // to treat 'a' as char. only used in TK_NUM 154 | int pline; 155 | } Token; 156 | 157 | typedef struct { 158 | Token **data; 159 | long capacity; 160 | long len; 161 | } Vector; 162 | 163 | typedef enum { 164 | PRIVATE, 165 | PUBLIC, 166 | HIDED, 167 | PROTECTED, 168 | } MemberAccess; 169 | 170 | typedef struct { 171 | Vector *keys; 172 | Vector *vals; 173 | } Map; 174 | 175 | typedef struct Context { 176 | char *is_previous_class; 177 | char *method_name; 178 | } Context; 179 | 180 | typedef struct Type { 181 | enum { 182 | TY_INT = 3, 183 | TY_PTR, 184 | TY_ARRAY, 185 | TY_CHAR, 186 | TY_LONG, 187 | TY_STRUCT, 188 | TY_CLASS, 189 | TY_VOID, 190 | TY_FLOAT, 191 | TY_DOUBLE, 192 | TY_FUNC, 193 | TY_TEMPLATE, 194 | TY_AUTO, 195 | } ty; 196 | Map *structure; // 197 | struct Type *ptrof; 198 | struct Type *ret; 199 | int argc; 200 | struct Type *args[6]; 201 | int array_size; 202 | int offset; 203 | int is_const; 204 | int is_static; 205 | int is_omiited; 206 | int is_extern; 207 | char *var_name; // for args 208 | char *type_name; 209 | MemberAccess memaccess; 210 | Context *context; 211 | Map *local_typedb; 212 | struct Type *base_class; 213 | } Type; 214 | 215 | typedef struct Env { 216 | struct Env *env; 217 | Map *idents; 218 | int *rsp_offset_max; 219 | int rsp_offset; 220 | Type *ret; 221 | Type *current_class; 222 | Type *current_func; 223 | } Env; 224 | 225 | typedef struct LocalVariable { 226 | int lvar_offset; 227 | Type *type; 228 | char *name; 229 | } LocalVariable; 230 | 231 | typedef struct GlobalVariable { 232 | Vector *inits; // Node* 233 | Type *type; 234 | char *name; 235 | } GlobalVariable; 236 | 237 | typedef struct Node { 238 | NodeType ty; 239 | struct Node *lhs; 240 | struct Node *rhs; 241 | struct Node *conds[3]; 242 | struct Node *args[6]; 243 | Vector *code; 244 | long argc; 245 | long num_val; 246 | double float_val; 247 | char *name; // Name Before Mangled 248 | char *gen_name; // Mangled Name 249 | Env *env; 250 | Type *type; 251 | Type *sizeof_type; 252 | struct Node *is_omiited; 253 | int is_static; 254 | int is_recursive; 255 | int pline; 256 | struct Node *funcdef; 257 | LocalVariable *local_variable; 258 | } Node; 259 | 260 | // Extended Register. with global variables, local variables, memory map, 261 | // registers, ... 262 | typedef struct Register { 263 | enum { R_REGISTER, R_LVAR, R_REVERSED_LVAR, R_GVAR, R_XMM } kind; 264 | int id; // offset or type 265 | int size; 266 | char *name; // for global variable 267 | } Register; 268 | 269 | Map *new_map(); 270 | int map_put(Map *map, const char *key, const void *val); 271 | void *map_get(const Map *map, const char *key); 272 | Vector *new_vector(); 273 | int vec_push(Vector *vec, Token *element); 274 | 275 | void preprocess(Vector *pre_tokens, char *fname); 276 | 277 | Vector *read_tokenize(char *fname); 278 | Vector *tokenize(char *p); 279 | 280 | Node *new_node(NodeType ty, Node *lhs, Node *rhs); 281 | Node *new_num_node(long num_val); 282 | int cnt_size(Type *type); 283 | 284 | Node *analyzing(Node *node); 285 | char *mangle_func_name(char *name); 286 | Type *duplicate_type(Type *old_type); 287 | Type *copy_type(Type *old_type, Type *type); 288 | Type *find_typed_db(char *input, Map *db); 289 | Type *find_typed_db_without_copy(char *input, Map *db); 290 | Type *class_declaration(Map *local_typedb); 291 | Type *new_type(void); 292 | int type2size(Type *type); 293 | 294 | void gen_register_top(void); 295 | void init_reg_registers(void); 296 | void globalvar_gen(void); 297 | 298 | char *strdup(const char *s); 299 | 300 | // util.c 301 | void test_map(void); 302 | _Noreturn void error(const char *str, ...); 303 | 304 | #endif /* __HANANDO_FUKUI_MAIN__ */ 305 | -------------------------------------------------------------------------------- /preprocess.c: -------------------------------------------------------------------------------- 1 | // preprocess.c 2 | // SPDX-License-Identifier: Apache-2.0 3 | /* 4 | Copyright 2020 hiromi-mi 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include "main.h" 20 | #include "selfhost.h" 21 | #include 22 | #include 23 | #include 24 | // dirname() 25 | #include 26 | 27 | extern Vector *tokens; 28 | 29 | void preprocess(Vector *pre_tokens, char *fname) { 30 | Map *defined = new_map(); 31 | // when compiled with hanando 32 | Token *hanando_fukui_compiled = malloc(sizeof(Token)); 33 | hanando_fukui_compiled->ty = TK_NUM; 34 | hanando_fukui_compiled->pos = 0; 35 | hanando_fukui_compiled->num_val = 1; 36 | hanando_fukui_compiled->input = "__HANANDO_FUKUI__"; 37 | map_put(defined, "__HANANDO_FUKUI__", hanando_fukui_compiled); 38 | 39 | int skipped = 0; 40 | int j, k; 41 | for (j = 0; j < pre_tokens->len; j++) { 42 | if (pre_tokens->data[j]->ty == '#') { 43 | // preprocessor begin 44 | j++; 45 | if (strcmp(pre_tokens->data[j]->input, "ifndef") == 0) { 46 | if (map_get(defined, pre_tokens->data[j + 2]->input)) { 47 | skipped = 1; 48 | // TODO skip until #endif 49 | // read because of defined. 50 | } else { 51 | while (pre_tokens->data[j]->ty != TK_NEWLINE && 52 | pre_tokens->data[j]->ty != TK_EOF) { 53 | j++; 54 | } 55 | } 56 | continue; 57 | } 58 | if (strcmp(pre_tokens->data[j]->input, "ifdef") == 0) { 59 | if (!map_get(defined, pre_tokens->data[j + 2]->input)) { 60 | skipped = 1; 61 | // TODO skip until #endif 62 | // read because of defined. 63 | } else { 64 | while (pre_tokens->data[j]->ty != TK_NEWLINE && 65 | pre_tokens->data[j]->ty != TK_EOF) { 66 | j++; 67 | } 68 | } 69 | continue; 70 | } 71 | if (strcmp(pre_tokens->data[j]->input, "endif") == 0) { 72 | skipped = 0; 73 | while (pre_tokens->data[j]->ty != TK_NEWLINE && 74 | pre_tokens->data[j]->ty != TK_EOF) { 75 | j++; 76 | } 77 | continue; 78 | } 79 | // skip without #ifdef, #endif. TODO dirty 80 | if (skipped != 0) { 81 | continue; 82 | } 83 | if (strcmp(pre_tokens->data[j]->input, "define") == 0) { 84 | map_put(defined, pre_tokens->data[j + 2]->input, 85 | pre_tokens->data[j + 4]); 86 | while (pre_tokens->data[j]->ty != TK_NEWLINE && 87 | pre_tokens->data[j]->ty != TK_EOF) { 88 | j++; 89 | } 90 | continue; 91 | } 92 | if (strcmp(pre_tokens->data[j]->input, "include") == 0) { 93 | if (pre_tokens->data[j + 2]->ty == TK_STRING) { 94 | char *buf = NULL; 95 | if (fname) { 96 | char *filename; 97 | filename = strdup(fname); 98 | char *basedirname = dirname(filename); 99 | buf = malloc(sizeof(char) * 256); 100 | snprintf(buf, 255, "%s/%s", basedirname, 101 | pre_tokens->data[j + 2]->input); 102 | } else { 103 | buf = pre_tokens->data[j + 2]->input; 104 | } 105 | preprocess(read_tokenize(buf), buf); 106 | // 最後のToken が EOF なので除く 107 | if (tokens->data[tokens->len - 1]->ty == TK_EOF) { 108 | tokens->len--; 109 | } 110 | } 111 | while (pre_tokens->data[j]->ty != TK_NEWLINE && 112 | pre_tokens->data[j]->ty != TK_EOF) { 113 | j++; 114 | } 115 | } 116 | continue; 117 | } 118 | // skip without #ifdef, #endif 119 | if (skipped != 0 || pre_tokens->data[j]->ty == TK_NEWLINE || 120 | pre_tokens->data[j]->ty == TK_SPACE) 121 | continue; 122 | 123 | int called = 0; 124 | for (k = 0; k < defined->keys->len; k++) { 125 | char *chr = (char *)defined->keys->data[k]; 126 | if (pre_tokens->data[j]->ty == TK_IDENT && 127 | strcmp(pre_tokens->data[j]->input, chr) == 0) { 128 | called = 1; 129 | vec_push(tokens, defined->vals->data[k]); 130 | continue; 131 | } 132 | } 133 | if (!called) { 134 | vec_push(tokens, pre_tokens->data[j]); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /samples/1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __HANANDO_FUKUI__ 4 | FILE* fopen(char* name, char* type); 5 | #endif 6 | int main() { 7 | FILE* fp; 8 | fp = fopen("1.c", "r"); 9 | fclose(fp); 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /samples/10.c: -------------------------------------------------------------------------------- 1 | #include "../main.h" 2 | #ifdef __HANANDO_FUKUI__ 3 | FILE* fopen(char* name, char* type); 4 | void* malloc(int size); 5 | void* realloc(void* ptr, int size); 6 | #endif 7 | int main(int argc, char **argv) { 8 | if (argc < 2) { 9 | puts("Incorrect Arguments.\n"); 10 | return 0; 11 | } 12 | puts(argv[1]); 13 | Token *token = malloc(sizeof(Token)); 14 | token->ty = TK_EOF; 15 | token->input = ""; 16 | int j; 17 | for (j = 0; j < 10; j++) { 18 | fprintf(stderr, "j: %d\n", j); 19 | j+1; 20 | fprintf(stderr, "j: %d\n", j); 21 | j+2; 22 | fprintf(stderr, "j: %d\n", j); 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /samples/11.c: -------------------------------------------------------------------------------- 1 | extern int cd[30]; 2 | 3 | #ifdef __HANANDO_FUKUI__ 4 | FILE* fopen(char* name, char* type); 5 | void* malloc(int size); 6 | void* realloc(void* ptr, int size); 7 | #endif 8 | int func2(char* input) { 9 | int k=0; 10 | for (k=0;input[k] != '\0';k++) { 11 | printf("%c S ", input[k]); 12 | if (k > 10) { 13 | putchar('J'); 14 | break; 15 | } 16 | } 17 | putchar('\n'); 18 | return k; 19 | } 20 | int main() { 21 | int j = 0; 22 | char* p = "This is"; 23 | func(p); 24 | func2(p); 25 | char* input; 26 | input = malloc(sizeof(char) * 256); 27 | printf("%c %d\n", *p, 'A' <= *p); 28 | do { 29 | input[j] = *p; 30 | p++; 31 | j++; 32 | } while (('a' <= *p && *p <= 'z') || ('0' <= *p && *p <= '9') || 33 | ('A' <= *p && *p <= 'Z') || *p == '_'); 34 | input[j] = '\0'; 35 | int k=0; 36 | func(input); 37 | func2(input); 38 | printf("%d\n", cd[1]); 39 | if (cd[1] != 9) { 40 | puts("Error! extern does not work!"); 41 | return 1; 42 | } 43 | cd[2]=4; 44 | printf("%d\n", cd[2]); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /samples/11_min.c: -------------------------------------------------------------------------------- 1 | int func2(char* input) { 2 | int k; 3 | //for (k;input[k] != '\0';) { 4 | for (*(input+k);1;1) { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /samples/12.c: -------------------------------------------------------------------------------- 1 | int cd[30]; 2 | 3 | int func(char* input) { 4 | cd[1]=9; 5 | int k=0; 6 | for (k=0;input[k] != '\0';k++) { 7 | printf("%c ", input[k]); 8 | } 9 | putchar('\n'); 10 | return k; 11 | } 12 | -------------------------------------------------------------------------------- /samples/13.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int j = 1 == 2; 3 | printf("%d\n", j); 4 | j = !(1==2); 5 | printf("%d \n", j); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /samples/14.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int a[2]; 3 | a[0] = 450; 4 | a[1] = 435; 5 | printf("%d %ld\n", (long)a[0], (long)a[0]); 6 | printf("%d %ld\n", (long)a[1], (long)a[1]); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /samples/15.c: -------------------------------------------------------------------------------- 1 | /* test */ 2 | int a; 3 | -------------------------------------------------------------------------------- /samples/16.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | long num_val; 3 | char *input; 4 | int pos; 5 | } Token; 6 | 7 | int main() { 8 | Token* a; 9 | } 10 | -------------------------------------------------------------------------------- /samples/18.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int func(char *str, ...); 5 | int main() { 6 | func("Hoge: %s\n", "TEST", 12); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /samples/19.c: -------------------------------------------------------------------------------- 1 | //#include 2 | //#include 3 | #include "../../hoc_nyan/src/hoc.h" 4 | int func(char *str, ...) { 5 | va_list ap; 6 | va_start(ap, str); 7 | /*char* arg = va_arg(ap, int); 8 | puts(arg); 9 | int arg2 = va_arg(ap, int); 10 | printf("%d\n", arg2);*/ 11 | vprintf(str, ap); 12 | va_end(ap); 13 | return 0; 14 | } 15 | 16 | int main() { 17 | func("%d\n", 30); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /samples/2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | char a; 3 | a='b'; 4 | return a; 5 | } 6 | -------------------------------------------------------------------------------- /samples/3.c: -------------------------------------------------------------------------------- 1 | #include "../main.h" 2 | #include 3 | 4 | void* malloc(int size); 5 | int node2(Node* node, int j); 6 | 7 | int getnode(Node* node, int j) { 8 | { 9 | printf("%p\n", node->ty); 10 | printf("%p\n", node->lhs); 11 | printf("%p\n", node->rhs); 12 | printf("%p\n", node->args); 13 | printf("%p\n", node->code); 14 | printf("%p\n", node->argc); 15 | printf("%p\n", node->num_val); 16 | printf("%p\n", node->name); 17 | printf("%p\n", node->env); 18 | printf("%p\n", node->type); 19 | } 20 | puts(node->args[j]->name); 21 | return node->args[j]->ty; 22 | } 23 | 24 | int main() { 25 | puts("aaa"); 26 | int j=1; 27 | Node* node = malloc(sizeof(Node)); 28 | node->args[j]=malloc(sizeof(Node)); 29 | node->args[j]->ty = 36; 30 | node->args[j]->name = "afegerjger\n"; 31 | printf("%d\n", getnode(node, j)); 32 | printf("%d\n", node2(node, j)); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /samples/31.c: -------------------------------------------------------------------------------- 1 | void *malloc(int size); 2 | #include "../main.h" 3 | int main() { 4 | int j=1; 5 | Node* node; 6 | node = malloc(sizeof(Node)); 7 | node->args[j]=malloc(sizeof(Node)); 8 | node->args[j]->ty = 36; 9 | node->args[j]->name = "afegerjger\n"; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /samples/32.c: -------------------------------------------------------------------------------- 1 | void func(const char* str) { 2 | puts(str); 3 | } 4 | 5 | int main() { 6 | func("aaa"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /samples/33.c: -------------------------------------------------------------------------------- 1 | void func(char* str) { 2 | puts(str); 3 | } 4 | 5 | int main() { 6 | func("aaa"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /samples/34.c: -------------------------------------------------------------------------------- 1 | #include "../main.h" 2 | 3 | Type *new_type() { 4 | Type *type = malloc(sizeof(Type)); 5 | type->argc = 0; 6 | type->name = NULL; 7 | return type; 8 | } 9 | 10 | int main() { 11 | Type *concrete_type = new_type(); 12 | concrete_type->args[concrete_type->argc++]->name = "aaa"; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /samples/35.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gcc 35.c -o 35_gcc 4 | ../hanando -f 35.c > 35.s 5 | gcc 35.s -o 35_hanando 6 | gcc_result=$(./35_gcc) 7 | hanando_result=$(./35_hanando) 8 | if test "${gcc_result}" != "${hanando_result}" 9 | then 10 | echo $gcc_result 11 | echo "Error: samples/35 does not match" 12 | echo $hanando_result 13 | return 1 14 | fi 15 | -------------------------------------------------------------------------------- /samples/35.c: -------------------------------------------------------------------------------- 1 | // float comparison 2 | #include 3 | 4 | int main() { 5 | double a = 1.2; 6 | double b = 3.5; 7 | printf("%d ", a b); 10 | printf("%d\n", a >=b); 11 | a = 3.5; 12 | b = 1.2; 13 | printf("%d ", a b); 16 | printf("%d\n", a >=b); 17 | a = 3; 18 | b = 3; 19 | printf("%d ", a b); 22 | printf("%d\n", a >=b); 23 | double c = -3.6; 24 | printf("ND_NEG TEST\n%f\n", -c); 25 | printf("TEST\n%f\n", c); 26 | float d = -5.6; 27 | printf("ND_NEG TEST\n%f\n", (double)(-d)); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /samples/36.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gcc -g 36.c -o 36_gcc 4 | ../hanando -f 36.c > 36.s 5 | gcc -g 36.s -o 36_hanando 6 | gcc_result=$(./36_gcc) 7 | hanando_result=$(./36_hanando) 8 | if test "${gcc_result}" != "${hanando_result}" 9 | then 10 | echo $gcc_result 11 | echo "Error: samples/36 does not match" 12 | echo $hanando_result 13 | return 1 14 | fi 15 | -------------------------------------------------------------------------------- /samples/36.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | int a = -5; 4 | double b = 0.5; 5 | float c = 2.6f; 6 | printf("%d\n", a < a); 7 | printf("%f\n", a < b); 8 | printf("%f\n", a < c); 9 | printf("%f\n", b < c); 10 | printf("%d\n", a + a); 11 | printf("%f\n", a + b); 12 | printf("%f\n", (double)(a + c)); 13 | printf("%f\n", b + c); 14 | printf("%d\n", a * a); 15 | printf("%f\n", a * b); 16 | printf("%f\n", (double)(a * c)); 17 | printf("%f\n", b * c); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /samples/37.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char *a = "Sendai"; 5 | int main() { 6 | char* x[3] = {"Tokyo", "Yokohama", "Osaka"}; 7 | 8 | if (strcmp(x[0], "Tokyo") != 0) { 9 | exit(1); 10 | } 11 | if (strcmp(x[1], "Yokohama") != 0) { 12 | exit(1); 13 | } 14 | if (strcmp(x[2], "Osaka") != 0) { 15 | exit(1); 16 | } 17 | if (strcmp(a, "Sendai") != 0) { 18 | exit(1); 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /samples/38.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | long __val[16]; 3 | } __sigset_t; 4 | 5 | typedef long __jmp_buf[8]; 6 | 7 | typedef struct __jmp_buf_tag { 8 | __jmp_buf __jmpbuf; 9 | int __mask_was_saved; 10 | __sigset_t __saved_mask; 11 | } jmp_buf; 12 | 13 | void longjmp(jmp_buf env, int val); 14 | int setjmp(jmp_buf env); 15 | 16 | jmp_buf jbuf; 17 | /* 18 | int func(jmp_buf buf) { 19 | buf.__jmpbuf[0] = 3; 20 | return 0; 21 | }*/ 22 | 23 | int main() { 24 | /* 25 | int value; 26 | func(jbuf); 27 | value = setjmp(jbuf); 28 | if (value == 0) { 29 | longjmp(jbuf, 1); 30 | } else { 31 | printf("Throw, %d\n", value); 32 | return 0; 33 | } 34 | */ 35 | __sigset_t t; 36 | t.__val[0] = 10; 37 | t.__val[3] = 40; 38 | /* 39 | jbuf.__jmpbuf[1] = 3; 40 | jbuf.__mask_was_saved = 20; 41 | jbuf.__saved_mask.__val[0] = 30; 42 | */ 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /samples/39.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | long __val[16]; 3 | } __sigset_t; 4 | 5 | typedef long __jmp_buf[8]; 6 | 7 | typedef struct __jmp_buf_tag { 8 | __jmp_buf __jmpbuf; 9 | int __mask_was_saved; 10 | __sigset_t __saved_mask; 11 | } jmp_buf; 12 | 13 | void longjmp(jmp_buf env, int val); 14 | int setjmp(jmp_buf env); 15 | 16 | int func(__sigset_t buf) { 17 | printf("%d\n", buf.__val[13]); 18 | return 0; 19 | } 20 | 21 | int main() { 22 | __sigset_t t; 23 | t.__val[13] = 2; 24 | func(t); 25 | printf("%d\n", t.__val[13]); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /samples/4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../main.h" 3 | int node2(Node* node, int j) { 4 | { 5 | printf("%p\n", node->ty); 6 | printf("%p\n", node->lhs); 7 | printf("%p\n", node->rhs); 8 | printf("%p\n", node->args); 9 | printf("%p\n", node->code); 10 | printf("%p\n", node->argc); 11 | printf("%p\n", node->num_val); 12 | printf("%p\n", node->name); 13 | printf("%p\n", node->env); 14 | printf("%p\n", node->type); 15 | } 16 | printf("%s\n", node->args[j]->name); 17 | return node->args[j]->ty; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /samples/41.c: -------------------------------------------------------------------------------- 1 | // test of function pointer 2 | 3 | int func() { 4 | return 9; 5 | } 6 | 7 | int main() { 8 | //printf("Call Directly: %d\n", func()); 9 | int (*x)(); 10 | x = func; 11 | printf("Call with Pointer: %d\n", x()); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /samples/5.c: -------------------------------------------------------------------------------- 1 | #include 2 | typedef struct { 3 | int a; 4 | char b; 5 | int c; 6 | void* d; 7 | } Kind; 8 | 9 | 10 | int func1(Kind* kind) { 11 | char i = kind->b; 12 | int j = kind->c; 13 | printf("%c, %d\n", i, j); 14 | return 8; 15 | } 16 | int func2(Kind* kind); 17 | int main() { 18 | Kind e; 19 | e.a = 4; 20 | e.b = 'c'; 21 | e.c = 17; 22 | //e.d = &e; 23 | func1(&e); 24 | func2(&e); 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /samples/6.c: -------------------------------------------------------------------------------- 1 | #include 2 | typedef struct { 3 | int a; 4 | char b; 5 | int c; 6 | void* d; 7 | int e; 8 | char f; 9 | char g; 10 | int* h; 11 | int j; 12 | } Kind; 13 | 14 | int func2(Kind* kind) { 15 | char i = kind->b; 16 | int j = kind->c; 17 | printf("%c, %d\n", i, j); 18 | return 8; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /samples/7.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int j = 0; 3 | int i = -1; 4 | printf("%d %d\n", i, j-1); 5 | } 6 | -------------------------------------------------------------------------------- /samples/8.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int a[6][2]; 5 | puts("aaa"); 6 | puts("bbb"); 7 | a[0][1] = 2; 8 | printf("%d\n", a[0][1]); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /samples/9.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../main.h" 4 | #ifdef __HANANDO_FUKUI__ 5 | FILE* fopen(char* name, char* type); 6 | void* malloc(int size); 7 | void* realloc(void* ptr, int size); 8 | #endif 9 | Vector *new_vector() { 10 | Vector *vec = malloc(sizeof(Vector)); 11 | vec->capacity = 16; 12 | vec->data = malloc(sizeof(Token *) * vec->capacity); 13 | vec->len = 0; 14 | return vec; 15 | } 16 | 17 | int vec_push(Vector *vec, Token *element) { 18 | if (vec->capacity == vec->len) { 19 | vec->capacity *= 2; 20 | vec->data = realloc(vec->data, sizeof(Token *) * vec->capacity); 21 | } 22 | vec->data[vec->len] = element; 23 | return vec->len++; 24 | } 25 | 26 | int main() { 27 | Vector *test = new_vector(); 28 | Token *hanando_fukui_compiled = malloc(sizeof(Token)); 29 | hanando_fukui_compiled->ty = TK_NUM; 30 | hanando_fukui_compiled->pos = 8; 31 | hanando_fukui_compiled->num_val = 1; 32 | hanando_fukui_compiled->input = "HANANDO_FUKUI"; 33 | vec_push(test, hanando_fukui_compiled); 34 | fprintf(stderr,"%s %d\n", test->data[0]->input, test->len); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /samples/Makefile: -------------------------------------------------------------------------------- 1 | CC = ../hanando 2 | test: test3 test8 test11 test13 test14 test31 test17 test35 test41 test36 test37 3 | $(CC) -r -f 9.c > 9.s 4 | gcc 9.s -o 9 5 | ./9 6 | $(CC) -r -f 10.c > 10.s 7 | gcc 10.s -o 10 8 | ./10 "aaa" 9 | 10 | test11: 11 | $(CC) -r -f 11.c > 11.s 12 | gcc -g -S -masm=intel 12.c -o 12.s 13 | gcc -g 12.s 11.s -o 11 14 | ./11 15 | test13: 16 | $(CC) -r -f 13.c > 13.s 17 | gcc 13.s -o 13 18 | ./13 19 | 20 | test14: 21 | $(CC) -r -f 14.c > 14.s 22 | gcc 14.s -o 14 23 | ./14 24 | 25 | test3: 26 | $(CC) -r -f 3.c > 3.s 27 | gcc -S 4.c -masm=intel 28 | gcc 3.s 4.s -o 3 29 | ./3 30 | test8: 31 | $(CC) -r -f 8.c > 8.s 32 | gcc 8.s -o 8 33 | ./8 34 | test31: 35 | $(CC) -r -f 31.c > 31.s 36 | gcc 31.s -o 31 37 | ./31 38 | test18: 39 | $(CC) -r -f 18.c > 18.s 40 | gcc -g 18.s 19.c -o 18 41 | ./18 42 | 43 | test17: 44 | $(CC) -r -f 17.c > 17.s 45 | gcc -g 17.s -o 17 46 | ./17 47 | 48 | test41: 49 | $(CC) -r -f 41.c > 41.s 50 | gcc -g 41.s -o 41 51 | ./41 52 | test37: 53 | $(CC) -r -f 37.c > 37.s 54 | gcc -g 37.s -o 37 55 | ./37 56 | test39: 57 | $(CC) -r -f 39.c > 39.s 58 | gcc -g 39.s -o 39 59 | ./39 60 | 61 | test35: 62 | ./35.bash 63 | 64 | test36: 65 | ./36.bash 66 | clean: 67 | $(RM) -f *.s 68 | 69 | .PHONY: test3 test8 test11 test13 test14 test31 clean test17 test41 test37 70 | -------------------------------------------------------------------------------- /selfhost.h: -------------------------------------------------------------------------------- 1 | // selfhost.h 2 | // This file is required for self-hosting. 3 | #ifdef __HANANDO_FUKUI__ 4 | FILE *fopen(char *name, char *type); 5 | void *malloc(int size); 6 | void *realloc(void *ptr, int size); 7 | float strtof(char *nptr, char **endptr); 8 | double strtod(char *nptr, char **endptr); 9 | char *dirname(char *path); 10 | char *basename(char *path); 11 | 12 | int isspace(int c); 13 | #endif 14 | -------------------------------------------------------------------------------- /stabs/1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | int x; 5 | x = 8; 6 | return x; 7 | } 8 | 9 | // stabs: 文字列 10 | // stabn: 数値 11 | // stabdd (dot) ? 12 | // 13 | // .stabs "string",type,other,desc,value 14 | // .stabn type,other,desc,value 15 | // .stabd type,other,desc 16 | // value フィールドは自明 17 | // type フィールド: stab のどの型が普通なのか 18 | // 2.3 は読み飛ばす (Include Files の名前は不要) 19 | // 20 | /* 21 | 22 | .stabs "1.c",4,0,0,Ltext0 23 | // 0x4 がC言語らしい、100 かも? 24 | .text 25 | Ltext0: 26 | .stabs "int:t1=r1;-21...;",128,0,0,0 27 | // 0x44: N_SLINE が行番号の最初らしい 28 | idesc = 行番号 29 | other = 0 30 | value = コードアドレス (参照を表す) 31 | .stabn 0x44,0,行番号, LM5 32 | 33 | // 関数名 N_FUN 0x24 34 | .stabs "main:F1",36,0,0,_main 35 | // f は static F はglobal 36 | // 再配置ごにょぎょは後回し? 37 | .stabs "main:f1",36,0,0,_main 38 | 39 | 40 | // 2.6 ネストしてると comma で繋ぐ baz:f1,baz,bar,... と徐々に外側に 41 | // 2.7 42 | // Begin of a lexical block 192 N_LBRAC 43 | .stabn 192,0,0,LBE2 44 | // End of a lexical block 0xe0 N_RBRAC 45 | .stabn 224,0,0,LBE2 46 | 47 | // 4. 変数定義 48 | // スタック上に確保される自動変数 N_LSYM シンボル 4.1節 49 | // 第四引数value は ローカル変数内でのoffset: frame pointer で大体負 50 | .stabs "x:1", 128,0,0,-2 51 | // N_GSYM (32) 4.2節 52 | .stabs "g_foo:G2", 32, 0, 0, 0 (G シンボルディスクー) 53 | // N_PSYM 4.6節 (パラメータ) 54 | .stabs "x:p13", 160,0,3,8 55 | desc は行番号 56 | 57 | // 5. Builtin Type 58 | */ 59 | -------------------------------------------------------------------------------- /stabs/1.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .align 4 3 | .file 1 "1.c" 4 | .data 5 | .stabs "1.c",100,0,0,.Ltext0 6 | .stabs "int:t1=r1;-2147483648;2147483647;",128,0,0,0 7 | // 0x4 がC言語らしい、100 かも? 8 | .Ltext0: 9 | .text 10 | .type main,@function 11 | .global main 12 | .stabs "main:F1",36,0,0,.main 13 | // Begin of a lexical block 192 N_LBRAC 14 | .main: 15 | main: 16 | push rbp 17 | mov rbp, rsp 18 | sub rsp, 8 19 | .LBB2: 20 | .LM5: 21 | .loc 1 5 22 | mov r10d, 8 23 | mov dword ptr [rbp-8], r10d 24 | .loc 1 6 25 | .LM6: 26 | mov eax, dword ptr [rbp-8] 27 | mov rsp, rbp 28 | pop rbp 29 | .LBE2: 30 | ret 31 | // End of a lexical block 0xe0 N_RBRAC 32 | .stabn 192,0,0,.LBB2 33 | .stabn 224,0,0,.LBE2 34 | .stabn 0x44,0,5, .LM5 35 | .stabn 0x44,0,6, .LM6 36 | .stabs "x:1", 128,0,0,-8 37 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | // test.c 2 | 3 | #include "main.h" 4 | extern int *stderr; 5 | extern int *stdout; 6 | #define NULL 0 7 | 8 | int retval = 0; 9 | // See hoc_nyan/test/test.c 10 | #define EXPECT(expr1, expr2) \ 11 | { \ 12 | int e1, e2; \ 13 | e1 = (expr1); \ 14 | e2 = (expr2); \ 15 | if (e1 == e2) { \ 16 | fprintf(stdout, "Line %d: %s: OK %d\n", __LINE__, #expr1, e2); \ 17 | } else { \ 18 | fprintf(stderr, "Line %d: %s: Expr1 %d, Expr2 %d\n", __LINE__, \ 19 | #expr1, e1, e2); \ 20 | retval++; \ 21 | } \ 22 | } \ 23 | 0 24 | 25 | #define EXPECTVAR(init, expr1, expr2) 26 | 27 | typedef struct STRUCTA { 28 | int b; 29 | char d; 30 | int e; 31 | } ASTRUCT; 32 | 33 | int globalvar[3] = {1, 2, 3}; 34 | 35 | int func1(void) { 36 | int ce; 37 | ce = -324; 38 | return ce; 39 | } 40 | 41 | char func71(void) { 42 | char a = -34; 43 | a -= -45; 44 | return a; 45 | } 46 | 47 | int func72(void) { 48 | int a = 4; 49 | a <<= 2; 50 | a /= 2; // 8 51 | a >>= 2; // 2 52 | a %= 2; // 0 53 | a -= 23; // -23 54 | a *= 3; // -69 55 | return a; 56 | } 57 | 58 | int func10_1(int a) { 59 | if (a) { 60 | return 7; 61 | } else { 62 | return 42; 63 | } 64 | return 21; 65 | } 66 | 67 | int func11(int a, int b, int c, int d, int e, int f) { 68 | // six arguments 69 | return a + b + c + d + e + f; 70 | } 71 | 72 | int func21(int a) { 73 | // Recursion 74 | if (a <= 1) { 75 | return 1; 76 | } else { 77 | return func21(a - 1) * a; 78 | } 79 | } 80 | 81 | int func32_1(...) { 82 | int result; 83 | va_list ap; 84 | 85 | va_start(ap, NULL); 86 | result = va_arg(ap, int); 87 | EXPECT(result, 1); 88 | result = va_arg(ap, int); 89 | EXPECT(result, -2); 90 | va_end(ap); 91 | return 0; 92 | } 93 | 94 | int func32_2(char c, ...) { 95 | int result; 96 | char result2; 97 | va_list ap; 98 | EXPECT(c, 'a'); 99 | va_start(ap, c); 100 | result = va_arg(ap, int); 101 | EXPECT(result, -5); 102 | result2 = va_arg(ap, char); 103 | EXPECT(result2, 'b'); 104 | va_end(ap); 105 | return 0; 106 | } 107 | 108 | int func32_3(char *str, ...) { 109 | // gcc との互換性を確認 110 | va_list ap; 111 | va_start(ap, str); 112 | vprintf(str, ap); 113 | va_end(ap); 114 | return 0; 115 | } 116 | 117 | int main(void) { 118 | /* test1 */ 119 | EXPECT(1, 1); 120 | EXPECT(1 + 9, 10); 121 | EXPECT(13 - 9, 4); 122 | EXPECT(0x1f, 31); 123 | EXPECT(0X04, 4); 124 | EXPECT(0Xff, 255); 125 | 126 | /* test2 */ 127 | EXPECT(1 * 9, 9); 128 | EXPECT(-1 * 9, -9); 129 | EXPECT(-2 * -9, 18); 130 | EXPECT(-2 / -9, 0); 131 | EXPECT((9 - 11) * 34, -68); 132 | EXPECT(255 * 2, 510); 133 | 134 | EXPECT(func1(), -324); 135 | 136 | /* test3 */ 137 | EXPECT(3 == 3, 1); 138 | EXPECT(3 == 4, 0); 139 | EXPECT(-3 == 4, 0); 140 | EXPECT(3 != 3 + 8, 1); 141 | EXPECT(!(2 == 2), 0); 142 | EXPECT(!(-5 == 2), 1); 143 | 144 | /* test5,6*/ 145 | EXPECT(6 % 3, 0); 146 | // C と Python で異なる仕様 147 | EXPECT(-1 % 3, -1); 148 | EXPECT(5 % 4, 1); 149 | EXPECT(1 ^ 0, 1); 150 | EXPECT(0 ^ 1, 1); 151 | EXPECT(3 ^ 2, 1); 152 | EXPECT(6 | 3, 7); 153 | EXPECT(1 | 0, 1); 154 | EXPECT(1 & 0, 0); 155 | EXPECT(1 << 1, 2); 156 | EXPECT(1 << 0, 1); 157 | EXPECT(2 << 4, 32); 158 | EXPECT(9 >> 1, 4); 159 | 160 | /* test7 */ 161 | EXPECT(func71(), 11); 162 | EXPECT(func72(), -69); 163 | 164 | /* test8 */ 165 | int a = -34; 166 | EXPECT(++a, -33); 167 | EXPECT(a++, -33); 168 | EXPECT(a++, -32); 169 | EXPECT(a, -31); 170 | EXPECT(a--, -31); 171 | EXPECT(a, -32); 172 | EXPECT(--a, -33); 173 | 174 | /* test9 */ 175 | EXPECT(0 > -2, 1); 176 | EXPECT(-8 > 12, 0); 177 | EXPECT(-234232 < 0, 1); 178 | EXPECT(43 < 43, 0); 179 | 180 | /* test10 */ 181 | EXPECT(func10_1(1), 7); 182 | EXPECT(func10_1(0), 42); 183 | { 184 | int a = 0; 185 | while (a < 3) { 186 | a++; 187 | } 188 | EXPECT(a, 3); 189 | 190 | do { 191 | a++; 192 | } while (a < 0); 193 | EXPECT(a, 4); 194 | } 195 | 196 | /* test11 */ 197 | EXPECT(func11(1, -2, 3, -4, 5, -6), -3); 198 | 199 | /* test12 */ 200 | { 201 | int x, *y; 202 | x = 5; 203 | y = &x; 204 | EXPECT(*y, 5); 205 | EXPECT(*y = 4, 4); 206 | EXPECT(x, 4); 207 | } 208 | 209 | /* test13 */ 210 | { 211 | int x[10]; 212 | *x = 3; 213 | EXPECT(x[0], 3); 214 | } 215 | 216 | /* test15 */ 217 | { 218 | char a; 219 | EXPECT(sizeof a, 1); 220 | EXPECT(sizeof(int), 4); 221 | } 222 | 223 | /* test16 */ 224 | { 225 | int i; 226 | for (i = 1; i < 5; ++i) { 227 | EXPECT(i, 1); 228 | break; 229 | } 230 | EXPECT(i, 1); 231 | for (i = 1; i < 5; ++i) { 232 | } 233 | EXPECT(i, 5); 234 | } 235 | 236 | EXPECT((3, -4), -4); 237 | 238 | /* test17 */ 239 | /* test18 */ 240 | /* test29 */ 241 | /* test30 */ 242 | { 243 | char a[5]; 244 | a[0] = 'a'; 245 | a[1] = 'b'; 246 | a[2] = '\n'; 247 | a[3] = '\0'; 248 | puts(a); 249 | EXPECT(strncmp(a, "ab\n", 4), 0); 250 | EXPECT(*a, 'a'); 251 | EXPECT(*(a + 2), '\n'); 252 | char b = '\n'; 253 | EXPECT(b, 10); 254 | EXPECT('a' <= 'h' && 'h' <= 'z', 1); 255 | } 256 | 257 | // test20 258 | EXPECT(-1 == -1, 1); 259 | EXPECT((1 == 1) || (2 == 2), 1); 260 | EXPECT((1 == 2) || (2 == 2), 1); 261 | EXPECT((1 == 1) || (1 == 2), 1); 262 | EXPECT((1 == 2) || (3 == 2), 0); 263 | EXPECT((1 == 1) && (2 == 2), 1); 264 | EXPECT((1 == 2) && (2 == 2), 0); 265 | EXPECT((1 == 1) && (1 == 2), 0); 266 | EXPECT((1 == 2) && (3 == 2), 0); 267 | EXPECT(2 && 1, 1); 268 | 269 | /* test20.5 */ 270 | EXPECT(3 ? 2 : 1, 2); 271 | EXPECT(0 ? 2 : 1, 1); 272 | 273 | /* test19,21 */ 274 | EXPECT(func21(3), 6); 275 | 276 | /* test22 */ 277 | /* TODO ここの挙動がおかしい */ 278 | EXPECT((char)255 + 2, 257); // unsigned を仮定 279 | EXPECT((char)255 + (char)2, 1); 280 | 281 | EXPECT(1 <= 2, 1); 282 | EXPECT(1 <= 1, 1); 283 | EXPECT(4 <= 1, 0); 284 | EXPECT(1 >= 2, 0); 285 | EXPECT(1 >= 1, 1); 286 | EXPECT(4 >= 1, 1); 287 | EXPECT(-4 >= 1, 0); 288 | EXPECT(-4 <= 1, 1); 289 | 290 | /* test23,24 */ 291 | EXPECT(NULL, 0); 292 | 293 | /* test25*/ 294 | EXPECT(((int *)3) + 1, 7); 295 | EXPECT(((int **)3) + 1, 11); 296 | EXPECT(((char *)3) + 1, 4); 297 | EXPECT(((long)3) + 1, 4); 298 | 299 | /* test26 */ 300 | { 301 | int a = 4; 302 | switch (a) { 303 | case 4: 304 | a = 7; 305 | case 6: 306 | a = -8; 307 | break; 308 | } 309 | EXPECT(a, -8); 310 | switch (a) { 311 | case (-7): 312 | a = 3; 313 | break; 314 | default: 315 | a = -3411; 316 | break; 317 | } 318 | EXPECT(a, -3411); 319 | } 320 | 321 | /* test28, 38 */ 322 | { 323 | Type a, *b; 324 | a.argc = -4; 325 | b = &a; 326 | EXPECT(b->argc, -4); 327 | b->argc = 5; 328 | EXPECT(a.argc, 5); 329 | struct STRUCTA f; 330 | f.e = -5; 331 | EXPECT(f.e, -5); 332 | EXPECT(TY_CHAR == TY_INT, 0); 333 | } 334 | 335 | // test31 336 | EXPECT((int)-1 == (long)-1, 1); 337 | EXPECT((char)0xFFFFF == (int)0xFFFFF, 0); 338 | EXPECT((int)-1 == (long)4, 0); 339 | 340 | /* test32 */ 341 | func32_1(1, -2); 342 | func32_2('a', -5, 'b'); 343 | func32_3("%d %s\n", 3, "test"); 344 | 345 | // 空文でレジスタを使い切らないかのテスト 346 | 1; 347 | 2; 348 | 3; 349 | 4; 350 | 5; 351 | 6; 352 | 7; 353 | 8; 354 | /* 355 | sh testfdef.sh "int main(){{return 3;}}" 3 356 | */ 357 | fprintf(stderr, "The number of errors are: %d\n", retval); 358 | return retval; 359 | } 360 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | # test.sh 2 | 3 | tmps=$(mktemp --tmpdir XXXXXX.s) 4 | tmprun=$(mktemp --tmpdir XXXXXX.run) 5 | # Not safe for exception trapping. 6 | naiyou=$1 7 | naiyou2="int main(){$naiyou}" 8 | echo $naiyou2 9 | ./hanando $3 "$naiyou2" > $tmps 10 | clang $tmps -g -o $tmprun 11 | $tmprun 12 | actual="$?" 13 | if [ $actual -ne $2 ]; then 14 | echo "Error: $2 but $actual on $tmps and $1" 15 | exit 1 16 | fi 17 | rm -f $tmps $tmprun 18 | -------------------------------------------------------------------------------- /testfdef.sh: -------------------------------------------------------------------------------- 1 | # test.sh 2 | 3 | tmps=$(mktemp --tmpdir XXXXXX.s) 4 | tmprun=$(mktemp --tmpdir XXXXXX.run) 5 | # Not safe for exception trapping. 6 | echo $(printf "$1") 7 | ./hanando $3 "$(printf "$1")" > $tmps 8 | clang $tmps -g -o $tmprun 9 | $tmprun 10 | actual="$?" 11 | if [ $actual -ne $2 ]; then 12 | echo "Error: $2 but $actual on $tmps and $1" 13 | exit 1 14 | fi 15 | rm -f $tmps $tmprun 16 | -------------------------------------------------------------------------------- /testfunccall.sh: -------------------------------------------------------------------------------- 1 | # testfunccall.sh 2 | 3 | clang foo.c -o foo.o -c 4 | ./hanando $4 "$(printf "$1")" > tmp.s 5 | clang tmp.s foo.o -o tmp 6 | actual=$(./tmp) 7 | retval=$? 8 | if [ "$actual" != $2 ]; then 9 | echo "Error: $2 but $actual" 10 | exit 1 11 | fi 12 | if [ $retval != $3 ]; then 13 | echo "Error: Retren $3 but $retval" 14 | exit 1 15 | fi 16 | -------------------------------------------------------------------------------- /token.c: -------------------------------------------------------------------------------- 1 | // token.c 2 | // SPDX-License-Identifier: Apache-2.0 3 | /* 4 | Copyright 2020 hiromi-mi 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include "main.h" 20 | #include "selfhost.h" 21 | #include 22 | // isspace(), isdigit() 23 | #include 24 | #include 25 | #include 26 | 27 | #define SEEK_END 2 28 | #define SEEK_SET 0 29 | 30 | extern int lang; 31 | 32 | Token *new_token(int pline, TokenConst ty, char *p) { 33 | Token *token = malloc(sizeof(Token)); 34 | token->ty = ty; 35 | token->input = p; 36 | token->pline = pline; 37 | return token; 38 | } 39 | 40 | Vector *tokenize(char *p) { 41 | Vector *pre_tokens = new_vector(); 42 | int pline = 1; // LINE No. 43 | while (*p != '\0') { 44 | if (*p == '\n') { 45 | Token *token = malloc(sizeof(Token)); 46 | token->ty = TK_NEWLINE; 47 | vec_push(pre_tokens, token); 48 | while (*p == '\n' && *p != '\0') { 49 | pline++; 50 | p++; 51 | } 52 | continue; 53 | } 54 | if (*p == '/' && *(p + 1) == '/') { 55 | // skip because of one-lined comment 56 | while (*p != '\n' && *p != '\0') 57 | p++; 58 | continue; 59 | } 60 | if (*p == '/' && *(p + 1) == '*') { 61 | // skip because of one-lined comment 62 | while (*p != '\0') { 63 | if (*p == '*' && *(p + 1) == '/') { 64 | p += 2; // due to * and / 65 | /* 66 | if (*p == '\n') { 67 | pline++; 68 | }*/ 69 | break; 70 | } 71 | p++; 72 | if (*p == '\n') { 73 | pline++; 74 | } 75 | } 76 | } 77 | if (isspace(*p)) { 78 | vec_push(pre_tokens, new_token(pline, TK_SPACE, p)); 79 | while (isspace(*p) && *p != '\0') { 80 | if (*p == '\n') { 81 | pline++; 82 | } 83 | p++; 84 | } 85 | continue; 86 | } 87 | 88 | if (*p == '\"') { 89 | Token *token = new_token(pline, TK_STRING, malloc(sizeof(char) * 256)); 90 | int i = 0; 91 | while (*++p != '\"') { 92 | if (*p == '\\' && *(p + 1) == '\"') { 93 | // read 2 character and write them into 1 bytes 94 | token->input[i++] = *p; 95 | token->input[i++] = *(p + 1); 96 | p++; 97 | } else { 98 | token->input[i++] = *p; 99 | } 100 | } 101 | token->input[i] = '\0'; 102 | vec_push(pre_tokens, token); 103 | p++; // skip " 104 | continue; 105 | } 106 | if (*p == '\'') { 107 | Token *token = new_token(pline, TK_NUM, p); 108 | token->type_size = 1; // to treat 'a' as char 109 | if (*(p + 1) != '\\') { 110 | token->num_val = *(p + 1); 111 | } else { 112 | switch (*(p + 2)) { 113 | case 'n': 114 | token->num_val = '\n'; 115 | break; 116 | case 'b': 117 | token->num_val = '\b'; 118 | break; 119 | case '0': 120 | token->num_val = '\0'; 121 | break; 122 | case 't': 123 | token->num_val = '\t'; 124 | break; 125 | case '\\': 126 | token->num_val = '\\'; 127 | break; 128 | case '\"': 129 | token->num_val = '\"'; 130 | break; 131 | case '\'': 132 | token->num_val = '\''; 133 | break; 134 | default: 135 | error( 136 | "Error: Error On this unsupported escape sequence: %d\n", 137 | *(p + 2)); 138 | } 139 | p++; 140 | } 141 | vec_push(pre_tokens, token); 142 | p += 3; // *p = '', *p+1 = a, *p+2 = ' 143 | continue; 144 | } 145 | if ((*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '%' || 146 | *p == '^' || *p == '|' || *p == '&') && 147 | (*(p + 1) == '=')) { 148 | vec_push(pre_tokens, new_token(pline, '=', p + 1)); 149 | vec_push(pre_tokens, new_token(pline, TK_OPAS, p)); 150 | p += 2; 151 | continue; 152 | } 153 | 154 | if ((*p == '+' && *(p + 1) == '+') || (*p == '-' && *(p + 1) == '-')) { 155 | vec_push(pre_tokens, new_token(pline, *p + *(p + 1), p)); 156 | p += 2; 157 | continue; 158 | } 159 | 160 | if ((*p == '|' && *(p + 1) == '|')) { 161 | vec_push(pre_tokens, new_token(pline, TK_OR, p)); 162 | p += 2; 163 | continue; 164 | } 165 | if ((*p == '&' && *(p + 1) == '&')) { 166 | vec_push(pre_tokens, new_token(pline, TK_AND, p)); 167 | p += 2; 168 | continue; 169 | } 170 | 171 | if ((*p == '-' && *(p + 1) == '>')) { 172 | vec_push(pre_tokens, new_token(pline, TK_ARROW, p)); 173 | p += 2; 174 | continue; 175 | } 176 | 177 | if (strncmp(p, "...", 3) == 0) { 178 | vec_push(pre_tokens, new_token(pline, TK_OMIITED, p)); 179 | p += 3; 180 | continue; 181 | } 182 | 183 | if ((*p == ':' && *(p + 1) == ':')) { 184 | vec_push(pre_tokens, new_token(pline, TK_COLONCOLON, p)); 185 | p += 2; 186 | continue; 187 | } 188 | 189 | if (*p == '+' || *p == '-' || *p == '*' || *p == '/' || *p == '(' || 190 | *p == ')' || *p == ';' || *p == ',' || *p == '{' || *p == '}' || 191 | *p == '%' || *p == '^' || *p == '|' || *p == '&' || *p == '?' || 192 | *p == ':' || *p == '[' || *p == ']' || *p == '#' || *p == '.') { 193 | vec_push(pre_tokens, new_token(pline, *p, p)); 194 | p++; 195 | continue; 196 | } 197 | if (*p == '=') { 198 | if (*(p + 1) == '=') { 199 | vec_push(pre_tokens, new_token(pline, TK_ISEQ, p)); 200 | p += 2; 201 | } else { 202 | vec_push(pre_tokens, new_token(pline, '=', p)); 203 | p++; 204 | } 205 | continue; 206 | } 207 | if (*p == '!') { 208 | if (*(p + 1) == '=') { 209 | vec_push(pre_tokens, new_token(pline, TK_ISNOTEQ, p)); 210 | p += 2; 211 | } else { 212 | vec_push(pre_tokens, new_token(pline, *p, p)); 213 | p++; 214 | } 215 | continue; 216 | } 217 | if (*p == '<') { 218 | if (*(p + 1) == '<') { 219 | if (*(p + 2) == '=') { 220 | vec_push(pre_tokens, new_token(pline, '=', p + 2)); 221 | vec_push(pre_tokens, new_token(pline, TK_OPAS, p)); 222 | p += 3; 223 | } else { 224 | vec_push(pre_tokens, new_token(pline, TK_LSHIFT, p)); 225 | p += 2; 226 | } 227 | } else if (*(p + 1) == '=') { 228 | vec_push(pre_tokens, new_token(pline, TK_ISLESSEQ, p)); 229 | p += 2; 230 | } else { 231 | vec_push(pre_tokens, new_token(pline, *p, p)); 232 | p++; 233 | } 234 | continue; 235 | } 236 | if (*p == '>') { 237 | if (*(p + 1) == '>') { 238 | if (*(p + 2) == '=') { 239 | vec_push(pre_tokens, new_token(pline, '=', p + 2)); 240 | vec_push(pre_tokens, new_token(pline, TK_OPAS, p)); 241 | p += 3; 242 | } else { 243 | vec_push(pre_tokens, new_token(pline, TK_RSHIFT, p)); 244 | p += 2; 245 | } 246 | } else if (*(p + 1) == '=') { 247 | vec_push(pre_tokens, new_token(pline, TK_ISMOREEQ, p)); 248 | p += 2; 249 | } else { 250 | vec_push(pre_tokens, new_token(pline, *p, p)); 251 | p++; 252 | } 253 | continue; 254 | } 255 | if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) { 256 | Token *token = new_token(pline, TK_NUM, p); 257 | token->num_val = strtol(p + 2, &p, 16); 258 | token->type_size = 4; // to treat as int 259 | vec_push(pre_tokens, token); 260 | continue; 261 | } 262 | 263 | if (isdigit(*p)) { 264 | Token *token = new_token(pline, TK_NUM, p); 265 | token->num_val = strtol(p, &p, 10); 266 | token->type_size = 4; // to treat as int 267 | 268 | // if there are FLOAT 269 | if (*p == '.') { 270 | token->float_val = strtod(token->input, &p); 271 | if (*p == 'f') { 272 | // when ends with f: 273 | token->ty = TK_FLOAT; 274 | p++; 275 | } else { 276 | token->ty = TK_DOUBLE; 277 | } 278 | } 279 | vec_push(pre_tokens, token); 280 | continue; 281 | } 282 | 283 | if (('a' <= *p && *p <= 'z') || ('A' <= *p && *p <= 'Z') || *p == '_') { 284 | Token *token = new_token(pline, TK_IDENT, malloc(sizeof(char) * 256)); 285 | int j = 0; 286 | do { 287 | token->input[j] = *p; 288 | p++; 289 | j++; 290 | if (*p == ':' && *(p + 1) == ':') { 291 | token->input[j] = *p; 292 | p++; 293 | j++; 294 | token->input[j] = *p; 295 | p++; 296 | j++; 297 | } 298 | } while (('a' <= *p && *p <= 'z') || ('0' <= *p && *p <= '9') || 299 | ('A' <= *p && *p <= 'Z') || *p == '_'); 300 | token->input[j] = '\0'; 301 | 302 | if (strcmp(token->input, "if") == 0) { 303 | token->ty = TK_IF; 304 | } else if (strcmp(token->input, "else") == 0) { 305 | token->ty = TK_ELSE; 306 | } else if (strcmp(token->input, "do") == 0) { 307 | token->ty = TK_DO; 308 | } else if (strcmp(token->input, "while") == 0) { 309 | token->ty = TK_WHILE; 310 | } else if (strcmp(token->input, "for") == 0) { 311 | token->ty = TK_FOR; 312 | } else if (strcmp(token->input, "return") == 0) { 313 | token->ty = TK_RETURN; 314 | } else if (strcmp(token->input, "sizeof") == 0) { 315 | token->ty = TK_SIZEOF; 316 | } else if (strcmp(token->input, "goto") == 0) { 317 | token->ty = TK_GOTO; 318 | } else if (strcmp(token->input, "struct") == 0) { 319 | token->ty = TK_STRUCT; 320 | } else if (strcmp(token->input, "static") == 0) { 321 | token->ty = TK_STATIC; 322 | } else if (strcmp(token->input, "typedef") == 0) { 323 | token->ty = TK_TYPEDEF; 324 | } else if (strcmp(token->input, "break") == 0) { 325 | token->ty = TK_BREAK; 326 | } else if (strcmp(token->input, "continue") == 0) { 327 | token->ty = TK_CONTINUE; 328 | } else if (strcmp(token->input, "const") == 0) { 329 | token->ty = TK_CONST; 330 | } else if (strcmp(token->input, "NULL") == 0) { 331 | token->ty = TK_NULL; 332 | } else if (strcmp(token->input, "switch") == 0) { 333 | token->ty = TK_SWITCH; 334 | } else if (strcmp(token->input, "case") == 0) { 335 | token->ty = TK_CASE; 336 | } else if (strcmp(token->input, "default") == 0) { 337 | token->ty = TK_DEFAULT; 338 | } else if (strcmp(token->input, "enum") == 0) { 339 | token->ty = TK_ENUM; 340 | } else if (strcmp(token->input, "extern") == 0) { 341 | token->ty = TK_EXTERN; 342 | } else if (strcmp(token->input, "_Noreturn") == 0) { 343 | continue; // just skipping 344 | } else if (strcmp(token->input, "__LINE__") == 0) { 345 | token->ty = TK_NUM; 346 | token->num_val = pline; 347 | token->type_size = 8; 348 | } 349 | 350 | if (lang & 1) { 351 | if (strcmp(token->input, "class") == 0) { 352 | token->ty = TK_CLASS; 353 | } else if (strcmp(token->input, "public") == 0) { 354 | token->ty = TK_PUBLIC; 355 | } else if (strcmp(token->input, "private") == 0) { 356 | token->ty = TK_PRIVATE; 357 | } else if (strcmp(token->input, "protected") == 0) { 358 | token->ty = TK_PROTECTED; 359 | } else if (strcmp(token->input, "template") == 0) { 360 | token->ty = TK_TEMPLATE; 361 | } else if (strcmp(token->input, "typename") == 0) { 362 | token->ty = TK_TYPENAME; 363 | } else if (strcmp(token->input, "try") == 0) { 364 | token->ty = TK_TRY; 365 | } else if (strcmp(token->input, "catch") == 0) { 366 | token->ty = TK_CATCH; 367 | } else if (strcmp(token->input, "throw") == 0) { 368 | token->ty = TK_THROW; 369 | } else if (strcmp(token->input, "decltype") == 0) { 370 | token->ty = TK_DECLTYPE; 371 | } else if (strcmp(token->input, "new") == 0) { 372 | token->ty = TK_NEW; 373 | } 374 | } 375 | 376 | vec_push(pre_tokens, token); 377 | continue; 378 | } 379 | 380 | error("Cannot Tokenize: %s\n", p); 381 | } 382 | 383 | vec_push(pre_tokens, new_token(pline, TK_EOF, p)); 384 | return pre_tokens; 385 | } 386 | 387 | Vector *read_tokenize(char *fname) { 388 | FILE *fp = fopen(fname, "r"); 389 | if (!fp) { 390 | error("No file found: %s\n", fname); 391 | } 392 | fseek(fp, 0, SEEK_END); 393 | long length = ftell(fp); 394 | fseek(fp, 0, SEEK_SET); 395 | char *buf = malloc(sizeof(char) * (length + 5)); 396 | fread(buf, length + 5, sizeof(char), fp); 397 | fclose(fp); 398 | return tokenize(buf); 399 | } 400 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | // util.c 2 | // SPDX-License-Identifier: Apache-2.0 3 | /* 4 | Copyright 2019, 2020 hiromi-mi 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | #include "main.h" 20 | #include "selfhost.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | extern Vector *tokens; 27 | extern int pos; 28 | _Noreturn void error(const char *str, ...) { 29 | va_list ap; 30 | va_start(ap, str); 31 | if (tokens && tokens->len > pos) { 32 | char *buf = malloc(sizeof(char) * 256); 33 | vsnprintf(buf, 255, str, ap); 34 | fprintf(stderr, "%s on line %d pos %d: %s\n", buf, 35 | tokens->data[pos]->pline, pos, tokens->data[pos]->input); 36 | } else { 37 | vfprintf(stderr, str, ap); 38 | } 39 | va_end(ap); 40 | exit(1); 41 | } 42 | 43 | void test_map(void) { 44 | Vector *vec = new_vector(); 45 | Token *hanando_fukui_compiled = malloc(sizeof(Token)); 46 | hanando_fukui_compiled->ty = TK_NUM; 47 | hanando_fukui_compiled->pos = 0; 48 | hanando_fukui_compiled->num_val = 1; 49 | hanando_fukui_compiled->input = "HANANDO_FUKUI"; 50 | vec_push(vec, hanando_fukui_compiled); 51 | vec_push(vec, (Token *)9); 52 | if (vec->len != 2) { 53 | error("Vector does not work yet!"); 54 | } 55 | if (strcmp(vec->data[0]->input, "HANANDO_FUKUI") != 0) { 56 | error("Vector does not work yet!"); 57 | } 58 | 59 | Map *map = new_map(); 60 | map_put(map, "foo", hanando_fukui_compiled); 61 | if (map->keys->len != 1 || map->vals->len != 1) { 62 | error("Error: Map does not work yet!"); 63 | } 64 | if ((long)map_get(map, "bar") != 0) { 65 | error("Error: Map does not work yet! on 3"); 66 | } 67 | Token *te = map_get(map, "foo"); 68 | if (strcmp(te->input, "HANANDO_FUKUI") != 0) { 69 | error("Error: Map does not work yet! on 3a"); 70 | } 71 | } 72 | --------------------------------------------------------------------------------