├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── selfhost.sh ├── src ├── cc │ ├── cc.h │ ├── cpp.c │ ├── error.c │ ├── foldexpr.c │ ├── lex.c │ ├── parse.c │ └── types.c ├── cmd │ ├── 6c │ │ ├── emit.c │ │ ├── frontend.c │ │ └── main.c │ ├── abifuzz │ │ └── main.c │ └── cpp │ │ └── main.c ├── ds │ ├── ds.h │ ├── list.c │ ├── map.c │ ├── strset.c │ └── vec.c ├── mem │ ├── mem.c │ └── mem.h ├── panic.c ├── selfhost │ ├── README │ ├── stdarg.h │ ├── stdint.h │ ├── stdio.h │ ├── stdlib.h │ └── string.h └── u.h ├── test.sh └── test ├── LICENSE ├── bugs ├── 0001.c ├── 0002.c ├── 0004.c ├── 0005.c ├── 0006.c ├── 0008.c ├── 0012.c ├── 0013.c.disabled ├── 0014.c.disabled ├── 0015.c ├── 0017.c ├── 0018.c ├── 0019.c.disabled ├── 0020.c └── 0021.c ├── cpp ├── 0001-define1.c ├── 0001-define2.c └── 0001-define3.c ├── cpperror ├── 0001-define1.c ├── 0001-define2.c └── 0001-define3.c ├── error ├── 0001-undefined1.c ├── 0002-redefinition1.c ├── 0002-redefinition2.c ├── 0002-redefinition3.c ├── 0002-redefinition4.c ├── 0003-lval1.c ├── 0003-lval2.c ├── 0003-lval3.c ├── 0004-tags1.c ├── 0004-tags2.c ├── 0004-tags3.c ├── 0004-tags4.c ├── 0004-tags5.c ├── 0005-incomplete1.c ├── 0005-incomplete2.c ├── 0006-inits1.c ├── 0006-inits2.c ├── 0006-inits3.c ├── 0006-inits4.c └── 0006-inits5.c └── execute ├── 0001-sanity.c ├── 0002-global1.c ├── 0003-locals1.c ├── 0004-operators1.c ├── 0004-operators2.c ├── 0004-operators3.c ├── 0004-operators4.c ├── 0004-operators5.c ├── 0005-if1.c ├── 0006-while1.c ├── 0007-dowhile1.c ├── 0008-for1.c ├── 0009-breakcont1.c ├── 0010-goto1.c ├── 0011-switch1.c ├── 0012-pointers1.c ├── 0012-pointers2.c ├── 0013-struct1.c ├── 0013-struct2.c ├── 0013-struct3.c ├── 0013-struct4.c ├── 0013-struct5.c ├── 0013-struct6.c ├── 0014-array1.c ├── 0015-calls01.c ├── 0015-calls02.c ├── 0015-calls03.c ├── 0015-calls04.c ├── 0015-calls05.c.disabled ├── 0015-calls06.c.disabled ├── 0015-calls07.c.disabled ├── 0015-calls08.c.disabled ├── 0015-calls09.c.disabled ├── 0015-calls10.c.disabled ├── 0015-calls11.c.disabled ├── 0015-calls12.c.disabled ├── 0015-calls13.c.disabled ├── 0016-string1.c ├── 0017-incdec1.c ├── 0018-funcptr1.c ├── 0019-condexpr1.c ├── 0020-comma1.c ├── 0020-comma2.c ├── 0021-tentativedefs1.c ├── 0022-namespaces1.c ├── 0023-incomplete1.c ├── 0024-enums1.c ├── 0025-duff.c ├── 0026-sizeof1.c ├── 0027-structcopy.c ├── 0028-inits01.c ├── 0028-inits02.c ├── 0028-inits03.c ├── 0028-inits04.c ├── 0028-inits05.c ├── 0028-inits06.c ├── 0028-inits07.c ├── 0028-inits08.c ├── 0028-inits09.c ├── 0028-inits10.c ├── 0028-inits11.c ├── 0028-inits12.c ├── 0028-inits13.c ├── 0028-inits14.c ├── 0028-inits15.c ├── 0029-ptrarith1.c └── 0029-ptrarith2.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | test/*/*.bin 3 | test/*/*.s 4 | test/*/*.stderr 5 | bin/* 6 | lib/* 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Andrew Chambers 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS = -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE 3 | 4 | # NOTE if one of these headers does not exist, the wildcard rule fails. 5 | HFILES = src/u.h src/cc/cc.h src/ds/ds.h src/mem/mem.h 6 | CCO = src/cc/cpp.o \ 7 | src/cc/lex.o \ 8 | src/cc/parse.o \ 9 | src/cc/types.o \ 10 | src/cc/foldexpr.o \ 11 | src/cc/error.o 12 | GCO = src/mem/mem.o 13 | DSO = src/ds/list.o \ 14 | src/ds/map.o \ 15 | src/ds/vec.o \ 16 | src/ds/strset.o 17 | LIBO = src/panic.o $(CCO) $(GCO) $(DSO) 18 | LIBA = lib/libcompiler.a 19 | CPPO = src/cmd/cpp/main.o 20 | _6CO = src/cmd/6c/emit.o \ 21 | src/cmd/6c/frontend.o \ 22 | src/cmd/6c/main.o 23 | ABIFZO = src/cmd/abifuzz/main.o 24 | all: bin/6c \ 25 | bin/cpp \ 26 | bin/abifuzz 27 | 28 | .PHONY: all clean test selfhost 29 | 30 | test: 31 | make clean 32 | make all 33 | ./test.sh 34 | 35 | selfhost: 36 | make clean 37 | make all 38 | ./test.sh 39 | ./selfhost.sh 40 | mv ./bin/selfhosted ./bin/6c 41 | ./test.sh 42 | ./selfhost.sh 43 | mv ./bin/selfhosted ./bin/6c 44 | ./test.sh 45 | ./selfhost.sh 46 | mv ./bin/selfhosted ./bin/6c 47 | ./test.sh 48 | 49 | .c.o: $(HFILES) 50 | $(CC) $(CFLAGS) -Isrc/ -o $@ -c $< 51 | 52 | bin/6c: $(_6CO) $(LIBA) 53 | @ mkdir -p bin 54 | $(CC) $(LDFLAGS) $(_6CO) $(LIBA) -o $@ 55 | 56 | bin/cpp: $(CPPO) $(LIBA) 57 | @ mkdir -p bin 58 | $(CC) $(LDFLAGS) $(CPPO) $(LIBA) -o $@ 59 | 60 | bin/abifuzz: $(ABIFZO) $(LIBA) 61 | @ mkdir -p bin 62 | $(CC) $(LDFLAGS) $(ABIFZO) $(LIBA) -o $@ 63 | 64 | $(LIBA): $(LIBO) 65 | @ mkdir -p lib 66 | $(AR) rcs $(LIBA) $(LIBO) 67 | 68 | clean: 69 | rm -rf $(LIBO) $(CPPO) $(_6CO) $(ABIFZO) lib bin 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A small, fast C compiler suite. 2 | 3 | NOTE - This project is not being actively developed. Please direct yourself to https://github.com/michaelforney/cc which 4 | is a successor that is more complete. I direct my own fixes to that project instead now. 5 | 6 | [![Join the chat at https://gitter.im/andrewchambers/c](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/andrewchambers/c?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | 8 | - Small. 9 | - Fast. 10 | - Consistent. 11 | - High quality. 12 | - Low complexity. 13 | - No dependencies. 14 | - No fussy configuration. 15 | - Painless cross compiling. 16 | - Just work. 17 | 18 | You should be able to get a C compiler, assembler, linker and libc for any 19 | supported target in less than 30 seconds. 20 | 21 | ## Building 22 | 23 | Requires an external C compiler and gnu binutils (for now), and I have only tested 24 | it on linux 64 bit so far. 25 | 26 | The code does use anonymous union extensions, so your compiler will need to support them too. 27 | 28 | ``` 29 | $ make 30 | ``` 31 | 32 | ## Testing 33 | ``` 34 | $ make test 35 | $ make selfhost # self hosting 36 | ``` 37 | 38 | ## Plan 39 | 40 | ### Stage 1. 41 | 42 | Self hosting x86_64, dumb backend. 43 | 44 | ### Stage 2. 45 | 46 | Self hosting arm, something like raspberry pi/android. 47 | 48 | ### Stage 3. 49 | 50 | Build small clean C code bases like 8cc, tcc, sbase. 51 | 52 | ### Stage 4. 53 | 54 | Build musl libc. 55 | 56 | ### Beyond. 57 | 58 | - Build more programs. 59 | - Replace gnu as with our own assembler. 60 | - Replace ld with our own static linker. 61 | - Build OS kernels. 62 | - SSA backend. 63 | 64 | ## Status 65 | 66 | Pre stage 2. Self hosting with lots of missing common cases. Though technically these 67 | bugs can be fixed with the compiler itself :). It uses it's own stubbed out headers 68 | and cannot correctly process system headers yet (Help wanted). 69 | 70 | 71 | ## Contributing 72 | 73 | Project on hold. See https://github.com/michaelforney/cc for a new compiler project that is more complete. 74 | 75 | ### Code layout 76 | 77 | - Libraries are in src/* 78 | - Commands are in src/cmd/* 79 | 80 | If you are unsure about the purpose of a library, check the header which 81 | should give a short description. 82 | 83 | ### Code style 84 | 85 | Follow Plan9 style conventions. Headers are not allowed to include 86 | other headers to eliminate circular dependencies and increase build speed. 87 | src/u.h is the only exception to this rule. 88 | 89 | - http://www.lysator.liu.se/c/pikestyle.html 90 | - http://plan9.bell-labs.com/magic/man2html/6/style 91 | - http://aiju.de/b/style 92 | 93 | ### Bug fixes and issues 94 | 95 | Try and attach a single source file which exibits your issue. If possible 96 | reduce the test case by hand until it is as small as possible. 97 | 98 | Try and follow the general template changed where needed: 99 | ``` 100 | What are you trying to do: 101 | ... 102 | What you expected to happen: 103 | ... 104 | What actually hapened: 105 | ... 106 | ``` 107 | Try and add a small self contained file which reproduces the issue. 108 | 109 | In general each bug fix or change should add a test file which triggers the bug. 110 | 111 | ### Memory management 112 | 113 | The compiler does not explicitly free memory. Peak memory usage while self hosting 114 | is approximately 2Mb, so it should not be an issue, even for planned targets/hosts like 115 | the raspberry pi. 116 | 117 | This actually simplifies the code and probably makes it faster because allocations can be pointer bumps. 118 | 119 | ## Useful Links 120 | 121 | - C11 standard final draft http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 122 | - Dave Prosser's C Preprocessing Algorithm http://www.spinellis.gr/blog/20060626/ 123 | - The x86-64 ABI http://www.x86-64.org/documentation/abi.pdf 124 | - http://aiju.de/rant/cross-compiling 125 | - http://bellard.org/tcc/ 126 | - https://github.com/rui314/8cc 127 | - http://harmful.cat-v.org/software/ 128 | - http://suckless.org/philosophy 129 | 130 | -------------------------------------------------------------------------------- /selfhost.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | SELFHOSTSRC="src/cc/cpp.c 6 | src/cc/error.c 7 | src/cc/foldexpr.c 8 | src/cc/lex.c 9 | src/cc/parse.c 10 | src/cc/types.c 11 | src/cmd/6c/emit.c 12 | src/cmd/6c/frontend.c 13 | src/cmd/6c/main.c 14 | src/ds/list.c 15 | src/ds/map.c 16 | src/ds/strset.c 17 | src/ds/vec.c 18 | src/mem/mem.c 19 | src/panic.c" 20 | SELFHOSTOBJDIR=lib/selfhostobj 21 | mkdir -p lib/selfhostobj 22 | 23 | for C in $SELFHOSTSRC 24 | do 25 | O=$SELFHOSTOBJDIR/`basename $C .c`.o 26 | S=$SELFHOSTOBJDIR/`basename $C .c`.s 27 | bin/6c -I src -I src/selfhost -I `dirname $C` $C > $S 28 | gcc -c $S -o $O 29 | done 30 | 31 | mkdir -p bin/ 32 | gcc $SELFHOSTOBJDIR/*.o -o bin/selfhosted 33 | -------------------------------------------------------------------------------- /src/cc/cc.h: -------------------------------------------------------------------------------- 1 | /* Provides the preprocessor, compiler frontend. It also 2 | contains the interface the c compilers implement. */ 3 | 4 | typedef struct SrcPos SrcPos; 5 | typedef struct StructMember StructMember; 6 | typedef struct StructExport StructExport; 7 | typedef struct StructIter StructIter; 8 | typedef struct ExportPath ExportPath; 9 | typedef struct NameTy NameTy; 10 | typedef struct CTy CTy; 11 | typedef struct Sym Sym; 12 | typedef struct StkSlot StkSlot; 13 | typedef struct Node Node; 14 | typedef struct Lexer Lexer; 15 | 16 | /* Token types */ 17 | typedef enum { 18 | TOKADD = '+', 19 | TOKSUB = '-', 20 | TOKMUL = '*', 21 | TOKMOD = '%', 22 | TOKDIV = '/', 23 | TOKNOT = '!', 24 | TOKBNOT = '~', 25 | TOKGT = '>', 26 | TOKLT = '<', 27 | TOKASS = '=', 28 | TOKQUES = '?', 29 | TOKLBRACK = '[', 30 | TOKRBRACK = ']', 31 | TOKBAND = '&', 32 | TOKBOR = '|', 33 | TOKLBRACE = '{', 34 | TOKRBRACE = '}', 35 | TOKSEMI = ';', 36 | TOKLPAREN = '(', 37 | TOKRPAREN = ')', 38 | TOKDOT = '.', 39 | TOKCOLON = ':', 40 | TOKXOR = '^', 41 | TOKSTAR = '*', 42 | TOKCOMMA = ',', 43 | TOKBSLASH = '\\', 44 | TOKHASH = '#', 45 | TOKNUM = 256, 46 | TOKIDENT, 47 | TOKHEADER, 48 | TOKIF, 49 | TOKDO, 50 | TOKFOR, 51 | TOKWHILE, 52 | TOKRETURN, 53 | TOKINC, 54 | TOKDEC, 55 | TOKADDASS, 56 | TOKSUBASS, 57 | TOKMULASS, 58 | TOKDIVASS, 59 | TOKMODASS, 60 | TOKORASS, 61 | TOKANDASS, 62 | TOKEQL, 63 | TOKVOID, 64 | TOKCHAR, 65 | TOKCHARLIT, 66 | TOKINT, 67 | TOKELSE, 68 | TOKVOLATILE, 69 | TOKCONST, 70 | TOKLOR, 71 | TOKLAND, 72 | TOKNEQ, 73 | TOKLEQ, 74 | TOKGEQ, 75 | TOKSHL, 76 | TOKSHR, 77 | TOKARROW, 78 | TOKSTR, 79 | TOKTYPEDEF, 80 | TOKSIGNED, 81 | TOKUNSIGNED, 82 | TOKSHORT, 83 | TOKLONG, 84 | TOKSIZEOF, 85 | TOKFLOAT, 86 | TOKDOUBLE, 87 | TOKSTRUCT, 88 | TOKUNION, 89 | TOKGOTO, 90 | TOKSWITCH, 91 | TOKCASE, 92 | TOKDEFAULT, 93 | TOKCONTINUE, 94 | TOKBREAK, 95 | TOKREGISTER, 96 | TOKEXTERN, 97 | TOKSTATIC, 98 | TOKAUTO, 99 | TOKENUM, 100 | TOKELLIPSIS, 101 | TOKHASHHASH, 102 | TOKDIRSTART, 103 | TOKDIREND, 104 | TOKEOF /* EOF needs to be the last. */ 105 | } Tokkind; 106 | 107 | /* Storage classes */ 108 | typedef enum { 109 | SCNONE, 110 | SCEXTERN, 111 | SCSTATIC, 112 | SCREGISTER, 113 | SCGLOBAL, 114 | SCTYPEDEF, 115 | SCAUTO 116 | } Sclass; 117 | 118 | struct SrcPos { 119 | char *file; 120 | int line; 121 | int col; 122 | }; 123 | 124 | typedef enum { 125 | CVOID, 126 | CPRIM, 127 | CSTRUCT, 128 | CARR, 129 | CPTR, 130 | CFUNC, 131 | CENUM, 132 | } Ctypekind; 133 | 134 | typedef enum { 135 | PRIMCHAR, 136 | PRIMSHORT, 137 | PRIMINT, 138 | PRIMLONG, 139 | PRIMLLONG, 140 | PRIMFLOAT, 141 | PRIMDOUBLE, 142 | PRIMLDOUBLE 143 | } Primkind; 144 | 145 | struct StructMember { 146 | int offset; 147 | char *name; 148 | CTy *type; 149 | }; 150 | 151 | struct NameTy { 152 | char *name; 153 | CTy *type; 154 | }; 155 | 156 | struct StructIter { 157 | CTy *root; 158 | int depth; 159 | int path[1024]; 160 | }; 161 | 162 | struct ExportPath { 163 | int idx; 164 | ExportPath *next; 165 | }; 166 | 167 | struct StructExport { 168 | char *name; 169 | ExportPath *path; 170 | }; 171 | 172 | struct CTy { 173 | Ctypekind t; 174 | int size; 175 | int align; 176 | int incomplete; 177 | union { 178 | struct { 179 | CTy *rtype; 180 | Vec *params; /* Vec of *NameTy */ 181 | int isvararg; 182 | } Func; 183 | struct { 184 | int isunion; 185 | char *name; 186 | Vec *members; 187 | Vec *exports; 188 | } Struct; 189 | struct { 190 | Vec *members; 191 | } Enum; 192 | struct { 193 | CTy *subty; 194 | } Ptr; 195 | struct { 196 | CTy *subty; 197 | int dim; 198 | } Arr; 199 | struct { 200 | int issigned; 201 | int type; 202 | } Prim; 203 | }; 204 | }; 205 | 206 | /* node types */ 207 | typedef enum { 208 | NASSIGN, 209 | NFUNC, 210 | NLABELED, 211 | NWHILE, 212 | NDOWHILE, 213 | NFOR, 214 | NBINOP, 215 | NBLOCK, 216 | NUNOP, 217 | NCAST, 218 | NCASE, 219 | NCOMMA, 220 | NCOND, 221 | NINIT, 222 | NRETURN, 223 | NSWITCH, 224 | NGOTO, 225 | NIDENT, 226 | NNUM, 227 | NSTR, 228 | NIDX, 229 | NINCDEC, 230 | NPTRADD, 231 | NSEL, 232 | NCALL, 233 | NSIZEOF, 234 | NIF, 235 | NDECL, 236 | NEXPRSTMT, 237 | NBUILTIN 238 | } Nodekind; 239 | 240 | typedef struct { 241 | int offset; 242 | Node *n; 243 | } InitMember; 244 | 245 | typedef enum { 246 | BUILTIN_VASTART 247 | } Builtinkind; 248 | 249 | struct Node { 250 | /* type tag, one of the N* types */ 251 | Nodekind t; 252 | SrcPos pos; 253 | CTy *type; 254 | union { 255 | struct { 256 | int localsz; 257 | char *name; 258 | Node *body; 259 | Vec *params; /* list of *Sym */ 260 | Vec *stkslots; /* list of *Stkslot */ 261 | } Func; 262 | struct { 263 | Vec *syms; 264 | } Decl; 265 | struct { 266 | char *lelse; 267 | Node *expr; 268 | Node *iftrue; 269 | Node *iffalse; 270 | } If; 271 | struct { 272 | Node *cond; 273 | Node *iftrue; 274 | Node *iffalse; 275 | } Cond; 276 | struct { 277 | char *lstart; 278 | char *lstep; 279 | char *lend; 280 | Node *init; 281 | Node *cond; 282 | Node *step; 283 | Node *stmt; 284 | } For; 285 | struct { 286 | char *lstart; 287 | char *lcond; 288 | char *lend; 289 | Node *stmt; 290 | Node *expr; 291 | } DoWhile; 292 | struct { 293 | char *lstart; 294 | char *lend; 295 | Node *expr; 296 | Node *stmt; 297 | } While; 298 | struct { 299 | char *lend; 300 | char *ldefault; 301 | Node *expr; 302 | Node *stmt; 303 | Vec *cases; 304 | } Switch; 305 | struct { 306 | char *l; 307 | int64 cond; 308 | Node *stmt; 309 | } Case; 310 | struct { 311 | char *l; 312 | Node *stmt; 313 | } Labeled; 314 | struct { 315 | Node *expr; 316 | } Return; 317 | struct { 318 | Vec *exprs; 319 | } Comma; 320 | struct { 321 | Vec *stmts; 322 | } Block; 323 | struct { 324 | int op; 325 | Node *l; 326 | Node *r; 327 | } Binop; 328 | struct { 329 | int op; 330 | Node *l; 331 | Node *r; 332 | } Assign; 333 | struct { 334 | int op; 335 | Node *operand; 336 | } Unop; 337 | struct { 338 | int op; 339 | int post; 340 | Node *operand; 341 | } Incdec; 342 | struct { 343 | Node *ptr; 344 | Node *offset; 345 | } Ptradd; 346 | struct { 347 | Node *operand; 348 | } Cast; 349 | struct { 350 | Vec *inits; 351 | } Init; 352 | struct { 353 | int64 v; 354 | } Num; 355 | struct { 356 | char *v; 357 | } Str; 358 | struct { 359 | char *l; 360 | char *name; 361 | } Goto; 362 | struct { 363 | Sym *sym; 364 | } Ident; 365 | struct { 366 | Node *idx; 367 | Node *operand; 368 | } Idx; 369 | struct { 370 | int arrow; 371 | char *name; 372 | Node *operand; 373 | } Sel; 374 | struct { 375 | Node *expr; 376 | } ExprStmt; 377 | struct { 378 | Node *funclike; 379 | Vec *args; 380 | } Call; 381 | struct { 382 | CTy *type; 383 | } Sizeof; 384 | struct { 385 | Builtinkind t; 386 | union { 387 | struct { 388 | Node *valist; 389 | Node *param; 390 | } Vastart; 391 | }; 392 | } Builtin; 393 | }; 394 | }; 395 | 396 | typedef enum { 397 | SYMENUM, 398 | SYMTYPE, 399 | SYMGLOBAL, 400 | SYMLOCAL, 401 | } Symkind; 402 | 403 | struct Sym { 404 | Symkind k; 405 | SrcPos *pos; 406 | CTy *type; 407 | char *name; 408 | Node *init; 409 | union { 410 | struct { 411 | int sclass; 412 | char *label; 413 | } Global; 414 | struct { 415 | StkSlot *slot; 416 | /* XXX make a Param sym type */ 417 | CTy *functy; 418 | int paramidx; 419 | int isparam; 420 | } Local; 421 | struct { 422 | int64 v; 423 | } Enum; 424 | }; 425 | }; 426 | 427 | struct StkSlot { 428 | int size; 429 | int align; 430 | int offset; 431 | }; 432 | 433 | #define MAXTOKSZ 4096 434 | 435 | struct Lexer { 436 | FILE *f; 437 | SrcPos pos; 438 | SrcPos prevpos; 439 | SrcPos markpos; 440 | int nchars; 441 | int indirective; 442 | int ws; 443 | int nl; 444 | int includestate; 445 | char tokval[MAXTOKSZ+1]; 446 | }; 447 | 448 | typedef struct Tok Tok; 449 | struct Tok { 450 | Tokkind k; 451 | char *v; 452 | int ws; /* There was whitespace before this token */ 453 | int nl; /* There was a newline before this token */ 454 | StrSet *hs; /* Hideset, the list of tokens expanded to get this token */ 455 | SrcPos pos; 456 | }; 457 | 458 | typedef struct Const Const; 459 | struct Const { 460 | char *p; /* p is null, or the label of a symbol */ 461 | int64 v; 462 | }; 463 | 464 | typedef struct Data Data; 465 | struct Data { 466 | char *label; 467 | CTy *type; 468 | Node *init; 469 | int isglobal; 470 | }; 471 | 472 | /* dbg.c */ 473 | void dumpty(CTy *); 474 | 475 | /* error.c */ 476 | void errorf(char *, ...) NORETURN; 477 | void errorposf(SrcPos *, char *, ...) NORETURN; 478 | 479 | /* lex.c cpp.c */ 480 | void cppinit(char *, Vec *); 481 | char *tokktostr(Tokkind); 482 | Tok *lex(Lexer *); 483 | Tok *pp(void); 484 | 485 | /* types.c */ 486 | CTy *newtype(int); 487 | CTy *mkptr(CTy *); 488 | int isvoid(CTy *); 489 | int isftype(CTy *); 490 | int isitype(CTy *); 491 | int isarithtype(CTy *); 492 | int isptr(CTy *); 493 | int ischarptr(CTy *t); 494 | int ischararray(CTy *t); 495 | int isfunc(CTy *); 496 | int isfuncptr(CTy *); 497 | int isstruct(CTy *); 498 | int isarray(CTy *); 499 | int sametype(CTy *, CTy *); 500 | int convrank(CTy *); 501 | int canrepresent(CTy *, CTy *); 502 | int getstructiter(StructIter *, CTy *, char *); 503 | int structnext(StructIter *); 504 | int structoffsetfromname(CTy *, char *); 505 | CTy * structtypefromname(CTy *, char *); 506 | void initstructiter(StructIter *, CTy *); 507 | void structwalk(StructIter *, StructMember **, int *); 508 | void addtostruct(CTy *, char *, CTy *); 509 | void finalizestruct(SrcPos *, CTy *); 510 | 511 | /* parse.c */ 512 | void parse(void); 513 | char *newlabel(void); 514 | 515 | /* foldexpr.c */ 516 | Const *foldexpr(Node *); 517 | 518 | /* target specific types and functions. */ 519 | 520 | /* Frontend */ 521 | 522 | extern CTy *cvoid; 523 | extern CTy *cchar; 524 | extern CTy *cshort; 525 | extern CTy *cint; 526 | extern CTy *clong; 527 | extern CTy *cllong; 528 | extern CTy *cuchar; 529 | extern CTy *cushort; 530 | extern CTy *cuint; 531 | extern CTy *culong; 532 | extern CTy *cullong; 533 | extern CTy *cfloat; 534 | extern CTy *cdouble; 535 | extern CTy *cldouble; 536 | 537 | uint64 getmaxval(CTy *); 538 | int64 getminval(CTy *); 539 | 540 | /* Backend */ 541 | 542 | void emitinit(FILE *); 543 | void emitsym(Sym *); 544 | void penddata(char *, CTy *, Node *, int); 545 | void emitend(); 546 | 547 | 548 | -------------------------------------------------------------------------------- /src/cc/cpp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cc.h" 5 | 6 | #define MAXINCLUDE 128 7 | 8 | typedef enum { 9 | OBJMACRO, 10 | FUNCMACRO, 11 | BUILTINMACRO, 12 | } MacroKind; 13 | 14 | typedef struct Macro Macro; 15 | struct Macro { 16 | MacroKind k; 17 | union { 18 | struct { 19 | Vec *toks; 20 | } Obj; 21 | struct { 22 | Vec *argnames; /* vec of char * */ 23 | Vec *toks; 24 | } Func; 25 | }; 26 | }; 27 | 28 | int nlexers; 29 | Lexer *lexers[MAXINCLUDE]; 30 | 31 | static Vec *includedirs; 32 | 33 | /* List of tokens inserted into the stream */ 34 | static List *toks; 35 | static Map *macros; 36 | 37 | static Tok *ppnoexpand(); 38 | static int64 ifexpr(); 39 | 40 | static void 41 | pushlex(char *path) 42 | { 43 | Lexer *l; 44 | 45 | if(nlexers == MAXINCLUDE) 46 | panic("include depth limit reached!"); 47 | l = xmalloc(sizeof(Lexer)); 48 | l->pos.file = path; 49 | l->prevpos.file = path; 50 | l->markpos.file = path; 51 | l->pos.line = 1; 52 | l->pos.col = 1; 53 | l->nl = 1; 54 | l->f = fopen(path, "r"); 55 | if (!l->f) 56 | errorf("error opening file %s\n", path); 57 | lexers[nlexers] = l; 58 | nlexers += 1; 59 | } 60 | 61 | static void 62 | poplex() 63 | { 64 | nlexers--; 65 | fclose(lexers[nlexers]->f); 66 | } 67 | 68 | static int 69 | fileexists(char *fname) 70 | { 71 | FILE *f; 72 | 73 | f = fopen(fname, "r"); 74 | if(!f) 75 | return 0; 76 | fclose(f); 77 | return 1; 78 | } 79 | 80 | static char * 81 | findinclude(char *path, int issysinclude) 82 | { 83 | int i; 84 | char buf[4096]; 85 | 86 | /* XXX check current dir */ 87 | /* XXX proper path join */ 88 | for(i = 0; i < includedirs->len; i++) { 89 | snprintf(buf, sizeof(buf), "%s/%s", (char*)vecget(includedirs, i), path); 90 | if(fileexists(buf)) 91 | return xstrdup(buf); 92 | } 93 | return 0; 94 | } 95 | 96 | static void 97 | include() 98 | { 99 | int n; 100 | Tok *t; 101 | char *path, *fullpath; 102 | SrcPos *pos; 103 | int sysinclude; 104 | 105 | t = ppnoexpand(); 106 | pos = &t->pos; 107 | if(t->k != TOKSTR && t->k != TOKHEADER) 108 | errorposf(pos, "#include expects a string or '<>' style header"); 109 | sysinclude = t->k == TOKHEADER; 110 | path = xstrdup(t->v); 111 | n = strlen(path); 112 | path[n - 1] = 0; 113 | path++; 114 | t = ppnoexpand(); 115 | if(t->k != TOKDIREND) 116 | errorposf(&t->pos, "garbage at end of #include (%s)", tokktostr(t->k)); 117 | fullpath = findinclude(path, sysinclude); 118 | if(!fullpath) 119 | errorposf(pos, "could not find header %s", path); 120 | pushlex(fullpath); 121 | } 122 | 123 | static int 124 | validmacrotok(Tokkind k) 125 | { 126 | switch(k) { 127 | case TOKIDENT: 128 | return 1; 129 | default: 130 | return 0; 131 | } 132 | } 133 | 134 | static Macro * 135 | lookupmacro(Tok *t) 136 | { 137 | if(!validmacrotok(t->k)) 138 | return 0; 139 | return mapget(macros, t->v); 140 | } 141 | 142 | static void 143 | define() 144 | { 145 | Macro *m; 146 | Tok *n, *t; 147 | 148 | n = ppnoexpand(); 149 | if(!validmacrotok(n->k)) 150 | errorposf(&n->pos, "invalid macro name %s", n->v); 151 | if(lookupmacro(n)) 152 | errorposf(&n->pos, "redefinition of macro %s", n->v); 153 | m = xmalloc(sizeof(Macro)); 154 | t = ppnoexpand(); 155 | if(t->k == '(' && !t->ws) { 156 | m->k = FUNCMACRO; 157 | m->Func.toks = vec(); 158 | m->Func.argnames = vec(); 159 | for(;;) { 160 | t = ppnoexpand(); 161 | if(t->k != TOKIDENT) 162 | errorposf(&t->pos, "invalid macro argname"); 163 | vecappend(m->Func.argnames, t->v); 164 | t = ppnoexpand(); 165 | if(t->k == ')') 166 | break; 167 | if(t->k != ',') 168 | errorposf(&t->pos, "preprocessor expected ','"); 169 | } 170 | while(1) { 171 | t = ppnoexpand(); 172 | if(t->k == TOKDIREND) 173 | break; 174 | vecappend(m->Func.toks, t); 175 | } 176 | } else { 177 | m->k = OBJMACRO; 178 | m->Obj.toks = vec(); 179 | while(t->k != TOKDIREND) { 180 | vecappend(m->Obj.toks, t); 181 | t = ppnoexpand(); 182 | } 183 | } 184 | mapset(macros, n->v, m); 185 | } 186 | 187 | static void 188 | undef() 189 | { 190 | Tok *t; 191 | 192 | t = ppnoexpand(); 193 | if(!lookupmacro(t)) 194 | errorposf(&t->pos, "cannot #undef macro that isn't defined"); 195 | mapdel(macros, t->v); 196 | t = ppnoexpand(); 197 | if(t->k != TOKDIREND) 198 | errorposf(&t->pos, "garbage at end of #undef"); 199 | } 200 | 201 | static void 202 | pif() 203 | { 204 | ifexpr(); 205 | panic("unimplemented"); 206 | } 207 | 208 | static void 209 | elseif() 210 | { 211 | panic("unimplemented"); 212 | } 213 | 214 | static void 215 | pelse() 216 | { 217 | panic("unimplemented"); 218 | } 219 | 220 | static void 221 | endif() 222 | { 223 | panic("unimplemented"); 224 | } 225 | 226 | static int64 227 | ifexpr() 228 | { 229 | return 0; 230 | } 231 | 232 | static void 233 | directive() 234 | { 235 | Tok *t; 236 | char *dir; 237 | 238 | t = ppnoexpand(); 239 | dir = t->v; 240 | if(strcmp(dir, "include") == 0) 241 | include(); 242 | else if(strcmp(dir, "define") == 0) 243 | define(); 244 | else if(strcmp(dir, "undef") == 0) 245 | undef(); 246 | else if(strcmp(dir, "if") == 0) 247 | pif(); 248 | else if(strcmp(dir, "elseif") == 0) 249 | elseif(); 250 | else if(strcmp(dir, "else") == 0) 251 | pelse(); 252 | else if(strcmp(dir, "endif") == 0) 253 | endif(); 254 | else 255 | errorposf(&t->pos, "invalid directive %s", dir); 256 | } 257 | 258 | static struct {char *kw; int t;} keywordlut[] = { 259 | {"auto", TOKAUTO}, 260 | {"break", TOKBREAK}, 261 | {"case", TOKCASE}, 262 | {"char", TOKCHAR}, 263 | {"const", TOKCONST}, 264 | {"continue", TOKCONTINUE}, 265 | {"default", TOKDEFAULT}, 266 | {"do", TOKDO}, 267 | {"double", TOKDOUBLE}, 268 | {"else", TOKELSE}, 269 | {"enum", TOKENUM}, 270 | {"extern", TOKEXTERN}, 271 | {"float", TOKFLOAT}, 272 | {"for", TOKFOR}, 273 | {"goto", TOKGOTO}, 274 | {"if", TOKIF}, 275 | {"int", TOKINT}, 276 | {"long", TOKLONG}, 277 | {"register", TOKREGISTER}, 278 | {"return", TOKRETURN}, 279 | {"short", TOKSHORT}, 280 | {"signed", TOKSIGNED}, 281 | {"sizeof", TOKSIZEOF}, 282 | {"static", TOKSTATIC}, 283 | {"struct", TOKSTRUCT}, 284 | {"switch", TOKSWITCH}, 285 | {"typedef", TOKTYPEDEF}, 286 | {"union", TOKUNION}, 287 | {"unsigned", TOKUNSIGNED}, 288 | {"void", TOKVOID}, 289 | {"volatile", TOKVOLATILE}, 290 | {"while", TOKWHILE}, 291 | {0, 0} 292 | }; 293 | 294 | static int 295 | identkind(char *s) { 296 | int i; 297 | 298 | i = 0; 299 | while(keywordlut[i].kw) { 300 | if(strcmp(keywordlut[i].kw, s) == 0) 301 | return keywordlut[i].t; 302 | i++; 303 | } 304 | return TOKIDENT; 305 | } 306 | 307 | static Tok * 308 | ppnoexpand() 309 | { 310 | Tok *t; 311 | 312 | if(toks->len) 313 | return listpopfront(toks); 314 | t = lex(lexers[nlexers - 1]); 315 | if(t->k == TOKEOF && nlexers == 1) 316 | return t; 317 | if(t->k == TOKEOF && nlexers > 1) { 318 | poplex(); 319 | return ppnoexpand(); 320 | } 321 | if(t->k == TOKIDENT) 322 | t->k = identkind(t->v); 323 | return t; 324 | } 325 | 326 | /* TODO, inline? it isn't really too clear by itself */ 327 | static void 328 | expandfunclike(SrcPos *pos, Macro *m, Vec *params, StrSet *hs) 329 | { 330 | int i, j, k, argfound; 331 | Tok *t1, *t2; 332 | Vec *v, *expanded; 333 | 334 | if(m->k != FUNCMACRO) 335 | panic("internal error"); 336 | if(m->Func.argnames->len != params->len) 337 | panic("internal error"); 338 | expanded = vec(); 339 | for(i = 0; i < m->Func.toks->len; i++) { 340 | t1 = vecget(m->Func.toks, i); 341 | argfound = 0; 342 | for(j = 0; j < m->Func.argnames->len; j++) { 343 | if(strcmp(t1->v, vecget(m->Func.argnames, j)) == 0) { 344 | v = vecget(params, j); 345 | for(k = 0; k < v->len; k++) { 346 | t2 = xmalloc(sizeof(Tok)); 347 | *t2 = *(Tok*)(vecget(v, k)); 348 | t2->pos = *pos; 349 | t2->hs = hs; 350 | vecappend(expanded, t2); 351 | } 352 | argfound = 1; 353 | break; 354 | } 355 | } 356 | if(!argfound) { 357 | t2 = xmalloc(sizeof(Tok)); 358 | *t2 = *t1; 359 | t2->pos = *pos; 360 | t2->hs = hs; 361 | vecappend(expanded, t2); 362 | } 363 | } 364 | for(i = 0; i < expanded->len; i++) 365 | listprepend(toks, vecget(expanded, expanded->len - i - 1)); 366 | } 367 | 368 | Tok * 369 | pp() 370 | { 371 | int i, depth; 372 | Macro *m; 373 | Vec *params, *curparam; 374 | Tok *t1, *t2, *expanded; 375 | StrSet *hsparen, *hsmacro; 376 | 377 | t1 = ppnoexpand(); 378 | if(t1->k == TOKDIRSTART && toks->len == 0) { 379 | directive(); 380 | return pp(); 381 | } 382 | m = lookupmacro(t1); 383 | if(!m) 384 | return t1; 385 | hsmacro = t1->hs; 386 | switch(m->k) { 387 | case FUNCMACRO: 388 | t2 = pp(); 389 | if(t2->k != '(') { 390 | listprepend(toks, t2); 391 | return t1; 392 | } 393 | params = vec(); 394 | depth = 1; 395 | for(;;) { 396 | t2 = pp(); 397 | if(t2->k == TOKEOF) 398 | errorposf(&t2->pos, "end of file in macro arguments"); 399 | if(t2->k == ')' && depth == 1) { 400 | hsparen = t2->hs; 401 | break; 402 | } 403 | if(params->len == 0 || (t2->k == ',' && depth == 1)) { 404 | curparam = vec(); 405 | vecappend(params, curparam); 406 | } 407 | if(t2->k != ',') 408 | vecappend(curparam, t2); 409 | if(t2->k == '(') 410 | depth++; 411 | if(t2->k == ')') 412 | depth--; 413 | } 414 | if(m->Func.argnames->len != params->len) 415 | errorposf(&t1->pos, "macro invoked with incorrect number of args"); 416 | expandfunclike(&t1->pos, m, params, strsetadd(strsetintersect(hsmacro, hsparen), t1->v)); 417 | return pp(); 418 | case OBJMACRO: 419 | if(strsethas(t1->hs, t1->v)) 420 | return t1; 421 | for(i = 0; i < m->Obj.toks->len; i++) { 422 | expanded = xmalloc(sizeof(Tok)); 423 | *expanded = *(Tok*)vecget(m->Obj.toks, m->Obj.toks->len - i - 1); 424 | expanded->hs = strsetadd(expanded->hs, t1->v); 425 | listprepend(toks, expanded); 426 | } 427 | return pp(); 428 | default: 429 | ; 430 | } 431 | panic("unimplemented"); 432 | return 0; 433 | } 434 | 435 | void 436 | cppinit(char *path, Vec *includes) 437 | { 438 | includedirs = includes; 439 | nlexers = 0; 440 | toks = list(); 441 | macros = map(); 442 | pushlex(path); 443 | } 444 | 445 | -------------------------------------------------------------------------------- /src/cc/error.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cc.h" 4 | 5 | static void 6 | printpos(SrcPos *p) 7 | { 8 | FILE *f; 9 | int line; 10 | int c; 11 | int i; 12 | 13 | line = 1; 14 | f = fopen(p->file, "r"); 15 | if (!f) 16 | return; 17 | while(1) { 18 | if(p->line == line) 19 | break; 20 | c = fgetc(f); 21 | if(c == EOF) 22 | goto cleanup; 23 | if(c == '\n') 24 | line += 1; 25 | } 26 | while(1) { 27 | c = fgetc(f); 28 | if(c == EOF || c == '\n') 29 | break; 30 | if(c == '\t') 31 | fputs(" ", stderr); 32 | else 33 | fputc(c, stderr); 34 | } 35 | fputc('\n', stderr); 36 | for(i = 0; i < p->col-1; i++) 37 | fputc(' ', stderr); 38 | fputs("^\n", stderr); 39 | cleanup: 40 | fclose(f); 41 | } 42 | 43 | void 44 | errorf(char *fmt, ...) 45 | { 46 | va_list va; 47 | 48 | va_start(va, fmt); 49 | vfprintf(stderr, fmt, va); 50 | va_end(va); 51 | exit(1); 52 | } 53 | 54 | void 55 | errorposf(SrcPos *p, char *fmt, ...) 56 | { 57 | va_list va; 58 | 59 | va_start(va, fmt); 60 | vfprintf(stderr, fmt, va); 61 | va_end(va); 62 | fprintf(stderr, " at %s:%d:%d\n", p->file, p->line, p->col); 63 | printpos(p); 64 | exit(1); 65 | } 66 | -------------------------------------------------------------------------------- /src/cc/foldexpr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cc.h" 5 | 6 | static Const * 7 | mkconst(char *p, int64 v) 8 | { 9 | Const *c; 10 | 11 | c = xmalloc(sizeof(Const)); 12 | c->p = p; 13 | c->v = v; 14 | return c; 15 | } 16 | 17 | static Const * 18 | foldbinop(Node *n) 19 | { 20 | Const *l, *r; 21 | 22 | l = foldexpr(n->Binop.l); 23 | r = foldexpr(n->Binop.r); 24 | if(!l || !r) 25 | return 0; 26 | if(isitype(n->type)) { 27 | switch(n->Binop.op) { 28 | case '+': 29 | if(l->p && r->p) 30 | return 0; 31 | if(l->p) 32 | mkconst(l->p, l->v + r->v); 33 | if(r->p) 34 | mkconst(r->p, l->v + r->v); 35 | return mkconst(0, l->v + r->v); 36 | case '-': 37 | if(l->p || r->p) { 38 | if(l->p && !r->p) 39 | return mkconst(l->p, l->v - r->v); 40 | if(!l->p && r->p) 41 | return 0; 42 | if(strcmp(l->p, r->p) == 0) 43 | return mkconst(0, l->v - r->v); 44 | return 0; 45 | } 46 | return mkconst(0, l->v - r->v); 47 | case '*': 48 | if(l->p || r->p) 49 | return 0; 50 | return mkconst(0, l->v * r->v); 51 | case '/': 52 | if(l->p || r->p) 53 | return 0; 54 | if(r->v == 0) 55 | return 0; 56 | return mkconst(0, l->v / r->v); 57 | case TOKSHL: 58 | if(l->p || r->p) 59 | return 0; 60 | return mkconst(0, l->v << r->v); 61 | case '|': 62 | if(l->p || r->p) 63 | return 0; 64 | return mkconst(0, l->v | r->v); 65 | default: 66 | errorposf(&n->pos, "unimplemented fold binop %d", n->Binop.op); 67 | } 68 | } 69 | panic("unimplemented fold binop"); 70 | return 0; 71 | } 72 | 73 | static Const * 74 | foldaddr(Node *n) 75 | { 76 | char *l; 77 | Sym *sym; 78 | 79 | if(n->Unop.operand->t == NINIT) { 80 | l = newlabel(); 81 | penddata(l, n->Unop.operand->type, n->Unop.operand, 0); 82 | return mkconst(l, 0); 83 | } 84 | if(n->Unop.operand->t != NIDENT) 85 | return 0; 86 | sym = n->Unop.operand->Ident.sym; 87 | if(sym->k != SYMGLOBAL) 88 | return 0; 89 | return mkconst(sym->Global.label, 0); 90 | } 91 | 92 | static Const * 93 | foldunop(Node *n) 94 | { 95 | Const *c; 96 | 97 | switch(n->Unop.op) { 98 | case '&': 99 | return foldaddr(n); 100 | case '-': 101 | c = foldexpr(n->Unop.operand); 102 | if(!c) 103 | return 0; 104 | if(c->p) 105 | return 0; 106 | return mkconst(0, -c->v); 107 | default: 108 | panic("unimplemented fold unop %d", n->Binop.op); 109 | } 110 | panic("unimplemented fold unop"); 111 | return 0; 112 | } 113 | 114 | Const * 115 | foldcast(Node *n) 116 | { 117 | if(!isitype(n->type)) 118 | return 0; 119 | if(!isitype(n->Cast.operand->type)) 120 | return 0; 121 | return foldexpr(n->Cast.operand); 122 | } 123 | 124 | Const * 125 | foldident(Node *n) 126 | { 127 | Sym *sym; 128 | 129 | sym = n->Ident.sym; 130 | switch(sym->k) { 131 | case SYMENUM: 132 | return mkconst(0, sym->Enum.v); 133 | default: 134 | return 0; 135 | } 136 | } 137 | 138 | Const * 139 | foldexpr(Node *n) 140 | { 141 | char *l; 142 | CTy *ty; 143 | 144 | switch(n->t) { 145 | case NBINOP: 146 | return foldbinop(n); 147 | case NUNOP: 148 | return foldunop(n); 149 | case NNUM: 150 | return mkconst(0, n->Num.v); 151 | case NSIZEOF: 152 | return mkconst(0, n->Sizeof.type->size); 153 | case NCAST: 154 | return foldcast(n); 155 | case NIDENT: 156 | return foldident(n); 157 | case NSTR: 158 | l = newlabel(); 159 | ty = newtype(CARR); 160 | ty->Arr.subty = cchar; 161 | /* XXX DIM? */ 162 | penddata(l, ty, n, 0); 163 | return mkconst(l, 0); 164 | default: 165 | return 0; 166 | } 167 | } 168 | 169 | -------------------------------------------------------------------------------- /src/cc/lex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cc.h" 5 | 6 | static void ungetch(Lexer *l, int c); 7 | static int nextc(Lexer *l); 8 | 9 | char * 10 | tokktostr(Tokkind t) 11 | { 12 | switch(t) { 13 | case TOKIDENT: return "ident"; 14 | case TOKNUM: return "number"; 15 | case TOKIF: return "if"; 16 | case TOKELSE: return "else"; 17 | case TOKDO: return "do"; 18 | case TOKWHILE: return "while"; 19 | case TOKFOR: return "for"; 20 | case TOKVOID: return "void"; 21 | case TOKCHAR: return "char"; 22 | case TOKCHARLIT: return "character literal"; 23 | case TOKSHORT: return "short"; 24 | case TOKINT: return "int"; 25 | case TOKLONG: return "long"; 26 | case TOKSIGNED: return "signed"; 27 | case TOKUNSIGNED: return "unsigned"; 28 | case TOKEOF: return "end of file"; 29 | case TOKENUM: return "enum"; 30 | case TOKCONST: return "const"; 31 | case TOKRETURN: return "return"; 32 | case TOKSTR: return "string"; 33 | case TOKAUTO: return "auto"; 34 | case TOKEXTERN: return "extern"; 35 | case TOKSTATIC: return "static"; 36 | case TOKVOLATILE: return "volatile"; 37 | case TOKSIZEOF: return "sizeof"; 38 | case TOKFLOAT: return "float"; 39 | case TOKDOUBLE: return "double"; 40 | case TOKTYPEDEF: return "typedef"; 41 | case TOKUNION: return "union"; 42 | case TOKSTRUCT: return "struct"; 43 | case TOKGOTO: return "goto"; 44 | case TOKSWITCH: return "switch"; 45 | case TOKCASE: return "case"; 46 | case TOKDEFAULT: return "default"; 47 | case TOKCONTINUE: return "continue"; 48 | case TOKBREAK: return "break"; 49 | case TOKREGISTER: return "register"; 50 | case TOKSUBASS: return "-="; 51 | case TOKSHR: return ">>"; 52 | case TOKSHL: return "<<"; 53 | case TOKORASS: return "|="; 54 | case TOKNEQ: return "!="; 55 | case TOKMULASS: return "*="; 56 | case TOKMODASS: return "%="; 57 | case TOKLOR: return "||"; 58 | case TOKLEQ: return "<="; 59 | case TOKLAND: return "&&"; 60 | case TOKINC: return "++"; 61 | case TOKGEQ: return ">="; 62 | case TOKEQL: return "=="; 63 | case TOKELLIPSIS: return "..."; 64 | case TOKDIVASS: return "/="; 65 | case TOKDEC: return "--"; 66 | case TOKARROW: return "->"; 67 | case TOKANDASS: return "&="; 68 | case TOKADDASS: return "+="; 69 | case TOKHASH: return "#"; 70 | case TOKHASHHASH: return "##"; 71 | case TOKDIRSTART: return "Directive start"; 72 | case TOKDIREND: return "Directive end"; 73 | case TOKHEADER: return "include header"; 74 | case '?': return "?"; 75 | case '[': return "["; 76 | case '+': return "+"; 77 | case '%': return "%"; 78 | case '&': return "&"; 79 | case '*': return "*"; 80 | case '}': return "}"; 81 | case '{': return "{"; 82 | case ']': return "]"; 83 | case ')': return ")"; 84 | case '(': return "("; 85 | case '.': return "."; 86 | case '/': return "/"; 87 | case '!': return "!"; 88 | case ':': return ":"; 89 | case ';': return ";"; 90 | case '<': return "<"; 91 | case '>': return ">"; 92 | case ',': return ","; 93 | case '-': return "-"; 94 | case '|': return "|"; 95 | case '=': return "="; 96 | case '~': return "~"; 97 | case '^': return "^"; 98 | case '\\': return "\\"; 99 | } 100 | panic("internal error converting token to string: %d", t); 101 | return 0; 102 | } 103 | 104 | enum { 105 | INCLUDEBEGIN, 106 | INCLUDEIDENT, 107 | INCLUDEHEADER, 108 | }; 109 | 110 | /* makes a token, copies v */ 111 | static Tok * 112 | mktok(Lexer *l, int kind) { 113 | Tok *r; 114 | 115 | l->tokval[l->nchars] = 0; 116 | r = xmalloc(sizeof(Tok)); 117 | r->pos.line = l->markpos.line; 118 | r->pos.col = l->markpos.col; 119 | r->pos.file = l->markpos.file; 120 | r->k = kind; 121 | r->ws = l->ws; 122 | r->nl = l->nl; 123 | l->ws = 0; 124 | l->nl = 0; 125 | switch(kind){ 126 | case TOKSTR: 127 | case TOKNUM: 128 | case TOKIDENT: 129 | case TOKCHARLIT: 130 | case TOKHEADER: 131 | /* TODO: intern strings */ 132 | r->v = xstrdup(l->tokval); 133 | break; 134 | default: 135 | r->v = tokktostr(kind); 136 | break; 137 | } 138 | /* The lexer needs to be aware of '<>' style includes. */ 139 | switch(l->includestate) { 140 | case INCLUDEBEGIN: 141 | if(kind == TOKDIRSTART) 142 | l->includestate = INCLUDEIDENT; 143 | else 144 | l->includestate = INCLUDEBEGIN; 145 | break; 146 | case INCLUDEIDENT: 147 | if(kind == TOKIDENT && strcmp(r->v, "include") == 0) 148 | l->includestate = INCLUDEHEADER; 149 | else 150 | l->includestate = INCLUDEBEGIN; 151 | break; 152 | default: 153 | l->includestate = INCLUDEBEGIN; 154 | break; 155 | } 156 | return r; 157 | } 158 | 159 | static int 160 | numberc(int c) 161 | { 162 | return c >= '0' && c <= '9'; 163 | } 164 | 165 | static int 166 | hexnumberc(int c) 167 | { 168 | if(numberc(c)) 169 | return 1; 170 | if(c >= 'a' && c <= 'f') 171 | return 1; 172 | if(c >= 'A' && c <= 'F') 173 | return 1; 174 | return 0; 175 | } 176 | 177 | static int 178 | identfirstc(int c) 179 | { 180 | if(c == '_') 181 | return 1; 182 | if(c >= 'a' && c <= 'z') 183 | return 1; 184 | if(c >= 'A' && c <= 'Z') 185 | return 1; 186 | return 0; 187 | } 188 | 189 | static int 190 | identtailc(int c) 191 | { 192 | if(numberc(c) || identfirstc(c)) 193 | return 1; 194 | return 0; 195 | } 196 | 197 | static int 198 | wsc(int c) 199 | { 200 | return (c == '\r' || c == '\n' || c == ' ' || c == '\t'); 201 | } 202 | 203 | static void 204 | mark(Lexer *l) 205 | { 206 | l->nchars = 0; 207 | l->markpos.line = l->pos.line; 208 | l->markpos.col = l->pos.col; 209 | } 210 | 211 | static void 212 | accept(Lexer *l, int c) 213 | { 214 | l->tokval[l->nchars] = c; 215 | l->nchars += 1; 216 | if(l->nchars > MAXTOKSZ) 217 | errorposf(&l->markpos, "token too large"); 218 | } 219 | 220 | static int 221 | nextc(Lexer *l) 222 | { 223 | int c; 224 | l->prevpos.col = l->pos.col; 225 | l->prevpos.line = l->pos.line; 226 | c = fgetc(l->f); 227 | if(c == '\n') { 228 | l->pos.line += 1; 229 | l->pos.col = 1; 230 | } else if(c == '\t') 231 | l->pos.col += 4; 232 | else 233 | l->pos.col += 1; 234 | return c; 235 | } 236 | 237 | static void 238 | ungetch(Lexer *l, int c) /* avoid name conflict */ 239 | { 240 | l->pos.col = l->prevpos.col; 241 | l->pos.line = l->prevpos.line; 242 | ungetc(c, l->f); 243 | } 244 | 245 | Tok * 246 | lex(Lexer *l) 247 | { 248 | Tok *t; 249 | int c, c2; 250 | 251 | mark(l); 252 | if(l->indirective && l->nl) { 253 | l->indirective = 0; 254 | t = mktok(l, TOKDIREND); 255 | l->nl = 1; 256 | return t; 257 | } 258 | c = nextc(l); 259 | if(c == EOF) { 260 | if(l->indirective) { 261 | l->indirective = 0; 262 | return mktok(l, TOKDIREND); 263 | } 264 | return mktok(l, TOKEOF); 265 | } else if(wsc(c)) { 266 | l->ws = 1; 267 | if(c == '\n') 268 | l->nl = 1; 269 | do { 270 | c = nextc(l); 271 | if(c == EOF) { 272 | if(l->indirective) { 273 | l->indirective = 0; 274 | return mktok(l, TOKDIREND); 275 | } 276 | return mktok(l, TOKEOF); 277 | } 278 | if(c == '\n') 279 | l->nl = 1; 280 | } while(wsc(c)); 281 | ungetch(l, c); 282 | return lex(l); 283 | } else if (c == '"') { 284 | accept(l, c); 285 | for(;;) { 286 | c = nextc(l); 287 | if(c == EOF) 288 | errorf("unclosed string\n"); /* TODO error pos */ 289 | accept(l, c); 290 | if(c == '\\') { 291 | c = nextc(l); 292 | if(c == EOF || c == '\n') 293 | errorf("EOF or newline in string literal"); 294 | accept(l, c); 295 | continue; 296 | } 297 | if(c == '"') /* TODO: escape chars */ 298 | return mktok(l, TOKSTR); 299 | } 300 | } else if (c == '\'') { 301 | accept(l, c); 302 | c = nextc(l); 303 | if(c == EOF) 304 | errorf("unclosed char\n"); /* TODO error pos */ 305 | accept(l, c); 306 | if(c == '\\') { 307 | c = nextc(l); 308 | if(c == EOF || c == '\n') 309 | errorf("EOF or newline in char literal\n"); 310 | accept(l, c); 311 | } 312 | c = nextc(l); 313 | accept(l, c); 314 | if(c != '\'') 315 | errorf("char literal expects '\n"); 316 | return mktok(l, TOKCHARLIT); 317 | } else if(identfirstc(c)) { 318 | accept(l, c); 319 | for(;;) { 320 | c = nextc(l); 321 | if (!identtailc(c)) { 322 | ungetch(l, c); 323 | return mktok(l, TOKIDENT); 324 | } 325 | accept(l, c); 326 | } 327 | } else if(numberc(c)) { 328 | accept(l, c); 329 | c2 = nextc(l); 330 | if(c == '0' && c2 == 'x') { 331 | accept(l, c); 332 | for(;;) { 333 | c = nextc(l); 334 | if (!hexnumberc(c)) { 335 | while(c == 'u' || c == 'l' || c == 'U' || c == 'L') { 336 | accept(l, c); 337 | c = nextc(l); 338 | } 339 | ungetch(l, c); 340 | return mktok(l, TOKNUM); 341 | } 342 | accept(l, c); 343 | } 344 | } 345 | ungetch(l, c2); 346 | for(;;) { 347 | c = nextc(l); 348 | if (!numberc(c)) { 349 | while(c == 'u' || c == 'l' || c == 'U' || c == 'L') { 350 | accept(l, c); 351 | c = nextc(l); 352 | } 353 | ungetch(l, c); 354 | return mktok(l, TOKNUM); 355 | } 356 | accept(l, c); 357 | } 358 | } else if(c == '<' && l->includestate == INCLUDEHEADER) { 359 | for(;;){ 360 | accept(l, c); 361 | if(c == EOF) 362 | errorf("eof in include\n"); 363 | if(c == '>') 364 | return mktok(l, TOKHEADER); 365 | c = nextc(l); 366 | } 367 | } else { 368 | c2 = nextc(l); 369 | if(c == '/' && c2 == '*') { 370 | l->ws = 1; 371 | for(;;) { 372 | do { 373 | c = nextc(l); 374 | if(c == EOF) { 375 | return mktok(l, TOKEOF); 376 | } 377 | if(c == '\n') 378 | l->nl = 1; 379 | } while(c != '*'); 380 | c = nextc(l); 381 | if(c == EOF) 382 | return mktok(l, TOKEOF); 383 | if(c == '/') 384 | return lex(l); 385 | if(c == '\n') 386 | l->nl = 1; 387 | } 388 | } else if(c == '/' && c2 == '/') { 389 | l->ws = 1; 390 | do { 391 | c = nextc(l); 392 | if (c == EOF) 393 | return mktok(l, TOKEOF); 394 | } while(c != '\n'); 395 | l->nl = 1; 396 | ungetch(l, c); 397 | return lex(l); 398 | } else if(c == '.' && c2 == '.') { 399 | /* TODO, errorpos? */ 400 | c = nextc(l); 401 | if(c != '.') 402 | errorf("expected ...\n"); 403 | return mktok(l, TOKELLIPSIS); 404 | } else if(c == '+' && c2 == '=') return mktok(l, TOKADDASS); 405 | else if(c == '-' && c2 == '=') return mktok(l, TOKSUBASS); 406 | else if(c == '-' && c2 == '>') return mktok(l, TOKARROW); 407 | else if(c == '*' && c2 == '=') return mktok(l, TOKMULASS); 408 | else if(c == '/' && c2 == '=') return mktok(l, TOKDIVASS); 409 | else if(c == '%' && c2 == '=') return mktok(l, TOKMODASS); 410 | else if(c == '&' && c2 == '=') return mktok(l, TOKANDASS); 411 | else if(c == '|' && c2 == '=') return mktok(l, TOKORASS); 412 | else if(c == '>' && c2 == '=') return mktok(l, TOKGEQ); 413 | else if(c == '<' && c2 == '=') return mktok(l, TOKLEQ); 414 | else if(c == '!' && c2 == '=') return mktok(l, TOKNEQ); 415 | else if(c == '=' && c2 == '=') return mktok(l, TOKEQL); 416 | else if(c == '+' && c2 == '+') return mktok(l, TOKINC); 417 | else if(c == '-' && c2 == '-') return mktok(l, TOKDEC); 418 | else if(c == '<' && c2 == '<') return mktok(l, TOKSHL); 419 | else if(c == '>' && c2 == '>') return mktok(l, TOKSHR); 420 | else if(c == '|' && c2 == '|') return mktok(l, TOKLOR); 421 | else if(c == '&' && c2 == '&') return mktok(l, TOKLAND); 422 | else if(c == '#' && c2 == '#') return mktok(l, TOKHASHHASH); 423 | else if(c == '\\' && c2 == '\n') return lex(l); 424 | else { 425 | /* TODO, detect invalid operators */ 426 | ungetch(l, c2); 427 | if(c == '#' && l->nl) { 428 | l->indirective = 1; 429 | return mktok(l, TOKDIRSTART); 430 | } 431 | return mktok(l, c); 432 | } 433 | panic("internal error\n"); 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/cc/parse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cc.h" 5 | 6 | static Const *constexpr(void); 7 | static Node *stmt(void); 8 | static Node *pif(void); 9 | static Node *pfor(void); 10 | static Node *dowhile(void); 11 | static Node *pwhile(void); 12 | static Node *block(void); 13 | static Node *preturn(void); 14 | static Node *pswitch(void); 15 | static Node *pdefault(void); 16 | static Node *pcase(void); 17 | static Node *pcontinue(void); 18 | static Node *pbreak(void); 19 | static Node *stmt(void); 20 | static Node *exprstmt(void); 21 | static Node *expr(void); 22 | static Node *assignexpr(void); 23 | static Node *condexpr(void); 24 | static Node *logorexpr(void); 25 | static Node *logandexpr(void); 26 | static Node *orexpr(void); 27 | static Node *xorexpr(void); 28 | static Node *andexpr(void); 29 | static Node *eqlexpr(void); 30 | static Node *relexpr(void); 31 | static Node *shiftexpr(void); 32 | static Node *addexpr(void); 33 | static Node *mulexpr(void); 34 | static Node *castexpr(void); 35 | static Node *unaryexpr(void); 36 | static Node *postexpr(void); 37 | static Node *primaryexpr(void); 38 | static Node *declorstmt(void); 39 | static Node *decl(void); 40 | static Node *declinit(CTy *); 41 | static Node *vastart(); 42 | static void fbody(void); 43 | static CTy *declspecs(int *); 44 | 45 | static CTy *ptag(void); 46 | static CTy *pstruct(int); 47 | static CTy *penum(void); 48 | static CTy *typename(void); 49 | static CTy *declarator(CTy *, char **, Node **); 50 | static CTy *directdeclarator(CTy *, char **); 51 | static CTy *declaratortail(CTy *); 52 | static Node *ipromote(Node *); 53 | static CTy *usualarithconv(Node **, Node **); 54 | static Node *mkcast(SrcPos *, Node *, CTy *); 55 | static void expect(Tokkind); 56 | static int islval(Node *); 57 | static int isassignop(Tokkind); 58 | 59 | 60 | Tok *tok; 61 | Tok *nexttok; 62 | 63 | #define MAXSCOPES 1024 64 | static int nscopes; 65 | static Map *tags[MAXSCOPES]; 66 | static Map *syms[MAXSCOPES]; 67 | 68 | #define MAXLABELDEPTH 2048 69 | static int switchdepth; 70 | static int brkdepth; 71 | static int contdepth; 72 | static char *breaks[MAXLABELDEPTH]; 73 | static char *conts[MAXLABELDEPTH]; 74 | static Node *switches[MAXLABELDEPTH]; 75 | 76 | Node *curfunc; 77 | Map *labels; 78 | Vec *gotos; 79 | Vec *tentativesyms; 80 | 81 | int labelcount; 82 | 83 | char * 84 | newlabel(void) 85 | { 86 | char *s; 87 | int n; 88 | 89 | n = snprintf(0, 0, ".L%d", labelcount); 90 | if(n < 0) 91 | panic("internal error"); 92 | n += 1; 93 | s = xmalloc(n); 94 | if(snprintf(s, n, ".L%d", labelcount) < 0) 95 | panic("internal error"); 96 | labelcount++; 97 | return s; 98 | } 99 | 100 | static void 101 | pushswitch(Node *n) 102 | { 103 | switches[switchdepth] = n; 104 | switchdepth += 1; 105 | } 106 | 107 | static void 108 | popswitch(void) 109 | { 110 | switchdepth -= 1; 111 | if(switchdepth < 0) 112 | panic("internal error"); 113 | } 114 | 115 | static Node * 116 | curswitch(void) 117 | { 118 | if(switchdepth == 0) 119 | return 0; 120 | return switches[switchdepth - 1]; 121 | } 122 | 123 | static void 124 | pushcontbrk(char *lcont, char *lbreak) 125 | { 126 | conts[contdepth] = lcont; 127 | breaks[brkdepth] = lbreak; 128 | brkdepth += 1; 129 | contdepth += 1; 130 | } 131 | 132 | static void 133 | popcontbrk(void) 134 | { 135 | brkdepth -= 1; 136 | contdepth -= 1; 137 | if(brkdepth < 0 || contdepth < 0) 138 | panic("internal error"); 139 | } 140 | 141 | static char * 142 | curcont() 143 | { 144 | if(contdepth == 0) 145 | return 0; 146 | return conts[contdepth - 1]; 147 | } 148 | 149 | static char * 150 | curbrk() 151 | { 152 | if(brkdepth == 0) 153 | return 0; 154 | return breaks[brkdepth - 1]; 155 | } 156 | 157 | static void 158 | pushbrk(char *lbreak) 159 | { 160 | breaks[brkdepth] = lbreak; 161 | brkdepth += 1; 162 | } 163 | 164 | static void 165 | popbrk(void) 166 | { 167 | brkdepth -= 1; 168 | if(brkdepth < 0) 169 | panic("internal error"); 170 | } 171 | 172 | 173 | static void 174 | popscope(void) 175 | { 176 | nscopes -= 1; 177 | if(nscopes < 0) 178 | errorf("bug: scope underflow\n"); 179 | syms[nscopes] = 0; 180 | tags[nscopes] = 0; 181 | } 182 | 183 | static void 184 | pushscope(void) 185 | { 186 | syms[nscopes] = map(); 187 | tags[nscopes] = map(); 188 | nscopes += 1; 189 | if(nscopes > MAXSCOPES) 190 | errorf("scope depth exceeded maximum\n"); 191 | } 192 | 193 | static int 194 | isglobal(void) 195 | { 196 | return nscopes == 1; 197 | } 198 | 199 | static int 200 | islval(Node *n) 201 | { 202 | switch(n->t) { 203 | case NUNOP: 204 | if(n->Unop.op == '*') 205 | return 1; 206 | return 0; 207 | case NIDENT: 208 | case NIDX: 209 | case NSEL: 210 | case NINIT: 211 | return 1; 212 | default: 213 | return 0; 214 | } 215 | } 216 | 217 | static int 218 | define(Map *scope[], char *k, void *v) 219 | { 220 | Map *m; 221 | 222 | m = scope[nscopes - 1]; 223 | if(mapget(m, k)) 224 | return 0; 225 | mapset(m, k, v); 226 | return 1; 227 | } 228 | 229 | static void * 230 | lookup(Map *scope[], char *k) 231 | { 232 | int i; 233 | void *v; 234 | 235 | i = nscopes; 236 | while(i--) { 237 | v = mapget(scope[i], k); 238 | if(v) 239 | return v; 240 | } 241 | return 0; 242 | } 243 | 244 | /* TODO: proper efficient set for tentative syms */ 245 | static void 246 | removetentativesym(Sym *sym) 247 | { 248 | int i; 249 | Vec *newv; 250 | Sym *s; 251 | 252 | newv = vec(); 253 | for(i = 0; i < tentativesyms->len; i++) { 254 | s = vecget(tentativesyms, i); 255 | if(s == sym) 256 | continue; 257 | vecappend(newv, s); 258 | } 259 | tentativesyms = newv; 260 | } 261 | 262 | static void 263 | addtentativesym(Sym *sym) 264 | { 265 | int i; 266 | Sym *s; 267 | 268 | for(i = 0; i < tentativesyms->len; i++) { 269 | s = vecget(tentativesyms, i); 270 | if(s == sym) 271 | return; 272 | } 273 | vecappend(tentativesyms, sym); 274 | } 275 | 276 | 277 | static Sym * 278 | defineenum(SrcPos *p, char *name, CTy *type, int64 v) 279 | { 280 | Sym *sym; 281 | 282 | sym = xmalloc(sizeof(Sym)); 283 | sym->pos = p; 284 | sym->name = name; 285 | sym->type = type; 286 | sym->k = SYMENUM; 287 | sym->Enum.v = v; 288 | if(!define(syms, name, sym)) 289 | errorposf(p, "redefinition of %s", name); 290 | return sym; 291 | } 292 | 293 | static Sym * 294 | definesym(SrcPos *p, int sclass, char *name, CTy *type, Node *n) 295 | { 296 | Sym *sym; 297 | 298 | if(sclass == SCAUTO || n != 0) 299 | if(type->incomplete) 300 | errorposf(p, "cannot use incomplete type in this context"); 301 | if(sclass == SCAUTO && isglobal()) 302 | errorposf(p, "defining local symbol in global scope"); 303 | sym = mapget(syms[nscopes - 1], name); 304 | if(sym) { 305 | switch(sym->k) { 306 | case SYMTYPE: 307 | if(sclass != SCTYPEDEF || !sametype(sym->type, type)) 308 | errorposf(p, "incompatible redefinition of typedef %s", name); 309 | break; 310 | case SYMGLOBAL: 311 | if(sym->Global.sclass == SCEXTERN && sclass == SCGLOBAL) 312 | sym->Global.sclass = SCGLOBAL; 313 | if(sym->Global.sclass != sclass) 314 | errorposf(p, "redefinition of %s with differing storage class", name); 315 | if(sym->init && n) 316 | errorposf(p, "%s already initialized", name); 317 | if(!sym->init && n) { 318 | sym->init = n; 319 | emitsym(sym); 320 | removetentativesym(sym); 321 | } 322 | break; 323 | default: 324 | errorposf(p, "redefinition of %s", name); 325 | } 326 | return sym; 327 | } 328 | sym = xmalloc(sizeof(Sym)); 329 | sym->name = name; 330 | sym->type = type; 331 | sym->init = n; 332 | switch(sclass) { 333 | case SCAUTO: 334 | sym->k = SYMLOCAL; 335 | sym->Local.slot = xmalloc(sizeof(StkSlot)); 336 | sym->Local.slot->size = sym->type->size; 337 | sym->Local.slot->align = sym->type->align; 338 | vecappend(curfunc->Func.stkslots, sym->Local.slot); 339 | break; 340 | case SCTYPEDEF: 341 | sym->k = SYMTYPE; 342 | break; 343 | case SCEXTERN: 344 | sym->k = SYMGLOBAL; 345 | sym->Global.label = name; 346 | sym->Global.sclass = SCEXTERN; 347 | break; 348 | case SCGLOBAL: 349 | sym->k = SYMGLOBAL; 350 | sym->Global.label = name; 351 | sym->Global.sclass = SCGLOBAL; 352 | break; 353 | case SCSTATIC: 354 | sym->k = SYMGLOBAL; 355 | sym->Global.label = newlabel(); 356 | sym->Global.sclass = SCSTATIC; 357 | break; 358 | default: 359 | panic("internal error"); 360 | } 361 | if(sym->k == SYMGLOBAL) { 362 | if(sym->init) 363 | emitsym(sym); 364 | else if(sym->Global.sclass == SCEXTERN) 365 | emitsym(sym); 366 | else 367 | if(!isfunc(sym->type)) 368 | addtentativesym(sym); 369 | } 370 | if(!define(syms, name, sym)) 371 | panic("internal error"); 372 | return sym; 373 | } 374 | 375 | static NameTy * 376 | newnamety(char *n, CTy *t) 377 | { 378 | NameTy *nt; 379 | 380 | nt = xmalloc(sizeof(NameTy)); 381 | nt->name = n; 382 | nt->type = t; 383 | return nt; 384 | } 385 | 386 | static Node * 387 | mknode(int type, SrcPos *p) 388 | { 389 | Node *n; 390 | 391 | n = xmalloc(sizeof(Node)); 392 | n->pos = *p; 393 | n->t = type; 394 | return n; 395 | } 396 | 397 | static Node * 398 | mkblock(SrcPos *p, Vec *v) 399 | { 400 | Node *n; 401 | 402 | n = mknode(NBLOCK, p); 403 | n->Block.stmts = v; 404 | return n; 405 | } 406 | 407 | static Node * 408 | mkincdec(SrcPos *p, int op, int post, Node *operand) 409 | { 410 | Node *n; 411 | 412 | if(!islval(operand)) 413 | errorposf(&operand->pos, "++ and -- expects an lvalue"); 414 | n = mknode(NINCDEC, p); 415 | n->Incdec.op = op; 416 | n->Incdec.post = post; 417 | n->Incdec.operand = operand; 418 | n->type = operand->type; 419 | return n; 420 | } 421 | 422 | static Node * 423 | mkptradd(SrcPos *p, Node *ptr, Node *offset) 424 | { 425 | Node *n; 426 | if(!isptr(ptr->type)) 427 | panic("internal error"); 428 | if(!isitype(offset->type)) 429 | errorposf(&offset->pos, "addition with a pointer requires an integer type"); 430 | n = mknode(NPTRADD, p); 431 | n->Ptradd.ptr = ptr; 432 | n->Ptradd.offset = offset; 433 | n->type = ptr->type; 434 | return n; 435 | } 436 | 437 | static Node * 438 | mkbinop(SrcPos *p, int op, Node *l, Node *r) 439 | { 440 | Node *n; 441 | CTy *t; 442 | 443 | t = 0; 444 | if(op == '+') { 445 | if(isptr(l->type)) 446 | return mkptradd(p, l, r); 447 | if(isptr(r->type)) 448 | return mkptradd(p, r, l); 449 | } 450 | 451 | if(!isptr(l->type)) 452 | l = ipromote(l); 453 | if(!isptr(r->type)) 454 | r = ipromote(r); 455 | if(!isptr(l->type) && !isptr(r->type)) 456 | t = usualarithconv(&l, &r); 457 | /* Other relationals? */ 458 | if(op == TOKEQL || op == TOKNEQ) 459 | t = cint; 460 | n = mknode(NBINOP, p); 461 | n->Binop.op = op; 462 | n->Binop.l = l; 463 | n->Binop.r = r; 464 | n->type = t; 465 | return n; 466 | } 467 | 468 | static Node * 469 | mkassign(SrcPos *p, int op, Node *l, Node *r) 470 | { 471 | Node *n; 472 | CTy *t; 473 | 474 | if(!islval(l)) 475 | errorposf(&l->pos, "assign expects an lvalue"); 476 | r = mkcast(p, r, l->type); 477 | t = l->type; 478 | n = mknode(NASSIGN, p); 479 | switch(op) { 480 | case '=': 481 | n->Assign.op = '='; 482 | break; 483 | case TOKADDASS: 484 | n->Assign.op = '+'; 485 | break; 486 | case TOKSUBASS: 487 | n->Assign.op = '-'; 488 | break; 489 | case TOKORASS: 490 | n->Assign.op = '|'; 491 | break; 492 | case TOKANDASS: 493 | n->Assign.op = '&'; 494 | break; 495 | case TOKMULASS: 496 | n->Assign.op = '*'; 497 | break; 498 | default: 499 | panic("mkassign"); 500 | } 501 | n->Assign.l = l; 502 | n->Assign.r = r; 503 | n->type = t; 504 | return n; 505 | } 506 | 507 | static Node * 508 | mkunop(SrcPos *p, int op, Node *o) 509 | { 510 | Node *n; 511 | 512 | n = mknode(NUNOP, p); 513 | n->Unop.op = op; 514 | switch(op) { 515 | case '&': 516 | if(!islval(o)) 517 | errorposf(&o->pos, "& expects an lvalue"); 518 | n->type = mkptr(o->type); 519 | break; 520 | case '*': 521 | if(!isptr(o->type)) 522 | errorposf(&o->pos, "cannot deref non pointer"); 523 | n->type = o->type->Ptr.subty; 524 | break; 525 | default: 526 | if(isitype(o->type)) 527 | o = ipromote(o); 528 | n->type = o->type; 529 | break; 530 | } 531 | n->Unop.operand = o; 532 | return n; 533 | } 534 | 535 | static Node * 536 | mkcast(SrcPos *p, Node *o, CTy *to) 537 | { 538 | Node *n; 539 | 540 | if(sametype(o->type, to)) 541 | return o; 542 | n = mknode(NCAST, p); 543 | n->type = to; 544 | n->Cast.operand = o; 545 | return n; 546 | } 547 | 548 | static Node * 549 | ipromote(Node *n) 550 | { 551 | if(!isitype(n->type)) 552 | errorposf(&n->pos, "internal error - ipromote expects itype got %d", n->type->t); 553 | switch(n->type->Prim.type) { 554 | case PRIMCHAR: 555 | case PRIMSHORT: 556 | if(n->type->Prim.issigned) 557 | return mkcast(&n->pos, n, cint); 558 | else 559 | return mkcast(&n->pos, n, cuint); 560 | } 561 | return n; 562 | } 563 | 564 | static CTy * 565 | usualarithconv(Node **a, Node **b) 566 | { 567 | Node **large, **small; 568 | CTy *t; 569 | 570 | if(!isarithtype((*a)->type) || !isarithtype((*b)->type)) 571 | panic("internal error\n"); 572 | if(convrank((*a)->type) < convrank((*b)->type)) { 573 | large = a; 574 | small = b; 575 | } else { 576 | large = b; 577 | small = a; 578 | } 579 | if(isftype((*large)->type)) { 580 | *small = mkcast(&(*small)->pos, *small, (*large)->type); 581 | return (*large)->type; 582 | } 583 | *large = ipromote(*large); 584 | *small = ipromote(*small); 585 | if(sametype((*large)->type, (*small)->type)) 586 | return (*large)->type; 587 | if((*large)->type->Prim.issigned == (*small)->type->Prim.issigned ) { 588 | *small = mkcast(&(*small)->pos, *small, (*large)->type); 589 | return (*large)->type; 590 | } 591 | if(!(*large)->type->Prim.issigned) { 592 | *small = mkcast(&(*small)->pos, *small, (*large)->type); 593 | return (*large)->type; 594 | } 595 | if((*large)->type->Prim.issigned && canrepresent((*large)->type, (*small)->type)) { 596 | *small = mkcast(&(*small)->pos, *small, (*large)->type); 597 | return (*large)->type; 598 | } 599 | t = xmalloc(sizeof(CTy)); 600 | *t = *((*large)->type); 601 | t->Prim.issigned = 0; 602 | *large = mkcast(&(*large)->pos, *large, t); 603 | *small = mkcast(&(*small)->pos, *small, t); 604 | return t; 605 | } 606 | 607 | static void 608 | next(void) 609 | { 610 | tok = nexttok; 611 | nexttok = pp(); 612 | } 613 | 614 | static void 615 | expect(Tokkind kind) 616 | { 617 | if(tok->k != kind) 618 | errorposf(&tok->pos,"expected %s, got %s", 619 | tokktostr(kind), tokktostr(tok->k)); 620 | next(); 621 | } 622 | 623 | void 624 | parse() 625 | { 626 | int i; 627 | Sym *sym; 628 | 629 | switchdepth = 0; 630 | brkdepth = 0; 631 | contdepth = 0; 632 | nscopes = 0; 633 | tentativesyms = vec(); 634 | pushscope(); 635 | next(); 636 | next(); 637 | while(tok->k != TOKEOF) 638 | decl(); 639 | for(i = 0; i < tentativesyms->len; i++) { 640 | sym = vecget(tentativesyms, i); 641 | emitsym(sym); 642 | } 643 | } 644 | 645 | static void 646 | params(CTy *fty) 647 | { 648 | int sclass; 649 | CTy *t; 650 | char *name; 651 | SrcPos *pos; 652 | 653 | fty->Func.isvararg = 0; 654 | if(tok->k == ')') 655 | return; 656 | if(tok->k == TOKVOID && nexttok->k == ')') { 657 | next(); 658 | return; 659 | } 660 | for(;;) { 661 | pos = &tok->pos; 662 | t = declspecs(&sclass); 663 | t = declarator(t, &name, 0); 664 | if(sclass != SCNONE) 665 | errorposf(pos, "storage class not allowed in parameter decl"); 666 | vecappend(fty->Func.params, newnamety(name, t)); 667 | if(tok->k != ',') 668 | break; 669 | next(); 670 | if(tok->k == TOKELLIPSIS) { 671 | fty->Func.isvararg = 1; 672 | next(); 673 | break; 674 | } 675 | } 676 | } 677 | 678 | static Node * 679 | decl() 680 | { 681 | Node *n, *init; 682 | char *name; 683 | CTy *type, *basety; 684 | SrcPos *pos; 685 | Sym *sym; 686 | Vec *syms; 687 | int sclass; 688 | 689 | pos = &tok->pos; 690 | syms = vec(); 691 | basety = declspecs(&sclass); 692 | while(tok->k != ';' && tok->k != TOKEOF) { 693 | type = declarator(basety, &name, &init); 694 | switch(sclass){ 695 | case SCNONE: 696 | if(isglobal()) { 697 | sclass = SCGLOBAL; 698 | } else { 699 | sclass = SCAUTO; 700 | } 701 | break; 702 | case SCTYPEDEF: 703 | if(init) 704 | errorposf(pos, "typedef cannot have an initializer"); 705 | break; 706 | } 707 | if(!name) 708 | errorposf(pos, "decl needs to specify a name"); 709 | sym = definesym(pos, sclass, name, type, init); 710 | vecappend(syms, sym); 711 | if(isglobal() && tok->k == '{') { 712 | if(init) 713 | errorposf(pos, "function declaration has an initializer"); 714 | if(type->t != CFUNC) 715 | errorposf(pos, "expected a function"); 716 | curfunc = mknode(NFUNC, pos); 717 | curfunc->type = type; 718 | curfunc->Func.name = name; 719 | curfunc->Func.params = vec(); 720 | curfunc->Func.stkslots = vec(); 721 | fbody(); 722 | definesym(pos, sclass, name, type, curfunc); 723 | curfunc = 0; 724 | goto done; 725 | } 726 | if(tok->k == ',') 727 | next(); 728 | else 729 | break; 730 | } 731 | expect(';'); 732 | done: 733 | n = mknode(NDECL, pos); 734 | n->Decl.syms = syms; 735 | return n; 736 | } 737 | 738 | static void 739 | fbody(void) 740 | { 741 | Node *gotofixup; 742 | int i; 743 | char *l; 744 | NameTy *nt; 745 | Sym *sym; 746 | 747 | pushscope(); 748 | labels = map(); 749 | gotos = vec(); 750 | for(i = 0; i < curfunc->type->Func.params->len; i++) { 751 | nt = vecget(curfunc->type->Func.params, i); 752 | if(nt->name) { 753 | sym = definesym(&curfunc->pos, SCAUTO, nt->name, nt->type, 0); 754 | sym->Local.isparam = 1; 755 | sym->Local.paramidx = i; 756 | sym->Local.functy = curfunc->type; 757 | vecappend(curfunc->Func.params, sym); 758 | } 759 | } 760 | curfunc->Func.body = block(); 761 | popscope(); 762 | for(i = 0 ; i < gotos->len ; i++) { 763 | gotofixup = vecget(gotos, i); 764 | l = mapget(labels, gotofixup->Goto.name); 765 | if(!l) 766 | errorposf(&gotofixup->pos, "goto target does not exist"); 767 | gotofixup->Goto.l = l; 768 | } 769 | } 770 | 771 | static int 772 | issclasstok(Tok *t) { 773 | switch(t->k) { 774 | case TOKEXTERN: 775 | case TOKSTATIC: 776 | case TOKREGISTER: 777 | case TOKTYPEDEF: 778 | case TOKAUTO: 779 | return 1; 780 | default: 781 | return 0; 782 | } 783 | } 784 | 785 | static CTy * 786 | declspecs(int *sclass) 787 | { 788 | CTy *t; 789 | SrcPos *pos; 790 | Sym *sym; 791 | int bits; 792 | 793 | enum { 794 | BITCHAR = 1<<0, 795 | BITSHORT = 1<<1, 796 | BITINT = 1<<2, 797 | BITLONG = 1<<3, 798 | BITLONGLONG = 1<<4, 799 | BITSIGNED = 1<<5, 800 | BITUNSIGNED = 1<<6, 801 | BITFLOAT = 1<<7, 802 | BITDOUBLE = 1<<8, 803 | BITENUM = 1<<9, 804 | BITSTRUCT = 1<<10, 805 | BITVOID = 1<<11, 806 | BITIDENT = 1<<12, 807 | }; 808 | 809 | t = 0; 810 | bits = 0; 811 | pos = &tok->pos; 812 | *sclass = SCNONE; 813 | 814 | for(;;) { 815 | if(issclasstok(tok)) { 816 | if(*sclass != SCNONE) 817 | errorposf(pos, "multiple storage classes in declaration specifiers."); 818 | switch(tok->k) { 819 | case TOKEXTERN: 820 | *sclass = SCEXTERN; 821 | break; 822 | case TOKSTATIC: 823 | *sclass = SCSTATIC; 824 | break; 825 | case TOKREGISTER: 826 | *sclass = SCREGISTER; 827 | break; 828 | case TOKAUTO: 829 | *sclass = SCAUTO; 830 | break; 831 | case TOKTYPEDEF: 832 | *sclass = SCTYPEDEF; 833 | break; 834 | default: 835 | panic("internal error"); 836 | } 837 | next(); 838 | continue; 839 | } 840 | switch(tok->k) { 841 | case TOKCONST: 842 | case TOKVOLATILE: 843 | next(); 844 | break; 845 | case TOKSTRUCT: 846 | case TOKUNION: 847 | if(bits) 848 | goto err; 849 | bits |= BITSTRUCT; 850 | t = ptag(); 851 | goto done; 852 | case TOKENUM: 853 | if(bits) 854 | goto err; 855 | bits |= BITENUM; 856 | t = ptag(); 857 | goto done; 858 | case TOKVOID: 859 | if(bits&BITVOID) 860 | goto err; 861 | bits |= BITVOID; 862 | next(); 863 | goto done; 864 | case TOKCHAR: 865 | if(bits&BITCHAR) 866 | goto err; 867 | bits |= BITCHAR; 868 | next(); 869 | break; 870 | case TOKSHORT: 871 | if(bits&BITSHORT) 872 | goto err; 873 | bits |= BITSHORT; 874 | next(); 875 | break; 876 | case TOKINT: 877 | if(bits&BITINT) 878 | goto err; 879 | bits |= BITINT; 880 | next(); 881 | break; 882 | case TOKLONG: 883 | if(bits&BITLONGLONG) 884 | goto err; 885 | if(bits&BITLONG) { 886 | bits &= ~BITLONG; 887 | bits |= BITLONGLONG; 888 | } else { 889 | bits |= BITLONG; 890 | } 891 | next(); 892 | break; 893 | case TOKFLOAT: 894 | if(bits&BITFLOAT) 895 | goto err; 896 | bits |= BITFLOAT; 897 | next(); 898 | break; 899 | case TOKDOUBLE: 900 | if(bits&BITDOUBLE) 901 | goto err; 902 | bits |= BITDOUBLE; 903 | next(); 904 | break; 905 | case TOKSIGNED: 906 | if(bits&BITSIGNED) 907 | goto err; 908 | bits |= BITSIGNED; 909 | next(); 910 | break; 911 | case TOKUNSIGNED: 912 | if(bits&BITUNSIGNED) 913 | goto err; 914 | bits |= BITUNSIGNED; 915 | next(); 916 | break; 917 | case TOKIDENT: 918 | sym = lookup(syms, tok->v); 919 | if(sym && sym->k == SYMTYPE) 920 | t = sym->type; 921 | if(t && !bits) { 922 | bits |= BITIDENT; 923 | next(); 924 | goto done; 925 | } 926 | /* fallthrough */ 927 | default: 928 | goto done; 929 | } 930 | } 931 | done: 932 | switch(bits){ 933 | case BITFLOAT: 934 | return cfloat; 935 | case BITDOUBLE: 936 | return cdouble; 937 | case BITLONG|BITDOUBLE: 938 | return cldouble; 939 | case BITSIGNED|BITCHAR: 940 | case BITCHAR: 941 | return cchar; 942 | case BITUNSIGNED|BITCHAR: 943 | return cuchar; 944 | case BITSIGNED|BITSHORT|BITINT: 945 | case BITSHORT|BITINT: 946 | case BITSHORT: 947 | return cshort; 948 | case BITUNSIGNED|BITSHORT|BITINT: 949 | case BITUNSIGNED|BITSHORT: 950 | return cushort; 951 | case BITSIGNED|BITINT: 952 | case BITSIGNED: 953 | case BITINT: 954 | case 0: 955 | return cint; 956 | case BITUNSIGNED|BITINT: 957 | case BITUNSIGNED: 958 | return cuint; 959 | case BITSIGNED|BITLONG|BITINT: 960 | case BITSIGNED|BITLONG: 961 | case BITLONG|BITINT: 962 | case BITLONG: 963 | return clong; 964 | case BITUNSIGNED|BITLONG|BITINT: 965 | case BITUNSIGNED|BITLONG: 966 | return culong; 967 | case BITSIGNED|BITLONGLONG|BITINT: 968 | case BITSIGNED|BITLONGLONG: 969 | case BITLONGLONG|BITINT: 970 | case BITLONGLONG: 971 | return cllong; 972 | case BITUNSIGNED|BITLONGLONG|BITINT: 973 | case BITUNSIGNED|BITLONGLONG: 974 | return cullong; 975 | case BITVOID: 976 | t = cvoid; 977 | return t; 978 | case BITENUM: 979 | case BITSTRUCT: 980 | case BITIDENT: 981 | return t; 982 | default: 983 | goto err; 984 | } 985 | err: 986 | errorposf(pos, "invalid declaration specifiers"); 987 | return 0; 988 | } 989 | 990 | /* Declarator is what introduces names into the program. */ 991 | static CTy * 992 | declarator(CTy *basety, char **name, Node **init) 993 | { 994 | CTy *t; 995 | 996 | while (tok->k == TOKCONST || tok->k == TOKVOLATILE) 997 | next(); 998 | switch(tok->k) { 999 | case '*': 1000 | next(); 1001 | basety = mkptr(basety); 1002 | t = declarator(basety, name, init); 1003 | return t; 1004 | default: 1005 | t = directdeclarator(basety, name); 1006 | if(tok->k == '=') { 1007 | if(!init) 1008 | errorposf(&tok->pos, "unexpected initializer"); 1009 | next(); 1010 | *init = declinit(t); 1011 | } else { 1012 | if(init) 1013 | *init = 0; 1014 | } 1015 | return t; 1016 | } 1017 | 1018 | } 1019 | 1020 | static CTy * 1021 | directdeclarator(CTy *basety, char **name) 1022 | { 1023 | CTy *ty, *stub; 1024 | 1025 | *name = 0; 1026 | switch(tok->k) { 1027 | case '(': 1028 | expect('('); 1029 | stub = xmalloc(sizeof(CTy)); 1030 | *stub = *basety; 1031 | ty = declarator(stub, name, 0); 1032 | expect(')'); 1033 | *stub = *declaratortail(basety); 1034 | return ty; 1035 | case TOKIDENT: 1036 | if(name) 1037 | *name = tok->v; 1038 | next(); 1039 | return declaratortail(basety); 1040 | default: 1041 | if(!name) 1042 | errorposf(&tok->pos, "expected ident or ( but got %s", tokktostr(tok->k)); 1043 | return declaratortail(basety); 1044 | } 1045 | errorf("unreachable"); 1046 | return 0; 1047 | } 1048 | 1049 | static CTy * 1050 | declaratortail(CTy *basety) 1051 | { 1052 | SrcPos *p; 1053 | CTy *t, *newt; 1054 | Const *c; 1055 | 1056 | t = basety; 1057 | for(;;) { 1058 | c = 0; 1059 | switch (tok->k) { 1060 | case '[': 1061 | newt = newtype(CARR); 1062 | newt->Arr.subty = t; 1063 | newt->Arr.dim = -1; 1064 | next(); 1065 | if(tok->k != ']') { 1066 | p = &tok->pos; 1067 | /* XXX check for int type? */ 1068 | c = constexpr(); 1069 | if(c->p) 1070 | errorposf(p, "pointer derived constant in array size"); 1071 | newt->Arr.dim = c->v; 1072 | newt->size = newt->Arr.dim * newt->Arr.subty->size; 1073 | } 1074 | newt->align = newt->Arr.subty->align; 1075 | expect(']'); 1076 | t = newt; 1077 | break; 1078 | case '(': 1079 | newt = newtype(CFUNC); 1080 | newt->Func.rtype = basety; 1081 | newt->Func.params = vec(); 1082 | next(); 1083 | params(newt); 1084 | if(tok->k != ')') 1085 | errorposf(&tok->pos, "expected valid parameter or )"); 1086 | next(); 1087 | t = newt; 1088 | break; 1089 | default: 1090 | return t; 1091 | } 1092 | } 1093 | } 1094 | 1095 | static CTy * 1096 | ptag() 1097 | { 1098 | SrcPos *pos; 1099 | char *name; 1100 | int tkind; 1101 | CTy *namety, *bodyty; 1102 | 1103 | pos = &tok->pos; 1104 | namety = 0; 1105 | bodyty = 0; 1106 | name = 0; 1107 | switch(tok->k) { 1108 | case TOKUNION: 1109 | case TOKSTRUCT: 1110 | case TOKENUM: 1111 | tkind = tok->k; 1112 | next(); 1113 | break; 1114 | default: 1115 | errorposf(pos, "expected a tag"); 1116 | } 1117 | if(tok->k == TOKIDENT) { 1118 | name = tok->v; 1119 | next(); 1120 | namety = lookup(tags, name); 1121 | if(namety) { 1122 | switch(tkind) { 1123 | case TOKUNION: 1124 | case TOKSTRUCT: 1125 | if(namety->t != CSTRUCT) 1126 | errorposf(pos, "struct/union accessed by enum tag"); 1127 | if(namety->Struct.isunion != (tkind == TOKUNION)) 1128 | errorposf(pos, "struct/union accessed by wrong tag type"); 1129 | break; 1130 | case TOKENUM: 1131 | if(namety->t != CENUM) 1132 | errorposf(pos, "enum tag accessed by struct or union"); 1133 | break; 1134 | default: 1135 | panic("internal error"); 1136 | } 1137 | } else { 1138 | switch(tkind) { 1139 | case TOKUNION: 1140 | namety = newtype(CSTRUCT); 1141 | namety->Struct.isunion = 1; 1142 | namety->incomplete = 1; 1143 | break; 1144 | case TOKSTRUCT: 1145 | namety = newtype(CSTRUCT); 1146 | namety->incomplete = 1; 1147 | break; 1148 | case TOKENUM: 1149 | namety = newtype(CENUM); 1150 | namety->incomplete = 1; 1151 | break; 1152 | default: 1153 | panic("unreachable"); 1154 | } 1155 | mapset(tags[nscopes - 1], name, namety); 1156 | } 1157 | } 1158 | if(tok->k == '{' || !name) { 1159 | switch(tkind) { 1160 | case TOKUNION: 1161 | bodyty = pstruct(1); 1162 | break; 1163 | case TOKSTRUCT: 1164 | bodyty = pstruct(0); 1165 | break; 1166 | case TOKENUM: 1167 | bodyty = penum(); 1168 | break; 1169 | default: 1170 | panic("unreachable"); 1171 | } 1172 | } 1173 | if(!name) { 1174 | if(!bodyty) 1175 | panic("internal error"); 1176 | return bodyty; 1177 | } 1178 | if(bodyty) { 1179 | namety = mapget(tags[nscopes - 1], name); 1180 | if(!namety) { 1181 | mapset(tags[nscopes - 1], name, bodyty); 1182 | return bodyty; 1183 | } 1184 | if(!namety->incomplete) 1185 | errorposf(pos, "redefinition of tag %s", name); 1186 | *namety = *bodyty; 1187 | return namety; 1188 | } 1189 | return namety; 1190 | } 1191 | 1192 | static CTy * 1193 | pstruct(int isunion) 1194 | { 1195 | SrcPos *startpos, *p; 1196 | CTy *strct; 1197 | char *name; 1198 | int sclass; 1199 | CTy *t, *basety; 1200 | 1201 | strct = newtype(CSTRUCT); 1202 | strct->align = 1; /* XXX zero sized structs? */ 1203 | strct->Struct.isunion = isunion; 1204 | strct->Struct.exports = vec(); 1205 | strct->Struct.members = vec(); 1206 | 1207 | startpos = &tok->pos; 1208 | expect('{'); 1209 | while(tok->k != '}') { 1210 | basety = declspecs(&sclass); 1211 | for(;;) { 1212 | p = &tok->pos; 1213 | t = declarator(basety, &name, 0); 1214 | if(tok->k == ':') { 1215 | next(); 1216 | constexpr(); 1217 | } 1218 | if(t->incomplete) 1219 | errorposf(p, "incomplete type inside struct/union"); 1220 | addtostruct(strct, name, t); 1221 | if(tok->k != ',') 1222 | break; 1223 | next(); 1224 | } 1225 | expect(';'); 1226 | } 1227 | expect('}'); 1228 | finalizestruct(startpos, strct); 1229 | return strct; 1230 | } 1231 | 1232 | static CTy * 1233 | penum() 1234 | { 1235 | SrcPos *p; 1236 | char *name; 1237 | CTy *t; 1238 | Const *c; 1239 | Sym *s; 1240 | int64 v; 1241 | 1242 | v = 0; 1243 | t = newtype(CENUM); 1244 | /* TODO: backend specific? */ 1245 | t->size = 4; 1246 | t->align = 4; 1247 | t->Enum.members = vec(); 1248 | expect('{'); 1249 | for(;;) { 1250 | if(tok->k == '}') 1251 | break; 1252 | p = &tok->pos; 1253 | name = tok->v; 1254 | expect(TOKIDENT); 1255 | if(tok->k == '=') { 1256 | next(); 1257 | c = constexpr(); 1258 | if(c->p) 1259 | errorposf(p, "pointer derived constant in enum"); 1260 | v = c->v; 1261 | } 1262 | s = defineenum(p, name, t, v); 1263 | vecappend(t->Enum.members, s); 1264 | if(tok->k != ',') 1265 | break; 1266 | next(); 1267 | v += 1; 1268 | } 1269 | expect('}'); 1270 | 1271 | return t; 1272 | } 1273 | 1274 | static Node * 1275 | pif(void) 1276 | { 1277 | SrcPos *p; 1278 | Node *n, *e, *t, *f; 1279 | 1280 | p = &tok->pos; 1281 | expect(TOKIF); 1282 | expect('('); 1283 | e = expr(); 1284 | expect(')'); 1285 | t = stmt(); 1286 | if(tok->k != TOKELSE) { 1287 | f = 0; 1288 | } else { 1289 | expect(TOKELSE); 1290 | f = stmt(); 1291 | } 1292 | n = mknode(NIF, p); 1293 | n->If.lelse = newlabel(); 1294 | n->If.expr = e; 1295 | n->If.iftrue = t; 1296 | n->If.iffalse = f; 1297 | return n; 1298 | } 1299 | 1300 | static Node * 1301 | pfor(void) 1302 | { 1303 | SrcPos *p; 1304 | Node *n, *i, *c, *s, *st; 1305 | char *lstart, *lstep, *lend; 1306 | 1307 | i = 0; 1308 | c = 0; 1309 | s = 0; 1310 | st = 0; 1311 | lstart = newlabel(); 1312 | lstep = newlabel(); 1313 | lend = newlabel(); 1314 | p = &tok->pos; 1315 | expect(TOKFOR); 1316 | expect('('); 1317 | if(tok->k == ';') { 1318 | next(); 1319 | } else { 1320 | i = expr(); 1321 | expect(';'); 1322 | } 1323 | if(tok->k == ';') { 1324 | next(); 1325 | } else { 1326 | c = expr(); 1327 | expect(';'); 1328 | } 1329 | if(tok->k != ')') 1330 | s = expr(); 1331 | expect(')'); 1332 | pushcontbrk(lstep, lend); 1333 | st = stmt(); 1334 | popcontbrk(); 1335 | n = mknode(NFOR, p); 1336 | n->For.lstart = lstart; 1337 | n->For.lstep = lstep; 1338 | n->For.lend = lend; 1339 | n->For.init = i; 1340 | n->For.cond = c; 1341 | n->For.step = s; 1342 | n->For.stmt = st; 1343 | return n; 1344 | } 1345 | 1346 | static Node * 1347 | pwhile(void) 1348 | { 1349 | SrcPos *p; 1350 | Node *n, *e, *s; 1351 | char *lcont, *lbreak; 1352 | 1353 | lcont = newlabel(); 1354 | lbreak = newlabel(); 1355 | p = &tok->pos; 1356 | expect(TOKWHILE); 1357 | expect('('); 1358 | e = expr(); 1359 | expect(')'); 1360 | pushcontbrk(lcont, lbreak); 1361 | s = stmt(); 1362 | popcontbrk(); 1363 | n = mknode(NWHILE, p); 1364 | n->While.lstart = lcont; 1365 | n->While.lend = lbreak; 1366 | n->While.expr = e; 1367 | n->While.stmt = s; 1368 | return n; 1369 | } 1370 | 1371 | static Node * 1372 | dowhile(void) 1373 | { 1374 | SrcPos *p; 1375 | Node *n, *e, *s; 1376 | char *lstart, *lcont, *lbreak; 1377 | 1378 | lstart = newlabel(); 1379 | lcont = newlabel(); 1380 | lbreak = newlabel(); 1381 | p = &tok->pos; 1382 | expect(TOKDO); 1383 | pushcontbrk(lcont, lbreak); 1384 | s = stmt(); 1385 | popcontbrk(); 1386 | expect(TOKWHILE); 1387 | expect('('); 1388 | e = expr(); 1389 | expect(')'); 1390 | expect(';'); 1391 | n = mknode(NDOWHILE, p); 1392 | n->DoWhile.lstart = lstart; 1393 | n->DoWhile.lcond = lcont; 1394 | n->DoWhile.lend = lbreak; 1395 | n->DoWhile.expr = e; 1396 | n->DoWhile.stmt = s; 1397 | return n; 1398 | } 1399 | 1400 | static Node * 1401 | pswitch(void) 1402 | { 1403 | SrcPos *p; 1404 | Node *n, *e, *s; 1405 | char *lbreak; 1406 | 1407 | lbreak = newlabel(); 1408 | p = &tok->pos; 1409 | expect(TOKSWITCH); 1410 | expect('('); 1411 | e = expr(); 1412 | expect(')'); 1413 | n = mknode(NSWITCH, p); 1414 | n->Switch.lend = lbreak; 1415 | n->Switch.expr = e; 1416 | n->Switch.cases = vec(); 1417 | pushbrk(lbreak); 1418 | pushswitch(n); 1419 | s = stmt(); 1420 | popswitch(); 1421 | popbrk(); 1422 | n->Switch.stmt = s; 1423 | return n; 1424 | } 1425 | 1426 | static Node * 1427 | pgoto() 1428 | { 1429 | Node *n; 1430 | 1431 | n = mknode(NGOTO, &tok->pos); 1432 | expect(TOKGOTO); 1433 | n->Goto.name = tok->v; 1434 | expect(TOKIDENT); 1435 | expect(';'); 1436 | vecappend(gotos, n); 1437 | return n; 1438 | } 1439 | 1440 | static int 1441 | istypename(char *n) 1442 | { 1443 | Sym *sym; 1444 | 1445 | sym = lookup(syms, n); 1446 | if(sym && sym->k == SYMTYPE) 1447 | return 1; 1448 | return 0; 1449 | } 1450 | 1451 | static int 1452 | istypestart(Tok *t) 1453 | { 1454 | switch(t->k) { 1455 | case TOKENUM: 1456 | case TOKSTRUCT: 1457 | case TOKUNION: 1458 | case TOKVOID: 1459 | case TOKCHAR: 1460 | case TOKSHORT: 1461 | case TOKINT: 1462 | case TOKLONG: 1463 | case TOKSIGNED: 1464 | case TOKUNSIGNED: 1465 | return 1; 1466 | case TOKIDENT: 1467 | return istypename(t->v); 1468 | default: 1469 | return 0; 1470 | } 1471 | } 1472 | 1473 | static int 1474 | isdeclstart(Tok *t) 1475 | { 1476 | if(istypestart(t)) 1477 | return 1; 1478 | switch(tok->k) { 1479 | case TOKEXTERN: 1480 | case TOKREGISTER: 1481 | case TOKSTATIC: 1482 | case TOKAUTO: 1483 | case TOKCONST: 1484 | case TOKVOLATILE: 1485 | return 1; 1486 | case TOKIDENT: 1487 | return istypename(t->v); 1488 | default: 1489 | return 0; 1490 | } 1491 | } 1492 | 1493 | static Node * 1494 | declorstmt() 1495 | { 1496 | if(isdeclstart(tok)) 1497 | return decl(); 1498 | return stmt(); 1499 | } 1500 | 1501 | static Node * 1502 | stmt(void) 1503 | { 1504 | Tok *t; 1505 | Node *n; 1506 | char *label; 1507 | 1508 | if(tok->k == TOKIDENT && nexttok->k == ':') { 1509 | t = tok; 1510 | label = newlabel(); 1511 | next(); 1512 | next(); 1513 | if(mapget(labels, t->v)) 1514 | errorposf(&t->pos, "redefinition of label %s", t->v); 1515 | mapset(labels, t->v, label); 1516 | n = mknode(NLABELED, &t->pos); 1517 | n->Labeled.stmt = stmt(); 1518 | n->Labeled.l = label; 1519 | return n; 1520 | } 1521 | switch(tok->k) { 1522 | case TOKIF: 1523 | return pif(); 1524 | case TOKFOR: 1525 | return pfor(); 1526 | case TOKWHILE: 1527 | return pwhile(); 1528 | case TOKDO: 1529 | return dowhile(); 1530 | case TOKRETURN: 1531 | return preturn(); 1532 | case TOKSWITCH: 1533 | return pswitch(); 1534 | case TOKCASE: 1535 | return pcase(); 1536 | case TOKDEFAULT: 1537 | return pdefault(); 1538 | case TOKBREAK: 1539 | return pbreak(); 1540 | case TOKCONTINUE: 1541 | return pcontinue(); 1542 | case TOKGOTO: 1543 | return pgoto(); 1544 | case '{': 1545 | return block(); 1546 | default: 1547 | return exprstmt(); 1548 | } 1549 | } 1550 | 1551 | static int 1552 | compareinits(const void *lvoid, const void *rvoid) 1553 | { 1554 | const InitMember *l, *r; 1555 | 1556 | l = *(void**)lvoid; 1557 | r = *(void**)rvoid; 1558 | if(l->offset < r->offset) 1559 | return -1; 1560 | if(l->offset > r->offset) 1561 | return 1; 1562 | return 0; 1563 | } 1564 | 1565 | static void 1566 | checkinitoverlap(Node *n) 1567 | { 1568 | InitMember *init, *nextinit; 1569 | int i; 1570 | 1571 | qsort(n->Init.inits->d, n->Init.inits->len, sizeof(void*), compareinits); 1572 | for(i = 0; i < n->Init.inits->len - 1; i++) { 1573 | init = vecget(n->Init.inits, i); 1574 | nextinit = vecget(n->Init.inits, i + 1); 1575 | if(nextinit->offset < init->offset + init->n->type->size) 1576 | errorposf(&init->n->pos, "fields in init overlaps with another field"); 1577 | } 1578 | } 1579 | 1580 | static Node * 1581 | declarrayinit(CTy *t) 1582 | { 1583 | InitMember *initmemb; 1584 | Node *n, *subinit; 1585 | CTy *subty; 1586 | SrcPos *initpos, *selpos; 1587 | Const *arrayidx; 1588 | int i; 1589 | int idx; 1590 | int largestidx; 1591 | 1592 | subty = t->Arr.subty; 1593 | initpos = &tok->pos; 1594 | n = mknode(NINIT, initpos); 1595 | n->type = t; 1596 | n->Init.inits = vec(); 1597 | idx = 0; 1598 | largestidx = 0; 1599 | expect('{'); 1600 | for(;;) { 1601 | if(tok->k == '}') 1602 | break; 1603 | if(tok->k == '[') { 1604 | selpos = &tok->pos; 1605 | expect('['); 1606 | arrayidx = constexpr(); 1607 | expect(']'); 1608 | expect('='); 1609 | if(arrayidx->p != 0) 1610 | errorposf(selpos, "pointer derived constants not allowed in initializer selector"); 1611 | if(arrayidx->v < 0) 1612 | errorposf(selpos, "negative initializer index not allowed"); 1613 | idx = arrayidx->v; 1614 | if(largestidx < idx) 1615 | largestidx = idx; 1616 | } 1617 | subinit = declinit(subty); 1618 | /* Flatten nested inits */ 1619 | if(subinit->t == NINIT) { 1620 | for(i = 0; i < subinit->Init.inits->len; i++) { 1621 | initmemb = vecget(subinit->Init.inits, i); 1622 | initmemb->offset = subty->size * idx + initmemb->offset; 1623 | vecappend(n->Init.inits, initmemb); 1624 | } 1625 | } else { 1626 | initmemb = xmalloc(sizeof(InitMember)); 1627 | initmemb->offset = subty->size * idx; 1628 | initmemb->n = subinit; 1629 | vecappend(n->Init.inits, initmemb); 1630 | } 1631 | idx += 1; 1632 | if(largestidx < idx) 1633 | largestidx = idx; 1634 | if(tok->k != ',') 1635 | break; 1636 | next(); 1637 | } 1638 | checkinitoverlap(n); 1639 | expect('}'); 1640 | if(t->Arr.dim == -1) 1641 | t->Arr.dim = largestidx; 1642 | if(largestidx != t->Arr.dim) 1643 | errorposf(initpos, "array initializer wrong size for type"); 1644 | return n; 1645 | } 1646 | 1647 | static Node * 1648 | declstructinit(CTy *t) 1649 | { 1650 | StructMember *structmember; 1651 | InitMember *initmemb; 1652 | StructIter it; 1653 | Node *n, *subinit; 1654 | CTy *subty; 1655 | SrcPos *initpos, *selpos; 1656 | char *selname; 1657 | int i, offset, neednext; 1658 | 1659 | initpos = &tok->pos; 1660 | if(t->incomplete) 1661 | errorposf(initpos, "cannot initialize an incomplete struct/union"); 1662 | 1663 | n = mknode(NINIT, initpos); 1664 | n->type = t; 1665 | n->Init.inits = vec(); 1666 | 1667 | initstructiter(&it, t); 1668 | expect('{'); 1669 | neednext = 0; 1670 | for(;;) { 1671 | if(tok->k == '}') 1672 | break; 1673 | if(tok->k == '.') { 1674 | neednext = 0; 1675 | selpos = &tok->pos; 1676 | expect('.'); 1677 | selname = tok->v; 1678 | expect(TOKIDENT); 1679 | expect('='); 1680 | if(!getstructiter(&it, t, selname)) 1681 | errorposf(selpos, "struct has no member '%s'", selname); 1682 | } 1683 | if(neednext) { 1684 | if(!structnext(&it)) 1685 | errorposf(&tok->pos, "end of struct already reached"); 1686 | } 1687 | structwalk(&it, &structmember, &offset); 1688 | if(!structmember) 1689 | errorposf(initpos, "too many elements in struct initializer"); 1690 | subty = structmember->type; 1691 | subinit = declinit(subty); 1692 | /* Flatten nested inits */ 1693 | if(subinit->t == NINIT) { 1694 | for(i = 0; i < subinit->Init.inits->len; i++) { 1695 | initmemb = vecget(subinit->Init.inits, i); 1696 | initmemb->offset += offset; 1697 | vecappend(n->Init.inits, initmemb); 1698 | } 1699 | } else { 1700 | initmemb = xmalloc(sizeof(InitMember)); 1701 | initmemb->offset = offset; 1702 | initmemb->n = subinit; 1703 | vecappend(n->Init.inits, initmemb); 1704 | } 1705 | if(tok->k != ',') 1706 | break; 1707 | next(); 1708 | neednext = 1; 1709 | } 1710 | checkinitoverlap(n); 1711 | expect('}'); 1712 | return n; 1713 | } 1714 | 1715 | static Node * 1716 | declinit(CTy *t) 1717 | { 1718 | if(isarray(t) && tok->k == '{') 1719 | return declarrayinit(t); 1720 | if(isstruct(t) && tok->k == '{') 1721 | return declstructinit(t); 1722 | return assignexpr(); 1723 | } 1724 | 1725 | static Node * 1726 | exprstmt(void) 1727 | { 1728 | Node *n; 1729 | 1730 | n = mknode(NEXPRSTMT, &tok->pos); 1731 | if(tok->k == ';') { 1732 | next(); 1733 | return n; 1734 | } 1735 | n->ExprStmt.expr = expr(); 1736 | expect(';'); 1737 | return n; 1738 | } 1739 | 1740 | static Node * 1741 | preturn(void) 1742 | { 1743 | Node *n; 1744 | 1745 | n = mknode(NRETURN, &tok->pos); 1746 | expect(TOKRETURN); 1747 | if(tok->k != ';') 1748 | n->Return.expr = expr(); 1749 | expect(';'); 1750 | return n; 1751 | } 1752 | 1753 | static Node * 1754 | pcontinue(void) 1755 | { 1756 | SrcPos *pos; 1757 | Node *n; 1758 | char *l; 1759 | 1760 | pos = &tok->pos; 1761 | n = mknode(NGOTO, pos); 1762 | l = curcont(); 1763 | if(!l) 1764 | errorposf(pos, "continue without parent statement"); 1765 | n->Goto.l = l; 1766 | expect(TOKCONTINUE); 1767 | expect(';'); 1768 | return n; 1769 | } 1770 | 1771 | static Node * 1772 | pbreak(void) 1773 | { 1774 | SrcPos *pos; 1775 | Node *n; 1776 | char *l; 1777 | 1778 | pos = &tok->pos; 1779 | n = mknode(NGOTO, pos); 1780 | l = curbrk(); 1781 | if(!l) 1782 | errorposf(pos, "break without parent statement"); 1783 | n->Goto.l = l; 1784 | expect(TOKBREAK); 1785 | expect(';'); 1786 | return n; 1787 | } 1788 | 1789 | static Node * 1790 | pdefault(void) 1791 | { 1792 | SrcPos *pos; 1793 | Node *n, *s; 1794 | char *l; 1795 | 1796 | pos = &tok->pos; 1797 | l = newlabel(); 1798 | n = mknode(NLABELED, pos); 1799 | n->Labeled.l = l; 1800 | s = curswitch(); 1801 | if(s->Switch.ldefault) 1802 | errorposf(pos, "switch already has default"); 1803 | s->Switch.ldefault = l; 1804 | expect(TOKDEFAULT); 1805 | expect(':'); 1806 | n->Labeled.stmt = stmt(); 1807 | return n; 1808 | } 1809 | 1810 | static Node * 1811 | pcase(void) 1812 | { 1813 | SrcPos *pos; 1814 | Node *n; 1815 | Node *s; 1816 | Const *c; 1817 | 1818 | pos = &tok->pos; 1819 | s = curswitch(); 1820 | expect(TOKCASE); 1821 | n = mknode(NCASE, pos); 1822 | c = constexpr(); 1823 | if(c->p) 1824 | errorposf(pos, "case cannot have pointer derived constant"); 1825 | n->Case.cond = c->v; 1826 | expect(':'); 1827 | n->Case.l = newlabel(); 1828 | n->Case.stmt = stmt(); 1829 | vecappend(s->Switch.cases, n); 1830 | return n; 1831 | } 1832 | 1833 | static Node * 1834 | block(void) 1835 | { 1836 | Vec *v; 1837 | SrcPos *p; 1838 | 1839 | v = vec(); 1840 | pushscope(); 1841 | p = &tok->pos; 1842 | expect('{'); 1843 | while(tok->k != '}' && tok->k != TOKEOF) 1844 | vecappend(v, declorstmt()); 1845 | expect('}'); 1846 | popscope(); 1847 | return mkblock(p, v); 1848 | } 1849 | 1850 | static Node * 1851 | expr(void) 1852 | { 1853 | SrcPos *p; 1854 | Vec *v; 1855 | Node *n, *last; 1856 | 1857 | p = &tok->pos; 1858 | n = assignexpr(); 1859 | last = n; 1860 | if(tok->k == ',') { 1861 | v = vec(); 1862 | vecappend(v, n); 1863 | while(tok->k == ',') { 1864 | next(); 1865 | last = assignexpr(); 1866 | vecappend(v, last); 1867 | } 1868 | n = mknode(NCOMMA, p); 1869 | n->Comma.exprs = v; 1870 | n->type = last->type; 1871 | } 1872 | return n; 1873 | } 1874 | 1875 | static int 1876 | isassignop(Tokkind k) 1877 | { 1878 | switch(k) { 1879 | case '=': 1880 | case TOKADDASS: 1881 | case TOKSUBASS: 1882 | case TOKMULASS: 1883 | case TOKDIVASS: 1884 | case TOKMODASS: 1885 | case TOKORASS: 1886 | case TOKANDASS: 1887 | return 1; 1888 | default: 1889 | return 0; 1890 | } 1891 | } 1892 | 1893 | static Node * 1894 | assignexpr(void) 1895 | { 1896 | Tok *t; 1897 | Node *l, *r; 1898 | 1899 | l = condexpr(); 1900 | if(isassignop(tok->k)) { 1901 | t = tok; 1902 | next(); 1903 | r = assignexpr(); 1904 | l = mkassign(&t->pos, t->k, l, r); 1905 | } 1906 | return l; 1907 | } 1908 | 1909 | static Const * 1910 | constexpr(void) 1911 | { 1912 | Const *c; 1913 | Node *n; 1914 | 1915 | n = condexpr(); 1916 | c = foldexpr(n); 1917 | if(!c) 1918 | errorposf(&n->pos, "not a constant expression"); 1919 | return c; 1920 | } 1921 | 1922 | /* Aka Ternary operator. */ 1923 | static Node * 1924 | condexpr(void) 1925 | { 1926 | Node *n, *c, *t, *f; 1927 | 1928 | c = logorexpr(); 1929 | if(tok->k != '?') 1930 | return c; 1931 | next(); 1932 | t = expr(); 1933 | expect(':'); 1934 | f = condexpr(); 1935 | n = mknode(NCOND, &tok->pos); 1936 | n->Cond.cond = c; 1937 | n->Cond.iftrue = t; 1938 | n->Cond.iffalse = f; 1939 | /* TODO: what are the limitations? */ 1940 | if(!sametype(t->type, f->type)) 1941 | errorposf(&n->pos, "both cases of ? must be same type."); 1942 | n->type = t->type; 1943 | return n; 1944 | } 1945 | 1946 | static Node * 1947 | logorexpr(void) 1948 | { 1949 | Tok *t; 1950 | Node *l, *r; 1951 | 1952 | l = logandexpr(); 1953 | while(tok->k == TOKLOR) { 1954 | t = tok; 1955 | next(); 1956 | r = logandexpr(); 1957 | l = mkbinop(&t->pos, t->k, l, r); 1958 | } 1959 | return l; 1960 | } 1961 | 1962 | static Node * 1963 | logandexpr(void) 1964 | { 1965 | Tok *t; 1966 | Node *l, *r; 1967 | 1968 | l = orexpr(); 1969 | while(tok->k == TOKLAND) { 1970 | t = tok; 1971 | next(); 1972 | r = orexpr(); 1973 | l = mkbinop(&t->pos, t->k, l, r); 1974 | } 1975 | return l; 1976 | } 1977 | 1978 | static Node * 1979 | orexpr(void) 1980 | { 1981 | Tok *t; 1982 | Node *l, *r; 1983 | 1984 | l = xorexpr(); 1985 | while(tok->k == '|') { 1986 | t = tok; 1987 | next(); 1988 | r = xorexpr(); 1989 | l = mkbinop(&t->pos, t->k, l, r); 1990 | } 1991 | return l; 1992 | } 1993 | 1994 | static Node * 1995 | xorexpr(void) 1996 | { 1997 | Tok *t; 1998 | Node *l, *r; 1999 | 2000 | l = andexpr(); 2001 | while(tok->k == '^') { 2002 | t = tok; 2003 | next(); 2004 | r = andexpr(); 2005 | l = mkbinop(&t->pos, t->k, l, r); 2006 | } 2007 | return l; 2008 | } 2009 | 2010 | static Node * 2011 | andexpr(void) 2012 | { 2013 | Tok *t; 2014 | Node *l, *r; 2015 | 2016 | l = eqlexpr(); 2017 | while(tok->k == '&') { 2018 | t = tok; 2019 | next(); 2020 | r = eqlexpr(); 2021 | l = mkbinop(&t->pos, t->k, l, r); 2022 | } 2023 | return l; 2024 | } 2025 | 2026 | static Node * 2027 | eqlexpr(void) 2028 | { 2029 | Tok *t; 2030 | Node *l, *r; 2031 | 2032 | l = relexpr(); 2033 | while(tok->k == TOKEQL || tok->k == TOKNEQ) { 2034 | t = tok; 2035 | next(); 2036 | r = relexpr(); 2037 | l = mkbinop(&t->pos, t->k, l, r); 2038 | } 2039 | return l; 2040 | } 2041 | 2042 | static Node * 2043 | relexpr(void) 2044 | { 2045 | Tok *t; 2046 | Node *l, *r; 2047 | 2048 | l = shiftexpr(); 2049 | while(tok->k == '>' || tok->k == '<' 2050 | || tok->k == TOKLEQ || tok->k == TOKGEQ) { 2051 | t = tok; 2052 | next(); 2053 | r = shiftexpr(); 2054 | l = mkbinop(&t->pos, t->k, l, r); 2055 | } 2056 | return l; 2057 | } 2058 | 2059 | static Node * 2060 | shiftexpr(void) 2061 | { 2062 | Tok *t; 2063 | Node *l, *r; 2064 | 2065 | l = addexpr(); 2066 | while(tok->k == TOKSHL || tok->k == TOKSHR) { 2067 | t = tok; 2068 | next(); 2069 | r = addexpr(); 2070 | l = mkbinop(&t->pos, t->k, l, r); 2071 | } 2072 | return l; 2073 | } 2074 | 2075 | static Node * 2076 | addexpr(void) 2077 | { 2078 | Tok *t; 2079 | Node *l, *r; 2080 | 2081 | l = mulexpr(); 2082 | while(tok->k == '+' || tok->k == '-' ) { 2083 | t = tok; 2084 | next(); 2085 | r = mulexpr(); 2086 | l = mkbinop(&t->pos, t->k, l, r); 2087 | } 2088 | return l; 2089 | } 2090 | 2091 | static Node * 2092 | mulexpr(void) 2093 | { 2094 | Tok *t; 2095 | Node *l, *r; 2096 | 2097 | l = castexpr(); 2098 | while(tok->k == '*' || tok->k == '/' || tok->k == '%') { 2099 | t = tok; 2100 | next(); 2101 | r = castexpr(); 2102 | l = mkbinop(&t->pos, t->k, l, r); 2103 | } 2104 | return l; 2105 | } 2106 | 2107 | static Node * 2108 | castexpr(void) 2109 | { 2110 | Tok *t; 2111 | Node *o; 2112 | CTy *ty; 2113 | 2114 | if(tok->k == '(' && istypestart(nexttok)) { 2115 | t = tok; 2116 | expect('('); 2117 | ty = typename(); 2118 | expect(')'); 2119 | if(tok->k == '{') { 2120 | o = declinit(ty); 2121 | return o; 2122 | } 2123 | o = unaryexpr(); 2124 | return mkcast(&t->pos, o, ty); 2125 | } 2126 | return unaryexpr(); 2127 | } 2128 | 2129 | static CTy * 2130 | typename(void) 2131 | { 2132 | int sclass; 2133 | CTy *t; 2134 | char *name; 2135 | 2136 | t = declspecs(&sclass); 2137 | t = declarator(t, &name, 0); 2138 | return t; 2139 | } 2140 | 2141 | static Node * 2142 | unaryexpr(void) 2143 | { 2144 | Tok *t; 2145 | CTy *ty; 2146 | Node *n; 2147 | 2148 | switch (tok->k) { 2149 | case TOKINC: 2150 | case TOKDEC: 2151 | t = tok; 2152 | next(); 2153 | n = unaryexpr(); 2154 | return mkincdec(&t->pos, t->k, 0, n); 2155 | case '*': 2156 | case '&': 2157 | case '-': 2158 | case '!': 2159 | case '~': 2160 | t = tok; 2161 | next(); 2162 | return mkunop(&t->pos, t->k, castexpr()); 2163 | case TOKSIZEOF: 2164 | n = mknode(NSIZEOF, &tok->pos); 2165 | next(); 2166 | if(tok->k == '(' && istypestart(nexttok)) { 2167 | expect('('); 2168 | ty = typename(); 2169 | expect(')'); 2170 | } else { 2171 | ty = unaryexpr()->type; 2172 | } 2173 | n->Sizeof.type = ty; 2174 | n->type = cint; 2175 | return n; 2176 | default: 2177 | ; 2178 | } 2179 | return postexpr(); 2180 | } 2181 | 2182 | static Node * 2183 | call(Node *funclike) 2184 | { 2185 | Node *n; 2186 | CTy *fty; 2187 | SrcPos *pos ; 2188 | 2189 | pos = &tok->pos; 2190 | expect('('); 2191 | n = mknode(NCALL, &tok->pos); 2192 | n->Call.funclike = funclike; 2193 | n->Call.args = vec(); 2194 | if(isfunc(funclike->type)) 2195 | fty = funclike->type; 2196 | else if (isfuncptr(funclike->type)) 2197 | fty = funclike->type->Ptr.subty; 2198 | else 2199 | errorposf(pos, "cannot call non function"); 2200 | n->type = fty->Func.rtype; 2201 | if(tok->k != ')') { 2202 | for(;;) { 2203 | vecappend(n->Call.args, assignexpr()); 2204 | if(tok->k != ',') { 2205 | break; 2206 | } 2207 | next(); 2208 | } 2209 | } 2210 | expect(')'); 2211 | if(n->Call.args->len < fty->Func.params->len) 2212 | errorposf(pos, "function called with too few args"); 2213 | if(n->Call.args->len > fty->Func.params->len && !fty->Func.isvararg) 2214 | errorposf(pos, "function called with too many args"); 2215 | return n; 2216 | } 2217 | 2218 | static Node * 2219 | postexpr(void) 2220 | { 2221 | int done; 2222 | Tok *t; 2223 | Node *n1, *n2, *n3; 2224 | 2225 | n1 = primaryexpr(); 2226 | done = 0; 2227 | while(!done) { 2228 | switch(tok->k) { 2229 | case '[': 2230 | t = tok; 2231 | next(); 2232 | n2 = expr(); 2233 | expect(']'); 2234 | n3 = mknode(NIDX, &t->pos); 2235 | if(isptr(n1->type)) 2236 | n3->type = n1->type->Ptr.subty; 2237 | else if (isarray(n1->type)) 2238 | n3->type = n1->type->Arr.subty; 2239 | else 2240 | errorposf(&t->pos, "can only index an array or pointer"); 2241 | n3->Idx.idx = n2; 2242 | n3->Idx.operand = n1; 2243 | n1 = n3; 2244 | break; 2245 | case '.': 2246 | if(!isstruct(n1->type)) 2247 | errorposf(&tok->pos, "expected a struct"); 2248 | if(n1->type->incomplete) 2249 | errorposf(&tok->pos, "selector on incomplete type"); 2250 | n2 = mknode(NSEL, &tok->pos); 2251 | next(); 2252 | n2->Sel.name = tok->v; 2253 | n2->Sel.operand = n1; 2254 | n2->type = structtypefromname(n1->type, tok->v); 2255 | if(!n2->type) 2256 | errorposf(&tok->pos, "struct has no member %s", tok->v); 2257 | expect(TOKIDENT); 2258 | n1 = n2; 2259 | break; 2260 | case TOKARROW: 2261 | if(!(isptr(n1->type) && isstruct(n1->type->Ptr.subty))) 2262 | errorposf(&tok->pos, "expected a struct pointer"); 2263 | if(n1->type->Ptr.subty->incomplete) 2264 | errorposf(&tok->pos, "selector on incomplete type"); 2265 | n2 = mknode(NSEL, &tok->pos); 2266 | next(); 2267 | n2->Sel.name = tok->v; 2268 | n2->Sel.operand = n1; 2269 | n2->Sel.arrow = 1; 2270 | n2->type = structtypefromname(n1->type->Ptr.subty, tok->v); 2271 | if(!n2->type) 2272 | errorposf(&tok->pos, "struct pointer has no member %s", tok->v); 2273 | expect(TOKIDENT); 2274 | n1 = n2; 2275 | break; 2276 | case '(': 2277 | n1 = call(n1); 2278 | break; 2279 | case TOKINC: 2280 | n1 = mkincdec(&tok->pos, TOKINC, 1, n1); 2281 | next(); 2282 | break; 2283 | case TOKDEC: 2284 | n1 = mkincdec(&tok->pos, TOKDEC, 1, n1); 2285 | next(); 2286 | break; 2287 | default: 2288 | done = 1; 2289 | } 2290 | } 2291 | return n1; 2292 | } 2293 | 2294 | static Node * 2295 | primaryexpr(void) 2296 | { 2297 | Sym *sym; 2298 | Node *n; 2299 | 2300 | switch (tok->k) { 2301 | case TOKIDENT: 2302 | if(strcmp(tok->v, "__builtin_va_start") == 0) 2303 | return vastart(); 2304 | sym = lookup(syms, tok->v); 2305 | if(!sym) 2306 | errorposf(&tok->pos, "undefined symbol %s", tok->v); 2307 | n = mknode(NIDENT, &tok->pos); 2308 | n->Ident.sym = sym; 2309 | n->type = sym->type; 2310 | next(); 2311 | return n; 2312 | case TOKNUM: 2313 | n = mknode(NNUM, &tok->pos); 2314 | n->Num.v = atoll(tok->v); 2315 | n->type = cint; 2316 | next(); 2317 | return n; 2318 | case TOKCHARLIT: 2319 | /* XXX it seems wrong to do this here, also table is better */ 2320 | n = mknode(NNUM, &tok->pos); 2321 | if(strcmp(tok->v, "'\\n'") == 0) { 2322 | n->Num.v = '\n'; 2323 | } else if(strcmp(tok->v, "'\\\\'") == 0) { 2324 | n->Num.v = '\\'; 2325 | } else if(strcmp(tok->v, "'\\''") == 0) { 2326 | n->Num.v = '\''; 2327 | } else if(strcmp(tok->v, "'\\r'") == 0) { 2328 | n->Num.v = '\r'; 2329 | } else if(strcmp(tok->v, "'\\t'") == 0) { 2330 | n->Num.v = '\t'; 2331 | } else if(tok->v[1] == '\\') { 2332 | errorposf(&tok->pos, "unknown escape code"); 2333 | } else { 2334 | n->Num.v = tok->v[1]; 2335 | } 2336 | n->type = cint; 2337 | next(); 2338 | return n; 2339 | case TOKSTR: 2340 | n = mknode(NSTR, &tok->pos); 2341 | n->Str.v = tok->v; 2342 | n->type = mkptr(cchar); 2343 | next(); 2344 | return n; 2345 | case '(': 2346 | next(); 2347 | n = expr(); 2348 | expect(')'); 2349 | return n; 2350 | default: 2351 | errorposf(&tok->pos, "expected an ident, constant, string or ("); 2352 | } 2353 | errorf("unreachable."); 2354 | return 0; 2355 | } 2356 | 2357 | static Node * 2358 | vastart() 2359 | { 2360 | Node *n, *valist, *param; 2361 | 2362 | n = mknode(NBUILTIN, &tok->pos); 2363 | expect(TOKIDENT); 2364 | expect('('); 2365 | valist = assignexpr(); 2366 | expect(','); 2367 | param = assignexpr(); 2368 | expect(')'); 2369 | n->type = cvoid; 2370 | n->Builtin.t = BUILTIN_VASTART; 2371 | n->Builtin.Vastart.param = param; 2372 | n->Builtin.Vastart.valist = valist; 2373 | if(param->t != NIDENT) 2374 | errorposf(&n->pos, "expected an identifer in va_start"); 2375 | if(param->Ident.sym->k != SYMLOCAL 2376 | || !param->Ident.sym->Local.isparam) 2377 | errorposf(&n->pos, "expected a parameter symbol in va_start"); 2378 | return n; 2379 | } 2380 | 2381 | -------------------------------------------------------------------------------- /src/cc/types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cc.h" 5 | 6 | static int 7 | align(int v, int a) 8 | { 9 | if(v % a) 10 | return v + a - (v % a); 11 | return v; 12 | } 13 | 14 | CTy * 15 | newtype(int type) 16 | { 17 | CTy *t; 18 | 19 | t = xmalloc(sizeof(CTy)); 20 | t->t = type; 21 | return t; 22 | } 23 | 24 | CTy * 25 | mkptr(CTy *t) 26 | { 27 | CTy *p; 28 | 29 | p = newtype(CPTR); 30 | p->Ptr.subty = t; 31 | p->size = 8; 32 | p->align = 8; 33 | return p; 34 | } 35 | 36 | 37 | int 38 | convrank(CTy *t) 39 | { 40 | if(t->t != CPRIM && t->t != CENUM) 41 | panic("internal error"); 42 | if(t->t == CENUM) 43 | return 2; 44 | switch(t->Prim.type){ 45 | case PRIMCHAR: 46 | return 0; 47 | case PRIMSHORT: 48 | return 1; 49 | case PRIMINT: 50 | return 2; 51 | case PRIMLONG: 52 | return 3; 53 | case PRIMLLONG: 54 | return 4; 55 | case PRIMFLOAT: 56 | return 5; 57 | case PRIMDOUBLE: 58 | return 6; 59 | case PRIMLDOUBLE: 60 | return 7; 61 | default: 62 | panic("internal error"); 63 | return -1; 64 | } 65 | } 66 | 67 | int 68 | compatiblestruct(CTy *l, CTy *r) 69 | { 70 | if(l || r) 71 | errorf("unimplemented compatiblestruct"); 72 | /* TODO */ 73 | return 0; 74 | } 75 | 76 | int 77 | sametype(CTy *l, CTy *r) 78 | { 79 | int i; 80 | NameTy *lnt, *rnt; 81 | StructMember *lsm, *rsm; 82 | 83 | if(l == r) 84 | return 1; 85 | switch(l->t) { 86 | case CENUM: 87 | if(r->t != CENUM) 88 | return 0; 89 | return 1; 90 | case CVOID: 91 | if(r->t != CVOID) 92 | return 0; 93 | return 1; 94 | case CPRIM: 95 | if(r->t != CPRIM) 96 | return 0; 97 | if(l->Prim.issigned != r->Prim.issigned) 98 | return 0; 99 | if(l->Prim.type != r->Prim.type) 100 | return 0; 101 | return 1; 102 | case CPTR: 103 | if(r->t != CPTR) 104 | return 0; 105 | return sametype(l->Ptr.subty, r->Ptr.subty); 106 | case CFUNC: 107 | if(r->t != CFUNC) 108 | return 0; 109 | if(!sametype(l->Func.rtype, r->Func.rtype)) 110 | return 0; 111 | if(l->Func.isvararg != r->Func.isvararg) 112 | return 0; 113 | if(l->Func.params->len != r->Func.params->len) 114 | return 0; 115 | for(i = 0; i < l->Func.params->len; i++) { 116 | lnt = vecget(l->Func.params, i); 117 | rnt = vecget(r->Func.params, i); 118 | if(!sametype(lnt->type, rnt->type)) 119 | return 0; 120 | } 121 | return 1; 122 | case CSTRUCT: 123 | if(r->t != CSTRUCT) 124 | return 0; 125 | if(l->incomplete || r->incomplete) 126 | return l->incomplete == r->incomplete; 127 | if(l->Struct.members->len != r->Struct.members->len) 128 | return 0; 129 | for(i = 0; i < l->Struct.members->len; i++) { 130 | lsm = vecget(l->Struct.members, i); 131 | rsm = vecget(r->Struct.members, i); 132 | if(!sametype(lsm->type, rsm->type)) 133 | return 0; 134 | } 135 | return 1; 136 | case CARR: 137 | if(r->t != CARR) 138 | return 0; 139 | if(r->Arr.dim != l->Arr.dim) 140 | return 0; 141 | return 1; 142 | default: 143 | panic("unimplemented same type"); 144 | } 145 | return 0; 146 | } 147 | 148 | int 149 | isftype(CTy *t) 150 | { 151 | if(t->t != CPRIM) 152 | return 0; 153 | switch(t->Prim.type){ 154 | case PRIMFLOAT: 155 | case PRIMDOUBLE: 156 | case PRIMLDOUBLE: 157 | return 1; 158 | } 159 | return 0; 160 | } 161 | 162 | int 163 | isvoid(CTy *t) 164 | { 165 | return t->t == CVOID; 166 | } 167 | 168 | int 169 | isitype(CTy *t) 170 | { 171 | if(t->t == CENUM) 172 | return 1; 173 | if(t->t != CPRIM) 174 | return 0; 175 | switch(t->Prim.type){ 176 | case PRIMCHAR: 177 | case PRIMSHORT: 178 | case PRIMINT: 179 | case PRIMLONG: 180 | case PRIMLLONG: 181 | return 1; 182 | } 183 | return 0; 184 | } 185 | 186 | int 187 | isarithtype(CTy *t) 188 | { 189 | return isftype(t) || isitype(t); 190 | } 191 | 192 | int 193 | isptr(CTy *t) 194 | { 195 | return t->t == CPTR; 196 | } 197 | 198 | int 199 | ischarptr(CTy *t) 200 | { 201 | if(!isptr(t)) 202 | return 0; 203 | if(t->Ptr.subty->t != CPRIM) 204 | return 0; 205 | return t->Ptr.subty->Prim.type == PRIMCHAR; 206 | } 207 | 208 | int 209 | ischararray(CTy *t) 210 | { 211 | if(!isarray(t)) 212 | return 0; 213 | if(t->Ptr.subty->t != CPRIM) 214 | return 0; 215 | return t->Ptr.subty->Prim.type == PRIMCHAR; 216 | } 217 | 218 | int 219 | isfunc(CTy *t) 220 | { 221 | return t->t == CFUNC; 222 | } 223 | 224 | int 225 | isfuncptr(CTy *t) 226 | { 227 | return isptr(t) && isfunc(t->Ptr.subty); 228 | } 229 | 230 | int 231 | isstruct(CTy *t) 232 | { 233 | return t->t == CSTRUCT; 234 | } 235 | 236 | int 237 | isarray(CTy *t) 238 | { 239 | return t->t == CARR; 240 | } 241 | 242 | int 243 | structoffsetfromname(CTy *t, char *name) 244 | { 245 | int offset; 246 | StructMember *sm; 247 | StructIter it; 248 | 249 | if(!getstructiter(&it, t, name)) 250 | return -1; 251 | structwalk(&it, &sm, &offset); 252 | return offset; 253 | } 254 | 255 | CTy * 256 | structtypefromname(CTy *t, char *name) 257 | { 258 | int offset; 259 | StructMember *sm; 260 | StructIter it; 261 | 262 | if(!getstructiter(&it, t, name)) 263 | return 0; 264 | structwalk(&it, &sm, &offset); 265 | return sm->type; 266 | } 267 | 268 | void 269 | initstructiter(StructIter *it, CTy *t) 270 | { 271 | if(!isstruct(t)) 272 | panic("internal error"); 273 | it->root = t; 274 | it->depth = 1; 275 | it->path[0] = 0; 276 | } 277 | 278 | int 279 | getstructiter(StructIter *it, CTy *t, char *name) 280 | { 281 | StructExport *export; 282 | ExportPath *path; 283 | int i; 284 | 285 | it->root = t; 286 | it->depth = 0; 287 | for(i = 0; i < t->Struct.exports->len; i++) { 288 | export = vecget(t->Struct.exports, i); 289 | if(strcmp(export->name, name) != 0) 290 | continue; 291 | path = export->path; 292 | while(path) { 293 | it->path[it->depth++] = path->idx; 294 | path = path->next; 295 | } 296 | return 1; 297 | } 298 | return 0; 299 | } 300 | 301 | static void 302 | _structwalk(StructIter *it, CTy *cur, int depth, StructMember **smout, int *offout) 303 | { 304 | *smout = vecget(cur->Struct.members, it->path[depth]); 305 | *offout = *offout + (*smout)->offset; 306 | if((depth + 1) == it->depth) 307 | return; 308 | _structwalk(it, (*smout)->type, depth + 1, smout, offout); 309 | } 310 | 311 | void 312 | structwalk(StructIter *it, StructMember **smout, int *offout) 313 | { 314 | *smout = 0; 315 | *offout = 0; 316 | _structwalk(it, it->root, 0, smout, offout); 317 | } 318 | 319 | int 320 | structnext(StructIter *it) 321 | { 322 | StructMember *sm; 323 | CTy *curstruct; 324 | int offset; 325 | 326 | if(it->depth == 0) 327 | return 0; 328 | 329 | if(it->depth == 1) { 330 | curstruct = it->root; 331 | offset = 0; 332 | } else { 333 | it->depth--; 334 | structwalk(it, &sm, &offset); 335 | curstruct = sm->type; 336 | it->depth++; 337 | } 338 | if(curstruct->Struct.isunion) { 339 | if(curstruct == it->root) 340 | return 0; 341 | it->depth--; 342 | return structnext(it); 343 | } 344 | if(it->path[it->depth-1] + 1 < curstruct->Struct.members->len) { 345 | it->path[it->depth-1]++; 346 | while(1) { 347 | structwalk(it, &sm, &offset); 348 | if(!sm->name) 349 | if(isstruct(sm->type)) { 350 | if(!sm->type->Struct.members->len) 351 | return structnext(it); 352 | it->path[it->depth] = 0; 353 | it->depth++; 354 | continue; 355 | } 356 | break; 357 | } 358 | return 1; 359 | } 360 | it->depth -= 1; 361 | return structnext(it); 362 | } 363 | 364 | static StructMember * 365 | newstructmember(char *name, int offset, CTy *membt) 366 | { 367 | StructMember *sm; 368 | 369 | sm = xmalloc(sizeof(StructMember)); 370 | sm->name = name; 371 | sm->type = membt; 372 | sm->offset = offset; 373 | return sm; 374 | } 375 | 376 | void 377 | addtostruct(CTy *t, char *name, CTy *membt) 378 | { 379 | vecappend(t->Struct.members, newstructmember(name, -1, membt)); 380 | } 381 | 382 | void 383 | finalizestruct(SrcPos *pos, CTy *t) 384 | { 385 | StructMember *sm; 386 | int i, j, curoffset; 387 | StrSet *exportednames; 388 | StructExport *export, *subexport; 389 | 390 | /* calc alignment */ 391 | for(i = 0; i < t->Struct.members->len; i++) { 392 | sm = vecget(t->Struct.members, i); 393 | t->align = align(t->align, sm->type->align); 394 | } 395 | /* calc member offsets */ 396 | if(t->Struct.isunion) { 397 | for(i = 0; i < t->Struct.members->len; i++) { 398 | sm = vecget(t->Struct.members, i); 399 | sm->offset = 0; 400 | if(t->size < sm->type->size) 401 | t->size = sm->type->size; 402 | } 403 | } else { 404 | curoffset = 0; 405 | for(i = 0; i < t->Struct.members->len; i++) { 406 | sm = vecget(t->Struct.members, i); 407 | curoffset = align(curoffset, sm->type->align); 408 | sm->offset = curoffset; 409 | curoffset += sm->type->size; 410 | } 411 | t->size = curoffset; 412 | } 413 | /* Calc export fields */ 414 | exportednames = 0; 415 | for(i = 0; i < t->Struct.members->len; i++) { 416 | sm = vecget(t->Struct.members, i); 417 | if(sm->name) { 418 | if(strsethas(exportednames, sm->name)) 419 | errorposf(pos, "field %s duplicated in struct", sm->name); 420 | export = xmalloc(sizeof(StructExport)); 421 | export->name = sm->name; 422 | export->path = xmalloc(sizeof(ExportPath)); 423 | export->path->idx = i; 424 | export->path->next = 0; 425 | vecappend(t->Struct.exports, export); 426 | exportednames = strsetadd(exportednames, export->name); 427 | continue; 428 | } 429 | if(!isstruct(sm->type)) 430 | continue; 431 | for(j = 0; j < sm->type->Struct.exports->len; j++) { 432 | subexport = vecget(sm->type->Struct.exports, j); 433 | if(strsethas(exportednames, subexport->name)) 434 | errorposf(pos, "field %s duplicated in struct", subexport->name); 435 | export = xmalloc(sizeof(StructExport)); 436 | export->name = subexport->name; 437 | export->path = xmalloc(sizeof(ExportPath)); 438 | export->path->idx = i; 439 | export->path->next = subexport->path; 440 | vecappend(t->Struct.exports, export); 441 | exportednames = strsetadd(exportednames, export->name); 442 | } 443 | } 444 | t->size = align(t->size, t->align); 445 | } 446 | 447 | int 448 | isassignable(CTy *to, CTy *from) 449 | { 450 | if((isarithtype(to) || isptr(to)) && 451 | (isarithtype(from) || isptr(from))) 452 | return 1; 453 | if(compatiblestruct(to, from)) 454 | return 1; 455 | return 0; 456 | } 457 | 458 | int 459 | canrepresent(CTy *l, CTy *r) 460 | { 461 | if(!isitype(l) || !isitype(r)) 462 | panic("internal error"); 463 | return getmaxval(l) <= getmaxval(r) && getminval(l) >= getminval(r); 464 | } 465 | 466 | 467 | -------------------------------------------------------------------------------- /src/cmd/6c/emit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static void expr(Node *); 7 | static void stmt(Node *); 8 | static void store(CTy *); 9 | 10 | char *intargregs[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}; 11 | int stackoffset; 12 | 13 | Vec *pendingdata; 14 | 15 | static FILE *o; 16 | 17 | void 18 | emitinit(FILE *out) 19 | { 20 | o = out; 21 | pendingdata = vec(); 22 | } 23 | 24 | void 25 | penddata(char *label, CTy *ty, Node *init, int isglobal) 26 | { 27 | Data *d; 28 | 29 | d = xmalloc(sizeof(Data)); 30 | d->label = label; 31 | d->type = ty; 32 | d->init = init; 33 | d->isglobal = isglobal; 34 | vecappend(pendingdata, d); 35 | } 36 | 37 | static void 38 | out(char *fmt, ...) 39 | { 40 | va_list va; 41 | 42 | va_start(va, fmt); 43 | if(vfprintf(o, fmt, va) < 0) 44 | errorf("Error printing\n"); 45 | va_end(va); 46 | } 47 | 48 | static void 49 | outi(char *fmt, ...) 50 | { 51 | va_list va; 52 | 53 | va_start(va, fmt); 54 | fprintf(o, " "); 55 | if(vfprintf(o, fmt, va) < 0) 56 | errorf("Error printing\n"); 57 | va_end(va); 58 | } 59 | 60 | static void 61 | block(Node *n) 62 | { 63 | Vec *v; 64 | int i; 65 | 66 | v = n->Block.stmts; 67 | for(i = 0; i < v->len ; i++) { 68 | stmt(vecget(v, i)); 69 | } 70 | } 71 | 72 | static void 73 | calcslotoffsets(Node *f) 74 | { 75 | int i, tsz, curoffset; 76 | StkSlot *s; 77 | 78 | curoffset = 0; 79 | for(i = 0; i < f->Func.stkslots->len; i++) { 80 | s = vecget(f->Func.stkslots, i); 81 | tsz = s->size; 82 | if(tsz <= 8) 83 | tsz = 8; 84 | curoffset += tsz; 85 | if(curoffset % s->align) 86 | curoffset = (curoffset - (curoffset % s->align) + s->align); 87 | s->offset = -curoffset; 88 | if(f->type->Func.isvararg) 89 | s->offset -= 176; 90 | } 91 | if(curoffset % 16) 92 | curoffset = (curoffset - (curoffset % 16) + 16); 93 | f->Func.localsz = curoffset; 94 | } 95 | 96 | static void 97 | pushq(char *reg) 98 | { 99 | stackoffset += 8; 100 | outi("pushq %%%s\n", reg); 101 | } 102 | 103 | static void 104 | popq(char *reg) 105 | { 106 | stackoffset -= 8; 107 | outi("popq %%%s\n", reg); 108 | } 109 | 110 | static void 111 | func(Node *f, char *label, int isglobal) 112 | { 113 | Vec *v; 114 | Sym *sym; 115 | int i; 116 | 117 | calcslotoffsets(f); 118 | out("\n"); 119 | out(".text\n"); 120 | out("# function %s\n", f->Func.name); 121 | if(isglobal) 122 | out(".globl %s\n", label); 123 | out("%s:\n", label); 124 | pushq("rbp"); 125 | outi("movq %%rsp, %%rbp\n"); 126 | if(f->type->Func.isvararg) { 127 | stackoffset += 176; 128 | outi("sub $176, %%rsp\n"); 129 | outi("movq %%rdi, (%%rsp)\n"); 130 | outi("movq %%rsi, 8(%%rsp)\n"); 131 | outi("movq %%rdx, 16(%%rsp)\n"); 132 | outi("movq %%rcx, 24(%%rsp)\n"); 133 | outi("movq %%r8, 32(%%rsp)\n"); 134 | outi("movq %%r9, 40(%%rsp)\n"); 135 | } 136 | if(f->Func.localsz) { 137 | outi("sub $%d, %%rsp\n", f->Func.localsz); 138 | stackoffset += f->Func.localsz; 139 | } 140 | v = f->Func.params; 141 | for(i = 0; i < v->len; i++) { 142 | sym = vecget(v, i); 143 | if(!isitype(sym->type) && !isptr(sym->type) && !isarray(sym->type)) 144 | errorposf(&f->pos, "unimplemented arg type"); 145 | if(i < 6) { 146 | outi("movq %%%s, %d(%%rbp)\n", intargregs[i], sym->Local.slot->offset); 147 | } else { 148 | outi("movq %d(%%rbp), %%rcx\n", 16 + 8 * (i - 6)); 149 | outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); 150 | store(sym->type); 151 | } 152 | } 153 | block(f->Func.body); 154 | outi("leave\n"); 155 | outi("ret\n"); 156 | } 157 | 158 | 159 | static void 160 | call(Node *n) 161 | { 162 | int i, nargs, nintargs, cleanup; 163 | Vec *args; 164 | Node *arg; 165 | 166 | args = n->Call.args; 167 | i = nargs = args->len; 168 | /* Push args in reverse order */ 169 | while(i-- != 0) { 170 | arg = vecget(args, i); 171 | if(!isitype(arg->type) && !isptr(arg->type) && !isarray(arg->type) && !isfunc(arg->type)) 172 | errorposf(&arg->pos, "unimplemented arg type\n"); 173 | expr(arg); 174 | pushq("rax"); 175 | } 176 | nintargs = nargs; 177 | if(nintargs > 6) 178 | nintargs = 6; 179 | for(i = 0; i < nintargs; i++) 180 | popq(intargregs[i]); 181 | expr(n->Call.funclike); 182 | outi("call *%%rax\n"); 183 | cleanup = 8 * (nargs - nintargs); 184 | if(cleanup) { 185 | outi("add $%d, %%rsp\n", cleanup); 186 | stackoffset -= cleanup; 187 | } 188 | } 189 | 190 | static void 191 | ereturn(Node *r) 192 | { 193 | CTy *ty; 194 | 195 | if(r->Return.expr) { 196 | ty = r->Return.expr->type; 197 | if(!isitype(ty) && !isptr(ty)) 198 | errorposf(&r->pos, "unimplemented return type"); 199 | expr(r->Return.expr); 200 | } 201 | /* No need to cleanup with leave */ 202 | outi("leave\n"); 203 | outi("ret\n"); 204 | } 205 | 206 | 207 | static void 208 | load(CTy *t) 209 | { 210 | if(isitype(t) || isptr(t)) { 211 | switch(t->size) { 212 | case 8: 213 | outi("movq (%%rax), %%rax\n"); 214 | break; 215 | case 4: 216 | outi("movslq (%%rax), %%rax\n"); 217 | break; 218 | case 2: 219 | outi("movswq (%%rax), %%rax\n"); 220 | break; 221 | case 1: 222 | outi("movsbq (%%rax), %%rax\n"); 223 | break; 224 | default: 225 | panic("internal error\n"); 226 | } 227 | return; 228 | } 229 | if(isstruct(t)) { 230 | return; 231 | } 232 | if(isarray(t)) { 233 | return; 234 | } 235 | if(isfunc(t)) { 236 | return; 237 | } 238 | errorf("unimplemented load %d\n", t->t); 239 | } 240 | 241 | static void 242 | store(CTy *t) 243 | { 244 | if(isitype(t) || isptr(t)) { 245 | switch(t->size) { 246 | case 8: 247 | outi("movq %%rcx, (%%rax)\n"); 248 | break; 249 | case 4: 250 | outi("movl %%ecx, (%%rax)\n"); 251 | break; 252 | case 2: 253 | outi("movw %%cx, (%%rax)\n"); 254 | break; 255 | case 1: 256 | outi("movb %%cl, (%%rax)\n"); 257 | break; 258 | default: 259 | panic("internal error\n"); 260 | } 261 | return; 262 | } 263 | if(isstruct(t)) { 264 | pushq("rdi"); 265 | pushq("rsi"); 266 | pushq("rcx"); 267 | outi("movq %%rcx, %%rsi\n"); 268 | outi("movq %%rax, %%rdi\n"); 269 | outi("movq $%d, %%rcx\n", t->size); 270 | outi("rep movsb\n"); 271 | popq("rcx"); 272 | popq("rsi"); 273 | popq("rdi"); 274 | return; 275 | } 276 | errorf("unimplemented store\n"); 277 | } 278 | 279 | static void 280 | decl(Node *n) 281 | { 282 | int i; 283 | Sym *sym; 284 | 285 | for(i = 0; i < n->Decl.syms->len; i++) { 286 | sym = vecget(n->Decl.syms, i); 287 | emitsym(sym); 288 | } 289 | } 290 | 291 | static void 292 | addr(Node *n) 293 | { 294 | int sz; 295 | int offset; 296 | Sym *sym; 297 | 298 | switch(n->t) { 299 | case NUNOP: 300 | expr(n->Unop.operand); 301 | break; 302 | case NSEL: 303 | expr(n->Sel.operand); 304 | if(isptr(n->Sel.operand->type)) 305 | offset = structoffsetfromname(n->Sel.operand->type->Ptr.subty, n->Sel.name); 306 | else if(isstruct(n->Sel.operand->type)) 307 | offset = structoffsetfromname(n->Sel.operand->type, n->Sel.name); 308 | else 309 | panic("internal error"); 310 | if(offset < 0) 311 | panic("internal error"); 312 | outi("addq $%d, %%rax\n", offset); 313 | break; 314 | case NIDENT: 315 | sym = n->Ident.sym; 316 | switch(sym->k) { 317 | case SYMGLOBAL: 318 | outi("leaq %s(%%rip), %%rax\n", sym->Global.label); 319 | break; 320 | case SYMLOCAL: 321 | outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); 322 | break; 323 | default: 324 | panic("internal error"); 325 | } 326 | break; 327 | case NIDX: 328 | expr(n->Idx.idx); 329 | sz = n->type->size; 330 | if(sz != 1) { 331 | outi("imul $%d, %%rax\n", sz); 332 | } 333 | pushq("rax"); 334 | expr(n->Idx.operand); 335 | popq("rcx"); 336 | outi("addq %%rcx, %%rax\n"); 337 | break; 338 | default: 339 | errorf("unimplemented addr\n"); 340 | } 341 | } 342 | 343 | static void 344 | obinop(int op, CTy *t) 345 | { 346 | char *lset; 347 | char *lafter; 348 | char *opc; 349 | 350 | if(!isitype(t) && !isptr(t)) 351 | panic("unimplemented binary operator type\n"); 352 | switch(op) { 353 | case '+': 354 | outi("addq %%rcx, %%rax\n"); 355 | break; 356 | case '-': 357 | outi("subq %%rcx, %%rax\n"); 358 | break; 359 | case '*': 360 | outi("imul %%rcx, %%rax\n"); 361 | break; 362 | case '/': 363 | outi("cqto\n"); 364 | outi("idiv %%rcx\n"); 365 | break; 366 | case '%': 367 | outi("cqto\n"); 368 | outi("idiv %%rcx\n"); 369 | outi("mov %%rdx, %%rax\n"); 370 | break; 371 | case '|': 372 | outi("or %%rcx, %%rax\n"); 373 | break; 374 | case '&': 375 | outi("and %%rcx, %%rax\n"); 376 | break; 377 | case '^': 378 | outi("xor %%rcx, %%rax\n"); 379 | break; 380 | case TOKSHR: 381 | outi("sar %%cl, %%rax\n"); 382 | break; 383 | case TOKSHL: 384 | outi("sal %%cl, %%rax\n"); 385 | break; 386 | case TOKEQL: 387 | case TOKNEQ: 388 | case TOKGEQ: 389 | case TOKLEQ: 390 | case '>': 391 | case '<': 392 | lset = newlabel(); 393 | lafter = newlabel(); 394 | switch(op) { 395 | case TOKEQL: 396 | opc = "jz"; 397 | break; 398 | case TOKNEQ: 399 | opc = "jnz"; 400 | break; 401 | case '<': 402 | opc = "jl"; 403 | break; 404 | case '>': 405 | opc = "jg"; 406 | break; 407 | case TOKGEQ: 408 | opc = "jge"; 409 | break; 410 | case TOKLEQ: 411 | opc = "jle"; 412 | break; 413 | } 414 | outi("cmp %%rcx, %%rax\n"); 415 | outi("%s %s\n", opc, lset); 416 | outi("movq $0, %%rax\n"); 417 | outi("jmp %s\n", lafter); 418 | out("%s:\n", lset); 419 | outi("movq $1, %%rax\n"); 420 | out("%s:\n", lafter); 421 | break; 422 | default: 423 | errorf("unimplemented binop %d\n", op); 424 | } 425 | } 426 | 427 | static void 428 | assign(Node *n) 429 | { 430 | Node *l, *r; 431 | int op; 432 | 433 | op = n->Assign.op; 434 | l = n->Assign.l; 435 | r = n->Assign.r; 436 | if(op == '=') { 437 | expr(r); 438 | pushq("rax"); 439 | addr(l); 440 | popq("rcx"); 441 | if(!isptr(l->type) && !isitype(l->type) && !isstruct(l->type)) 442 | errorf("unimplemented assign\n"); 443 | store(l->type); 444 | outi("movq %%rcx, %%rax\n"); 445 | return; 446 | } 447 | addr(l); 448 | pushq("rax"); 449 | load(l->type); 450 | pushq("rax"); 451 | expr(r); 452 | outi("movq %%rax, %%rcx\n"); 453 | popq("rax"); 454 | /* XXX this type is not correct for comparison ops works anyway, but should be changed*/ 455 | obinop(op, n->type); 456 | outi("movq %%rax, %%rcx\n"); 457 | popq("rax"); 458 | store(l->type); 459 | outi("movq %%rcx, %%rax\n"); 460 | } 461 | 462 | static void 463 | shortcircuit(Node *n) 464 | { 465 | char *t, *f, *e; 466 | 467 | t = newlabel(); 468 | f = newlabel(); 469 | e = newlabel(); 470 | 471 | expr(n->Binop.l); 472 | if(n->Binop.op == TOKLAND) { 473 | outi("testq %%rax, %%rax\n"); 474 | outi("jz %s\n", f); 475 | } else if(n->Binop.op == TOKLOR) { 476 | outi("testq %%rax, %%rax\n"); 477 | outi("jnz %s\n", t); 478 | } else { 479 | panic("internal error"); 480 | } 481 | expr(n->Binop.r); 482 | if(n->Binop.op == TOKLAND) { 483 | outi("testq %%rax, %%rax\n"); 484 | outi("jz %s\n", f); 485 | outi("jmp %s\n", t); 486 | } else if(n->Binop.op == TOKLOR) { 487 | outi("testq %%rax, %%rax\n"); 488 | outi("jnz %s\n", t); 489 | outi("jmp %s\n", f); 490 | } else { 491 | panic("internal error"); 492 | } 493 | out("%s:\n", t); 494 | outi("mov $1, %%rax\n"); 495 | outi("jmp %s\n", e); 496 | out("%s:\n", f); 497 | outi("xor %%rax, %%rax\n"); 498 | outi("jmp %s\n", e); 499 | out("%s:\n", e); 500 | } 501 | 502 | static void 503 | binop(Node *n) 504 | { 505 | if(n->Binop.op == TOKLAND || n->Binop.op == TOKLOR) { 506 | shortcircuit(n); 507 | return; 508 | } 509 | expr(n->Binop.l); 510 | pushq("rax"); 511 | expr(n->Binop.r); 512 | outi("movq %%rax, %%rcx\n"); 513 | popq("rax"); 514 | obinop(n->Binop.op, n->type); 515 | } 516 | 517 | static void 518 | unop(Node *n) 519 | { 520 | switch(n->Unop.op) { 521 | case '*': 522 | expr(n->Unop.operand); 523 | load(n->type); 524 | break; 525 | case '&': 526 | addr(n->Unop.operand); 527 | break; 528 | case '~': 529 | expr(n->Unop.operand); 530 | out("notq %%rax\n"); 531 | break; 532 | case '!': 533 | expr(n->Unop.operand); 534 | outi("xorq %%rcx, %%rcx\n"); 535 | outi("testq %%rax, %%rax\n"); 536 | outi("setz %%cl\n"); 537 | outi("movq %%rcx, %%rax\n"); 538 | break; 539 | case '-': 540 | expr(n->Unop.operand); 541 | outi("neg %%rax\n"); 542 | break; 543 | case TOKINC: 544 | default: 545 | errorf("unimplemented unop %d\n", n->Unop.op); 546 | } 547 | } 548 | 549 | static void 550 | incdec(Node *n) 551 | { 552 | if(!isitype(n->type) && !isptr(n->type)) 553 | panic("unimplemented incdec"); 554 | addr(n->Incdec.operand); 555 | pushq("rax"); 556 | load(n->type); 557 | if(isptr(n->type)) { 558 | if(n->Incdec.op == TOKINC) 559 | outi("add $%d, %%rax\n", n->type->Ptr.subty->size); 560 | else 561 | outi("add $%d, %%rax\n", -n->type->Ptr.subty->size); 562 | } else { 563 | if(n->Incdec.op == TOKINC) 564 | outi("inc %%rax\n"); 565 | else 566 | outi("dec %%rax\n"); 567 | } 568 | outi("movq %%rax, %%rcx\n"); 569 | popq("rax"); 570 | store(n->type); 571 | outi("movq %%rcx, %%rax\n"); 572 | if(n->Incdec.post == 1) { 573 | if(n->Incdec.op == TOKINC) 574 | outi("dec %%rax\n"); 575 | else 576 | outi("inc %%rax\n"); 577 | } 578 | } 579 | 580 | static void 581 | ident(Node *n) 582 | { 583 | Sym *sym; 584 | 585 | sym = n->Ident.sym; 586 | if(sym->k == SYMENUM) { 587 | outi("movq $%d, %%rax\n", sym->Enum.v); 588 | return; 589 | } 590 | addr(n); 591 | if(sym->k == SYMLOCAL) 592 | if(sym->Local.isparam) 593 | if(isarray(sym->type)) 594 | outi("movq (%%rax), %%rax\n"); 595 | load(n->type); 596 | } 597 | 598 | static void 599 | eif(Node *n) 600 | { 601 | char *end; 602 | 603 | end = newlabel(); 604 | expr(n->If.expr); 605 | outi("test %%rax, %%rax\n"); 606 | outi("jz %s\n", n->If.lelse); 607 | stmt(n->If.iftrue); 608 | outi("jmp %s\n", end); 609 | out("%s:\n", n->If.lelse); 610 | if(n->If.iffalse) 611 | stmt(n->If.iffalse); 612 | out("%s:\n", end); 613 | } 614 | 615 | static void 616 | efor(Node *n) 617 | { 618 | if(n->For.init) 619 | expr(n->For.init); 620 | out("%s:\n", n->For.lstart); 621 | if(n->For.cond) { 622 | expr(n->For.cond); 623 | outi("test %%rax, %%rax\n"); 624 | outi("jz %s\n", n->For.lend); 625 | } 626 | stmt(n->For.stmt); 627 | outi("%s:\n", n->For.lstep); 628 | if(n->For.step) 629 | expr(n->For.step); 630 | outi("jmp %s\n", n->For.lstart); 631 | out("%s:\n", n->For.lend); 632 | } 633 | 634 | static void 635 | ewhile(Node *n) 636 | { 637 | out("%s:\n", n->While.lstart); 638 | expr(n->While.expr); 639 | outi("test %%rax, %%rax\n"); 640 | outi("jz %s\n", n->While.lend); 641 | stmt(n->While.stmt); 642 | outi("jmp %s\n", n->While.lstart); 643 | out("%s:\n", n->While.lend); 644 | } 645 | 646 | static void 647 | dowhile(Node *n) 648 | { 649 | out("%s:\n", n->DoWhile.lstart); 650 | stmt(n->DoWhile.stmt); 651 | out("%s:\n", n->DoWhile.lcond); 652 | expr(n->DoWhile.expr); 653 | outi("test %%rax, %%rax\n"); 654 | outi("jz %s\n", n->DoWhile.lend); 655 | outi("jmp %s\n", n->DoWhile.lstart); 656 | out("%s:\n", n->DoWhile.lend); 657 | } 658 | 659 | static void 660 | eswitch(Node *n) 661 | { 662 | int i; 663 | Node *c; 664 | 665 | expr(n->Switch.expr); 666 | for(i = 0; i < n->Switch.cases->len; i++) { 667 | c = vecget(n->Switch.cases, i); 668 | outi("mov $%lld, %%rcx\n", c->Case.cond); 669 | outi("cmp %%rax, %%rcx\n"); 670 | outi("je %s\n", c->Case.l); 671 | } 672 | if(n->Switch.ldefault) { 673 | outi("jmp %s\n", n->Switch.ldefault); 674 | } else { 675 | outi("jmp %s\n", n->Switch.lend); 676 | } 677 | stmt(n->Switch.stmt); 678 | out("%s:\n", n->Switch.lend); 679 | } 680 | 681 | static void 682 | cond(Node *n) 683 | { 684 | char *lfalse, *lend; 685 | 686 | if(!isitype(n->type) && !isptr(n->type)) 687 | panic("unimplemented emit cond"); 688 | expr(n->Cond.cond); 689 | lfalse = newlabel(); 690 | lend = newlabel(); 691 | outi("test %%rax, %%rax\n"); 692 | outi("jz %s\n", lfalse); 693 | expr(n->Cond.iftrue); 694 | outi("jmp %s\n", lend); 695 | out("%s:\n", lfalse); 696 | expr(n->Cond.iffalse); 697 | out("%s:\n", lend); 698 | } 699 | 700 | static void 701 | cast(Node *n) 702 | { 703 | CTy *from; 704 | CTy *to; 705 | 706 | expr(n->Cast.operand); 707 | from = n->Cast.operand->type; 708 | to = n->type; 709 | if(isptr(from) && isptr(to)) 710 | return; 711 | if(isptr(to) && isitype(from)) 712 | return; 713 | if(isptr(from) && isitype(to)) 714 | return; 715 | if(isitype(from) && isitype(to)) 716 | return; 717 | if(isfunc(from) && isptr(to)) 718 | return; 719 | if(isarray(from) && isptr(to)) 720 | return; 721 | errorf("unimplemented cast %d %d\n", from->t, to->t); 722 | } 723 | 724 | static void 725 | sel(Node *n) 726 | { 727 | CTy *t; 728 | int offset; 729 | 730 | expr(n->Sel.operand); 731 | t = n->Sel.operand->type; 732 | if(isptr(t)) 733 | offset = structoffsetfromname(t->Ptr.subty, n->Sel.name); 734 | else if(isstruct(t)) 735 | offset = structoffsetfromname(t, n->Sel.name); 736 | else 737 | panic("internal error"); 738 | if(offset < 0) 739 | panic("internal error"); 740 | if(offset != 0) 741 | outi("add $%d, %%rax\n", offset); 742 | load(n->type); 743 | } 744 | 745 | static void 746 | idx(Node *n) 747 | { 748 | int sz; 749 | 750 | expr(n->Idx.idx); 751 | sz = n->type->size; 752 | if(sz != 1) 753 | outi("imul $%d, %%rax\n", sz); 754 | outi("push %%rax\n"); 755 | expr(n->Idx.operand); 756 | outi("pop %%rcx\n"); 757 | outi("addq %%rcx, %%rax\n"); 758 | load(n->type); 759 | } 760 | 761 | static void 762 | ptradd(Node *n) 763 | { 764 | int sz; 765 | 766 | sz = n->type->Ptr.subty->size; 767 | expr(n->Ptradd.offset); 768 | if(sz != 1) 769 | outi("imul $%d, %%rax\n", sz); 770 | outi("push %%rax\n"); 771 | expr(n->Ptradd.ptr); 772 | outi("pop %%rcx\n"); 773 | outi("addq %%rcx, %%rax\n"); 774 | } 775 | 776 | static void 777 | comma(Node *n) 778 | { 779 | int i; 780 | 781 | for(i = 0; i < n->Comma.exprs->len; i++) { 782 | expr(vecget(n->Comma.exprs, i)); 783 | } 784 | } 785 | 786 | static void 787 | str(Node *n) 788 | { 789 | char *l; 790 | 791 | l = newlabel(); 792 | penddata(l, n->type, n, 0); 793 | outi("leaq %s(%%rip), %%rax\n", l); 794 | outi("movq (%%rax), %%rax\n", l); 795 | } 796 | 797 | static void 798 | vastart(Node *n) 799 | { 800 | int argend; 801 | 802 | expr(n->Builtin.Vastart.valist); 803 | /* XXX currently only support int args */ 804 | argend = (n->Builtin.Vastart.param->Ident.sym->Local.paramidx + 1) * 8; 805 | pushq("rcx"); 806 | outi("movl $%d, (%%rax)\n", argend); 807 | outi("movl $%d, 4(%%rax)\n", 48 + 0 * 16); 808 | outi("leaq %d(%%rbp), %%rcx\n", -176); 809 | outi("movq %%rcx, 16(%%rax)\n"); 810 | popq("rcx"); 811 | } 812 | 813 | static void 814 | expr(Node *n) 815 | { 816 | switch(n->t){ 817 | case NCOMMA: 818 | comma(n); 819 | break; 820 | case NCAST: 821 | cast(n); 822 | break; 823 | case NSTR: 824 | str(n); 825 | break; 826 | case NSIZEOF: 827 | outi("movq $%lld, %%rax\n", n->Sizeof.type->size); 828 | break; 829 | case NNUM: 830 | outi("movq $%lld, %%rax\n", n->Num.v); 831 | break; 832 | case NIDENT: 833 | ident(n); 834 | break; 835 | case NUNOP: 836 | unop(n); 837 | break; 838 | case NASSIGN: 839 | assign(n); 840 | break; 841 | case NBINOP: 842 | binop(n); 843 | break; 844 | case NIDX: 845 | idx(n); 846 | break; 847 | case NSEL: 848 | sel(n); 849 | break; 850 | case NCOND: 851 | cond(n); 852 | break; 853 | case NCALL: 854 | call(n); 855 | break; 856 | case NPTRADD: 857 | ptradd(n); 858 | break; 859 | case NINCDEC: 860 | incdec(n); 861 | break; 862 | case NBUILTIN: 863 | switch(n->Builtin.t) { 864 | case BUILTIN_VASTART: 865 | vastart(n); 866 | break; 867 | default: 868 | errorposf(&n->pos, "unimplemented builtin"); 869 | } 870 | break; 871 | default: 872 | errorf("unimplemented emit expr %d\n", n->t); 873 | } 874 | } 875 | 876 | static void 877 | stmt(Node *n) 878 | { 879 | switch(n->t){ 880 | case NDECL: 881 | decl(n); 882 | out(".text\n"); 883 | break; 884 | case NRETURN: 885 | ereturn(n); 886 | break; 887 | case NIF: 888 | eif(n); 889 | break; 890 | case NWHILE: 891 | ewhile(n); 892 | break; 893 | case NFOR: 894 | efor(n); 895 | break; 896 | case NDOWHILE: 897 | dowhile(n); 898 | break; 899 | case NBLOCK: 900 | block(n); 901 | break; 902 | case NSWITCH: 903 | eswitch(n); 904 | break; 905 | case NGOTO: 906 | outi("jmp %s\n", n->Goto.l); 907 | break; 908 | case NCASE: 909 | out("%s:\n", n->Case.l); 910 | stmt(n->Case.stmt); 911 | break; 912 | case NLABELED: 913 | out("%s:\n", n->Labeled.l); 914 | stmt(n->Labeled.stmt); 915 | break; 916 | case NEXPRSTMT: 917 | if(n->ExprStmt.expr) 918 | expr(n->ExprStmt.expr); 919 | break; 920 | default: 921 | errorf("unimplemented emit stmt %d\n", n->t); 922 | } 923 | } 924 | 925 | static void 926 | itypedata(Node *prim) 927 | { 928 | Const *c; 929 | 930 | if(!isitype(prim->type) && !isptr(prim->type)) 931 | panic("internal error %d"); 932 | c = foldexpr(prim); 933 | if(!c) 934 | errorposf(&prim->pos, "not a constant expression"); 935 | if(c->p) { 936 | switch(prim->type->size) { 937 | case 8: 938 | out(".quad %s + %d\n", c->p, c->v); 939 | return; 940 | case 4: 941 | out(".long %s + %d\n", c->p, c->v); 942 | return; 943 | case 2: 944 | out(".short %s + %d\n", c->p, c->v); 945 | return; 946 | case 1: 947 | out(".byte %s + %d\n", c->p, c->v); 948 | return; 949 | default: 950 | panic("unimplemented"); 951 | } 952 | } 953 | switch(prim->type->size) { 954 | case 8: 955 | out(".quad %d\n", c->v); 956 | return; 957 | case 4: 958 | out(".long %d\n", c->v); 959 | return; 960 | case 2: 961 | out(".short %d\n", c->v); 962 | return; 963 | case 1: 964 | out(".byte %d\n", c->v); 965 | return; 966 | default: 967 | panic("unimplemented"); 968 | } 969 | panic("internal error"); 970 | } 971 | 972 | static void 973 | data(Data *d) 974 | { 975 | InitMember *initmemb; 976 | int i, offset; 977 | char *l; 978 | 979 | if(!d->init) { 980 | out(".comm %s, %d, %d\n", d->label, d->type->size, d->type->align); 981 | return; 982 | } 983 | if(d->isglobal) 984 | out(".globl %s\n", d->label); 985 | out("%s:\n", d->label); 986 | 987 | if(ischararray(d->type)) 988 | if(d->init->t == NSTR) { 989 | out(".string %s\n", d->init->Str.v); 990 | return; 991 | } 992 | 993 | if(ischarptr(d->type)) 994 | if(d->init->t == NSTR) { 995 | l = newlabel(); 996 | out(".quad %s\n", l); 997 | out("%s:\n", l); 998 | out(".string %s\n", d->init->Str.v); 999 | return; 1000 | } 1001 | if(isitype(d->type) || isptr(d->type)) { 1002 | itypedata(d->init); 1003 | return; 1004 | } 1005 | if(isarray(d->type) || isstruct(d->type)) { 1006 | if(d->init->t != NINIT) 1007 | errorposf(&d->init->pos, "array/struct expects a '{' style initializer"); 1008 | offset = 0; 1009 | for(i = 0; i < d->init->Init.inits->len ; i++) { 1010 | initmemb = vecget(d->init->Init.inits, i); 1011 | if(initmemb->offset != offset) 1012 | out(".fill %d, 1, 0\n", initmemb->offset - offset); 1013 | itypedata(initmemb->n); 1014 | offset = initmemb->offset + initmemb->n->type->size; 1015 | } 1016 | if(offset < d->type->size) 1017 | out(".fill %d, 1, 0\n", d->type->size - offset); 1018 | return; 1019 | } 1020 | panic("internal error"); 1021 | } 1022 | 1023 | 1024 | void 1025 | emitsym(Sym *sym) 1026 | { 1027 | out("# emit sym %s\n", sym->name); 1028 | switch(sym->k){ 1029 | case SYMGLOBAL: 1030 | if(sym->Global.sclass == SCEXTERN) 1031 | break; 1032 | if(isfunc(sym->type)) { 1033 | func(sym->init, sym->Global.label, sym->Global.sclass == SCGLOBAL); 1034 | break; 1035 | } 1036 | penddata(sym->Global.label, sym->type, sym->init, sym->Global.sclass == SCGLOBAL); 1037 | break; 1038 | case SYMLOCAL: 1039 | if(sym->init) { 1040 | expr(sym->init); 1041 | pushq("rax"); 1042 | outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); 1043 | popq("rcx"); 1044 | if(!isptr(sym->type) && !isitype(sym->type) && !isstruct(sym->type)) 1045 | errorf("unimplemented init\n"); 1046 | store(sym->type); 1047 | } 1048 | break; 1049 | case SYMENUM: 1050 | case SYMTYPE: 1051 | panic("internal error"); 1052 | } 1053 | out("\n"); 1054 | } 1055 | 1056 | void 1057 | emitend() 1058 | { 1059 | int i; 1060 | 1061 | out(".data\n\n"); 1062 | for(i = 0; i < pendingdata->len; i++) 1063 | data(vecget(pendingdata, i)); 1064 | } 1065 | 1066 | -------------------------------------------------------------------------------- /src/cmd/6c/frontend.c: -------------------------------------------------------------------------------- 1 | #include "u.h" 2 | #include "ds/ds.h" 3 | #include "cc/cc.h" 4 | 5 | uint64 6 | getmaxval(CTy *l) 7 | { 8 | if(l->t == CENUM) 9 | return 0xffffffff; 10 | switch(l->Prim.type) { 11 | case PRIMCHAR: 12 | if(l->Prim.issigned) 13 | return 0x7f; 14 | else 15 | return 0xff; 16 | case PRIMSHORT: 17 | if(l->Prim.issigned) 18 | return 0x7fff; 19 | else 20 | return 0xffff; 21 | case PRIMINT: 22 | case PRIMLONG: 23 | if(l->Prim.issigned) 24 | return 0x7fffffff; 25 | else 26 | return 0xffffffff; 27 | case PRIMLLONG: 28 | if(l->Prim.issigned) 29 | return 0x7fffffffffffffff; 30 | else 31 | return 0xffffffffffffffff; 32 | } 33 | panic("internal error"); 34 | return 0; 35 | } 36 | 37 | int64 38 | getminval(CTy *l) 39 | { 40 | if(l->t == CENUM) 41 | return -2147483648LL; 42 | if(!l->Prim.issigned) 43 | return 0; 44 | switch(l->Prim.type) { 45 | case PRIMCHAR: 46 | return -128LL; 47 | case PRIMSHORT: 48 | return -32768LL; 49 | case PRIMINT: 50 | case PRIMLONG: 51 | return -2147483648LL; 52 | case PRIMLLONG: 53 | return (int64)1 << 63; 54 | } 55 | panic("internal error"); 56 | return 0; 57 | } 58 | 59 | CTy *cvoid = &(CTy){ .t = CVOID, .incomplete = 1}; 60 | CTy *cchar = &(CTy){ .t = CPRIM, .size = 1, .align = 1, .Prim = {.type = PRIMCHAR, .issigned = 1}}; 61 | CTy *cshort = &(CTy){ .t = CPRIM, .size = 2, .align = 2, .Prim = {.type = PRIMSHORT, .issigned = 1}}; 62 | CTy *cint = &(CTy){ .t = CPRIM, .size = 4, .align = 4, .Prim = {.type = PRIMINT, .issigned = 1}}; 63 | CTy *clong = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMLONG, .issigned = 1}}; 64 | CTy *cllong = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMLLONG, .issigned = 1}}; 65 | CTy *cuchar = &(CTy){ .t = CPRIM, .size = 1, .align = 1, .Prim = {.type = PRIMCHAR}}; 66 | CTy *cushort = &(CTy){ .t = CPRIM, .size = 2, .align = 2, .Prim = {.type = PRIMSHORT}}; 67 | CTy *cuint = &(CTy){ .t = CPRIM, .size = 4, .align = 4, .Prim = {.type = PRIMINT}}; 68 | CTy *culong = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMLONG}}; 69 | CTy *cullong = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMLLONG}}; 70 | CTy *cfloat = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMFLOAT}}; 71 | CTy *cdouble = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMDOUBLE}}; 72 | CTy *cldouble = &(CTy){ .t = CPRIM, .size = 8, .align = 8, .Prim = {.type = PRIMLDOUBLE}}; 73 | 74 | -------------------------------------------------------------------------------- /src/cmd/6c/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | usage() 7 | { 8 | puts("Usage: 6c file.c"); 9 | exit(1); 10 | } 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | int i; 16 | Vec *includedirs; 17 | char *cfile; 18 | 19 | cfile = 0; 20 | includedirs = vec(); 21 | for(i = 1; i < argc; i++) { 22 | if(strcmp(argv[i], "-I") == 0) { 23 | i++; 24 | if(i >= argc) 25 | errorf("-I requires an include path\n"); 26 | vecappend(includedirs, argv[i]); 27 | } else if(strncmp(argv[i], "-I", 2) == 0) { 28 | vecappend(includedirs, argv[i]+2); 29 | } else { 30 | if(argv[i][0] == '-') 31 | errorf("unknown flag %s\n", argv[i]); 32 | if(cfile) 33 | errorf("please specify a single c file\n"); 34 | cfile = argv[i]; 35 | } 36 | } 37 | if(!cfile) 38 | usage(); 39 | cppinit(cfile, includedirs); 40 | emitinit(stdout); 41 | parse(); 42 | emitend(); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/cmd/abifuzz/main.c: -------------------------------------------------------------------------------- 1 | #include "u.h" 2 | #include "ds/ds.h" 3 | #include "mem/mem.h" 4 | #include 5 | 6 | #define MAXPARAMS 10 7 | #define MAXSTRUCTM 10 8 | #define MAXNEST 4 9 | 10 | typedef enum { 11 | CHAR, 12 | SHORT, 13 | INT, 14 | LONG, 15 | LLONG, 16 | FLOAT, 17 | DOUBLE, 18 | STRUCT, 19 | TEND, 20 | } Type; 21 | 22 | typedef struct { 23 | Type t; 24 | union { 25 | struct { 26 | char v; 27 | } Cchar; 28 | struct { 29 | short v; 30 | } Cshort; 31 | struct { 32 | int v; 33 | } Cint; 34 | struct { 35 | long v; 36 | } Clong; 37 | struct { 38 | long long v; 39 | } Cllong; 40 | struct { 41 | float v; 42 | } Cfloat; 43 | struct { 44 | double v; 45 | } Cdouble; 46 | struct { 47 | char *name; 48 | Vec *members; 49 | } Cstruct; 50 | }; 51 | } Val; 52 | 53 | typedef struct { 54 | Val *ret; 55 | Vec *vals; 56 | } Testcase; 57 | 58 | static Val *randval(); 59 | 60 | void 61 | printvaltype(Val *v) 62 | { 63 | switch(v->t) { 64 | case CHAR: 65 | printf("char"); 66 | break; 67 | case SHORT: 68 | printf("short"); 69 | break; 70 | case INT: 71 | printf("int"); 72 | break; 73 | case LONG: 74 | printf("long"); 75 | break; 76 | case LLONG: 77 | printf("long long"); 78 | break; 79 | case FLOAT: 80 | printf("float"); 81 | break; 82 | case DOUBLE: 83 | printf("double"); 84 | break; 85 | case STRUCT: 86 | printf("struct %s", v->Cstruct.name); 87 | break; 88 | default: 89 | panic("internal error"); 90 | } 91 | } 92 | 93 | int structcount = 0; 94 | 95 | static Val * 96 | randstruct(int depth) 97 | { 98 | Val *r, *p; 99 | int i, n; 100 | char buff[1024]; 101 | 102 | r = xmalloc(sizeof(Val)); 103 | r->t = STRUCT; 104 | r->Cstruct.members = vec(); 105 | n = rand() % MAXSTRUCTM; 106 | for(i = 0; i < n; i++) 107 | vecappend(r->Cstruct.members, randval(depth + 1)); 108 | snprintf(buff, sizeof buff, "s%d", structcount++); 109 | r->Cstruct.name = xstrdup(buff); 110 | printf("struct %s {\n", r->Cstruct.name); 111 | for(i = 0; i < r->Cstruct.members->len; i++) { 112 | p = vecget(r->Cstruct.members, i); 113 | printf("\t"); 114 | printvaltype(p); 115 | printf(" m%d;\n", i); 116 | } 117 | printf("};\n"); 118 | return r; 119 | } 120 | 121 | static Val * 122 | randval(int depth) 123 | { 124 | Val *r; 125 | 126 | again: 127 | switch(rand() % TEND) { 128 | case CHAR: 129 | r = xmalloc(sizeof(Val)); 130 | r->t = CHAR; 131 | r->Cchar.v = rand(); 132 | break; 133 | case SHORT: 134 | r = xmalloc(sizeof(Val)); 135 | r->t = SHORT; 136 | r->Cshort.v = rand(); 137 | break; 138 | case INT: 139 | r = xmalloc(sizeof(Val)); 140 | r->t = INT; 141 | r->Cint.v = rand(); 142 | break; 143 | case LONG: 144 | r = xmalloc(sizeof(Val)); 145 | r->t = LONG; 146 | r->Clong.v = rand(); 147 | break; 148 | case LLONG: 149 | r = xmalloc(sizeof(Val)); 150 | r->t = LLONG; 151 | r->Cllong.v = rand(); 152 | break; 153 | case FLOAT: 154 | r = xmalloc(sizeof(Val)); 155 | r->t = FLOAT; 156 | r->Cfloat.v = (float)rand(); 157 | break; 158 | case DOUBLE: 159 | r = xmalloc(sizeof(Val)); 160 | r->t = DOUBLE; 161 | r->Cdouble.v = (double)rand(); 162 | break; 163 | case STRUCT: 164 | if(depth > MAXNEST) 165 | goto again; 166 | r = randstruct(depth); 167 | break; 168 | default: 169 | panic("internal error randval"); 170 | } 171 | return r; 172 | } 173 | 174 | static Testcase * 175 | randtestcase() 176 | { 177 | Testcase *t; 178 | int n, i; 179 | 180 | t = xmalloc(sizeof(Testcase)); 181 | t->vals = vec(); 182 | t->ret = randval(0); 183 | n = rand() % MAXPARAMS; 184 | for(i = 0; i < n; i++) 185 | vecappend(t->vals, randval(0)); 186 | return t; 187 | } 188 | 189 | static void 190 | printinit(char *sel, Val *p) 191 | { 192 | Val *mem; 193 | char buf[128]; 194 | int i; 195 | 196 | switch(p->t) { 197 | case CHAR: 198 | printf("\t%s = %d;\n", sel, p->Cchar.v); 199 | break; 200 | case SHORT: 201 | printf("\t%s = %d;\n", sel, p->Cshort.v); 202 | break; 203 | case INT: 204 | printf("\t%s = %d;\n", sel, p->Cint.v); 205 | break; 206 | case LONG: 207 | printf("\t%s = %ld;\n", sel, p->Clong.v); 208 | break; 209 | case LLONG: 210 | printf("\t%s = %lld;\n", sel, p->Cllong.v); 211 | break; 212 | case FLOAT: 213 | printf("\t%s = %f;\n", sel, p->Cfloat.v); 214 | break; 215 | case DOUBLE: 216 | printf("\t%s = %f;\n", sel, p->Cdouble.v); 217 | break; 218 | case STRUCT: 219 | for(i = 0; i < p->Cstruct.members->len; i++) { 220 | mem = vecget(p->Cstruct.members, i); 221 | snprintf(buf, sizeof(buf), "%s.m%d", sel, i); 222 | printinit(buf, mem); 223 | } 224 | break; 225 | default: 226 | panic("internal error"); 227 | } 228 | } 229 | 230 | static void 231 | printcheck(char *sel, Val *p) 232 | { 233 | Val *mem; 234 | char buf[128]; 235 | int i; 236 | 237 | switch(p->t) { 238 | case CHAR: 239 | printf("\tif(%s != %d) abort();\n", sel, p->Cchar.v); 240 | break; 241 | case SHORT: 242 | printf("\tif(%s != %d) abort();\n", sel, p->Cshort.v); 243 | break; 244 | case INT: 245 | printf("\tif(%s != %d) abort();\n", sel, p->Cint.v); 246 | break; 247 | case LONG: 248 | printf("\tif(%s != %ld) abort();\n", sel, p->Clong.v); 249 | break; 250 | case LLONG: 251 | printf("\tif(%s != %lld) abort();\n", sel, p->Cllong.v); 252 | break; 253 | case FLOAT: 254 | printf("\tif(%s != %f) abort();\n", sel, p->Cfloat.v); 255 | break; 256 | case DOUBLE: 257 | printf("\tif(%s != %f) abort();\n", sel, p->Cdouble.v); 258 | break; 259 | case STRUCT: 260 | for(i = 0; i < p->Cstruct.members->len; i++) { 261 | mem = vecget(p->Cstruct.members, i); 262 | snprintf(buf, sizeof(buf), "%s.m%d", sel, i); 263 | printcheck(buf, mem); 264 | } 265 | break; 266 | default: 267 | panic("internal error"); 268 | } 269 | } 270 | 271 | static void 272 | printfunc(Testcase *t) 273 | { 274 | int i; 275 | char buf[64]; 276 | Vec *v; 277 | Val *p; 278 | 279 | v = t->vals; 280 | printvaltype(t->ret); 281 | printf("\n"); 282 | printf("f("); 283 | for(i = 0; i < v->len; i++) { 284 | p = vecget(v, i); 285 | printvaltype(p); 286 | printf(" p%d%s", i, (i == v->len - 1) ? "" : ", "); 287 | } 288 | printf(")\n"); 289 | printf("{\n"); 290 | printf("\t"); 291 | printvaltype(t->ret); 292 | printf(" r;\n"); 293 | printinit("r", t->ret); 294 | for(i = 0; i < v->len; i++) { 295 | p = vecget(v, i); 296 | snprintf(buf, sizeof(buf), "p%d", i); 297 | printcheck(buf, p); 298 | } 299 | printf("\treturn r;\n"); 300 | printf("}\n"); 301 | } 302 | 303 | static void 304 | printmain(Testcase *t) 305 | { 306 | Vec *v; 307 | Val *p; 308 | char buf[64]; 309 | int i; 310 | 311 | v = t->vals; 312 | printf("int\n"); 313 | printf("main()\n"); 314 | printf("{\n"); 315 | printf("\t"); 316 | printvaltype(t->ret); 317 | printf(" r;\n"); 318 | for(i = 0; i < v->len; i++) { 319 | p = vecget(v, i); 320 | printf("\t"); 321 | printvaltype(p); 322 | printf(" p%d;\n", i); 323 | } 324 | for(i = 0; i < v->len; i++) { 325 | p = vecget(v, i); 326 | snprintf(buf, sizeof(buf), "p%d", i); 327 | printinit(buf, p); 328 | } 329 | printf("\tr = f("); 330 | for(i = 0; i < v->len; i++) { 331 | printf("p%d%s", i, (i == v->len - 1) ? "" : ", "); 332 | } 333 | printf(");\n"); 334 | printcheck("r", t->ret); 335 | printf("\treturn 0;\n"); 336 | printf("}\n"); 337 | } 338 | 339 | static int 340 | getseed() 341 | { 342 | int i, c, r; 343 | FILE *f; 344 | 345 | f = fopen("/dev/urandom", "r"); 346 | if(!f) 347 | panic("get seed failed"); 348 | r = 0; 349 | for(i = 0; i < (int)sizeof(int); i++) { 350 | c = fgetc(f); 351 | if(c == EOF) 352 | panic("get seed read failed"); 353 | r = (r << 8) | c; 354 | } 355 | if(fclose(f) != 0) 356 | panic("get seed close failed"); 357 | return r; 358 | } 359 | 360 | int 361 | main(int argc, char *argv[]) 362 | { 363 | Testcase *t; 364 | int seed; 365 | 366 | if(argc == 1) 367 | seed = getseed(); 368 | else 369 | seed = strtoul(argv[1], 0, 10); 370 | printf("/* seed %u */\n", seed); 371 | srand(seed); 372 | t = randtestcase(); 373 | printf("void abort(void);\n"); 374 | printfunc(t); 375 | printmain(t); 376 | return 0; 377 | } 378 | -------------------------------------------------------------------------------- /src/cmd/cpp/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | usage(void) 7 | { 8 | puts("Usage: cpp file.c"); 9 | exit(1); 10 | } 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | Tok *t; 16 | 17 | if(argc != 2) 18 | usage(); 19 | cppinit(argv[1], vec()); 20 | while(1) { 21 | t = pp(); 22 | if(t->k == TOKEOF) 23 | break; 24 | printf("%s %s\n", tokktostr(t->k), t->v); 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/ds/ds.h: -------------------------------------------------------------------------------- 1 | /* Provides generic data structures. */ 2 | 3 | typedef struct ListEnt ListEnt; 4 | struct ListEnt { 5 | ListEnt *next; 6 | void *v; 7 | }; 8 | 9 | typedef struct List List; 10 | struct List { 11 | int len; 12 | ListEnt *head; 13 | }; 14 | 15 | List *list(); 16 | void listappend(List *, void *); 17 | void listprepend(List *, void *); 18 | void listinsert(List *, int, void *); 19 | void *listpopfront(List *); 20 | 21 | typedef struct Map Map; 22 | struct Map { 23 | List *l; 24 | }; 25 | 26 | Map *map(); 27 | void *mapget(Map *, char *); 28 | void mapdel(Map *, char *); 29 | void mapset(Map *, char *, void *); 30 | 31 | /* StrSet is an immutable set of strings. 32 | The null pointer is the empty set. */ 33 | typedef struct StrSet StrSet; 34 | struct StrSet { 35 | StrSet *next; 36 | char *v; 37 | }; 38 | 39 | StrSet *strsetadd(StrSet *, char *); 40 | int strsethas(StrSet *, char *); 41 | StrSet *strsetintersect(StrSet *, StrSet *); 42 | 43 | typedef struct Vec Vec; 44 | struct Vec { 45 | int cap; 46 | int len; 47 | void **d; 48 | }; 49 | 50 | Vec *vec(); 51 | void *vecget(Vec *, int); 52 | void vecset(Vec *, int, void *); 53 | void vecappend(Vec *, void *); 54 | -------------------------------------------------------------------------------- /src/ds/list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ds.h" 4 | 5 | List * 6 | list() 7 | { 8 | List *l; 9 | 10 | l = xmalloc(sizeof(List)); 11 | return l; 12 | } 13 | 14 | void 15 | listappend(List *l, void *v) 16 | { 17 | ListEnt *e, *ne; 18 | 19 | l->len++; 20 | ne = xmalloc(sizeof(ListEnt)); 21 | ne->v = v; 22 | if(l->head == 0) { 23 | l->head = ne; 24 | return; 25 | } 26 | e = l->head; 27 | while(e->next) 28 | e = e->next; 29 | e->next = ne; 30 | } 31 | 32 | void 33 | listprepend(List *l, void *v) 34 | { 35 | ListEnt *e; 36 | 37 | l->len++; 38 | e = xmalloc(sizeof(ListEnt)); 39 | e->v = v; 40 | e->next = l->head; 41 | l->head = e; 42 | } 43 | 44 | void 45 | listinsert(List *l, int idx, void *v) 46 | { 47 | ListEnt *e, *newe; 48 | int i; 49 | 50 | i = 0; 51 | e = l->head; 52 | if(!e) { 53 | listappend(l, v); 54 | return; 55 | } 56 | while(1) { 57 | if(i == idx) 58 | break; 59 | if(!e->next) 60 | break; 61 | e = e->next; 62 | i++; 63 | } 64 | newe = xmalloc(sizeof(ListEnt)); 65 | newe->v = v; 66 | newe->next = e->next; 67 | e->next = newe; 68 | } 69 | 70 | void * 71 | listpopfront(List *l) 72 | { 73 | ListEnt *e; 74 | 75 | if(!l->len) 76 | panic("pop from empty list"); 77 | if(l->len == 1) { 78 | e = l->head; 79 | l->head = 0; 80 | l->len = 0; 81 | return e->v; 82 | } 83 | l->len--; 84 | e = l->head; 85 | l->head = e->next; 86 | return e->v; 87 | } 88 | -------------------------------------------------------------------------------- /src/ds/map.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ds.h" 4 | 5 | typedef struct MapEnt MapEnt; 6 | struct MapEnt { 7 | char *k; 8 | void *v; 9 | }; 10 | 11 | Map *map() 12 | { 13 | Map *m; 14 | 15 | m = xmalloc(sizeof(Map)); 16 | m->l = list(); 17 | return m; 18 | } 19 | 20 | void 21 | mapset(Map *m, char *k, void *v) 22 | { 23 | MapEnt *me; 24 | 25 | me = xmalloc(sizeof(MapEnt)); 26 | me->k = k; 27 | me->v = v; 28 | listprepend(m->l, me); 29 | } 30 | 31 | void * 32 | mapget(Map *m, char *k) 33 | { 34 | MapEnt *me; 35 | ListEnt *e; 36 | 37 | for(e = m->l->head; e != 0; e = e->next) { 38 | me = e->v; 39 | if(strcmp(me->k, k) == 0) 40 | return me->v; 41 | } 42 | return 0; 43 | } 44 | 45 | void 46 | mapdel(Map *m, char *k) 47 | { 48 | mapset(m, k, 0); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/ds/strset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ds.h" 4 | 5 | StrSet * 6 | strsetadd(StrSet *ss, char *v) 7 | { 8 | StrSet *r; 9 | 10 | if(strsethas(ss,v)) 11 | return ss; 12 | r = xmalloc(sizeof(StrSet)); 13 | r->v = v; 14 | r->next = ss; 15 | return r; 16 | } 17 | 18 | int 19 | strsethas(StrSet *ss, char *v) 20 | { 21 | while(ss) { 22 | if(strcmp(v, ss->v) == 0) 23 | return 1; 24 | ss = ss->next; 25 | } 26 | return 0; 27 | } 28 | 29 | StrSet * 30 | strsetintersect(StrSet *ss, StrSet *other) 31 | { 32 | char *v; 33 | StrSet *r; 34 | 35 | r = 0; 36 | while(ss) { 37 | v = ss->v; 38 | if(strsethas(other, v)) 39 | r = strsetadd(r, v); 40 | ss = ss->next; 41 | } 42 | return r; 43 | } 44 | -------------------------------------------------------------------------------- /src/ds/vec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ds.h" 4 | 5 | Vec * 6 | vec() 7 | { 8 | Vec *v; 9 | 10 | v = xmalloc(sizeof(Vec)); 11 | v->len = 0; 12 | v->cap = 16; 13 | v->d = xmalloc(sizeof(void*) * v->cap); 14 | return v; 15 | } 16 | 17 | void * 18 | vecget(Vec *v, int idx) 19 | { 20 | if(idx >= v->len) 21 | panic("vec get out of bounds"); 22 | return v->d[idx]; 23 | } 24 | 25 | void 26 | vecset(Vec *v, int idx, void *x) 27 | { 28 | if(idx >= v->len) 29 | panic("vec set out of bounds"); 30 | v->d[idx] = x; 31 | } 32 | 33 | static void 34 | vecresize(Vec *v, int cap) 35 | { 36 | int i; 37 | void **nd; 38 | 39 | if(v->cap >= cap) 40 | return; 41 | nd = xmalloc(cap*sizeof(void*)); 42 | for(i = 0; i < v->len; i++) 43 | nd[i] = v->d[i]; 44 | v->d = nd; 45 | v->cap = cap; 46 | } 47 | 48 | void 49 | vecappend(Vec *v, void *x) 50 | { 51 | if(v->len == v->cap) 52 | vecresize(v, v->len + 16); 53 | v->d[v->len] = x; 54 | v->len++; 55 | } 56 | 57 | int 58 | vecremove(Vec *v, void *x) 59 | { 60 | int i; 61 | 62 | for(i = 0; i < v->len; i++) { 63 | if(v->d[i] == x) 64 | break; 65 | } 66 | if(i == v->len) 67 | return 0; 68 | for(; i < v->len - 1; i++) { 69 | v->d[i] = v->d[i+1]; 70 | } 71 | v->len -= 1; 72 | return 1; 73 | } 74 | -------------------------------------------------------------------------------- /src/mem/mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mem.h" 3 | 4 | char * 5 | xstrdup(char *s) 6 | { 7 | int l; 8 | char *r; 9 | 10 | l = strlen(s); 11 | r = xmalloc(l + 1); 12 | strncpy(r, s, l); 13 | return r; 14 | } 15 | 16 | void * 17 | xmalloc(int n) 18 | { 19 | char *v; 20 | int i; 21 | 22 | v = malloc(n); 23 | if(!v) 24 | panic("out of memory!"); 25 | for(i = 0; i < n; i++) 26 | v[i] = 0; 27 | return v; 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/mem/mem.h: -------------------------------------------------------------------------------- 1 | 2 | void *xmalloc(int); 3 | char *xstrdup(char *); 4 | -------------------------------------------------------------------------------- /src/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void panic(char *fmt, ...) 4 | { 5 | va_list va; 6 | 7 | va_start(va, fmt); 8 | vfprintf(stderr, fmt, va); 9 | fputs("\n", stderr); 10 | va_end(va); 11 | exit(1); 12 | } 13 | -------------------------------------------------------------------------------- /src/selfhost/README: -------------------------------------------------------------------------------- 1 | This directory contains stubbed headers to aid in bootstrapping the compiler. 2 | It should be removed when the compiler can handle a real C library. 3 | -------------------------------------------------------------------------------- /src/selfhost/stdarg.h: -------------------------------------------------------------------------------- 1 | 2 | typedef struct { 3 | unsigned int gp_offset; 4 | unsigned int fp_offset; 5 | void *overflow_arg_area; 6 | void *reg_save_area; 7 | } __va_elem; 8 | 9 | typedef __va_elem va_list[1]; 10 | 11 | #define va_start(X, Y) __builtin_va_start((X), (Y)) 12 | #define va_end(X) (X) 13 | 14 | int vfprintf(FILE *stream, const char *format, va_list ap); 15 | 16 | -------------------------------------------------------------------------------- /src/selfhost/stdint.h: -------------------------------------------------------------------------------- 1 | 2 | typedef long long int64_t; 3 | typedef unsigned long long uint64_t; 4 | typedef int int32_t; 5 | typedef unsigned int uint32_t; 6 | 7 | #define __attribute__(X) 8 | 9 | -------------------------------------------------------------------------------- /src/selfhost/stdio.h: -------------------------------------------------------------------------------- 1 | 2 | #define EOF -1 3 | 4 | typedef struct FILE FILE; 5 | extern FILE *stdout, *stderr; 6 | 7 | 8 | int ungetc(int c, FILE *stream); 9 | int puts(const char *); 10 | int snprintf(char *, long long, const char *, ...); 11 | int fprintf(FILE *stream, const char *format, ...); 12 | int fgetc(FILE *stream); 13 | int fputs(const char *s, FILE *stream); 14 | int fputc(int c, FILE *stream); 15 | FILE *fopen(const char *, const char *); 16 | int *fclose(FILE *); 17 | 18 | -------------------------------------------------------------------------------- /src/selfhost/stdlib.h: -------------------------------------------------------------------------------- 1 | 2 | long long atoll(const char *); 3 | void qsort(void *, long , long ,int (*)(const void *, const void *)); 4 | void *malloc(long size); 5 | void exit(int); 6 | -------------------------------------------------------------------------------- /src/selfhost/string.h: -------------------------------------------------------------------------------- 1 | 2 | int strcmp(const char *s1, const char *s2); 3 | int strncmp(const char *s1, const char *s2, long n); 4 | long strlen(const char *s); 5 | char *strncpy(char *dest, const char *src, long n); 6 | -------------------------------------------------------------------------------- /src/u.h: -------------------------------------------------------------------------------- 1 | /* Provides the core types and core functions like panic */ 2 | 3 | /* This is the only header in the code base 4 | which is allowed to include other headers. 5 | Keep the list small. */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NORETURN __attribute__((__noreturn__)) 14 | 15 | typedef int64_t int64; 16 | typedef int32_t int32; 17 | typedef uint64_t uint64; 18 | typedef uint32_t uint32; 19 | typedef unsigned int uint; 20 | 21 | void panic(char *fmt, ...) NORETURN; 22 | 23 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | for T in test/execute/*.c test/cpp/*.c test/bugs/*.c 6 | do 7 | if ! ( bin/6c $T > $T.s && 8 | gcc -c $T.s -o $T.o && 9 | gcc $T.o -o $T.bin && 10 | $T.bin > /dev/null ) 11 | then 12 | echo $T FAIL 13 | exit 1 14 | fi 15 | echo $T PASS 16 | done 17 | 18 | for T in test/error/*.c test/cpperror/*.c 19 | do 20 | if bin/6c $T > /dev/null 2> $T.stderr 21 | then 22 | echo $T FAIL 23 | exit 1 24 | fi 25 | for P in `sed -n '/^PATTERN:/s/PATTERN://gp' $T` 26 | do 27 | if ! grep -q $P $T.stderr 28 | then 29 | echo pattern: $P failed 30 | echo $T FAIL 31 | exit 1 32 | fi 33 | done 34 | echo $T PASS 35 | done 36 | -------------------------------------------------------------------------------- /test/LICENSE: -------------------------------------------------------------------------------- 1 | The following license is applied to all tests within this directory. 2 | The intention is to allow free use of these tests without requiring 3 | that the license be reproduced. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | 20 | -------------------------------------------------------------------------------- /test/bugs/0001.c: -------------------------------------------------------------------------------- 1 | int 2 | main() { 3 | int x; 4 | 5 | x = -1; 6 | return x > 2; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /test/bugs/0002.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | long long x; 5 | x = 0; 6 | return x; 7 | } 8 | -------------------------------------------------------------------------------- /test/bugs/0004.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | main() 4 | { 5 | int i, n, p, next, isprime; 6 | 7 | n = 5; 8 | p = 11; 9 | next = 12; 10 | while(n != 100) { 11 | isprime = 1; 12 | if(next % 2 == 0) { 13 | isprime = 0; 14 | } else { 15 | for(i = 3; i < next; i = i + 2) { 16 | if(next % i == 0) { 17 | isprime = 0; 18 | break; 19 | } 20 | } 21 | } 22 | if(isprime) { 23 | p = next; 24 | n++; 25 | } 26 | next = next + 1; 27 | } 28 | if(p != 541) 29 | return 1; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/bugs/0005.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | main() 4 | { 5 | int (((p))); 6 | 7 | p = 0; 8 | return p; 9 | } 10 | -------------------------------------------------------------------------------- /test/bugs/0006.c: -------------------------------------------------------------------------------- 1 | 2 | void * 3 | foo() 4 | { 5 | return 0; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/bugs/0008.c: -------------------------------------------------------------------------------- 1 | 2 | int main() 3 | { 4 | int x; 5 | 6 | x = 2; 7 | if(!(x == 2)) 8 | return 1; 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/bugs/0012.c: -------------------------------------------------------------------------------- 1 | abort(); 2 | main() { 3 | int b; 4 | b = 1080377166; 5 | if (b != 1080377166) 6 | abort(); 7 | } 8 | -------------------------------------------------------------------------------- /test/bugs/0013.c.disabled: -------------------------------------------------------------------------------- 1 | /* seed 3533508740 */ 2 | struct s0 { 3 | long m0; 4 | long m1; 5 | }; 6 | struct s1 { 7 | struct s0 m0; 8 | long m1; 9 | }; 10 | struct s2 { 11 | int m0; 12 | }; 13 | void abort(void); 14 | struct s1 15 | f(int p0, struct s2 p1) 16 | { 17 | struct s1 r; 18 | r.m0.m0 = 1293431308; 19 | r.m0.m1 = 61651767; 20 | r.m1 = 1736112203; 21 | if(p0 != 413324820) abort(); 22 | if(p1.m0 != 1141848071) abort(); 23 | return r; 24 | } 25 | int 26 | main() 27 | { 28 | struct s1 r; 29 | int p0; 30 | struct s2 p1; 31 | p0 = 413324820; 32 | p1.m0 = 1141848071; 33 | r = f(p0, p1); 34 | if(r.m0.m0 != 1293431308) abort(); 35 | if(r.m0.m1 != 61651767) abort(); 36 | if(r.m1 != 1736112203) abort(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /test/bugs/0014.c.disabled: -------------------------------------------------------------------------------- 1 | struct s { 2 | char a; 3 | char b; 4 | }; 5 | 6 | void abort(void); 7 | 8 | struct s 9 | f() 10 | { 11 | struct s r; 12 | r.a = 1; 13 | r.b = 2; 14 | return r; 15 | } 16 | int 17 | main() 18 | { 19 | struct s r; 20 | r = f(); 21 | if(r.a != 1) abort(); 22 | if(r.b != 2) abort(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/bugs/0015.c: -------------------------------------------------------------------------------- 1 | 2 | int *calloc(int, int); 3 | 4 | int N; 5 | int *t; 6 | 7 | int 8 | chk(int x, int y) 9 | { 10 | int i; 11 | int r; 12 | 13 | for (r=i=0; i<8; i++) { 14 | r = r + t[x + 8*i]; 15 | r = r + t[i + 8*y]; 16 | if (x+i < 8 & y+i < 8) 17 | r = r + t[x+i + 8*(y+i)]; 18 | if (x+i < 8 & y-i >= 0) 19 | r = r + t[x+i + 8*(y-i)]; 20 | if (x-i >= 0 & y+i < 8) 21 | r = r + t[x-i + 8*(y+i)]; 22 | if (x-i >= 0 & y-i >= 0) 23 | r = r + t[x-i + 8*(y-i)]; 24 | } 25 | return r; 26 | } 27 | 28 | int 29 | go(int n, int x, int y) 30 | { 31 | if (n == 8) { 32 | N++; 33 | return 0; 34 | } 35 | for (; y<8; y++) { 36 | for (; x<8; x++) 37 | if (chk(x, y) == 0) { 38 | t[x + 8*y]++; 39 | go(n+1, x, y); 40 | t[x + 8*y]--; 41 | } 42 | x = 0; 43 | } 44 | } 45 | 46 | int 47 | main() 48 | { 49 | t = calloc(64, sizeof(int)); 50 | go(0, 0, 0); 51 | if(N != 92) 52 | return 1; 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /test/bugs/0017.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | foo(void) 4 | { 5 | return 0; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | return foo(); 12 | } 13 | -------------------------------------------------------------------------------- /test/bugs/0018.c: -------------------------------------------------------------------------------- 1 | 2 | static int x = 0; 3 | static int 4 | foo() 5 | { 6 | return x; 7 | } 8 | 9 | int 10 | main() 11 | { 12 | return foo(); 13 | } 14 | -------------------------------------------------------------------------------- /test/bugs/0019.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | 3 | enum { 4 | TOKAUTO, 5 | }; 6 | 7 | static struct {char *kw; int t;} arr[2] = { 8 | {0, TOKAUTO}, 9 | {0, 0} 10 | }; 11 | 12 | int 13 | main() 14 | { 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/bugs/0020.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | int 4 | main() 5 | { 6 | 7 | int i; 8 | 9 | for(i = 0; i < 3; i++) 10 | continue; 11 | return 0; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/bugs/0021.c: -------------------------------------------------------------------------------- 1 | char *x = "abc"; 2 | 3 | int 4 | main() 5 | { 6 | char *p; 7 | 8 | p = x; 9 | p = p + 1; 10 | if(p[0] != 'b') 11 | return 1; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/cpp/0001-define1.c: -------------------------------------------------------------------------------- 1 | #define X x 2 | 3 | int 4 | main() 5 | { 6 | int x; 7 | 8 | x = 0; 9 | return X; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/cpp/0001-define2.c: -------------------------------------------------------------------------------- 1 | #define x x 2 | 3 | int 4 | main() 5 | { 6 | int x; 7 | 8 | x = 0; 9 | return x; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/cpp/0001-define3.c: -------------------------------------------------------------------------------- 1 | #define A 3 2 | #define FOO(X,Y,Z) X + Y + Z 3 | #define SEMI ; 4 | 5 | int 6 | main() 7 | { 8 | if(FOO(1, 2, A) != 6) 9 | return 1 SEMI 10 | return FOO(0,0,0); 11 | } 12 | -------------------------------------------------------------------------------- /test/cpperror/0001-define1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: redefinition 3 | PATTERN: c:7: 4 | */ 5 | 6 | #define X Y 7 | #define X Z 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/cpperror/0001-define2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: undef 3 | PATTERN: c:6: 4 | */ 5 | 6 | #undef X 7 | 8 | -------------------------------------------------------------------------------- /test/cpperror/0001-define3.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: garbage 3 | PATTERN: c:7: 4 | */ 5 | 6 | #define X 7 | #undef X asdfad 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/error/0001-undefined1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: undefined 3 | PATTERN: c:9:5 4 | */ 5 | 6 | int 7 | main() 8 | { 9 | x; 10 | } 11 | -------------------------------------------------------------------------------- /test/error/0002-redefinition1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: redefinition 3 | PATTERN: c:7: 4 | */ 5 | 6 | int x = 0; 7 | int x = 1; 8 | 9 | -------------------------------------------------------------------------------- /test/error/0002-redefinition2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: L1 3 | PATTERN: c:11 4 | */ 5 | 6 | void 7 | foo() 8 | { 9 | L1: 10 | L2: 11 | L1: 12 | return; 13 | } 14 | -------------------------------------------------------------------------------- /test/error/0002-redefinition3.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: x 3 | */ 4 | 5 | struct x { 6 | int x; 7 | int y; 8 | int x; 9 | }; 10 | -------------------------------------------------------------------------------- /test/error/0002-redefinition4.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: x 3 | PATTERN: typedef 4 | PATTERN: c:9 5 | */ 6 | 7 | typedef int x; 8 | typedef int x; 9 | typedef int *x; 10 | -------------------------------------------------------------------------------- /test/error/0003-lval1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: c:8 3 | PATTERN: lvalue 4 | */ 5 | int 6 | main() 7 | { 8 | 3++; 9 | } 10 | -------------------------------------------------------------------------------- /test/error/0003-lval2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: c:8 3 | PATTERN: lvalue 4 | */ 5 | int 6 | main() 7 | { 8 | 3 = 2; 9 | } 10 | -------------------------------------------------------------------------------- /test/error/0003-lval3.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: c:10 3 | PATTERN: lvalue 4 | */ 5 | int 6 | main() 7 | { 8 | int *p; 9 | 10 | p = &2; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/error/0004-tags1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: redefinition 3 | PATTERN: c:8: 4 | */ 5 | 6 | struct X; 7 | struct X {}; 8 | struct X {int x;}; 9 | -------------------------------------------------------------------------------- /test/error/0004-tags2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: tag 3 | PATTERN: c:7: 4 | */ 5 | 6 | struct X; 7 | enum X; 8 | -------------------------------------------------------------------------------- /test/error/0004-tags3.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: tag 3 | PATTERN: c:7: 4 | */ 5 | 6 | enum X; 7 | struct X; 8 | -------------------------------------------------------------------------------- /test/error/0004-tags4.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: incomplete 3 | PATTERN: c:12: 4 | */ 5 | 6 | int 7 | main() 8 | { 9 | { 10 | struct X {}; 11 | } 12 | struct X x; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/error/0004-tags5.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: incomplete 3 | PATTERN: c:7: 4 | */ 5 | 6 | struct X; 7 | struct X { struct X x; }; 8 | -------------------------------------------------------------------------------- /test/error/0005-incomplete1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: incomplete 3 | PATTERN: c:10: 4 | */ 5 | 6 | struct X; 7 | 8 | int main() 9 | { 10 | struct X x; 11 | return 0; 12 | } 13 | 14 | struct X {int v;}; 15 | -------------------------------------------------------------------------------- /test/error/0005-incomplete2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: incomplete 3 | PATTERN: c:10: 4 | */ 5 | 6 | struct X x; 7 | 8 | int main() 9 | { 10 | return x.v; 11 | } 12 | 13 | struct X {int v;}; 14 | -------------------------------------------------------------------------------- /test/error/0006-inits1.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: size 3 | PATTERN: c:6: 4 | */ 5 | 6 | int x[3] = {1, 2}; 7 | 8 | -------------------------------------------------------------------------------- /test/error/0006-inits2.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: end of struct 3 | PATTERN: c:6: 4 | */ 5 | 6 | struct { int a; int b; int c; } x = {1, 2, 3, 4}; 7 | 8 | -------------------------------------------------------------------------------- /test/error/0006-inits3.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: overlap 3 | PATTERN: c:6: 4 | */ 5 | 6 | int arr[3] = {[0] = 1, [1] = 2, [0] = 3}; 7 | 8 | -------------------------------------------------------------------------------- /test/error/0006-inits4.c: -------------------------------------------------------------------------------- 1 | /* 2 | PATTERN: wrong size 3 | PATTERN: c:6: 4 | */ 5 | 6 | int arr[3] = {[5] = 4}; 7 | 8 | -------------------------------------------------------------------------------- /test/error/0006-inits5.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | PATTERN: incomplete 4 | PATTERN: c:6: 5 | */ 6 | struct S s = {1}; 7 | 8 | -------------------------------------------------------------------------------- /test/execute/0001-sanity.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /test/execute/0002-global1.c: -------------------------------------------------------------------------------- 1 | int x; 2 | 3 | int 4 | main() 5 | { 6 | x = 0; 7 | return x; 8 | } 9 | -------------------------------------------------------------------------------- /test/execute/0003-locals1.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | main() 4 | { 5 | int x; 6 | 7 | x = 0; 8 | return x; 9 | } 10 | -------------------------------------------------------------------------------- /test/execute/0004-operators1.c: -------------------------------------------------------------------------------- 1 | /* TODO: more types */ 2 | 3 | int 4 | main() 5 | { 6 | int x; 7 | 8 | x = 0; 9 | x = x + 2; // 2 10 | x = x - 1; // 1 11 | x = x * 6; // 6 12 | x = x / 2; // 3 13 | x = x % 2; // 1 14 | x = x << 2; // 4 15 | x = x >> 1; // 2 16 | x = x | 255; // 255 17 | x = x & 3; // 3 18 | x = x ^ 1; // 2 19 | if(x != 2) 20 | return 1; 21 | if(!(x == 2)) 22 | return 2; 23 | if(x == 3) 24 | return 3; 25 | if(x != 2) 26 | return 4; 27 | if(!(x != 3)) 28 | return 5; 29 | if(x < 1) 30 | return 6; 31 | if(x < 2) 32 | return 7; 33 | if(!(x < 3)) 34 | return 8; 35 | if(!(x > 1)) 36 | return 9; 37 | if(x > 2) 38 | return 10; 39 | if(x > 3) 40 | return 11; 41 | if(x <= 1) 42 | return 12; 43 | if(!(x <= 2)) 44 | return 13; 45 | if(!(x <= 3)) 46 | return 14; 47 | if(!(x >= 1)) 48 | return 15; 49 | if(!(x >= 2)) 50 | return 16; 51 | if(x >= 3) 52 | return 17; 53 | return 0; 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/execute/0004-operators2.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 3; 7 | x = !x; // 0 8 | x = !x; // 1 9 | x = ~x; // -1 10 | x = -x; // 2 11 | if(x != 2) 12 | return 1; 13 | return 0; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /test/execute/0004-operators3.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 0; 7 | x += 1; 8 | if (x != 1) 9 | return 1; 10 | x -= 1; 11 | if(x != 0) 12 | return 1; 13 | x |= 3; 14 | if(x != 3) 15 | return 1; 16 | x &= 2; 17 | if(x != 2) 18 | return 1; 19 | x *= 2; 20 | if(x != 4) 21 | return 1; 22 | return 0; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/execute/0004-operators4.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | main() 4 | { 5 | int x; 6 | int y; 7 | 8 | x = 1; 9 | y = 1; 10 | x = y = 0; 11 | if(x != 0) 12 | return 1; 13 | if(y != 0) 14 | return 1; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/execute/0004-operators5.c: -------------------------------------------------------------------------------- 1 | 2 | int g; 3 | 4 | int 5 | effect() 6 | { 7 | g = 1; 8 | return 1; 9 | } 10 | 11 | int 12 | main() 13 | { 14 | int x; 15 | 16 | g = 0; 17 | x = 0; 18 | if(x && effect()) 19 | return 1; 20 | if(g) 21 | return 2; 22 | x = 1; 23 | if(x && effect()) { 24 | if(g != 1) 25 | return 3; 26 | } else { 27 | return 4; 28 | } 29 | g = 0; 30 | x = 1; 31 | if(x || effect()) { 32 | if(g) 33 | return 5; 34 | } else { 35 | return 6; 36 | } 37 | x = 0; 38 | if(x || effect()) { 39 | if(g != 1) 40 | return 7; 41 | } else { 42 | return 8; 43 | } 44 | return 0; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /test/execute/0005-if1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | if(0) { 5 | return 1; 6 | } else if(0) { 7 | /* empty */ 8 | } else { 9 | if(1) { 10 | if(0) 11 | return 1; 12 | else 13 | return 0; 14 | } else { 15 | return 1; 16 | } 17 | } 18 | return 1; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /test/execute/0006-while1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 10; 7 | while(x) 8 | x = x - 1; 9 | return x; 10 | } 11 | -------------------------------------------------------------------------------- /test/execute/0007-dowhile1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 0; 7 | do 8 | x = x + 1; 9 | while(x < 10); 10 | 11 | do { 12 | x = x + 1; 13 | } while(x < 20); 14 | 15 | return x - 20; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /test/execute/0008-for1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | for(x = 0; x < 10 ; x = x + 1) 7 | ; 8 | if(x != 10) 9 | return 1; 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/execute/0009-breakcont1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 0; 7 | while(1) 8 | break; 9 | while(1) { 10 | if (x == 5) { 11 | break; 12 | } 13 | x = x + 1; 14 | continue; 15 | } 16 | for (;;) { 17 | if (x == 10) { 18 | break; 19 | } 20 | x = x + 1; 21 | continue; 22 | } 23 | do { 24 | if (x == 15) { 25 | break; 26 | } 27 | x = x + 1; 28 | continue; 29 | } while(1); 30 | return x - 15; 31 | } 32 | -------------------------------------------------------------------------------- /test/execute/0010-goto1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() { 3 | start: 4 | goto next; 5 | return 1; 6 | success: 7 | return 0; 8 | next: 9 | foo: 10 | goto success; 11 | return 1; 12 | } 13 | -------------------------------------------------------------------------------- /test/execute/0011-switch1.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | int 4 | main() 5 | { 6 | int x; 7 | 8 | x = 0; 9 | switch(x) 10 | case 0: 11 | ; 12 | switch(x) 13 | case 0: 14 | switch(x) { 15 | case 0: 16 | goto next; 17 | default: 18 | return 1; 19 | } 20 | return 1; 21 | next: 22 | switch(x) 23 | case 1: 24 | return 1; 25 | switch(x) { 26 | { 27 | x = 1 + 1; 28 | foo: 29 | case 1: 30 | return 1; 31 | } 32 | } 33 | switch(x) { 34 | case 0: 35 | return x; 36 | case 1: 37 | return 1; 38 | default: 39 | return 1; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/execute/0012-pointers1.c: -------------------------------------------------------------------------------- 1 | int g; 2 | 3 | int 4 | main() 5 | { 6 | int x; 7 | int *p; 8 | 9 | g = 1; 10 | x = 1; 11 | p = &x; 12 | *p = 0; 13 | if(x) 14 | return 1; 15 | 16 | p = &g; 17 | *p = 0; 18 | if(g) 19 | return 1; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/execute/0012-pointers2.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | int *p; 6 | int **pp; 7 | 8 | x = 1; 9 | p = &x; 10 | pp = &p; 11 | **pp = 0; 12 | return x; 13 | } 14 | -------------------------------------------------------------------------------- /test/execute/0013-struct1.c: -------------------------------------------------------------------------------- 1 | struct T { 2 | int x; 3 | int y; 4 | }; 5 | 6 | int 7 | main() 8 | { 9 | struct T v; 10 | 11 | v.y = 0; 12 | return v.y; 13 | } 14 | -------------------------------------------------------------------------------- /test/execute/0013-struct2.c: -------------------------------------------------------------------------------- 1 | struct s { 2 | int x; 3 | int y; 4 | }; 5 | 6 | int 7 | main() { 8 | struct s v; 9 | v.x = 2; 10 | v.y = 1; 11 | if(v.x != 2) 12 | return 1; 13 | if(v.y !=1) 14 | return 1; 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /test/execute/0013-struct3.c: -------------------------------------------------------------------------------- 1 | struct s { 2 | int x; 3 | struct { 4 | int y; 5 | int z; 6 | } nest; 7 | }; 8 | 9 | int 10 | main() { 11 | struct s v; 12 | v.x = 1; 13 | v.nest.y = 2; 14 | v.nest.z = 3; 15 | if (v.x + v.nest.y + v.nest.z != 6) 16 | return 1; 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test/execute/0013-struct4.c: -------------------------------------------------------------------------------- 1 | struct T { 2 | int x; 3 | int y; 4 | }; 5 | 6 | int 7 | main() 8 | { 9 | struct T v, *p; 10 | 11 | p = &v; 12 | v.y = 2; 13 | if(p->y != 2) 14 | return 1; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/execute/0013-struct5.c: -------------------------------------------------------------------------------- 1 | struct T; 2 | 3 | struct T { 4 | int x; 5 | }; 6 | 7 | int 8 | main() 9 | { 10 | struct T v; 11 | { struct T { int z; }; } 12 | v.x = 2; 13 | if(v.x != 2) 14 | return 1; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/execute/0013-struct6.c: -------------------------------------------------------------------------------- 1 | struct T { 2 | struct T *p; 3 | int x; 4 | }; 5 | 6 | int 7 | main() 8 | { 9 | struct T a, b; 10 | b.p = &a; 11 | b.p->x = 42; 12 | if(a.x != 42) 13 | return 1; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/execute/0014-array1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int arr[2]; 5 | 6 | arr[1] = 2; 7 | if(arr[1] != 2) 8 | return 1; 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /test/execute/0015-calls01.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | foo() 4 | { 5 | return 0; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | return foo(); 12 | } 13 | -------------------------------------------------------------------------------- /test/execute/0015-calls02.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | foo(int a, int b) 4 | { 5 | return a + b; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | return foo(1, 2) - 3; 12 | } 13 | -------------------------------------------------------------------------------- /test/execute/0015-calls03.c: -------------------------------------------------------------------------------- 1 | int x; 2 | 3 | int 4 | foo(int *p1) 5 | { 6 | *p1 = 0; 7 | return 0; 8 | } 9 | 10 | int 11 | main() 12 | { 13 | x = 6; 14 | foo(&x); 15 | return x; 16 | } 17 | -------------------------------------------------------------------------------- /test/execute/0015-calls04.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | foo(int a, int b, int c, int d, int e, int f, 4 | int g, int h, int i, int j, int k, int l) 5 | { 6 | if(a != 1) 7 | return 0; 8 | if(f != 2) 9 | return 0; 10 | if(l != 2) 11 | return 0; 12 | return a+b+c+d+e+f+g+h+i+j+k+l; 13 | } 14 | 15 | int 16 | main() 17 | { 18 | int x; 19 | 20 | x = foo(1,1,1,1,1,2,1,1,1,1,1,2); 21 | if(x != 14) 22 | return 1; 23 | return 0; 24 | } -------------------------------------------------------------------------------- /test/execute/0015-calls05.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo1 { 3 | char a; 4 | }; 5 | 6 | int f1(struct Foo1 v1, struct Foo1 v2) 7 | { 8 | return v1.a + v2.a; 9 | } 10 | 11 | struct Foo2 { 12 | int a; 13 | int b; 14 | }; 15 | 16 | int f2(struct Foo2 v) 17 | { 18 | return v.a + v.b; 19 | } 20 | 21 | int 22 | main() 23 | { 24 | struct Foo1 v1, v2; 25 | 26 | v1.a = 1; 27 | v2.a = 2; 28 | if(f1(v1, v2) != 3) 29 | return 1; 30 | 31 | struct Foo2 v; 32 | 33 | v.a = 1; 34 | v.b = 2; 35 | if(f2(v) != 3) 36 | return 2; 37 | return 0; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/execute/0015-calls06.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | int c; 6 | int d; 7 | }; 8 | 9 | int f(struct Foo s) 10 | { 11 | if(s.a != 1) 12 | return 1; 13 | if(s.b != 2) 14 | return 2; 15 | if(s.c != 3) 16 | return 3; 17 | if(s.d != 4) 18 | return 4; 19 | return 0; 20 | } 21 | 22 | int 23 | main() 24 | { 25 | struct Foo s; 26 | 27 | s.a = 1; 28 | s.b = 2; 29 | s.c = 3; 30 | s.d = 4; 31 | return f(s); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/execute/0015-calls07.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | int c; 6 | int d; 7 | int e; 8 | }; 9 | 10 | int f(struct Foo s) 11 | { 12 | if(s.a != 1) 13 | return 1; 14 | if(s.b != 2) 15 | return 2; 16 | if(s.c != 3) 17 | return 3; 18 | if(s.d != 4) 19 | return 4; 20 | if(s.e != 5) 21 | return 5; 22 | return 0; 23 | } 24 | 25 | int 26 | main() 27 | { 28 | struct Foo s; 29 | 30 | s.a = 1; 31 | s.b = 2; 32 | s.c = 3; 33 | s.d = 4; 34 | s.e = 5; 35 | return f(s); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /test/execute/0015-calls08.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | int c; 6 | int d; 7 | }; 8 | 9 | /* on amd64 this tests a 2 reg struct arg being demoted to memory. */ 10 | int f(int a, int b, int c, int d, int e, struct Foo s, int f) 11 | { 12 | if(a != 1) 13 | return 1; 14 | if(b != 2) 15 | return 2; 16 | if(c != 3) 17 | return 3; 18 | if(d != 4) 19 | return 4; 20 | if(e != 5) 21 | return 5; 22 | if(s.a != 6) 23 | return 6; 24 | if(s.b != 7) 25 | return 7; 26 | if(s.c != 8) 27 | return 8; 28 | if(s.d != 9) 29 | return 9; 30 | if(f != 10) 31 | return 10; 32 | return 0; 33 | } 34 | 35 | int 36 | main() 37 | { 38 | struct Foo s; 39 | 40 | s.a = 6; 41 | s.b = 7; 42 | s.c = 8; 43 | s.d = 9; 44 | return f(1, 2, 3, 4, 5, s, 10); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /test/execute/0015-calls09.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | }; 5 | 6 | struct Foo 7 | func() 8 | { 9 | struct Foo v; 10 | v.a = 123; 11 | return v; 12 | } 13 | 14 | int 15 | main() 16 | { 17 | struct Foo v; 18 | v = func(); 19 | if(v.a != 123) 20 | return 1; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/execute/0015-calls10.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | int c; 6 | int d; 7 | }; 8 | 9 | struct Foo 10 | func() 11 | { 12 | struct Foo v; 13 | v.a = 1; 14 | v.b = 2; 15 | v.c = 3; 16 | v.d = 4; 17 | return v; 18 | } 19 | 20 | int 21 | main() 22 | { 23 | struct Foo v; 24 | v = func(); 25 | if(v.a != 1) 26 | return 1; 27 | if(v.b != 2) 28 | return 2; 29 | if(v.c != 3) 30 | return 3; 31 | if(v.d != 4) 32 | return 4; 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/execute/0015-calls11.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | int c; 6 | int d; 7 | int e; 8 | int f; 9 | }; 10 | 11 | struct Foo 12 | func() 13 | { 14 | struct Foo v; 15 | v.a = 1; 16 | v.b = 2; 17 | v.c = 3; 18 | v.d = 4; 19 | v.e = 5; 20 | v.f = 6; 21 | return v; 22 | } 23 | 24 | int 25 | main() 26 | { 27 | struct Foo v; 28 | 29 | v = func(); 30 | if(v.a != 1) 31 | return 1; 32 | if(v.b != 2) 33 | return 2; 34 | if(v.c != 3) 35 | return 3; 36 | if(v.d != 4) 37 | return 4; 38 | if(v.e != 5) 39 | return v.e; 40 | if(v.f != 6) 41 | return 6; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/execute/0015-calls12.c.disabled: -------------------------------------------------------------------------------- 1 | 2 | struct s1 { 3 | int a; 4 | int b; 5 | }; 6 | 7 | struct s2 { 8 | int a; 9 | int b; 10 | int c; 11 | int d; 12 | }; 13 | 14 | struct s3 { 15 | int a; 16 | int b; 17 | int c; 18 | int d; 19 | int e; 20 | int f; 21 | }; 22 | 23 | int 24 | func(struct s1 a, struct s2 b, struct s3 c, struct s1 d) 25 | { 26 | if(a.a != 1) 27 | return 1; 28 | if(a.b != 2) 29 | return 2; 30 | if(b.a != 3) 31 | return 3; 32 | if(b.b != 4) 33 | return 4; 34 | if(b.c != 5) 35 | return 5; 36 | if(b.d != 6) 37 | return 6; 38 | if(c.a != 7) 39 | return 7; 40 | if(c.b != 8) 41 | return 8; 42 | if(c.c != 9) 43 | return 9; 44 | if(c.d != 10) 45 | return 10; 46 | if(c.e != 11) 47 | return 11; 48 | if(c.f != 12) 49 | return 12; 50 | if(d.a != 13) 51 | return 13; 52 | if(d.b != 14) 53 | return 14; 54 | return 0; 55 | } 56 | 57 | int 58 | main() 59 | { 60 | struct s1 a; 61 | struct s2 b; 62 | struct s3 c; 63 | struct s1 d; 64 | 65 | a.a = 1; 66 | a.b = 2; 67 | b.a = 3; 68 | b.b = 4; 69 | b.c = 5; 70 | b.d = 6; 71 | c.a = 7; 72 | c.b = 8; 73 | c.c = 9; 74 | c.d = 10; 75 | c.e = 11; 76 | c.f = 12; 77 | d.a = 13; 78 | d.b = 14; 79 | return func(a, b, c, d); 80 | } 81 | -------------------------------------------------------------------------------- /test/execute/0015-calls13.c.disabled: -------------------------------------------------------------------------------- 1 | struct Empty {}; 2 | void abort(void); 3 | struct Empty 4 | f(struct Empty e1, int a, struct Empty e2, int b, struct Empty e3, int c, int d, int e, int f, int g) 5 | { 6 | if(a != 1) 7 | abort(); 8 | if(b != 2) 9 | abort(); 10 | if(c != 3) 11 | abort(); 12 | if(d != 4) 13 | abort(); 14 | if(e != 5) 15 | abort(); 16 | if(f != 6) 17 | abort(); 18 | if(g != 7) 19 | abort(); 20 | return e1; 21 | } 22 | 23 | int 24 | main() 25 | { 26 | struct Empty e; 27 | e = f(e, 1, e, 2, e, 3, 4, 5, 6, 7); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/execute/0016-string1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | char *p; 5 | 6 | p = "foobar"; 7 | if(p[1] != 111) 8 | return 1; 9 | if(p[6] != 0) 10 | return 1; 11 | return 0; 12 | } -------------------------------------------------------------------------------- /test/execute/0017-incdec1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 0; 7 | if(x++) 8 | return 1; 9 | if(x != 1) 10 | return 2; 11 | if(++x != 2) 12 | return 3; 13 | if(x != 2) 14 | return 4; 15 | if(--x != 1) 16 | return 5; 17 | if(x != 1) 18 | return 6; 19 | if(x-- != 1) 20 | return 7; 21 | if(x != 0) 22 | return 8; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/execute/0018-funcptr1.c: -------------------------------------------------------------------------------- 1 | 2 | int 3 | foo() 4 | { 5 | return 0; 6 | } 7 | 8 | int 9 | main() 10 | { 11 | int (*pf)(); 12 | 13 | pf = &foo; 14 | return pf(); 15 | } 16 | -------------------------------------------------------------------------------- /test/execute/0019-condexpr1.c: -------------------------------------------------------------------------------- 1 | int 2 | main() 3 | { 4 | int x; 5 | 6 | x = 0; 7 | x = x ? 0 : 2; 8 | if(x != 2) 9 | return 1; 10 | return x == 2 ? 0 : 1; 11 | } -------------------------------------------------------------------------------- /test/execute/0020-comma1.c: -------------------------------------------------------------------------------- 1 | int x; 2 | 3 | int 4 | foo() 5 | { 6 | x = x + 1; 7 | return 1; 8 | } 9 | 10 | int 11 | bar() 12 | { 13 | x = x + 2; 14 | return 2; 15 | } 16 | 17 | main() 18 | { 19 | int v; 20 | 21 | x = 0; 22 | v = foo(),bar(); 23 | if(v != 1) 24 | return 1; 25 | if(x != 3) 26 | return 2; 27 | return 0; 28 | } -------------------------------------------------------------------------------- /test/execute/0020-comma2.c: -------------------------------------------------------------------------------- 1 | int x; 2 | 3 | int 4 | foo() 5 | { 6 | x = x + 1; 7 | return 1; 8 | } 9 | 10 | int 11 | bar() 12 | { 13 | x = x + 2; 14 | return 2; 15 | } 16 | 17 | main() 18 | { 19 | int v; 20 | 21 | x = 0; 22 | v = (foo(),bar()); 23 | if(v != 2) 24 | return 1; 25 | if(x != 3) 26 | return 2; 27 | return 0; 28 | } -------------------------------------------------------------------------------- /test/execute/0021-tentativedefs1.c: -------------------------------------------------------------------------------- 1 | 2 | int x; 3 | int x = 0; 4 | int x; 5 | 6 | int main(); 7 | 8 | void * 9 | foo() 10 | { 11 | return &main; 12 | } 13 | 14 | int 15 | main() 16 | { 17 | x = 0; 18 | return x; 19 | } 20 | -------------------------------------------------------------------------------- /test/execute/0022-namespaces1.c: -------------------------------------------------------------------------------- 1 | typedef struct s s; 2 | 3 | struct s { 4 | struct s1 { 5 | int s; 6 | struct s2 { 7 | int s; 8 | } s1; 9 | } s; 10 | } s2; 11 | 12 | int 13 | main() 14 | { 15 | goto s; 16 | struct s s; 17 | { 18 | int s; 19 | return s; 20 | } 21 | return s.s.s + s.s.s1.s; 22 | s: 23 | return 0; 24 | } -------------------------------------------------------------------------------- /test/execute/0023-incomplete1.c: -------------------------------------------------------------------------------- 1 | struct X x; 2 | int foo(); 3 | 4 | int main() 5 | { 6 | return 0; 7 | } 8 | 9 | struct X {int v;}; 10 | 11 | int foo() 12 | { 13 | x.v = 0; 14 | return x.v; 15 | } -------------------------------------------------------------------------------- /test/execute/0024-enums1.c: -------------------------------------------------------------------------------- 1 | 2 | enum E { 3 | x, 4 | y = 2, 5 | z, 6 | }; 7 | 8 | int 9 | main() 10 | { 11 | enum E e; 12 | 13 | if(x != 0) 14 | return 1; 15 | if(y != 2) 16 | return 2; 17 | if(z != 3) 18 | return 3; 19 | 20 | e = x; 21 | return x; 22 | } 23 | -------------------------------------------------------------------------------- /test/execute/0025-duff.c: -------------------------------------------------------------------------------- 1 | /* Disgusting, no? But it compiles and runs just fine. I feel a combination of 2 | pride and revulsion at this discovery. If no one's thought of it before, 3 | I think I'll name it after myself. 4 | 5 | It amazes me that after 10 years of writing C there are still 6 | little corners that I haven't explored fully. 7 | 8 | - Tom Duff */ 9 | 10 | int main() 11 | { 12 | int count, n; 13 | char *from, *to; 14 | char a[39], b[39]; 15 | 16 | for(n = 0; n < 39; n++) { 17 | a[n] = n; 18 | b[n] = 0; 19 | } 20 | from = a; 21 | to = b; 22 | count = 39; 23 | n = (count + 7) / 8; 24 | switch (count % 8) { 25 | case 0: do { *to++ = *from++; 26 | case 7: *to++ = *from++; 27 | case 6: *to++ = *from++; 28 | case 5: *to++ = *from++; 29 | case 4: *to++ = *from++; 30 | case 3: *to++ = *from++; 31 | case 2: *to++ = *from++; 32 | case 1: *to++ = *from++; 33 | } while (--n > 0); 34 | } 35 | for(n = 0; n < 39; n++) 36 | if(a[n] != b[n]) 37 | return 1; 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/execute/0026-sizeof1.c: -------------------------------------------------------------------------------- 1 | 2 | int main() 3 | { 4 | if(sizeof(0) != 4) 5 | return 1; 6 | if(sizeof(char) != 1) 7 | return 2; 8 | if(sizeof(int) != 4) 9 | return 3; 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /test/execute/0027-structcopy.c: -------------------------------------------------------------------------------- 1 | 2 | struct Foo { 3 | int a; 4 | int b; 5 | }; 6 | 7 | int 8 | main() 9 | { 10 | struct Foo v1, v2; 11 | 12 | v1.a = 1; 13 | v1.b = 6; 14 | v2 = v1; 15 | if(v2.a != 1) 16 | return 1; 17 | if(v2.b != 6) 18 | return 2; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/execute/0028-inits01.c: -------------------------------------------------------------------------------- 1 | 2 | int x = 5; 3 | 4 | int 5 | main() 6 | { 7 | if(x != 5) 8 | return 1; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test/execute/0028-inits02.c: -------------------------------------------------------------------------------- 1 | 2 | int x[3] = {1, 2, 3}; 3 | 4 | int 5 | main() 6 | { 7 | if(x[0] != 1) 8 | return 1; 9 | if(x[1] != 2) 10 | return 2; 11 | if(x[2] != 3) 12 | return 3; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/execute/0028-inits03.c: -------------------------------------------------------------------------------- 1 | 2 | struct S { 3 | int a; 4 | int b; 5 | int c; 6 | }; 7 | 8 | struct S x = {1, 2, 3}; 9 | 10 | int 11 | main() 12 | { 13 | if(x.a != 1) 14 | return 1; 15 | if(x.b != 2) 16 | return 2; 17 | if(x.c != 3) 18 | return 3; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/execute/0028-inits04.c: -------------------------------------------------------------------------------- 1 | 2 | struct S { 3 | int a; 4 | int b; 5 | }; 6 | 7 | struct S x[1] = {{1, 2}}; 8 | 9 | int 10 | main() 11 | { 12 | if(x[0].a != 1) 13 | return 1; 14 | if(x[0].b != 2) 15 | return 2; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/execute/0028-inits05.c: -------------------------------------------------------------------------------- 1 | 2 | int x = 5; 3 | int *p = &x; 4 | 5 | int 6 | main() 7 | { 8 | if(*p != 5) 9 | return 1; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/execute/0028-inits06.c: -------------------------------------------------------------------------------- 1 | 2 | struct S { int a; int b; }; 3 | struct S s = (struct S){1, 2}; 4 | 5 | int 6 | main() 7 | { 8 | if(s.a != 1) 9 | return 1; 10 | if(s.b != 2) 11 | return 2; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/execute/0028-inits07.c: -------------------------------------------------------------------------------- 1 | 2 | int arr[3] = {[2] = 2, [0] = 0, [1] = 1}; 3 | 4 | int 5 | main() 6 | { 7 | if(arr[0] != 0) 8 | return 1; 9 | if(arr[1] != 1) 10 | return 2; 11 | if(arr[2] != 2) 12 | return 3; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/execute/0028-inits08.c: -------------------------------------------------------------------------------- 1 | 2 | struct S {int a; int b;}; 3 | struct S arr[2] = {[1] = {3, 4}, [0] = {1, 2}}; 4 | 5 | int 6 | main() 7 | { 8 | if(arr[0].a != 1) 9 | return 1; 10 | if(arr[0].b != 2) 11 | return 2; 12 | if(arr[1].a != 3) 13 | return 3; 14 | if(arr[1].b != 4) 15 | return 4; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/execute/0028-inits09.c: -------------------------------------------------------------------------------- 1 | 2 | struct S {int a; int b;}; 3 | struct S s = { .b = 2, .a = 1}; 4 | 5 | int 6 | main() 7 | { 8 | if(s.a != 1) 9 | return 1; 10 | if(s.b != 2) 11 | return 2; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/execute/0028-inits10.c: -------------------------------------------------------------------------------- 1 | 2 | struct S { int a; int b; }; 3 | struct S *s = &(struct S) { 1, 2 }; 4 | 5 | int 6 | main() 7 | { 8 | if(s->a != 1) 9 | return 1; 10 | if(s->b != 2) 11 | return 2; 12 | return 0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /test/execute/0028-inits11.c: -------------------------------------------------------------------------------- 1 | 2 | struct S1 { 3 | int a; 4 | int b; 5 | }; 6 | struct S2 { 7 | struct S1 s1; 8 | struct S1 *ps1; 9 | int arr[2]; 10 | }; 11 | struct S1 gs1 = (struct S1) {.a = 1, 2}; 12 | struct S2 *s = &(struct S2) { 13 | {.b = 2, .a = 1}, 14 | &gs1, 15 | {[0] = 1, 1+1} 16 | }; 17 | 18 | int 19 | main() 20 | { 21 | if(s->s1.a != 1) 22 | return 1; 23 | if(s->s1.b != 2) 24 | return 2; 25 | if(s->ps1->a != 1) 26 | return 3; 27 | if(s->ps1->b != 2) 28 | return 4; 29 | if(s->arr[0] != 1) 30 | return 5; 31 | if(s->arr[1] != 2) 32 | return 6; 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /test/execute/0028-inits12.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | union U { 4 | int a; 5 | struct { 6 | int b; 7 | int c; 8 | }; 9 | int d; 10 | }; 11 | 12 | union U u = {.b = 1, 2}; 13 | 14 | int 15 | main() 16 | { 17 | if(u.a != 1) 18 | return 1; 19 | if(u.b != 1) 20 | return 2; 21 | if(u.c != 2) 22 | return 3; 23 | if(u.d != 1) 24 | return 4; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/execute/0028-inits13.c: -------------------------------------------------------------------------------- 1 | 2 | struct S { 3 | int a; 4 | struct { 5 | int b; 6 | int c; 7 | }; 8 | int d; 9 | }; 10 | 11 | struct S s = {.a = 1, 2, .c = 3, 4}; 12 | 13 | int 14 | main() 15 | { 16 | if(s.a != 1) 17 | return 1; 18 | if(s.b != 2) 19 | return 2; 20 | if(s.c != 3) 21 | return 3; 22 | if(s.d != 4) 23 | return 4; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/execute/0028-inits14.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | struct S { 4 | int a; 5 | union { 6 | struct { 7 | struct { 8 | int b; 9 | int c; 10 | }; 11 | }; 12 | }; 13 | int d; 14 | }; 15 | 16 | struct S s = {.a = 1, 2, .c = 3, 4}; 17 | 18 | int 19 | main() 20 | { 21 | if(s.a != 1) 22 | return 1; 23 | if(s.b != 2) 24 | return 2; 25 | if(s.c != 3) 26 | return 3; 27 | if(s.d != 4) 28 | return 4; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /test/execute/0028-inits15.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | struct S { 4 | int a; 5 | struct { 6 | int b; 7 | int c; 8 | struct { 9 | int d; 10 | struct { 11 | int e; 12 | }; 13 | }; 14 | struct { 15 | int x; 16 | struct { 17 | int y; 18 | }; 19 | } f; 20 | int g; 21 | }; 22 | }; 23 | struct S s = {1, 2, 3, 4, 5, {6, 7}, 8}; 24 | 25 | int 26 | main() 27 | { 28 | if(s.a != 1) 29 | return 1; 30 | if(s.b != 2) 31 | return 2; 32 | if(s.c != 3) 33 | return 3; 34 | if(s.d != 4) 35 | return 4; 36 | if(s.e != 5) 37 | return 5; 38 | if(s.f.x != 6) 39 | return 6; 40 | if(s.f.y != 7) 41 | return 7; 42 | if(s.g != 8) 43 | return 8; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/execute/0029-ptrarith1.c: -------------------------------------------------------------------------------- 1 | 2 | int main() 3 | { 4 | char *a, *b; 5 | 6 | a = "abcdef"; 7 | if(*(a + 2) != 'c') 8 | return 1; 9 | if(*(2 + a) != 'c') 10 | return 2; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/execute/0029-ptrarith2.c: -------------------------------------------------------------------------------- 1 | 2 | int x[] = {1, 2, 3}; 3 | 4 | int 5 | main() 6 | { 7 | int *p; 8 | 9 | p = &x[0]; 10 | if(*(p + 1) != 2) 11 | return 1; 12 | if(*(2 + p) != 3) 13 | return 1; 14 | return 0; 15 | } 16 | 17 | --------------------------------------------------------------------------------