├── Changes ├── Makefile ├── Porting ├── README ├── Todo ├── _sums ├── book ├── cg1.c ├── cg1.o ├── cg2.c ├── cg3.c ├── cg4.c ├── opt1.c ├── p.c └── s.c ├── configure ├── osversion └── src ├── Makefile ├── cexpr.c ├── cg.c ├── cg.h ├── cgen.h ├── data.h ├── decl.c ├── decl.h ├── defs.h ├── error.c ├── expr.c ├── gen.c ├── include ├── ctype.h ├── errno.h ├── limits.h ├── setjmp.h ├── signal.h ├── stdio.h ├── stdlib.h ├── string.h ├── syscall.h └── time.h ├── lib ├── Makefile ├── abort.c ├── abs.c ├── atexit.c ├── atoi.c ├── bsearch.c ├── calloc.c ├── clearerr.c ├── crt0.s ├── ctime.c ├── ctype.c ├── difftime.c ├── exit.c ├── fclose.c ├── fdopen.c ├── feof.c ├── ferror.c ├── fflush.c ├── fgetc.c ├── fgetpos.c ├── fgets.c ├── fileno.c ├── fopen.c ├── fprintf.c ├── fputc.c ├── fputs.c ├── fread.c ├── free.c ├── freopen.c ├── fscanf.c ├── fseek.c ├── fsetpos.c ├── ftell.c ├── fwrite.c ├── getchar.c ├── getenv.c ├── init.c ├── kprintf.c ├── malloc.c ├── memchr.c ├── memcmp.c ├── memcpy.c ├── memmove.c ├── memset.c ├── perror.c ├── printf.c ├── putchar.c ├── puts.c ├── qsort.c ├── rand.c ├── realloc.c ├── remove.c ├── rename.c ├── rewind.c ├── scanf.c ├── setbuf.c ├── setvbuf.c ├── sprintf.c ├── sscanf.c ├── strcat.c ├── strchr.c ├── strcmp.c ├── strcpy.c ├── strcspn.c ├── strdup.c ├── strerror.c ├── strlen.c ├── strncat.c ├── strncmp.c ├── strncpy.c ├── strpbrk.c ├── strrchr.c ├── strspn.c ├── strtok.c ├── strtol.c ├── system.c ├── time.c ├── tmpfile.c ├── tmpnam.c ├── ungetc.c ├── vformat.c └── vscan.c ├── main.c ├── misc.c ├── prec.h ├── prep.c ├── scan.c ├── stmt.c ├── sym.c └── targets ├── cg386.c ├── cg386.h ├── cgx86-64.c ├── cgx86-64.h ├── crt0-freebsd-386.s ├── crt0-freebsd-x86-64.s ├── crt0-linux-386.s └── crt0-netbsd-x86-64.s /Changes: -------------------------------------------------------------------------------- 1 | 2012-03-26 Made "&array" valid syntax. 2 | 2012-03-26 Added auto and register keywords (no-ops). 3 | 2012-03-26 Added local enum declarations. 4 | 2012-03-26 Added local extern identifiers. 5 | 2012-03-26 Added static prototypes. 6 | 2012-03-27 Added global struct/union declaration syntax. 7 | 2012-03-28 Added struct/union symbol table support. 8 | 2012-03-29 Added global struct/union definition syntax and semantics. 9 | 2012-03-29 Added local struct/union definition syntax and semantics. 10 | 2012-03-30 Added local static struct/union definition semantics. 11 | 2012-03-30 Added struct/union access syntax (x->y and x.y). 12 | 2012-03-31 Added struct/union access semantics. 13 | 2012-04-01 Changed jmp_buf type from int[2] to struct _jmp_buf. 14 | 2012-04-02 Fixed declaration parser (accept fn returning struct/union). 15 | 2012-04-02 Made FILE a struct. (Breaking stdio library!) 16 | 2012-04-03 Fixed pointer arithmetics (struct/union**). 17 | 2012-04-03 Added the kprintf() function (fd-based printf()). 18 | 2012-04-03 Added #error, #line, #pragma preprocessor commands. 19 | 2012-04-03 Added proper struct* arithmetics for ++ and --. 20 | 2012-04-04 Added proper struct* arithmetics for + and -. 21 | 2012-04-05 Added struct/union cast operators. 22 | 2012-04-05 Made structs/unions invalid operands to arithmetic ops. 23 | 2012-04-12 Fixed increment/decrement of pointer to struct/union. 24 | 2012-04-13 Added the x86-64 code generator (cgx86-64.c). 25 | 2012-04-14 Added the NetBSD/x86-64 startup module (crt0-netbsd-x86-64.s). 26 | 2012-04-15 Experimental NetBSD/x86 support completed. 27 | 2012-04-15 Re-organized archive to support multiple targets. 28 | 2012-04-16 Fixed an off-by-one error in getenv(). 29 | 2012-04-17 Improved some error messages. 30 | 2012-04-17 Added the FreeBSD/x86-64 crt0 module (crt0-freebsd-x86-64.s). 31 | 2012-04-18 Moved machine word size to target description. 32 | 2012-04-18 Added a configure script. 33 | 2012-04-25 Added the Linux/386 crt0 module (crt0-linux-386.s). 34 | 2012-04-26 Removed all GNU libc dependencies from Linux crt0. 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SNAP= 20120415 2 | REL= 20120426 3 | ARC= subc-$(SNAP).tgz 4 | DIST= subc-$(REL).tgz 5 | 6 | csums: 7 | csum -u <_sums >_newsums ; mv -f _newsums _sums 8 | 9 | sums: clean 10 | find . -type f | grep -v _sums | csum >_sums 11 | 12 | clean: 13 | cd src && make clean 14 | rm -f $(ARC) $(DIST) 15 | 16 | arc: clean 17 | tar cvfz $(ARC) * 18 | 19 | dist: clean 20 | tar cvfz $(DIST) * 21 | -------------------------------------------------------------------------------- /Porting: -------------------------------------------------------------------------------- 1 | 2 | 3 | PORTING SUBC TO DIFFERENT PLATFORMS 4 | 5 | 6 | (1) Create a new target description file 7 | 8 | Copy one of the existing cg*.c files in the src/targets 9 | directory to create a new target description. The target 10 | description will contain the instructions that will be 11 | emitted by the code generator. Also copy the corresponding 12 | cg*.h file. For example, to create an FOO back-end: 13 | 14 | cp src/targets/cg386.c src/targets/cgxFOO.c 15 | cp src/targets/cg386.h src/targets/cgxFOO-64.h 16 | 17 | 18 | (2) Select the proper machine word size 19 | 20 | Edit the newly created header file (e.g.: cgFOO-64.h) and 21 | change its BPW constant to the *natural* machine word size 22 | on the new target. This would be 32 bits for a 32-bit 23 | processor, 64 bits for a 64-bit processor, etc. Note that 24 | the word size selected here must be large enough to hold 25 | an arbitrary address (a pointer) on the target. Incidentally, 26 | the selected size will be sizeof(int) in the new back-end. 27 | 28 | 29 | (3) Create a target description 30 | 31 | This is one of the hard parts. You will have to replace the 32 | code emitted by each function in the new target description 33 | file to generate code for your new platform. If you are and 34 | experienced compiler writer and you are familiar with one of 35 | the existing targets, you may be able to guess the proper 36 | sequences. Otherwise, you probably need a copy of the book 37 | "Practical Compiler Construction"[1] now, which explains the 38 | target description format in detail. 39 | 40 | [1] See the README. 41 | 42 | For adapting the 386 target to the x86-64 processor, this 43 | step basically involved (a) replacing register names (%eax 44 | to %rax, etc), (b) replacing instruction suffixes (movl->movq, 45 | etc), (c) replacing ".long" by ".quad", and (d) adjusting all 46 | values that deal with word sized, i.e. adding multiples of 8 47 | in stead of 4 to a register in pointer arithmetics, etc. 48 | 49 | Of course, other processors will differ from the 386 by a 50 | greater margin, so this step will be quite a piece of work. 51 | The conclusion part of the book contains some practical tips 52 | for approaching this task. 53 | 54 | 55 | (4) Create an OS-specific C startup file 56 | 57 | Copy one of the existing crt0-*.s files in the src/targets 58 | directory to create a new startup file. For example, to create 59 | a NetBSD/FOO startup file: 60 | 61 | cp src/targets/crt0-freebsd-386.s \ 62 | src/targets/crt0-netbsd-foo.s 63 | 64 | 65 | (5) Create the OS interface 66 | 67 | This step is a mess and requires some decent in-depth knowledge 68 | of the target platform, i.e. its internal command line argument 69 | format, environment location, its calling conventions, etc. 70 | 71 | Again, if you are really familiar with one of the supported 72 | platforms, you may be able to rewrite the individual functions. 73 | Otherwise, it is time to get a copy of "Practical Compiler 74 | Construction", which explains this part in depth. 75 | 76 | You may run into a lot of trouble at this point. For example, 77 | the author needed quite a while to figure out that NetBSD needs 78 | a PT_NOTE section now, or the executable ejected by ld will not 79 | be executable. What a mess! 80 | 81 | 82 | (6) Compile, Test, Repeat 83 | 84 | A lot of things will go wrong. Do not get discouraged. This 85 | is normal. First make the compiler emit syntactically correct 86 | assembler code. Then make it compile the library. Then test 87 | some small programs. Then compile the compiler with itself. 88 | Once it passes the triple test (make test), the compiler can 89 | be considered stable. 90 | 91 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | SubC Compiler, Version 2012-04-15 3 | By Nils M Holm, 2011--2012 4 | Placed in the public domain 5 | 6 | 7 | SUMMARY 8 | 9 | SubC is a compiler for a (mostly) strict and sane subset of 10 | C as described in "The C Programming Language", 2nd Ed. 11 | The language is also known informally as "ANSI C" or "C89". 12 | 13 | A previous version of the compiler is described in great detail 14 | in the book "Practical Compiler Construction", which can be 15 | purchased at Lulu.com. See the end of this text for ordering 16 | information. 17 | 18 | The SubC compiler can compile itself. Unlike many other small C 19 | compilers, it does not bend the rules, though. Its code passes 20 | "gcc -Wall -pedantic" with little or no warnings (depending on 21 | the gcc version used). 22 | 23 | The compiler generates code for GAS, the GNU assembler. It 24 | targets the 386 and x86-64 processors and currently offers 25 | runtime support for the following platforms: 26 | 27 | FreeBSD/386 28 | FreeBSD/x86-64 29 | NetBSD/x86-64 30 | Linux/386 31 | 32 | Porting it to other 32-bit or 64-bit platforms should be quite 33 | straight-forward. See the file "Porting" and/or the book for a 34 | general road map. 35 | 36 | SubC is fast and simple. Its output is typically small (due 37 | to a non-bloated library), but not very runtime efficient, 38 | because it employs none of the code synthesis or optimization 39 | strategies explained in the book. 40 | 41 | 42 | CHANGES TO THE BOOK VERSION 43 | 44 | Note: The book version runs on FreeBSD/386 exclusively. 45 | 46 | This version of the SubC compiler supports the following 47 | parts of C language that were not supported by the SubC 48 | version described in "Practical Compiler Construction": 49 | 50 | o &array is now valid syntax (you no longer have to write 51 | &array[0]). 52 | 53 | o the auto and register keywords are recognized (as no-ops). 54 | 55 | o enums may now be local. 56 | 57 | o extern identifiers may now be declared locally. 58 | 59 | o Prototypes may have the static storage class. 60 | 61 | o There is experimental support for structs and unions. 62 | 63 | o jmp_buf is now a struct; setjmp() and longjmp() must be 64 | called with &jmp_buf. 65 | 66 | o FILEs are now structs and can no longer be mistaken for 67 | ints by the type checker. 68 | 69 | o The #error, #line, and #pragma command have been added. 70 | 71 | o There is a (non-standard) kprintf() function, which is 72 | like fprintf(), but uses a file descriptor. 73 | 74 | 75 | DIFFERENCES BETWEEN SUBC (THIS VERSION) AND FULL C89 76 | 77 | o The following keywords are not recognized: 78 | const, double, float, goto, long, short, signed, typedef, 79 | unsigned, volatile. 80 | 81 | o There are only two primitive data types: the signed int and 82 | the unsigned char; there are also void pointers, and there 83 | is limited support for int(*)() (pointers to functions 84 | of type int). 85 | 86 | o No more than two levels of indirection are supported, and 87 | arrays are limited to one dimension, i.e. valid declarators 88 | are limited to x, x[], *x, *x[], **x (and (*x)()). 89 | 90 | o K&R-style function declarations (with parameter 91 | declarations between the parameter list and function body) 92 | are not accepted. 93 | 94 | o There are no ``volatile'', or ``const'' variables. No 95 | register allocation takes place, so all variables are 96 | implicitly ``volatile''. 97 | 98 | o There is no typedef. 99 | 100 | o There are no unsigned integers and no long integers. 101 | 102 | o Struct/union declarations must be separate from the 103 | declarations of struct/union objects, i.e. 104 | ``struct p { int x, y; } q;'' will not work. 105 | 106 | o Struct/union declarations must be global (struct and union 107 | objects may be declared locally, though). 108 | 109 | o Only ints, chars and arrays of int and char can be 110 | initialized in their declarations; pointers can be 111 | initialized with 0 (but not with NULL). 112 | 113 | o Local arrays cannot have initializers. 114 | 115 | o Local declarations are limited to the beginnings of function 116 | bodies (they do not work in other compound statements). 117 | 118 | o Arguments of prototypes must be named. 119 | 120 | o There is no goto. 121 | 122 | o There are no parameterized macros. 123 | 124 | o The #if and #elif preprocessor commands are not recognized. 125 | 126 | o The preprocessor does not accept multi-line command. 127 | 128 | o The preprocessor does not accept comments in commands. 129 | 130 | o The preprocessor does not recognize the # and ## operators. 131 | 132 | o There may not be any blanks between the # that introduces 133 | a preprocessor command and the subsequent command (e.g.: 134 | "# define" would not be recognized as a valid command). 135 | 136 | o The sizeof operator requires parentheses. 137 | 138 | o Subscripting an integer with a pointer (e.g. 1["foo"]) is 139 | not supported. 140 | 141 | o Function pointers are limited to one single type, int(*)(), 142 | and they have no argument types. 143 | 144 | o There is no assert() due to the lack of parameterized macros. 145 | 146 | o The atexit() mechanism is limited to one function (this may 147 | even be covered by TCPL2). 148 | 149 | o The setjmp()/longjmp() functions must be called with &jmp_buf 150 | due to the lack of typedef. 151 | 152 | o The signal() function returns int due to the lack of a more 153 | sophisticated type system; the return value must be casted to 154 | int(*)() manually. 155 | 156 | o Most of the time-related functions are missing, in particular: 157 | asctime(), gmtime(), localtime(), mktime(), and strftime(). 158 | 159 | o The clock() function is missing, because CLOCKS_PER_SEC 160 | varies among systems. 161 | 162 | o The ctime() function ignores the time zone. 163 | 164 | 165 | SELECTING A TARGET PLATFORM 166 | 167 | The easiest way to prepare a build is to run the configure 168 | script in this directiry. Don't worry, it is just a simple 169 | script that will figure out the host platform via uname and 170 | link a few machine-dependent files into place. 171 | 172 | If you want to do this manually: select one of the cg*.c 173 | files in src/targets and symlink it to src/cg.c. Also link 174 | the corresponding header file. E.g.: 175 | 176 | (cd src && ln -fs targets/cg386.c cg.c) 177 | (cd src && ln -fs targets/cg386.h cg.h) 178 | 179 | Select the C startup (crt0) file for your OS and CPU type 180 | from src/targets and link it to src/lib/crt0.s, e.g.: 181 | 182 | (cd src/lib && \ 183 | ln -fs ../targets/crt0-freebsd-386.s crt0.s) 184 | 185 | If your OS/CPU combination is not supported, you might try 186 | to port the compiler. See the file "Porting" for details. 187 | 188 | 189 | COMPILING THE COMPILER 190 | 191 | The compiler sources are contained in the "src" directory, 192 | so all the subsequent steps assume that this is your current 193 | working directory. (I.e. do a "cd src" now.) 194 | 195 | On a supported system, just type "make". 196 | 197 | Without "make" the compiler can be bootstrapped by running: 198 | 199 | cc -o scc0 *.c 200 | 201 | To compile and package the runtime library: 202 | 203 | ./scc0 -c lib/*.c 204 | ar -rc lib/libscc.a lib/*.o 205 | ranlib lib/libscc.a 206 | 207 | To compile the startup module: 208 | 209 | as -o lib/crt0.o lib/crt0.s 210 | 211 | To test the compiler, either run "make test" or perform the 212 | following steps: 213 | 214 | ./scc0 -o scc1 *.c 215 | ./scc1 -o scc *.c 216 | cmp scc1 scc 217 | 218 | There should not be any differences between the scc1 and scc 219 | executables. 220 | 221 | 222 | INSTALLING THE COMPILER 223 | 224 | The easy way would be to set up the SCCDIR and BINDIR variables 225 | in src/Makefile to suit your taste and then run "make install". 226 | 227 | If you want to install the SubC compiler manually, you will 228 | have to change the SCCDIR variable in the compiler itself. 229 | It points to the base directory which will contain the SubC 230 | headers and runtime library. SCCDIR defaults to "." and can 231 | be overridden on the command line: 232 | 233 | ./scc1 -o scc -D 'SCCDIR="$INSTALLDIR"' *.c 234 | 235 | (where $INSTALLDIR is where the compiler will be installed.) 236 | 237 | You can place the 'scc' executable wherever you want, as long 238 | as its location is covered by the PATH environment variable. 239 | The headers (include/*) go to $INSTALLDIR/include, the library 240 | 'lib/libscc.a' and the startup module 'lib/crt0.o' go to 241 | $INSTALLDIR/lib. 242 | 243 | To test the installation just re-compile the compiler: 244 | 245 | rm scc && scc -o scc *.c 246 | 247 | 248 | FURTHER INFORMATION 249 | 250 | For a thorough explanation of the internals of (an earlier 251 | version of) the compiler, including theoretical backgrounds, 252 | see my book 253 | 254 | "Practical Compiler Construction" 255 | 256 | which can be bought at Lulu.com: 257 | 258 | http://www.lulu.com/content/12610903 (Paperback) 259 | http://www.lulu.com/content/12685672 (PDF) 260 | 261 | 262 | THANKS 263 | 264 | To the Super Dimension Fortress (SDF.ORG) for providing 265 | free shell accounts on 64-bit NetBSD machines. 266 | 267 | To Bakul Shah for granting me remote access to a 64-bit 268 | FreeBSD system and a Linux VM. 269 | 270 | 271 | CONTACT 272 | 273 | Send feedback, suggestions, etc to: 274 | 275 | n m h @ t 3 x . o r g 276 | 277 | See http://t3x.org/contact.html for current ways through my 278 | spam filter. 279 | 280 | -------------------------------------------------------------------------------- /Todo: -------------------------------------------------------------------------------- 1 | 2 | - add a code synthesizer and optimizer 3 | - add parameterized macros 4 | - add assert() 5 | - add stdio macros: getc(), putchar(), etc 6 | ? add dynamic local initializers 7 | ? add GOTO and labels 8 | 9 | -------------------------------------------------------------------------------- /_sums: -------------------------------------------------------------------------------- 1 | 35241 4 ./Porting 2 | 57642 2 ./Changes 3 | 32233 1 ./Makefile 4 | 18660 9 ./README 5 | 43209 1 ./Todo 6 | 40751 1 ./book/s.c 7 | 13233 5 ./book/cg1.o 8 | 42598 1 ./book/p.c 9 | 43827 2 ./book/cg1.c 10 | 25758 3 ./book/cg2.c 11 | 42915 3 ./book/cg3.c 12 | 38847 3 ./book/cg4.c 13 | 56897 6 ./book/opt1.c 14 | 26600 3 ./src/cexpr.c 15 | 12832 12 ./src/decl.c 16 | 16707 1 ./src/error.c 17 | 48084 14 ./src/expr.c 18 | 10894 11 ./src/gen.c 19 | 64722 6 ./src/main.c 20 | 21925 2 ./src/misc.c 21 | 57073 4 ./src/prep.c 22 | 35153 10 ./src/scan.c 23 | 52924 5 ./src/stmt.c 24 | 39131 8 ./src/sym.c 25 | 43646 3 ./src/cgen.h 26 | 25808 2 ./src/data.h 27 | 7143 4 ./src/decl.h 28 | 46045 2 ./src/defs.h 29 | 59304 1 ./src/prec.h 30 | 5747 2 ./src/Makefile 31 | 1109 1 ./src/include/stdlib.h 32 | 12662 2 ./src/include/stdio.h 33 | 39963 1 ./src/include/ctype.h 34 | 22651 1 ./src/include/string.h 35 | 9140 1 ./src/include/syscall.h 36 | 25232 1 ./src/include/setjmp.h 37 | 53401 1 ./src/include/signal.h 38 | 8539 1 ./src/include/time.h 39 | 28246 1 ./src/include/limits.h 40 | 34769 1 ./src/include/errno.h 41 | 9493 2 ./src/lib/ctype.c 42 | 4109 1 ./src/lib/exit.c 43 | 19173 1 ./src/lib/strcat.c 44 | 49680 1 ./src/lib/strcpy.c 45 | 7528 2 ./src/lib/Makefile 46 | 31494 1 ./src/lib/strlen.c 47 | 32040 1 ./src/lib/abs.c 48 | 16357 1 ./src/lib/getenv.c 49 | 39962 4 ./src/lib/vformat.c 50 | 27096 1 ./src/lib/remove.c 51 | 53486 1 ./src/lib/strcmp.c 52 | 25944 1 ./src/lib/strncmp.c 53 | 40788 1 ./src/lib/abort.c 54 | 40208 1 ./src/lib/atoi.c 55 | 34713 1 ./src/lib/strncpy.c 56 | 26362 1 ./src/lib/strchr.c 57 | 50458 1 ./src/lib/strrchr.c 58 | 22906 1 ./src/lib/fflush.c 59 | 56613 1 ./src/lib/fseek.c 60 | 15917 4 ./src/lib/vscan.c 61 | 50862 1 ./src/lib/scanf.c 62 | 62941 1 ./src/lib/difftime.c 63 | 58940 1 ./src/lib/rand.c 64 | 21480 1 ./src/lib/rename.c 65 | 35325 1 ./src/lib/getchar.c 66 | 53600 1 ./src/lib/memset.c 67 | 25251 1 ./src/lib/memcmp.c 68 | 59970 1 ./src/lib/memcpy.c 69 | 43845 1 ./src/lib/memmove.c 70 | 48289 2 ./src/lib/fread.c 71 | 26022 1 ./src/lib/fgetc.c 72 | 57129 2 ./src/lib/malloc.c 73 | 19718 1 ./src/lib/strncat.c 74 | 9838 1 ./src/lib/strdup.c 75 | 577 1 ./src/lib/system.c 76 | 60717 1 ./src/lib/sprintf.c 77 | 45659 1 ./src/lib/qsort.c 78 | 28039 1 ./src/lib/feof.c 79 | 20336 1 ./src/lib/ftell.c 80 | 49973 1 ./src/lib/fdopen.c 81 | 31595 2 ./src/lib/fwrite.c 82 | 5556 1 ./src/lib/fclose.c 83 | 4775 1 ./src/lib/printf.c 84 | 1057 1 ./src/lib/fputc.c 85 | 63200 1 ./src/lib/fopen.c 86 | 51247 1 ./src/lib/putchar.c 87 | 24468 1 ./src/lib/fprintf.c 88 | 37377 1 ./src/lib/freopen.c 89 | 26313 1 ./src/lib/strerror.c 90 | 13005 1 ./src/lib/fputs.c 91 | 62266 1 ./src/lib/puts.c 92 | 19608 1 ./src/lib/fgets.c 93 | 37554 1 ./src/lib/memchr.c 94 | 4536 1 ./src/lib/setvbuf.c 95 | 18294 1 ./src/lib/strtol.c 96 | 8350 1 ./src/lib/strspn.c 97 | 29825 1 ./src/lib/strcspn.c 98 | 9155 1 ./src/lib/strpbrk.c 99 | 54612 1 ./src/lib/strtok.c 100 | 19858 1 ./src/lib/setbuf.c 101 | 41989 1 ./src/lib/init.c 102 | 27567 1 ./src/lib/time.c 103 | 29538 1 ./src/lib/calloc.c 104 | 63923 1 ./src/lib/realloc.c 105 | 13988 1 ./src/lib/free.c 106 | 59101 1 ./src/lib/atexit.c 107 | 44042 1 ./src/lib/bsearch.c 108 | 59794 1 ./src/lib/ferror.c 109 | 12837 1 ./src/lib/fileno.c 110 | 27356 1 ./src/lib/clearerr.c 111 | 33859 1 ./src/lib/ungetc.c 112 | 27120 1 ./src/lib/fsetpos.c 113 | 23718 1 ./src/lib/fgetpos.c 114 | 36336 1 ./src/lib/rewind.c 115 | 35542 2 ./src/lib/ctime.c 116 | 5772 1 ./src/lib/sscanf.c 117 | 5630 1 ./src/lib/fscanf.c 118 | 53134 1 ./src/lib/tmpfile.c 119 | 10985 1 ./src/lib/tmpnam.c 120 | 19018 1 ./src/lib/perror.c 121 | 88 1 ./src/lib/kprintf.c 122 | 29226 7 ./src/targets/cg386.c 123 | 61436 7 ./src/targets/cgx86-64.c 124 | 43588 3 ./src/targets/crt0-freebsd-386.s 125 | 20278 4 ./src/targets/crt0-netbsd-x86-64.s 126 | 24614 4 ./src/targets/crt0-freebsd-x86-64.s 127 | 3659 1 ./src/targets/cg386.h 128 | 3661 1 ./src/targets/cgx86-64.h 129 | 3548 4 ./src/targets/crt0-linux-386.s 130 | 7177 1 ./osversion 131 | 54968 1 ./configure 132 | -------------------------------------------------------------------------------- /book/cg1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *P; 6 | int A = 0; 7 | 8 | void emit(int i, int x) { 9 | if ('l' == i || 'g' == i) { 10 | if (A) emit('p', 0); 11 | A = 1; 12 | } 13 | switch (i) { 14 | case '_': printf("neg A\n"); 15 | break; 16 | case '+': printf("pop X\n"); 17 | printf("addr X,A\n"); 18 | break; 19 | case '*': printf("pop X\n"); 20 | printf("mulr X,A\n"); 21 | break; 22 | case '-': printf("pop X\n"); 23 | printf("swap A,X\n"); 24 | printf("subr X,A\n"); 25 | break; 26 | case '/': printf("pop X\n"); 27 | printf("swap A,X\n"); 28 | printf("divr X,A\n"); 29 | break; 30 | case 'g': printf("lg _%c,A\n", x); 31 | break; 32 | case 'l': printf("ll _%c,A\n", x); 33 | break; 34 | case 'p': printf("push A\n"); 35 | break; 36 | } 37 | } 38 | 39 | void skip(void) { 40 | while (isspace(*P)) P++; 41 | } 42 | 43 | void factor(void) { 44 | skip(); 45 | if ('-' == *P) { 46 | P++; 47 | factor(); 48 | emit('_', 0); 49 | } 50 | else if (isupper(*P)) 51 | emit('g', *P++); 52 | else 53 | emit('l', *P++); 54 | } 55 | 56 | void term(void) { 57 | skip(); 58 | factor(); 59 | for (;;) { 60 | skip(); 61 | switch (*P) { 62 | case '*': P++; 63 | factor(); 64 | emit('*', 0); 65 | break; 66 | case '/': P++; 67 | factor(); 68 | emit('/', 0); 69 | break; 70 | default: return; 71 | } 72 | } 73 | } 74 | 75 | void sum(void) { 76 | skip(); 77 | term(); 78 | for (;;) { 79 | skip(); 80 | switch (*P) { 81 | case '+': P++; 82 | term(); 83 | emit('+', 0); 84 | break; 85 | case '-': P++; 86 | term(); 87 | emit('-', 0); 88 | break; 89 | default: return; 90 | } 91 | } 92 | } 93 | 94 | void expr(char *s) { 95 | P = s; 96 | sum(); 97 | } 98 | 99 | main(int argc, char **argv) { 100 | expr(argc>1? argv[1]: ""); 101 | return EXIT_SUCCESS; 102 | } 103 | -------------------------------------------------------------------------------- /book/cg1.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kstephens/subc/5d3b13ba063370bac76647a1800c139366ad773f/book/cg1.o -------------------------------------------------------------------------------- /book/cg2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *P; 6 | int A = 0; 7 | int Qi = 0, Qx; 8 | 9 | void gen(char *s) { 10 | puts(s); 11 | } 12 | 13 | void gen2(char *s, int a) { 14 | printf(s, a); 15 | putchar('\n'); 16 | } 17 | 18 | void synth(int i) { 19 | int g; 20 | 21 | g = isupper(Qx); 22 | if (!Qi) gen("pop X"); 23 | switch (i) { 24 | case '+': if (!Qi) 25 | gen("addr X,A"); 26 | else if (g) 27 | gen2("addg _%c,A", Qx); 28 | else 29 | gen2("addl _%c,A", Qx); 30 | break; 31 | case '*': if (!Qi) 32 | gen("mulr X,A"); 33 | else if (g) 34 | gen2("mulg _%c,A", Qx); 35 | else 36 | gen2("mull _%c,A", Qx); 37 | break; 38 | case '-': if (!Qi) { 39 | gen("swap A,X"); 40 | gen("subr X,A"); 41 | } 42 | else if (g) 43 | gen2("subg _%c,A", Qx); 44 | else 45 | gen2("subl _%c,A", Qx); 46 | break; 47 | case '/': if (!Qi) { 48 | gen("swap A,X"); 49 | gen("divr X,A"); 50 | } 51 | else if (g) 52 | gen2("divg _%c,A", Qx); 53 | else 54 | gen2("divl _%c,A", Qx); 55 | break; 56 | } 57 | Qi = 0; 58 | } 59 | 60 | void load(void) { 61 | if (A) gen("push A"); 62 | switch (Qi) { 63 | case 'l': gen2("ll _%c,A", Qx); 64 | break; 65 | case 'g': gen2("lg _%c,A", Qx); 66 | break; 67 | } 68 | Qi = 0; 69 | A = 1; 70 | } 71 | 72 | void queue(int i, int x) { 73 | if (Qi) load(); 74 | Qi = i; 75 | Qx = x; 76 | } 77 | 78 | void emit(int i, int x) { 79 | switch (i) { 80 | case 'l': 81 | case 'g': queue(i, x); 82 | break; 83 | case '_': load(); 84 | gen("neg A"); 85 | break; 86 | default: synth(i); 87 | break; 88 | } 89 | } 90 | 91 | void skip(void) { 92 | while (isspace(*P)) P++; 93 | } 94 | 95 | void factor(void) { 96 | skip(); 97 | if ('-' == *P) { 98 | P++; 99 | factor(); 100 | emit('_', 0); 101 | } 102 | else if (isupper(*P)) 103 | emit('g', *P++); 104 | else 105 | emit('l', *P++); 106 | } 107 | 108 | void term(void) { 109 | skip(); 110 | factor(); 111 | for (;;) { 112 | skip(); 113 | switch (*P) { 114 | case '*': P++; 115 | factor(); 116 | emit('*', 0); 117 | break; 118 | case '/': P++; 119 | factor(); 120 | emit('/', 0); 121 | break; 122 | default: return; 123 | } 124 | } 125 | } 126 | 127 | void sum(void) { 128 | skip(); 129 | term(); 130 | for (;;) { 131 | skip(); 132 | switch (*P) { 133 | case '+': P++; 134 | term(); 135 | emit('+', 0); 136 | break; 137 | case '-': P++; 138 | term(); 139 | emit('-', 0); 140 | break; 141 | default: return; 142 | } 143 | } 144 | } 145 | 146 | void expr(char *s) { 147 | P = s; 148 | sum(); 149 | } 150 | 151 | main(int argc, char **argv) { 152 | expr(argc>1? argv[1]: ""); 153 | return EXIT_SUCCESS; 154 | } 155 | -------------------------------------------------------------------------------- /book/cg3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *P; 6 | int R = 0; 7 | int N = 4; 8 | int Qi = 0, Qx; 9 | 10 | void gen(char *s) { 11 | printf(s, R); 12 | putchar('\n'); 13 | } 14 | 15 | void gen2(char *s, int a) { 16 | printf(s, a, R); 17 | putchar('\n'); 18 | } 19 | 20 | void genr(char *s) { 21 | printf(s, R, R-1); 22 | putchar('\n'); 23 | } 24 | 25 | void push(void) { 26 | if (++R > N) { 27 | fprintf(stderr, "out of registers\n"); 28 | exit(1); 29 | } 30 | } 31 | 32 | void pop(void) { 33 | R--; 34 | } 35 | 36 | void synth(int i) { 37 | int g; 38 | 39 | g = isupper(Qx); 40 | switch (i) { 41 | case '+': if (!Qi) 42 | genr("addr R%d,R%d"); 43 | else if (g) 44 | gen2("addg _%c,R%d", Qx); 45 | else 46 | gen2("addl _%c,R%d", Qx); 47 | break; 48 | case '*': if (!Qi) 49 | genr("mulr R%d,R%d"); 50 | else if (g) 51 | gen2("mulg _%c,R%d", Qx); 52 | else 53 | gen2("mull _%c,R%d", Qx); 54 | break; 55 | case '-': if (!Qi) { 56 | genr("swap R%d,R%d"); 57 | genr("subr R%d,R%d"); 58 | } 59 | else if (g) 60 | gen2("subg _%c,R%d", Qx); 61 | else 62 | gen2("subl _%c,R%d", Qx); 63 | break; 64 | case '/': if (!Qi) { 65 | genr("swap R%d,R%d"); 66 | genr("divr R%d,R%d"); 67 | } 68 | else if (g) 69 | gen2("divg _%c,R%d", Qx); 70 | else 71 | gen2("divl _%c,R%d", Qx); 72 | break; 73 | } 74 | if (!Qi) pop(); 75 | Qi = 0; 76 | } 77 | 78 | void load(void) { 79 | push(); 80 | switch (Qi) { 81 | case 'l': gen2("ll _%c,R%d", Qx); 82 | break; 83 | case 'g': gen2("lg _%c,R%d", Qx); 84 | break; 85 | } 86 | Qi = 0; 87 | } 88 | 89 | void queue(int i, int x) { 90 | if (Qi) load(); 91 | Qi = i; 92 | Qx = x; 93 | } 94 | 95 | void emit(int i, int x) { 96 | switch (i) { 97 | case 'l': 98 | case 'g': queue(i, x); 99 | break; 100 | case '_': load(); 101 | gen("neg R%d"); 102 | break; 103 | default: synth(i); 104 | break; 105 | } 106 | } 107 | 108 | void skip(void) { 109 | while (isspace(*P)) P++; 110 | } 111 | 112 | void sum(void); 113 | 114 | void factor(void) { 115 | skip(); 116 | if ('-' == *P) { 117 | P++; 118 | factor(); 119 | emit('_', 0); 120 | } 121 | else if ('(' == *P) { 122 | P++; 123 | sum(); 124 | P++; 125 | } 126 | else if (isupper(*P)) 127 | emit('g', *P++); 128 | else 129 | emit('l', *P++); 130 | } 131 | 132 | void term(void) { 133 | skip(); 134 | factor(); 135 | for (;;) { 136 | skip(); 137 | switch (*P) { 138 | case '*': P++; 139 | factor(); 140 | emit('*', 0); 141 | break; 142 | case '/': P++; 143 | factor(); 144 | emit('/', 0); 145 | break; 146 | default: return; 147 | } 148 | } 149 | } 150 | 151 | void sum(void) { 152 | skip(); 153 | term(); 154 | for (;;) { 155 | skip(); 156 | switch (*P) { 157 | case '+': P++; 158 | term(); 159 | emit('+', 0); 160 | break; 161 | case '-': P++; 162 | term(); 163 | emit('-', 0); 164 | break; 165 | default: return; 166 | } 167 | } 168 | } 169 | 170 | void expr(char *s) { 171 | P = s; 172 | sum(); 173 | } 174 | 175 | main(int argc, char **argv) { 176 | expr(argc>1? argv[1]: ""); 177 | return EXIT_SUCCESS; 178 | } 179 | -------------------------------------------------------------------------------- /book/cg4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *P; 6 | int R = 0; 7 | int S = 0; 8 | int N = 4; 9 | int Qi = 0, Qx; 10 | 11 | void gen(char *s) { 12 | printf(s, R); 13 | putchar('\n'); 14 | } 15 | 16 | void gen2(char *s, int a) { 17 | printf(s, a, R); 18 | putchar('\n'); 19 | } 20 | 21 | void genr(char *s) { 22 | int d; 23 | 24 | d = R < 2? N: R-1; 25 | printf(s, R, d); 26 | putchar('\n'); 27 | } 28 | 29 | void push(void) { 30 | if (R >= N) { 31 | R = 1; 32 | gen("push R%d"); 33 | S++; 34 | } 35 | else if (S) { 36 | R++; 37 | gen("push R%d"); 38 | S++; 39 | } 40 | else { 41 | R++; 42 | } 43 | } 44 | 45 | void pop(void) { 46 | if (R <= 1) { 47 | gen("pop R%d"); 48 | R = N; 49 | S--; 50 | } 51 | else if (S) { 52 | gen("pop R%d"); 53 | S--; 54 | R--; 55 | } 56 | else { 57 | R--; 58 | } 59 | } 60 | 61 | void synth(int i) { 62 | int g; 63 | 64 | g = isupper(Qx); 65 | switch (i) { 66 | case '+': if (!Qi) 67 | genr("addr R%d,R%d"); 68 | else if (g) 69 | gen2("addg _%c,R%d", Qx); 70 | else 71 | gen2("addl _%c,R%d", Qx); 72 | break; 73 | case '*': if (!Qi) 74 | genr("mulr R%d,R%d"); 75 | else if (g) 76 | gen2("mulg _%c,R%d", Qx); 77 | else 78 | gen2("mull _%c,R%d", Qx); 79 | break; 80 | case '-': if (!Qi) { 81 | genr("swap R%d,R%d"); 82 | genr("subr R%d,R%d"); 83 | } 84 | else if (g) 85 | gen2("subg _%c,R%d", Qx); 86 | else 87 | gen2("subl _%c,R%d", Qx); 88 | break; 89 | case '/': if (!Qi) { 90 | genr("swap R%d,R%d"); 91 | genr("divr R%d,R%d"); 92 | } 93 | else if (g) 94 | gen2("divg _%c,R%d", Qx); 95 | else 96 | gen2("divl _%c,R%d", Qx); 97 | break; 98 | } 99 | if (!Qi) pop(); 100 | Qi = 0; 101 | } 102 | 103 | void load(void) { 104 | push(); 105 | switch (Qi) { 106 | case 'l': gen2("ll _%c,R%d", Qx); 107 | break; 108 | case 'g': gen2("lg _%c,R%d", Qx); 109 | break; 110 | } 111 | Qi = 0; 112 | } 113 | 114 | void queue(int i, int x) { 115 | if (Qi) load(); 116 | Qi = i; 117 | Qx = x; 118 | } 119 | 120 | void emit(int i, int x) { 121 | switch (i) { 122 | case 'l': 123 | case 'g': queue(i, x); 124 | break; 125 | case '_': load(); 126 | gen("neg R%d"); 127 | break; 128 | default: synth(i); 129 | break; 130 | } 131 | } 132 | 133 | void skip(void) { 134 | while (isspace(*P)) P++; 135 | } 136 | 137 | void sum(void); 138 | 139 | void factor(void) { 140 | skip(); 141 | if ('-' == *P) { 142 | P++; 143 | factor(); 144 | emit('_', 0); 145 | } 146 | else if ('(' == *P) { 147 | P++; 148 | sum(); 149 | P++; 150 | } 151 | else if (isupper(*P)) 152 | emit('g', *P++); 153 | else 154 | emit('l', *P++); 155 | } 156 | 157 | void term(void) { 158 | skip(); 159 | factor(); 160 | for (;;) { 161 | skip(); 162 | switch (*P) { 163 | case '*': P++; 164 | factor(); 165 | emit('*', 0); 166 | break; 167 | case '/': P++; 168 | factor(); 169 | emit('/', 0); 170 | break; 171 | default: return; 172 | } 173 | } 174 | } 175 | 176 | void sum(void) { 177 | skip(); 178 | term(); 179 | for (;;) { 180 | skip(); 181 | switch (*P) { 182 | case '+': P++; 183 | term(); 184 | emit('+', 0); 185 | break; 186 | case '-': P++; 187 | term(); 188 | emit('-', 0); 189 | break; 190 | default: return; 191 | } 192 | } 193 | } 194 | 195 | void expr(char *s) { 196 | P = s; 197 | sum(); 198 | } 199 | 200 | main(int argc, char **argv) { 201 | expr(argc>1? argv[1]: ""); 202 | return EXIT_SUCCESS; 203 | } 204 | -------------------------------------------------------------------------------- /book/opt1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NODES 1024 6 | 7 | char *P; 8 | 9 | int Type[NODES], 10 | Value[NODES], 11 | Left[NODES], 12 | Right[NODES]; 13 | int Next = 1; 14 | 15 | int node(int t, int v, int l, int r) { 16 | if (Next >= NODES) { 17 | fprintf(stderr, "out of nodes\n"); 18 | exit(EXIT_FAILURE); 19 | } 20 | Type[Next] = t; 21 | Value[Next] = v; 22 | Left[Next] = l; 23 | Right[Next] = r; 24 | return Next++; 25 | } 26 | 27 | void skip(void) { 28 | while (isspace(*P)) P++; 29 | } 30 | 31 | int sum(void); 32 | 33 | int factor(void) { 34 | int n = 0, v; 35 | 36 | skip(); 37 | if ('(' == *P) { 38 | P++; 39 | n = sum(); 40 | P++; 41 | } 42 | else if ('-' == *P) { 43 | P++; 44 | n = node('-', 0, factor(), 0); 45 | } 46 | else if (isdigit(*P)) { 47 | for (v=0; isdigit(*P); P++) 48 | v = v*10 + *P-'0'; 49 | n = node('c', v, 0, 0); 50 | } 51 | else if (isalpha(*P)) { 52 | n = node('v', *P++, 0, 0); 53 | } 54 | return n; 55 | } 56 | 57 | int term(void) { 58 | int n, n2; 59 | 60 | skip(); 61 | n = factor(); 62 | for (;;) { 63 | skip(); 64 | switch (*P) { 65 | case '*': P++; 66 | n2 = factor(); 67 | n = node('*', 0, n, n2); 68 | break; 69 | case '/': P++; 70 | n2 = factor(); 71 | n = node('/', 0, n, n2); 72 | break; 73 | default: return n; 74 | } 75 | } 76 | } 77 | 78 | int sum(void) { 79 | int n, n2; 80 | 81 | skip(); 82 | n = term(); 83 | for (;;) { 84 | skip(); 85 | switch (*P) { 86 | case '+': P++; 87 | n2 = term(); 88 | n = node('+', 0, n, n2); 89 | break; 90 | case '-': P++; 91 | n2 = term(); 92 | n = node('-', 0, n, n2); 93 | break; 94 | default: return n; 95 | } 96 | } 97 | } 98 | 99 | int expr(char *s) { 100 | P = s; 101 | return sum(); 102 | } 103 | 104 | void dump(int n, int k) { 105 | int i; 106 | 107 | if (!n) return; 108 | for (i=0; i 2 && find(n, t) && k > K) { 278 | K = k; 279 | Sub = n; 280 | } 281 | trav2(t, Left[n]); 282 | trav2(t, Right[n]); 283 | } 284 | 285 | int maxduptree(int n) { 286 | Sub = 0; 287 | K = 0; 288 | trav2(n, n); 289 | return Sub; 290 | } 291 | 292 | int replace(int x, int n) { 293 | if (!n) return 0; 294 | if (equal(x, n)) return node('v', '@', 0, 0); 295 | return node(Type[n], Value[n], 296 | replace(x, Left[n]), 297 | replace(x, Right[n])); 298 | } 299 | 300 | int cse(int n) { 301 | int csub, t; 302 | 303 | csub = maxduptree(n); 304 | if (csub) { 305 | n = replace(csub, n); 306 | t = node('v', '@', 0, 0); 307 | csub = node('=', 0, t, csub); 308 | n = node(',', 0, csub, n); 309 | } 310 | return n; 311 | } 312 | 313 | void comp(char *s, int d) { 314 | int n; 315 | 316 | n = expr(s); 317 | n = fold(n); 318 | n = rewrite(n); 319 | n = cse(n); 320 | d? draw(n): dump(n, 0); 321 | } 322 | 323 | int main(int argc, char **argv) { 324 | int d = 0; 325 | 326 | if (argc > 1 && !strcmp(argv[1], "-d")) { 327 | d = 1; 328 | argc--; 329 | argv++; 330 | } 331 | comp(argc>1? argv[1]: "", d); 332 | return EXIT_SUCCESS; 333 | } 334 | -------------------------------------------------------------------------------- /book/p.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAX 20000 4 | 5 | main() { 6 | int i, j, p[MAX], k, ref = 0; 7 | 8 | for (k=0, i=3; k 2 | #include 3 | #include 4 | 5 | #define boolean char 6 | 7 | static void nsieve(int m) { 8 | int count = 0, i, j; 9 | boolean *flags; 10 | 11 | flags = malloc(m * sizeof(boolean)); 12 | memset(flags, 1, m); 13 | for (i = 2; i < m; ++i) { 14 | if (flags[i]) { 15 | ++count; 16 | for (j = i << 1; j < m; j += i) 17 | flags[j] = 0; 18 | } 19 | } 20 | free(flags); 21 | printf("primes up to %8d %8d\n", m, count); 22 | } 23 | 24 | int main(int argc, char *argv[]) { 25 | int m; 26 | 27 | m = atoi(argv[1]); 28 | nsieve(10000 << m); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | os=`uname` 4 | mac=`uname -m` 5 | 6 | if test -f src/scc0; then 7 | echo "You may want to run 'make clean' first." 8 | exit 1 9 | fi 10 | 11 | case $os/$mac in 12 | FreeBSD/i386) os=freebsd ; mac=386 ;; 13 | FreeBSD/amd64) os=freebsd ; mac=x86-64 ;; 14 | NetBSD/amd64) os=netbsd ; mac=x86-64 ;; 15 | Linux/i386) os=linux ; mac=386 ;; 16 | Linux/i686) os=linux ; mac=386 ;; 17 | *) 18 | echo "Sorry, $os/$mac is currently not supported." 19 | exit 1 20 | ;; 21 | esac 22 | 23 | (cd src && ln -fs targets/cg$mac.c cg.c) 24 | (cd src && ln -fs targets/cg$mac.h cg.h) 25 | (cd src/lib && ln -fs ../targets/crt0-$os-$mac.s crt0.s) 26 | 27 | echo "Building for $os/$mac. Now cd to src and run make." 28 | -------------------------------------------------------------------------------- /osversion: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | grep "^#define.*`uname`_[Vv]ersion" /usr/include/sys/param.h | awk '{print $3}' 4 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | LINT= gcc -c -o /dev/null -ansi -pedantic -Wall 2 | 3 | FILES= cexpr.c cg.c decl.c error.c expr.c gen.c \ 4 | main.c misc.c prep.c scan.c stmt.c sym.c 5 | HDRS= data.h decl.h defs.h prec.h 6 | 7 | SCCDIR= /u/scc 8 | BINDIR= /u/bin 9 | 10 | all: scc0 lib/crt0.o lib/libscc.a 11 | 12 | test: scc $(FILES) 13 | ./scc -o scc2 $(FILES) 14 | cmp scc scc2 && rm -f scc2 15 | 16 | install: all 17 | ./scc0 -o scc -D 'SCCDIR="$(SCCDIR)"' *.c 18 | cp scc $(BINDIR) 19 | cp include/* $(SCCDIR)/include 20 | cp lib/libscc.a lib/crt0.o $(SCCDIR)/lib 21 | 22 | scc: scc1 $(FILES) 23 | ./scc1 -o scc $(FILES) 24 | 25 | scc1: scc0 lib/crt0.o lib/libscc.a $(FILES) 26 | ./scc0 -o scc1 $(FILES) 27 | 28 | scc0: $(FILES) 29 | $(CC) -o scc0 $(FILES) 30 | 31 | lib/libscc.a: 32 | make -f lib/Makefile 33 | 34 | libc: 35 | make -f lib/Makefile 36 | 37 | lib/crt0.o: lib/crt0.s 38 | as -o lib/crt0.o lib/crt0.s 39 | 40 | $(FILES): $(HDRS) 41 | gen.c: cgen.h 42 | 43 | lint: 44 | $(LINT) cexpr.c 45 | $(LINT) cg386.c 46 | $(LINT) cgx86_64.c 47 | $(LINT) decl.c 48 | $(LINT) error.c 49 | $(LINT) expr.c 50 | $(LINT) gen.c 51 | $(LINT) main.c 52 | $(LINT) misc.c 53 | $(LINT) prep.c 54 | $(LINT) scan.c 55 | $(LINT) stmt.c 56 | $(LINT) sym.c 57 | 58 | clean: 59 | rm -f scc0 scc1 scc2 scc test.s *.o *.core core a.out lib/crt0.o 60 | make -f lib/Makefile clean 61 | -------------------------------------------------------------------------------- /src/cexpr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Constant expression parser 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | #include "prec.h" 10 | 11 | /* 12 | * cfactor := 13 | * INTLIT 14 | * | IDENT 15 | * | - cfactor 16 | * | ~ cfactor 17 | * | ( constexpr ) 18 | * 19 | * cterm := 20 | * cfactor 21 | * | cterm * cprefix 22 | * | cterm / cprefix 23 | * | cterm % cprefix 24 | * 25 | * csum := 26 | * cterm 27 | * | csum + cterm 28 | * | csum - cterm 29 | * 30 | * cshift := 31 | * csum 32 | * | cshift << csum 33 | * | cshift >> csum 34 | * 35 | * crelation := 36 | * cshift 37 | * | crelation < cshift 38 | * | crelation > cshift 39 | * | crelation <= cshift 40 | * | crelation >= cshift 41 | * 42 | * cequation := 43 | * crelation 44 | * | cequation == crelation 45 | * | cequation != crelation 46 | * 47 | * cbinand := 48 | * cequation 49 | * | cbinand & cequation 50 | * 51 | * cbinxor := 52 | * cbinand 53 | * | cbinxor ^ cbinand 54 | * 55 | * cbinor := 56 | * cbinxor 57 | * | cbinor ^ cbinxor 58 | * 59 | * constexpr := 60 | * cbinor 61 | */ 62 | 63 | static int constfac(void) { 64 | int y, v; 65 | 66 | v = Value; 67 | if (INTLIT == Token) { 68 | Token = scan(); 69 | return v; 70 | } 71 | if (MINUS == Token) { 72 | Token = scan(); 73 | return -constfac(); 74 | } 75 | if (TILDE == Token) { 76 | Token = scan(); 77 | return ~constfac(); 78 | } 79 | if (LPAREN == Token) { 80 | Token = scan(); 81 | v = constexpr(); 82 | rparen(); 83 | return v; 84 | } 85 | if (Token == IDENT) { 86 | y = findsym(Text); 87 | if (!y || Types[y] != TCONSTANT) 88 | error("not a constant: %s", Text); 89 | Token = scan(); 90 | return y? Vals[y]: 0; 91 | } 92 | else { 93 | error("constant expression expected at: %s", Text); 94 | Token = scan(); 95 | return 1; 96 | } 97 | } 98 | 99 | static int constop(int op, int v1, int v2) { 100 | if ((SLASH == op || MOD == op) && 0 == v2) { 101 | error("constant divide by zero", NULL); 102 | return 0; 103 | } 104 | switch (op) { 105 | case SLASH: v1 /= v2; break; 106 | case STAR: v1 *= v2; break; 107 | case MOD: v1 %= v2; break; 108 | case PLUS: v1 += v2; break; 109 | case MINUS: v1 -= v2; break; 110 | case LSHIFT: v1 <<= v2; break; 111 | case RSHIFT: v1 >>= v2; break; 112 | case GREATER: v1 = v1 > v2; break; 113 | case GTEQ: v1 = v1 >= v2; break; 114 | case LESS: v1 = v1 < v2; break; 115 | case LTEQ: v1 = v1 <= v2; break; 116 | case EQUAL: v1 = v1 == v2; break; 117 | case NOTEQ: v1 = v1 != v2; break; 118 | case AMPER: v1 &= v2; break; 119 | case CARET: v1 ^= v2; break; 120 | case PIPE: v1 |= v2; break; 121 | } 122 | return v1; 123 | } 124 | 125 | int constexpr(void) { 126 | int v, ops[9], vals[10], sp = 0; 127 | 128 | vals[0] = constfac(); 129 | while (SLASH == Token || STAR == Token || MOD == Token || 130 | PLUS == Token || MINUS == Token || LSHIFT == Token || 131 | RSHIFT == Token || GREATER == Token || GTEQ == Token || 132 | LESS == Token || LTEQ == Token || EQUAL == Token || 133 | NOTEQ == Token || AMPER == Token || CARET == Token || 134 | PIPE == Token 135 | ) { 136 | while (sp > 0 && Prec[Token] <= Prec[ops[sp-1]]) { 137 | v = constop(ops[sp-1], vals[sp-1], vals[sp]); 138 | vals[--sp] = v; 139 | } 140 | ops[sp++] = Token; 141 | Token = scan(); 142 | vals[sp] = constfac(); 143 | } 144 | while (sp > 0) { 145 | v = constop(ops[sp-1], vals[sp-1], vals[sp]); 146 | vals[--sp] = v; 147 | } 148 | return vals[0]; 149 | } 150 | -------------------------------------------------------------------------------- /src/cg.c: -------------------------------------------------------------------------------- 1 | targets/cg386.c -------------------------------------------------------------------------------- /src/cg.h: -------------------------------------------------------------------------------- 1 | targets/cg386.h -------------------------------------------------------------------------------- /src/cgen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Code generator interface 4 | */ 5 | 6 | void cgadd(void); 7 | void cgand(void); 8 | void cgargc(void); 9 | void cgbool(void); 10 | void cgbrfalse(int n); 11 | void cgbrtrue(int n); 12 | void cgbss(char *s, int z); 13 | void cgcall(char *s); 14 | void cgcalr(void); 15 | void cgcalswtch(void); 16 | void cgcase(int v, int l); 17 | void cgclear(void); 18 | void cgdata(void); 19 | void cgdec1ib(void); 20 | void cgdec1iw(void); 21 | void cgdec1pi(int v); 22 | void cgdec2ib(void); 23 | void cgdec2iw(void); 24 | void cgdec2pi(int v); 25 | void cgdecgb(char *s); 26 | void cgdecgw(char *s); 27 | void cgdeclb(int a); 28 | void cgdeclw(int a); 29 | void cgdecpg(char *s, int v); 30 | void cgdecpl(int a, int v); 31 | void cgdecps(int a, int v); 32 | void cgdecsb(int a); 33 | void cgdecsw(int a); 34 | void cgdefb(int v); 35 | void cgdefc(int c); 36 | void cgdefl(int v); 37 | void cgdefp(int v); 38 | void cgdefw(int v); 39 | void cgdiv(void); 40 | void cgentry(void); 41 | void cgeq(void); 42 | void cgexit(void); 43 | void cgge(void); 44 | void cggt(void); 45 | void cginc1ib(void); 46 | void cginc1iw(void); 47 | void cginc1pi(int v); 48 | void cginc2ib(void); 49 | void cginc2iw(void); 50 | void cginc2pi(int v); 51 | void cgincgb(char *s); 52 | void cgincgw(char *s); 53 | void cginclb(int a); 54 | void cginclw(int a); 55 | void cgincpg(char *s, int v); 56 | void cgincpl(int a, int v); 57 | void cgincps(int a, int v); 58 | void cgincsb(int a); 59 | void cgincsw(int a); 60 | void cgindb(void); 61 | void cgindw(void); 62 | void cginitlw(int v, int a); 63 | void cgior(void); 64 | void cgjump(int n); 65 | void cgldga(char *s); 66 | void cgldgb(char *s); 67 | void cgldgw(char *s); 68 | void cgldinc(void); 69 | void cgldla(int n); 70 | void cgldlab(int id); 71 | void cgldlb(int n); 72 | void cgldlw(int n); 73 | void cgldsa(int n); 74 | void cgldsb(int n); 75 | void cgldsw(int n); 76 | void cgldswtch(int n); 77 | void cgle(void); 78 | void cglit(int v); 79 | void cglognot(void); 80 | void cglt(void); 81 | void cgmod(void); 82 | void cgmul(void); 83 | void cgne(void); 84 | void cgneg(void); 85 | void cgnot(void); 86 | void cgpop2(void); 87 | void cgpopptr(void); 88 | void cgpostlude(void); 89 | void cgprelude(void); 90 | void cgpublic(char *s); 91 | void cgpush(void); 92 | void cgpushlit(int n); 93 | void cgscale(void); 94 | void cgscale2(void); 95 | void cgscale2by(int v); 96 | void cgscaleby(int v); 97 | void cgshl(void); 98 | void cgshr(void); 99 | void cgstack(int n); 100 | void cgstorgb(char *s); 101 | void cgstorgw(char *s); 102 | void cgstorib(void); 103 | void cgstoriw(void); 104 | void cgstorlb(int n); 105 | void cgstorlw(int n); 106 | void cgstorsb(int n); 107 | void cgstorsw(int n); 108 | void cgsub(void); 109 | void cgswap(void); 110 | void cgtext(void); 111 | void cgunscale(void); 112 | void cgunscaleby(int v); 113 | void cgxor(void); 114 | -------------------------------------------------------------------------------- /src/data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Global variables 4 | */ 5 | 6 | #ifndef _extern 7 | #define _extern extern 8 | #endif 9 | 10 | _extern FILE *Infile; 11 | _extern FILE *Outfile; 12 | _extern int Token; 13 | _extern char Text[TEXTLEN+1]; 14 | _extern int Value; 15 | _extern int Line; 16 | _extern int Errors; 17 | _extern int Syntoken; 18 | _extern int Putback; 19 | _extern int Rejected; 20 | _extern int Rejval; 21 | _extern char Rejtext[TEXTLEN+1]; 22 | _extern char *File; 23 | _extern char *Basefile; 24 | _extern char *Macp[MAXNMAC]; 25 | _extern int Macc[MAXNMAC]; 26 | _extern int Mp; 27 | _extern int Expandmac; 28 | _extern int Ifdefstk[MAXIFDEF], Isp; 29 | _extern int Inclev; 30 | _extern int Textseg; 31 | 32 | /* symbol tabel structure */ 33 | _extern char *Names[NSYMBOLS]; 34 | _extern int Prims[NSYMBOLS]; 35 | _extern char Types[NSYMBOLS]; 36 | _extern char Stcls[NSYMBOLS]; 37 | _extern int Sizes[NSYMBOLS]; 38 | _extern int Vals[NSYMBOLS]; 39 | _extern char *Mtext[NSYMBOLS]; 40 | _extern int Globs; 41 | _extern int Locs; 42 | 43 | _extern int Thisfn; 44 | 45 | /* name list */ 46 | _extern char Nlist[POOLSIZE]; 47 | _extern int Nbot; 48 | _extern int Ntop; 49 | 50 | _extern int Breakstk[MAXBREAK], Bsp; 51 | _extern int Contstk[MAXBREAK], Csp; 52 | _extern int Retlab; 53 | 54 | /* local init structure */ 55 | _extern int LIaddr[MAXLOCINIT]; 56 | _extern int LIval[MAXLOCINIT]; 57 | _extern int Nli; 58 | 59 | _extern char *Files[MAXFILES]; 60 | _extern int Nf; 61 | 62 | _extern int O_verbose; 63 | _extern int O_componly; 64 | _extern int O_asmonly; 65 | _extern int O_testonly; 66 | _extern char *O_outfile; 67 | _extern int O_debug; 68 | -------------------------------------------------------------------------------- /src/decl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Function declarations 4 | */ 5 | 6 | int addglob(char *name, int prim, int type, int scls, int size, int val, 7 | char *mval, int init); 8 | int addloc(char *name, int prim, int type, int scls, int size, int val, 9 | int init); 10 | void cerror(char *s, int c); 11 | int chrpos(char *s, int c); 12 | void clear(void); 13 | void clrlocs(void); 14 | void colon(void); 15 | void compound(int lbr); 16 | int comptype(int p); 17 | int constexpr(void); 18 | void copyname(char *name, char *s); 19 | int deref(int p); 20 | void dumpsyms(char *title, char *sub, int from, int to); 21 | int eofcheck(void); 22 | void error(char *s, char *a); 23 | int expr(int *lv); 24 | void fatal(char *s); 25 | int findglob(char *s); 26 | int findloc(char *s); 27 | int findmem(int y, char *s); 28 | int findstruct(char *s); 29 | int findsym(char *s); 30 | int findmac(char *s); 31 | int frozen(int depth); 32 | char *galloc(int k); 33 | void gen(char *s); 34 | int genadd(int p1, int p2); 35 | void genaddr(int y); 36 | void genand(void); 37 | void genargc(void); 38 | void genasop(int op, int p1, int p2); 39 | int genbinop(int op, int p1, int p2); 40 | void genbool(void); 41 | void genbrfalse(int dest); 42 | void genbrtrue(int dest); 43 | void genbss(char *name, int len); 44 | void gencall(int y); 45 | void gencalr(void); 46 | void gencmp(char *inst); 47 | void gendata(void); 48 | void gendefb(int v); 49 | void gendefl(int id); 50 | void gendefp(int v); 51 | void gendefs(char *s, int len); 52 | void gendefw(int v); 53 | void gendiv(int swap); 54 | void genentry(void); 55 | void genexit(void); 56 | void geninc(int *lv, int inc, int pre); 57 | void genind(int p); 58 | void genior(void); 59 | void genjump(int dest); 60 | void genlab(int id); 61 | void genldlab(int id); 62 | void genlit(int v); 63 | void genln(char *s); 64 | void genlocinit(void); 65 | void genlognot(void); 66 | void genmod(int swap); 67 | void genmul(void); 68 | void genname(char *name); 69 | void genneg(void); 70 | void gennot(void); 71 | void genpostlude(void); 72 | void genprelude(void); 73 | void genpublic(char *name); 74 | void genpush(void); 75 | void genpushlit(int n); 76 | void genraw(char *s); 77 | void genscale(void); 78 | void genscale2(void); 79 | void genshl(int swap); 80 | void genshr(int swap); 81 | void genstack(int n); 82 | void genstore(int op, int *lv, int *lv2); 83 | int gensub(int p1, int p2, int swap); 84 | void genswitch(int *vals, int *labs, int nc, int dflt); 85 | void gentext(void); 86 | void genxor(void); 87 | char *globname(char *s); 88 | char *gsym(char *s); 89 | void ident(void); 90 | int inttype(int p); 91 | int label(void); 92 | char *labname(int id); 93 | void lbrace(void); 94 | void lgen(char *s, char *inst, int n); 95 | void lgen2(char *s, int v1, int v2); 96 | void load(void); 97 | void lparen(void); 98 | void match(int t, char *what); 99 | char *newfilename(char *name, int sfx); 100 | int next(void); 101 | void ngen(char *s, char *inst, int n); 102 | void ngen2(char *s, char *inst, int n, int a); 103 | int objsize(int prim, int type, int size); 104 | void playmac(char *s); 105 | int pointerto(int prim); 106 | void preproc(void); 107 | int primtype(int t, char *s); 108 | void putback(int t); 109 | void rbrace(void); 110 | void rbrack(void); 111 | void reject(void); 112 | void resume(void); 113 | int rexpr(void); 114 | void rparen(void); 115 | void rvalue(int *lv); 116 | int scan(void); 117 | int scanraw(void); 118 | void semi(void); 119 | void sgen(char *s, char *inst, char *s2); 120 | void sgen2(char *s, char *inst, int v, char *s2); 121 | int skip(void); 122 | void suspend(void); 123 | int synch(int syn); 124 | void top(void); 125 | int typematch(int p1, int p2); 126 | -------------------------------------------------------------------------------- /src/defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Definitions 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "cg.h" 11 | 12 | #ifndef SCCDIR 13 | #define SCCDIR "." 14 | #endif 15 | 16 | #define PREFIX 'C' 17 | #define LPREFIX 'L' 18 | 19 | #define ASCMD "as -o %s %s" 20 | #define LDCMD "ld -o %s %s/lib/crt0.o" 21 | #define SCCLIBC "%s/lib/libscc.a" 22 | #define SYSLIBC "/usr/lib/libc.a" 23 | 24 | #define INTSIZE BPW 25 | #define PTRSIZE INTSIZE 26 | #define CHARSIZE 1 27 | 28 | #define TEXTLEN 512 29 | #define NAMELEN 16 30 | 31 | #define MAXFILES 32 32 | 33 | #define MAXIFDEF 16 34 | #define MAXNMAC 32 35 | #define MAXCASE 256 36 | #define MAXBREAK 16 37 | #define MAXLOCINIT 32 38 | #define MAXFNARGS 32 39 | 40 | /* assert(NSYMBOLS < PSTRUCT) */ 41 | #define NSYMBOLS 1024 42 | #define POOLSIZE 16384 43 | 44 | /* types */ 45 | enum { 46 | TVARIABLE = 1, 47 | TARRAY, 48 | TFUNCTION, 49 | TCONSTANT, 50 | TMACRO, 51 | TSTRUCT 52 | }; 53 | 54 | /* primitive types */ 55 | enum { 56 | PCHAR = 1, 57 | PINT, 58 | CHARPTR, 59 | INTPTR, 60 | CHARPP, 61 | INTPP, 62 | PVOID, 63 | VOIDPTR, 64 | VOIDPP, 65 | FUNPTR, 66 | PSTRUCT = 0x2000, 67 | PUNION = 0x4000, 68 | STCPTR = 0x6000, 69 | STCPP = 0x8000, 70 | UNIPTR = 0xA000, 71 | UNIPP = 0xC000, 72 | STCMASK = 0xE000 73 | }; 74 | 75 | /* storage classes */ 76 | enum { 77 | CPUBLIC = 1, 78 | CEXTERN, 79 | CSTATIC, 80 | CLSTATC, 81 | CAUTO, 82 | CSPROTO, 83 | CMEMBER, 84 | CSTCDEF 85 | }; 86 | 87 | /* lvalue structure */ 88 | enum { 89 | LVSYM, 90 | LVPRIM, 91 | LV 92 | }; 93 | 94 | /* debug options */ 95 | enum { 96 | D_LSYM = 1, 97 | D_GSYM = 2, 98 | D_STAT = 4 99 | }; 100 | 101 | enum { 102 | SLASH, STAR, MOD, PLUS, MINUS, LSHIFT, RSHIFT, 103 | GREATER, GTEQ, LESS, LTEQ, EQUAL, NOTEQ, AMPER, 104 | CARET, PIPE, LOGAND, LOGOR, 105 | 106 | __ARGC, ARROW, ASAND, ASXOR, ASLSHIFT, ASMINUS, ASMOD, ASOR, 107 | ASPLUS, ASRSHIFT, ASDIV, ASMUL, ASSIGN, AUTO, BREAK, CASE, 108 | CHAR, COLON, COMMA, CONTINUE, DECR, DEFAULT, DO, DOT, 109 | ELLIPSIS, ELSE, ENUM, EXTERN, FOR, IDENT, IF, INCR, INT, 110 | INTLIT, LBRACE, LBRACK, LPAREN, NOT, QMARK, RBRACE, RBRACK, 111 | REGISTER, RETURN, RPAREN, SEMI, SIZEOF, STATIC, STRLIT, 112 | STRUCT, SWITCH, TILDE, UNION, VOID, WHILE, XEOF, XMARK, 113 | 114 | P_DEFINE, P_ELSE, P_ELSENOT, P_ENDIF, P_ERROR, P_IFDEF, 115 | P_IFNDEF, P_INCLUDE, P_LINE, P_PRAGMA, P_UNDEF 116 | }; 117 | -------------------------------------------------------------------------------- /src/error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Error handling 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | 10 | static void cleanup(void) { 11 | if (!O_testonly && NULL != Basefile) { 12 | remove(newfilename(Basefile, 's')); 13 | remove(newfilename(Basefile, 'o')); 14 | } 15 | } 16 | 17 | void error(char *s, char *a) { 18 | if (Syntoken) return; 19 | if (!Errors) cleanup(); 20 | fprintf(stderr, "error: %s: %d: ", File, Line); 21 | fprintf(stderr, s, a); 22 | fprintf(stderr, "\n"); 23 | if (++Errors > 10) { 24 | Errors = 0; 25 | fatal("too many errors"); 26 | } 27 | } 28 | 29 | void fatal(char *s) { 30 | error(s, NULL); 31 | error("fatal error, stop", NULL); 32 | exit(EXIT_FAILURE); 33 | } 34 | 35 | void cerror(char *s, int c) { 36 | char buf[32]; 37 | 38 | if (isprint(c)) 39 | sprintf(buf, "'%c' (\\x%x)", c, c); 40 | else 41 | sprintf(buf, "\\x%x", c); 42 | error(s, buf); 43 | } 44 | 45 | int synch(int syn) { 46 | int t; 47 | 48 | t = scan(); 49 | while (t != syn) { 50 | if (EOF == t) 51 | fatal("error recovery failed"); 52 | t = next(); 53 | } 54 | Syntoken = syn; 55 | return t; 56 | } 57 | -------------------------------------------------------------------------------- /src/gen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Code generator (emitter) 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | #include "cgen.h" 10 | 11 | int Acc = 0; 12 | 13 | void clear(void) { 14 | Acc = 0; 15 | } 16 | 17 | void load(void) { 18 | Acc = 1; 19 | } 20 | 21 | int label(void) { 22 | static int id = 1; 23 | 24 | return id++; 25 | } 26 | 27 | void spill(void) { 28 | if (Acc) genpush(); 29 | } 30 | 31 | void genraw(char *s) { 32 | if (NULL == Outfile) return; 33 | fprintf(Outfile, "%s", s); 34 | } 35 | 36 | void gen(char *s) { 37 | if (NULL == Outfile) return; 38 | fprintf(Outfile, "\t%s\n", s); 39 | } 40 | 41 | void ngen(char *s, char *inst, int n) { 42 | if (NULL == Outfile) return; 43 | fputc('\t', Outfile); 44 | fprintf(Outfile, s, inst, n); 45 | fputc('\n', Outfile); 46 | } 47 | 48 | void ngen2(char *s, char *inst, int n, int a) { 49 | if (NULL == Outfile) return; 50 | fputc('\t', Outfile); 51 | fprintf(Outfile, s, inst, n, a); 52 | fputc('\n', Outfile); 53 | } 54 | 55 | void lgen(char *s, char *inst, int n) { 56 | if (NULL == Outfile) return; 57 | fputc('\t', Outfile); 58 | fprintf(Outfile, s, inst, LPREFIX, n); 59 | fputc('\n', Outfile); 60 | } 61 | 62 | void lgen2(char *s, int v1, int v2) { 63 | if (NULL == Outfile) return; 64 | fputc('\t', Outfile); 65 | fprintf(Outfile, s, v1, LPREFIX, v2); 66 | fputc('\n', Outfile); 67 | } 68 | 69 | void sgen(char *s, char *inst, char *s2) { 70 | if (NULL == Outfile) return; 71 | fputc('\t', Outfile); 72 | fprintf(Outfile, s, inst, s2); 73 | fputc('\n', Outfile); 74 | } 75 | 76 | void sgen2(char *s, char *inst, int v, char *s2) { 77 | if (NULL == Outfile) return; 78 | fputc('\t', Outfile); 79 | fprintf(Outfile, s, inst, v, s2); 80 | fputc('\n', Outfile); 81 | } 82 | 83 | void genlab(int id) { 84 | if (NULL == Outfile) return; 85 | fprintf(Outfile, "%c%d:", LPREFIX, id); 86 | } 87 | 88 | char *labname(int id) { 89 | static char name[100]; 90 | 91 | sprintf(name, "%c%d", LPREFIX, id); 92 | return name; 93 | } 94 | 95 | char *gsym(char *s) { 96 | static char name[NAMELEN+2]; 97 | 98 | name[0] = PREFIX; 99 | name[1] = 0; 100 | strcat(name, s); 101 | return name; 102 | } 103 | 104 | /* administrativa */ 105 | 106 | void gendata(void) { 107 | if (Textseg) cgdata(); 108 | Textseg = 0; 109 | } 110 | 111 | void gentext(void) { 112 | if (!Textseg) cgtext(); 113 | Textseg = 1; 114 | } 115 | 116 | void genprelude(void) { 117 | Textseg = 0; 118 | gentext(); 119 | cgprelude(); 120 | } 121 | 122 | void genpostlude(void) { 123 | cgpostlude(); 124 | } 125 | 126 | void genname(char *name) { 127 | genraw(gsym(name)); 128 | genraw(":"); 129 | } 130 | 131 | void genpublic(char *name) { 132 | cgpublic(gsym(name)); 133 | } 134 | 135 | /* loading values */ 136 | 137 | void genaddr(int y) { 138 | gentext(); 139 | spill(); 140 | if (CAUTO == Stcls[y]) 141 | cgldla(Vals[y]); 142 | else if (CLSTATC == Stcls[y]) 143 | cgldsa(Vals[y]); 144 | else 145 | cgldga(gsym(Names[y])); 146 | load(); 147 | } 148 | 149 | void genldlab(int id) { 150 | gentext(); 151 | spill(); 152 | cgldlab(id); 153 | load(); 154 | } 155 | 156 | void genlit(int v) { 157 | gentext(); 158 | spill(); 159 | cglit(v); 160 | load(); 161 | } 162 | 163 | void genargc(void) { 164 | gentext(); 165 | spill(); 166 | cgargc(); 167 | load(); 168 | } 169 | 170 | /* binary ops */ 171 | 172 | void genand(void) { 173 | gentext(); 174 | cgpop2(); 175 | cgand(); 176 | } 177 | 178 | void genior(void) { 179 | gentext(); 180 | cgpop2(); 181 | cgior(); 182 | } 183 | 184 | void genxor(void) { 185 | gentext(); 186 | cgpop2(); 187 | cgxor(); 188 | } 189 | 190 | void genshl(int swap) { 191 | gentext(); 192 | cgpop2(); 193 | if (swap) cgswap(); 194 | cgshl(); 195 | } 196 | 197 | void genshr(int swap) { 198 | gentext(); 199 | cgpop2(); 200 | if (swap) cgswap(); 201 | cgshr(); 202 | } 203 | 204 | static int ptr(int p) { 205 | int sp; 206 | 207 | sp = p & STCMASK; 208 | return INTPTR == p || INTPP == p || 209 | CHARPTR == p || CHARPP == p || 210 | VOIDPTR == p || VOIDPP == p || 211 | STCPTR == sp || STCPP == sp || 212 | UNIPTR == sp || UNIPP == sp || 213 | FUNPTR == p; 214 | } 215 | 216 | static int needscale(int p) { 217 | int sp; 218 | 219 | sp = p & STCMASK; 220 | return INTPTR == p || INTPP == p || CHARPP == p || VOIDPP == p || 221 | STCPTR == sp || STCPP == sp || UNIPTR == sp || UNIPP == sp; 222 | } 223 | 224 | int genadd(int p1, int p2) { 225 | int rp = PINT; 226 | 227 | gentext(); 228 | if (ptr(p1)) { 229 | if (needscale(p1)) { 230 | if ( (p1 & STCMASK) == STCPTR || 231 | (p1 & STCMASK) == UNIPTR 232 | ) 233 | cgscaleby(objsize(deref(p1), TVARIABLE, 1)); 234 | else 235 | cgscale(); 236 | } 237 | cgpop2(); 238 | rp = p1; 239 | } 240 | else if (ptr(p2)) { 241 | cgpop2(); 242 | if (needscale(p2)) { 243 | if ( (p2 & STCMASK) == STCPTR || 244 | (p2 & STCMASK) == UNIPTR 245 | ) 246 | cgscale2by(objsize(deref(p2), TVARIABLE, 1)); 247 | else 248 | cgscale2(); 249 | } 250 | rp = p2; 251 | } 252 | else { 253 | cgpop2(); 254 | } 255 | cgadd(); 256 | return rp; 257 | } 258 | 259 | int gensub(int p1, int p2, int swap) { 260 | int rp = PINT; 261 | 262 | gentext(); 263 | cgpop2(); 264 | if (swap) cgswap(); 265 | if (!inttype(p1) && !inttype(p2) && p1 != p2) 266 | error("incompatible pointer types in binary '-'", NULL); 267 | if (ptr(p1) && !ptr(p2)) { 268 | if (needscale(p1)) { 269 | if ( (p1 & STCMASK) == STCPTR || 270 | (p1 & STCMASK) == UNIPTR 271 | ) 272 | cgscale2by(objsize(deref(p1), TVARIABLE, 1)); 273 | else 274 | cgscale2(); 275 | } 276 | rp = p1; 277 | } 278 | cgsub(); 279 | if (needscale(p1) && needscale(p2)) { 280 | if ( (p1 & STCMASK) == STCPTR || 281 | (p1 & STCMASK) == UNIPTR 282 | ) 283 | cgunscaleby(objsize(deref(p1), TVARIABLE, 1)); 284 | else 285 | cgunscale(); 286 | } 287 | return rp; 288 | } 289 | 290 | void genmul(void) { 291 | gentext(); 292 | cgpop2(); 293 | cgmul(); 294 | } 295 | 296 | void gendiv(int swap) { 297 | gentext(); 298 | cgpop2(); 299 | if (swap) cgswap(); 300 | cgdiv(); 301 | } 302 | 303 | void genmod(int swap) { 304 | gentext(); 305 | cgpop2(); 306 | if (swap) cgswap(); 307 | cgmod(); 308 | } 309 | 310 | static void binopchk(int op, int p1, int p2) { 311 | if (ASPLUS == op) 312 | op = PLUS; 313 | else if (ASMINUS == op) 314 | op = MINUS; 315 | if (inttype(p1) && inttype(p2)) 316 | return; 317 | else if (comptype(p1) || comptype(p2)) 318 | /* fail */; 319 | else if (PLUS == op && (inttype(p1) || inttype(p2))) 320 | return; 321 | else if (MINUS == op && (!inttype(p1) || inttype(p2))) 322 | return; 323 | else if ((EQUAL == op || NOTEQ == op || LESS == op || 324 | GREATER == op || LTEQ == op || GTEQ == op) 325 | && 326 | (p1 == p2 || 327 | VOIDPTR == p1 && !inttype(p2) || 328 | VOIDPTR == p2 && !inttype(p1)) 329 | ) 330 | return; 331 | error("invalid operands to binary operator", NULL); 332 | } 333 | 334 | int genbinop(int op, int p1, int p2) { 335 | binopchk(op, p1, p2); 336 | switch (op) { 337 | case PLUS: return genadd(p1, p2); 338 | case MINUS: return gensub(p1, p2, 1); 339 | case STAR: genmul(); break; 340 | case SLASH: gendiv(1); break; 341 | case MOD: genmod(1); break; 342 | case LSHIFT: genshl(1); break; 343 | case RSHIFT: genshr(1); break; 344 | case AMPER: genand(); break; 345 | case CARET: genxor(); break; 346 | case PIPE: genior(); break; 347 | case EQUAL: cgeq(); break; 348 | case NOTEQ: cgne(); break; 349 | case LESS: cglt(); break; 350 | case GREATER: cggt(); break; 351 | case LTEQ: cgle(); break; 352 | case GTEQ: cgge(); break; 353 | } 354 | return PINT; 355 | } 356 | 357 | /* unary ops */ 358 | 359 | void genbool(void) { 360 | gentext(); 361 | cgbool(); 362 | } 363 | 364 | void genind(int p) { 365 | gentext(); 366 | if (PCHAR == p) 367 | cgindb(); 368 | else 369 | cgindw(); 370 | } 371 | 372 | void genlognot(void) { 373 | gentext(); 374 | cglognot(); 375 | } 376 | 377 | void genneg(void) { 378 | gentext(); 379 | cgneg(); 380 | } 381 | 382 | void gennot(void) { 383 | gentext(); 384 | cgnot(); 385 | } 386 | 387 | void genscale(void) { 388 | gentext(); 389 | cgscale(); 390 | } 391 | 392 | void genscale2(void) { 393 | gentext(); 394 | cgscale2(); 395 | } 396 | 397 | /* jump/call/function ops */ 398 | 399 | void genjump(int dest) { 400 | gentext(); 401 | cgjump(dest); 402 | } 403 | 404 | void genbrfalse(int dest) { 405 | gentext(); 406 | cgbrfalse(dest); 407 | } 408 | 409 | void genbrtrue(int dest) { 410 | gentext(); 411 | cgbrtrue(dest); 412 | } 413 | 414 | void gencall(int y) { 415 | gentext(); 416 | cgcall(gsym(Names[y])); 417 | load(); 418 | } 419 | 420 | void gencalr(void) { 421 | gentext(); 422 | cgcalr(); 423 | load(); 424 | } 425 | 426 | void genentry(void) { 427 | gentext(); 428 | cgentry(); 429 | } 430 | 431 | void genexit(void) { 432 | gentext(); 433 | cgexit(); 434 | } 435 | 436 | void genpush(void) { 437 | gentext(); 438 | cgpush(); 439 | } 440 | 441 | void genpushlit(int n) { 442 | gentext(); 443 | spill(); 444 | cgpushlit(n); 445 | } 446 | 447 | void genstack(int n) { 448 | if (n) { 449 | gentext(); 450 | cgstack(n); 451 | } 452 | } 453 | 454 | void genlocinit(void) { 455 | int i; 456 | 457 | gentext(); 458 | for (i=0; i 7 | #include 8 | 9 | void abort(void) { 10 | raise(SIGABRT); 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/abs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * abs() 4 | */ 5 | 6 | #include 7 | 8 | int abs(int n) { 9 | return n<0? -n: n; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/atexit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * atexit() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int (*_exitfn)() = 0; 10 | 11 | int atexit(int (*fn)()) { 12 | if (_exitfn) { 13 | errno = ENOMEM; 14 | return -1; 15 | } 16 | _exitfn = fn; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/atoi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * atoi() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int atoi(char *s) { 10 | return strtol(s, NULL, 10); 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/bsearch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * bsearch() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | void *bsearch(void *key, void *array, int count, int size, int (*cmp)()) { 10 | void *p, *end; 11 | int r, r2, delta; 12 | 13 | end = array + size * count; 14 | delta = count/2; 15 | p = array + delta * size; 16 | while ((r = cmp(p, key)) != 0 && delta) { 17 | if (r < 0) 18 | p += delta * size; 19 | else 20 | p -= delta * size; 21 | delta /= 2; 22 | if (p < array) 23 | p = array; 24 | else if (p >= end) 25 | p = end - size; 26 | } 27 | if (0 == r) return p; 28 | r2 = r; 29 | while (r2<0 == r<0 && p >= array && p < end) { 30 | if (0 == r) 31 | return p; 32 | else if (r < 0) 33 | p += size; 34 | else 35 | p -= size; 36 | r = cmp(p, key); 37 | } 38 | return r? NULL: p; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/calloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * calloc() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void *calloc(int count, int size) { 11 | void *p; 12 | 13 | if ((p = malloc(count * size)) == NULL) 14 | return NULL; 15 | memset(p, 0, count * size); 16 | return p; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/clearerr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * clearerr() 4 | */ 5 | 6 | #include 7 | 8 | void clearerr(FILE *f) { 9 | f->iom &= ~_FERROR; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/crt0.s: -------------------------------------------------------------------------------- 1 | ../targets/crt0-freebsd-386.s -------------------------------------------------------------------------------- /src/lib/ctime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * ctime() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #define S_MIN 60 10 | #define S_HOUR (60*S_MIN) 11 | #define S_DAY (24*S_HOUR) 12 | #define S_YEAR (365*S_DAY) 13 | 14 | static int ndays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 15 | 16 | char *ctime(int t) { 17 | static char buf[100]; 18 | int m, t2, t3; 19 | int wday, year, yday, mon, mday, hour, min, sec; 20 | char *days, *months; 21 | 22 | days = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat"; 23 | months = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec"; 24 | wday = (t / S_DAY + 4) % 7; 25 | year = t / S_YEAR; 26 | t -= year * S_YEAR; 27 | t -= (year+2)/4 * S_DAY; 28 | year += 1970; 29 | yday = t / S_DAY; 30 | m = 1; 31 | t3 = t2 = 0; 32 | while (t2 <= t) { 33 | t3 = t2; 34 | t2 += ndays[m++-1] * S_DAY; 35 | } 36 | mon = m-1; 37 | t -= t3; 38 | mday = t / S_DAY; 39 | t -= (mday * S_DAY); 40 | mday++; 41 | hour = t / S_HOUR; 42 | t -= hour * S_HOUR; 43 | min = t / S_MIN; 44 | t -= min * S_MIN; 45 | sec = t; 46 | sprintf(buf, "%s %s %2d %2d:%02d:%02d %04d\n", 47 | days + wday*4, 48 | months + (mon-1)*4, 49 | mday+1, 50 | hour, min, sec, 51 | year); 52 | return buf; 53 | } 54 | -------------------------------------------------------------------------------- /src/lib/ctype.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * ctype functions 4 | */ 5 | 6 | #include 7 | 8 | enum { 9 | U = 0x01, /* upper case */ 10 | L = 0x02, /* lower case */ 11 | C = 0x04, /* control */ 12 | D = 0x08, /* decimal */ 13 | X = 0x10, /* hex letter */ 14 | P = 0x20, /* punctuation */ 15 | S = 0x40, /* space */ 16 | G = 0x80 /* graph */ 17 | }; 18 | 19 | static char ctypes[] = { 20 | C, C, C, C, C, C, C, C, 21 | C, C|S, C|S, C|S, C|S, C|S, C, C, 22 | C, C, C, C, C, C, C, C, 23 | C, C, C, C, C, C, C, C, 24 | S, G|P, G|P, G|P, G|P, G|P, G|P, G|P, 25 | G|P, G|P, G|P, G|P, G|P, G|P, G|P, G|P, 26 | G|D, G|D, G|D, G|D, G|D, G|D, G|D, G|D, 27 | G|D, G|D, G|P, G|P, G|P, G|P, G|P, G|P, 28 | G|P, G|U|X, G|U|X, G|U|X, G|U|X, G|U|X, G|U|X, G|U, 29 | G|U, G|U, G|U, G|U, G|U, G|U, G|U, G|U, 30 | G|U, G|U, G|U, G|U, G|U, G|U, G|U, G|U, 31 | G|U, G|U, G|U, G|P, G|P, G|P, G|P, G|P, 32 | G|P, G|L|X, G|L|X, G|L|X, G|L|X, G|L|X, G|L|X, G|L, 33 | G|L, G|L, G|L, G|L, G|L, G|L, G|L, G|L, 34 | G|L, G|L, G|L, G|L, G|L, G|L, G|L, G|L, 35 | G|L, G|L, G|L, G|P, G|P, G|P, G|P, C, 36 | }; 37 | 38 | int isalnum(int c) { return 0 != (ctypes[c & 127] & (D|U|L)); } 39 | int isalpha(int c) { return 0 != (ctypes[c & 127] & (U|L)); } 40 | int iscntrl(int c) { return 0 != (ctypes[c & 127] & C); } 41 | int isdigit(int c) { return 0 != (ctypes[c & 127] & D); } 42 | int isgraph(int c) { return 0 != (ctypes[c & 127] & G); } 43 | int islower(int c) { return 0 != (ctypes[c & 127] & L); } 44 | int isprint(int c) { return c == ' ' || isgraph(c); } 45 | int ispunct(int c) { return 0 != (ctypes[c & 127] & P); } 46 | int isspace(int c) { return 0 != (ctypes[c & 127] & S); } 47 | int isupper(int c) { return 0 != (ctypes[c & 127] & U); } 48 | int isxdigit(int c){ return 0 != (ctypes[c & 127] & (D|X)); } 49 | 50 | int tolower(int c) { 51 | return isupper(c)? c - 'A' + 'a': c; 52 | } 53 | 54 | int toupper(int c) { 55 | return islower(c)? c - 'a' + 'A': c; 56 | } 57 | -------------------------------------------------------------------------------- /src/lib/difftime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * difftime() 4 | */ 5 | 6 | #include 7 | 8 | int difftime(int t1, int t0) { 9 | return t1 - t0; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/exit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * exit() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern int (*_exitfn)(); 11 | extern FILE *_files[]; 12 | 13 | void exit(int rc) { 14 | int i; 15 | 16 | if (_exitfn) _exitfn(); 17 | for (i = 0; i < FOPEN_MAX; i++) 18 | fclose(_files[i]); 19 | _exit(rc); 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/fclose.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fclose() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern FILE *_files[]; 11 | 12 | int fclose(FILE *f) { 13 | int i; 14 | 15 | if (NULL == f) return EOF; 16 | if (_FCLOSED == f->iom) return EOF; 17 | if (_FWRITE == f->last && fflush(f)) 18 | return EOF; 19 | _close(f->fd); 20 | if (f->buf != NULL && (f->mode & _IOUSR) == 0) 21 | free(f->buf); 22 | for (i=0; i 7 | #include 8 | #include 9 | #include 10 | 11 | int _openmode(char *mode) { 12 | int n; 13 | 14 | if (strchr(mode, '+')) return _FREAD | _FWRITE; 15 | else if ('r' == *mode) return _FREAD; 16 | else if ('w' == *mode) return _FWRITE; 17 | else if ('a' == *mode) return _FWRITE; 18 | return _FCLOSED; 19 | } 20 | 21 | extern FILE *_files[]; 22 | 23 | FILE *fdopen(int fd, char *mode) { 24 | int i; 25 | FILE *f; 26 | 27 | for (i = 0; i < FOPEN_MAX; i++) 28 | if (NULL == _files[i]) 29 | break; 30 | if (i >= FOPEN_MAX) { 31 | errno = ENFILE; 32 | return NULL; 33 | } 34 | if ((f = malloc(sizeof(FILE))) == NULL) 35 | return NULL; 36 | _files[i] = f; 37 | f->buf = NULL; 38 | f->fd = fd; 39 | f->iom = _openmode(mode); 40 | f->last = _FCLOSED; 41 | f->mode = _IOFBF; 42 | f->ptr = 0; 43 | f->end = 0; 44 | f->size = 0; 45 | f->ch = EOF; 46 | if (_FCLOSED == f->iom) { 47 | fclose(f); 48 | errno = EINVAL; 49 | return NULL; 50 | } 51 | if (setvbuf(f, NULL, _IOFBF, 0) == EOF) { 52 | fclose(f); 53 | return NULL; 54 | } 55 | return f; 56 | } 57 | -------------------------------------------------------------------------------- /src/lib/feof.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * feof() 4 | */ 5 | 6 | #include 7 | 8 | int feof(FILE *f) { 9 | return (f->iom & _FERROR) != 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/ferror.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * ferror() 4 | */ 5 | 6 | #include 7 | 8 | int ferror(FILE *f) { 9 | return (f->iom & _FERROR) != 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/fflush.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fflush() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | static int _fflush(FILE *f) { 11 | int p, e; 12 | 13 | if (f->iom & _FERROR) return 0; 14 | f->ch = EOF; 15 | if (f->last != _FWRITE) { 16 | f->ptr = f->end = 0; 17 | return 0; 18 | } 19 | if ((f->mode & _IOACC) == _IONBF) return 0; 20 | p = f->ptr; 21 | e = f->end; 22 | f->ptr = f->end = 0; 23 | if (_write(f->fd, f->buf + p, e-p) == e-p) 24 | return 0; 25 | errno = EIO; 26 | return -1; 27 | } 28 | 29 | extern FILE *_files[]; 30 | 31 | int fflush(FILE *f) { 32 | int i, rc = 0; 33 | 34 | if (f != NULL) return _fflush(f); 35 | for (i = 0; i < FOPEN_MAX; i++) 36 | if (!_fflush(_files[i])) rc = -1; 37 | return rc; 38 | } 39 | -------------------------------------------------------------------------------- /src/lib/fgetc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fgetc() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int _refill(FILE *f); 11 | 12 | int fgetc(FILE *f) { 13 | char c, b[1]; 14 | 15 | if ((f->iom & _FREAD) == 0) 16 | return EOF; 17 | if (f->iom & _FERROR) 18 | return EOF; 19 | f->last = _FREAD; 20 | if (f->ch != EOF) { 21 | c = f->ch; 22 | f->ch = EOF; 23 | return c; 24 | } 25 | if ((f->mode & _IOACC) == _IONBF) 26 | if (_read(f->fd, b, 1) == 1) 27 | return *b; 28 | else { 29 | errno = EIO; 30 | return EOF; 31 | } 32 | if (f->ptr >= f->end) 33 | if (!_refill(f)) 34 | return EOF; 35 | return f->buf[f->ptr++]; 36 | } 37 | -------------------------------------------------------------------------------- /src/lib/fgetpos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fgetpos() 4 | */ 5 | 6 | #include 7 | 8 | int fgetpos(FILE *f, int *pos) { 9 | int n; 10 | 11 | if ((n = ftell(f)) < 0) return -1; 12 | *pos = n; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/fgets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fgets() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int _refill(FILE *f); 12 | 13 | static char *fgets_raw(char *s, int len, FILE *f) { 14 | char *p; 15 | 16 | p = s; 17 | while (len-- > 1) { 18 | if (_read(f->fd, p, 1) != 1) { 19 | errno = EIO; 20 | return NULL; 21 | } 22 | if ('\n' == *p++) break; 23 | } 24 | *p = 0; 25 | return s; 26 | } 27 | 28 | char *fgets(char *s, int len, FILE *f) { 29 | int k; 30 | char *p, *buf, *pn; 31 | 32 | if ((f->iom & _FREAD) == 0) return NULL; 33 | if (f->iom & _FERROR) return NULL; 34 | f->last = _FREAD; 35 | p = s; 36 | if (f->ch != EOF) { 37 | *p++ = f->ch; 38 | f->ch = EOF; 39 | len--; 40 | } 41 | if ((f->mode & _IOACC) == _IONBF) 42 | return fgets_raw(s, len, f); 43 | buf = f->buf; 44 | pn = NULL; 45 | while (len > 1 && pn == NULL) { 46 | if (!_refill(f)) 47 | return NULL; 48 | if ((pn = memchr(buf + f->ptr, '\n', f->end - f->ptr)) != NULL) 49 | k = pn - buf - f->ptr + 1; 50 | else 51 | k = f->end - f->ptr; 52 | if (len-1 < k) k = len-1; 53 | memcpy(p, buf + f->ptr, k); 54 | f->ptr += k; 55 | p += k; 56 | len -= k; 57 | } 58 | *p = 0; 59 | return s; 60 | } 61 | -------------------------------------------------------------------------------- /src/lib/fileno.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fileno() 4 | */ 5 | 6 | #include 7 | 8 | int fileno(FILE *f) { 9 | return f->fd; 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/fopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * fopen() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int _openfd(char *path, char *mode) { 12 | int i, plus, fd = -1; 13 | 14 | plus = strchr(mode, '+')? 1: 0; 15 | if ('w' == *mode) { 16 | fd = _creat(path, 0666); 17 | if (fd < 0) errno = EACCESS; 18 | if (fd >= 0 && plus) { 19 | _close(fd); 20 | fd = _open(path, 2); 21 | } 22 | } 23 | else if ('r' == *mode) { 24 | fd = _open(path, plus? 2: 0); 25 | if (fd < 0) errno = ENOENT; 26 | } 27 | else if ('a' == *mode) { 28 | fd = _open(path, plus? 2: 1); 29 | if (fd < 0) { 30 | fd = _creat(path, 0644); 31 | if (fd < 0) errno = EACCESS; 32 | _close(fd); 33 | fd = _open(path, plus? 2: 1); 34 | } 35 | _lseek(fd, 0, SEEK_END); 36 | } 37 | else { 38 | errno = EINVAL; 39 | } 40 | return fd; 41 | } 42 | 43 | FILE *fopen(char *path, char *mode) { 44 | int fd; 45 | FILE *f; 46 | 47 | fd = _openfd(path, mode); 48 | if (fd < 0) return NULL; 49 | return fdopen(fd, mode); 50 | } 51 | -------------------------------------------------------------------------------- /src/lib/fprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fprintf() 4 | */ 5 | 6 | #include 7 | 8 | extern int _vformat(int mode, int max, void *dest, char *fmt, void **varg); 9 | 10 | int fprintf(void *last, ...) { 11 | void **args; 12 | FILE *f; 13 | char *fmt, *p; 14 | 15 | args = &last; 16 | args += __argc; 17 | f = *--args; 18 | fmt = *--args; 19 | return _vformat(1, 0, f, fmt, --args); 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/fputc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * fputc() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int _fsync(FILE *f); 11 | 12 | int fputc(int c, FILE *f) { 13 | char b[1]; 14 | 15 | if ((f->iom & _FWRITE) == 0) 16 | return EOF; 17 | if (f->iom & _FERROR) 18 | return EOF; 19 | f->last = _FWRITE; 20 | if ((f->mode & _IOACC) == _IONBF) { 21 | *b = c; 22 | if (_write(f->fd, b, 1) == 1) 23 | return c; 24 | else { 25 | errno = EIO; 26 | return EOF; 27 | } 28 | } 29 | if (f->end >= f->size) 30 | if (!_fsync(f)) 31 | return EOF; 32 | f->buf[f->end++] = c; 33 | if ((f->mode & _IOACC) == _IOLBF) 34 | if (!_fsync(f)) 35 | return EOF; 36 | return c; 37 | } 38 | -------------------------------------------------------------------------------- /src/lib/fputs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fputs() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int _fwrite(char *p, int len, FILE *f); 10 | 11 | int fputs(char *s, FILE *f) { 12 | int k; 13 | 14 | k = strlen(s); 15 | if (_fwrite(s, k, f) != k) 16 | return EOF; 17 | return k; 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/fread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fread() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int _refill(FILE *f) { 12 | int k; 13 | 14 | if (f->ptr >= f->end) { 15 | f->ptr = 0; 16 | k = _read(f->fd, f->buf, f->size); 17 | if (k <= 0) { 18 | f->end = 0; 19 | f->iom |= _FERROR; 20 | if (k < 0) errno = EIO; 21 | return 0; 22 | } 23 | f->end = k; 24 | } 25 | return 1; 26 | } 27 | 28 | int _fread(void *p, int size, FILE *f) { 29 | int k, len, end, ptr, total; 30 | 31 | if ((f->iom & _FREAD) == 0) return 0; 32 | if (f->iom & _FERROR) return 0; 33 | f->last = _FREAD; 34 | total = size; 35 | if (f->ch != EOF) { 36 | *(char *)p++ = f->ch; 37 | f->ch = EOF; 38 | size--; 39 | } 40 | if ((f->mode & _IOACC) == _IONBF) { 41 | if ((total = _read(f->fd, p, size)) != size) { 42 | f->iom |= _FERROR; 43 | errno = EIO; 44 | } 45 | return total; 46 | } 47 | if (!_refill(f)) return 0; 48 | end = f->end; 49 | ptr = f->ptr; 50 | k = end - ptr; 51 | if (size < k) k = size; 52 | memcpy(p, f->buf + ptr, k); 53 | f->ptr += k; 54 | p += k; 55 | size -= k; 56 | len = f->size; 57 | while (size > len) { 58 | if (_read(f->fd, p, len) != len) { 59 | f->iom |= _FERROR; 60 | errno = EIO; 61 | return total-size; 62 | } 63 | p += len; 64 | size -= len; 65 | } 66 | if (size != 0) { 67 | if (!_refill(f)) return total-size; 68 | memcpy(p, f->buf, size); 69 | f->ptr = size; 70 | } 71 | return total; 72 | } 73 | 74 | int fread(void *p, int size, int count, FILE *f) { 75 | int k; 76 | 77 | if ((k = _fread(p, size * count, f)) < 0) 78 | return -1; 79 | return k / size; 80 | } 81 | -------------------------------------------------------------------------------- /src/lib/free.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * free() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern int *_arena, _asize; 11 | 12 | void free(void *p) { 13 | int *pi; 14 | 15 | if (NULL == p) return; 16 | pi = p; 17 | if (pi < _arena || _arena + _asize < pi || pi[-1] >= 0) { 18 | _write(2, "bad pointer in free()\n", 22); 19 | abort(); 20 | } 21 | --pi; 22 | *pi = -*pi; 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/freopen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * freopen() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int _openfd(char *path, char *mode); 11 | int _openmode(char *mode); 12 | 13 | FILE *freopen(char *path, char *mode, FILE *f) { 14 | int fd, om; 15 | 16 | if ((om = _openmode(mode)) == _FCLOSED) { 17 | errno = EINVAL; 18 | return NULL; 19 | } 20 | if (f->iom & (_FREAD|_FWRITE) == _FREAD|_FWRITE) 21 | ; 22 | else if (f->iom & _FREAD && *mode != 'r') { 23 | fclose(f); 24 | return NULL; 25 | } 26 | else if (f->iom & _FWRITE && *mode != 'w' && *mode != 'a') { 27 | fclose(f); 28 | return NULL; 29 | } 30 | if (path) { 31 | fd = _openfd(path, mode); 32 | if (fd < 0) { 33 | fclose(f); 34 | return NULL; 35 | } 36 | _close(f->fd); 37 | f->fd = fd; 38 | } 39 | f->iom = om; 40 | f->last = _FCLOSED; 41 | f->ptr = 0; 42 | f->end = 0; 43 | f->ch = EOF; 44 | return f; 45 | } 46 | -------------------------------------------------------------------------------- /src/lib/fscanf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fscanf() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | extern int _vscan(int mode, void *src, char *fmt, void **varg); 10 | 11 | int fscanf(void *last, ...) { 12 | void **args; 13 | FILE *f; 14 | char *fmt, *p; 15 | 16 | args = &last; 17 | args += __argc; 18 | f = *--args; 19 | fmt = *--args; 20 | return _vscan(1, f, fmt, --args); 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/fseek.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fseek() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int fseek(FILE *f, int pos, int how) { 11 | int adjust = 0; 12 | char b[101]; 13 | 14 | if (how != SEEK_SET && how != SEEK_CUR && how != SEEK_END) { 15 | errno = EINVAL; 16 | return -1; 17 | } 18 | if (SEEK_CUR == how && (f->mode & _IOACC) != _IONBF) { 19 | adjust = f->end - f->ptr; 20 | if (_FREAD == f->last) { 21 | adjust = -adjust; 22 | if (f->ch != EOF) adjust--; 23 | } 24 | } 25 | if (fflush(f) < 0) return -1; 26 | f->ch = EOF; 27 | if ((pos = _lseek(f->fd, pos + adjust, how)) < 0) { 28 | errno = EIO; 29 | return -1; 30 | } 31 | return pos; 32 | } 33 | -------------------------------------------------------------------------------- /src/lib/fsetpos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * fsetpos() 4 | */ 5 | 6 | #include 7 | 8 | int fsetpos(FILE *f, int *pos) { 9 | return fseek(f, *pos, SEEK_SET); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/ftell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * ftell() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int ftell(FILE *f) { 11 | int adjust = 0, pos; 12 | 13 | if ((f->mode & _IOACC) != _IONBF) { 14 | adjust = f->end - f->ptr; 15 | if (_FREAD == f->last) { 16 | adjust = -adjust; 17 | if (f->ch != EOF) adjust--; 18 | } 19 | } 20 | if ((pos = _lseek(f->fd, 0, SEEK_CUR)) < 0) { 21 | errno = EIO; 22 | return -1; 23 | } 24 | return pos + adjust; 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/fwrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * fwrite() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int _fsync(FILE *f) { 12 | int ptr, end, k, pn, p; 13 | char *buf; 14 | 15 | if (f->end >= f->size) { 16 | ptr = f->ptr; 17 | end = f->end; 18 | f->end = f->ptr = 0; 19 | k = _write(f->fd, f->buf + ptr, end-ptr); 20 | if (k != end-ptr) { 21 | f->iom |= _FERROR; 22 | errno = EIO; 23 | return 0; 24 | } 25 | } 26 | else if ((f->mode & _IOACC) == _IOLBF) { 27 | ptr = f->ptr; 28 | end = f->end; 29 | buf = f->buf; 30 | pn = -1; 31 | for (p = ptr; p < end; p++) 32 | if ('\n' == buf[p]) pn = p+1; 33 | if (pn >= 0) { 34 | k = _write(f->fd, f->buf + ptr, pn-ptr); 35 | f->ptr = pn; 36 | if (k != pn - ptr) { 37 | f->iom |= _FERROR; 38 | errno = EIO; 39 | return 0; 40 | } 41 | } 42 | } 43 | return 1; 44 | } 45 | 46 | int _fwrite(void *p, int size, FILE *f) { 47 | int k, len, total; 48 | 49 | if ((f->iom & _FWRITE) == 0) return 0; 50 | if (f->iom & _FERROR) return 0; 51 | f->last = _FWRITE; 52 | if ((f->mode & _IOACC) == _IONBF) { 53 | if ((k = _write(f->fd, p, size)) != size) { 54 | f->iom |= _FERROR; 55 | errno = EIO; 56 | } 57 | return k; 58 | } 59 | total = size; 60 | len = f->size; 61 | k = len - f->end; 62 | if (size < k) k = size; 63 | memcpy(f->buf + f->end, p, k); 64 | f->end += k; 65 | size -= k; 66 | p += k; 67 | if (!_fsync(f)) return 0; 68 | while (size > len) { 69 | if ((k = _write(f->fd, p, len)) != len) { 70 | f->iom |= _FERROR; 71 | errno = EIO; 72 | return total - size; 73 | } 74 | p += len; 75 | size -= len; 76 | } 77 | if (size != 0) { 78 | memcpy(f->buf, p, size); 79 | f->end = size; 80 | } 81 | if ((f->mode & _IOACC) == _IOLBF && !_fsync(f)) 82 | return total-size; 83 | return total; 84 | } 85 | 86 | int fwrite(void *p, int size, int count, FILE *f) { 87 | int k; 88 | 89 | if ((k = _fwrite(p, size * count, f)) < 0) 90 | return -1; 91 | return k / size; 92 | } 93 | -------------------------------------------------------------------------------- /src/lib/getchar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * getchar() 4 | */ 5 | 6 | #include 7 | 8 | int getchar(void) { 9 | return fgetc(stdin); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/getenv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * getenv() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | char *getenv(char *name) { 11 | char **p; 12 | int k; 13 | 14 | k = strlen(name); 15 | for (p = environ; *p; p++) { 16 | if ( strlen(*p) > k && 17 | '=' == (*p)[k] && 18 | !strncmp(*p, name, k) 19 | ) { 20 | return (*p) + k+1; 21 | } 22 | } 23 | return NULL; 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * C runtime initialization 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int errno = EOK; 10 | 11 | FILE *_files[FOPEN_MAX]; 12 | 13 | FILE *stdin, *stdout, *stderr; 14 | 15 | void _init(void) { 16 | int i; 17 | 18 | for (i=0; imode = _IOLBF; 24 | stderr->mode = _IOLBF; 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/kprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * kprintf() 4 | */ 5 | 6 | #include 7 | 8 | extern int _vformat(int mode, int max, void *dest, char *fmt, void **varg); 9 | 10 | int kprintf(void *last, ...) { 11 | void **args; 12 | int fd; 13 | char *fmt, *p; 14 | 15 | args = &last; 16 | args += __argc; 17 | fd = (int) *--args; 18 | fmt = *--args; 19 | return _vformat(-1, 0, (void *) fd, fmt, --args); 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/malloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * malloc() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define THRESHOLD 128 12 | 13 | int *_arena = 0; 14 | int _asize; 15 | static int *freep; 16 | 17 | static void defrag(void) { 18 | int *p, *q, *end; 19 | 20 | end = _arena + _asize; 21 | for (p = _arena; p < end; p += abs(*p)) { 22 | if (*p > 0) { 23 | for (q = p; q < end && *q > 0; q += *q) 24 | ; 25 | *p = q - p; 26 | } 27 | } 28 | } 29 | 30 | void *malloc(int size) { 31 | int *p, *end; 32 | int k, n, tries; 33 | 34 | size = (size + sizeof(int) - 1) / sizeof(int); 35 | if (NULL == _arena) { 36 | if (size >= THRESHOLD) 37 | _asize = size + 1; 38 | else 39 | _asize = size * 50; 40 | _arena = _sbrk(_asize * sizeof(int)); 41 | if (_arena == (int *)-1) { 42 | errno = ENOMEM; 43 | return NULL; 44 | } 45 | _arena[0] = _asize; 46 | freep = _arena; 47 | } 48 | for (tries = 0; tries < 3; tries++) { 49 | end = _arena + _asize; 50 | p = freep; 51 | do { 52 | if (*p > size) { 53 | if (size + 1 == *p) { 54 | *p = -*p; 55 | } 56 | else { 57 | k = *p; 58 | *p = -(size+1); 59 | p[size+1] = k - size - 1; 60 | } 61 | freep = p; 62 | return p+1; 63 | } 64 | p += abs(*p); 65 | if (p == end) p = _arena; 66 | if (p < _arena || p >= end || 0 == *p) { 67 | _write(2, "malloc(): corrupt arena\n", 24); 68 | abort(); 69 | } 70 | } while (p != freep); 71 | if (0 == tries) 72 | defrag(); 73 | else { 74 | if (size >= THRESHOLD) 75 | n = size + 1; 76 | else 77 | n = size * 50; 78 | if (_sbrk(n * sizeof(int)) == (void *)-1) { 79 | errno = ENOMEM; 80 | return NULL; 81 | } 82 | k = _asize; 83 | _asize += n; 84 | *end = _asize - k; 85 | } 86 | } 87 | errno = ENOMEM; 88 | return NULL; 89 | } 90 | -------------------------------------------------------------------------------- /src/lib/memchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * memchr() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | void *memchr(void *p, int c, int n) { 10 | while (n--) { 11 | if (*(char *)p == c) return p; 12 | p++; 13 | } 14 | return NULL; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/memcmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * memcmp() 4 | */ 5 | 6 | #include 7 | 8 | int memcmp(void *p1, void *p2, int n) { 9 | while (n-- && *(char *)p1++ == *(char *)p2++) 10 | ; 11 | return *(char *)--p1 - *(char *)--p2; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/memcpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * memcpy() 4 | */ 5 | 6 | #include 7 | 8 | void *memcpy(void *d, void *s, int n) { 9 | char *p; 10 | 11 | p = d; 12 | while (n--) *p++ = *(char *)s++; 13 | return d; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/memmove.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * memmove() 4 | */ 5 | 6 | #include 7 | 8 | void *memmove(void *d, void *s, int n) { 9 | char *p; 10 | 11 | if (d < s) return memcpy(d, s, n); 12 | p = d + n; 13 | s += n; 14 | while (n--) *--p = *(char *)--s; 15 | return d; 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/memset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * memset() 4 | */ 5 | 6 | #include 7 | 8 | void *memset(void *p, int c, int n) { 9 | char *q; 10 | 11 | q = p; 12 | while (n--) *(char *)p++ = c; 13 | return q; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/perror.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * perror() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void perror(char *msg) { 11 | fprintf(stderr, "%s: %s\n", msg, strerror(errno)); 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/printf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * printf() 4 | */ 5 | 6 | #include 7 | 8 | extern int _vformat(int mode, int max, void *dest, char *fmt, void **varg); 9 | 10 | int printf(void *last, ...) { 11 | void **args; 12 | char *fmt, *p; 13 | 14 | args = &last; 15 | args += __argc; 16 | fmt = *--args; 17 | return _vformat(1, 0, stdout, fmt, --args); 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/putchar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * putchar() 4 | */ 5 | 6 | #include 7 | 8 | int putchar(int c) { 9 | return fputc(c, stdout); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/puts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * puts() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int _fwrite(char *p, int len, FILE *f); 10 | 11 | int puts(char *s) { 12 | int k; 13 | 14 | k = strlen(s); 15 | if (_fwrite(s, k, stdout) != k) 16 | return EOF; 17 | return putchar('\n'); 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/qsort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * qsort() 4 | */ 5 | 6 | #include 7 | 8 | /* In fact we are using the shellsort algorithm (TCPL, ed2, pg62) */ 9 | 10 | void qsort(void *list, int count, int size, int (*cmp)()) { 11 | int gap, i, j, k, tmp; 12 | char *p, *x1, *x2; 13 | 14 | p = list; 15 | for (gap = count/2; gap > 0; gap /= 2) { 16 | for (i = gap; i < count; i++) { 17 | for (j = i-gap; j >= 0; j -= gap) { 18 | if (cmp(p+j*size, p+(j+gap)*size) <= 0) 19 | break; 20 | x1 = p + j * size; 21 | x2 = p + (j+gap) * size; 22 | for (k = 0; k < size; k++) { 23 | tmp = x1[k]; 24 | x1[k] = x2[k]; 25 | x2[k] = tmp; 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/rand.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * rand() and srand() 4 | */ 5 | 6 | #include 7 | 8 | static int _seed = 57005; 9 | 10 | int rand(void) { 11 | int rot; 12 | 13 | rot = ((_seed>>0) ^ (_seed>>2) ^ (_seed>>3) ^ (_seed>>5) ) & 1; 14 | _seed = (_seed>>1) | (rot<<15); 15 | return _seed; 16 | } 17 | 18 | void srand(int n) { 19 | _seed = n & 0xffff; 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/realloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * realloc() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void *realloc(void *p, int size) { 11 | void *new; 12 | int *pi, k; 13 | 14 | if ((new = malloc(size)) == NULL) 15 | return NULL; 16 | if (p) { 17 | pi = p; 18 | k = pi[-1] < size? pi[-1]: size; 19 | memcpy(new, p, k); 20 | free(p); 21 | } 22 | return new; 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/remove.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * remove() 4 | */ 5 | 6 | #include 7 | 8 | int remove(char *path) { 9 | return _unlink(path); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/rename.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * rename() 4 | */ 5 | 6 | #include 7 | 8 | int rename(char *old, char *new) { 9 | return _rename(old, new); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/rewind.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * rewind() 4 | */ 5 | 6 | #include 7 | 8 | void rewind(FILE *f) { 9 | fseek(f, 0, SEEK_SET); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/scanf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * scanf() 4 | */ 5 | 6 | #include 7 | 8 | extern int _vscan(int mode, void *dest, char *fmt, void **varg); 9 | 10 | int scanf(void *last, ...) { 11 | void **args; 12 | char *fmt, *p; 13 | 14 | args = &last; 15 | args += __argc; 16 | fmt = *--args; 17 | return _vscan(1, stdin, fmt, --args); 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/setbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * setbuf() 4 | */ 5 | 6 | #include 7 | 8 | void setbuf(FILE *f, char *buf) { 9 | setvbuf(f, buf, buf? _IOFBF: _IONBF, BUFSIZ); 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/setvbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * setvbuf() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | static void freebuf(FILE *f) { 10 | if (f->buf != NULL && (f->mode & _IOUSR) == 0) 11 | free(f->buf); 12 | } 13 | 14 | int setvbuf(FILE *f, char *buf, int mode, int size) { 15 | if (0 == size) size = BUFSIZ; 16 | if (buf) { 17 | freebuf(f); 18 | f->mode = mode | _IOUSR; 19 | } 20 | else { 21 | if (_IONBF != mode) 22 | if ((buf = malloc(size)) == NULL) 23 | return EOF; 24 | freebuf(f); 25 | f->mode = mode; 26 | } 27 | f->buf = buf; 28 | f->size = size; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/sprintf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * sprintf() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | extern int _vformat(int mode, int max, void *dest, char *fmt, void **varg); 10 | 11 | int sprintf(void *last, ...) { 12 | void **args; 13 | char *buf; 14 | char *fmt, *p; 15 | 16 | args = &last; 17 | args += __argc; 18 | buf = *--args; 19 | fmt = *--args; 20 | return _vformat(0, 0, buf, fmt, --args); 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/sscanf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * sscanf() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | extern int _vscan(int mode, void *src, char *fmt, void **varg); 10 | 11 | int sscanf(void *last, ...) { 12 | void **args; 13 | char *buf; 14 | char *fmt, *p; 15 | 16 | args = &last; 17 | args += __argc; 18 | buf = *--args; 19 | fmt = *--args; 20 | return _vscan(0, buf, fmt, --args); 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/strcat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strcat() 4 | */ 5 | 6 | #include 7 | 8 | char *strcat(char *d, char *a) { 9 | char *p; 10 | 11 | for (p = d; *p; p++) 12 | ; 13 | while (*a) *p++ = *a++; 14 | *p = 0; 15 | return d; 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/strchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * strchr() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *strchr(char *s, int c) { 10 | while (*s && *s != c) 11 | s++; 12 | return *s || !c? s: NULL; 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/strcmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strcmp() 4 | */ 5 | 6 | #include 7 | 8 | int strcmp(char *s1, char *s2) { 9 | while (*s1 && *s1 == *s2) 10 | s1++, s2++; 11 | return *s1 - *s2; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/strcpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strcpy() 4 | */ 5 | 6 | #include 7 | 8 | char *strcpy(char *d, char *s) { 9 | char *p; 10 | 11 | p = d; 12 | while (*s) *p++ = *s++; 13 | *p = 0; 14 | return d; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/strcspn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strcspn() 4 | */ 5 | 6 | #include 7 | 8 | int strcspn(char *s, char *set) { 9 | int i = 0; 10 | 11 | while (*s && !strchr(set, *s)) 12 | s++, i++; 13 | return i; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/strdup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strdup() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | char *strdup(char *s) { 11 | char *p; 12 | 13 | if ((p = malloc(strlen(s)+1)) == NULL) 14 | return NULL; 15 | strcpy(p, s); 16 | return p; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/strerror.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strerror() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *strerror(int err) { 10 | switch (err) { 11 | case EOK: return "no error"; 12 | case ENOENT: return "no such file"; 13 | case EACCESS: return "access denied"; 14 | case EIO: return "input/output error"; 15 | case ENFILE: return "too many open files"; 16 | case EINVAL: return "invalid argument"; 17 | case ENOMEM: return "out of memory"; 18 | default: return "unknown error"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/strlen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * strlen() 4 | */ 5 | 6 | #include 7 | 8 | int strlen(char *s) { 9 | char *p; 10 | 11 | for (p = s; *p; p++) 12 | ; 13 | return p - s; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/strncat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strncat() 4 | */ 5 | 6 | #include 7 | 8 | char *strncat(char *d, char *a, int n) { 9 | char *p; 10 | 11 | for (p = d; *p; p++) 12 | ; 13 | for (; n && *a; n--) 14 | *p++ = *a++; 15 | *p = 0; 16 | return d; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/strncmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strncmp() 4 | */ 5 | 6 | #include 7 | 8 | int strncmp(char *s1, char *s2, int n) { 9 | while (n && *s1 && *s1 == *s2) 10 | s1++, s2++, n--; 11 | return n? *s1 - *s2: 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/strncpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * strncpy() 4 | */ 5 | 6 | #include 7 | 8 | char *strncpy(char *d, char *s, int n) { 9 | char *p; 10 | 11 | for (p = d; n && *s; n--) 12 | *p++ = *s++; 13 | if (n) *p = 0; 14 | return d; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/strpbrk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strpbrk() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *strpbrk(char *s, char *set) { 10 | while (*s && !strchr(set, *s)) 11 | s++; 12 | return *s? s: NULL; 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/strrchr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011 3 | * strrchr() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *strrchr(char *s, int c) { 10 | char *p; 11 | 12 | p = NULL; 13 | while (*s) 14 | if (*s++ == c) 15 | p = s-1; 16 | return p; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/strspn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strspn() 4 | */ 5 | 6 | #include 7 | 8 | int strspn(char *s, char *set) { 9 | int i = 0; 10 | 11 | while (*s && strchr(set, *s)) 12 | s++, i++; 13 | return i; 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/strtok.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strtok() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *strtok(char *s, char *sep) { 10 | static char *src = 0; 11 | char *p; 12 | 13 | if (s == NULL) s = src; 14 | while (*s && strchr(sep, *s)) 15 | s++; 16 | if (!*s) return NULL; 17 | for (p = s; *s && !strchr(sep, *s); s++) 18 | ; 19 | if (*s && s[1]) *s++ = 0; 20 | src = s; 21 | return p; 22 | } 23 | -------------------------------------------------------------------------------- /src/lib/strtol.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * strtol() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int strtol(char *s, char **endp, int base) { 12 | int sign = 1, ok = 0; 13 | char *p, *digits, *src; 14 | int v = 0; 15 | 16 | if (base < 0 || base > 36) { 17 | errno = EINVAL; 18 | return 0; 19 | } 20 | src = s; 21 | while (isspace(*s)) s++; 22 | if ('-' == *s) sign = -1, s++; 23 | else if ('+' == *s) s++; 24 | if ((0 == base || 16 == base) && '0' == *s && 'x' == s[1]) { 25 | base = 16; 26 | s += 2; 27 | } 28 | else if ((0 == base || 8 == base) && '0' == *s) { 29 | base = 8; 30 | s++; 31 | } 32 | if (0 == base) base = 10; 33 | digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 34 | for (;;) { 35 | p = strchr(digits, tolower(*s)); 36 | if (!p || p - digits >= base) break; 37 | v = v * base + p - digits; 38 | s++; 39 | ok = 1; 40 | } 41 | if (endp) *endp = ok? s: src; 42 | return v * sign; 43 | } 44 | -------------------------------------------------------------------------------- /src/lib/system.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * system() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int system(char *cmd) { 11 | int pid, rc; 12 | char *argv[4]; 13 | 14 | if ((pid = _fork()) == -1) { 15 | return -1; 16 | } 17 | else if (pid) { 18 | _wait(&rc); 19 | return cmd? rc: !rc; 20 | } 21 | else { 22 | argv[0] = "/bin/sh"; 23 | argv[1] = "-c"; 24 | argv[2] = cmd? cmd: "exit"; 25 | argv[3] = NULL; 26 | _execve(argv[0], argv, environ); 27 | exit(cmd? -1: 0); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lib/time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * time() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int time(int *tp) { 10 | int t; 11 | 12 | t = _time(); 13 | if (tp) *tp = t; 14 | return t; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/tmpfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * tmpfile() 4 | */ 5 | 6 | #include 7 | 8 | FILE *tmpfile(void) { 9 | FILE *f; 10 | char s[L_tmpnam]; 11 | 12 | if (tmpnam(s) == NULL) return NULL; 13 | if ((f = fopen(s, "w+")) == NULL) return NULL; 14 | remove(s); 15 | return f; 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/tmpnam.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * tmpnam() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | char *tmpnam(char *buf) { 10 | static int id = 0; 11 | static char tmp[L_tmpnam]; 12 | FILE *f; 13 | 14 | for (;;) { 15 | sprintf(tmp, "tmp%04x", id); 16 | if (++id > 32766) return NULL; 17 | if ((f = fopen(tmp, "r")) == NULL) { 18 | if (buf) { 19 | strcpy(buf, tmp); 20 | return buf; 21 | } 22 | return tmp; 23 | } 24 | fclose(f); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/ungetc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * ungetc() 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | int ungetc(int c, FILE *f) { 10 | if (f->ch != EOF) return EOF; 11 | f->iom &= ~_FERROR; 12 | return f->ch = c; 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/vformat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * _vformat() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int _fwrite(void *buf, int len, FILE *f); 11 | 12 | static int ofd; 13 | static FILE *outf; 14 | static int olen; 15 | static int limit; 16 | static char *vbuf; 17 | static int err; 18 | 19 | /* 20 | * Convert integer N to string. Write the string to P. 21 | * P must point to the *end* of the buffer initially; 22 | * the output is written backward! 23 | * BASE is the numeric base (8,10,16). SGNCH points 24 | * to a buffer to which ITOA writes the sign of N. The 25 | * sign is *not* included in the buffer P. 26 | */ 27 | 28 | static char *itoa(char *p, int n, int base, char *sgnch) { 29 | int s = 0, a = 'a'; 30 | 31 | if (base < 0) base = -base, a = 'A'; 32 | if (n < 0) s = 1, n = -n; 33 | *--p = 0; 34 | while (n || 0 == *p) { 35 | *--p = n % base + '0'; 36 | if (n % base > 9) *p += a-10-'0'; 37 | n /= base; 38 | } 39 | if (s) *sgnch = '-'; 40 | return p; 41 | } 42 | 43 | static void append(char *what, int len) { 44 | int k; 45 | 46 | if (ofd >= 0) { 47 | if (_write(ofd, what, len) != len) 48 | err = 1; 49 | olen += len; 50 | } 51 | else if (outf) { 52 | if (_fwrite(what, len, outf) != len) 53 | err = 1; 54 | olen += len; 55 | } 56 | else if (0 == limit) { 57 | memcpy(vbuf + olen, what, len); 58 | olen += len; 59 | vbuf[olen] = 0; 60 | } 61 | else { 62 | k = limit-olen-1; 63 | len = len < k? len: k; 64 | memcpy(vbuf + olen, what, len); 65 | olen += len; 66 | vbuf[olen] = 0; 67 | } 68 | } 69 | 70 | /* 71 | * Format and write output in the style of PRINTF. 72 | * When MODE==0, write the output to DEST (assuming 73 | * that DEST is a CHAR*). 74 | * When MODE==1, assume that DEST is a FILE* and 75 | * write the output to that stream. 76 | * In MODE==0, write at most MAX characters to DEST 77 | * where MAX==0 means unlimited). 78 | */ 79 | 80 | int _vformat(int mode, int max, void *dest, char *fmt, void **varg) { 81 | #define BUFLEN 256 82 | 83 | char lbuf[BUFLEN], *p, *end; 84 | int left, len, alt, k; 85 | char pad[1], sgnch[2], *pfx; 86 | int na = 0; 87 | 88 | end = &lbuf[BUFLEN]; 89 | sgnch[1] = 0; 90 | if (0 == mode) { 91 | outf = NULL; 92 | ofd = -1; 93 | vbuf = dest; 94 | *vbuf = 0; 95 | } 96 | else if (-1 == mode) { 97 | outf = NULL; 98 | ofd = (int) dest; 99 | err = 0; 100 | } 101 | else { 102 | outf = dest; 103 | ofd = -1; 104 | err = 0; 105 | } 106 | olen = 0; 107 | limit = max; 108 | while (*fmt) { 109 | left = len = 0; 110 | *sgnch = 0; 111 | pfx = ""; 112 | if ('%' == *fmt && fmt[1] != '%') { 113 | fmt++; 114 | *pad = ' '; 115 | alt = 0; 116 | while (strchr("-+0 #", *fmt)) { 117 | if ('-' == *fmt) { 118 | left = 1, *pad = ' '; 119 | fmt++; 120 | } 121 | else if ('0' == *fmt) { 122 | if (!left) *pad = '0'; 123 | fmt++; 124 | } 125 | else if ('#' == *fmt) { 126 | alt = 1; 127 | fmt++; 128 | } 129 | else if ('+' == *fmt) { 130 | *sgnch = '+'; 131 | fmt++; 132 | } 133 | else if (' ' == *fmt) { 134 | if (!*sgnch) *sgnch = ' '; 135 | fmt++; 136 | } 137 | } 138 | if ('*' == *fmt) 139 | len = (int) *varg--, fmt++; 140 | else 141 | while (isdigit(*fmt)) 142 | len = len * 10 + *fmt++ - '0'; 143 | switch (*fmt++) { 144 | case 'c': 145 | *pad = ' '; 146 | *sgnch = 0; 147 | lbuf[0] = (char) *varg--; 148 | lbuf[1] = 0; 149 | p = lbuf; 150 | na++; 151 | break; 152 | case 'd': 153 | p = itoa(end, (int) *varg--, 10, sgnch); 154 | na++; 155 | break; 156 | case 'n': 157 | p = itoa(end, olen, 10, sgnch); 158 | break; 159 | case 'o': 160 | p = itoa(end, (int) *varg--, 8, sgnch); 161 | if (alt) pfx = "0"; 162 | na++; 163 | break; 164 | case 's': 165 | *sgnch = 0; 166 | *pad = ' '; 167 | p = *varg--; 168 | na++; 169 | break; 170 | case 'p': 171 | case 'x': 172 | case 'X': 173 | k = 'X' == fmt[-1]? -16: 16; 174 | p = itoa(end, (int) *varg--, k, sgnch); 175 | if (alt) pfx = k<0? "0X": "0x"; 176 | na++; 177 | break; 178 | } 179 | } 180 | else { 181 | if ('%' == *fmt) fmt++; 182 | lbuf[0] = *fmt++; 183 | lbuf[1] = 0; 184 | p = lbuf; 185 | } 186 | k = strlen(p) + strlen(pfx) + strlen(sgnch); 187 | if ('0' == *pad) { 188 | if (*sgnch) append(sgnch, 1); 189 | append(pfx, strlen(pfx)); 190 | pfx = ""; 191 | } 192 | while (!left && len-- > k) 193 | append(pad, 1); 194 | if (*sgnch && *pad != '0') { 195 | append(sgnch, 1); 196 | append(pfx, strlen(pfx)); 197 | } 198 | if (!*sgnch) append(pfx, strlen(pfx)); 199 | append(p, strlen(p)); 200 | while (left && len-- > k) 201 | append(pad, 1); 202 | if (outf && err) break; 203 | } 204 | return na; 205 | } 206 | -------------------------------------------------------------------------------- /src/lib/vscan.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * _vscan() 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | static FILE *inf; 11 | static char *inp; 12 | static int nchar; 13 | 14 | static int next(void) { 15 | nchar++; 16 | if (inf) return fgetc(inf); 17 | if (!*inp) return EOF; 18 | return *inp++; 19 | } 20 | 21 | static void back(int c) { 22 | nchar--; 23 | if (inf) 24 | ungetc(c, inf); 25 | else 26 | inp--; 27 | } 28 | 29 | static int skip(void) { 30 | int c; 31 | 32 | while (isspace(c = next())) 33 | ; 34 | back(c); 35 | } 36 | 37 | static int scanchar(char *p, int len) { 38 | int c; 39 | 40 | if (0 == len) len = 1; 41 | while (len--) { 42 | if ((c = next()) == EOF) 43 | return 0; 44 | if (p) *p++ = c; 45 | } 46 | return 1; 47 | } 48 | 49 | static int scanstr(char *p, int len) { 50 | int k, c; 51 | 52 | k = len; 53 | while (0 == len || k--) { 54 | c = next(); 55 | if (isspace(c) || c == EOF) 56 | return 1; 57 | if (p) *p++ = c; 58 | } 59 | return 1; 60 | } 61 | 62 | static char *mkclass(char *fmt) { 63 | static char clss[128]; 64 | int i = 0, j; 65 | 66 | clss[0] = 0; 67 | if (*fmt == '^') fmt++, clss[0] = 1; 68 | i = 1; 69 | while (*fmt && *fmt != ']' && i < 127) { 70 | clss[i++] = *fmt++; 71 | if (i > 127) i--; 72 | if ('-' == *fmt && fmt[1] && fmt[1] != ']') { 73 | for (j = fmt[-1]; j < fmt[1]; j++) { 74 | if (i < 127) clss[i] = j; 75 | i++; 76 | } 77 | } 78 | } 79 | clss[i] = 0; 80 | return clss; 81 | } 82 | 83 | static int nstrchr(char *s, int c) { 84 | return !strchr(s, c); 85 | } 86 | 87 | static int scanclass(char *p, char *clss, int len) { 88 | int cmp, k, c; 89 | int (*in)(); 90 | 91 | k = len; 92 | in = *clss++? nstrchr: strchr; 93 | while ((0 == len || k--) && in(clss, c = next())) 94 | if (p) *p++ = c; 95 | return 1; 96 | } 97 | 98 | static int scannum(int *pi, int base, int len) { 99 | int sign = 1, ok = 0, k; 100 | char *p, *digits, *src; 101 | int v = 0, c; 102 | 103 | k = len; 104 | skip(); 105 | c = next(); 106 | k--; 107 | if ('-' == c) sign = -1, k--, c = next(); 108 | else if ('+' == c) c = next(), k--; 109 | if ((0 == base || 16 == base) && '0' == c) { 110 | if ((c = next()) == 'x' || c == 'X') { 111 | base = 16; 112 | c = next(); 113 | k--; 114 | } 115 | else { 116 | back(c); 117 | k++; 118 | if (0 == base) base = 8; 119 | c = '0'; 120 | } 121 | } 122 | else if ((0 == base || 8 == base) && '0' == c) { 123 | base = 8; 124 | c = next(); 125 | k--; 126 | } 127 | if (len && k < 1) return 0; 128 | if (0 == base) base = 10; 129 | digits = "0123456789abcdef"; 130 | while (0 == len || k--) { 131 | p = strchr(digits, tolower(c)); 132 | if (!p || p - digits >= base) break; 133 | v = v * base + p - digits; 134 | c = next(); 135 | ok = 1; 136 | } 137 | if (c >= 0) back(c); 138 | if (!ok) return 0; 139 | if (pi) *pi = v * sign; 140 | return 1; 141 | } 142 | 143 | /* 144 | * Read and scan input in the style of SCANF. 145 | * When MODE==0, read input from SRC (assuming 146 | * that SRCis a CHAR*). 147 | * When MODE==1, assume that SRC is a FILE* and 148 | * read input from that stream. 149 | */ 150 | 151 | int _vscan(int mode, void *src, char *fmt, void **varg) { 152 | int noasg, len, na = 0, c, pna; 153 | char *clss; 154 | void *p; 155 | 156 | if (0 == mode) { 157 | inp = src; 158 | inf = NULL; 159 | } 160 | else { 161 | inf = src; 162 | } 163 | nchar = 0; 164 | while (*fmt) { 165 | noasg = 0; 166 | if ('%' == *fmt && fmt[1] != '%') { 167 | len = 0; 168 | fmt++; 169 | if ('*' == *fmt) 170 | fmt++, noasg = 1; 171 | while (isdigit(*fmt)) 172 | len = len * 10 + *fmt++ - '0'; 173 | p = NULL; 174 | pna = na; 175 | switch (*fmt++) { 176 | case 'c': 177 | if (!noasg) p = *varg--; 178 | if (scanchar(p, len)) na++; 179 | break; 180 | case 'd': 181 | if (!noasg) p = *varg--; 182 | if (scannum(p, 10, len)) na++; 183 | break; 184 | case 'i': 185 | if (!noasg) p = *varg--; 186 | if (scannum(p, 0, len)) na++; 187 | break; 188 | case 'n': 189 | if (!noasg) p = *varg--; 190 | *(int *)p = nchar; 191 | break; 192 | case 'o': 193 | if (!noasg) p = *varg--; 194 | if (scannum(p, 8, len)) na++; 195 | break; 196 | case 's': 197 | if (!noasg) p = *varg--; 198 | if (scanstr(p, len)) na++; 199 | break; 200 | case 'p': 201 | case 'x': 202 | case 'X': 203 | if (!noasg) p = *varg--; 204 | if (scannum(p, 16, len)) na++; 205 | break; 206 | case '[': 207 | if (!noasg) p = *varg--; 208 | if (scanclass(p, mkclass(fmt), len)) 209 | na++; 210 | break; 211 | } 212 | if (pna == na) break; 213 | } 214 | else { 215 | if ('%' == *fmt) fmt++; 216 | if (isspace(*fmt)) { 217 | while ((c = isspace(next())) != 0) 218 | ; 219 | back(c); 220 | } 221 | else if (*fmt != next()) 222 | break; 223 | *fmt++; 224 | } 225 | } 226 | return na; 227 | } 228 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Main program 4 | */ 5 | 6 | #include "defs.h" 7 | #define _extern 8 | #include "data.h" 9 | #undef _extern 10 | #include "decl.h" 11 | 12 | static void init(void) { 13 | Line = 1; 14 | Putback = '\n'; 15 | Rejected = -1; 16 | Errors = 0; 17 | Mp = 0; 18 | Expandmac = 1; 19 | Syntoken = 0; 20 | Isp = 0; 21 | Inclev = 0; 22 | Globs = 0; 23 | Locs = NSYMBOLS; 24 | Nbot = 0; 25 | Ntop = POOLSIZE; 26 | Bsp = 0; 27 | Csp = 0; 28 | addglob("", 0, 0, 0, 0, 0, NULL, 0); 29 | addglob("__SUBC__", 0, TMACRO, 0, 0, 0, globname(""), 0); 30 | Infile = stdin; 31 | File = "(stdin)"; 32 | Basefile = NULL; 33 | Outfile = stdout; 34 | } 35 | 36 | static void cmderror(char *s, char *a) { 37 | fprintf(stderr, "scc: "); 38 | fprintf(stderr, s, a); 39 | fputc('\n', stderr); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | static int filetype(char *file) { 44 | int k; 45 | 46 | k = strlen(file); 47 | if ('.' == file[k-2]) return file[k-1]; 48 | return 0; 49 | } 50 | 51 | static void defarg(char *s) { 52 | char *p; 53 | 54 | if (NULL == s) return; 55 | if ((p = strchr(s, '=')) != NULL) 56 | *p++ = 0; 57 | else 58 | p = ""; 59 | addglob(s, 0, TMACRO, 0, 0, 0, globname(p), 0); 60 | if (*p) *--p = '='; 61 | } 62 | 63 | static void stats(void) { 64 | printf( "Memory usage: " 65 | "Symbols: %5d/%5d, " 66 | "Name pool: %5d/%5d\n", 67 | Globs, NSYMBOLS, 68 | Nbot, POOLSIZE); 69 | } 70 | 71 | static void compile(char *file, char *def) { 72 | char *ofile; 73 | 74 | init(); 75 | defarg(def); 76 | if (file) { 77 | ofile = newfilename(file, 's'); 78 | if ((Infile = fopen(file, "r")) == NULL) 79 | cmderror("no such file: %s", file); 80 | Basefile = File = file; 81 | if (!O_testonly) { 82 | if ((Outfile = fopen(ofile, "r")) != NULL) 83 | cmderror("will not overwrite file: %s", 84 | ofile); 85 | if ((Outfile = fopen(ofile, "w")) == NULL) 86 | cmderror("cannot create file: %s", ofile); 87 | } 88 | } 89 | if (O_testonly) Outfile = NULL; 90 | if (O_verbose) { 91 | if (O_testonly) 92 | printf("testing %s\n", file); 93 | else 94 | printf("compiling %s\n", file); 95 | } 96 | genprelude(); 97 | Token = scan(); 98 | while (XEOF != Token) 99 | top(); 100 | genpostlude(); 101 | if (file) { 102 | fclose(Infile); 103 | if (Outfile) fclose(Outfile); 104 | } 105 | if (O_debug & D_GSYM) dumpsyms("GLOBALS", "", 1, Globs); 106 | if (O_debug & D_STAT) stats(); 107 | } 108 | 109 | static void collect(char *file) { 110 | if (O_componly || O_asmonly) return; 111 | if (Nf >= MAXFILES) 112 | cmderror("too many input files", NULL); 113 | Files[Nf++] = file; 114 | } 115 | 116 | static void assemble(char *file, int delete) { 117 | char *ofile; 118 | char cmd[TEXTLEN+1]; 119 | 120 | file = newfilename(file, 's'); 121 | collect(ofile = newfilename(file, 'o')); 122 | if (strlen(file) + strlen(ofile) + strlen(ASCMD) >= TEXTLEN) 123 | cmderror("assembler command too long", NULL); 124 | sprintf(cmd, ASCMD, ofile, file); 125 | if (O_verbose > 1) printf("%s\n", cmd); 126 | if (system(cmd)) 127 | cmderror("assembler invocation failed", NULL); 128 | if (delete) remove(file); 129 | } 130 | 131 | static int concat(int k, char *buf, char *s) { 132 | int n; 133 | 134 | n = strlen(s); 135 | if (k + n + 2 >= TEXTLEN) 136 | cmderror("linker command too long", buf); 137 | strcat(buf, " "); 138 | strcat(buf, s); 139 | return k + n + 1; 140 | } 141 | 142 | static void link(void) { 143 | int i, k; 144 | char cmd[TEXTLEN+1], *msg; 145 | char cmd2[TEXTLEN+1]; 146 | 147 | if (strlen(O_outfile) + strlen(LDCMD) + strlen(SCCDIR)*2 >= TEXTLEN) 148 | cmderror(msg, NULL); 149 | sprintf(cmd, LDCMD, O_outfile, SCCDIR); 150 | k = strlen(cmd); 151 | for (i=0; i 1) printf("%s\n", cmd2); 157 | if (system(cmd2)) 158 | cmderror("linker invocation failed", NULL); 159 | } 160 | 161 | static void usage(void) { 162 | printf("Usage: scc [-h] [-ctvS] [-d opt] [-o file] [-D macro[=text]]" 163 | " file [...]\n"); 164 | } 165 | 166 | static void longusage(void) { 167 | printf("\n"); 168 | usage(); 169 | printf( "\n" 170 | "-c compile only, do not link\n" 171 | "-d opt activate debug option OPT\n" 172 | "-o file write linker output to FILE\n" 173 | "-t test only, generate no code\n" 174 | "-v verbose, more v's = more verbose\n" 175 | "-D m=v define macro M with optional value V\n" 176 | "-S compile to assembly language\n" 177 | "\n" ); 178 | } 179 | 180 | static char *nextarg(int argc, char *argv[], int *pi, int *pj) { 181 | char *s; 182 | 183 | if (argv[*pi][*pj+1] || *pi >= argc-1) { 184 | usage(); 185 | exit(EXIT_FAILURE); 186 | } 187 | s = argv[++*pi]; 188 | *pj = strlen(s)-1; 189 | return s; 190 | } 191 | 192 | static int dbgopt(int argc, char *argv[], int *pi, int *pj) { 193 | char *s; 194 | 195 | s = nextarg(argc, argv, pi, pj); 196 | if (!strcmp(s, "lsym")) return D_LSYM; 197 | if (!strcmp(s, "gsym")) return D_GSYM; 198 | if (!strcmp(s, "stat")) return D_STAT; 199 | printf( "\n" 200 | "scc: valid -d options are: \n\n" 201 | "lsym - dump local symbol tables\n" 202 | "gsym - dump global symbol table\n" 203 | "stat - print usage statistics\n" 204 | "\n"); 205 | exit(EXIT_FAILURE); 206 | } 207 | 208 | int main(int argc, char *argv[]) { 209 | int i, j; 210 | char *def; 211 | 212 | def = NULL; 213 | O_verbose = 0; 214 | O_componly = 0; 215 | O_asmonly = 0; 216 | O_testonly = 0; 217 | O_outfile = "a.out"; 218 | for (i=1; i= argc) { 259 | usage(); 260 | exit(EXIT_FAILURE); 261 | } 262 | Nf = 0; 263 | while (i < argc) { 264 | if (filetype(argv[i]) == 'c') { 265 | compile(argv[i], def); 266 | if (Errors && !O_testonly) 267 | cmderror("compilation stopped", NULL); 268 | if (!O_asmonly && !O_testonly) 269 | assemble(argv[i], 1); 270 | i++; 271 | } 272 | else if (filetype(argv[i]) == 's') { 273 | if (!O_testonly) assemble(argv[i++], 0); 274 | } 275 | else { 276 | collect(argv[i++]); 277 | } 278 | } 279 | if (!O_componly && !O_testonly) link(); 280 | return EXIT_SUCCESS; 281 | } 282 | -------------------------------------------------------------------------------- /src/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Miscellanea 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | 10 | int chrpos(char *s, int c) { 11 | char *p; 12 | 13 | p = strchr(s, c); 14 | return p? p-s: -1; 15 | } 16 | 17 | void copyname(char *name, char *s) { 18 | strncpy(name, s, NAMELEN); 19 | name[NAMELEN] = 0; 20 | } 21 | 22 | char *newfilename(char *file, int sfx) { 23 | char *ofile; 24 | 25 | ofile = strdup(file); 26 | ofile[strlen(ofile)-1] = sfx; 27 | return ofile; 28 | } 29 | 30 | static FILE *suspended; 31 | 32 | void suspend(void) { 33 | suspended = Outfile; 34 | Outfile = NULL; 35 | } 36 | 37 | void resume(void) { 38 | Outfile = suspended; 39 | clear(); 40 | } 41 | 42 | void match(int t, char *what) { 43 | if (Token == t) { 44 | Token = scan(); 45 | } 46 | else { 47 | error("%s expected", what); 48 | } 49 | } 50 | 51 | void lparen(void) { 52 | match(LPAREN, "'('"); 53 | } 54 | 55 | void rparen(void) { 56 | match(RPAREN, "')'"); 57 | } 58 | 59 | void lbrace(void) { 60 | match(LBRACE, "'{'"); 61 | } 62 | 63 | void rbrace(void) { 64 | match(RBRACE, "'}'"); 65 | } 66 | 67 | void rbrack(void) { 68 | match(RBRACK, "']'"); 69 | } 70 | 71 | void semi(void) { 72 | match(SEMI, "';'"); 73 | } 74 | 75 | void colon(void) { 76 | match(COLON, "':'"); 77 | } 78 | 79 | void ident(void) { 80 | match(IDENT, "identifier"); 81 | } 82 | 83 | int eofcheck(void) { 84 | if (XEOF == Token) { 85 | error("missing '}'", NULL); 86 | return 1; 87 | } 88 | return 0; 89 | } 90 | 91 | int inttype(int p) { 92 | return PINT == p || PCHAR == p; 93 | } 94 | 95 | int comptype(int p) { 96 | p &= STCMASK; 97 | return p == PSTRUCT || p == PUNION; 98 | } 99 | -------------------------------------------------------------------------------- /src/prec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Binary operator precedence 4 | */ 5 | 6 | static int Prec[] = { 7 | 7, /* SLASH */ 8 | 7, /* STAR */ 9 | 7, /* MOD */ 10 | 6, /* PLUS */ 11 | 6, /* MINUS */ 12 | 5, /* LSHIFT */ 13 | 5, /* RSHIFT */ 14 | 4, /* GREATER */ 15 | 4, /* GTEQ */ 16 | 4, /* LESS */ 17 | 4, /* LTEQ */ 18 | 3, /* EQUAL */ 19 | 3, /* NOTEQ */ 20 | 2, /* AMPER */ 21 | 1, /* CARET */ 22 | 0, /* PIPE */ 23 | }; 24 | -------------------------------------------------------------------------------- /src/prep.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Preprocessor 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | 10 | void playmac(char *s) { 11 | if (Mp >= MAXNMAC) fatal("too many nested macros"); 12 | Macc[Mp] = next(); 13 | Macp[Mp++] = s; 14 | } 15 | 16 | static void defmac(void) { 17 | char name[NAMELEN+1]; 18 | char buf[TEXTLEN+1], *p; 19 | int k, y; 20 | 21 | Token = scanraw(); 22 | if (Token != IDENT) 23 | error("identifier expected after '#define': %s", Text); 24 | copyname(name, Text); 25 | if ('\n' == Putback) 26 | buf[0] = 0; 27 | else 28 | fgets(buf, TEXTLEN-1, Infile); 29 | k = strlen(buf); 30 | if (k) buf[k-1] = 0; 31 | for (p = buf; isspace(*p); p++) 32 | ; 33 | if ((y = findmac(name)) != 0) { 34 | if (strcmp(Mtext[y], buf)) 35 | error("macro redefinition: %s", name); 36 | } 37 | else { 38 | addglob(name, 0, TMACRO, 0, 0, 0, globname(p), 0); 39 | } 40 | Line++; 41 | } 42 | 43 | static void undef(void) { 44 | char name[NAMELEN+1]; 45 | int y; 46 | 47 | Token = scanraw(); 48 | copyname(name, Text); 49 | if (IDENT != Token) 50 | error("identifier expected after '#undef': %s", Text); 51 | if ((y = findmac(name)) != 0) 52 | Names[y] = "#undef'd"; 53 | } 54 | 55 | static void include(void) { 56 | char file[TEXTLEN+1], path[TEXTLEN+1]; 57 | int c, k; 58 | FILE *inc, *oinfile; 59 | char *ofile; 60 | int oc, oline; 61 | 62 | if ((c = skip()) == '<') 63 | c = '>'; 64 | fgets(file, TEXTLEN-strlen(SCCDIR)-9, Infile); 65 | Line++; 66 | k = strlen(file); 67 | file[k-1] = 0; 68 | if (file[k-2] != c) 69 | error("missing delimiter in '#include'", NULL); 70 | file[k-2] = 0; 71 | if (c == '"') 72 | strcpy(path, file); 73 | else { 74 | strcpy(path, SCCDIR); 75 | strcat(path, "/include/"); 76 | strcat(path, file); 77 | } 78 | if ((inc = fopen(path, "r")) == NULL) 79 | error("cannot open include file: %s", path); 80 | else { 81 | Inclev++; 82 | oc = next(); 83 | oline = Line; 84 | ofile = File; 85 | oinfile = Infile; 86 | Line = 1; 87 | putback('\n'); 88 | File = path; 89 | Infile = inc; 90 | Token = scan(); 91 | while (XEOF != Token) 92 | top(); 93 | Line = oline; 94 | File = ofile; 95 | Infile = oinfile; 96 | fclose(inc); 97 | putback(oc); 98 | Inclev--; 99 | } 100 | } 101 | 102 | static void ifdef(int expect) { 103 | char name[NAMELEN+1]; 104 | 105 | if (Isp >= MAXIFDEF) 106 | fatal("too many nested '#ifdef's"); 107 | Token = scanraw(); 108 | copyname(name, Text); 109 | if (IDENT != Token) 110 | error("identifier expected in '#ifdef'", NULL); 111 | if (frozen(1)) 112 | Ifdefstk[Isp++] = P_IFNDEF; 113 | else if ((findmac(name) != 0) == expect) 114 | Ifdefstk[Isp++] = P_IFDEF; 115 | else 116 | Ifdefstk[Isp++] = P_IFNDEF; 117 | } 118 | 119 | static void p_else(void) { 120 | if (!Isp) 121 | error("'#else' without matching '#ifdef'", NULL); 122 | else if (frozen(2)) 123 | ; 124 | else if (P_IFDEF == Ifdefstk[Isp-1]) 125 | Ifdefstk[Isp-1] = P_ELSENOT; 126 | else if (P_IFNDEF == Ifdefstk[Isp-1]) 127 | Ifdefstk[Isp-1] = P_ELSE; 128 | else 129 | error("'#else' without matching '#ifdef'", NULL); 130 | 131 | } 132 | 133 | static void endif(void) { 134 | if (!Isp) 135 | error("'#endif' without matching '#ifdef'", NULL); 136 | else 137 | Isp--; 138 | } 139 | 140 | static void pperror(void) { 141 | char buf[TEXTLEN+1]; 142 | int k; 143 | 144 | if ('\n' == Putback) 145 | buf[0] = 0; 146 | else 147 | fgets(buf, TEXTLEN-1, Infile); 148 | k = strlen(buf); 149 | if (k) buf[k-1] = 0; 150 | error("#error: %s", buf); 151 | exit(1); 152 | } 153 | 154 | static void setline(void) { 155 | char buf[TEXTLEN+1]; 156 | 157 | if ('\n' == Putback) 158 | buf[0] = 0; 159 | else 160 | fgets(buf, TEXTLEN-1, Infile); 161 | Line = atoi(buf) - 1; 162 | } 163 | 164 | static void junkln(void) { 165 | while (!feof(Infile) && fgetc(Infile) != '\n') 166 | ; 167 | Line++; 168 | } 169 | 170 | int frozen(int depth) { 171 | return Isp >= depth && 172 | (P_IFNDEF == Ifdefstk[Isp-depth] || 173 | P_ELSENOT == Ifdefstk[Isp-depth]); 174 | } 175 | 176 | void preproc(void) { 177 | putback('#'); 178 | Token = scanraw(); 179 | if ( frozen(1) && 180 | (P_DEFINE == Token || P_INCLUDE == Token || P_UNDEF == Token) 181 | ) { 182 | junkln(); 183 | return; 184 | } 185 | switch (Token) { 186 | case P_DEFINE: defmac(); break; 187 | case P_UNDEF: undef(); break; 188 | case P_INCLUDE: include(); break; 189 | case P_IFDEF: ifdef(1); break; 190 | case P_IFNDEF: ifdef(0); break; 191 | case P_ELSE: p_else(); break; 192 | case P_ENDIF: endif(); break; 193 | case P_ERROR: pperror(); break; 194 | case P_LINE: setline(); break; 195 | case P_PRAGMA: junkln(); break; 196 | default: junkln(); break; 197 | break; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/scan.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Lexical analysis (scanner) 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | 10 | int next(void) { 11 | int c; 12 | 13 | if (Putback) { 14 | c = Putback; 15 | Putback = 0; 16 | return c; 17 | } 18 | if (Mp) { 19 | if ('\0' == *Macp[Mp-1]) { 20 | Macp[Mp-1] = NULL; 21 | return Macc[--Mp]; 22 | } 23 | else { 24 | return *Macp[Mp-1]++; 25 | } 26 | } 27 | c = fgetc(Infile); 28 | if ('\n' == c) Line++; 29 | return c; 30 | } 31 | 32 | void putback(int c) { 33 | Putback = c; 34 | } 35 | 36 | static int hexchar(void) { 37 | int c, h, n = 0, f = 0; 38 | 39 | while (isxdigit(c = next())) { 40 | h = chrpos("0123456789abcdef", tolower(c)); 41 | n = n * 16 + h; 42 | f = 1; 43 | } 44 | putback(c); 45 | if (!f) 46 | error("missing digits after '\\x'", NULL); 47 | if (n > 255) 48 | error("value out of range after '\\x'", NULL); 49 | return n; 50 | } 51 | 52 | static int scanch(void) { 53 | int c, c2; 54 | 55 | c = next(); 56 | if ('\\' == c) { 57 | switch (c = next()) { 58 | case 'a': return '\a'; 59 | case 'b': return '\b'; 60 | case 'f': return '\f'; 61 | case 'n': return '\n'; 62 | case 'r': return '\r'; 63 | case 't': return '\t'; 64 | case 'v': return '\v'; 65 | case '\\': return '\\'; 66 | case '"': return '"' | 256; 67 | case '\'': return '\''; 68 | case '0': case '1': case '2': 69 | case '3': case '4': case '5': 70 | case '6': case '7': 71 | for (c2 = 0; isdigit(c) && c < '8'; c = next()) 72 | c2 = c2 * 8 + (c - '0'); 73 | putback(c); 74 | return c2; 75 | case 'x': 76 | return hexchar(); 77 | default: 78 | cerror("unknown escape sequence: %s", c); 79 | return ' '; 80 | } 81 | } 82 | else { 83 | return c; 84 | } 85 | } 86 | 87 | static int scanint(int c) { 88 | int val, radix, k, i = 0; 89 | 90 | val = 0; 91 | radix = 10; 92 | if ('0' == c) { 93 | Text[i++] = '0'; 94 | if ((c = next()) == 'x') { 95 | radix = 16; 96 | Text[i++] = c; 97 | c = next(); 98 | } 99 | else { 100 | radix = 8; 101 | } 102 | } 103 | while ((k = chrpos("0123456789abcdef", tolower(c))) >= 0) { 104 | Text[i++] = c; 105 | if (k >= radix) 106 | cerror("invalid digit in integer literal: %s", c); 107 | val = val * radix + k; 108 | c = next(); 109 | } 110 | putback(c); 111 | Text[i] = 0; 112 | return val; 113 | } 114 | 115 | static int scanstr(char *buf) { 116 | int i, c; 117 | 118 | buf[0] = '"'; 119 | for (i=1; i"); 157 | return EOF; 158 | } 159 | while (' ' == c || '\t' == c || '\n' == c || 160 | '\r' == c || '\f' == c 161 | ) { 162 | if ('\n' == c) nl = 1; 163 | c = next(); 164 | } 165 | if (nl && c == '#') { 166 | preproc(); 167 | c = next(); 168 | continue; 169 | } 170 | nl = 0; 171 | if (c != '/') 172 | break; 173 | if ((c = next()) != '*') { 174 | putback(c); 175 | c = '/'; 176 | break; 177 | } 178 | p = 0; 179 | while ((c = next()) != EOF) { 180 | if ('/' == c && '*' == p) { 181 | c = next(); 182 | break; 183 | } 184 | p = c; 185 | } 186 | } 187 | return c; 188 | } 189 | 190 | static int keyword(char *s) { 191 | switch (*s) { 192 | case '#': 193 | switch (s[1]) { 194 | case 'd': 195 | if (!strcmp(s, "#define")) return P_DEFINE; 196 | break; 197 | case 'e': 198 | if (!strcmp(s, "#else")) return P_ELSE; 199 | if (!strcmp(s, "#endif")) return P_ENDIF; 200 | if (!strcmp(s, "#error")) return P_ERROR; 201 | break; 202 | case 'i': 203 | if (!strcmp(s, "#ifdef")) return P_IFDEF; 204 | if (!strcmp(s, "#ifndef")) return P_IFNDEF; 205 | if (!strcmp(s, "#include")) return P_INCLUDE; 206 | break; 207 | case 'l': 208 | if (!strcmp(s, "#line")) return P_LINE; 209 | break; 210 | case 'p': 211 | if (!strcmp(s, "#pragma")) return P_PRAGMA; 212 | break; 213 | case 'u': 214 | if (!strcmp(s, "#undef")) return P_UNDEF; 215 | break; 216 | } 217 | break; 218 | case 'a': 219 | if (!strcmp(s, "auto")) return AUTO; 220 | break; 221 | case 'b': 222 | if (!strcmp(s, "break")) return BREAK; 223 | break; 224 | case 'c': 225 | if (!strcmp(s, "case")) return CASE; 226 | if (!strcmp(s, "char")) return CHAR; 227 | if (!strcmp(s, "continue")) return CONTINUE; 228 | break; 229 | case 'd': 230 | if (!strcmp(s, "default")) return DEFAULT; 231 | if (!strcmp(s, "do")) return DO; 232 | break; 233 | case 'e': 234 | if (!strcmp(s, "else")) return ELSE; 235 | if (!strcmp(s, "enum")) return ENUM; 236 | if (!strcmp(s, "extern")) return EXTERN; 237 | break; 238 | case 'f': 239 | if (!strcmp(s, "for")) return FOR; 240 | break; 241 | case 'i': 242 | if (!strcmp(s, "if")) return IF; 243 | if (!strcmp(s, "int")) return INT; 244 | break; 245 | case 'r': 246 | if (!strcmp(s, "register")) return REGISTER; 247 | if (!strcmp(s, "return")) return RETURN; 248 | break; 249 | case 's': 250 | if (!strcmp(s, "sizeof")) return SIZEOF; 251 | if (!strcmp(s, "static")) return STATIC; 252 | if (!strcmp(s, "struct")) return STRUCT; 253 | if (!strcmp(s, "switch")) return SWITCH; 254 | break; 255 | case 'u': 256 | if (!strcmp(s, "union")) return UNION; 257 | break; 258 | case 'v': 259 | if (!strcmp(s, "void")) return VOID; 260 | break; 261 | case 'w': 262 | if (!strcmp(s, "while")) return WHILE; 263 | break; 264 | case '_': 265 | if (!strcmp(s, "__argc")) return __ARGC; 266 | break; 267 | } 268 | return 0; 269 | } 270 | 271 | static int macro(char *name) { 272 | int y; 273 | 274 | y = findmac(name); 275 | if (!y || Types[y] != TMACRO) 276 | return 0; 277 | playmac(Mtext[y]); 278 | return 1; 279 | } 280 | 281 | static int scanpp(void) { 282 | int c, t; 283 | 284 | if (Rejected != -1) { 285 | t = Rejected; 286 | Rejected = -1; 287 | strcpy(Text, Rejtext); 288 | Value = Rejval; 289 | return t; 290 | } 291 | for (;;) { 292 | Value = 0; 293 | c = skip(); 294 | memset(Text, 0, 4); 295 | Text[0] = c; 296 | switch (c) { 297 | case '!': 298 | if ((c = next()) == '=') { 299 | Text[1] = '='; 300 | return NOTEQ; 301 | } 302 | else { 303 | putback(c); 304 | return XMARK; 305 | } 306 | case '%': 307 | if ((c = next()) == '=') { 308 | Text[1] = '='; 309 | return ASMOD; 310 | } 311 | else { 312 | putback(c); 313 | return MOD; 314 | } 315 | case '&': 316 | if ((c = next()) == '&') { 317 | Text[1] = '&'; 318 | return LOGAND; 319 | } 320 | else if ('=' == c) { 321 | Text[1] = '='; 322 | return ASAND; 323 | } 324 | else { 325 | putback(c); 326 | return AMPER; 327 | } 328 | case '(': 329 | return LPAREN; 330 | case ')': 331 | return RPAREN; 332 | case '*': 333 | if ((c = next()) == '=') { 334 | Text[1] = '='; 335 | return ASMUL; 336 | } 337 | else { 338 | putback(c); 339 | return STAR; 340 | } 341 | case '+': 342 | if ((c = next()) == '+') { 343 | Text[1] = '+'; 344 | return INCR; 345 | } 346 | else if ('=' == c) { 347 | Text[1] = '='; 348 | return ASPLUS; 349 | } 350 | else { 351 | putback(c); 352 | return PLUS; 353 | } 354 | case ',': 355 | return COMMA; 356 | case '-': 357 | if ((c = next()) == '-') { 358 | Text[1] = '-'; 359 | return DECR; 360 | } 361 | else if ('=' == c) { 362 | Text[1] = '='; 363 | return ASMINUS; 364 | } 365 | else if ('>' == c) { 366 | Text[1] = '>'; 367 | return ARROW; 368 | } 369 | else { 370 | putback(c); 371 | return MINUS; 372 | } 373 | case '/': 374 | if ((c = next()) == '=') { 375 | Text[1] = '='; 376 | return ASDIV; 377 | } 378 | else { 379 | putback(c); 380 | return SLASH; 381 | } 382 | case ':': 383 | return COLON; 384 | case ';': 385 | return SEMI; 386 | case '<': 387 | if ((c = next()) == '<') { 388 | Text[1] = '<'; 389 | if ((c = next()) == '=') { 390 | Text[2] = '='; 391 | return ASLSHIFT; 392 | } 393 | else { 394 | putback(c); 395 | return LSHIFT; 396 | } 397 | } 398 | else if ('=' == c) { 399 | Text[1] = '='; 400 | return LTEQ; 401 | } 402 | else { 403 | putback(c); 404 | return LESS; 405 | } 406 | case '=': 407 | if ((c = next()) == '=') { 408 | Text[1] = '='; 409 | return EQUAL; 410 | } 411 | else { 412 | putback(c); 413 | return ASSIGN; 414 | } 415 | case '>': 416 | if ((c = next()) == '>') { 417 | Text[1] = '>'; 418 | if ((c = next()) == '=') { 419 | Text[1] = '='; 420 | return ASRSHIFT; 421 | } 422 | else { 423 | putback(c); 424 | return RSHIFT; 425 | } 426 | } 427 | else if ('=' == c) { 428 | Text[1] = '='; 429 | return GTEQ; 430 | } 431 | else { 432 | putback(c); 433 | return GREATER; 434 | } 435 | case '?': 436 | return QMARK; 437 | case '[': 438 | return LBRACK; 439 | case ']': 440 | return RBRACK; 441 | case '^': 442 | if ((c = next()) == '=') { 443 | Text[1] = '='; 444 | return ASXOR; 445 | } 446 | else { 447 | putback(c); 448 | return CARET; 449 | } 450 | case '{': 451 | return LBRACE; 452 | case '|': 453 | if ((c = next()) == '|') { 454 | Text[1] = '|'; 455 | return LOGOR; 456 | } 457 | else if ('=' == c) { 458 | Text[1] = '='; 459 | return ASOR; 460 | } 461 | else { 462 | putback(c); 463 | return PIPE; 464 | } 465 | case '}': 466 | return RBRACE; 467 | case '~': 468 | return TILDE; 469 | case EOF: 470 | strcpy(Text, ""); 471 | return XEOF; 472 | case '\'': 473 | Text[1] = Value = scanch(); 474 | if ((c = next()) != '\'') 475 | error( 476 | "expected '\\'' at end of char literal", 477 | NULL); 478 | Text[2] = '\''; 479 | return INTLIT; 480 | case '"': 481 | Value = scanstr(Text); 482 | return STRLIT; 483 | case '#': 484 | Text[0] = '#'; 485 | scanident(next(), &Text[1], TEXTLEN-1); 486 | if ((t = keyword(Text)) != 0) 487 | return t; 488 | error("unknown preprocessor command: %s", Text); 489 | return IDENT; 490 | case '.': 491 | if ((c = next()) == '.') { 492 | Text[1] = Text[2] = '.'; 493 | Text[3] = 0; 494 | if ((c = next()) == '.') 495 | return ELLIPSIS; 496 | putback(c); 497 | error("incomplete '...'", NULL); 498 | return ELLIPSIS; 499 | } 500 | putback(c); 501 | return DOT; 502 | default: 503 | if (isdigit(c)) { 504 | Value = scanint(c); 505 | return INTLIT; 506 | } 507 | else if (isalpha(c) || '_' == c) { 508 | Value = scanident(c, Text, TEXTLEN); 509 | if (Expandmac && macro(Text)) 510 | break; 511 | if ((t = keyword(Text)) != 0) 512 | return t; 513 | return IDENT; 514 | } 515 | else { 516 | cerror("funny input character: %s", c); 517 | break; 518 | } 519 | } 520 | } 521 | } 522 | 523 | int scan(void) { 524 | int t; 525 | 526 | do { 527 | t = scanpp(); 528 | if (!Inclev && Isp && XEOF == t) 529 | fatal("missing '#endif'"); 530 | } while (frozen(1)); 531 | if (t == Syntoken) 532 | Syntoken = 0; 533 | return t; 534 | } 535 | 536 | int scanraw(void) { 537 | int t, oisp; 538 | 539 | oisp = Isp; 540 | Isp = 0; 541 | Expandmac = 0; 542 | t = scan(); 543 | Expandmac = 1; 544 | Isp = oisp; 545 | return t; 546 | } 547 | 548 | void reject(void) { 549 | Rejected = Token; 550 | Rejval = Value; 551 | strcpy(Rejtext, Text); 552 | } 553 | -------------------------------------------------------------------------------- /src/stmt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Statement parser 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | 10 | static void stmt(void); 11 | 12 | /* 13 | * compound := 14 | * { stmt_list } 15 | * | { } 16 | * 17 | * stmt_list: 18 | * stmt 19 | * | stmt stmt_list 20 | */ 21 | 22 | void compound(int lbr) { 23 | if (lbr) Token = scan(); 24 | while (RBRACE != Token) { 25 | if (eofcheck()) return; 26 | stmt(); 27 | } 28 | Token = scan(); 29 | } 30 | 31 | static void pushbrk(int id) { 32 | if (Bsp >= MAXBREAK) 33 | fatal("too many nested loops/switches"); 34 | Breakstk[Bsp++] = id; 35 | } 36 | 37 | static void pushcont(int id) { 38 | if (Csp >= MAXBREAK) 39 | fatal("too many nested loops/switches"); 40 | Contstk[Csp++] = id; 41 | } 42 | 43 | /* 44 | * break_stmt := BREAK ; 45 | */ 46 | 47 | static void break_stmt(void) { 48 | Token = scan(); 49 | if (!Bsp) error("'break' not in loop/switch context", NULL); 50 | genjump(Breakstk[Bsp-1]); 51 | semi(); 52 | } 53 | 54 | /* 55 | * continue_stmt := CONTINUE ; 56 | */ 57 | 58 | static void continue_stmt(void) { 59 | Token = scan(); 60 | if (!Csp) error("'continue' not in loop context", NULL); 61 | genjump(Contstk[Csp-1]); 62 | semi(); 63 | } 64 | 65 | /* 66 | * do_stmt := DO stmt WHILE ( expr ) ; 67 | */ 68 | 69 | static void do_stmt(void) { 70 | int ls, lb, lc; 71 | 72 | Token = scan(); 73 | ls = label(); 74 | pushbrk(lb = label()); 75 | pushcont(lc = label()); 76 | genlab(ls); 77 | stmt(); 78 | match(WHILE, "'while'"); 79 | lparen(); 80 | genlab(lc); 81 | rexpr(); 82 | genbrtrue(ls); 83 | genlab(lb); 84 | rparen(); 85 | semi(); 86 | Bsp--; 87 | Csp--; 88 | } 89 | 90 | /* 91 | * for_stmt := 92 | * FOR ( opt_expr ; opt_expr ; opt_expr ) stmt 93 | * 94 | * opt_expr := 95 | * | expr 96 | */ 97 | 98 | static void for_stmt(void) { 99 | int ls, lbody, lb, lc; 100 | 101 | Token = scan(); 102 | ls = label(); 103 | lbody = label(); 104 | pushbrk(lb = label()); 105 | pushcont(lc = label()); 106 | lparen(); 107 | if (Token != SEMI) { 108 | rexpr(); 109 | clear(); 110 | } 111 | semi(); 112 | genlab(ls); 113 | if (Token != SEMI) { 114 | rexpr(); 115 | clear(); 116 | genbrfalse(lb); 117 | } 118 | genjump(lbody); 119 | semi(); 120 | genlab(lc); 121 | if (Token != RPAREN) { 122 | rexpr(); 123 | clear(); 124 | } 125 | genjump(ls); 126 | rparen(); 127 | genlab(lbody); 128 | stmt(); 129 | genjump(lc); 130 | genlab(lb); 131 | Bsp--; 132 | Csp--; 133 | } 134 | 135 | /* 136 | * if_stmt := 137 | * IF ( expr ) stmt 138 | * | IF ( expr ) stmt ELSE stmt 139 | */ 140 | 141 | static void if_stmt(void) { 142 | int l1, l2; 143 | 144 | Token = scan(); 145 | lparen(); 146 | rexpr(); 147 | clear(); 148 | rparen(); 149 | l1 = label(); 150 | genbrfalse(l1); 151 | stmt(); 152 | if (ELSE == Token) { 153 | l2 = label(); 154 | genjump(l2); 155 | genlab(l1); 156 | l1 = l2; 157 | Token = scan(); 158 | stmt(); 159 | } 160 | genlab(l1); 161 | } 162 | 163 | /* 164 | * return_stmt := 165 | * RETURN ; 166 | * | RETURN expr ; 167 | */ 168 | 169 | static void return_stmt(void) { 170 | int lv[LV]; 171 | 172 | Token = scan(); 173 | if (Token != SEMI) { 174 | if (expr(lv)) 175 | rvalue(lv); 176 | if (!typematch(lv[LVPRIM], Prims[Thisfn])) 177 | error("incompatible type in 'return'", NULL); 178 | } 179 | else { 180 | if (Prims[Thisfn] != PVOID) 181 | error("missing value after 'return'", NULL); 182 | } 183 | genjump(Retlab); 184 | semi(); 185 | } 186 | 187 | /* 188 | * switch_stmt := 189 | * SWITCH ( expr ) { switch_block } 190 | * 191 | * switch_block := 192 | * switch_block_stmt 193 | * | switch_block_stmt switch_block 194 | * 195 | * switch_block_stmt := 196 | * CASE constexpr : 197 | * | DEFAULT : 198 | * | stmt 199 | */ 200 | 201 | static void switch_block(void) { 202 | int lb, ls, ldflt = 0; 203 | int cval[MAXCASE]; 204 | int clab[MAXCASE]; 205 | int nc = 0; 206 | 207 | Token = scan(); 208 | pushbrk(lb = label()); 209 | ls = label(); 210 | genjump(ls); 211 | while (RBRACE != Token) { 212 | if (eofcheck()) return; 213 | if ((CASE == Token || DEFAULT == Token) && nc >= MAXCASE) { 214 | error("too many 'case's in 'switch'", NULL); 215 | nc = 0; 216 | } 217 | if (CASE == Token) { 218 | Token = scan(); 219 | cval[nc] = constexpr(); 220 | genlab(clab[nc++] = label()); 221 | colon(); 222 | } 223 | else if (DEFAULT == Token) { 224 | Token = scan(); 225 | ldflt = label(); 226 | genlab(ldflt); 227 | colon(); 228 | } 229 | else 230 | stmt(); 231 | } 232 | if (!nc) { 233 | if (ldflt) { 234 | cval[nc] = 0; 235 | clab[nc++] = ldflt; 236 | } 237 | else 238 | error("empty switch", NULL); 239 | } 240 | genjump(lb); 241 | genlab(ls); 242 | genswitch(cval, clab, nc, ldflt? ldflt: lb); 243 | gentext(); 244 | genlab(lb); 245 | Token = scan(); 246 | Bsp--; 247 | } 248 | 249 | static void switch_stmt(void) { 250 | Token = scan(); 251 | lparen(); 252 | rexpr(); 253 | clear(); 254 | rparen(); 255 | if (Token != LBRACE) 256 | error("'{' expected after 'switch'", NULL); 257 | switch_block(); 258 | } 259 | 260 | /* 261 | * while_stmt := WHILE ( expr ) stmt 262 | */ 263 | 264 | static void while_stmt(void) { 265 | int lb, lc; 266 | 267 | Token = scan(); 268 | pushbrk(lb = label()); 269 | pushcont(lc = label()); 270 | genlab(lc); 271 | lparen(); 272 | rexpr(); 273 | clear(); 274 | genbrfalse(lb); 275 | rparen(); 276 | stmt(); 277 | genjump(lc); 278 | genlab(lb); 279 | Bsp--; 280 | Csp--; 281 | } 282 | 283 | void wrong_ctx(int t) { 284 | if (DEFAULT == t) { 285 | error("'default' not in 'switch' context", NULL); 286 | Token = scan(); 287 | colon(); 288 | } 289 | else { 290 | error("'case' not in 'switch' context", NULL); 291 | Token = scan(); 292 | constexpr(); 293 | colon(); 294 | } 295 | } 296 | 297 | /* 298 | * stmt := 299 | * break_stmt 300 | * | continue_stmt 301 | * | do_stmt 302 | * | for_stmt 303 | * | if_stmt 304 | * | return_stmt 305 | * | switch_stmt 306 | * | while_stmt 307 | * | compound 308 | * | ; 309 | * | expr ; 310 | */ 311 | 312 | static void stmt(void) { 313 | switch (Token) { 314 | case BREAK: break_stmt(); break; 315 | case CONTINUE: continue_stmt(); break; 316 | case DO: do_stmt(); break; 317 | case FOR: for_stmt(); break; 318 | case IF: if_stmt(); break; 319 | case RETURN: return_stmt(); break; 320 | case SWITCH: switch_stmt(); break; 321 | case WHILE: while_stmt(); break; 322 | case LBRACE: compound(1); break; 323 | case SEMI: Token = scan(); break; 324 | case DEFAULT: wrong_ctx(DEFAULT); break; 325 | case CASE: wrong_ctx(CASE); break; 326 | default: rexpr(); semi(); break; 327 | } 328 | clear(); 329 | } 330 | -------------------------------------------------------------------------------- /src/sym.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * Symbol table management 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | #include "cgen.h" 10 | 11 | int findglob(char *s) { 12 | int i; 13 | 14 | for (i=0; i= Locs && 71 | y < NSYMBOLS && 72 | CMEMBER == Stcls[y] 73 | ) { 74 | if (*s == *Names[y] && !strcmp(s, Names[y])) 75 | return y; 76 | y++; 77 | } 78 | return 0; 79 | } 80 | 81 | int newglob(void) { 82 | int p; 83 | 84 | if ((p = Globs++) >= Locs) 85 | fatal("too many global symbols"); 86 | return p; 87 | } 88 | 89 | int newloc(void) { 90 | int p; 91 | 92 | if ((p = --Locs) <= Globs) 93 | fatal("too many local symbols"); 94 | return p; 95 | } 96 | 97 | char *galloc(int k) { 98 | int p; 99 | 100 | if (Nbot + k >= Ntop) 101 | fatal("out of space for symbol names"); 102 | p = Nbot; 103 | Nbot += k; 104 | return &Nlist[p]; 105 | } 106 | 107 | char *globname(char *s) { 108 | char *p; 109 | 110 | p = galloc(strlen(s)+1); 111 | strcpy(p, s); 112 | return p; 113 | } 114 | 115 | char *locname(char *s) { 116 | int p, k; 117 | 118 | k = strlen(s) + 1; 119 | if (Nbot + k >= Ntop) 120 | fatal("out of space for symbol names"); 121 | Ntop -= k; 122 | p = Ntop; 123 | strcpy(&Nlist[p], s); 124 | return &Nlist[p]; 125 | } 126 | 127 | static void defglob(char *name, int prim, int type, int size, int val, 128 | int scls, int init) 129 | { 130 | if (TCONSTANT == type || TFUNCTION == type) return; 131 | gendata(); 132 | if (CPUBLIC == scls) genpublic(name); 133 | if (init && TARRAY == type) 134 | return; 135 | if (TARRAY != type && !(prim & STCMASK)) genname(name); 136 | if (prim & STCMASK) { 137 | if (TARRAY == type) 138 | genbss(gsym(name), objsize(prim, TARRAY, size)); 139 | else 140 | genbss(gsym(name), objsize(prim, TVARIABLE, size)); 141 | } 142 | else if (PCHAR == prim) { 143 | if (TARRAY == type) 144 | genbss(gsym(name), size); 145 | else { 146 | gendefb(val); 147 | genalign(1); 148 | } 149 | } 150 | else if (PINT == prim) { 151 | if (TARRAY == type) 152 | genbss(gsym(name), size*INTSIZE); 153 | else 154 | gendefw(val); 155 | } 156 | else { 157 | if (TARRAY == type) 158 | genbss(gsym(name), size*PTRSIZE); 159 | else 160 | gendefp(val); 161 | } 162 | } 163 | 164 | int redeclare(char *name, int oldcls, int newcls) { 165 | switch (oldcls) { 166 | case CEXTERN: 167 | if (newcls != CPUBLIC && newcls != CEXTERN) 168 | error("extern symbol redeclared static: %s", name); 169 | return newcls; 170 | case CPUBLIC: 171 | if (CEXTERN == newcls) 172 | return CPUBLIC; 173 | if (newcls != CPUBLIC) { 174 | error("extern symbol redeclared static: %s", name); 175 | return CPUBLIC; 176 | } 177 | break; 178 | case CSPROTO: 179 | if (newcls != CSTATIC && newcls != CSPROTO) 180 | error("static symbol redeclared extern: %s", name); 181 | return newcls; 182 | case CSTATIC: 183 | if (CSPROTO == newcls) 184 | return CSTATIC; 185 | if (newcls != CSTATIC) { 186 | error("static symbol redeclared extern: %s", name); 187 | return CSTATIC; 188 | } 189 | break; 190 | } 191 | error("redefined symbol: %s", name); 192 | return newcls; 193 | } 194 | 195 | int addglob(char *name, int prim, int type, int scls, int size, int val, 196 | char *mtext, int init) 197 | { 198 | int y; 199 | 200 | if ((y = findglob(name)) != 0) { 201 | scls = redeclare(name, Stcls[y], scls); 202 | if (TFUNCTION == Types[y]) 203 | mtext = Mtext[y]; 204 | } 205 | if (y == 0) { 206 | y = newglob(); 207 | Names[y] = globname(name); 208 | } 209 | else if (TFUNCTION == Types[y] || TMACRO == Types[y]) { 210 | if (Prims[y] != prim || Types[y] != type) 211 | error("redefinition does not match prior type: %s", 212 | name); 213 | } 214 | if (CPUBLIC == scls || CSTATIC == scls) 215 | defglob(name, prim, type, size, val, scls, init); 216 | Prims[y] = prim; 217 | Types[y] = type; 218 | Stcls[y] = scls; 219 | Sizes[y] = size; 220 | Vals[y] = val; 221 | Mtext[y] = mtext; 222 | return y; 223 | } 224 | 225 | static void defloc(int prim, int type, int size, int val, int init) { 226 | gendata(); 227 | if (type != TARRAY && !(prim &STCMASK)) genlab(val); 228 | if (prim & STCMASK) { 229 | if (TARRAY == type) 230 | genbss(labname(val), objsize(prim, TARRAY, size)); 231 | else 232 | genbss(labname(val), objsize(prim, TVARIABLE, size)); 233 | } 234 | else if (PCHAR == prim) { 235 | if (TARRAY == type) 236 | genbss(labname(val), size); 237 | else { 238 | gendefb(init); 239 | genalign(1); 240 | } 241 | } 242 | else if (PINT == prim) { 243 | if (TARRAY == type) 244 | genbss(labname(val), size*INTSIZE); 245 | else 246 | gendefw(init); 247 | } 248 | else { 249 | if (TARRAY == type) 250 | genbss(labname(val), size*PTRSIZE); 251 | else 252 | gendefp(init); 253 | } 254 | } 255 | 256 | int addloc(char *name, int prim, int type, int scls, int size, int val, 257 | int init) 258 | { 259 | int y; 260 | 261 | if (findloc(name)) 262 | error("redefinition of: %s", name); 263 | y = newloc(); 264 | if (CLSTATC == scls) defloc(prim, type, size, val, init); 265 | Names[y] = locname(name); 266 | Prims[y] = prim; 267 | Types[y] = type; 268 | Stcls[y] = scls; 269 | Sizes[y] = size; 270 | Vals[y] = val; 271 | return y; 272 | } 273 | 274 | void clrlocs(void) { 275 | Ntop = POOLSIZE; 276 | Locs = NSYMBOLS; 277 | } 278 | 279 | int objsize(int prim, int type, int size) { 280 | int k = 0, sp; 281 | 282 | sp = prim & STCMASK; 283 | if (PINT == prim) 284 | k = INTSIZE; 285 | else if (PCHAR == prim) 286 | k = CHARSIZE; 287 | else if (INTPTR == prim || CHARPTR == prim || VOIDPTR == prim) 288 | k = PTRSIZE; 289 | else if (INTPP == prim || CHARPP == prim || VOIDPP == prim) 290 | k = PTRSIZE; 291 | else if (STCPTR == sp || STCPP == sp) 292 | k = PTRSIZE; 293 | else if (UNIPTR == sp || UNIPP == sp) 294 | k = PTRSIZE; 295 | else if (PSTRUCT == sp || PUNION == sp) 296 | k = Sizes[prim & ~STCMASK]; 297 | else if (FUNPTR == prim) 298 | k = PTRSIZE; 299 | if (TFUNCTION == type || TCONSTANT == type || TMACRO == type) 300 | return 0; 301 | if (TARRAY == type) 302 | k *= size; 303 | return k; 304 | } 305 | 306 | static char *typename(int p) { 307 | switch (p & STCMASK) { 308 | case PSTRUCT: return "STRUCT"; 309 | case STCPTR: return "STCT*"; 310 | case STCPP: return "STCT**"; 311 | case PUNION: return "UNION"; 312 | case UNIPTR: return "UNIO*"; 313 | case UNIPP: return "UNIO**"; 314 | } 315 | return PINT == p? "INT": 316 | PCHAR == p? "CHAR": 317 | INTPTR == p? "INT*": 318 | CHARPTR == p? "CHAR*": 319 | VOIDPTR == p? "VOID*": 320 | FUNPTR == p? "FUN*": 321 | INTPP == p? "INT**": 322 | CHARPP == p? "CHAR**": 323 | VOIDPP == p? "VOID**": 324 | PVOID == p? "VOID": "n/a"; 325 | } 326 | 327 | void dumpsyms(char *title, char *sub, int from, int to) { 328 | int i; 329 | char *p; 330 | 331 | printf("\n===== %s%s =====\n", title, sub); 332 | printf( "PRIM TYPE STCLS SIZE VALUE NAME [MVAL]/(SIG)\n" 333 | "------ ---- ----- ----- ----- -----------------\n"); 334 | for (i = from; i < to; i++) { 335 | printf("%-6s %s %s %5d %5d %s", 336 | typename(Prims[i]), 337 | TVARIABLE == Types[i]? "VAR ": 338 | TARRAY == Types[i]? "ARRY": 339 | TFUNCTION == Types[i]? "FUN ": 340 | TCONSTANT == Types[i]? "CNST": 341 | TMACRO == Types[i]? "MAC ": 342 | TSTRUCT == Types[i]? "STCT": "n/a", 343 | CPUBLIC == Stcls[i]? "PUBLC": 344 | CEXTERN == Stcls[i]? "EXTRN": 345 | CSTATIC == Stcls[i]? "STATC": 346 | CSPROTO == Stcls[i]? "STATP": 347 | CLSTATC == Stcls[i]? "LSTAT": 348 | CAUTO == Stcls[i]? "AUTO ": 349 | CMEMBER == Stcls[i]? "MEMBR": "n/a ", 350 | Sizes[i], 351 | Vals[i], 352 | Names[i]); 353 | if (TMACRO == Types[i]) 354 | printf(" [\"%s\"]", Mtext[i]); 355 | if (TFUNCTION == Types[i]) { 356 | printf(" ("); 357 | for (p = Mtext[i]; *p; p++) { 358 | printf("%s", typename(*p)); 359 | if (p[1]) printf(", "); 360 | } 361 | putchar(')'); 362 | } 363 | putchar('\n'); 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/targets/cg386.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2011,2012 3 | * 386 target description 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | #include "cgen.h" 10 | 11 | void cgdata(void) { gen(".data"); } 12 | void cgtext(void) { gen(".text"); } 13 | void cgprelude(void) { } 14 | void cgpostlude(void) { } 15 | void cgpublic(char *s) { ngen(".globl\t%s", s, 0); } 16 | 17 | void cglit(int v) { ngen("%s\t$%d,%%eax", "movl", v); } 18 | void cgclear(void) { gen("xorl\t%eax,%eax"); } 19 | void cgldgb(char *s) { sgen("%s\t%s,%%al", "movb", s); } 20 | void cgldgw(char *s) { sgen("%s\t%s,%%eax", "movl", s); } 21 | void cgldlb(int n) { ngen("%s\t%d(%%ebp),%%al", "movb", n); } 22 | void cgldlw(int n) { ngen("%s\t%d(%%ebp),%%eax", "movl", n); } 23 | void cgldsb(int n) { lgen("%s\t%c%d,%%al", "movb", n); } 24 | void cgldsw(int n) { lgen("%s\t%c%d,%%eax", "movl", n); } 25 | void cgldla(int n) { ngen("%s\t%d(%%ebp),%%eax", "leal", n); } 26 | void cgldsa(int n) { lgen("%s\t$%c%d,%%eax", "movl", n); } 27 | void cgldga(char *s) { sgen("%s\t$%s,%%eax", "movl", s); } 28 | void cgindb(void) { gen("movl\t%eax,%edx"); 29 | cgclear(); 30 | gen("movb\t(%edx),%al"); } 31 | void cgindw(void) { gen("movl\t(%eax),%eax"); } 32 | void cgargc(void) { gen("movl\t8(%ebp),%eax"); } 33 | void cgldlab(int id) { lgen("%s\t$%c%d,%%eax", "movl", id); } 34 | 35 | void cgpush(void) { gen("pushl\t%eax"); } 36 | void cgpushlit(int n) { ngen("%s\t$%d", "pushl", n); } 37 | void cgpop2(void) { gen("popl\t%ecx"); } 38 | void cgswap(void) { gen("xchgl\t%eax,%ecx"); } 39 | 40 | void cgand(void) { gen("andl\t%ecx,%eax"); } 41 | void cgxor(void) { gen("xorl\t%ecx,%eax"); } 42 | void cgior(void) { gen("orl\t%ecx,%eax"); } 43 | void cgadd(void) { gen("addl\t%ecx,%eax"); } 44 | void cgmul(void) { gen("imull\t%ecx,%eax"); } 45 | void cgsub(void) { gen("subl\t%ecx,%eax"); } 46 | void cgdiv(void) { gen("cdq"); 47 | gen("idivl\t%ecx"); } 48 | void cgmod(void) { cgdiv(); 49 | gen("movl\t%edx,%eax"); } 50 | void cgshl(void) { gen("shll\t%cl,%eax"); } 51 | void cgshr(void) { gen("sarl\t%cl,%eax"); } 52 | void cgcmp(char *inst) { int lab; 53 | lab = label(); 54 | gen("xorl\t%edx,%edx"); 55 | cgpop2(); 56 | gen("cmpl\t%eax,%ecx"); 57 | lgen("%s\t%c%d", inst, lab); 58 | gen("incl\t%edx"); 59 | genlab(lab); 60 | gen("movl\t%edx,%eax"); } 61 | void cgeq() { cgcmp("jne"); } 62 | void cgne() { cgcmp("je"); } 63 | void cglt() { cgcmp("jge"); } 64 | void cggt() { cgcmp("jle"); } 65 | void cgle() { cgcmp("jg"); } 66 | void cgge() { cgcmp("jl"); } 67 | 68 | void cgneg(void) { gen("negl\t%eax"); } 69 | void cgnot(void) { gen("notl\t%eax"); } 70 | void cglognot(void) { gen("negl\t%eax"); 71 | gen("sbbl\t%eax,%eax"); 72 | gen("incl\t%eax"); } 73 | void cgscale(void) { gen("shll\t$2,%eax"); } 74 | void cgscale2(void) { gen("shll\t$2,%ecx"); } 75 | void cgunscale(void) { gen("shrl\t$2,%eax"); } 76 | void cgscaleby(int v) { ngen("%s\t$%d,%%ecx", "movl", v); 77 | gen("mull\t%ecx"); } 78 | void cgscale2by(int v) { gen("pushl\t%eax"); 79 | ngen("%s\t$%d,%%eax", "movl", v); 80 | gen("mull\t%ecx"); 81 | gen("movl\t%eax,%ecx"); 82 | gen("popl\t%eax"); } 83 | void cgunscaleby(int v) { ngen("%s\t$%d,%%ecx", "movl", v); 84 | gen("xorl\t%edx,%edx"); 85 | gen("div\t%ecx"); } 86 | void cgbool(void) { gen("negl\t%eax"); 87 | gen("sbbl\t%eax,%eax"); 88 | gen("negl\t%eax"); } 89 | 90 | void cgldinc(void) { gen("movl\t%eax,%edx"); } 91 | void cginc1pi(int v) { ngen("%s\t$%d,(%%eax)", "addl", v); } 92 | void cgdec1pi(int v) { ngen("%s\t$%d,(%%eax)", "subl", v); } 93 | void cginc2pi(int v) { ngen("%s\t$%d,(%%edx)", "addl", v); } 94 | void cgdec2pi(int v) { ngen("%s\t$%d,(%%edx)", "subl", v); } 95 | void cgincpl(int a, int v) { ngen2("%s\t$%d,%d(%%ebp)", "addl", v, a); } 96 | void cgdecpl(int a, int v) { ngen2("%s\t$%d,%d(%%ebp)", "subl", v, a); } 97 | void cgincps(int a, int v) { lgen2("addl\t$%d,%c%d", v, a); } 98 | void cgdecps(int a, int v) { lgen2("subl\t$%d,%c%d", v, a); } 99 | void cgincpg(char *s, int v) { sgen2("%s\t$%d,%s", "addl", v, s); } 100 | void cgdecpg(char *s, int v) { sgen2("%s\t$%d,%s", "subl", v, s); } 101 | void cginc1iw(void) { ngen("%s\t(%%eax)", "incl", 0); } 102 | void cgdec1iw(void) { ngen("%s\t(%%eax)", "decl", 0); } 103 | void cginc2iw(void) { ngen("%s\t(%%edx)", "incl", 0); } 104 | void cgdec2iw(void) { ngen("%s\t(%%edx)", "decl", 0); } 105 | void cginclw(int a) { ngen("%s\t%d(%%ebp)", "incl", a); } 106 | void cgdeclw(int a) { ngen("%s\t%d(%%ebp)", "decl", a); } 107 | void cgincsw(int a) { lgen("%s\t%c%d", "incl", a); } 108 | void cgdecsw(int a) { lgen("%s\t%c%d", "decl", a); } 109 | void cgincgw(char *s) { sgen("%s\t%s", "incl", s); } 110 | void cgdecgw(char *s) { sgen("%s\t%s", "decl", s); } 111 | void cginc1ib(void) { ngen("%s\t(%%eax)", "incb", 0); } 112 | void cgdec1ib(void) { ngen("%s\t(%%eax)", "decb", 0); } 113 | void cginc2ib(void) { ngen("%s\t(%%edx)", "incb", 0); } 114 | void cgdec2ib(void) { ngen("%s\t(%%edx)", "decb", 0); } 115 | void cginclb(int a) { ngen("%s\t%d(%%ebp)", "incb", a); } 116 | void cgdeclb(int a) { ngen("%s\t%d(%%ebp)", "decb", a); } 117 | void cgincsb(int a) { lgen("%s\t%c%d", "incb", a); } 118 | void cgdecsb(int a) { lgen("%s\t%c%d", "decb", a); } 119 | void cgincgb(char *s) { sgen("%s\t%s", "incb", s); } 120 | void cgdecgb(char *s) { sgen("%s\t%s", "decb", s); } 121 | 122 | void cgbr(char *how, int n) { int lab; 123 | lab = label(); 124 | gen("orl\t%eax,%eax"); 125 | lgen("%s\t%c%d", how, lab); 126 | lgen("%s\t%c%d", "jmp", n); 127 | genlab(lab); } 128 | void cgbrtrue(int n) { cgbr("jz", n); } 129 | void cgbrfalse(int n) { cgbr("jnz", n); } 130 | void cgjump(int n) { lgen("%s\t%c%d", "jmp", n); } 131 | void cgldswtch(int n) { lgen("%s\t$%c%d,%%edx", "movl", n); } 132 | void cgcalswtch(void) { gen("jmp\tswitch"); } 133 | void cgcase(int v, int l) { lgen2(".long\t%d,%c%d", v, l); } 134 | 135 | void cgpopptr(void) { gen("popl\t%edx"); } 136 | void cgstorib(void) { ngen("%s\t%%al,(%%edx)", "movb", 0); } 137 | void cgstoriw(void) { ngen("%s\t%%eax,(%%edx)", "movl", 0); } 138 | void cgstorlb(int n) { ngen("%s\t%%al,%d(%%ebp)", "movb", n); } 139 | void cgstorlw(int n) { ngen("%s\t%%eax,%d(%%ebp)", "movl", n); } 140 | void cgstorsb(int n) { lgen("%s\t%%al,%c%d", "movb", n); } 141 | void cgstorsw(int n) { lgen("%s\t%%eax,%c%d", "movl", n); } 142 | void cgstorgb(char *s) { sgen("%s\t%%al,%s", "movb", s); } 143 | void cgstorgw(char *s) { sgen("%s\t%%eax,%s", "movl", s); } 144 | 145 | void cginitlw(int v, int a) { ngen2("%s\t$%d,%d(%%ebp)", "movl", v, a); } 146 | void cgcall(char *s) { sgen("%s\t%s", "call", s); } 147 | void cgcalr(void) { gen("call\t*%eax"); } 148 | void cgstack(int n) { ngen("%s\t$%d,%%esp", "addl", n); } 149 | void cgentry(void) { gen("pushl\t%ebp"); 150 | gen("movl\t%esp,%ebp"); } 151 | void cgexit(void) { gen("popl\t%ebp"); 152 | gen("ret"); } 153 | 154 | void cgdefb(int v) { ngen("%s\t%d", ".byte", v); } 155 | void cgdefw(int v) { ngen("%s\t%d", ".long", v); } 156 | void cgdefp(int v) { ngen("%s\t%d", ".long", v); } 157 | void cgdefl(int v) { lgen("%s\t%c%d", ".long", v); } 158 | void cgdefc(int c) { ngen("%s\t'%c'", ".byte", c); } 159 | void cgbss(char *s, int z) { ngen(".lcomm\t%s,%d", s, z); } 160 | -------------------------------------------------------------------------------- /src/targets/cg386.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * 386 target description 4 | */ 5 | 6 | #define BPW 4 7 | -------------------------------------------------------------------------------- /src/targets/cgx86-64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * x86-64 target description 4 | */ 5 | 6 | #include "defs.h" 7 | #include "data.h" 8 | #include "decl.h" 9 | #include "cgen.h" 10 | 11 | void cgdata(void) { gen(".data"); } 12 | void cgtext(void) { gen(".text"); } 13 | void cgprelude(void) { } 14 | void cgpostlude(void) { } 15 | void cgpublic(char *s) { ngen(".globl\t%s", s, 0); } 16 | 17 | void cglit(int v) { ngen("%s\t$%d,%%rax", "movq", v); } 18 | void cgclear(void) { gen("xorq\t%rax,%rax"); } 19 | void cgldgb(char *s) { sgen("%s\t%s,%%al", "movb", s); } 20 | void cgldgw(char *s) { sgen("%s\t%s,%%rax", "movq", s); } 21 | void cgldlb(int n) { ngen("%s\t%d(%%rbp),%%al", "movb", n); } 22 | void cgldlw(int n) { ngen("%s\t%d(%%rbp),%%rax", "movq", n); } 23 | void cgldsb(int n) { lgen("%s\t%c%d,%%al", "movb", n); } 24 | void cgldsw(int n) { lgen("%s\t%c%d,%%rax", "movq", n); } 25 | void cgldla(int n) { ngen("%s\t%d(%%rbp),%%rax", "leaq", n); } 26 | void cgldsa(int n) { lgen("%s\t$%c%d,%%rax", "movq", n); } 27 | void cgldga(char *s) { sgen("%s\t$%s,%%rax", "movq", s); } 28 | void cgindb(void) { gen("movq\t%rax,%rdx"); 29 | cgclear(); 30 | gen("movb\t(%rdx),%al"); } 31 | void cgindw(void) { gen("movq\t(%rax),%rax"); } 32 | void cgargc(void) { gen("movq\t16(%rbp),%rax"); } 33 | void cgldlab(int id) { lgen("%s\t$%c%d,%%rax", "movq", id); } 34 | 35 | void cgpush(void) { gen("pushq\t%rax"); } 36 | void cgpushlit(int n) { ngen("%s\t$%d", "pushq", n); } 37 | void cgpop2(void) { gen("popq\t%rcx"); } 38 | void cgswap(void) { gen("xchgq\t%rax,%rcx"); } 39 | 40 | void cgand(void) { gen("andq\t%rcx,%rax"); } 41 | void cgxor(void) { gen("xorq\t%rcx,%rax"); } 42 | void cgior(void) { gen("orq\t%rcx,%rax"); } 43 | void cgadd(void) { gen("addq\t%rcx,%rax"); } 44 | void cgmul(void) { gen("imulq\t%rcx,%rax"); } 45 | void cgsub(void) { gen("subq\t%rcx,%rax"); } 46 | void cgdiv(void) { gen("cqo"); 47 | gen("idivq\t%rcx"); } 48 | void cgmod(void) { cgdiv(); 49 | gen("movq\t%rdx,%rax"); } 50 | void cgshl(void) { gen("shlq\t%cl,%rax"); } 51 | void cgshr(void) { gen("sarq\t%cl,%rax"); } 52 | void cgcmp(char *inst) { int lab; 53 | lab = label(); 54 | gen("xorq\t%rdx,%rdx"); 55 | cgpop2(); 56 | gen("cmpq\t%rax,%rcx"); 57 | lgen("%s\t%c%d", inst, lab); 58 | gen("incq\t%rdx"); 59 | genlab(lab); 60 | gen("movq\t%rdx,%rax"); } 61 | void cgeq() { cgcmp("jne"); } 62 | void cgne() { cgcmp("je"); } 63 | void cglt() { cgcmp("jge"); } 64 | void cggt() { cgcmp("jle"); } 65 | void cgle() { cgcmp("jg"); } 66 | void cgge() { cgcmp("jl"); } 67 | 68 | void cgneg(void) { gen("negq\t%rax"); } 69 | void cgnot(void) { gen("notq\t%rax"); } 70 | void cglognot(void) { gen("negq\t%rax"); 71 | gen("sbbq\t%rax,%rax"); 72 | gen("incq\t%rax"); } 73 | void cgscale(void) { gen("shlq\t$3,%rax"); } 74 | void cgscale2(void) { gen("shlq\t$3,%rcx"); } 75 | void cgunscale(void) { gen("shrq\t$3,%rax"); } 76 | void cgscaleby(int v) { ngen("%s\t$%d,%%rcx", "movq", v); 77 | gen("mulq\t%rcx,%rax"); } 78 | void cgscale2by(int v) { gen("pushq\t%rax"); 79 | ngen("%s\t$%d,%%rax", "movq", v); 80 | gen("mulq\t%rcx,%rax"); 81 | gen("movq\t%rax,%rcx"); 82 | gen("popq\t%rax"); } 83 | void cgunscaleby(int v) { ngen("%s\t$%d,%%rcx", "movq", v); 84 | gen("xorq\t%rdx,%rdx"); 85 | gen("divq\t%rcx"); } 86 | void cgbool(void) { gen("negq\t%rax"); 87 | gen("sbbq\t%rax,%rax"); 88 | gen("negq\t%rax"); } 89 | 90 | void cgldinc(void) { gen("movq\t%rax,%rdx"); } 91 | void cginc1pi(int v) { ngen("%s\t$%d,(%%rax)", "addq", v); } 92 | void cgdec1pi(int v) { ngen("%s\t$%d,(%%rax)", "subq", v); } 93 | void cginc2pi(int v) { ngen("%s\t$%d,(%%rdx)", "addq", v); } 94 | void cgdec2pi(int v) { ngen("%s\t$%d,(%%rdx)", "subq", v); } 95 | void cgincpl(int a, int v) { ngen2("%s\t$%d,%d(%%rbp)", "addq", v, a); } 96 | void cgdecpl(int a, int v) { ngen2("%s\t$%d,%d(%%rbp)", "subq", v, a); } 97 | void cgincps(int a, int v) { lgen2("addq\t$%d,%c%d", v, a); } 98 | void cgdecps(int a, int v) { lgen2("subq\t$%d,%c%d", v, a); } 99 | void cgincpg(char *s, int v) { sgen2("%s\t$%d,%s", "addq", v, s); } 100 | void cgdecpg(char *s, int v) { sgen2("%s\t$%d,%s", "subq", v, s); } 101 | void cginc1iw(void) { ngen("%s\t(%%rax)", "incq", 0); } 102 | void cgdec1iw(void) { ngen("%s\t(%%rax)", "decq", 0); } 103 | void cginc2iw(void) { ngen("%s\t(%%rdx)", "incq", 0); } 104 | void cgdec2iw(void) { ngen("%s\t(%%rdx)", "decq", 0); } 105 | void cginclw(int a) { ngen("%s\t%d(%%rbp)", "incq", a); } 106 | void cgdeclw(int a) { ngen("%s\t%d(%%rbp)", "decq", a); } 107 | void cgincsw(int a) { lgen("%s\t%c%d", "incq", a); } 108 | void cgdecsw(int a) { lgen("%s\t%c%d", "decq", a); } 109 | void cgincgw(char *s) { sgen("%s\t%s", "incq", s); } 110 | void cgdecgw(char *s) { sgen("%s\t%s", "decq", s); } 111 | void cginc1ib(void) { ngen("%s\t(%%rax)", "incb", 0); } 112 | void cgdec1ib(void) { ngen("%s\t(%%rax)", "decb", 0); } 113 | void cginc2ib(void) { ngen("%s\t(%%rdx)", "incb", 0); } 114 | void cgdec2ib(void) { ngen("%s\t(%%rdx)", "decb", 0); } 115 | void cginclb(int a) { ngen("%s\t%d(%%rbp)", "incb", a); } 116 | void cgdeclb(int a) { ngen("%s\t%d(%%rbp)", "decb", a); } 117 | void cgincsb(int a) { lgen("%s\t%c%d", "incb", a); } 118 | void cgdecsb(int a) { lgen("%s\t%c%d", "decb", a); } 119 | void cgincgb(char *s) { sgen("%s\t%s", "incb", s); } 120 | void cgdecgb(char *s) { sgen("%s\t%s", "decb", s); } 121 | 122 | void cgbr(char *how, int n) { int lab; 123 | lab = label(); 124 | gen("orq\t%rax,%rax"); 125 | lgen("%s\t%c%d", how, lab); 126 | lgen("%s\t%c%d", "jmp", n); 127 | genlab(lab); } 128 | void cgbrtrue(int n) { cgbr("jz", n); } 129 | void cgbrfalse(int n) { cgbr("jnz", n); } 130 | void cgjump(int n) { lgen("%s\t%c%d", "jmp", n); } 131 | void cgldswtch(int n) { lgen("%s\t$%c%d,%%rdx", "movq", n); } 132 | void cgcalswtch(void) { gen("jmp\tswitch"); } 133 | void cgcase(int v, int l) { lgen2(".quad\t%d,%c%d", v, l); } 134 | 135 | void cgpopptr(void) { gen("popq\t%rdx"); } 136 | void cgstorib(void) { ngen("%s\t%%al,(%%rdx)", "movb", 0); } 137 | void cgstoriw(void) { ngen("%s\t%%rax,(%%rdx)", "movq", 0); } 138 | void cgstorlb(int n) { ngen("%s\t%%al,%d(%%rbp)", "movb", n); } 139 | void cgstorlw(int n) { ngen("%s\t%%rax,%d(%%rbp)", "movq", n); } 140 | void cgstorsb(int n) { lgen("%s\t%%al,%c%d", "movb", n); } 141 | void cgstorsw(int n) { lgen("%s\t%%rax,%c%d", "movq", n); } 142 | void cgstorgb(char *s) { sgen("%s\t%%al,%s", "movb", s); } 143 | void cgstorgw(char *s) { sgen("%s\t%%rax,%s", "movq", s); } 144 | 145 | void cginitlw(int v, int a) { ngen2("%s\t$%d,%d(%%rbp)", "movq", v, a); } 146 | void cgcall(char *s) { sgen("%s\t%s", "call", s); } 147 | void cgcalr(void) { gen("call\t*%rax"); } 148 | void cgstack(int n) { ngen("%s\t$%d,%%rsp", "addq", n); } 149 | void cgentry(void) { gen("pushq\t%rbp"); 150 | gen("movq\t%rsp,%rbp"); } 151 | void cgexit(void) { gen("popq\t%rbp"); 152 | gen("ret"); } 153 | 154 | void cgdefb(int v) { ngen("%s\t%d", ".byte", v); } 155 | void cgdefw(int v) { ngen("%s\t%d", ".quad", v); } 156 | void cgdefp(int v) { ngen("%s\t%d", ".quad", v); } 157 | void cgdefl(int v) { lgen("%s\t%c%d", ".quad", v); } 158 | void cgdefc(int c) { ngen("%s\t'%c'", ".byte", c); } 159 | void cgbss(char *s, int z) { ngen(".lcomm\t%s,%d", s, z); } 160 | -------------------------------------------------------------------------------- /src/targets/cgx86-64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NMH's Simple C Compiler, 2012 3 | * 386 target description 4 | */ 5 | 6 | #define BPW 8 7 | -------------------------------------------------------------------------------- /src/targets/crt0-freebsd-386.s: -------------------------------------------------------------------------------- 1 | # 2 | # NMH's Simple C Compiler, 2011,2012 3 | # C runtime module for FreeBSD/386 4 | # 5 | 6 | .data 7 | .globl Cenviron 8 | Cenviron: 9 | .long 0 10 | 11 | .text 12 | .globl _start 13 | _start: call C_init 14 | leal 4(%esp),%esi # argv 15 | movl 0(%esp),%ecx # argc 16 | movl %ecx,%eax # environ = &argv[argc+1] 17 | incl %eax 18 | shll $2,%eax 19 | addl %esi,%eax 20 | movl %eax,Cenviron 21 | pushl %ecx 22 | pushl %esi 23 | pushl $2 # __argc 24 | call Cmain 25 | addl $12,%esp 26 | pushl %eax 27 | pushl $1 28 | x: call Cexit 29 | xorl %ebx,%ebx 30 | divl %ebx 31 | jmp x 32 | 33 | # internal switch(expr) routine 34 | # %esi = switch table, %eax = expr 35 | 36 | .globl switch 37 | switch: pushl %esi 38 | movl %edx,%esi 39 | movl %eax,%ebx 40 | cld 41 | lodsl 42 | movl %eax,%ecx 43 | next: lodsl 44 | movl %eax,%edx 45 | lodsl 46 | cmpl %edx,%ebx 47 | jnz no 48 | popl %esi 49 | jmp *%eax 50 | no: loop next 51 | lodsl 52 | popl %esi 53 | jmp *%eax 54 | 55 | # int setjmp(jmp_buf env); 56 | 57 | .globl Csetjmp 58 | Csetjmp: 59 | movl 8(%esp),%edx 60 | movl %esp,(%edx) 61 | movl (%esp),%eax 62 | movl %eax,4(%edx) 63 | xorl %eax,%eax 64 | ret 65 | 66 | # void longjmp(jmp_buf env, int v); 67 | 68 | .globl Clongjmp 69 | Clongjmp: 70 | movl 8(%esp),%eax 71 | movl 12(%esp),%edx 72 | movl (%edx),%esp 73 | movl 4(%edx),%edx 74 | jmp *%edx 75 | 76 | # int _exit(int rc); 77 | 78 | .globl C_exit 79 | C_exit: pushl 8(%esp) 80 | call _exit 81 | addl $4,%esp 82 | ret 83 | 84 | # int _sbrk(int size); 85 | 86 | .globl C_sbrk 87 | C_sbrk: pushl 8(%esp) 88 | call sbrk 89 | addl $4,%esp 90 | ret 91 | 92 | # int _write(int fd, char *buf, int len); 93 | 94 | .globl C_write 95 | C_write: 96 | pushl 8(%esp) 97 | pushl 16(%esp) 98 | pushl 24(%esp) 99 | call write 100 | addl $12,%esp 101 | ret 102 | 103 | # int _read(int fd, char *buf, int len); 104 | 105 | .globl C_read 106 | C_read: pushl 8(%esp) 107 | pushl 16(%esp) 108 | pushl 24(%esp) 109 | call read 110 | addl $12,%esp 111 | ret 112 | 113 | # int _lseek(int fd, int pos, int how); 114 | 115 | .globl C_lseek 116 | C_lseek: 117 | pushl 8(%esp) 118 | movl 16(%esp),%eax 119 | cdq 120 | pushl %edx # off_t, high word 121 | pushl %eax # off_t, low word 122 | pushl 28(%esp) 123 | call lseek 124 | addl $16,%esp 125 | ret 126 | 127 | # int _creat(char *path, int mode); 128 | 129 | .globl C_creat 130 | C_creat: 131 | pushl 8(%esp) 132 | pushl 16(%esp) 133 | call creat 134 | addl $8,%esp 135 | ret 136 | 137 | # int _open(char *path, int flags); 138 | 139 | .globl C_open 140 | C_open: pushl 8(%esp) 141 | pushl 16(%esp) 142 | call open 143 | addl $8,%esp 144 | ret 145 | 146 | # int _close(int fd); 147 | 148 | .globl C_close 149 | C_close: 150 | pushl 8(%esp) 151 | call close 152 | addl $4,%esp 153 | ret 154 | 155 | # int _unlink(char *path); 156 | 157 | .globl C_unlink 158 | C_unlink: 159 | pushl 8(%esp) 160 | call unlink 161 | addl $4,%esp 162 | ret 163 | 164 | # int _rename(char *old, char *new); 165 | 166 | .globl C_rename 167 | C_rename: 168 | pushl 8(%esp) 169 | pushl 16(%esp) 170 | call rename 171 | addl $8,%esp 172 | ret 173 | 174 | # int _fork(void); 175 | 176 | .globl C_fork 177 | C_fork: call fork 178 | ret 179 | 180 | # int _wait(int *rc); 181 | 182 | .globl C_wait 183 | C_wait: pushl 8(%esp) 184 | call wait 185 | addl $4,%esp 186 | ret 187 | 188 | # int _execve(char *path, char *argv[], char *envp[]); 189 | 190 | .globl C_execve 191 | C_execve: 192 | pushl 8(%esp) 193 | pushl 16(%esp) 194 | pushl 24(%esp) 195 | call execve 196 | addl $12,%esp 197 | ret 198 | 199 | # int _time(void); 200 | 201 | .globl C_time 202 | C_time: pushl $0 203 | call time 204 | addl $4,%esp 205 | ret 206 | 207 | # int raise(int sig); 208 | 209 | .globl Craise 210 | Craise: 211 | call getpid 212 | pushl 8(%esp) 213 | pushl %eax 214 | call kill 215 | addl $8,%esp 216 | ret 217 | 218 | # int signal(int sig, int (*fn)()); 219 | 220 | .globl Csignal 221 | Csignal: 222 | pushl 8(%esp) 223 | pushl 16(%esp) 224 | call signal 225 | addl $8,%esp 226 | ret 227 | -------------------------------------------------------------------------------- /src/targets/crt0-freebsd-x86-64.s: -------------------------------------------------------------------------------- 1 | # 2 | # NMH's Simple C Compiler, 2012 3 | # C runtime module for FreeBSD/x86-64 4 | # 5 | 6 | # FreeBSD voodoo stuff 7 | 8 | .section .note.ABI-tag,"a",@note 9 | .align 4 10 | abitag: .long 8, 4, 1 11 | .string "FreeBSD" 12 | .long 802000 13 | .p2align 2 14 | .data 15 | .globl __progname 16 | .globl environ 17 | environ: 18 | .quad 0 19 | __progname: 20 | .quad 0 21 | 22 | # End of voodoo stuff 23 | 24 | .data 25 | .globl Cenviron 26 | Cenviron: 27 | .quad 0 28 | 29 | .text 30 | .globl _start 31 | _start: pushq %rdi 32 | call C_init 33 | popq %rdi 34 | leaq 8(%rdi),%rsi # argv 35 | movq (%rdi),%rcx # argc 36 | movq %rcx,%rax # environ = &argv[argc+1] 37 | incq %rax 38 | shlq $3,%rax 39 | addq %rsi,%rax 40 | movq %rax,Cenviron 41 | pushq %rcx 42 | pushq %rsi 43 | pushq $2 # __argc 44 | call Cmain 45 | addq $24,%rsp 46 | pushq %rax 47 | pushq $1 48 | x: call Cexit 49 | xorq %rbx,%rbx 50 | divq %rbx 51 | jmp x 52 | 53 | # internal switch(expr) routine 54 | # %rsi = switch table, %rax = expr 55 | 56 | .globl switch 57 | switch: pushq %rsi 58 | movq %rdx,%rsi 59 | movq %rax,%rbx 60 | cld 61 | lodsq 62 | movq %rax,%rcx 63 | next: lodsq 64 | movq %rax,%rdx 65 | lodsq 66 | cmpq %rdx,%rbx 67 | jnz no 68 | popq %rsi 69 | jmp *%rax 70 | no: loop next 71 | lodsq 72 | popq %rsi 73 | jmp *%rax 74 | 75 | # int setjmp(jmp_buf env); 76 | 77 | .globl Csetjmp 78 | Csetjmp: 79 | movq 16(%rsp),%rdx 80 | movq %rsp,(%rdx) 81 | movq (%rsp),%rax 82 | movq %rax,8(%rdx) 83 | xorq %rax,%rax 84 | ret 85 | 86 | # void longjmp(jmp_buf env, int v); 87 | 88 | .globl Clongjmp 89 | Clongjmp: 90 | movq 16(%rsp),%rax 91 | movq 24(%rsp),%rdx 92 | movq (%rdx),%rsp 93 | movq 8(%rdx),%rdx 94 | jmp *%rdx 95 | 96 | # int _exit(int rc); 97 | 98 | .globl C_exit 99 | C_exit: movq 16(%rsp),%rdi 100 | call _exit 101 | ret 102 | 103 | # int _sbrk(int size); 104 | 105 | .globl C_sbrk 106 | C_sbrk: movq 16(%rsp),%rdi 107 | xorq %rax,%rax 108 | call sbrk 109 | ret 110 | 111 | # int _write(int fd, char *buf, int len); 112 | 113 | .globl C_write 114 | C_write: 115 | movq 16(%rsp),%rdx 116 | movq 24(%rsp),%rsi 117 | movq 32(%rsp),%rdi 118 | xorq %rax,%rax 119 | call write 120 | ret 121 | 122 | # int _read(int fd, char *buf, int len); 123 | 124 | .globl C_read 125 | C_read: movq 16(%rsp),%rdx 126 | movq 24(%rsp),%rsi 127 | movq 32(%rsp),%rdi 128 | xorq %rax,%rax 129 | call read 130 | ret 131 | 132 | # int _lseek(int fd, int pos, int how); 133 | 134 | .globl C_lseek 135 | C_lseek: 136 | movq 16(%rsp),%rdx 137 | movq 24(%rsp),%rsi 138 | movq 32(%rsp),%rdi 139 | xorq %rax,%rax 140 | call lseek 141 | ret 142 | 143 | # int _creat(char *path, int mode); 144 | 145 | .globl C_creat 146 | C_creat: 147 | movq 16(%rsp),%rsi 148 | movq 24(%rsp),%rdi 149 | xorq %rax,%rax 150 | call creat 151 | ret 152 | 153 | # int _open(char *path, int flags); 154 | 155 | .globl C_open 156 | C_open: movq 16(%rsp),%rsi 157 | movq 24(%rsp),%rdi 158 | xorq %rax,%rax 159 | call open 160 | ret 161 | 162 | # int _close(int fd); 163 | 164 | .globl C_close 165 | C_close: 166 | movq 16(%rsp),%rdi 167 | xorq %rax,%rax 168 | call close 169 | ret 170 | 171 | # int _unlink(char *path); 172 | 173 | .globl C_unlink 174 | C_unlink: 175 | movq 16(%rsp),%rdi 176 | xorq %rax,%rax 177 | call unlink 178 | ret 179 | 180 | # int _rename(char *old, char *new); 181 | 182 | .globl C_rename 183 | C_rename: 184 | movq 16(%rsp),%rsi 185 | movq 24(%rsp),%rdi 186 | xorq %rax,%rax 187 | call rename 188 | ret 189 | 190 | # int _fork(void); 191 | 192 | .globl C_fork 193 | C_fork: call fork 194 | ret 195 | 196 | # int _wait(int *rc); 197 | 198 | .data 199 | w: .long 0 200 | .text 201 | .globl C_wait 202 | C_wait: movq $w,%rdi 203 | xorq %rax,%rax 204 | call wait 205 | movl w,%eax 206 | cdq 207 | movq 16(%rsp),%rdx 208 | movq %rax,(%rdx) 209 | ret 210 | 211 | # int _execve(char *path, char *argv[], char *envp[]); 212 | 213 | .globl C_execve 214 | C_execve: 215 | movq 16(%rsp),%rdx 216 | movq 24(%rsp),%rsi 217 | movq 32(%rsp),%rdi 218 | xorq %rax,%rax 219 | call execve 220 | ret 221 | 222 | # int _time(void); 223 | 224 | .globl C_time 225 | C_time: xorq %rdi,%rdi 226 | xorq %rax,%rax 227 | call time 228 | ret 229 | 230 | # int raise(int sig); 231 | 232 | .globl Craise 233 | Craise: 234 | xorq %rax,%rax 235 | call getpid 236 | movq %rax,%rdi 237 | movq 16(%rsp),%rsi 238 | xorq %rax,%rax 239 | call kill 240 | ret 241 | 242 | # int signal(int sig, int (*fn)()); 243 | 244 | .globl Csignal 245 | Csignal: 246 | movq 16(%rsp),%rsi 247 | movq 24(%rsp),%rdi 248 | xorq %rax,%rax 249 | call signal 250 | ret 251 | -------------------------------------------------------------------------------- /src/targets/crt0-linux-386.s: -------------------------------------------------------------------------------- 1 | # 2 | # NMH's Simple C Compiler, 2011,2012 3 | # C runtime module for Linux/386 4 | # 5 | 6 | .data 7 | .globl Cenviron 8 | Cenviron: 9 | .long 0 10 | 11 | .text 12 | .globl _start 13 | _start: call C_init 14 | leal 4(%esp),%esi # argv 15 | movl 0(%esp),%ecx # argc 16 | movl %ecx,%eax # environ = &argv[argc+1] 17 | incl %eax 18 | shll $2,%eax 19 | addl %esi,%eax 20 | movl %eax,Cenviron 21 | pushl %ecx 22 | pushl %esi 23 | pushl $2 # __argc 24 | call Cmain 25 | addl $12,%esp 26 | pushl %eax 27 | pushl $1 28 | x: call Cexit 29 | xorl %ebx,%ebx 30 | divl %ebx 31 | jmp x 32 | 33 | # internal switch(expr) routine 34 | # %esi = switch table, %eax = expr 35 | 36 | .globl switch 37 | switch: pushl %esi 38 | movl %edx,%esi 39 | movl %eax,%ebx 40 | cld 41 | lodsl 42 | movl %eax,%ecx 43 | next: lodsl 44 | movl %eax,%edx 45 | lodsl 46 | cmpl %edx,%ebx 47 | jnz no 48 | popl %esi 49 | jmp *%eax 50 | no: loop next 51 | lodsl 52 | popl %esi 53 | jmp *%eax 54 | 55 | # int setjmp(jmp_buf env); 56 | 57 | .globl Csetjmp 58 | Csetjmp: 59 | movl 8(%esp),%edx 60 | movl %esp,(%edx) 61 | movl (%esp),%eax 62 | movl %eax,4(%edx) 63 | xorl %eax,%eax 64 | ret 65 | 66 | # void longjmp(jmp_buf env, int v); 67 | 68 | .globl Clongjmp 69 | Clongjmp: 70 | movl 8(%esp),%eax 71 | movl 12(%esp),%edx 72 | movl (%edx),%esp 73 | movl 4(%edx),%edx 74 | jmp *%edx 75 | 76 | # int _exit(int rc); 77 | 78 | .globl C_exit 79 | C_exit: movl 8(%esp),%ebx 80 | movl $1,%eax 81 | int $0x80 82 | ret 83 | 84 | # int _sbrk(int size); 85 | 86 | .data 87 | curbrk: .long 0 88 | 89 | .text 90 | .globl C_sbrk 91 | C_sbrk: 92 | # pushl 8(%esp) # this works, but will link 93 | # call sbrk # against GNU libc, which is a 94 | # addl $4,%esp # notorious source of trouble. 95 | # ret # 96 | cmpl $0,curbrk 97 | jnz sbrk 98 | xorl %ebx,%ebx # get break 99 | movl $45,%eax # brk 100 | int $0x80 101 | movl %eax,curbrk 102 | sbrk: cmpl $0,8(%esp) 103 | jnz setbrk 104 | mov curbrk,%eax # size==0, return break 105 | ret 106 | setbrk: movl curbrk,%ebx # set new break 107 | addl 8(%esp),%ebx 108 | movl $45,%eax # brk 109 | int $0x80 110 | cmpl %eax,curbrk # brk(x)==curbrk -> error 111 | jnz sbrkok 112 | movl $-1,%eax 113 | ret 114 | sbrkok: movl curbrk,%ebx # update curr. break 115 | movl %eax,curbrk 116 | movl %ebx,%eax 117 | ret 118 | 119 | # int _write(int fd, char *buf, int len); 120 | 121 | .globl C_write 122 | C_write: 123 | movl 8(%esp),%edx 124 | movl 12(%esp),%ecx 125 | movl 16(%esp),%ebx 126 | movl $4,%eax 127 | int $0x80 128 | ret 129 | 130 | # int _read(int fd, char *buf, int len); 131 | 132 | .globl C_read 133 | C_read: movl 8(%esp),%edx 134 | movl 12(%esp),%ecx 135 | movl 16(%esp),%ebx 136 | movl $3,%eax 137 | int $0x80 138 | ret 139 | 140 | # int _lseek(int fd, int pos, int how); 141 | 142 | .globl C_lseek 143 | C_lseek: 144 | movl 8(%esp),%edx 145 | movl 12(%esp),%ecx 146 | movl 16(%esp),%ebx 147 | movl $19,%eax 148 | int $0x80 149 | ret 150 | 151 | # int _creat(char *path, int mode); 152 | 153 | .globl C_creat 154 | C_creat: 155 | movl 8(%esp),%ecx 156 | movl 12(%esp),%ebx 157 | movl $8,%eax 158 | int $0x80 159 | ret 160 | 161 | # int _open(char *path, int flags); 162 | 163 | .globl C_open 164 | C_open: movl 8(%esp),%ecx 165 | movl 12(%esp),%ebx 166 | movl $5,%eax 167 | int $0x80 168 | ret 169 | 170 | # int _close(int fd); 171 | 172 | .globl C_close 173 | C_close: 174 | movl 8(%esp),%ebx 175 | movl $6,%eax 176 | int $0x80 177 | ret 178 | 179 | # int _unlink(char *path); 180 | 181 | .globl C_unlink 182 | C_unlink: 183 | movl 8(%esp),%ebx 184 | movl $10,%eax 185 | int $0x80 186 | ret 187 | 188 | # int _rename(char *old, char *new); 189 | 190 | .globl C_rename 191 | C_rename: 192 | movl 8(%esp),%ecx 193 | movl 12(%esp),%ebx 194 | mov $38,%eax 195 | int $0x80 196 | ret 197 | 198 | # int _fork(void); 199 | 200 | .globl C_fork 201 | C_fork: movl $2,%eax 202 | int $0x80 203 | ret 204 | 205 | # int _wait(int *rc); 206 | 207 | .globl C_wait 208 | C_wait: movl $-1,%ebx 209 | movl 8(%esp),%ecx 210 | xorl %edx,%edx 211 | movl $7,%eax 212 | int $0x80 213 | ret 214 | 215 | # int _execve(char *path, char *argv[], char *envp[]); 216 | 217 | .globl C_execve 218 | C_execve: 219 | movl 8(%esp),%edx 220 | movl 12(%esp),%ecx 221 | movl 16(%esp),%ebx 222 | movl $11,%eax 223 | int $0x80 224 | ret 225 | 226 | # int _time(void); 227 | 228 | .globl C_time 229 | C_time: xorl %ebx,%ebx 230 | movl $13,%eax 231 | int $0x80 232 | ret 233 | 234 | # int raise(int sig); 235 | 236 | .globl Craise 237 | Craise: 238 | movl $20,%eax 239 | int $0x80 240 | movl %eax,%ebx 241 | movl 8(%esp),%ecx 242 | movl $37,%eax 243 | int $0x80 244 | # int signal(int sig, int (*fn)()); 245 | 246 | .globl Csignal 247 | Csignal: 248 | movl 8(%esp),%ecx 249 | movl 12(%esp),%ebx 250 | movl $48,%eax 251 | int $0x80 252 | ret 253 | 254 | -------------------------------------------------------------------------------- /src/targets/crt0-netbsd-x86-64.s: -------------------------------------------------------------------------------- 1 | # 2 | # NMH's Simple C Compiler, 2012 3 | # C runtime module for NetBSD/x86-64 4 | # 5 | 6 | # NetBSD voodoo stuff 7 | 8 | .section ".note.netbsd.ident", "a" 9 | .long 7, 4, 1 10 | .ascii "NetBSD\0" 11 | .p2align 2 12 | .long 400000003 13 | .p2align 2 14 | .data 15 | .globl __progname 16 | .globl environ 17 | __progname: 18 | .quad 0 19 | environ: 20 | .quad 0 21 | 22 | # End of voodoo stuff 23 | 24 | .data 25 | .globl Cenviron 26 | Cenviron: 27 | .quad 0 28 | 29 | .text 30 | .globl _start 31 | _start: call C_init 32 | leaq 8(%rsp),%rsi # argv 33 | movq 0(%rsp),%rcx # argc 34 | movq %rcx,%rax # environ = &argv[argc+1] 35 | incq %rax 36 | shlq $3,%rax 37 | addq %rsi,%rax 38 | movq %rax,Cenviron 39 | pushq %rcx 40 | pushq %rsi 41 | pushq $2 # __argc 42 | call Cmain 43 | addq $24,%rsp 44 | pushq %rax 45 | pushq $1 46 | x: call Cexit 47 | xorq %rbx,%rbx 48 | divq %rbx 49 | jmp x 50 | 51 | # internal switch(expr) routine 52 | # %rsi = switch table, %rax = expr 53 | 54 | .globl switch 55 | switch: pushq %rsi 56 | movq %rdx,%rsi 57 | movq %rax,%rbx 58 | cld 59 | lodsq 60 | movq %rax,%rcx 61 | next: lodsq 62 | movq %rax,%rdx 63 | lodsq 64 | cmpq %rdx,%rbx 65 | jnz no 66 | popq %rsi 67 | jmp *%rax 68 | no: loop next 69 | lodsq 70 | popq %rsi 71 | jmp *%rax 72 | 73 | # int setjmp(jmp_buf env); 74 | 75 | .globl Csetjmp 76 | Csetjmp: 77 | movq 16(%rsp),%rdx 78 | movq %rsp,(%rdx) 79 | movq (%rsp),%rax 80 | movq %rax,8(%rdx) 81 | xorq %rax,%rax 82 | ret 83 | 84 | # void longjmp(jmp_buf env, int v); 85 | 86 | .globl Clongjmp 87 | Clongjmp: 88 | movq 16(%rsp),%rax 89 | movq 24(%rsp),%rdx 90 | movq (%rdx),%rsp 91 | movq 8(%rdx),%rdx 92 | jmp *%rdx 93 | 94 | # int _exit(int rc); 95 | 96 | .globl C_exit 97 | C_exit: movq 16(%rsp),%rdi 98 | call _exit 99 | ret 100 | 101 | # int _sbrk(int size); 102 | 103 | .globl C_sbrk 104 | C_sbrk: movq 16(%rsp),%rdi 105 | xorq %rax,%rax 106 | call sbrk 107 | ret 108 | 109 | # int _write(int fd, char *buf, int len); 110 | 111 | .globl C_write 112 | C_write: 113 | movq 16(%rsp),%rdx 114 | movq 24(%rsp),%rsi 115 | movq 32(%rsp),%rdi 116 | xorq %rax,%rax 117 | call write 118 | ret 119 | 120 | # int _read(int fd, char *buf, int len); 121 | 122 | .globl C_read 123 | C_read: movq 16(%rsp),%rdx 124 | movq 24(%rsp),%rsi 125 | movq 32(%rsp),%rdi 126 | xorq %rax,%rax 127 | call read 128 | ret 129 | 130 | # int _lseek(int fd, int pos, int how); 131 | 132 | .globl C_lseek 133 | C_lseek: 134 | movq 16(%rsp),%rdx 135 | movq 24(%rsp),%rsi 136 | movq 32(%rsp),%rdi 137 | xorq %rax,%rax 138 | call lseek 139 | ret 140 | 141 | # int _creat(char *path, int mode); 142 | 143 | .globl C_creat 144 | C_creat: 145 | movq 16(%rsp),%rsi 146 | movq 24(%rsp),%rdi 147 | xorq %rax,%rax 148 | call creat 149 | ret 150 | 151 | # int _open(char *path, int flags); 152 | 153 | .globl C_open 154 | C_open: movq 16(%rsp),%rsi 155 | movq 24(%rsp),%rdi 156 | xorq %rax,%rax 157 | call open 158 | ret 159 | 160 | # int _close(int fd); 161 | 162 | .globl C_close 163 | C_close: 164 | movq 16(%rsp),%rdi 165 | xorq %rax,%rax 166 | call close 167 | ret 168 | 169 | # int _unlink(char *path); 170 | 171 | .globl C_unlink 172 | C_unlink: 173 | movq 16(%rsp),%rdi 174 | xorq %rax,%rax 175 | call unlink 176 | ret 177 | 178 | # int _rename(char *old, char *new); 179 | 180 | .globl C_rename 181 | C_rename: 182 | movq 16(%rsp),%rsi 183 | movq 24(%rsp),%rdi 184 | xorq %rax,%rax 185 | call rename 186 | ret 187 | 188 | # int _fork(void); 189 | 190 | .globl C_fork 191 | C_fork: call fork 192 | ret 193 | 194 | # int _wait(int *rc); 195 | 196 | .data 197 | w: .long 0 198 | .text 199 | .globl C_wait 200 | C_wait: movq $w,%rdi 201 | xorq %rax,%rax 202 | call wait 203 | movl w,%eax 204 | cdq 205 | movq 16(%rsp),%rdx 206 | movq %rax,(%rdx) 207 | ret 208 | 209 | # int _execve(char *path, char *argv[], char *envp[]); 210 | 211 | .globl C_execve 212 | C_execve: 213 | movq 16(%rsp),%rdx 214 | movq 24(%rsp),%rsi 215 | movq 32(%rsp),%rdi 216 | xorq %rax,%rax 217 | call execve 218 | ret 219 | 220 | # int _time(void); 221 | 222 | .globl C_time 223 | C_time: xorq %rdi,%rdi 224 | xorq %rax,%rax 225 | call time 226 | ret 227 | 228 | # int raise(int sig); 229 | 230 | .globl Craise 231 | Craise: 232 | xorq %rax,%rax 233 | call getpid 234 | movq %rax,%rdi 235 | movq 16(%rsp),%rsi 236 | xorq %rax,%rax 237 | call kill 238 | ret 239 | 240 | # int signal(int sig, int (*fn)()); 241 | 242 | .globl Csignal 243 | Csignal: 244 | movq 16(%rsp),%rsi 245 | movq 24(%rsp),%rdi 246 | xorq %rax,%rax 247 | call signal 248 | ret 249 | --------------------------------------------------------------------------------