compiler.c (183584B)
1 #include <assert.h> 2 #include <ctype.h> 3 #include <stdarg.h> 4 #include <stdio.h> 5 #include <stdint.h> 6 #include <stdlib.h> 7 #include <stdbool.h> 8 #include <string.h> 9 10 /* @note redeinition of assert() for ease of debugging. */ 11 12 #if 0 13 #ifdef assert 14 #undef assert 15 #endif 16 static void 17 myassert(const char *expr, const char *file, int line) 18 { 19 _assert(expr, file, line); 20 } 21 22 #define assert(_Expression) (void) ( \ 23 (!!(_Expression)) || (myassert(#_Expression,__FILE__,__LINE__),0) \ 24 ) 25 #endif 26 27 // @section forward declarations {{{ 28 29 typedef unsigned char uchar; 30 typedef unsigned int uint; 31 32 typedef 33 struct Source Source; 34 35 typedef 36 struct Compiler Compiler; 37 38 typedef 39 struct Node Node; 40 41 typedef 42 struct Type Type; 43 44 typedef 45 struct Decl Decl; 46 47 typedef 48 struct Env Env; 49 50 typedef 51 struct AnnotParam AnnotParam; 52 53 typedef 54 struct Annot Annot; 55 56 typedef 57 struct Docket Docket; 58 59 typedef 60 struct Gist Gist; 61 62 typedef 63 struct Conduct Conduct; 64 65 typedef 66 struct Block Block; 67 68 69 70 // }}} 71 72 // @section node kind table {{{ 73 74 #define SENDOFFILE "end-of-file" 75 #define SINVALID "invalide token" 76 #define SLINEDELIM "line-delimiter" 77 78 #define SCHAR "character-literal" 79 #define SIDENT "identifier" 80 #define SNUMBER "number-literal" 81 #define SSTRING "string-literal" 82 83 #define SASTMT "statement" 84 #define SALOOPUNTIL "loop-until-clause" 85 #define SADECL "declaration" 86 #define SADECLREF "symbol-reference" 87 #define SASWITCH "case-clause" 88 #define SACASE "of-clause" 89 #define SACONV "conversion" 90 91 #define NODETAB \ 92 /* tag , string , childs , flags , prec */ \ 93 /* Basic */ \ 94 entry(ENDOFFILE , SENDOFFILE , 0 , 0 , 0) \ 95 entry(INVALID , SINVALID , 0 , 0 , 0) \ 96 entry(LINEDELIM , SLINEDELIM , 0 , 0 , 0) \ 97 entry(SEMIDELIM , ";" , 0 , 0 , 0) \ 98 entry(COMMADELIM , "," , 0 , 0 , 0) \ 99 entry(COLONDELIM , ":" , 0 , 0 , 0) \ 100 entry(LCURLDELIM , "{" , 0 , 0 , 0) \ 101 entry(LSQRDELIM , "[" , 0 , 0 , 0) \ 102 entry(LPARDELIM , "(" , 0 , 0 , 0) \ 103 entry(RCURLDELIM , "}" , 0 , 0 , 0) \ 104 entry(RSQRDELIM , "]" , 0 , 0 , 0) \ 105 entry(RPARDELIM , ")" , 0 , 0 , 0) \ 106 entry(ANNOT , "@" , 0 , 0 , 0) \ 107 entry(CHAR , SCHAR , 0 , 0 , 0) \ 108 entry(IDENT , SIDENT , 0 , 0 , 0) \ 109 entry(NUMBER , SNUMBER , 0 , 0 , 0) \ 110 entry(STRING , SSTRING , 0 , 0 , 0) \ 111 entry(TYPE , "type" , 0 , 0 , 0) \ 112 /* Keywords */ \ 113 entry(KVOID , "void" , 0 , 0 , 0) \ 114 entry(KBOOL , "bool" , 0 , 0 , 0) \ 115 entry(KU8 , "u8" , 0 , 0 , 0) \ 116 entry(KS8 , "s8" , 0 , 0 , 0) \ 117 entry(KU16 , "u16" , 0 , 0 , 0) \ 118 entry(KS16 , "s16" , 0 , 0 , 0) \ 119 entry(KU32 , "u32" , 0 , 0 , 0) \ 120 entry(KS32 , "s32" , 0 , 0 , 0) \ 121 entry(KU64 , "u64" , 0 , 0 , 0) \ 122 entry(KS64 , "s64" , 0 , 0 , 0) \ 123 entry(KF32 , "f32" , 0 , 0 , 0) \ 124 entry(KF64 , "f64" , 0 , 0 , 0) \ 125 entry(KUCHAR , "uchar" , 0 , 0 , 0) \ 126 entry(KCHAR , "char" , 0 , 0 , 0) \ 127 entry(KUSHORT , "ushort" , 0 , 0 , 0) \ 128 entry(KSHORT , "short" , 0 , 0 , 0) \ 129 entry(KUINT , "uint" , 0 , 0 , 0) \ 130 entry(KINT , "int" , 0 , 0 , 0) \ 131 entry(KULONG , "ulong" , 0 , 0 , 0) \ 132 entry(KLONG , "long" , 0 , 0 , 0) \ 133 entry(KULLONG , "ullong" , 0 , 0 , 0) \ 134 entry(KLLONG , "llong" , 0 , 0 , 0) \ 135 entry(KFLOAT , "float" , 0 , 0 , 0) \ 136 entry(KDOUBLE , "double" , 0 , 0 , 0) \ 137 entry(KLDOUBLE , "ldouble" , 0 , 0 , 0) \ 138 entry(KUSIZE , "usize" , 0 , 0 , 0) \ 139 entry(KSSIZE , "ssize" , 0 , 0 , 0) \ 140 entry(KFALSE , "false" , 0 , 0 , 0) \ 141 entry(KTRUE , "true" , 0 , 0 , 0) \ 142 entry(KNULL , "null" , 0 , 0 , 0) \ 143 entry(KUSE , "use" , 0 , 0 , 0) \ 144 entry(KBUNDLE , "bundle" , 0 , 0 , 0) \ 145 entry(KNOT , "not" , 0 , 0 , 0) \ 146 entry(KAND , "and" , 0 , 0 , 0) \ 147 entry(KOR , "or" , 0 , 0 , 0) \ 148 entry(KIS , "is" , 0 , 0 , 0) \ 149 entry(KSIZEOF , "sizeof" , 0 , 0 , 0) \ 150 entry(KALIGNOF , "alignof" , 0 , 0 , 0) \ 151 entry(KLENGTHOF , "lengthof" , 0 , 0 , 0) \ 152 entry(KBITCAST , "bitcast" , 0 , 0 , 0) \ 153 entry(KEXTERN , "extern" , 0 , 0 , 0) \ 154 entry(KINTERN , "intern" , 0 , 0 , 0) \ 155 entry(KSTATIC , "static" , 0 , 0 , 0) \ 156 entry(KCONST , "const" , 0 , 0 , 0) \ 157 entry(KVAR , "var" , 0 , 0 , 0) \ 158 entry(KBREAK , "break" , 0 , 0 , 0) \ 159 entry(KCONTINUE , "continue" , 0 , 0 , 0) \ 160 entry(KGOTO , "goto" , 0 , 0 , 0) \ 161 entry(KRETURN , "return" , 0 , 0 , 0) \ 162 entry(KIF , "if" , 0 , 0 , 0) \ 163 entry(KELSE , "else" , 0 , 0 , 0) \ 164 entry(KCASE , "case" , 0 , 0 , 0) \ 165 entry(KOF , "of" , 0 , 0 , 0) \ 166 entry(KDO , "do" , 0 , 0 , 0) \ 167 entry(KFOR , "for" , 0 , 0 , 0) \ 168 entry(KLOOP , "loop" , 0 , 0 , 0) \ 169 entry(KWHILE , "while" , 0 , 0 , 0) \ 170 entry(KUNTIL , "until" , 0 , 0 , 0) \ 171 entry(KSTRUCT , "struct" , 0 , 0 , 0) \ 172 entry(KUNION , "union" , 0 , 0 , 0) \ 173 /* Operators */ \ 174 entry(OSUFINC , "++" , 1 , FRASSOC , PUNSUF ) \ 175 entry(OSUFDEC , "--" , 1 , FRASSOC , PUNSUF ) \ 176 entry(OARRAY , "[]" , 1 , FRASSOC , PUNSUF ) \ 177 entry(OCALL , "()" , 1 , FRASSOC , PUNSUF ) \ 178 entry(ODISP , "." , 1 , FRASSOC , PUNSUF ) \ 179 entry(ODEREF , "*" , 1 , 0 , PUNARY ) \ 180 entry(OINC , "++" , 1 , 0 , PUNARY ) \ 181 entry(ODEC , "--" , 1 , 0 , PUNARY ) \ 182 entry(OBNOT , "~" , 1 , 0 , PUNARY ) \ 183 entry(OLNOT , "!" , 1 , 0 , PUNARY ) \ 184 entry(OFLIP , "!>" , 1 , 0 , PUNARY ) \ 185 entry(OADDR , "&" , 1 , 0 , PUNARY ) \ 186 entry(OPLUS , "+" , 1 , 0 , PUNARY ) \ 187 entry(OMINUS , "-" , 1 , 0 , PUNARY ) \ 188 entry(OCAST , "(type)" , 1 , 0 , PUNARY ) \ 189 entry(OMUL , "*" , 2 , 0 , PMUL ) \ 190 entry(ODIV , "/" , 2 , 0 , PMUL ) \ 191 entry(OMOD , "%" , 2 , 0 , PMUL ) \ 192 entry(OLSH , "<<" , 2 , 0 , PMUL ) \ 193 entry(OARSH , ">>>" , 2 , 0 , PMUL ) \ 194 entry(ORSH , ">>" , 2 , 0 , PMUL ) \ 195 entry(OBAND , "&" , 2 , 0 , PMUL ) \ 196 entry(OADD , "+" , 2 , 0 , PADD ) \ 197 entry(OSUB , "-" , 2 , 0 , PADD ) \ 198 entry(OBOR , "|" , 2 , 0 , PADD ) \ 199 entry(OXOR , "^" , 2 , 0 , PADD ) \ 200 entry(ORANGE , ".." , 2 , 0 , PRANGE ) \ 201 entry(OLEQ , "<=" , 2 , 0 , PRELAT ) \ 202 entry(OLET , "<" , 2 , 0 , PRELAT ) \ 203 entry(OGEQ , ">=" , 2 , 0 , PRELAT ) \ 204 entry(OGRT , ">" , 2 , 0 , PRELAT ) \ 205 entry(ONEQ , "!=" , 2 , 0 , PRELAT ) \ 206 entry(OEQU , "==" , 2 , 0 , PRELAT ) \ 207 entry(OIDENT , "===" , 2 , 0 , PRELAT ) \ 208 entry(OLAND , "&&" , 2 , 0 , PAND ) \ 209 entry(OLOR , "||" , 2 , 0 , POR ) \ 210 entry(OASS , "=" , 2 , FRASSOC , PASSIGN ) \ 211 entry(OMULA , "*=" , 2 , FRASSOC , PASSIGN ) \ 212 entry(ODIVA , "/=" , 2 , FRASSOC , PASSIGN ) \ 213 entry(OMODA , "%=" , 2 , FRASSOC , PASSIGN ) \ 214 entry(OLSHA , "<<=" , 2 , FRASSOC , PASSIGN ) \ 215 entry(OARSHA , ">>>=" , 2 , FRASSOC , PASSIGN ) \ 216 entry(ORSHA , ">>=" , 2 , FRASSOC , PASSIGN ) \ 217 entry(OANDA , "&=" , 2 , FRASSOC , PASSIGN ) \ 218 entry(OADDA , "+=" , 2 , FRASSOC , PASSIGN ) \ 219 entry(OSUBA , "-=" , 2 , FRASSOC , PASSIGN ) \ 220 entry(OORA , "|=" , 2 , FRASSOC , PASSIGN ) \ 221 entry(OXORA , "^=" , 2 , FRASSOC , PASSIGN ) \ 222 /* Ast */ \ 223 entry(ACOMMA , "," , 0 , 0 , 0) \ 224 entry(ASTMT , SASTMT , 0 , 0 , 0) \ 225 entry(ADECL , SADECL , 0 , 0 , 0) \ 226 entry(ADECLREF , SADECLREF , 0 , 0 , 0) \ 227 entry(AENV , "env" , 0 , 0 , 0) \ 228 entry(ALOOPUNTIL , SALOOPUNTIL , 0 , 0 , 0) \ 229 entry(AFOREACH , "for-each" , 0 , 0 , 0) \ 230 entry(AFORSTEP , "for-step" , 0 , 0 , 0) \ 231 entry(ASCOPE , "scope" , 0 , 0 , 0) \ 232 entry(ALABEL , "label" , 0 , 0 , 0) \ 233 entry(ASWITCH , SASWITCH , 0 , 0 , 0) \ 234 entry(ACASE , SACASE , 0 , 0 , 0) \ 235 entry(ACONV , SACONV , 0 , 0 , 0) \ 236 entry(ADEREF , "*" , 0 , 0 , 0) \ 237 entry(AADDR , "&" , 0 , 0 , 0) \ 238 entry(ACOMPOUND , "{...}" , 0 , 0 , 0) \ 239 entry(AFIELDINIT , ":" , 0 , 0 , 0) \ 240 entry(ASELFDISP , ":" , 0 , 0 , 0) \ 241 /* endof NODETAB */ 242 243 #define isbinaryop(kind) ((kind) >= OMUL && (kind) < ACOMMA) 244 245 246 247 // }}} 248 249 // @section type kind table {{{ 250 251 #define TYPETAB \ 252 /* tag , size , align*/ \ 253 entry(TNONE , 0 , 0) \ 254 entry(TERRTYPE , 0 , 0) \ 255 entry(TUNDEFINED , 0 , 0) \ 256 entry(TVOID , 0 , 0) \ 257 entry(TBOOL , 1 , 1) \ 258 entry(TINFER , 4 , 4) \ 259 entry(TUINFER , 4 , 4) \ 260 entry(TS8 , 1 , 1) \ 261 entry(TU8 , 1 , 1) \ 262 entry(TS16 , 2 , 2) \ 263 entry(TU16 , 2 , 2) \ 264 entry(TS32 , 4 , 4) \ 265 entry(TU32 , 4 , 4) \ 266 entry(TS64 , 8 , 8) \ 267 entry(TU64 , 8 , 8) \ 268 entry(TF32 , 4 , 4) \ 269 entry(TF64 , 8 , 8) \ 270 entry(TPTR , 8 , 8) \ 271 entry(TARRAY , 0 , 0) \ 272 entry(TTUPLE , 0 , 0) \ 273 entry(TFUNCTION , 0 , 0) \ 274 entry(TSTRUCT , 0 , 0) \ 275 entry(TUNION , 0 , 0) \ 276 /* endof TYPETAB */ 277 278 #define TCHAR TS8 279 #define TUCHAR TU8 280 #define TSHORT TS16 281 #define TUSHORT TU16 282 #define TINT TS32 283 #define TUINT TU32 284 #define TLONG TS64 285 #define TULONG TU64 286 #define TLLONG TS64 287 #define TULLONG TU64 288 289 #define TFLOAT TF32 290 #define TDOUBLE TF64 291 #define TLDOUBLE TF64 292 293 #define TSSIZE TS64 294 #define TUSIZE TU64 295 /* @todo maybe add long double type ? */ 296 297 #define TYPEKEWORDYTAB \ 298 entry(VOID) entry(BOOL) \ 299 entry(S8) entry(U8) \ 300 entry(S16) entry(U16) \ 301 entry(S32) entry(U32) \ 302 entry(S64) entry(U64) \ 303 entry(F32) entry(F64) \ 304 entry(CHAR) entry(UCHAR) \ 305 entry(SHORT) entry(USHORT) \ 306 entry(INT) entry(UINT) \ 307 entry(LONG) entry(ULONG) \ 308 entry(LLONG) entry(ULLONG) \ 309 entry(FLOAT) entry(DOUBLE) entry(LDOUBLE) \ 310 entry(SSIZE) entry(USIZE) \ 311 /* endof TYPEKEYWORDTAB */ 312 313 314 315 // }}} 316 317 // @section enumerations & constants {{{ 318 319 typedef 320 enum Flags { 321 FRASSOC = 1 322 } Flads; 323 324 typedef 325 enum Precedence { 326 PUNSUF = 10, 327 PUNARY = 9, 328 PMUL = 8, 329 PADD = 7, 330 PRANGE = 6, 331 PRELAT = 5, 332 PAND = 4, 333 POR = 3, 334 PASSIGN = 2, 335 336 PSTART = 1 337 } Precedence; 338 339 typedef 340 enum Kind { 341 #define entry(tag, string, childs, flags, prec) \ 342 tag, 343 NODETAB 344 #undef entry 345 346 MAXKINDS 347 } Kind; 348 349 #define KSTART KVOID 350 #define OSTART OSUFINC 351 #define ASTART ASTMT 352 353 #define iskeyword(kind) ((kind) >= KSTART && (kind) < OSTART) 354 #define isoperator(kind) ((kind) >= OSTART && (kind) < ASTART) 355 #define isastnode(kind) ((kind) >= ASTART && (kind) < MAXKINDS) 356 357 static bool 358 isatomnode(Kind kind) 359 { 360 return kind == IDENT || kind == ADECLREF || kind == NUMBER || 361 kind == STRING || kind == CHAR; 362 } 363 364 365 typedef 366 enum TypeKind { 367 #define entry(tag, size, align) \ 368 tag, 369 TYPETAB 370 #undef entry 371 372 TMAX 373 } TypeKind; 374 375 376 typedef 377 enum DeclKind { 378 DMODULE = 0, 379 DTYPE, /* @note maybe be the same as void-module ? */ 380 DVAR, 381 DPARAM, 382 DFUNCTION, 383 DFIELDALIAS, 384 DBUNDLE, 385 /* 386 DMACRO, 387 DENFOLD 388 */ 389 } DeclKind; 390 391 typedef 392 enum DeclFlags { 393 MSPECIAL = 0x0001, 394 MRECORDMEMBER = 0x0002, 395 /* MINPORT = 0x0004, ... */ 396 } DeclFlags; 397 398 typedef 399 enum EnvKind { 400 STOPLEVEL = 0, 401 SPARAMLIST, 402 SFUNCTION, 403 SSCOPE, 404 SIFHEADER, 405 SLOOPHEADER, 406 SDO, 407 SLOOP, 408 SWHILE, 409 SIF, 410 SELSE, 411 SSTRUCT, 412 SUNION 413 /* 414 SUNION, 415 SSTRUCT, 416 SENUM, 417 */ 418 } EnvKind; 419 420 typedef 421 enum Qualifier { 422 QINTERN = 0x0001, 423 QEXTERN = 0x0002, 424 425 QSTATIC = 0x0010, 426 427 QCONST = 0x0200, 428 429 QVAR = 0x1000, 430 431 /* masks */ 432 QALL = QINTERN | QEXTERN | QSTATIC | QCONST | QVAR, 433 QVISIB = QEXTERN | QINTERN, 434 QSTORAGE = QSTATIC, 435 QTYPE = QCONST, 436 QINFER = QVAR 437 } Qualifier; 438 439 typedef 440 enum AnnotParamKind { 441 NSTATEEXPR, 442 NPARAM, 443 NEXPR 444 } AnnotParamKind; 445 446 typedef 447 enum BlockKind { 448 BTOPLEVEL = 0, 449 BFUNCTION = 1, 450 BSCOPE = 2, 451 BIF = 3, 452 BLOOP = 4, 453 BWHILELOOP = 5, 454 BLOOPUNTIL = 6, 455 BFORLOOP = 7, 456 BELSE = 8 457 } BlockKind; 458 459 typedef 460 enum ConductKind { 461 CUNREACH = 0, /* alway after a break, continue, goto or return */ 462 CSCOPE = 1, /* only the first conduct of a block and conducts after 463 * cunducts containing blocks are of this kind */ 464 CBLOCK = 2, /* always containing one or more blocks and nothing 465 else */ 466 CLABEL = 3 /* always after a label */ 467 } ConductKind; 468 469 470 471 // }}} 472 473 // @section type definitions {{{ 474 475 #define ARENA_PAGE_SIZE 512 476 477 typedef 478 struct MemArena { 479 uint8_t **pages; 480 size_t capacity, top; 481 size_t elemsize; 482 } MemArena; 483 484 typedef 485 struct SourceArenas { 486 MemArena node, type, env, decl; 487 MemArena annot, docket; 488 MemArena record, field; 489 MemArena block, conduct, gist; 490 } SourceArenas; 491 492 typedef 493 struct SrcLoc { 494 uint line, column; 495 const char *filename; 496 } SrcLoc; 497 498 /** 499 * @brief A node in the abstract syntax tree. 500 * @details The location is used to report errors. The type is used to store the 501 * type of the node. The union u is used to store the value of the node 502 * for its given kind. The lhs pointer points to the left hand side of 503 * its child node and the rhs pointer points to the right hand side of 504 * its child node (if any). Or the lhs and rhs pointer are used to 505 * point to the previous and next statement in a linked list (in case 506 * of ASTMT). Additionally, the payload pointer is used to store the 507 * condition of an if-statement and other statements. 508 */ 509 struct Node { 510 Kind kind; 511 SrcLoc loc; 512 513 Type *type; 514 515 union { 516 int key; 517 518 double d; 519 uintmax_t u; 520 intmax_t s; 521 522 Node *payload; 523 Decl *declref; 524 Env *env; 525 } u; 526 527 Node *lhs, *rhs; 528 /* ASTMT: rhs points to next stmt (linked list) */ 529 }; 530 531 struct Type { 532 TypeKind kind; 533 SrcLoc loc; 534 535 Type *target; /* pointer, array, tuple-lht, function param-list, ... */ 536 537 size_t size, align; 538 539 union { 540 struct { 541 int offset, size; /* in bits */ 542 } bit; 543 544 struct { 545 size_t length; 546 size_t elemsize; 547 } array; 548 549 Node *val; 550 Type *rtarget; /* for tuples (rht) and function return-type */ 551 } u; 552 553 Decl *module; /* module and record info */ 554 }; 555 556 typedef struct Field Field; 557 558 typedef struct Record { 559 Field *head, *tail; 560 561 bool isunion; 562 } Record; 563 564 struct Field { 565 Decl *decl; 566 567 size_t offset, size; /* in bytes */ 568 569 bool use; 570 571 Field *prev, *next; 572 }; 573 574 struct Decl { 575 DeclKind kind; 576 SrcLoc loc; 577 578 Type *type; 579 Decl *module; /* module or bundle */ 580 Record *record; 581 582 int key; 583 DeclFlags flags; 584 585 Env *parentenv, *contentenv; 586 union { 587 Node *content; /* init or function body */ 588 589 bool usefield; 590 } u; 591 592 Decl *prev, *next; 593 }; 594 595 struct Env { 596 EnvKind kind; 597 SrcLoc loc; 598 599 uint8_t keycache[64]; 600 601 Decl *head, *tail; 602 603 Node *stmts; 604 Decl *envdecl; /* for SFUNCTION, SSTRUCT, SUNION */ 605 606 /* for toplevel declarations. it will be assigned to decl->module 607 * if decl->module is null (in declaration()). */ 608 Decl *bundle; 609 610 Env *below; 611 612 bool pending; 613 Env *pendingnext, *pendingprev; 614 615 /* carry on source for memory management*/ 616 SourceArenas *arenas; 617 }; 618 619 struct Source { 620 SrcLoc currloc; 621 622 /* pre-lexer state */ 623 624 char line[4096]; 625 long linepos; 626 627 bool hasnewline; 628 bool handlereplprompt; 629 630 /* error-reporting and lexer state */ 631 632 FILE *filein; 633 int tabwidth; 634 char stringbuf[1024]; 635 636 int lastindent, lastkind; 637 Node tok, savedtok; 638 639 /* environment */ 640 641 Env *headenv, *currenv; 642 Env *pendingenvhead, *pendingenvtail; 643 644 Env *implicitenv; 645 646 bool haspendingenv; 647 648 /* pending nodes */ 649 Node *pendingnodes[512]; 650 int pendingcount; 651 652 /* parser state */ 653 Node *lastis; 654 655 /* import use */ 656 Source *parent; 657 Source *head, *tail; 658 Source *prev, *next; 659 Compiler *compiler; 660 661 /* stack-alloc save state */ 662 SourceArenas arenas; 663 }; 664 665 struct AnnotParam { 666 AnnotParamKind kind; 667 668 int key; 669 670 Node *node; 671 672 AnnotParam *prev, *next; 673 }; 674 675 struct Annot { 676 int key; 677 SrcLoc loc; 678 679 AnnotParam *head, *tail; 680 681 Annot *prev, *next; 682 }; 683 684 struct Docket { 685 Node *node; 686 Decl *decl; 687 688 Annot *head, *tail; 689 }; 690 691 struct Gist { 692 Decl *decl; 693 Conduct *parent; 694 695 bool init; 696 Node *where; 697 698 /* for other declarations */ 699 Gist *prev, *next; 700 }; 701 702 struct Block { 703 BlockKind kind; 704 705 Env *env; 706 707 /* Conduct-Sequence list*/ 708 Conduct *head, *tail, *parent; 709 710 /* Neighbooring Blocks */ 711 Block *prev, *next; 712 }; 713 714 struct Conduct { 715 ConductKind kind; 716 uint id; 717 718 Node *label, *branch; 719 Node *first, *last; 720 721 bool doesbreak; 722 bool doescontinue; 723 bool doesreturn; 724 bool doesjump; 725 726 struct ConductGists { 727 Gist *head, *tail; 728 } gists; 729 730 struct ConductBranches { 731 /* Branch-relation from child to parents */ 732 Conduct *head, *tail; 733 734 /* Branch-parent list */ 735 Conduct *next, *prev; 736 } branches; 737 738 /* Block-stack */ 739 Block *head, *tail, *parent; 740 741 /* Conduct-sequence list */ 742 Conduct *next, *prev; 743 }; 744 745 typedef struct Section Section; 746 typedef struct Edge Edge; 747 typedef struct EdgeEntry EdgeEntry; 748 typedef struct Analysis Analysis; 749 750 typedef enum EdgeKind { 751 JBRANCH = 0, /* unconditional branch */ 752 JIFBRANCH = 1, /* conditional branch */ 753 JNEXT = 2, /* unconditional next section (without branch) */ 754 JIFNEXT = 3 /* conditional next section (without branch) */ 755 } EdgeKind; 756 757 struct Edge { 758 EdgeKind kind; 759 Section *section; 760 761 Conduct *gistlist; /* @note maybe remove this, since the gistlist 762 * is always the last of a section */ 763 764 /* @todo add information about the branch/edge condition */ 765 766 /* for memory-management, since an edge is used in mult. edge-entries */ 767 int refcount; 768 }; 769 770 typedef enum EdgeEntryKind { 771 JINGOING = 0, /* added as reachedfrom to section */ 772 JOUTGOING = 1, /* added as branchto to section */ 773 JSTART = 2, /* added as reachedfrom edge entry to first section */ 774 JEND = 3 /* added as branchto edge entry to last section */ 775 } EdgeEntryKind; 776 777 /* @note since an edge is used in multiple lists, edge-entry is used 778 * as linked-list entry */ 779 struct EdgeEntry { 780 EdgeEntryKind kind; 781 Section *belongsto; 782 783 Edge *edge; /* is NULL on JSTART or JEND */ 784 EdgeEntry *prev, *next; 785 }; 786 787 /* a section is single level. there is no hierarchy, like in the case of 788 * scopes/environments. a function has simply a list of section from top to 789 * bottom. */ 790 struct Section { 791 uint id; /* incremental number */ 792 793 /* a section begins after baranch/label/start and ends 794 * containing a terminating branch/label/end. this way it contains at 795 * least one instructin/statement (terminating branch/label), if the 796 * (terminating branch/label/end) is not augment at the end of the 797 * function-scope/clause. */ 798 Node *first, *last; 799 800 struct { 801 Conduct *head, *tail; 802 } gistlists; 803 804 struct { 805 EdgeEntry *head, *tail; 806 } reachedfrom; 807 808 struct { 809 EdgeEntry *head, *tail; 810 } branchto; 811 812 /* prev/next section in code (no branch-info) from top to bottom 813 * in function */ 814 Section *prev, *next; 815 }; 816 817 struct Analysis { 818 Section *head, *tail; 819 }; 820 821 typedef struct CodeGen CodeGen; 822 823 struct CodeGen { 824 FILE *out; 825 826 Env *env; 827 int indent, commacount; 828 bool needsvalue, hasclause; 829 const char *valuename; 830 }; 831 832 struct Compiler { 833 Source *head, *tail; 834 CodeGen cg; 835 }; 836 837 838 839 // }}} 840 841 // @section global-vars {{{ 842 843 Source testsource; 844 SourceArenas *arenas; 845 846 847 848 // }}} 849 850 // @section look-up tables {{{ 851 852 #define defaultloc {0, 1, "<builtin>"} 853 854 #define entry(tag, size, align) \ 855 {(tag), defaultloc, NULL, (size), (align), {{0}}, NULL}, 856 Type prim[] = { 857 TYPETAB 858 }; 859 #undef entry 860 861 #define primitive(typetag) (prim + typetag) 862 863 int keywordlengths[OSTART - KSTART]; 864 865 const int keywordtypeids[] = { 866 #define entry(tag) \ 867 [K##tag] = T##tag, 868 TYPEKEWORDYTAB 869 #undef entry 870 871 [OSTART] = 0 872 }; 873 874 const char *const nodestrings[MAXKINDS] = { 875 #define entry(tag, string, childs, flags, prec) \ 876 string, 877 NODETAB 878 #undef entry 879 }; 880 881 /* 882 Node kinds: 883 '@' - Annotation 884 ';' ',' ':' '{' '}' ']' ')' - Delimiters 885 'A' - Statement 886 'I' - Identifier 887 'K' - Keyword 888 'N' - Number-literal 889 'O' - Operator 890 'S' - String-literal 891 */ 892 893 #define opentry(numops, rassoc, prec) \ 894 ((uint8_t) ( ((numops) << 6) | ((rassoc) << 5) | (prec) )) 895 896 const uint8_t opinfo[] = { 897 #define entry(tag, string, childs, flags, prec) ((uint8_t) ( \ 898 ((childs) << 6) | \ 899 (!!(flags & FRASSOC) << 5) | \ 900 (prec) \ 901 )), 902 NODETAB 903 #undef entry 904 }; 905 906 #define getnumops(kind) (opinfo[kind] >> 6) 907 #define israssoc(kind) ((opinfo[kind] >> 5) & 0x01) 908 #define getprec(kind) ((opinfo[kind] & 0x1f)) 909 910 911 912 // }}} 913 914 // @section utility functions {{{ 915 916 #define listappendex(parent, child, head, tail, prev, next) do { \ 917 if ((parent)->head) { \ 918 assert((parent)->tail); \ 919 (child)->prev = (parent)->tail; \ 920 (child)->next = NULL; \ 921 (parent)->tail->next = (child); \ 922 } else { \ 923 assert(!(parent)->tail); \ 924 (child)->prev = NULL; \ 925 (child)->next = NULL; \ 926 (parent)->head = (child); \ 927 } \ 928 (parent)->tail = (child); \ 929 } while (0) 930 931 #define listappend(parent, child) \ 932 listappendex(parent, child, head, tail, prev, next) 933 934 #ifndef lengthof 935 #define lengthof(array) ((int) sizeof(array) / (int) sizeof(*(array))) 936 #endif 937 938 static int 939 mystrncasecmp(const char *str1, const char *str2, size_t max_len) 940 { 941 char tmp1[] = {'\0', '\0'}; 942 char tmp2[] = {'\0', '\0'}; 943 char c1, c2; 944 int result; 945 946 size_t i; 947 948 if (max_len == 0) { 949 size_t len1 = strlen(str1); 950 size_t len2 = strlen(str2); 951 max_len = len1 > len2 ? len1 : len2; 952 } 953 954 for (i = 0; i < max_len; ++i) { 955 c1 = tolower(str1[i]); 956 c2 = tolower(str2[i]); 957 if (c1 == '\0' && c2 == '\0') return 0; 958 tmp1[0] = c1; 959 tmp2[0] = c2; 960 result = strcmp(tmp1, tmp2); 961 if (result != 0) return result; 962 } 963 964 return 0; 965 } 966 967 static int 968 mystrcasecmp(const char *str1, const char *str2) 969 { 970 char tmp1[] = {'\0', '\0'}; 971 char tmp2[] = {'\0', '\0'}; 972 char c1, c2; 973 int result; 974 975 size_t i; 976 977 for (i = 0;; ++i) { 978 c1 = tolower(str1[i]); 979 c2 = tolower(str2[i]); 980 if (c1 == '\0' && c2 == '\0') return 0; 981 tmp1[0] = c1; 982 tmp2[0] = c2; 983 result = strcmp(tmp1, tmp2); 984 if (result != 0) return result; 985 } 986 987 return 0; 988 } 989 990 991 992 // }}} 993 994 // @section memory arena {{{ 995 996 #define myalloc(arena, Type) \ 997 ((Type *) myallocimpl(arena, sizeof(Type))) 998 999 static void * 1000 myallocimpl(MemArena *arena, size_t elemsize) 1001 { 1002 const size_t pageindex = arena->top / ARENA_PAGE_SIZE; 1003 const size_t pageoffset = arena->top % ARENA_PAGE_SIZE; 1004 1005 union {uint8_t *in; void *out;} bitcast; 1006 1007 assert(!arena->elemsize || arena->elemsize == elemsize); 1008 arena->elemsize = elemsize; 1009 1010 if (pageindex >= arena->capacity) { 1011 arena->capacity *= 2; 1012 if (!arena->capacity) 1013 arena->capacity = 1; 1014 arena->pages = realloc( 1015 arena->pages, arena->capacity * sizeof(void*)); 1016 assert(arena->pages); 1017 } 1018 1019 if (!arena->pages[pageindex]) { 1020 arena->pages[pageindex] = calloc( 1021 ARENA_PAGE_SIZE, arena->elemsize); 1022 assert(arena->pages[pageindex]); 1023 } 1024 1025 bitcast.in = arena->pages[pageindex] + pageoffset * arena->elemsize; 1026 1027 arena->top++; 1028 1029 return bitcast.out; 1030 } 1031 1032 /* @note for debugging */ 1033 static void * 1034 getalloc(MemArena *arena, size_t index) 1035 { 1036 const size_t pageindex = arena->top / ARENA_PAGE_SIZE; 1037 const size_t pageoffset = arena->top % ARENA_PAGE_SIZE; 1038 1039 union {uint8_t *in; void *out;} bitcast; 1040 1041 if (index >= arena->top) 1042 return NULL; 1043 1044 bitcast.in = arena->pages[pageindex] + pageoffset * arena->elemsize; 1045 return bitcast.out; 1046 } 1047 1048 static void 1049 disposearena(MemArena *arena) 1050 { 1051 int i; 1052 for (i = 0; i < arena->capacity; ++i) { 1053 if (arena->pages[i]) 1054 free(arena->pages[i]); 1055 arena->pages[i] = NULL; 1056 } 1057 free(arena->pages); 1058 arena->pages = NULL; 1059 } 1060 1061 1062 1063 1064 // }}} 1065 1066 // @section pre-lexer {{{ 1067 1068 static void 1069 tryprompt(Source *source, const char ch); 1070 1071 static bool 1072 processcommand(Source *source); 1073 1074 static bool 1075 mygetline(Source *source) 1076 { 1077 int i, l, c; 1078 FILE *in = source->filein; 1079 1080 tryprompt(source, '.'); 1081 c = getc(in); 1082 1083 source->linepos = ftell(in); 1084 1085 advance: 1086 ++source->currloc.line; 1087 1088 i = 0, l = 0; 1089 while (c == '\r' || c == '\n') { 1090 tryprompt(source, '.'); 1091 l = c, c = getc(in); 1092 1093 if (l == '\r' && c == '\n') 1094 c = getc(in); 1095 1096 ++source->currloc.line; 1097 } 1098 1099 source->tok.loc.line = source->currloc.line; 1100 1101 while (c != EOF && c != '\n' && c != '\r') { 1102 source->line[i++] = c; 1103 c = getc(in); 1104 1105 if (c == '\\') { 1106 int x = getc(in); 1107 if (x == '\n') { 1108 tryprompt(source, '\\'); 1109 c = getc(in); 1110 1111 ++source->currloc.line; 1112 } else if (x == '\r') { 1113 int y; 1114 1115 tryprompt(source, '\\'); 1116 y = getc(in); 1117 1118 c = (y == '\n') ? getc(in) : y; 1119 ++source->currloc.line; 1120 } else if (x == EOF) { 1121 c = x; 1122 } else { 1123 ungetc(x, in); 1124 } 1125 } 1126 } 1127 1128 if (c == '\r') { 1129 int x; 1130 1131 tryprompt(source, '.'); 1132 x = getc(in); 1133 if (x != '\n') 1134 ungetc(x, in); 1135 } 1136 1137 if (c != EOF && i == 0) 1138 goto advance; 1139 1140 source->line[i] = 0; 1141 1142 if (in == stdin && source->line[0] == ':') 1143 return processcommand(source); 1144 1145 return c != EOF || i; 1146 } 1147 1148 1149 1150 // }}} 1151 1152 // @section keyword map {{{ 1153 1154 #define KEYWORD_MAP_SIZE 128 1155 const char *keywordkeys[KEYWORD_MAP_SIZE]; 1156 int keywordvals[KEYWORD_MAP_SIZE]; 1157 1158 static int 1159 strnhash(const char *str, int n) 1160 { 1161 int hash = 5381, i; 1162 for (i = 0; i < n && str[i]; ++i) 1163 hash = (hash << 5) + hash + str[i]; 1164 return hash; 1165 } 1166 1167 static void 1168 initkeywords(void) 1169 { 1170 int i, j, h; 1171 for (i = 0; i < lengthof(keywordlengths); ++i) { 1172 int n = keywordlengths[i] = strlen(nodestrings[i + KSTART]); 1173 h = strnhash(nodestrings[i + KSTART], n) & 1174 (lengthof(keywordkeys) - 8); 1175 for (j = 0; j < 8; ++j, ++h) { 1176 if (!keywordkeys[h]) { 1177 keywordkeys[h] = nodestrings[i + KSTART]; 1178 keywordvals[h] = i; 1179 goto nextkeyword; 1180 } 1181 } 1182 1183 fprintf(stderr, "bug: keyword hash-map is too small\n"); 1184 abort(); 1185 nextkeyword: 1186 (void) 0; 1187 } 1188 1189 /* 1190 for (i = 0; i < lengthof(keywordkeys); ++i) { 1191 printf("%-12s%c", 1192 keywordkeys[i] ? keywordkeys[i] : ".", 1193 (i+1) % 8 ? ' ' : '\n'); 1194 } 1195 */ 1196 } 1197 1198 static int 1199 getkeyword(const char *str, int n) 1200 { 1201 int i, h = strnhash(str, n) & (lengthof(keywordkeys) - 8); 1202 for (i = 0; i < 8; ++i, ++h) { 1203 int len; 1204 if (!keywordkeys[h]) 1205 return -1; 1206 len = keywordlengths[keywordvals[h]]; 1207 if (n == len && memcmp(keywordkeys[h], str, n) == 0) 1208 return keywordvals[h]; 1209 } 1210 return -1; 1211 } 1212 1213 1214 1215 // }}} 1216 1217 // @section string map {{{ 1218 1219 typedef 1220 struct StringEntry { 1221 int len; 1222 const char *str; 1223 } StringEntry; 1224 1225 typedef 1226 struct StringMap { 1227 int *keys; 1228 int keyscap; 1229 1230 StringEntry *vals; 1231 int valscap, valslen; 1232 } StringMap; 1233 1234 StringMap idents; 1235 StringMap strings; 1236 1237 static void 1238 initstrmap(StringMap *map) 1239 { 1240 map->keys = calloc(32, sizeof(int)); 1241 map->keyscap = 32; 1242 assert(map->keys); 1243 1244 map->vals = calloc(32, sizeof(StringEntry)); 1245 map->valslen = 0; 1246 map->valscap = 32; 1247 assert(map->vals); 1248 } 1249 1250 #if 0 1251 static void 1252 disposestrmap(StringMap *map) 1253 { 1254 int i; 1255 for (i = map->valslen - 1; i >= 0; --i) { 1256 free((char *) map->vals[i].str); 1257 } 1258 1259 free(map->vals); 1260 free(map->keys); 1261 } 1262 #endif 1263 1264 static void 1265 putstringkey(StringMap *map, int key, int hash) 1266 { 1267 int *keys = map->keys; 1268 StringEntry *vals = map->vals; 1269 1270 int i, j; 1271 1272 redo: 1273 j = (hash << 3) & (map->keyscap - 1); 1274 for (i = 0; i < 8; ++i, ++j) { 1275 if (!keys[j]) { 1276 keys[j] = key; 1277 return; 1278 } 1279 } 1280 1281 free(keys); 1282 map->keyscap *= 2; 1283 keys = map->keys = calloc(map->keyscap, sizeof(int)); 1284 for (i = 0; i < map->valslen; ++i) { 1285 j = strnhash(vals[i].str, vals[i].len); 1286 putstringkey(map, i + 1, j); 1287 } 1288 1289 goto redo; 1290 } 1291 1292 int auxthen, auxin, auxto, auxstep; 1293 int auxself; 1294 1295 static int 1296 getstringkey(StringMap *map, const char *str, int n) 1297 { 1298 int *keys = map->keys; 1299 StringEntry *vals = map->vals; 1300 1301 int key, hash = strnhash(str, n); 1302 int i, j = (hash << 3) & (map->keyscap - 1); 1303 1304 char *newstr; 1305 1306 for (i = 0; i < 8; ++i, ++j) { 1307 key = keys[j]; 1308 if (!key) 1309 break; 1310 1311 assert(key > 0); 1312 if (n == vals[key - 1].len && 1313 memcmp(str, vals[key - 1].str, n) == 0) 1314 { 1315 return key; 1316 } 1317 } 1318 1319 key = map->valslen + 1; 1320 putstringkey(map, key, hash); 1321 1322 if (key > map->valscap) { 1323 int cap = map->valscap * 3 / 2 + 1; 1324 vals = map->vals = realloc(vals, cap * sizeof(StringEntry)); 1325 assert(vals); 1326 map->valscap = cap; 1327 } 1328 1329 /* @todo sizeof(char*) --> sizeof(char) ? */ 1330 newstr = calloc(n + 1, sizeof(char*)); 1331 1332 assert(newstr); 1333 memcpy(newstr, str, n); 1334 1335 vals[key - 1].len = n; 1336 vals[key - 1].str = newstr; 1337 ++map->valslen; 1338 1339 return key; 1340 } 1341 1342 #define getstring(map, key) ((map).vals[(key) - 1].str) 1343 #define getlength(map, key) ((map).vals[(key) - 1].len) 1344 1345 1346 1347 // }}} 1348 1349 // @section error reporting {{{ 1350 1351 int warningcount = 0; 1352 int errorcount = 0; 1353 1354 static int 1355 warn(SrcLoc *loc, const char *fmt, ...) 1356 { 1357 va_list ap; 1358 int n; 1359 1360 const char *filename = loc ? loc->filename : "<unknown-source>"; 1361 uint line = loc ? loc->line : 1; 1362 uint column = loc ? loc->column : 0; 1363 1364 va_start(ap, fmt); 1365 n = fprintf(stderr, "%s:%u:%u: warning: ", 1366 filename, line, column + 1); 1367 n += vfprintf(stderr, fmt, ap); 1368 n += fprintf(stderr, "\n"); 1369 va_end(ap); 1370 1371 ++warningcount; 1372 return n; 1373 } 1374 1375 #define error(loc, ...) \ 1376 error_(loc, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) 1377 1378 static int 1379 error_(SrcLoc *loc, const char *func, const char *file, int line_, 1380 const char *fmt, ...) 1381 { 1382 va_list ap; 1383 int n; 1384 1385 const char *filename = loc ? loc->filename : "<unknown-source>"; 1386 uint line = loc ? loc->line : 1; 1387 uint column = loc ? loc->column : 0; 1388 1389 va_start(ap, fmt); 1390 n = fprintf(stderr, "%s:%u:%u: error: ", 1391 filename, line, column + 1); 1392 n += vfprintf(stderr, fmt, ap); 1393 n += fprintf(stderr, " \x1b[30m[in %s() at %s:%u]\x1b[0m\n", 1394 func, file, line_); 1395 va_end(ap); 1396 1397 ++errorcount; 1398 return n; 1399 } 1400 1401 1402 1403 // }}} 1404 1405 // @section lexer {{{ 1406 1407 #define nextindent(source, indent) \ 1408 ((indent) + (source)->tabwidth - ((indent) % (source)->tabwidth)) 1409 1410 #define peekchar(source) \ 1411 ((source)->line[(source)->currloc.column]) 1412 1413 #define peeknextchar(source) \ 1414 ((source)->line[(source)->currloc.column + 1]) 1415 1416 #define nextchar(source) \ 1417 ((source)->line[++(source)->currloc.column]) 1418 1419 // @sub-section tokenize keyword / identifier {{{ 1420 1421 static int 1422 tokenizealphanumeric(Source *source, register int ch) 1423 { 1424 int keyword; 1425 1426 while (isalnum(ch) || ch == '_') 1427 ch = nextchar(source); 1428 1429 keyword = getkeyword( 1430 source->line + source->tok.loc.column, 1431 source->currloc.column - source->tok.loc.column 1432 ); 1433 1434 if (source->tok.kind != ANNOT && keyword >= 0 && 1435 source->tok.kind != ODISP) 1436 { 1437 if (keyword == KOR - KSTART || keyword == KAND - KSTART) { 1438 return source->tok.kind = 1439 keyword == KOR - KSTART ? OLOR : OLAND; 1440 } else if (keywordtypeids[keyword + KSTART]) { 1441 1442 source->tok.u.key = 1443 keywordtypeids[keyword + KSTART]; 1444 1445 source->tok.type = prim + source->tok.u.key; 1446 1447 return source->tok.kind = TYPE; 1448 } 1449 1450 return source->tok.kind = keyword + KSTART; 1451 } 1452 1453 source->tok.u.key = getstringkey( 1454 &idents, 1455 source->line + source->tok.loc.column, 1456 source->currloc.column - source->tok.loc.column 1457 ); 1458 1459 return source->tok.kind = IDENT; 1460 } 1461 1462 // }}} 1463 1464 // @sub-section tokenize number {{{ 1465 1466 static Type * 1467 suffixfloattype(Source *source, const char *end) 1468 { 1469 Type *ty = primitive(TDOUBLE); 1470 1471 if (*end == 0) 1472 return ty; 1473 1474 /* FIXME(m21c): r-suffix might conflict with radix */ 1475 if ((*end == 'f' || *end == 'F') && !end[1]) { 1476 ty = primitive(TFLOAT); 1477 1478 } else if (*end == 'l' || *end == 'L') { 1479 ty = primitive(TDOUBLE); 1480 1481 if (end[1]) 1482 goto errorfloat; 1483 1484 } else if (!mystrcasecmp(end, "f32") || !mystrcasecmp(end, "r32")) { 1485 ty = primitive(TF32); 1486 1487 } else if (!mystrcasecmp(end, "f64") || !mystrcasecmp(end, "r64")) { 1488 ty = primitive(TF64); 1489 1490 } else { 1491 errorfloat: 1492 error(&source->currloc, "invalid floating-point format"); 1493 } 1494 1495 return ty; 1496 } 1497 1498 static Type * 1499 suffixinttype(Source *source, const char *end) 1500 { 1501 int typeid = TUINT - TINT; 1502 1503 switch (*end) { 1504 case 0: 1505 return primitive(TINFER); 1506 1507 case 's': case 'S': case 'i': case 'I': 1508 typeid = 0; 1509 1510 /* fallthrough */ 1511 case 'u': case 'U': 1512 ++end; 1513 if (*end == 0) { 1514 return prim + (typeid + TINFER); 1515 1516 } else if (*end == '8') { 1517 typeid += TS8; 1518 1519 if (end[1]) 1520 goto errorint; 1521 1522 return prim + typeid; 1523 1524 } else if (!strcmp(end, "16")) { 1525 return prim + (typeid + TS16); 1526 1527 } else if (!strcmp(end, "32")) { 1528 return prim + (typeid + TS32); 1529 1530 } else if (!strcmp(end, "64")) { 1531 return prim + (typeid + TS64); 1532 1533 } else if (!mystrcasecmp(end, "sz")) { 1534 return prim + (typeid + TSSIZE); 1535 } 1536 1537 /* fallthrough */ 1538 default: 1539 if (!mystrcasecmp(end, "ll")) { 1540 return prim + (typeid + TLLONG); 1541 1542 } else if (*end == 'l' || *end == 'L') { 1543 typeid += TLONG; 1544 1545 if (end[1]) 1546 goto errorint; 1547 1548 return prim + typeid; 1549 } 1550 } 1551 1552 errorint: 1553 error(&source->currloc, "invalid integer format"); 1554 return primitive(TINT); 1555 } 1556 1557 static int 1558 tokenizenumber(Source *source, register int ch) 1559 { 1560 int l = ch, t = peeknextchar(source), i, j; 1561 bool hasdec = false, hasexp = false; 1562 char *end; 1563 1564 advancenum: 1565 while (isalnum(ch) || ch == '_' || 1566 (ch == '.' && peeknextchar(source) != '.' && !hasdec)) 1567 { 1568 if (ch != '_') 1569 l = ch; 1570 if (ch == '.') 1571 hasdec = true; 1572 1573 ch = nextchar(source); 1574 } 1575 1576 if (hasdec && !hasexp && (ch == '+' || ch == '-')) { 1577 t = tolower(t); 1578 l = tolower(l); 1579 1580 if ((l == 'e' && t != 'x') || (l == 'p' && t == 'x')) { 1581 ch = nextchar(source); 1582 hasexp = true; 1583 1584 goto advancenum; 1585 } 1586 } 1587 1588 /* remove underscores */ 1589 for (j = 0, i = source->tok.loc.column; 1590 i < (int) source->currloc.column; 1591 ++i) 1592 { 1593 if (source->line[i] != '_') { 1594 if (j >= lengthof(source->stringbuf) - 1) { 1595 error( 1596 &source->currloc, 1597 "number-literal is too long" 1598 ); 1599 1600 source->tok.u.u = 0; 1601 source->tok.type = primitive(TINT); 1602 1603 return source->tok.kind = NUMBER; 1604 } 1605 1606 source->stringbuf[j++] = source->line[i]; 1607 } 1608 } 1609 source->stringbuf[j] = 0; 1610 1611 if (strpbrk(source->stringbuf, ".pPrR") || 1612 (!strpbrk(source->stringbuf, "xX") && 1613 strpbrk(source->stringbuf, "eEfF"))) 1614 { 1615 source->tok.u.d = strtod(source->stringbuf, &end); 1616 source->tok.type = suffixfloattype(source, end); 1617 1618 } else { 1619 if (mystrncasecmp(source->stringbuf, "0b", 2) == 0) { 1620 source->tok.u.u = strtoull( 1621 source->stringbuf + 2, 1622 &end, 2 1623 ); 1624 1625 } else { 1626 source->tok.u.u = strtoull( 1627 source->stringbuf, 1628 &end, 0 1629 ); 1630 1631 } 1632 1633 source->tok.type = suffixinttype(source, end); 1634 } 1635 1636 return source->tok.kind = NUMBER; 1637 } 1638 1639 // }}} 1640 1641 // @sub-section tokenize string {{{ 1642 1643 static int 1644 tokenizestring(Source *source, register int ch) 1645 { 1646 int delim = ch, j; 1647 1648 ch = nextchar(source); 1649 source->tok.loc.column = source->currloc.column; 1650 1651 j = source->currloc.column; 1652 while (ch != delim && ch != 0) { 1653 if (ch == '\\') { 1654 ch = nextchar(source); 1655 1656 switch (ch) { 1657 case '\\': 1658 ch = '\\'; 1659 break; 1660 1661 case 'n': 1662 ch = '\n'; 1663 break; 1664 1665 case 'r': 1666 ch = '\r'; 1667 break; 1668 1669 case 't': 1670 ch = '\t'; 1671 break; 1672 1673 case '\'': 1674 ch = '\''; 1675 break; 1676 1677 case '"': 1678 ch = '"'; 1679 break; 1680 1681 /* @todo read more escape sequences */ 1682 case 0: 1683 goto stringeol; 1684 1685 default: 1686 error(&source->currloc, 1687 "invalid escape sequence '\\%c'", ch); 1688 } 1689 } 1690 1691 source->line[j++] = ch; 1692 ch = nextchar(source); 1693 } 1694 1695 ++source->currloc.column; 1696 source->line[j++] = 0; 1697 1698 if (ch == 0) { 1699 stringeol: 1700 error(&source->currloc, "unexpected end-of-line"); 1701 1702 return source->tok.kind = LINEDELIM; 1703 } 1704 1705 if (ch == '"') { 1706 source->tok.u.key = getstringkey( 1707 &strings, 1708 source->line + source->tok.loc.column, 1709 j - source->tok.loc.column 1710 ); 1711 1712 return source->tok.kind = STRING; 1713 } 1714 1715 /* @todo read numerical value of character properly 1716 * (escape sequences, etc.) */ 1717 source->tok.type = prim + TUCHAR; 1718 source->tok.u.u = source->line[source->tok.loc.column]; 1719 return source->tok.kind = CHAR; 1720 } 1721 1722 // }}} 1723 1724 // @sub-section tokenizer {{{ 1725 1726 static int 1727 gettok(Source *source) 1728 { 1729 register int ch = (uchar) peekchar(source); 1730 1731 source->lastkind = source->tok.kind; 1732 1733 if (source->savedtok.kind) { 1734 source->tok = source->savedtok; 1735 source->savedtok.kind = 0; 1736 return source->tok.kind; 1737 } 1738 1739 skipwhite: 1740 if (source->hasnewline) { 1741 if (!mygetline(source)) { 1742 source->lastindent = 0; 1743 return source->tok.kind = 0; 1744 } 1745 1746 source->currloc.column = 0; 1747 ch = peekchar(source); 1748 } 1749 1750 if (source->currloc.column) { 1751 /* just skip whitespace */ 1752 while (isspace(ch)) 1753 ch = nextchar(source); 1754 1755 } else { 1756 /* skip whitespace and calculate indentation */ 1757 source->lastindent = 0; 1758 while (isspace(ch)) { 1759 if (ch == '\t') { 1760 source->lastindent = nextindent( 1761 source, 1762 source->lastindent 1763 ); 1764 } else { 1765 ++source->lastindent; 1766 } 1767 1768 ch = nextchar(source); 1769 } 1770 } 1771 1772 source->tok.type = primitive(TUNDEFINED); 1773 source->tok.u.u = 0; 1774 source->tok.lhs = NULL; 1775 source->tok.rhs = NULL; 1776 source->tok.loc.column = source->currloc.column; 1777 1778 /* get line */ 1779 if (!ch || ch == '#') { 1780 if (source->hasnewline) { 1781 goto skipwhite; 1782 } else { 1783 /* defer reading new line to next call of gettok() 1784 * and return LINEDELIM */ 1785 source->hasnewline = true; 1786 return source->tok.kind = LINEDELIM; 1787 } 1788 } 1789 1790 /* c-syle block comment with nesting allowed */ 1791 if (ch == '/' && peeknextchar(source) == '*') { 1792 int nest = 1; 1793 1794 nextchar(source); 1795 ch = nextchar(source); 1796 1797 for (;nest; ch = nextchar(source)) { 1798 if (!ch) { 1799 if (!mygetline(source)) 1800 return source->tok.kind = 0; 1801 1802 /* is this needed? */ 1803 source->currloc.column = 0; 1804 ch = peekchar(source); 1805 } 1806 1807 if (ch == '*' && peeknextchar(source) == '/') { 1808 nextchar(source); 1809 --nest; 1810 } else if (ch == '/' && peeknextchar(source) == '*') { 1811 nextchar(source); 1812 ++nest; 1813 } 1814 } 1815 1816 goto skipwhite; 1817 } 1818 1819 source->hasnewline = false; 1820 1821 /* identifier or keyword */ 1822 if (isalpha(ch) || ch == '_') 1823 return tokenizealphanumeric(source, ch); 1824 1825 /* number literal */ 1826 if (isdigit(ch) || (ch == '.' && isdigit(peeknextchar(source)))) 1827 return tokenizenumber(source, ch); 1828 1829 /* string & character-literal */ 1830 if (ch == '"' || ch == '\'') 1831 return tokenizestring(source, ch); 1832 1833 /* operators */ 1834 #define select(ch, then, otherwise) ( \ 1835 peekchar(source) == (ch) ? \ 1836 ++source->currloc.column, (then) : \ 1837 (otherwise) \ 1838 ) 1839 1840 ++source->currloc.column; 1841 switch (ch) { 1842 case '.': 1843 /* tok.kind = select('.', ORANGE, ODISP); */ 1844 ch = ODISP; 1845 break; 1846 1847 case '*': 1848 ch = select('=', OMULA, OMUL); 1849 break; 1850 1851 case '/': 1852 ch = select('=', ODIVA, ODIV); 1853 break; 1854 1855 case '%': 1856 ch = select('=', OMODA, OMOD); 1857 break; 1858 1859 case '<': 1860 ch = select('=', OLEQ, 1861 select('<', 1862 select('=', OLSHA, OLSH), 1863 OLET)); 1864 break; 1865 1866 case '>': 1867 ch = select('=', OGEQ, 1868 select('>', 1869 select('>', 1870 select('=', OARSHA, OARSH), 1871 select('=', ORSHA, ORSH)), 1872 OGRT)); 1873 break; 1874 1875 case '&': 1876 ch = select('=', OANDA, select('&', OLAND, OBAND)); 1877 break; 1878 1879 case '+': 1880 ch = select('=', OADDA, select('+', OSUFINC, OADD)); 1881 break; 1882 1883 case '-': 1884 ch = select('=', OSUBA, select('-', OSUFDEC, OSUB)); 1885 break; 1886 1887 case '|': 1888 ch = select('=', OORA, select('|', OLOR, OBOR)); 1889 break; 1890 1891 case '^': 1892 ch = select('=', OXORA, OXOR); 1893 break; 1894 1895 case '!': 1896 ch = select('=', ONEQ, OLNOT); 1897 break; 1898 1899 case '~': 1900 ch = select('=', OFLIP, OBNOT); 1901 break; 1902 1903 case '=': 1904 ch = select('=', select('=', OIDENT, OEQU), OASS); 1905 break; 1906 1907 /* delimiters */ 1908 case ',': ch = COMMADELIM; break; 1909 case ';': ch = SEMIDELIM; break; 1910 case '@': ch = ANNOT; break; 1911 case ':': ch = COLONDELIM; break; 1912 case '{': ch = LCURLDELIM; break; 1913 case '}': ch = RCURLDELIM; break; 1914 case '[': ch = LSQRDELIM; break; 1915 case ']': ch = RSQRDELIM; break; 1916 case '(': ch = LPARDELIM; break; 1917 case ')': ch = RPARDELIM; break; 1918 1919 default: 1920 error(&source->currloc, "invalid input character '%c'", ch); 1921 return INVALID; 1922 } 1923 1924 return source->tok.kind = ch; 1925 #undef select 1926 } 1927 1928 // }}} 1929 1930 // @sub-section tokenizer utilities {{{ 1931 1932 static void 1933 pushbacktok(Source *source, Node *tok) 1934 { 1935 assert(source->savedtok.kind == 0); 1936 1937 source->savedtok = source->tok; 1938 source->tok = *tok; 1939 } 1940 1941 #define skipnewline(source) \ 1942 ((source)->tok.kind == LINEDELIM ? (void) gettok(source) : (void) 0) 1943 1944 static bool 1945 isbasicdelimiter(Kind kind) 1946 { 1947 switch ((int) kind) { 1948 case 0: 1949 case LINEDELIM: case COMMADELIM: case SEMIDELIM: 1950 case COLONDELIM: 1951 case RPARDELIM: case RSQRDELIM: case RCURLDELIM: 1952 case KELSE: 1953 case KUNTIL: 1954 return true; 1955 } 1956 1957 return false; 1958 } 1959 1960 static Kind 1961 getunary(Kind kind) 1962 { 1963 if (getprec(kind) == PUNARY) 1964 return kind; 1965 1966 switch (kind) { 1967 case OMUL: return ODEREF; 1968 case OBAND: return OADDR; 1969 case OADD: return OPLUS; 1970 case OSUB: return OMINUS; 1971 case OSUFINC: return OINC; 1972 case OSUFDEC: return ODEC; 1973 default: 1974 return 0; 1975 } 1976 } 1977 1978 static bool 1979 isdelimiter(Kind kind) 1980 { 1981 if (isbasicdelimiter(kind)) 1982 return true; 1983 1984 if (getunary(kind)) 1985 return false; 1986 1987 if (getnumops(kind)) 1988 return true; 1989 1990 return false; 1991 } 1992 1993 static Kind 1994 getunarysuffix(Source *source) 1995 { 1996 Kind kind = source->tok.kind; 1997 1998 if (getprec(kind) == PUNSUF) 1999 return kind; 2000 2001 /* @note fixes parsing unary suffix across multiple lines. 2002 * (which shouldn't happen) */ 2003 if (isbasicdelimiter(source->lastkind) && kind != COLONDELIM) 2004 return 0; 2005 2006 switch (kind) { 2007 case COLONDELIM: return ASELFDISP; 2008 case LPARDELIM: return OCALL; 2009 case LSQRDELIM: return OARRAY; 2010 default: 2011 return 0; 2012 } 2013 } 2014 2015 // }}} 2016 2017 2018 2019 // }}} 2020 2021 // @section ast-node {{{ 2022 2023 Node *poolednodes; 2024 int poolednodecount, totalnodecount; 2025 2026 #define tokennode(source, lhs) \ 2027 makenode(&(source)->arenas, &(source)->tok, (lhs)) 2028 2029 static Node * 2030 makenode(SourceArenas *arenas, Node *orig, Node *lhs) 2031 { 2032 Node *node; 2033 2034 if (poolednodes) { 2035 node = poolednodes; 2036 poolednodes = poolednodes->rhs; 2037 node->rhs = NULL; 2038 node->lhs = NULL; 2039 --poolednodecount; 2040 } else { 2041 node = myalloc(&arenas->node, Node); 2042 } 2043 2044 ++totalnodecount; 2045 *node = *orig; 2046 node->lhs = lhs; 2047 node->rhs = NULL; 2048 2049 return node; 2050 } 2051 2052 static void 2053 deleteenv(Env *env); 2054 2055 static void 2056 deletenode(Node *node) 2057 { 2058 if (node->kind == 0) 2059 return; 2060 2061 if (node->kind == ASCOPE) { 2062 Node *curr, *next; 2063 2064 if (node->u.env) { 2065 assert(node->u.env->stmts == node); 2066 node->u.env->stmts = NULL; 2067 deleteenv(node->u.env); 2068 } 2069 2070 for (curr = node->lhs; curr; curr = next) { 2071 assert(curr->kind == ASTMT); 2072 next = curr->rhs; 2073 deletenode(curr); 2074 } 2075 2076 } else if (node->kind == ASTMT) { 2077 if (node->lhs) 2078 deletenode(node->lhs); 2079 2080 } else { 2081 if (node->rhs) 2082 deletenode(node->rhs); 2083 2084 if (node->lhs) 2085 deletenode(node->lhs); 2086 2087 if (node->u.payload && (node->kind == KIF || 2088 node->kind == KWHILE || node->kind == ALOOPUNTIL)) 2089 { 2090 deletenode(node->u.payload); 2091 } 2092 } 2093 2094 ++poolednodecount; 2095 node->kind = 0; 2096 node->rhs = poolednodes; 2097 poolednodes = node; 2098 } 2099 2100 2101 2102 // }}} 2103 2104 // @section type-struct {{{ 2105 2106 static Type * 2107 maketype(SourceArenas *arenas, SrcLoc *loc, Type *orig, Type *target) 2108 { 2109 Type *ty = myalloc(&arenas->type, Type); 2110 2111 *ty = *orig; 2112 ty->loc = *loc; 2113 ty->target = target; 2114 2115 return ty; 2116 } 2117 2118 2119 2120 // }}} 2121 2122 // @section annotation {{{ 2123 2124 static Annot * 2125 makeannot(SourceArenas *arenas, SrcLoc *loc, int key) 2126 { 2127 Annot *annot = myalloc(&arenas->annot, Annot); 2128 2129 annot->key = key; 2130 annot->loc = *loc; 2131 2132 /* @todo implement initialization. */ 2133 2134 return annot; 2135 } 2136 2137 static Docket * 2138 makedocket(SourceArenas *arenas, Node *node) 2139 { 2140 Docket *docket = myalloc(&arenas->docket, Docket); 2141 2142 (void) node; /* @todo implement. */ 2143 2144 /* @todo implement initialization. */ 2145 2146 return docket; 2147 } 2148 2149 2150 2151 // }}} 2152 2153 // @section environment {{{ 2154 2155 static Decl * 2156 finddeclinenv(int key, Env *env) 2157 { 2158 const int cacheindex = (key >> 3) & 0x3f; 2159 const int cachebit = 1 << (key & 0x03); 2160 2161 Decl *decl; 2162 2163 if ((env->keycache[cacheindex] & cachebit) == 0) 2164 return NULL; 2165 2166 for (decl = env->head; decl; decl = decl->next) { 2167 if (decl->key == key) 2168 return decl; 2169 } 2170 2171 return NULL; 2172 } 2173 2174 static Decl * 2175 finddeclaration(Source *source, Env *startenv, int key) 2176 { 2177 const int cacheindex = (key >> 3) & 0x3f; 2178 const int cachebit = 1 << (key & 0x03); 2179 2180 Env *env; 2181 Decl *decl; 2182 2183 for (env = startenv; env; env = env->below) { 2184 /* @note look-up exclusion list first. 2185 * If found: only lookup in found env */ 2186 /* FIXME(m21c): make a separate list, and not use excludehead, 2187 * excludenext ! */ 2188 /* 2189 for (decl = env->excludehead; decl; decl = decl->excludenext) { 2190 if (decl->key == key) 2191 return finddeclinenv(key, env); 2192 } 2193 */ 2194 2195 2196 if ((env->keycache[cacheindex] & cachebit) == 0) 2197 continue; 2198 2199 for (decl = env->head; decl; decl = decl->next) { 2200 if (decl->key == key) 2201 return decl; 2202 } 2203 } 2204 2205 if (!source) 2206 return NULL; 2207 2208 env = source->implicitenv; 2209 2210 if ((env->keycache[cacheindex] & cachebit) == 0) 2211 return NULL; 2212 2213 for (decl = env->head; decl; decl = decl->next) { 2214 if (decl->key == key) 2215 return decl; 2216 } 2217 2218 return NULL; 2219 } 2220 2221 #if 0 2222 static Env * 2223 setheadenv(Source *source, EnvKind kind) 2224 { 2225 /* @note this might only be useful for parameter => function env 2226 * translation */ 2227 Env *env = myalloc(&source->arenas.env, Env); 2228 2229 env->kind = kind; 2230 2231 /* @todo make sure that source->tok.loc is the correct 2232 * source-location. */ 2233 /* @todo maybe use getloc(source) instead of 2234 * &source->tok.loc and move the declaration of 2235 * getloc() up in the source-code. */ 2236 env->loc = source->tok.loc; 2237 env->below = source->currenv; 2238 2239 assert(source->headenv == NULL); 2240 env->arenas = &source->arenas; 2241 source->currenv = source->headenv = env; 2242 2243 return env; 2244 } 2245 #endif 2246 2247 static Env * 2248 pushenv(Source *source, EnvKind kind) 2249 { 2250 Env *env; 2251 2252 if (source->headenv) { 2253 source->headenv->kind = kind; 2254 2255 assert(source->headenv == source->currenv); 2256 source->headenv = NULL; 2257 2258 return source->currenv; 2259 } 2260 2261 env = myalloc(&source->arenas.env, Env); 2262 env->kind = kind; 2263 /* @todo make sure that source->tok.loc is the correct 2264 * source-location. */ 2265 /* @todo maybe use getloc(source) instead of 2266 * &source->tok.loc and move the declaration of 2267 * getloc() up in the source-code. */ 2268 env->loc = source->tok.loc; 2269 env->below = source->currenv; 2270 2271 env->arenas = &source->arenas; 2272 source->currenv = env; 2273 2274 return env; 2275 } 2276 2277 static Env * 2278 popenv(Source *source) 2279 { 2280 Env *currenv = source->currenv; 2281 Env *env = currenv; 2282 2283 if (currenv) 2284 source->currenv = currenv->below; 2285 2286 return env; 2287 } 2288 2289 static Env * 2290 getfuncenv(Env *currenv) 2291 { 2292 Env *env; 2293 2294 for (env = currenv; env; env = env->below) { 2295 if (env->kind == SFUNCTION) { 2296 return env; 2297 } 2298 } 2299 2300 return NULL; 2301 } 2302 2303 static bool 2304 deferfuncenv(Source *source, int keydeclinfunc) 2305 { 2306 Env *funcenv = getfuncenv(source->currenv); 2307 2308 if (funcenv) { 2309 if (!funcenv->pending) { 2310 funcenv->pending = true; 2311 /* @todo handle nested functions properly */ 2312 source->haspendingenv = true; 2313 2314 listappendex(source, funcenv, 2315 pendingenvhead, pendingenvtail, 2316 pendingprev, pendingnext); 2317 } 2318 } else { 2319 /* @todo maybe use getloc(source) instead of 2320 * &source->tok.loc and move the declaration of 2321 * getloc() up in the source-code. */ 2322 error( 2323 &source->tok.loc, 2324 "'%s' undeclared", 2325 getstring(idents, keydeclinfunc) 2326 ); 2327 2328 return false; 2329 } 2330 2331 return true; 2332 } 2333 2334 2335 static Node * 2336 wrapenv(Node *node, Env *env) 2337 { 2338 Node *aenv = makenode(env->arenas, node, node); 2339 2340 aenv->kind = AENV; 2341 aenv->u.env = env; 2342 2343 return aenv; 2344 } 2345 2346 static void 2347 deleteenv(Env *env) 2348 { 2349 if (env->stmts) 2350 deletenode(env->stmts); 2351 2352 /* @todo delete env */ 2353 } 2354 2355 static bool 2356 isrecordenv(Env *env) 2357 { 2358 assert(env); 2359 return env->kind == SSTRUCT || env->kind == SUNION; 2360 } 2361 2362 2363 2364 // }}} 2365 2366 // @section declaration {{{ 2367 2368 static void 2369 appenddecltoenv(Decl *decl, Env *targetenv) 2370 { 2371 const int key = decl->key; 2372 const int cacheindex = (key >> 3) & 0x3f; 2373 const int cachebit = 1 << (key & 0x03); 2374 2375 targetenv->keycache[cacheindex] |= cachebit; 2376 2377 decl->parentenv = targetenv; 2378 2379 listappend(targetenv, decl); 2380 } 2381 2382 static void 2383 removedeclfromenv(Decl *decl) 2384 { 2385 Env *sourceenv = decl->parentenv; 2386 2387 if (decl->prev) 2388 decl->prev->next = decl->next; 2389 else 2390 sourceenv->head = decl->next; 2391 2392 if (decl->next) 2393 decl->next->prev = decl->prev; 2394 else 2395 sourceenv->tail = decl->prev; 2396 2397 decl->parentenv = NULL; 2398 decl->next = decl->prev = NULL; 2399 } 2400 2401 static Decl * 2402 makedecl(Source *source, int key, DeclKind kind) 2403 { 2404 Env *currenv = source->currenv; 2405 Decl *decl; 2406 2407 assert(currenv); 2408 2409 /* @todo maybe remove check if already declared, 2410 * since many functions that call makedecl 2411 * already try to obtain a declaration for 2412 * other reasons. So the check if it is 2413 * already declared can be done by those 2414 * functions */ 2415 2416 decl = finddeclinenv(key, currenv); 2417 2418 if (decl) { 2419 if (decl->parentenv == source->implicitenv) { 2420 removedeclfromenv(decl); 2421 appenddecltoenv(decl, currenv); 2422 2423 return decl; 2424 } 2425 2426 /* @todo make sure that source->tok.loc is the correct 2427 * source-location. */ 2428 /* @todo maybe use getloc(source) instead of 2429 * &source->tok.loc and move the declaration of 2430 * getloc() up in the source-code. */ 2431 error( 2432 &source->tok.loc, 2433 "'%s' already declared", 2434 getstring(idents, key) 2435 ); 2436 } 2437 2438 decl = myalloc(&source->arenas.decl, Decl); 2439 2440 decl->kind = kind; 2441 /* @todo make sure that source->tok.loc is the correct 2442 * source-location. */ 2443 /* @todo maybe use getloc(source) instead of 2444 * &source->tok.loc and move the declaration of 2445 * getloc() up in the source-code. */ 2446 decl->loc = source->tok.loc; 2447 decl->key = key; 2448 decl->type = primitive(TVOID); 2449 decl->contentenv = NULL; 2450 decl->module = NULL; 2451 2452 appenddecltoenv(decl, currenv); 2453 2454 return decl; 2455 } 2456 2457 static Decl * 2458 makebundle(Source *source, int key, Decl *parentbundle) 2459 { 2460 /* Env *currenv = source->currenv; */ 2461 Decl *decl; 2462 2463 /* assert(currenv); */ 2464 2465 decl = myalloc(&source->arenas.decl, Decl); 2466 2467 decl->kind = DBUNDLE; 2468 /* @todo make sure that source->tok.loc is the correct 2469 * source-location. */ 2470 /* @todo maybe use getloc(source) instead of 2471 * &source->tok.loc and move the declaration of 2472 * getloc() up in the source-code. */ 2473 decl->loc = source->tok.loc; 2474 decl->key = key; 2475 decl->type = primitive(TVOID); 2476 decl->contentenv = NULL; 2477 decl->module = parentbundle; 2478 2479 return decl; 2480 } 2481 2482 static Decl * 2483 makedecl2(SrcLoc *loc, Env *env, int key, DeclKind kind) 2484 { 2485 Decl *decl; 2486 2487 assert(env); 2488 2489 /* @todo maybe remove check if already declared, 2490 * since many functions that call makedecl 2491 * already try to obtain a declaration for 2492 * other reasons. So the check if it is 2493 * already declared can be done by those 2494 * functions */ 2495 2496 decl = finddeclinenv(key, env); 2497 if (decl) { 2498 /* @todo maybe check also for implicit declarations */ 2499 error(loc, "'%s' already declared", getstring(idents, key)); 2500 } 2501 2502 decl = myalloc(&env->arenas->decl, Decl); 2503 2504 decl->kind = kind; 2505 /* @todo make sure that source->tok.loc is the correct 2506 * source-location. */ 2507 /* @todo maybe use getloc(source) instead of 2508 * &source->tok.loc and move the declaration of 2509 * getloc() up in the source-code. */ 2510 decl->loc = *loc; 2511 decl->key = key; 2512 decl->type = primitive(TVOID); 2513 decl->contentenv = NULL; 2514 2515 appenddecltoenv(decl, env); 2516 2517 return decl; 2518 } 2519 2520 static Decl * 2521 defertypedeclaration(Source *source, int key) 2522 { 2523 Env *savedcurrenv = source->currenv; 2524 Decl *decl; 2525 2526 source->currenv = source->implicitenv; 2527 decl = makedecl(source, key, DTYPE); 2528 2529 /* FIXME(m21c): type may be overwritten, when the declaration 2530 * is completed */ 2531 decl->type = maketype( 2532 &source->arenas, &source->tok.loc, primitive(TVOID), NULL); 2533 decl->type->module = decl; 2534 source->currenv = savedcurrenv; 2535 2536 return decl; 2537 } 2538 2539 2540 2541 // }}} 2542 2543 // @section record {{{ 2544 2545 static Record * 2546 makerecord(Source *source, Decl *recorddecl) 2547 { 2548 Record *record = myalloc(&source->arenas.record, Record); 2549 2550 record->head = record->tail = NULL; 2551 2552 recorddecl->record = record; 2553 2554 assert(recorddecl->type); 2555 record->isunion = recorddecl->type->kind == TUNION; 2556 2557 return record; 2558 } 2559 2560 static Field * 2561 makefield(Source *source, Record *record, Decl *decl) 2562 { 2563 Field *field = myalloc(&source->arenas.field, Field); 2564 2565 field->decl = decl; 2566 field->offset = field->size = 0; 2567 field->use = false; 2568 field->prev = field->next = NULL; 2569 2570 assert(record); 2571 listappend(record, field); 2572 2573 return field; 2574 } 2575 2576 2577 2578 // }}} 2579 2580 // @section parser {{{ 2581 2582 #define getkind(source) \ 2583 ((source)->tok.kind) 2584 2585 #define getloc(source) \ 2586 (&(source)->tok.loc) 2587 2588 static bool 2589 expect(Source *source, int kind, const char *fmt, ...) 2590 { 2591 va_list ap; 2592 2593 int line = source->tok.loc.line; 2594 int column = source->tok.loc.column; 2595 const char *filename = source->tok.loc.filename; 2596 2597 if (getkind(source) != (Kind) kind) { 2598 va_start(ap, fmt); 2599 fprintf(stderr, "%s:%i:%i: error: ", 2600 filename, line, column + 1); 2601 vfprintf(stderr, fmt, ap); 2602 fprintf(stderr, "\n"); 2603 va_end(ap); 2604 2605 return false; 2606 } 2607 2608 gettok(source); 2609 return true; 2610 } 2611 2612 // @sub-section read annotations {{{ 2613 2614 static AnnotParam * 2615 readannotparam(Source *source) 2616 { 2617 bool hasident = false; 2618 2619 while (getkind(source)) { 2620 int count = 1; 2621 2622 switch (getkind(source)) { 2623 case IDENT: 2624 if (!hasident) { 2625 int key = source->tok.u.key; 2626 const char *ident = getstring(idents, key); 2627 printf("Annotation Parameter: %s\n", ident); 2628 2629 hasident = true; 2630 } 2631 2632 gettok(source); 2633 break; 2634 2635 case COMMADELIM: case RPARDELIM: 2636 goto finish; 2637 2638 case LPARDELIM: 2639 gettok(source); 2640 while (getkind(source) && count > 0) { 2641 switch (getkind(source)) { 2642 case LPARDELIM: 2643 ++count; 2644 break; 2645 case RPARDELIM: 2646 --count; 2647 break; 2648 default: 2649 break; 2650 } 2651 gettok(source); 2652 } 2653 2654 if(!getkind(source)) 2655 goto finish; 2656 2657 /* FALLTHROUGH */ 2658 default: 2659 gettok(source); 2660 } 2661 } 2662 2663 finish: 2664 return NULL; 2665 } 2666 2667 static void 2668 readannots(Source *source) 2669 { 2670 Docket *docket = NULL; 2671 2672 while (getkind(source) == ANNOT) { 2673 SrcLoc loc = source->tok.loc; 2674 int key = 0; 2675 2676 Annot *annot = NULL; 2677 2678 gettok(source); 2679 2680 key = source->tok.u.key; 2681 if (!expect(source, IDENT, "expected annotation-identifier.")) 2682 return; 2683 2684 annot = makeannot(&source->arenas, &loc, key); 2685 2686 if (getkind(source) == LPARDELIM) { 2687 int count; 2688 2689 gettok(source); 2690 for (count = 0; getkind(source); ++count) { 2691 AnnotParam *param = readannotparam(source); 2692 2693 if (param) 2694 listappend(annot, param); 2695 2696 if (getkind(source) == COMMADELIM) { 2697 gettok(source); 2698 continue; 2699 } 2700 2701 if (getkind(source) != RPARDELIM) { 2702 error(getloc(source), 2703 "expected ',' or ')'."); 2704 } else { 2705 gettok(source); 2706 } 2707 2708 break; 2709 } 2710 } 2711 2712 if (docket == NULL) { 2713 docket = makedocket(&source->arenas, NULL); 2714 /* @todo add docket to source */ 2715 } 2716 2717 listappend(docket, annot); 2718 2719 skipnewline(source); 2720 2721 printf("Annotation: '%s'\n", getstring(idents, key)); 2722 } 2723 } 2724 2725 // }}} 2726 2727 // @sub-section read statement list {{{ 2728 2729 static bool 2730 checkend(Source *source, bool hastail, int needindent, 2731 const char *expecterrmsg) 2732 { 2733 Node savedtok = {0}; 2734 2735 if (getkind(source) == LINEDELIM) { 2736 savedtok = source->tok; 2737 2738 gettok(source); 2739 2740 if (getkind(source) == SEMIDELIM) { 2741 error(getloc(source), expecterrmsg); 2742 gettok(source); 2743 2744 pushbacktok(source, &savedtok); 2745 return true; 2746 } 2747 } 2748 2749 if (source->lastkind == LINEDELIM && source->lastindent < needindent) { 2750 /* @note Is that correct? Maybe we should always pushback 2751 * a made-up new-line, instead of asserting that we 2752 * have saved one. Since it might be the case, that 2753 * we already have read a new-line prior the call 2754 * to this function. But I'll leave it this way, 2755 * for now. */ 2756 /* assert(savedtok.kind == LINEDELIM); */ 2757 2758 if (savedtok.kind == LINEDELIM) 2759 pushbacktok(source, &savedtok); 2760 return true; 2761 } 2762 2763 if (getkind(source) == SEMIDELIM) { 2764 savedtok = source->tok; 2765 gettok(source); 2766 2767 /* @note used for REPL. it allows having 2768 * semicolons on line-endings and nultiple 2769 * adjacent semecolons in REPL-mode. */ 2770 if ((getkind(source) == SEMIDELIM || 2771 getkind(source) == LINEDELIM) && 2772 source->filein != stdin) 2773 /* @note output an error-message if not in REPL-mode */ 2774 error(&savedtok.loc, "trailing semicolon."); 2775 } 2776 2777 if (isdelimiter(source->tok.kind)) 2778 return true; 2779 2780 if (hastail && 2781 source->lastkind != LINEDELIM && 2782 source->lastkind != SEMIDELIM) 2783 error(getloc(source), "expected line delimiter"); 2784 2785 return false; 2786 } 2787 2788 static Node * 2789 exprlist(Source *source, bool isparam, Type *paramtype); 2790 2791 static Node * 2792 stmtlist(Source *source, int indent, EnvKind envkind, 2793 Decl *envdecl, bool reuseenv) 2794 { 2795 Node *head = NULL, *tail = NULL; 2796 int needindent = nextindent(source, indent); 2797 2798 Env *env = NULL; 2799 2800 if (reuseenv) { 2801 source->currenv->kind = envkind; 2802 } else { 2803 env = pushenv(source, envkind); 2804 env->envdecl = envdecl; 2805 } 2806 2807 for (;;) { 2808 Node *stmt; 2809 2810 if (checkend(source, !!tail, needindent, "expected expression")) 2811 break; 2812 2813 if (getkind(source) == LINEDELIM) 2814 gettok(source); 2815 2816 readannots(source); 2817 stmt = exprlist(source, false, NULL); 2818 stmt = tokennode(source, stmt); 2819 stmt->kind = ASTMT; 2820 2821 if (!tail) { 2822 head = tail = stmt; 2823 } else { 2824 tail->rhs = stmt; 2825 tail = stmt; 2826 } 2827 } 2828 2829 if (reuseenv) { 2830 assert(env == NULL); 2831 env = source->currenv; 2832 } 2833 2834 if (head) { 2835 head = tokennode(source, head); 2836 head->kind = ASCOPE; 2837 head->u.env = env; 2838 env->stmts = head; 2839 2840 popenv(source); 2841 } else { 2842 popenv(source); 2843 /* if (!reuseenv) deleteenv(env); */ 2844 } 2845 2846 return head; 2847 } 2848 2849 // }}} 2850 2851 // @sub-section read declaration {{{ 2852 2853 static int 2854 qualifiers(Source *source, int allowmask) 2855 { 2856 int flags = 0, mask = allowmask; 2857 2858 while (iskeyword(getkind(source))) { 2859 int f, m; 2860 2861 switch (getkind(source)) { 2862 case KEXTERN: 2863 f = QEXTERN, m = ~QVISIB; 2864 break; 2865 2866 case KINTERN: 2867 f = QINTERN, m = ~QVISIB; 2868 break; 2869 2870 case KSTATIC: 2871 f = QSTATIC, m = ~QSTORAGE; 2872 break; 2873 2874 case KCONST: 2875 f = QCONST, m = 0; 2876 break; 2877 2878 /* @todo remove this */ 2879 case KVAR: 2880 f = QVAR, m = ~(QTYPE | QINFER); 2881 break; 2882 2883 default: 2884 goto finish; 2885 } 2886 2887 if (f & ~allowmask) { 2888 const char *str = nodestrings[getkind(source)]; 2889 2890 error(getloc(source), "invalid qualifier '%s'", str); 2891 } else if (f & flags & QTYPE) { 2892 const char *str = nodestrings[getkind(source)]; 2893 2894 warn(getloc(source), "redundant qualifier '%s'", str); 2895 } else if (f & ~mask) { 2896 const char *str = nodestrings[getkind(source)]; 2897 2898 error(getloc(source), "redundant qualifier '%s'", str); 2899 } 2900 2901 flags |= f & allowmask & mask; 2902 mask &= m; 2903 gettok(source); 2904 } 2905 2906 finish: 2907 return flags; 2908 } 2909 2910 static Node * 2911 readexpr(Source *source, int minprec); 2912 2913 static Type * 2914 gettype(Source *source, Type *basetype) 2915 { 2916 int flags; 2917 2918 if (!basetype) 2919 return NULL; 2920 2921 advance: 2922 flags = qualifiers(source, QTYPE); 2923 (void) flags; 2924 2925 if (getkind(source) == LSQRDELIM) { 2926 Type *tmp = maketype( 2927 &source->arenas, getloc(source), 2928 primitive(TARRAY), basetype); 2929 basetype = tmp; 2930 2931 gettok(source); 2932 if (source->tok.kind != RSQRDELIM) 2933 basetype->u.val = readexpr(source, PASSIGN); 2934 2935 expect(source, RSQRDELIM, "expect ']'"); 2936 goto advance; 2937 } 2938 2939 if (getkind(source) == OMUL) { 2940 Type *tmp = maketype( 2941 &source->arenas, getloc(source), 2942 primitive(TPTR), basetype); 2943 basetype = tmp; 2944 2945 gettok(source); 2946 goto advance; 2947 } 2948 2949 return basetype; 2950 } 2951 2952 static Node * 2953 typecheck(Env *env, Node *expr); 2954 2955 static Node * 2956 declaration(Source *source, Type *ty, bool tryreadtype) 2957 { 2958 bool selfparam = false; 2959 Type *module = NULL; 2960 Decl *decl = NULL; 2961 Node *result = NULL; 2962 2963 Env *env = source->currenv; 2964 2965 /* 2966 EnvKind context; 2967 */ 2968 2969 if (tryreadtype) { 2970 decl = finddeclaration( 2971 source, env, source->tok.u.key); 2972 2973 if (decl && decl->kind == DTYPE) { 2974 gettok(source); 2975 ty = gettype(source, decl->type); 2976 tryreadtype = false; 2977 } 2978 } 2979 2980 if (!ty) 2981 return NULL; 2982 2983 /* @todo use the currenv->kind as context, whether or how 2984 * certain declarations (like function-declarations) 2985 * are processed */ 2986 2987 /* 2988 context = env->kind; 2989 */ 2990 2991 redodeclaration: 2992 skipnewline(source); 2993 2994 /* variable name */ 2995 if (getkind(source) == IDENT) { 2996 int key = source->tok.u.key; 2997 SrcLoc loc = source->tok.loc; 2998 2999 gettok(source); 3000 3001 if (tryreadtype && isrecordenv(env)) { 3002 3003 if (!isbasicdelimiter(getkind(source)) && 3004 getkind(source) != LPARDELIM) 3005 { 3006 decl = defertypedeclaration(source, key); 3007 decl->loc = loc; 3008 ty = gettype(source, decl->type); 3009 tryreadtype = false; 3010 goto redodeclaration; 3011 } 3012 } 3013 3014 decl = finddeclaration(source, env, key); 3015 3016 if (decl && decl->kind != DFUNCTION && decl->kind != DPARAM && 3017 decl->kind != DVAR) 3018 { 3019 module = decl->type; 3020 decl = NULL; 3021 goto readvarmodule; 3022 } 3023 3024 if ((getkind(source) == ODISP || getkind(source) == COLONDELIM) 3025 && getkind(source) != LPARDELIM && getkind(source) != OASS) 3026 { 3027 error(&loc, "expected type or module"); 3028 } 3029 3030 decl = makedecl(source, key, DVAR); 3031 decl->loc = loc; 3032 decl->type = ty; 3033 3034 /* module for variable */ 3035 } else if (getkind(source) == TYPE) { 3036 module = source->tok.type; 3037 gettok(source); 3038 3039 readvarmodule: 3040 module = gettype(source, module); 3041 3042 if (getkind(source) == ODISP || getkind(source) == COLONDELIM) { 3043 selfparam = getkind(source) == COLONDELIM; 3044 (void) selfparam; 3045 gettok(source); 3046 } else { 3047 error(getloc(source), "expected '.' or ':'"); 3048 } 3049 3050 /* @todo obtain Decl* for 3051 * Type Module:my_decl 3052 * or Type Module.my_decl - declarations */ 3053 3054 /* variable name */ 3055 if (getkind(source) == IDENT) { 3056 Env *moduleenv = NULL; 3057 assert(module->module); 3058 assert(module->module->contentenv); 3059 moduleenv = module->module->contentenv; 3060 3061 decl = makedecl2(&source->tok.loc, 3062 moduleenv, source->tok.u.key, DVAR); 3063 decl->type = ty; 3064 decl->module = module->module; 3065 gettok(source); 3066 } else { 3067 error(getloc(source), "expected identifier"); 3068 } 3069 /* just return a node for the type */ 3070 } else { 3071 result = tokennode(source, NULL); 3072 result->kind = TYPE; 3073 result->type = ty; 3074 3075 return result; 3076 } 3077 3078 if (!decl->module) 3079 decl->module = env->bundle; 3080 3081 /* function declaration */ 3082 if (getkind(source) == LPARDELIM) { 3083 Type *paramtype = NULL; 3084 Env *functionenv = NULL; 3085 Node *body = NULL; 3086 3087 /* function params */ 3088 gettok(source); 3089 if (getkind(source) != RPARDELIM) { 3090 Decl *param; 3091 Node *paramlist; 3092 Type *paramtype = NULL; 3093 3094 functionenv = pushenv(source, SPARAMLIST); 3095 functionenv->envdecl = decl; 3096 3097 if (selfparam) { 3098 param = makedecl(source, auxself, DVAR); 3099 param->type = maketype( 3100 &source->arenas, ¶m->loc, 3101 prim + TPTR, module); 3102 param->flags |= MSPECIAL; 3103 /* @note param doesn't need to be added to 3104 * paramlist. since paramlist will be 3105 * deleted anyway and param is already 3106 * present in env. */ 3107 paramtype = param->type; 3108 } 3109 3110 paramlist = exprlist(source, true, paramtype); 3111 paramlist = typecheck(functionenv, paramlist); 3112 paramtype = paramlist->type; 3113 deletenode(paramlist); 3114 3115 for (param = functionenv->head; param; 3116 param = param->next) 3117 { 3118 assert(param->kind == DVAR); 3119 param->kind = DPARAM; 3120 } 3121 } else if (selfparam) { 3122 Type *selftype = maketype(&source->arenas, &decl->loc, 3123 primitive(TPTR), module); 3124 Decl *selfdecl; 3125 3126 functionenv = pushenv(source, SPARAMLIST); 3127 functionenv->envdecl = decl; 3128 3129 selfdecl = makedecl(source, auxself, DPARAM); 3130 selfdecl->type = selftype; 3131 selfdecl->flags |= MSPECIAL; 3132 } 3133 expect(source, RPARDELIM, "expected ')'"); 3134 3135 if (module && ty->kind == TINFER) { 3136 ty = module; 3137 } else if (ty->kind == TINFER) { 3138 error(&decl->loc, 3139 "cannot infer return type of function"); 3140 } 3141 3142 decl->type = maketype( 3143 &source->arenas, &decl->loc, 3144 primitive(TFUNCTION), paramtype); 3145 decl->kind = DFUNCTION; 3146 decl->type->u.rtarget = ty; 3147 ty = decl->type; 3148 3149 /* function body */ 3150 if (getkind(source) != OASS) { 3151 body = stmtlist(source, source->lastindent, 3152 SFUNCTION, decl, !!functionenv); 3153 3154 if (!isrecordenv(env)) { 3155 assert(body && body->kind == ASCOPE); 3156 functionenv = body->u.env; 3157 } 3158 3159 /* function init (body defined by assigment) */ 3160 } else if (getkind(source) == OASS) { 3161 gettok(source); 3162 3163 functionenv->kind = SFUNCTION; 3164 body = readexpr(source, PASSIGN); 3165 3166 popenv(source); 3167 3168 /* no function body */ 3169 } else { 3170 popenv(source); 3171 } 3172 3173 assert(decl->contentenv == NULL); 3174 decl->contentenv = functionenv; 3175 3176 assert(decl->u.content == NULL); 3177 decl->u.content = body; 3178 3179 3180 /* @todo maybe add function-declaration to its type and 3181 * add the paramlist to the type-info */ 3182 3183 /* @todo store the params-node (its initializations) 3184 * somewhere */ 3185 3186 goto finish; 3187 } 3188 3189 /* variable init */ 3190 if (getkind(source) == OASS) { 3191 gettok(source); 3192 assert(decl); 3193 decl->u.content = readexpr(source, PASSIGN); 3194 3195 /* no init */ 3196 } else { 3197 assert(decl); 3198 decl->u.content = NULL; 3199 3200 if (ty->kind == TINFER) { 3201 error(&decl->loc, 3202 "cannot infer type, expected initialization"); 3203 } 3204 } 3205 3206 finish: 3207 if (isrecordenv(env)) 3208 decl->flags |= MRECORDMEMBER; 3209 3210 result = tokennode(source, decl->u.content); 3211 result->type = ty; 3212 result->u.declref = decl; 3213 result->loc = decl->loc; 3214 result->kind = ADECL; 3215 3216 return result; 3217 } 3218 3219 // }}} 3220 3221 // @sub-section read atom {{{ 3222 3223 static Node * 3224 readident(Source *source, int flags) 3225 { 3226 Node *lhs = NULL; 3227 Decl *decl = NULL; 3228 SrcLoc loc = source->tok.loc; 3229 int key = source->tok.u.key; 3230 3231 decl = finddeclaration(source, source->currenv, source->tok.u.key); 3232 gettok(source); 3233 3234 if (!decl && isrecordenv(source->currenv)) { 3235 if (!isbasicdelimiter(getkind(source))) { 3236 decl = defertypedeclaration(source, key); 3237 decl->loc = loc; 3238 } 3239 } 3240 3241 if (decl && decl->kind == DTYPE) { 3242 lhs = declaration(source, gettype(source, decl->type), false); 3243 return lhs; 3244 } 3245 3246 lhs = tokennode(source, NULL); 3247 lhs->loc = loc; 3248 3249 if (decl) { 3250 lhs->kind = ADECLREF; 3251 lhs->type = decl->type; 3252 lhs->u.declref = decl; 3253 } else { 3254 if (deferfuncenv(source, key)) { 3255 lhs->kind = IDENT; 3256 lhs->u.key = key; 3257 } else { 3258 lhs->kind = NUMBER; 3259 lhs->u.u = 0; 3260 } 3261 3262 lhs->type = primitive(TVOID); 3263 } 3264 3265 if (flags & QCONST) { 3266 /* @todo const - conversion */ 3267 } 3268 3269 return lhs; 3270 } 3271 3272 static void 3273 extractfields(Source *source, Record *record, Node *recordscope) 3274 { 3275 Node *stmt; 3276 3277 for (stmt = recordscope->lhs; stmt; stmt = stmt->rhs) { 3278 Node *expr; 3279 3280 assert(stmt->kind == ASTMT); 3281 3282 expr = stmt->lhs; 3283 3284 /* @fixme expr might be validly NULL */ 3285 assert(expr); 3286 3287 if (expr->kind == ACOMMA) { 3288 for (; expr; expr = expr->lhs) { 3289 Node *nested; 3290 3291 if (expr->kind == ADECL) 3292 makefield( 3293 source, record, expr->u.declref); 3294 3295 if (expr->kind != ACOMMA) 3296 break; 3297 3298 nested = expr->rhs; 3299 3300 if (nested->kind != ADECL) 3301 continue; 3302 3303 makefield(source, record, nested->u.declref); 3304 } 3305 continue; 3306 } 3307 if (expr->kind != ADECL) 3308 continue; 3309 3310 makefield(source, record, expr->u.declref); 3311 } 3312 } 3313 3314 static void 3315 calculatefields(Record *record, Type *recordtype) 3316 { 3317 const bool isunion = record->isunion; 3318 Field *field; 3319 3320 /* @todo calculate size/align for unions */ 3321 for (field = record->head; field; field = field->next) { 3322 size_t mod = 0, padding; 3323 Type *type; 3324 3325 type = field->decl->type; 3326 3327 if (recordtype->align < type->align) 3328 recordtype->align = type->align; 3329 3330 if (isunion) { 3331 if (recordtype->size < type->size) 3332 recordtype->size = type->size; 3333 continue; 3334 } 3335 3336 if (recordtype->align) 3337 mod = recordtype->size % recordtype->align; 3338 3339 padding = mod ? recordtype->align - mod : 0; 3340 field->offset = padding + recordtype->size; 3341 recordtype->size += padding + type->size; 3342 } 3343 } 3344 3345 static Node * 3346 readrecord(Source *source, bool isunion) 3347 { 3348 Node *recordnode; 3349 Decl *module; 3350 Record *record; 3351 int indent = source->lastindent; 3352 3353 EnvKind envkind = SSTRUCT; 3354 TypeKind typekind = TSTRUCT; 3355 3356 if (isunion) { 3357 envkind = SUNION; 3358 typekind = TUNION; 3359 } 3360 3361 recordnode = tokennode(source, NULL); 3362 recordnode->kind = getkind(source); 3363 gettok(source); 3364 3365 /* read record tag-name */ 3366 if (getkind(source) == IDENT) { 3367 recordnode->lhs = tokennode(source, NULL); 3368 gettok(source); 3369 } else { 3370 recordnode->lhs = tokennode(source, NULL); 3371 recordnode->kind = 0; 3372 error(getloc(source), "expected identifier"); 3373 } 3374 3375 module = makedecl(source, recordnode->lhs->u.key, DTYPE); 3376 3377 if (module->type->module == module) { 3378 *module->type = prim[TSTRUCT]; 3379 } else { 3380 module->type = maketype( 3381 &source->arenas, &recordnode->loc, 3382 prim + typekind, NULL); 3383 } 3384 3385 module->type->module = module; 3386 recordnode->type = module->type; 3387 3388 if (!module->module) /* @note currently module->module == NULL always */ 3389 module->module = source->currenv->bundle; 3390 3391 /* read record body */ 3392 3393 /* @note maybe we will use stmtlist() for parsing the record body, 3394 since we have to parse statements or expressions beside 3395 field declarations */ 3396 3397 /* @todo check for new-line and only then read body */ 3398 module->contentenv = pushenv(source, envkind); 3399 module->contentenv->envdecl = module; 3400 recordnode->rhs = stmtlist(source, indent, envkind, module, true); 3401 3402 record = makerecord(source, module); 3403 3404 /* @todo validate record body, extract declarations, 3405 * compute size and align, resolve aliases */ 3406 3407 if (recordnode->rhs) { 3408 assert(recordnode->rhs->kind == ASCOPE); 3409 extractfields(source, record, recordnode->rhs); 3410 } 3411 3412 calculatefields(record, recordnode->type); 3413 return recordnode; 3414 } 3415 3416 static bool 3417 skipnewlineontok(Source *source, Kind kind, int neededindent) 3418 { 3419 Node savedtok; 3420 3421 if (getkind(source) == kind) 3422 return source->lastindent >= neededindent; 3423 3424 if (getkind(source) == LINEDELIM) { 3425 savedtok = source->tok; 3426 3427 if (gettok(source) == (int) kind && 3428 source->lastindent >= neededindent) 3429 return true; 3430 3431 pushbacktok(source, &savedtok); 3432 } 3433 3434 return false; 3435 } 3436 3437 static Node * 3438 readrecordinitfield(Source *source, Type *recordtype) 3439 { 3440 Node *fieldinit = NULL; 3441 Node savedtok = {0}; 3442 3443 /* @todo add init-env */ 3444 3445 skipnewline(source); 3446 3447 fieldinit = tokennode(source, NULL); 3448 fieldinit->kind = AFIELDINIT; 3449 if (getkind(source) == IDENT) { 3450 savedtok = source->tok; 3451 gettok(source); 3452 if (getkind(source) == COLONDELIM) { 3453 gettok(source); 3454 /* @todo associate field name with field in record 3455 * type */ 3456 fieldinit->lhs = makenode( 3457 &source->arenas, &savedtok, NULL); 3458 } else { 3459 pushbacktok(source, &savedtok); 3460 } 3461 } 3462 3463 fieldinit->rhs = readexpr(source, PASSIGN); 3464 return fieldinit; 3465 } 3466 3467 static Node * 3468 readrecordinitfieldlist(Source *source, Type *recordtype) 3469 { 3470 /* @todo add init-env */ 3471 /* @todo check for missing field-initializers */ 3472 Node *init = readrecordinitfield(source, recordtype); 3473 3474 while (skipnewline(source), getkind(source) == COMMADELIM) { 3475 init = tokennode(source, init); 3476 init->kind = ACOMMA; 3477 gettok(source); 3478 init->rhs = readrecordinitfield(source, recordtype); 3479 } 3480 3481 return init; 3482 } 3483 3484 static Node * 3485 finishcontrolflow(Source *source, Node *lhs, int indent) 3486 { 3487 if (skipnewlineontok(source, KELSE, indent)) { 3488 gettok(source); 3489 lhs->rhs = stmtlist(source, indent, SELSE, NULL, false); 3490 } 3491 3492 return wrapenv(lhs, popenv(source)); 3493 } 3494 3495 static Node * 3496 readatom(Source *source, int flags) 3497 { 3498 Node *lhs = NULL, *savedis = source->lastis; 3499 int indent; 3500 3501 /* unary 'is'-operator */ 3502 if (getkind(source) == KIS) { 3503 if (!source->lastis) { 3504 error( 3505 getloc(source), 3506 "there is no left-hand-side for 'is'" 3507 ); 3508 3509 lhs = tokennode(source, NULL); 3510 } else { 3511 lhs = tokennode(source, source->lastis->lhs); 3512 } 3513 3514 gettok(source); 3515 3516 if (getkind(source) == KNOT) 3517 gettok(source), lhs->kind = ONEQ; 3518 else 3519 lhs->kind = OEQU; 3520 3521 lhs->rhs = readexpr(source, PRELAT); 3522 return lhs; 3523 } 3524 3525 /* unary prefix operators */ 3526 if (getunary(source->tok.kind)) { 3527 lhs = tokennode(source, NULL); 3528 3529 /* @todo remove redundant function-call */ 3530 lhs->kind = getunary(source->tok.kind); 3531 3532 gettok(source); 3533 lhs->lhs = readatom(source, 0); 3534 return lhs; 3535 } 3536 3537 if (flags & ~(QINFER | QCONST)) { 3538 error(getloc(source), "invalid use of qualifiers"); 3539 flags = flags & (QINFER | QCONST); 3540 } 3541 3542 if (flags) { 3543 lhs = readatom(source, flags); 3544 return lhs; 3545 } 3546 3547 /* actual atom */ 3548 switch (getkind(source)) { 3549 case LPARDELIM: 3550 gettok(source); 3551 3552 if (getkind(source) == LINEDELIM) { 3553 /* FIXME(m21c): stmtlist should ignore indentation in 3554 * this case! */ 3555 lhs = stmtlist(source, source->lastindent, 3556 SSCOPE, NULL, false); 3557 source->lastis = savedis; 3558 } else { 3559 lhs = exprlist(source, false, NULL); 3560 source->lastis = savedis; 3561 3562 if (lhs->kind == TYPE) { 3563 /* @note expecting that the type is also set in 3564 * lhs->type */ 3565 lhs->kind = OCAST; 3566 skipnewline(source); 3567 expect(source, RPARDELIM, "expected ')'"); 3568 3569 lhs->lhs = readatom(source, 0); 3570 break; 3571 } 3572 3573 if (lhs->kind == ACOMMA && 3574 lhs->lhs->kind == TYPE && 3575 lhs->rhs->kind == TYPE) 3576 { 3577 Type *ty = maketype( 3578 &source->arenas, &lhs->loc, 3579 primitive(TTUPLE), NULL); 3580 ty->target = lhs->lhs->type; 3581 ty->u.rtarget = lhs->rhs->type; 3582 deletenode(lhs); 3583 3584 skipnewline(source); 3585 expect(source, RPARDELIM, "expected ')'"); 3586 3587 lhs = declaration(source, 3588 gettype(source, ty), false); 3589 3590 assert(lhs); 3591 return lhs; 3592 } 3593 3594 skipnewline(source); 3595 } 3596 3597 expect(source, RPARDELIM, "expected ')'"); 3598 break; 3599 3600 case IDENT: 3601 lhs = readident(source, flags); 3602 break; 3603 3604 case TYPE: 3605 do { 3606 Type *type = source->tok.type; 3607 gettok(source); 3608 lhs = declaration(source, gettype(source, type), false); 3609 } while (0); 3610 3611 break; 3612 3613 case NUMBER: 3614 case STRING: 3615 case CHAR: 3616 lhs = tokennode(source, NULL); 3617 gettok(source); 3618 3619 if (flags & QCONST) { 3620 /* @todo const - conversion */ 3621 } 3622 3623 break; 3624 3625 case KVAR: 3626 gettok(source); 3627 lhs = declaration(source, primitive(TINFER), false); 3628 /* skip postfix-operators */ 3629 return lhs; 3630 3631 case KFALSE: 3632 case KTRUE: 3633 lhs = tokennode(source, NULL); 3634 lhs->kind = NUMBER; 3635 lhs->type = primitive(TBOOL); 3636 lhs->u.u = (uintmax_t) (getkind(source) == KTRUE); 3637 gettok(source); 3638 break; 3639 3640 case KNULL: 3641 lhs = tokennode(source, NULL); 3642 lhs->kind = NUMBER; 3643 lhs->type = maketype( 3644 &source->arenas, &source->tok.loc, 3645 primitive(TPTR), primitive(TVOID)); 3646 lhs->u.u = (uintmax_t) (getkind(source) == KTRUE); 3647 gettok(source); 3648 break; 3649 3650 case KSTRUCT: 3651 case KUNION: 3652 lhs = readrecord(source, source->tok.kind == KUNION); 3653 /* skip postfix-operators */ 3654 return lhs; 3655 3656 case KNOT: 3657 lhs = tokennode(source, NULL); 3658 gettok(source); 3659 lhs->kind = OLNOT; 3660 lhs->lhs = readexpr(source, PRELAT); 3661 break; 3662 3663 case KALIGNOF: 3664 case KSIZEOF: 3665 case KLENGTHOF: 3666 lhs = tokennode(source, NULL); 3667 gettok(source); 3668 if (getkind(source) == LPARDELIM) { 3669 gettok(source); 3670 lhs->lhs = exprlist(source, false, NULL); 3671 expect(source, RPARDELIM, "expected ')'"); 3672 } else { 3673 lhs->lhs = readatom(source, 0); 3674 } 3675 3676 break; 3677 3678 case KBITCAST: 3679 lhs = tokennode(source, NULL); 3680 gettok(source); 3681 expect(source, LPARDELIM, "expected '('"); 3682 lhs->rhs = exprlist(source, false, NULL); 3683 expect(source, RPARDELIM, "expected ')'"); 3684 lhs->lhs = readatom(source, 0); 3685 break; 3686 3687 case KBREAK: 3688 case KCONTINUE: 3689 lhs = tokennode(source, NULL); 3690 lhs->kind = getkind(source); 3691 gettok(source); 3692 3693 if (getkind(source) == COLONDELIM) { 3694 gettok(source); 3695 skipnewline(source); 3696 if (getkind(source) == IDENT) { 3697 lhs->lhs = tokennode(source, NULL); 3698 gettok(source); 3699 } else { 3700 error(getloc(source), "expected identifier"); 3701 } 3702 } 3703 3704 break; 3705 3706 case KRETURN: 3707 lhs = tokennode(source, NULL); 3708 gettok(source); 3709 3710 if (getkind(source) == COLONDELIM) { 3711 gettok(source); 3712 skipnewline(source); 3713 if (getkind(source) == IDENT) { 3714 lhs->lhs = tokennode(source, NULL); 3715 gettok(source); 3716 } else { 3717 error(getloc(source), "expected identifier"); 3718 } 3719 } 3720 3721 /* if is atom */ 3722 if (!isdelimiter(source->tok.kind)) 3723 lhs->rhs = exprlist(source, false, NULL); 3724 3725 break; 3726 3727 case KDO: 3728 indent = source->lastindent; 3729 lhs = tokennode(source, NULL); 3730 gettok(source); 3731 lhs->lhs = stmtlist(source, indent, SDO, NULL, false); 3732 /* skip postfix-operators */ 3733 return lhs; 3734 3735 case KLOOP: 3736 indent = source->lastindent; 3737 lhs = tokennode(source, NULL); 3738 gettok(source); 3739 pushenv(source, SLOOPHEADER); 3740 lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false); 3741 3742 if (skipnewlineontok(source, KUNTIL, indent)) { 3743 lhs->kind = ALOOPUNTIL; 3744 gettok(source); 3745 lhs->u.payload = readexpr(source, POR); 3746 } 3747 3748 if (lhs->kind != KLOOP) 3749 goto joinelse; 3750 3751 /* skip postfix-operators */ 3752 // return finishcontrolflow(source, lhs, indent); 3753 3754 return wrapenv(lhs, popenv(source)); 3755 3756 case KFOR: 3757 indent = source->lastindent; 3758 lhs = tokennode(source, NULL); 3759 gettok(source); 3760 3761 pushenv(source, SLOOPHEADER); 3762 lhs->u.payload = readexpr(source, POR); 3763 if (getkind(source) == IDENT) { 3764 if (source->tok.u.key == auxin) { 3765 Node *aux = tokennode(source, NULL); 3766 aux->lhs = lhs->u.payload; 3767 aux->kind = AFOREACH; 3768 lhs->u.payload = aux; 3769 gettok(source); 3770 aux->rhs = readexpr(source, POR); 3771 } else if (source->tok.u.key == auxto) { 3772 Node *aux = tokennode(source, NULL); 3773 aux->lhs = lhs->u.payload; 3774 aux->kind = AFORSTEP; 3775 lhs->u.payload = aux; 3776 gettok(source); 3777 aux->rhs = readexpr(source, POR); 3778 if (getkind(source) == IDENT 3779 && source->tok.u.key == auxstep) { 3780 gettok(source); 3781 aux->u.payload = readexpr(source, POR); 3782 } else { 3783 aux->u.payload = tokennode(source, NULL); 3784 aux->u.payload->kind = NUMBER; 3785 aux->u.payload->type = primitive(TINFER); 3786 aux->u.payload->u.s = 1; 3787 } 3788 } else if (source->tok.u.key == auxstep) { 3789 Node *aux = tokennode(source, NULL); 3790 aux->lhs = lhs->u.payload; 3791 aux->kind = AFORSTEP; 3792 lhs->u.payload = aux; 3793 gettok(source); 3794 aux->u.payload = readexpr(source, POR); 3795 3796 /* @note is this even correct? */ 3797 aux->rhs = tokennode(source, NULL); 3798 aux->rhs->kind = NUMBER; 3799 aux->rhs->type = primitive(TINFER); 3800 aux->rhs->u.s = INTMAX_MAX; 3801 } 3802 } 3803 3804 /* @todo maybe use SFOR instead of SLOOP */ 3805 lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false); 3806 goto joinelse; 3807 return finishcontrolflow(source, lhs, indent); 3808 3809 case KWHILE: 3810 indent = source->lastindent; 3811 lhs = tokennode(source, NULL); 3812 gettok(source); 3813 pushenv(source, SLOOPHEADER); 3814 lhs->u.payload = readexpr(source, POR); 3815 lhs->lhs = stmtlist(source, indent, SWHILE, NULL, false); 3816 goto joinelse; 3817 return finishcontrolflow(source, lhs, indent); 3818 3819 case KIF: 3820 indent = source->lastindent; 3821 lhs = tokennode(source, NULL); 3822 gettok(source); 3823 pushenv(source, SIFHEADER); 3824 lhs->u.payload = readexpr(source, POR); 3825 /* skipnewline(source); */ 3826 3827 if (getkind(source) == IDENT && source->tok.u.key == auxthen) 3828 gettok(source); 3829 3830 lhs->lhs = stmtlist(source, indent, SIF, NULL, false); 3831 joinelse: 3832 if (skipnewlineontok(source, KELSE, indent)) { 3833 gettok(source); 3834 lhs->rhs = stmtlist(source, indent, SELSE, NULL, false); 3835 } 3836 return finishcontrolflow(source, lhs, indent); 3837 3838 /* skip postfix-operators */ 3839 return wrapenv(lhs, popenv(source)); 3840 3841 case LINEDELIM: 3842 /* @note is looping needed? */ 3843 while (getkind(source) == LINEDELIM) 3844 gettok(source); 3845 return readatom(source, flags); 3846 3847 default: 3848 /* joinerror: */ 3849 error(getloc(source), "expected expression"); 3850 lhs = tokennode(source, NULL); 3851 lhs->kind = NUMBER; 3852 lhs->type = primitive(TERRTYPE); 3853 lhs->u.u = 0; 3854 gettok(source); 3855 } 3856 3857 /* compound-literal */ 3858 if (getkind(source) == LCURLDELIM && lhs->kind == TYPE) { 3859 lhs = tokennode(source, lhs); 3860 lhs->kind = ACOMPOUND; 3861 lhs->type = lhs->lhs->type; 3862 3863 gettok(source); 3864 // source->lastindent = nextindent(source, source->lastindent); 3865 lhs->rhs = readrecordinitfieldlist(source, lhs->type); 3866 expect(source, RCURLDELIM, "expected '}'"); 3867 } 3868 3869 /* unary postfix operators */ 3870 while (getunarysuffix(source)) { 3871 lhs = tokennode(source, lhs); 3872 3873 /* @todo remove redundant function-call */ 3874 lhs->kind = getunarysuffix(source); 3875 3876 if (getkind(source) == ODISP) { 3877 gettok(source); 3878 skipnewline(source); 3879 3880 if (getkind(source) != IDENT) 3881 error(getloc(source), "expected identifier"); 3882 3883 lhs->rhs = tokennode(source, NULL); 3884 3885 } else if (getkind(source) == COLONDELIM) { 3886 gettok(source); 3887 skipnewline(source); 3888 3889 if (getkind(source) != IDENT) 3890 error(getloc(source), "expected identifier"); 3891 3892 lhs->rhs = tokennode(source, NULL); 3893 3894 } else if (getkind(source) == LPARDELIM) { 3895 gettok(source); 3896 3897 if (getkind(source) != RPARDELIM) { 3898 lhs->rhs = exprlist(source, false, NULL); 3899 source->lastis = savedis; 3900 } 3901 3902 expect(source, RPARDELIM, "expected ')'"); 3903 continue; 3904 3905 } else if (getkind(source) == LSQRDELIM) { 3906 gettok(source); 3907 3908 lhs->rhs = exprlist(source, false, NULL); 3909 source->lastis = savedis; 3910 3911 expect(source, RSQRDELIM, "expected ']'"); 3912 continue; 3913 } 3914 3915 gettok(source); 3916 } 3917 3918 /* 'not'-suffix for the binary 'is'-operator (i.e. 'is not') */ 3919 while (getkind(source) == KIS) { 3920 lhs = tokennode(source, lhs); 3921 gettok(source); 3922 3923 lhs->kind = 'O'; 3924 if (getkind(source) == KNOT) 3925 gettok(source), lhs->kind = ONEQ; 3926 else 3927 lhs->kind = OEQU; 3928 3929 source->lastis = lhs; 3930 lhs->rhs = readexpr(source, PRELAT); 3931 } 3932 3933 /* skip funtion-call without parentheses when next token is an 3934 * auxiliary keyword */ 3935 if (getkind(source) == IDENT) { 3936 if (source->tok.u.key == auxthen 3937 || source->tok.u.key == auxin 3938 || source->tok.u.key == auxto 3939 || source->tok.u.key == auxstep) { 3940 return lhs; 3941 } 3942 } 3943 3944 /* function call without parentheses */ 3945 if (lhs->kind == ADECLREF 3946 && lhs->u.declref->kind == DFUNCTION 3947 && isatomnode(getkind(source))) { 3948 lhs = tokennode(source, lhs); 3949 lhs->kind = OCALL; 3950 3951 lhs->rhs = exprlist(source, false, NULL); 3952 source->lastis = savedis; /* @note is this correct? */ 3953 3954 /* function call without parentheses for type.function */ 3955 } else if (lhs->kind == ODISP 3956 && lhs->lhs->type && lhs->lhs->type->module) { 3957 Decl *field; 3958 3959 assert(lhs->lhs->type->module->contentenv); 3960 field = finddeclinenv(lhs->rhs->u.key, 3961 lhs->lhs->type->module->contentenv); 3962 if (field && field->kind == DFUNCTION 3963 && isatomnode(getkind(source))) { 3964 lhs = tokennode(source, lhs); 3965 lhs->kind = OCALL; 3966 3967 lhs->rhs = exprlist(source, false, NULL); 3968 source->lastis = savedis; /* @note is this correct? */ 3969 } 3970 } 3971 3972 return lhs; 3973 } 3974 3975 // }}} 3976 3977 // @sub-section read expression {{{ 3978 3979 static Node * 3980 readexpr(Source *source, int minprec) 3981 { 3982 Node *lhs = readatom(source, 0), *last = NULL; 3983 3984 /* only binary expr */ 3985 while (getprec(getkind(source)) >= minprec) { 3986 lhs = tokennode(source, lhs); 3987 gettok(source); 3988 skipnewline(source); 3989 3990 lhs->rhs = readexpr( 3991 source, 3992 getprec(lhs->kind) + !israssoc(lhs->kind) 3993 ); 3994 3995 switch (getprec(lhs->kind)) { 3996 case PRELAT: 3997 if (last) { 3998 lhs = tokennode(source, lhs); 3999 4000 lhs->rhs = lhs->lhs; 4001 lhs->kind = OLAND; 4002 4003 lhs->lhs = lhs->rhs->lhs; 4004 lhs->rhs->lhs = last->rhs; /* copy */ 4005 last = lhs->rhs; 4006 } else { 4007 last = lhs; 4008 } 4009 4010 break; 4011 4012 default: 4013 last = NULL; 4014 break; 4015 } 4016 } 4017 4018 return lhs; 4019 } 4020 4021 #if 0 4022 static Node * 4023 todeclaration(Node *curr, Node **ty) 4024 { 4025 if (*ty) { 4026 if (curr->kind == IDENT) { 4027 Node *decl = makenode(curr, *ty); 4028 curr->kind = ADECL; 4029 decl->rhs = curr; 4030 curr = decl; 4031 } else if (curr->kind == OASS && 4032 curr->lhs && curr->lhs->kind == IDENT) 4033 { 4034 curr->kind = ADECL; 4035 curr->u.payload = curr->rhs; 4036 curr->rhs = curr->lhs; 4037 curr->lhs = *ty; 4038 } 4039 } 4040 4041 if (curr->kind == ADECL) 4042 *ty = curr->lhs; 4043 4044 return curr; 4045 } 4046 #endif 4047 4048 /* @todo this is stupid! There should be a simpler way to parse the 4049 * comma-expressions (comma-operator, param-list, declaration-list, 4050 * type-tuples and expression-tuples) */ 4051 static Node * 4052 exprlist(Source *source, bool isparam, Type *paramtype) 4053 { 4054 Node *lhs; 4055 bool isdeclaration, typetuple; 4056 4057 /* tail = todeclaration(tail, ¶mtype); */ 4058 4059 if (paramtype && getkind(source) == IDENT) { 4060 lhs = declaration(source, paramtype, true); 4061 } else { 4062 lhs = readexpr(source, PASSIGN); 4063 } 4064 4065 isdeclaration = lhs->kind == ADECL; 4066 4067 if (isdeclaration) 4068 paramtype = lhs->type; 4069 else if (isparam) 4070 error(getloc(source), "expected declaration"); 4071 4072 typetuple = lhs->kind == TYPE; 4073 4074 while (getkind(source) == COMMADELIM) { 4075 Node *rhs = NULL; 4076 4077 if (lhs->kind == ACOMMA && 4078 lhs->lhs->kind == TYPE && 4079 lhs->rhs->kind == TYPE) 4080 { 4081 lhs->type = maketype(&source->arenas, &lhs->loc, 4082 primitive(TTUPLE), lhs->lhs->type); 4083 lhs->type->u.rtarget = lhs->rhs->type; 4084 4085 lhs->lhs->type = NULL; 4086 lhs->rhs->type = NULL; 4087 deletenode(lhs->lhs); 4088 deletenode(lhs->rhs); 4089 4090 lhs->lhs = NULL; 4091 lhs->rhs = NULL; 4092 lhs->kind = TYPE; 4093 } 4094 4095 lhs = tokennode(source, lhs); 4096 lhs->kind = ACOMMA; 4097 gettok(source); 4098 4099 if (getkind(source) == IDENT && isdeclaration) { 4100 rhs = declaration(source, paramtype, true); 4101 typetuple = false; 4102 } else { 4103 rhs = readexpr(source, PASSIGN); 4104 typetuple &= rhs->kind == TYPE; 4105 /* rhs = todeclaration(curr, ¶mtype); */ 4106 } 4107 4108 if ((paramtype || isparam) && rhs->kind != ADECL) 4109 error(getloc(source), "expected declaration"); 4110 4111 if (rhs->kind == ADECL) { 4112 paramtype = rhs->type; 4113 isdeclaration = true; 4114 } 4115 4116 lhs->rhs = rhs; 4117 } 4118 4119 source->lastis = NULL; 4120 return lhs; 4121 } 4122 4123 // }}} 4124 4125 4126 4127 // }}} 4128 4129 // @section type-checking & folding {{{ 4130 4131 static bool 4132 isinttype(Type *ty) 4133 { 4134 switch (ty->kind) { 4135 case TINFER: case TUINFER: 4136 case TS8: case TU8: 4137 case TS16: case TU16: 4138 case TS32: case TU32: 4139 case TS64: case TU64: 4140 case TERRTYPE: /* avoiding error-reporting on error-type */ 4141 return true; 4142 4143 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4144 * certain kinds. In order to check wether two tuple-types 4145 * are compatible (for casting), another function has to 4146 * be implemented. */ 4147 case TTUPLE: 4148 return isinttype(ty->target) 4149 && isinttype(ty->u.rtarget); 4150 4151 default: 4152 return false; 4153 } 4154 } 4155 4156 static bool 4157 isintorbooltype(Type *ty) 4158 { 4159 switch (ty->kind) { 4160 case TBOOL: 4161 case TINFER: case TUINFER: 4162 case TS8: case TU8: 4163 case TS16: case TU16: 4164 case TS32: case TU32: 4165 case TS64: case TU64: 4166 case TERRTYPE: /* avoiding error-reporting on error-type */ 4167 return true; 4168 4169 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4170 * certain kinds. In order to check wether two tuple-types 4171 * are compatible (for casting), another function has to 4172 * be implemented. */ 4173 case TTUPLE: 4174 return isintorbooltype(ty->target) 4175 && isintorbooltype(ty->u.rtarget); 4176 4177 default: 4178 return false; 4179 } 4180 } 4181 4182 static bool 4183 isfloattype(Type *ty) 4184 { 4185 switch (ty->kind) { 4186 case TF32: case TF64: 4187 case TERRTYPE: /* avoiding error-reporting on error-type */ 4188 return true; 4189 4190 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4191 * certain kinds. In order to check wether two tuple-types 4192 * are compatible (for casting), another function has to 4193 * be implemented. */ 4194 case TTUPLE: 4195 return isfloattype(ty->target) 4196 && isfloattype(ty->u.rtarget); 4197 4198 default: 4199 return false; 4200 } 4201 } 4202 4203 static bool 4204 isarithtype(Type *ty) 4205 { 4206 switch (ty->kind) { 4207 case TBOOL: 4208 case TINFER: case TUINFER: 4209 case TS8: case TU8: 4210 case TS16: case TU16: 4211 case TS32: case TU32: 4212 case TS64: case TU64: 4213 case TF32: case TF64: 4214 case TERRTYPE: /* avoiding error-reporting on error-type */ 4215 return true; 4216 4217 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4218 * certain kinds. In order to check wether two tuple-types 4219 * are compatible (for casting), another function has to 4220 * be implemented. */ 4221 case TTUPLE: 4222 return isarithtype(ty->target) 4223 && isarithtype(ty->u.rtarget); 4224 4225 default: 4226 return false; 4227 } 4228 } 4229 4230 /* @note essentially arithmetic + reference type */ 4231 static bool 4232 islogicaltype(Type *ty) 4233 { 4234 switch (ty->kind) { 4235 case TBOOL: 4236 case TINFER: case TUINFER: 4237 case TS8: case TU8: 4238 case TS16: case TU16: 4239 case TS32: case TU32: 4240 case TS64: case TU64: 4241 case TF32: case TF64: 4242 case TPTR: 4243 /* @todo add ranges ? */ 4244 case TERRTYPE: /* avoiding error-reporting on error-type */ 4245 return true; 4246 4247 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4248 * certain kinds. In order to check wether two tuple-types 4249 * are compatible (for casting), another function has to 4250 * be implemented. */ 4251 case TTUPLE: 4252 return islogicaltype(ty->target) 4253 && islogicaltype(ty->u.rtarget); 4254 4255 default: 4256 return false; 4257 } 4258 } 4259 4260 static bool 4261 isunsignedtype(Type *ty) 4262 { 4263 switch (ty->kind) { 4264 case TBOOL: 4265 case TUINFER: 4266 case TU8: case TU16: 4267 case TU32: case TU64: 4268 case TERRTYPE: /* avoiding error-reporting on error-type */ 4269 return true; 4270 4271 /* FIXME(m21c): This *just* tests wether a tuple only contains types of 4272 * certain kinds. In order to check wether two tuple-types 4273 * are compatible (for casting), another function has to 4274 * be implemented. */ 4275 case TTUPLE: 4276 return isunsignedtype(ty->target) 4277 && isunsignedtype(ty->u.rtarget); 4278 4279 default: 4280 return false; 4281 } 4282 } 4283 4284 static bool 4285 islvalue(Node *node) 4286 { 4287 assert(node); 4288 4289 switch (node->kind) { 4290 case ADECLREF: 4291 case ADEREF: 4292 case ADECL: 4293 case ODISP: /* only for member fields. @todo evaluate for properties. */ 4294 case TERRTYPE: /* avoiding error-reporting on error-type */ 4295 return true; 4296 4297 /* @note for &array[i] */ 4298 case OARRAY: 4299 /* @todo evaluate target */ 4300 return true; 4301 4302 case ACOMMA: 4303 return islvalue(node->lhs) && islvalue(node->rhs); 4304 4305 default: 4306 return false; 4307 } 4308 } 4309 4310 /* @todo also mask int/float values in the tokenizer */ 4311 static uintmax_t 4312 maskint(int size, uintmax_t value) 4313 { 4314 if (size == 1) return value & 0xfful; 4315 if (size == 2) return value & 0xfffful; 4316 if (size == 4) return value & 0xfffffffful; 4317 4318 return value; 4319 } 4320 4321 static double 4322 maskfloat(int size, double value) 4323 { 4324 if (size == 4) return (double) (float) value; 4325 4326 return value; 4327 } 4328 4329 static uintmax_t 4330 convint(int srcsize, bool srcsigned, uintmax_t value) 4331 { 4332 if (!srcsigned) return value; 4333 if (srcsize == 1) return (uintmax_t) (int8_t ) value; 4334 if (srcsize == 2) return (uintmax_t) (int16_t) value; 4335 if (srcsize == 4) return (uintmax_t) (int32_t) value; 4336 4337 return value; 4338 } 4339 4340 static Node * 4341 conv(Env *env, Node *node); 4342 4343 static Node * 4344 wrap(Env *env, Type *type, Node *node) 4345 { 4346 Type *nodetype = node->type; 4347 4348 assert(type); 4349 4350 // @todo add error-reporting | refactor 4351 if (!nodetype) { 4352 printf("node has no type\n"); 4353 } 4354 4355 assert(nodetype); 4356 4357 /* @todo do proper type-check */ 4358 if (type->kind == nodetype->kind) 4359 return node; 4360 4361 if (node->kind == NUMBER) { 4362 /* @todo layout correct type-conversions ? */ 4363 if (isfloattype(nodetype)) { 4364 if (isfloattype(type)) { 4365 node->u.d = maskfloat( 4366 type->size, 4367 node->u.d 4368 ); 4369 4370 } else if (isintorbooltype(type)) { 4371 node->u.u = maskint( 4372 type->size, 4373 (intmax_t) node->u.d 4374 ); 4375 } 4376 } else if (isintorbooltype(nodetype)) { 4377 if (isfloattype(type)) { 4378 node->u.d = maskfloat( 4379 type->size, (double) 4380 (intmax_t) convint(node->type->size, 4381 !isunsignedtype(node->type), 4382 node->u.u 4383 ) 4384 ); 4385 4386 } else if (isintorbooltype(type)) { 4387 node->u.u = maskint( 4388 type->size, 4389 convint( 4390 nodetype->size, 4391 !isunsignedtype(nodetype), 4392 node->u.u 4393 ) 4394 ); 4395 } 4396 } 4397 4398 node->type = type; 4399 return node; 4400 } 4401 4402 /* @note no implicit (de-)referencing if the wrap-type is bool */ 4403 if (type->kind == TBOOL) 4404 goto doconversion; 4405 4406 /* @todo skip implicit (de-)referencing on arithmetic 4407 * conversion, also skip if called from conv() */ 4408 4409 /* implicit referencing: */ 4410 if (type->kind == TPTR && type->target->kind == nodetype->kind) { 4411 node = makenode(env->arenas, node, node); 4412 node->kind = OADDR; 4413 node->type = type->target; 4414 4415 /* @todo check for lvalue & maybe do further 4416 * type-checks*/ 4417 return node; 4418 } 4419 4420 /* implicit de-referencing: */ 4421 if (nodetype->kind == TPTR && nodetype->target->kind == type->kind) { 4422 node = makenode(env->arenas, node, node); 4423 node->kind = ODEREF; 4424 node->type = type; 4425 4426 /* @todo maybe do further type-checks*/ 4427 return node; 4428 } 4429 4430 doconversion: 4431 node = makenode(env->arenas, node, node); 4432 node->kind = ACONV; 4433 node->type = type; 4434 4435 return node; 4436 } 4437 4438 static Node * 4439 conv(Env *env, Node *node) 4440 { 4441 Type *ty = node->type; 4442 4443 assert(ty); 4444 4445 if (ty->kind == TINFER) 4446 return wrap(env, primitive(TINT), node); 4447 4448 if (ty->kind == TUINFER) 4449 return wrap(env, primitive(TUINT), node); 4450 4451 return node; 4452 } 4453 4454 4455 static bool 4456 arithtuplereorder(Env *env, Node *expr, int numops) 4457 { 4458 Node *tmp; 4459 4460 (void) env; 4461 4462 if (numops == 2) { 4463 if (expr->lhs->kind != ACOMMA) 4464 return false; 4465 4466 if (expr->rhs->kind != ACOMMA) 4467 return false; 4468 4469 /* (a, b) OP (x, y) ==> (a OP x, b OP y) */ 4470 expr->lhs->kind = expr->kind; 4471 expr->rhs->kind = expr->kind; 4472 expr->kind = ACOMMA; 4473 4474 tmp = expr->lhs->rhs; 4475 expr->lhs->rhs = expr->rhs->lhs; 4476 expr->rhs->lhs = tmp; 4477 4478 return true; 4479 } 4480 4481 if (numops == 1) { 4482 if (expr->lhs->kind != ACOMMA) 4483 return false; 4484 4485 /* OP (a, b) ==> (OP a, OP b) */ 4486 expr->lhs->kind = expr->kind; 4487 4488 tmp = expr->rhs; 4489 expr->rhs = makenode(env->arenas, expr, expr->lhs->rhs); 4490 expr->lhs->rhs = tmp; /* @note some unary nodes may have a rhs? */ 4491 expr->rhs->rhs = tmp; /* @todo make a copy */ 4492 expr->kind = ACOMMA; 4493 4494 return true; 4495 } 4496 4497 return false; 4498 } 4499 4500 static Type * 4501 typecheckdecl(Env *env, Decl *decl) 4502 { 4503 if (decl->kind == DPARAM || decl->kind == DVAR) { 4504 if (!decl->u.content) 4505 return decl->type; 4506 4507 decl->u.content = typecheck(env, decl->u.content); 4508 4509 if (decl->type->kind == TINFER) { 4510 decl->u.content = conv(env, decl->u.content); 4511 decl->type = decl->u.content->type; 4512 } else { 4513 decl->u.content = wrap(env, decl->type, decl->u.content); 4514 } 4515 } else if (decl->kind == DFUNCTION) { 4516 if (!decl->u.content) 4517 return decl->type; 4518 4519 assert(decl->contentenv); 4520 if (decl->contentenv->pending) 4521 return decl->type; 4522 4523 decl->u.content = typecheck(env, decl->u.content); 4524 } 4525 4526 return decl->type; 4527 } 4528 4529 static Node * 4530 substitutedispatch(Env *env, Node *expr) 4531 { 4532 #if 0 4533 /* This is wrong (tuple != comma-operator)*/ 4534 assert(expr->u.declref); 4535 assert(expr->type == expr->u.declref->type); 4536 4537 expr->kind = ACOMMA; 4538 expr->type = maketype(&expr->loc, primitive(TTUPLE), expr->lhs->type); 4539 4540 expr->rhs->kind = ADECLREF; 4541 expr->rhs->u.declref = expr->u.declref; 4542 expr->rhs->type = expr->type; 4543 4544 expr->type->u.rtarget = expr->lhs->type; 4545 return expr; 4546 #else 4547 Node *result = makenode(env->arenas, expr, NULL); 4548 result->kind = ADECLREF; 4549 result->u.declref = expr->u.declref; 4550 result->type = expr->type; 4551 4552 /* @fixme delete doesnt work (self is used multiple times) */ 4553 /* deletenode(expr); */ 4554 return result; 4555 #endif 4556 } 4557 4558 static Node * 4559 substitutedispatchcall(Env *env, Node *expr) 4560 { 4561 Decl *field = expr->lhs->u.declref; 4562 assert(field); 4563 4564 if (field->flags & MRECORDMEMBER) { 4565 expr->lhs->kind = ODISP; 4566 return expr; 4567 } 4568 4569 expr->lhs = substitutedispatch(env, expr->lhs); 4570 return expr; 4571 } 4572 4573 static Node * 4574 selfdispatchcall(Env *env, Node *expr) 4575 { 4576 Node *self, *probe, *insert; 4577 4578 assert(expr && expr->kind == OCALL); 4579 4580 if (expr->lhs->kind != ASELFDISP) 4581 return expr; 4582 4583 self = expr->lhs->lhs; 4584 assert(self); 4585 assert(self->type); 4586 4587 if (self->type->kind == TSTRUCT || self->type->kind == TUNION) { 4588 self = makenode(env->arenas, self, self); 4589 self->kind = OADDR; 4590 self->type = maketype( 4591 env->arenas, &self->loc, 4592 primitive(TINT), self->type); 4593 } else if (self->type->kind != TPTR) { 4594 error(&self->loc, "expected struct or union or pointer type"); 4595 } else if (self->type->target->kind != TSTRUCT && 4596 self->type->target->kind != TUNION) { 4597 error(&self->loc, "expected pointer to struct or union type"); 4598 } 4599 4600 if (!expr->rhs) { 4601 expr->rhs = self; 4602 return substitutedispatchcall(env, expr); 4603 } 4604 4605 if (expr->rhs->kind != ACOMMA) { 4606 insert = makenode(env->arenas, expr->rhs, self); 4607 insert->kind = ACOMMA; 4608 insert->rhs = expr->rhs; 4609 expr->rhs = insert; 4610 4611 return substitutedispatchcall(env, expr); 4612 } 4613 4614 probe = expr->rhs; 4615 while (probe->lhs && probe->lhs->kind == ACOMMA) 4616 probe = probe->lhs; 4617 4618 insert = makenode(env->arenas, probe, self); 4619 insert->rhs = probe->lhs; 4620 probe->lhs = insert; 4621 4622 return substitutedispatchcall(env, expr); 4623 } 4624 4625 static Node * 4626 resolvepending(Env *env, Node *expr) 4627 { 4628 Decl *decl; 4629 4630 assert(expr->kind == IDENT); 4631 4632 decl = finddeclaration(NULL, env, expr->u.key); 4633 4634 if (!decl) { 4635 error(&expr->loc, "'%s' undeclared", 4636 getstring(idents, expr->u.key)); 4637 4638 return expr; 4639 } 4640 4641 if (decl->kind != DVAR && decl->kind != DFUNCTION) { 4642 error(&expr->loc, "'%s' is not a variable nor a function", 4643 getstring(idents, expr->u.key)); 4644 4645 return expr; 4646 } 4647 4648 expr->kind = ADECLREF; 4649 expr->u.declref = decl; 4650 expr->type = decl->type; 4651 4652 return typecheck(env, expr); 4653 } 4654 4655 static Node * 4656 dispatch(Env *env, Node *expr, Node *parent) 4657 { 4658 Type *type; 4659 Decl *field; 4660 4661 /* @note might change in future */ 4662 assert(expr->lhs); 4663 type = expr->lhs->type; 4664 assert(type); 4665 4666 /* @todo maybe do implicit dereference */ 4667 if (type->kind == TPTR) { 4668 Node *lhs = makenode(env->arenas, expr->lhs, expr->lhs); 4669 lhs->kind = ADEREF; 4670 lhs->type = type->target; 4671 4672 type = type->target; 4673 expr->lhs = lhs; 4674 } 4675 4676 if (type->kind != TSTRUCT && type->kind != TUNION) { 4677 error(&expr->lhs->loc, "expected struct or union type"); 4678 return expr; 4679 } 4680 4681 /* @note might change in future */ 4682 assert(expr->rhs); 4683 assert(expr->rhs->kind == IDENT); 4684 4685 /* @note improvised for now */ 4686 assert(type->module->contentenv); 4687 field = finddeclinenv(expr->rhs->u.key, type->module->contentenv); 4688 4689 if (!field) { 4690 const char *typekind = type->kind == TSTRUCT ? "struct" : "union"; 4691 const char *modulename = getstring(idents, type->module->key); 4692 const char *fieldname = getstring(idents, expr->rhs->u.key); 4693 error(&expr->rhs->loc, "%s '%s' has no field '%s'", 4694 typekind, modulename, fieldname); 4695 expr->type = primitive(TERRTYPE); 4696 return expr; 4697 } 4698 4699 expr->type = field->type; 4700 expr->u.declref = field; 4701 4702 return expr; 4703 } 4704 4705 static void 4706 forloop(Env *env, Node *expr, Node *header) 4707 { 4708 if (header->kind == AFORSTEP) { 4709 Node *init = header->lhs; 4710 if (init->kind == ADECL) { 4711 Decl *it = init->u.declref; 4712 if (!it->u.content) { 4713 if (!isarithtype(it->type)) { 4714 error(&it->loc, 4715 "for loop variable must be initialized"); 4716 return; 4717 } 4718 it->u.content = makenode( 4719 env->arenas, header, NULL); 4720 it->u.content->kind = NUMBER; 4721 it->u.content->type = it->type; 4722 it->u.content->u.u = 0; 4723 } 4724 4725 header->lhs = conv(env, typecheck(env, header->lhs)); 4726 } 4727 4728 /* @todo do proper typechecking */ 4729 header->rhs = wrap( 4730 env, header->lhs->type, typecheck(env, header->rhs)); 4731 header->u.payload = wrap( 4732 env, header->lhs->type, 4733 typecheck(env, header->u.payload)); 4734 return; 4735 } 4736 4737 if (header->kind == AFOREACH) { 4738 4739 return; 4740 } 4741 4742 header = expr->u.payload = conv(env, typecheck(env, header)); 4743 4744 if (isarithtype(header->type)) { 4745 Decl *it; 4746 Node *forstep; 4747 4748 4749 it = makedecl2(&header->loc, env, 4750 getstringkey(&idents, "it", 2), DVAR); 4751 it->type = header->type; 4752 it->u.content = makenode(env->arenas, header, NULL); 4753 it->u.content->kind = NUMBER; 4754 it->u.content->type = header->type; 4755 it->u.content->u.u = 0; 4756 4757 forstep = makenode(env->arenas, header, NULL); 4758 forstep->kind = AFORSTEP; 4759 forstep->type = header->type; 4760 4761 forstep->lhs = makenode(env->arenas, header, NULL); 4762 forstep->lhs->kind = ADECL; 4763 forstep->lhs->u.declref = it; 4764 4765 forstep->rhs = header; 4766 4767 forstep->u.payload = makenode(env->arenas, header, NULL); 4768 forstep->u.payload->kind = NUMBER; 4769 forstep->u.payload->type = header->type; 4770 /* @todo handle negative step when possible 4771 * (i.e. when header is signed and constant) */ 4772 if (isfloattype(header->type)) 4773 forstep->u.payload->u.d = 1.0; 4774 else 4775 forstep->u.payload->u.u = 1; 4776 4777 expr->u.payload = forstep; 4778 return; 4779 } 4780 4781 /* @todo handle other cases (e.g. arrays/strings/lists/iterators) */ 4782 error(&expr->loc, "invalid loop header"); 4783 } 4784 4785 Node *parentnodes[1024]; 4786 int parenttop = 0; 4787 4788 static Node * 4789 typecheck(Env *env, Node *expr) 4790 { 4791 #define return return --parenttop, 4792 4793 Node *lhs = expr->lhs, *rhs = expr->rhs; 4794 4795 parentnodes[parenttop++] = expr; 4796 4797 #define errortype(condition) do { \ 4798 if (condition) { \ 4799 expr->type = primitive(TERRTYPE); \ 4800 return expr; \ 4801 } \ 4802 } while (0) 4803 4804 #define reporton(condition, loc, errormsg) do { \ 4805 if (condition) { \ 4806 error((loc), (errormsg)); \ 4807 expr->type = primitive(TERRTYPE); \ 4808 return expr; \ 4809 } \ 4810 } while (0) 4811 4812 switch (getnumops(expr->kind)) { 4813 case 2: 4814 assert(rhs); 4815 errortype(rhs->type->kind == TERRTYPE); 4816 rhs = typecheck(env, rhs); 4817 /* FALLTHROUGH */ 4818 case 1: 4819 assert(lhs); 4820 errortype(lhs->type->kind == TERRTYPE); 4821 lhs = typecheck(env, lhs); 4822 4823 if (arithtuplereorder(env, expr, getnumops(expr->kind))) 4824 goto joincomma; 4825 } 4826 4827 if (expr->type && expr->type->kind == TERRTYPE) 4828 return expr; 4829 4830 switch (expr->kind) { 4831 case ODISP: 4832 case ASELFDISP: 4833 lhs = typecheck(env, lhs); 4834 expr->lhs = conv(env, lhs); 4835 4836 if (parenttop > 1) 4837 return dispatch(env, expr, parentnodes[parenttop - 2]); 4838 4839 return dispatch(env, expr, NULL); 4840 4841 case OCALL: 4842 reporton(lhs->type->kind == TPTR && lhs->type->target->kind != TFUNCTION, 4843 &expr->loc, "operand is not a pointer to function"); 4844 4845 reporton(lhs->type->kind != TPTR && lhs->type->kind != TFUNCTION, 4846 &expr->loc, "operand is not a function"); 4847 4848 if (lhs->type->kind == TFUNCTION) 4849 expr->type = lhs->type->u.rtarget; 4850 else 4851 expr->type = lhs->type->target->u.rtarget; 4852 4853 expr = selfdispatchcall(env, expr); 4854 expr->rhs = typecheck(env, expr->rhs); 4855 return expr; 4856 4857 case OARRAY: 4858 expr->lhs = conv(env, lhs); 4859 reporton(lhs->type->kind != TARRAY && lhs->type->kind != TPTR, 4860 &expr->loc, "operand is not an array or pointer"); 4861 4862 expr->rhs = typecheck(env, rhs); 4863 4864 /* @todo handle negative indices when possible (use unsigned) */ 4865 reporton(!isinttype(rhs->type), 4866 &rhs->loc, "array index is not an integer"); 4867 4868 expr->rhs = wrap(env, primitive(TUSIZE), expr->rhs); 4869 4870 expr->type = lhs->type->target; 4871 return expr; 4872 4873 case OINC: case ODEC: case OSUFINC: case OSUFDEC: 4874 reporton(!islvalue(lhs), 4875 &expr->loc, "operand is not an lvalue"); 4876 4877 expr->lhs = conv(env, lhs); 4878 expr->type = lhs->type; 4879 return expr; 4880 4881 case ODEREF: 4882 expr->type = lhs->type; 4883 4884 reporton(expr->type->kind != TPTR, 4885 &expr->loc, "operand is not a pointer"); 4886 4887 expr->type = expr->type->target; 4888 return expr; 4889 4890 case OADDR: 4891 reporton(!islvalue(lhs), 4892 &expr->loc, "operand is not an lvalue"); 4893 4894 expr->type = maketype( 4895 env->arenas, &expr->loc, 4896 primitive(TPTR), lhs->type); 4897 return expr; 4898 4899 case OPLUS: case OMINUS: 4900 /* 4901 reporton(!isarithtype(lhs->type), 4902 &lhs->loc, "expression is not of arithmetic type"); 4903 */ 4904 4905 expr->lhs = conv(env, lhs); 4906 expr->type = lhs->type; 4907 return expr; 4908 4909 case OBNOT: 4910 reporton(!isintorbooltype(lhs->type), 4911 &lhs->loc, "expression is not of integer type"); 4912 4913 expr->lhs = conv(env, lhs); 4914 expr->type = lhs->type; 4915 return expr; 4916 4917 case OLNOT: 4918 reporton(!islogicaltype(lhs->type), 4919 &lhs->loc, "expression is not of logical type"); 4920 4921 expr->type = primitive(TBOOL); 4922 expr->lhs = conv(env, lhs); /* cannot be wrap(expr->type, lhs) */ 4923 return expr; 4924 4925 case OCAST: 4926 /* 4927 assert(rhs); 4928 assert(lhs->kind == TYPE); 4929 */ 4930 4931 if (arithtuplereorder(env, expr, 1)) 4932 goto joincomma; 4933 4934 /* expr->type = expr->lhs->type; */ 4935 return expr; 4936 4937 case OMUL: case ODIV: case OMOD: 4938 case OADD: case OSUB: 4939 reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type), 4940 &expr->loc, "expression is not of arithmetic type"); 4941 4942 /* usual arithmetic conversion */ 4943 if (lhs->type->kind < rhs->type->kind) 4944 expr->type = rhs->type; 4945 else 4946 expr->type = lhs->type; 4947 4948 expr->lhs = wrap(env, expr->type, lhs); 4949 expr->rhs = wrap(env, expr->type, rhs); 4950 return expr; 4951 4952 case OBAND: case OBOR: case OXOR: 4953 reporton(!isintorbooltype(lhs->type) || !isintorbooltype(rhs->type), 4954 &expr->loc, "expression is not of integer type"); 4955 4956 /* usual arithmetic conversion */ 4957 if (lhs->type->kind < rhs->type->kind) 4958 expr->type = rhs->type; 4959 else 4960 expr->type = lhs->type; 4961 4962 expr->lhs = wrap(env, expr->type, lhs); 4963 expr->rhs = wrap(env, expr->type, rhs); 4964 return expr; 4965 4966 case OLSH: case ORSH: case OARSH: 4967 reporton(!isinttype(lhs->type) || !isinttype(rhs->type), 4968 &expr->loc, "expression is not of integer type"); 4969 4970 expr->lhs = conv(env, lhs); 4971 expr->rhs = wrap(env, primitive(TINT), rhs); 4972 expr->type = lhs->type; 4973 return expr; 4974 4975 case OEQU: case ONEQ: 4976 case OLET: case OLEQ: 4977 case OGRT: case OGEQ: 4978 reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type), 4979 &expr->loc, "expression is not of arithmetic type"); 4980 4981 expr->lhs = conv(env, lhs); 4982 expr->rhs = conv(env, rhs); 4983 expr->type = primitive(TBOOL); 4984 return expr; 4985 4986 case OLAND: case OLOR: 4987 reporton(!islogicaltype(lhs->type) || !islogicaltype(rhs->type), 4988 &expr->loc, "expression is not of logical type"); 4989 4990 expr->type = primitive(TBOOL); 4991 expr->lhs = wrap(env, expr->type, lhs); 4992 expr->rhs = wrap(env, expr->type, rhs); 4993 return expr; 4994 4995 case OMULA: case ODIVA: case OMODA: 4996 case OADDA: case OSUBA: 4997 reporton(!isarithtype(lhs->type) || !isarithtype(rhs->type), 4998 &expr->loc, "expression is not of arithmetic type"); 4999 goto joinassign; 5000 5001 case OLSHA: case ORSHA: case OARSHA: 5002 case OANDA: 5003 case OORA: case OXORA: 5004 reporton(!isinttype(lhs->type) || !isinttype(rhs->type), 5005 &expr->loc, "expression is not of integer type"); 5006 /* FALLTHROUGH */ 5007 5008 case OASS: 5009 joinassign: 5010 reporton(!islvalue(lhs), 5011 &expr->loc, "left-hand-side is not an lvalue"); 5012 5013 expr->lhs = conv(env, lhs); 5014 expr->type = lhs->type; 5015 expr->rhs = wrap(env, expr->type, rhs); 5016 return expr; 5017 5018 case KIF: 5019 case KWHILE: 5020 case KUNTIL: 5021 assert(expr->u.payload); 5022 expr->u.payload = typecheck(env, expr->u.payload); 5023 expr->u.payload = wrap(env, primitive(TBOOL), expr->u.payload); 5024 5025 if (lhs) 5026 expr->lhs = typecheck(env, lhs); 5027 5028 if (rhs) 5029 expr->rhs = typecheck(env, rhs); 5030 5031 /* @todo find a way how we do type-checking for the 5032 * last expression in a statement-list, which 5033 * might be needed by the enclosed statement-list 5034 */ 5035 5036 expr->type = primitive(TVOID); 5037 return expr; 5038 5039 case KFOR: 5040 assert(expr->u.payload); 5041 forloop(env, expr, expr->u.payload); 5042 5043 if (lhs) 5044 expr->lhs = typecheck(env, lhs); 5045 5046 if (rhs) 5047 expr->rhs = typecheck(env, rhs); 5048 5049 /* @todo infer type of the for-loop like in the case above. */ 5050 5051 expr->type = primitive(TVOID); 5052 return expr; 5053 5054 case AENV: 5055 case ASCOPE: 5056 assert(lhs); 5057 assert(expr->u.env); 5058 5059 expr->lhs = typecheck(expr->u.env, lhs); 5060 return expr; 5061 5062 case ASTMT: 5063 rhs = expr; 5064 advancestmt: 5065 lhs = typecheck(env, lhs); 5066 rhs->lhs = lhs; 5067 5068 if (rhs->rhs) { 5069 assert(rhs->rhs->kind == ASTMT); 5070 rhs = rhs->rhs, lhs = rhs->lhs; 5071 goto advancestmt; 5072 } 5073 return expr; 5074 5075 case ADECL: 5076 expr->type = typecheckdecl(env, expr->u.declref); 5077 return expr; 5078 5079 case ADECLREF: 5080 /* @note propagate type changes from ADECL to ADECLREF */ 5081 expr->type = expr->u.declref->type; 5082 return expr; 5083 5084 case AADDR: 5085 case ADEREF: 5086 assert(lhs); 5087 lhs = typecheck(env, lhs); 5088 5089 expr->lhs = conv(env, lhs); 5090 return expr; 5091 5092 case ACOMPOUND: 5093 assert(lhs); 5094 assert(rhs); 5095 5096 expr->lhs = typecheck(env, lhs); 5097 expr->type = lhs->type; 5098 expr->rhs = typecheck(env, rhs); 5099 return expr; 5100 5101 case AFIELDINIT: 5102 assert(expr->rhs); 5103 expr->rhs = typecheck(env, rhs); 5104 return expr; 5105 5106 case IDENT: 5107 return resolvepending(env, expr); 5108 5109 joincomma: 5110 lhs = expr->lhs; 5111 rhs = expr->rhs; 5112 /* FALLTHROUGH */ 5113 case ACOMMA: 5114 assert(lhs); 5115 assert(rhs); 5116 5117 /* @todo make sure that typechecking is done 5118 * correctly, since comma might be re- 5119 * ordered: 5120 * - check that maketype is NOT called 5121 * multiple times and/or discarded on 5122 * the same node. 5123 * - check wether the resulting type 5124 * does account for nesting on rhs */ 5125 errortype(lhs->type->kind == TERRTYPE); 5126 errortype(rhs->type->kind == TERRTYPE); 5127 5128 lhs = typecheck(env, lhs); 5129 rhs = typecheck(env, rhs); 5130 5131 /* @note converting nodes may be uneccessary */ 5132 expr->lhs = conv(env, lhs); 5133 expr->rhs = conv(env, rhs); 5134 5135 expr->type = maketype( 5136 env->arenas, &expr->loc, 5137 primitive(TTUPLE), lhs->type); 5138 expr->type->u.rtarget = rhs->type; 5139 return expr; 5140 5141 case KBITCAST: 5142 assert(lhs); 5143 assert(rhs); 5144 5145 expr->lhs = lhs = typecheck(env, lhs); 5146 5147 errortype(lhs->type->kind == TERRTYPE); 5148 errortype(rhs->type->kind == TERRTYPE); 5149 reporton(rhs->kind != TYPE, &rhs->loc, "expected type"); 5150 5151 expr->type = rhs->type; 5152 return expr; 5153 5154 case KSIZEOF: 5155 case KALIGNOF: 5156 case KLENGTHOF: 5157 assert(lhs); 5158 5159 expr->lhs = lhs = typecheck(env, lhs); 5160 errortype(lhs->type->kind == TERRTYPE); 5161 5162 expr->type = primitive(TUSIZE); 5163 return expr; 5164 5165 case KRETURN: 5166 rhs = expr->rhs; 5167 5168 if (rhs) { 5169 expr->rhs = rhs = typecheck(env, rhs); 5170 errortype(rhs->type->kind == TERRTYPE); 5171 } 5172 5173 do { 5174 Env *funcenv = getfuncenv(env); 5175 Type *functype; 5176 5177 reporton( 5178 !funcenv, &expr->loc, 5179 "return statement is not inside a function"); 5180 5181 assert(funcenv->envdecl); 5182 assert(funcenv->envdecl->type); 5183 5184 functype = funcenv->envdecl->type; 5185 5186 assert(functype->kind == TFUNCTION); 5187 assert(functype->u.rtarget); 5188 5189 expr->type = functype->u.rtarget; 5190 } while (0); 5191 5192 reporton(expr->type->kind == TVOID && 5193 rhs && rhs->type->kind != TVOID, 5194 &expr->loc, "expected no return value"); 5195 5196 reporton(expr->type->kind != TVOID && 5197 (!rhs || rhs->type->kind == TVOID), 5198 &expr->loc, "expected return value"); 5199 5200 if (rhs) 5201 expr->lhs = wrap(env, expr->type, rhs); 5202 5203 return expr; 5204 5205 default: 5206 return expr; 5207 } 5208 5209 #undef errortype 5210 #undef reporton 5211 #undef return 5212 } 5213 5214 static Node * 5215 foldexpr(Env *env, Node *expr); 5216 5217 static Node * 5218 folddeclaration(Env *env, Node *expr) 5219 { 5220 Decl *decl = expr->u.declref; 5221 5222 assert(decl); 5223 5224 if (decl->kind == DFUNCTION) { 5225 if (decl->u.content) 5226 /* @todo make sure the correct env is used */ 5227 decl->u.content = foldexpr(env, decl->u.content); 5228 5229 } else if (decl->kind == DPARAM || decl->kind == DVAR) { 5230 5231 /* @todo remove condition. it is only for testing structs. 5232 * content may not be NULL otherwise (needs validation) */ 5233 if (decl->u.content) 5234 decl->u.content = foldexpr(env, decl->u.content); 5235 } 5236 5237 return expr; 5238 } 5239 5240 static Node * 5241 folddispatch(Env *env, Node *expr) 5242 { 5243 Node *lhs = expr->lhs, *rhs = expr->rhs; 5244 Decl *field = expr->u.declref; 5245 5246 assert(expr->kind == ODISP && lhs->kind == TYPE); 5247 assert(field); 5248 5249 /* @note field decl is already assigned to 5250 * expr->u.declref by dispatch() */ 5251 expr->kind = ADECLREF; 5252 expr->rhs = NULL; 5253 expr->lhs = NULL; 5254 /* deletenode(lhs); */ 5255 /* deletenode(rhs); */ 5256 return foldexpr(env, expr); 5257 } 5258 5259 static Node * 5260 foldexpr(Env *env, Node *expr) 5261 { 5262 Node *lhs = expr->lhs, *rhs = expr->rhs; 5263 Type *ty = expr->type; 5264 5265 5266 #define evalbinary(op) do { \ 5267 expr->kind = NUMBER; \ 5268 if (isfloattype(ty)) \ 5269 expr->u.d = maskfloat(ty->size, \ 5270 maskfloat(ty->size, lhs->u.d) op \ 5271 maskfloat(ty->size, rhs->u.d) \ 5272 ); \ 5273 else if (isintorbooltype(ty)) \ 5274 expr->u.u = maskint(ty->size, \ 5275 maskint(ty->size, lhs->u.u) op \ 5276 maskint(ty->size, rhs->u.u) \ 5277 ); \ 5278 deletenode(lhs); \ 5279 deletenode(rhs); \ 5280 } while (0) 5281 5282 #define isvalue(expr, value) (expr->kind == NUMBER && \ 5283 ((expr->u.u == value && isintorbooltype(ty)) || \ 5284 (expr->u.d == value && isarithtype(ty)))) 5285 5286 /* @todo maybe modify getnumops() in such a way, that it 5287 * will behave properly for non-operator nodes too */ 5288 switch (getnumops(expr->kind)) { 5289 case 2: 5290 rhs = foldexpr(env, rhs); 5291 /* FALLTHROUGH */ 5292 case 1: 5293 if (expr->kind == ODISP && lhs->kind == TYPE) 5294 return folddispatch(env, expr); 5295 lhs = foldexpr(env, lhs); 5296 } 5297 5298 switch ((int) expr->kind) { 5299 case OADD: case OSUB: 5300 if (lhs->kind == NUMBER && rhs->kind == NUMBER) { 5301 if (expr->kind == OADD) evalbinary(+); 5302 else evalbinary(-); 5303 } else if (isvalue(lhs, 0)) { 5304 if (expr->kind == OADD) { 5305 *expr = *rhs; 5306 deletenode(lhs); 5307 deletenode(rhs); 5308 } else { 5309 expr->kind = OMINUS; 5310 expr->lhs = rhs; 5311 deletenode(lhs); 5312 } 5313 } else if (isvalue(rhs, 0)) { 5314 *expr = *lhs; 5315 deletenode(lhs); deletenode(rhs); 5316 } 5317 5318 return expr; 5319 5320 case OMUL: case ODIV: case OMOD: 5321 if (lhs->kind == NUMBER && rhs->kind == NUMBER) { 5322 if (expr->kind == OMUL) { 5323 evalbinary(*); 5324 } else { 5325 if (rhs->u.u == 0 && isintorbooltype(ty)) { 5326 error( 5327 &expr->loc, 5328 "division by zero" 5329 ); 5330 } else if (expr->kind == ODIV) { 5331 evalbinary(/); 5332 } else { 5333 /* @todo implement modulus for 5334 * float-types */ 5335 evalbinary(/); 5336 } 5337 } 5338 } else if (isvalue(lhs, 0)) { 5339 *expr = *lhs; 5340 deletenode(lhs); 5341 deletenode(rhs); 5342 } else if (expr->kind == OMUL && isvalue(rhs, 0)) { 5343 *expr = *rhs; 5344 deletenode(lhs); 5345 deletenode(rhs); 5346 } else if (isvalue(rhs, 0)) { 5347 if (rhs->u.u == 0 && isintorbooltype(ty)) 5348 error(&expr->loc, "division by zero"); 5349 *expr = *rhs; 5350 deletenode(lhs); 5351 deletenode(rhs); 5352 } else if (isvalue(lhs, 1)) { 5353 *expr = *rhs; 5354 deletenode(lhs); 5355 deletenode(rhs); 5356 } else if (expr->kind == OMUL && isvalue(rhs, 1)) { 5357 *expr = *lhs; 5358 deletenode(lhs); 5359 deletenode(rhs); 5360 } 5361 5362 return expr; 5363 5364 case OPLUS: 5365 *expr = *lhs; 5366 5367 deletenode(lhs); 5368 return expr; 5369 5370 case OMINUS: 5371 if (lhs->kind == NUMBER) { 5372 if (isfloattype(ty)) { 5373 expr->kind = NUMBER; 5374 expr->u.d = maskfloat(ty->size, -lhs->u.d); 5375 deletenode(lhs); 5376 } else if (isintorbooltype(ty)) { 5377 expr->kind = NUMBER; 5378 expr->u.u = maskint(ty->size, -lhs->u.u); 5379 deletenode(lhs); 5380 } 5381 } else if (lhs->kind == OMINUS && lhs->lhs) { 5382 *expr = *lhs->lhs; 5383 deletenode(lhs); 5384 } 5385 5386 return expr; 5387 5388 case OBAND: case OBOR: case OXOR: 5389 if (lhs->kind == NUMBER && rhs->kind == NUMBER) { 5390 assert(isintorbooltype(lhs->type)); 5391 assert(isintorbooltype(rhs->type)); 5392 lhs->u.u = maskint(ty->size, lhs->u.u); 5393 rhs->u.u = maskint(ty->size, rhs->u.u); 5394 if (expr->kind == OBAND) 5395 expr->u.u = lhs->u.u & rhs->u.u; 5396 else if (expr->kind == OBOR) 5397 expr->u.u = lhs->u.u | rhs->u.u; 5398 else 5399 expr->u.u = lhs->u.u ^ rhs->u.u; 5400 expr->kind = NUMBER; 5401 expr->u.u = maskint(ty->size, expr->u.u); 5402 } 5403 5404 return expr; 5405 5406 case ASCOPE: 5407 assert(expr->lhs); 5408 assert(expr->u.env); 5409 5410 expr->lhs = foldexpr(expr->u.env, expr->lhs); 5411 return expr; 5412 5413 case ASTMT: 5414 rhs = expr; 5415 advancestmt: 5416 lhs = foldexpr(env, lhs); 5417 rhs->lhs = lhs; 5418 5419 if (rhs->rhs) { 5420 assert(rhs->rhs->kind == ASTMT); 5421 rhs = rhs->rhs, lhs = rhs->lhs; 5422 goto advancestmt; 5423 } 5424 5425 return expr; 5426 5427 case ACOMPOUND: 5428 expr->rhs = foldexpr(env, rhs); 5429 return expr; 5430 5431 case AFIELDINIT: 5432 expr->rhs = foldexpr(env, rhs); 5433 return expr; 5434 5435 case ACOMMA: 5436 expr->lhs = foldexpr(env, lhs); 5437 expr->rhs = foldexpr(env, rhs); 5438 return expr; 5439 5440 case KRETURN: 5441 expr->rhs = foldexpr(env, rhs); 5442 return expr; 5443 5444 case KSIZEOF: 5445 case KALIGNOF: 5446 case KLENGTHOF: 5447 assert(lhs); 5448 5449 expr->lhs = NULL; 5450 if (expr->kind == KSIZEOF) { 5451 expr->u.u = lhs->type->size; 5452 5453 } else if (expr->kind == KALIGNOF) { 5454 expr->u.u = lhs->type->align; 5455 5456 } else /* if (expr->kind == KLENGTHOF) */ { 5457 5458 /* @todo add case for slice */ 5459 if (lhs->type->kind == TARRAY) 5460 expr->u.u = lhs->type->u.array.length; 5461 else if (lhs->type->kind == TPTR) { 5462 expr->u.u = 1; 5463 } else { 5464 expr->u.u = 0; 5465 } 5466 } 5467 5468 deletenode(lhs); 5469 /* @todo delete type */ 5470 expr->type = prim + TUSIZE; 5471 expr->kind = NUMBER; 5472 return expr; 5473 5474 case ACONV: 5475 /* @todo implement this properly! */ 5476 lhs = foldexpr(env, lhs); 5477 if (lhs->type->kind == expr->type->kind) 5478 *expr = *lhs, deletenode(lhs); 5479 5480 return expr; 5481 5482 case ADECL: 5483 return folddeclaration(env, expr); 5484 5485 case TYPE: 5486 error(&expr->loc, "exptected expression, not type"); 5487 /* FALLTHROUGH */ 5488 5489 default: 5490 return expr; 5491 } 5492 } 5493 5494 5495 5496 // }}} 5497 5498 // @section data-flow analysis {{{ 5499 5500 /* 5501 In order to do DFA, we divide the code of a scope into sections. 5502 For each section there will be a DF-Conduct associated with it. 5503 5504 */ 5505 5506 static Block * 5507 makeblock(BlockKind kind, Env *env) 5508 { 5509 Block *block = myalloc(&env->arenas->block, Block); 5510 5511 block->kind = kind; 5512 block->env = env; 5513 5514 return block; 5515 } 5516 5517 static Conduct * 5518 makeconduct(Env *env, ConductKind kind, Node *label) 5519 { 5520 Conduct *conduct = myalloc(&env->arenas->conduct, Conduct); 5521 5522 conduct->kind = kind; 5523 conduct->label = label; 5524 5525 return conduct; 5526 } 5527 5528 static void 5529 transfergists(Env *env, Conduct *source, Conduct *dest); 5530 5531 static void 5532 appendconduct(Block *parent, ConductKind kind, Node *label) 5533 { 5534 Conduct *conduct = makeconduct(parent->env, kind, label); 5535 5536 if (!parent) 5537 return; 5538 5539 conduct->parent = parent; 5540 5541 listappend(parent, conduct); 5542 5543 if (conduct->prev) 5544 transfergists(parent->env, conduct->prev, conduct); 5545 } 5546 5547 static void 5548 appendblock(Conduct *parent, BlockKind kind, Env *env) 5549 { 5550 Block *block = makeblock(kind, env); 5551 5552 appendconduct(block, CSCOPE, NULL); 5553 5554 if (!parent) 5555 return; 5556 5557 block->parent = parent; 5558 5559 listappend(parent, block); 5560 5561 transfergists(env, parent, block->tail); 5562 } 5563 5564 static Gist * 5565 makegist(Env *env, Decl *decl, Node *where, bool init) 5566 { 5567 Gist *gist = myalloc(&env->arenas->gist, Gist); 5568 5569 gist->decl = decl; 5570 gist->where = where; 5571 gist->init = init; 5572 5573 return gist; 5574 } 5575 5576 static void 5577 appendgist(Conduct *conduct, Gist *info) 5578 { 5579 info->parent = conduct; 5580 5581 listappendex(conduct, info, gists.head, gists.tail, prev, next); 5582 } 5583 5584 static void 5585 transfergists(Env *env, Conduct *source, Conduct *dest) 5586 { 5587 Gist *info; 5588 5589 for (info = source->gists.head; info; info = info->next) { 5590 Gist *copy = makegist(env, NULL, NULL, false); 5591 5592 *copy = *info; 5593 5594 appendgist(dest, copy); 5595 } 5596 } 5597 5598 static Gist * 5599 getgist(Conduct *conduct, Decl *decl) 5600 { 5601 Gist *probe; 5602 assert(conduct); 5603 5604 for (probe = conduct->gists.head; probe; probe = probe->next) { 5605 if (probe->decl == decl) 5606 return probe; 5607 } 5608 5609 return NULL; 5610 } 5611 5612 static void 5613 gistread(Conduct *conduct, Node *node) 5614 { 5615 const char *name; 5616 Decl *decl; 5617 Gist *info; 5618 5619 if (!node || (node->kind != ADECLREF && node->kind != ADECL)) 5620 return; 5621 5622 decl = node->u.declref; 5623 5624 /* @note additional checks require that this moves 5625 * somewhere else. */ 5626 if ( decl->kind == DPARAM || 5627 (decl->kind == DVAR && 5628 decl->parentenv && 5629 decl->parentenv->kind == STOPLEVEL)) 5630 return; 5631 5632 name = getstring(idents, decl->key); 5633 info = getgist(conduct, decl); 5634 5635 if (info) { 5636 Node *where = info->where; 5637 5638 if (info->init) 5639 return; 5640 5641 assert(where); 5642 error(&node->loc, "use of un-initialized '%s'.", name); 5643 /* @todo change to notice or similiar, 5644 * instead of warn */ 5645 warn(&where->loc, "last use of '%s' was here.", name); 5646 } else { 5647 error(&node->loc, "use of un-initialized '%s'.", name); 5648 } 5649 } 5650 5651 static void 5652 gistwrite(Env *env, Conduct *conduct, Node *node, bool init) 5653 { 5654 Decl *decl; 5655 Gist *info; 5656 5657 if (!node || (node->kind != ADECLREF && node->kind != ADECL)) 5658 return; 5659 5660 decl = node->u.declref; 5661 5662 info = getgist(conduct, decl); 5663 if (!info) { 5664 info = makegist(env, decl, node, init); 5665 appendgist(conduct, info); 5666 return; 5667 } 5668 5669 info->init = init; 5670 info->where = node; 5671 } 5672 5673 static void 5674 fetchblocks(Block *block, Node *expr); 5675 5676 static void 5677 fetchscoped(Conduct *conduct, Node *expr, BlockKind kind) 5678 { 5679 if (expr && expr->kind == ASCOPE) { 5680 appendblock(conduct, kind, expr->u.env); 5681 fetchblocks(conduct->tail, expr->lhs); 5682 5683 } else if (expr) { 5684 assert(conduct->parent); 5685 assert(conduct->parent->env); 5686 5687 appendblock(conduct, kind, conduct->parent->env); 5688 fetchblocks(conduct->tail, expr); 5689 } 5690 } 5691 5692 static void 5693 fetchblocks(Block *block, Node *expr) 5694 { 5695 Node *lhs, *rhs; 5696 5697 assert(expr); 5698 assert(block); 5699 assert(block->tail); 5700 5701 lhs = expr->lhs; 5702 rhs = expr->rhs; 5703 5704 switch (expr->kind) { 5705 /* unary read */ 5706 case ODEREF: 5707 case OPLUS: case OMINUS: 5708 case OBNOT: 5709 case OLNOT: 5710 case OCAST: 5711 fetchblocks(block, lhs); 5712 gistread(block->tail, lhs); 5713 return; 5714 5715 /* unary read/write */ 5716 case OINC: case ODEC: 5717 case OSUFINC: case OSUFDEC: 5718 fetchblocks(block, lhs); 5719 gistread(block->tail, lhs); 5720 gistwrite(block->env, block->tail, lhs, true); 5721 return; 5722 5723 /* binary read */ 5724 case OMUL: case ODIV: case OMOD: 5725 case OADD: case OSUB: 5726 case OBAND: case OBOR: case OXOR: 5727 case OLSH: case ORSH: case OARSH: 5728 case OEQU: case ONEQ: 5729 case OLET: case OLEQ: 5730 case OGRT: case OGEQ: 5731 case OLAND: case OLOR: 5732 fetchblocks(block, lhs); 5733 gistread(block->tail, lhs); 5734 5735 fetchblocks(block, rhs); 5736 gistread(block->tail, rhs); 5737 return; 5738 5739 5740 /* binary write */ 5741 case OASS: 5742 fetchblocks(block, rhs); 5743 gistread(block->tail, rhs); 5744 5745 fetchblocks(block, lhs); 5746 gistwrite(block->env, block->tail, lhs, true); 5747 return; 5748 5749 /* binary read/write */ 5750 case OMULA: case ODIVA: case OMODA: 5751 case OADDA: case OSUBA: 5752 case OLSHA: case ORSHA: case OARSHA: 5753 case OANDA: 5754 case OORA: case OXORA: 5755 fetchblocks(block, rhs); 5756 gistread(block->tail, rhs); 5757 5758 fetchblocks(block, lhs); 5759 gistread(block->tail, lhs); 5760 gistwrite(block->env, block->tail, lhs, true); 5761 return; 5762 5763 case ASTMT: 5764 advancestmt: 5765 assert(lhs); 5766 5767 fetchblocks(block, lhs); 5768 5769 if (expr->rhs) { 5770 assert(expr->rhs->kind == ASTMT); 5771 expr = expr->rhs, lhs = expr->lhs; 5772 goto advancestmt; 5773 } 5774 return; 5775 5776 case ADECL: 5777 assert(expr->u.declref); 5778 lhs = expr->u.declref->u.content; 5779 5780 if (expr->u.declref->kind == DFUNCTION) { 5781 fetchscoped(block->tail, lhs, BFUNCTION); 5782 appendconduct(block, CSCOPE, NULL); 5783 } else if (lhs) { 5784 appendblock(block->tail, BSCOPE, block->env); 5785 fetchblocks(block->tail->tail, lhs); 5786 appendconduct(block, CSCOPE, NULL); 5787 } 5788 5789 gistwrite(block->env, block->tail, expr, !!lhs); 5790 return; 5791 5792 case ASCOPE: 5793 assert(lhs); 5794 5795 appendblock(block->tail, BSCOPE, expr->u.env); 5796 fetchblocks(block->tail->tail, lhs); 5797 appendconduct(block, CSCOPE, NULL); 5798 return; 5799 5800 case ACOMMA: 5801 assert(lhs); 5802 assert(rhs); 5803 5804 /* @note is this correct? */ 5805 fetchblocks(block, lhs); 5806 fetchblocks(block, rhs); 5807 return; 5808 5809 case KIF: 5810 assert(lhs); 5811 assert(expr->u.payload); 5812 5813 fetchscoped(block->tail, lhs, BIF); 5814 if (rhs) 5815 fetchscoped(block->tail, rhs, BELSE); 5816 5817 appendconduct(block, CSCOPE, NULL); 5818 return; 5819 5820 case KDO: 5821 return; 5822 5823 case KLOOP: 5824 return; 5825 5826 case ALOOPUNTIL: 5827 return; 5828 5829 case KBREAK: 5830 block->tail->doesbreak = true; 5831 goto joinctrltransfer; 5832 5833 case KCONTINUE: 5834 block->tail->doescontinue = true; 5835 goto joinctrltransfer; 5836 5837 case KRETURN: 5838 block->tail->doesreturn = true; 5839 goto joinctrltransfer; 5840 5841 case KGOTO: 5842 block->tail->doesjump = true; 5843 joinctrltransfer: 5844 appendconduct(block, CUNREACH, NULL); 5845 return; 5846 5847 default: 5848 case OADDR: 5849 return; 5850 } 5851 } 5852 5853 #if 0 5854 static void 5855 debugprintconduct(Conduct *conduct, int indent); 5856 5857 static void 5858 debugprintblock(Block *block, int indent) 5859 { 5860 Block *curr; 5861 assert(block); 5862 5863 for (curr = block; curr; curr = curr->next) { 5864 int i; 5865 5866 for (i = 0; i < indent; ++i) { 5867 printf("\t"); 5868 } 5869 5870 switch (curr->kind) { 5871 case BTOPLEVEL: printf("\x1b[31mblock<toplevel>\x1b[0m\n"); break; 5872 case BFUNCTION: printf("\x1b[31mblock<function>\x1b[0m\n"); break; 5873 case BSCOPE: printf("\x1b[31mblock<scope>\x1b[0m\n"); break; 5874 case BIF: printf("\x1b[31mblock<if>\x1b[0m\n"); break; 5875 case BLOOP: printf("\x1b[31mblock<loop>\x1b[0m\n"); break; 5876 case BWHILELOOP: printf("\x1b[31mblock<while-loop>\x1b[0m\n"); break; 5877 case BLOOPUNTIL: printf("\x1b[31mblock<loop-until>\x1b[0m\n"); break; 5878 case BFORLOOP: printf("\x1b[31mblock<for-loop>\x1b[0m\n"); break; 5879 case BELSE: printf("\x1b[31mblock<else>\x1b[0m\n"); break; 5880 } 5881 5882 if (curr->head) 5883 debugprintconduct(curr->head, indent); 5884 } 5885 } 5886 5887 static void 5888 debugprintconduct(Conduct *conduct, int indent) 5889 { 5890 Conduct *curr; 5891 assert(conduct); 5892 5893 for (curr = conduct; curr; curr = curr->next) { 5894 int i; 5895 5896 for (i = 0; i < indent; ++i) { 5897 printf("\t"); 5898 } 5899 5900 switch (curr->kind) { 5901 case CUNREACH: printf("\x1b[34mconduct<unreach>\x1b[0m\n"); break; 5902 case CSCOPE: printf("\x1b[34mconduct<scope>\x1b[0m\n"); break; 5903 case CLABEL: printf("\x1b[34mconduct<label>\x1b[0m\n"); break; 5904 case CBLOCK: 5905 break; 5906 } 5907 5908 if (curr->head) 5909 debugprintblock(curr->head, indent + 1); 5910 } 5911 } 5912 #else 5913 static void 5914 debugprintblock(Block *block, int indent) 5915 { 5916 (void) block; 5917 (void) indent; 5918 } 5919 #endif 5920 5921 static void 5922 dataflow(Block *block, Node *expr) 5923 { 5924 assert(expr); 5925 5926 fetchblocks(block, expr); 5927 5928 debugprintblock(block, 0); 5929 } 5930 5931 5932 5933 /* @section data-flow analysis version 2 */ 5934 5935 #if 0 5936 5937 static void 5938 fetchsections(Analysis *analysis, Node *expr) 5939 { 5940 Node *lhs, *rhs; 5941 5942 nextnode: 5943 switch (expr->kind) { 5944 default: 5945 break; 5946 } 5947 } 5948 5949 static void 5950 dataflow2(Analysis *analysis, Node *expr) 5951 { 5952 assert(expr); 5953 5954 fetchsections(analysis, expr); 5955 } 5956 5957 #endif 5958 5959 5960 5961 // }}} 5962 5963 5964 // @section extract nested functions {{{ 5965 5966 Node *extracted[1024 * 4]; 5967 int extractedtop = 0; 5968 5969 static bool 5970 isnestedfunction(Env *startenv) 5971 { 5972 Env *env; 5973 int n = 0; 5974 5975 for (env = startenv; env; env = env->below) { 5976 if (env->kind == SFUNCTION) 5977 ++n; 5978 } 5979 5980 return n > 1; 5981 } 5982 5983 static void 5984 extractnfs(Env *env, Node *expr); 5985 5986 static void 5987 substituenfs(Env *env, Node *expr) 5988 { 5989 Decl *decl = expr->u.declref; 5990 Node *enlist = NULL; 5991 5992 assert(decl); 5993 5994 if (decl->u.content) { 5995 env = decl->contentenv ? decl->contentenv : env; 5996 extractnfs(env, decl->u.content); 5997 } 5998 5999 if (decl->kind == DFUNCTION && isnestedfunction(decl->contentenv)) { 6000 enlist = makenode(env->arenas, expr, NULL); 6001 expr->kind = ADECLREF; 6002 6003 assert(extractedtop < lengthof(extracted)); 6004 extracted[extractedtop++] = enlist; 6005 } 6006 } 6007 6008 static void 6009 extractnfs(Env *env, Node *expr) 6010 { 6011 advance: 6012 assert(expr); 6013 6014 if (isoperator(expr->kind)) { 6015 switch (getnumops(expr->kind)) { 6016 case 3: 6017 assert(expr->u.payload); 6018 extractnfs(env, expr->u.payload); 6019 /* FALLTHROUGH */ 6020 case 2: 6021 assert(expr->rhs); 6022 extractnfs(env, expr->rhs); 6023 /* FALLTHROUGH */ 6024 case 1: 6025 assert(expr->lhs); 6026 extractnfs(env, expr->lhs); 6027 } 6028 return; 6029 } 6030 6031 switch (expr->kind) { 6032 case KRETURN: 6033 case KIF: 6034 case KCASE: 6035 case KOF: 6036 case KDO: 6037 case KFOR: 6038 case KLOOP: 6039 case KWHILE: 6040 case KUNTIL: 6041 case AFORSTEP: 6042 case AFOREACH: 6043 case ALOOPUNTIL: 6044 if (expr->u.payload) 6045 extractnfs(env, expr->u.payload); 6046 if (expr->lhs) 6047 extractnfs(env, expr->lhs); 6048 if (expr->rhs) 6049 extractnfs(env, expr->rhs); 6050 break; 6051 case ADEREF: 6052 case ACONV: 6053 case ASELFDISP: 6054 assert(expr->lhs); 6055 extractnfs(env, expr->lhs); 6056 break; 6057 case ACOMMA: 6058 assert(expr->lhs); 6059 assert(expr->rhs); 6060 extractnfs(env, expr->lhs); 6061 extractnfs(env, expr->rhs); 6062 break; 6063 case ASTMT: 6064 assert(expr->lhs); 6065 extractnfs(env, expr->lhs); 6066 if (expr->rhs) { 6067 expr = expr->rhs; 6068 goto advance; 6069 } 6070 break; 6071 case ADECL: 6072 substituenfs(env, expr); 6073 break; 6074 case AENV: 6075 case ASCOPE: 6076 assert(expr->lhs); 6077 assert(expr->u.env); 6078 extractnfs(expr->u.env, expr->lhs); 6079 break; 6080 case TYPE: /* @note is this correct? */ 6081 case CHAR: 6082 case NUMBER: 6083 case STRING: 6084 case ADECLREF: 6085 case IDENT: /* @note is this correct? */ 6086 break; 6087 6088 case ACOMPOUND: 6089 /* @todo extract within type (lhs)? */ 6090 assert(expr->rhs); 6091 extractnfs(env, expr->lhs); 6092 break; 6093 6094 case AFIELDINIT: 6095 assert(expr->rhs); 6096 extractnfs(env, expr->rhs); 6097 break; 6098 6099 case KSTRUCT: 6100 case KUNION: 6101 assert(expr->rhs); 6102 extractnfs(env, expr->rhs); 6103 break; 6104 6105 case KBREAK: 6106 case KCONTINUE: 6107 case KGOTO: 6108 break; 6109 6110 case KSIZEOF: 6111 case KALIGNOF: 6112 /* @todo check for nested functions and report error */ 6113 break; 6114 6115 default: 6116 error(&expr->loc, "internal error: unknown expression kind" 6117 " (%s).", nodestrings[expr->kind]); 6118 break; 6119 } 6120 } 6121 6122 static Node * 6123 extractnestedfunctions(Env *env, Node *expr) 6124 { 6125 extractedtop = 0; 6126 6127 extractnfs(env, expr); 6128 6129 assert(extractedtop < lengthof(extracted)); 6130 extracted[extractedtop++] = expr; 6131 return expr; 6132 } 6133 6134 // }}} 6135 6136 // @section c code generation {{{ 6137 6138 static void 6139 codegen(CodeGen *cg, Node *expr); 6140 6141 static void 6142 cgindent(CodeGen *cg) 6143 { 6144 int i; 6145 6146 for (i = 0; i < cg->indent; ++i) { 6147 fprintf(cg->out, "\t"); 6148 } 6149 } 6150 6151 static void 6152 cgprintf(CodeGen *cg, const char *fmt, ...) 6153 { 6154 va_list ap; 6155 6156 (void) cg; 6157 va_start(ap, fmt); 6158 vfprintf(cg->out, fmt, ap); 6159 va_end(ap); 6160 } 6161 6162 static void 6163 cginit(CodeGen *cg, FILE *out) 6164 { 6165 cg->out = out; 6166 cg->indent = 0; 6167 cg->commacount = 0; 6168 cg->needsvalue = false; 6169 cg->hasclause = false; 6170 cg->valuename = NULL; 6171 6172 assert(cg->out); 6173 6174 cgprintf(cg, "#include <assert.h>\n"); 6175 cgprintf(cg, "#include <stdarg.h>\n"); 6176 cgprintf(cg, "#include <stdbool.h>\n"); 6177 cgprintf(cg, "#include <stdint.h>\n"); 6178 cgprintf(cg, "#include <stdio.h>\n"); 6179 cgprintf(cg, "#include <stdlib.h>\n"); 6180 cgprintf(cg, "#include <string.h>\n"); 6181 6182 cgprintf(cg, "typedef unsigned char uchar;\n"); 6183 cgprintf(cg, "typedef unsigned uint;\n"); 6184 6185 cgprintf(cg, "typedef int16_t s16;\n"); 6186 cgprintf(cg, "typedef uint16_t u16;\n"); 6187 cgprintf(cg, "typedef unsigned int uint;\n"); 6188 cgprintf(cg, "typedef int64_t s64;\n"); 6189 cgprintf(cg, "typedef uint64_t u64;\n"); 6190 6191 cgprintf(cg, "\n"); 6192 } 6193 6194 static void 6195 cgtype(CodeGen *cg, Type *type, Decl *decl); 6196 6197 static void 6198 cgforward(Source *source, Node *ast, CodeGen *cg) 6199 { 6200 Decl *decl; 6201 assert(ast->kind == ADECL); 6202 6203 decl = ast->u.declref; 6204 if (decl->kind == DFUNCTION) { 6205 cgtype(cg, ast->type, decl); 6206 6207 } else if (decl->kind == DVAR) { 6208 /* @todo check storage class before using extern */ 6209 cgprintf(cg, "extern "); 6210 cgtype(cg, ast->type, decl); 6211 6212 /* @todo implement variable forward declaration */ 6213 } else { 6214 assert(!"never reach here"); 6215 } 6216 } 6217 6218 static void 6219 cgtoplevel(Source *source, Node *ast, CodeGen *cg) 6220 { 6221 if (source->haspendingenv) { 6222 assert(source->pendingcount < 512); 6223 source->pendingnodes[source->pendingcount++] = ast; 6224 source->haspendingenv = false; 6225 6226 /* @todo forwad declarations of nested function, etc. 6227 * may also be needed */ 6228 cgforward(source, ast, cg); 6229 cgprintf(cg, ";\n"); 6230 } else { 6231 codegen(cg, ast); 6232 if (ast->kind != ADECL || ast->u.declref->kind != DFUNCTION) 6233 cgprintf(cg, ";\n"); 6234 else 6235 cgprintf(cg, "\n"); 6236 /* deletenode(ast); */ 6237 } 6238 } 6239 6240 static void 6241 cgtoplevelfinish(Source *source, CodeGen *cg) 6242 { 6243 int i; 6244 6245 for (i = 0; i < source->pendingcount; ++i) { 6246 Node *ast = source->pendingnodes[i]; 6247 6248 codegen(cg, ast); 6249 if (ast->kind != ADECL || ast->u.declref->kind != DFUNCTION) 6250 cgprintf(cg, ";\n"); 6251 else 6252 cgprintf(cg, "\n"); 6253 /* deletenode(ast); */ 6254 } 6255 } 6256 6257 #if 0 6258 static void 6259 cgtypetail(CodeGen *cg, Type *type) 6260 { 6261 if (!type) 6262 return; 6263 6264 if (type->kind == TFUNCTION) { 6265 cgtypetail(cg, type->u.rtarget); 6266 cgprintf(cg, " function("); 6267 if (type->target) 6268 cgtypetail(cg, type->target); 6269 cgprintf(cg, ")"); 6270 return; 6271 } 6272 6273 if (type->kind != TTUPLE && type->target && 6274 type->target->kind == TTUPLE) 6275 { 6276 cgprintf(cg, "("); 6277 cgtypetail(cg, type->target); 6278 cgprintf(cg, ")"); 6279 } else { 6280 cgtypetail(cg, type->target); 6281 } 6282 6283 if (type->module) { 6284 cgprintf(cg, "%s", getstring(idents, type->module->key)); 6285 return; 6286 } 6287 6288 switch (type->kind) { 6289 case TARRAY: 6290 cgprintf(cg, "["); 6291 6292 /* @note the value may be always set in the future */ 6293 if (type->u.val) 6294 codegen(cg, type->u.val); 6295 6296 cgprintf(cg, "]"); 6297 break; 6298 6299 case TTUPLE: 6300 cgprintf(cg, ", "); 6301 if (type->u.rtarget && type->u.rtarget->kind == TTUPLE) { 6302 cgprintf(cg, "("); 6303 cgtypetail(cg, type->u.rtarget); 6304 cgprintf(cg, ")"); 6305 } else { 6306 cgtypetail(cg, type->u.rtarget); 6307 } 6308 6309 break; 6310 6311 default:; 6312 } 6313 6314 return; 6315 } 6316 6317 static void 6318 cgbasetype(CodeGen *cg, Type *type) 6319 { 6320 while (type->target) 6321 type = type->target; 6322 6323 switch (type->kind) { 6324 #define typecase(type, str) \ 6325 case type: cgprintf(cg, str); break 6326 typecase(TERRTYPE, "<error-type>"); 6327 typecase(TUNDEFINED, "<undefined-type>"); 6328 typecase(TPTR, "*"); 6329 typecase(TVOID, "void" ); typecase(TBOOL, "bool" ); 6330 typecase(TINFER, "infer"); typecase(TUINFER, "uinfer"); 6331 typecase(TS8, "char" ); typecase(TU8, "uchar" ); 6332 typecase(TS16, "s16" ); typecase(TU16, "u16" ); 6333 typecase(TS32, "int" ); typecase(TU32, "uint" ); 6334 typecase(TS64, "s64" ); typecase(TU64, "u64" ); 6335 typecase(TF32, "float"); typecase(TF64, "double"); 6336 #undef typecase 6337 default: 6338 cgprintf(cg, "<unknown-type-%d>", type->kind); 6339 } 6340 } 6341 #endif 6342 6343 static void 6344 cgnamedparams(CodeGen *cg, Decl *decl) 6345 { 6346 Decl *param, *head = NULL; 6347 6348 cgprintf(cg, "("); 6349 6350 if (decl->contentenv) { 6351 head = decl->contentenv->head; 6352 } 6353 6354 for (param = head; param; param = param->next) { 6355 if (param->kind != DPARAM) 6356 break; 6357 6358 if (param != head) { 6359 cgprintf(cg, ", "); 6360 } 6361 6362 ++cg->indent; 6363 cgtype(cg, param->type, param); 6364 --cg->indent; 6365 } 6366 6367 cgprintf(cg, ")"); 6368 } 6369 6370 static void 6371 cgdeclmodule(CodeGen *cg, Decl *module) 6372 { 6373 if (module->module) 6374 cgdeclmodule(cg, module->module); 6375 6376 cgprintf(cg, "%s_", getstring(idents, module->key)); 6377 } 6378 6379 static void 6380 cgdeclname(CodeGen *cg, Decl *decl) 6381 { 6382 if (decl->module) 6383 cgdeclmodule(cg, decl->module); 6384 6385 cgprintf(cg, "%s", getstring(idents, decl->key)); 6386 } 6387 6388 static void 6389 cgbasetype(CodeGen *cg, Type *type) 6390 { 6391 switch (type->kind) { 6392 #define typecase(type, str) \ 6393 case type: cgprintf(cg, str); break 6394 typecase(TERRTYPE, "<error-type>"); 6395 typecase(TUNDEFINED, "<undefined-type>"); 6396 typecase(TPTR, "*"); 6397 typecase(TVOID, "void" ); typecase(TBOOL, "bool" ); 6398 typecase(TINFER, "infer"); typecase(TUINFER, "uinfer"); 6399 typecase(TS8, "char" ); typecase(TU8, "uchar" ); 6400 typecase(TS16, "s16" ); typecase(TU16, "u16" ); 6401 typecase(TS32, "int" ); typecase(TU32, "uint" ); 6402 typecase(TS64, "s64" ); typecase(TU64, "u64" ); 6403 typecase(TF32, "float"); typecase(TF64, "double"); 6404 #undef typecase 6405 6406 case TUNION: 6407 cgprintf(cg, "union "); 6408 goto joinstruct; 6409 6410 case TSTRUCT: 6411 cgprintf(cg, "struct "); 6412 joinstruct: 6413 assert(type->module); 6414 cgdeclname(cg, type->module); 6415 break; 6416 6417 default: 6418 cgprintf(cg, "<unknown-type-%d>", type->kind); 6419 } 6420 } 6421 6422 static void 6423 cgtype(CodeGen *cg, Type *type, Decl *decl) 6424 { 6425 Type *stack[64]; 6426 Type *post[64]; 6427 int top = 0, pcount = 0; 6428 6429 if (isrecordenv(cg->env) && type->kind == TFUNCTION) { 6430 assert(top < lengthof(stack)); 6431 stack[top++] = maketype( 6432 cg->env->arenas, &decl->loc, 6433 primitive(TPTR), type); 6434 } 6435 6436 while (type->target || type->kind == TFUNCTION) { 6437 assert(top < lengthof(stack)); 6438 stack[top++] = type; 6439 if (type->kind == TFUNCTION) { 6440 assert(type->u.rtarget); 6441 type = type->u.rtarget; 6442 } else { 6443 type = type->target; 6444 } 6445 } 6446 6447 if (cg->commacount) 6448 goto decorate; 6449 6450 cgbasetype(cg, type); 6451 cgprintf(cg, " "); 6452 6453 decorate: 6454 while (top > 0) { 6455 Type *curr = stack[--top]; 6456 if (curr->kind == TPTR) { 6457 Type *target = curr->target; 6458 if (target->kind != TPTR && (target->target || target->u.rtarget)) { 6459 cgprintf(cg, "(*"); 6460 assert(pcount < lengthof(post)); 6461 post[pcount++] = curr; 6462 } else { 6463 cgprintf(cg, "*"); 6464 } 6465 #if 0 6466 if (target->isconst) 6467 cgprintf(cg, "const "); 6468 #endif 6469 } else { 6470 assert(pcount < lengthof(post)); 6471 post[pcount++] = curr; 6472 } 6473 } 6474 6475 if (decl) { 6476 if (isrecordenv(cg->env)) 6477 cgprintf(cg, "%s", getstring(idents, decl->key)); 6478 else 6479 cgdeclname(cg, decl); 6480 } 6481 6482 6483 while (pcount > 0) { 6484 Type *curr = post[--pcount]; 6485 switch (curr->kind) { 6486 case TPTR: 6487 cgprintf(cg, ")"); 6488 continue; 6489 case TARRAY: 6490 cgprintf(cg, "["); 6491 codegen(cg, curr->u.val); 6492 cgprintf(cg, "]"); 6493 continue; 6494 case TFUNCTION: 6495 if (decl && decl->kind == DFUNCTION) { 6496 /* print named or empty parameter list */ 6497 cgnamedparams(cg, decl); 6498 /* Only the innermost function is referred 6499 * by decl. So we can set decl to NULL. */ 6500 decl = NULL; 6501 } else if (curr->target 6502 && curr->target->kind == TTUPLE) { 6503 Type *tuple = curr->target; 6504 /* print anonymous parameter list */ 6505 cgprintf(cg, "("); 6506 for (;;) { 6507 assert(tuple->target); 6508 cgtype(cg, tuple->target, NULL); 6509 cgprintf(cg, ", "); 6510 6511 assert(tuple->u.rtarget); 6512 tuple = tuple->u.rtarget; 6513 if (tuple->kind != TTUPLE) { 6514 cgtype(cg, tuple, NULL); 6515 break; 6516 } 6517 } 6518 cgprintf(cg, ")"); 6519 } else { 6520 /* print empty parameter list */ 6521 cgprintf(cg, "()"); 6522 } 6523 default: 6524 continue; 6525 } 6526 } 6527 } 6528 6529 static void 6530 cgnumber(CodeGen *cg, Node *expr) 6531 { 6532 switch (expr->type->kind) { 6533 case TF32: case TF64: 6534 /* case TLDOUBLE: */ 6535 cgprintf(cg, "%f", expr->u.d); 6536 if (expr->type->kind == TF32) 6537 cgprintf(cg, "f"); 6538 break; 6539 6540 case TINFER: 6541 case TS8: case TS16: case TS32: case TS64: 6542 cgprintf(cg, "%lli", expr->u.s); 6543 break; 6544 6545 case TUINFER: 6546 case TU8: case TU16: case TU32: case TU64: 6547 cgprintf(cg, "%llu", expr->u.s); 6548 break; 6549 6550 case TBOOL: 6551 if (expr->u.u == 0) 6552 cgprintf(cg, "false"); 6553 else if (expr->u.u == 1) 6554 cgprintf(cg, "true"); 6555 else 6556 cgprintf(cg, "((bool) 0x%016llx)", expr->u.u); 6557 break; 6558 6559 case TPTR: 6560 if (expr->u.u == 0) 6561 cgprintf(cg, "NULL"); 6562 else 6563 cgprintf(cg, "((void *) 0x%016llx)", expr->u.u); 6564 break; 6565 6566 case TVOID: 6567 default: 6568 cgprintf(cg, "---"); 6569 break; 6570 6571 } 6572 6573 } 6574 6575 static void 6576 cgmapchar(CodeGen *cg, char ch) 6577 { 6578 #define mapchar(from, to) \ 6579 case from: cgprintf(cg, to); return 6580 switch (ch) { 6581 mapchar('\\', "\\\\"); 6582 mapchar('\"', "\\\""); 6583 mapchar('\'', "\\\'"); 6584 mapchar('\n', "\\n"); 6585 mapchar('\t', "\\t"); 6586 mapchar('\r', "\\r"); 6587 mapchar('\b', "\\b"); 6588 mapchar('\f', "\\f"); 6589 mapchar('\v', "\\v"); 6590 mapchar('\0', "\\0"); 6591 default: 6592 if (ch < 32 || (uint8_t) ch >= 127) 6593 cgprintf(cg, "\\x%02x", (uint8_t) ch); 6594 else 6595 cgprintf(cg, "%c", ch); 6596 break; 6597 } 6598 #undef mapchar 6599 } 6600 6601 static void 6602 cgdeclaration(CodeGen *cg, Node *expr) 6603 { 6604 Decl *decl = expr->u.declref; 6605 6606 assert(decl); 6607 assert(expr->type); 6608 6609 cgtype(cg, expr->type, decl); 6610 6611 if (decl->kind == DFUNCTION) { 6612 if (!decl->u.content) 6613 return; 6614 6615 cgprintf(cg, "\n"); 6616 cgindent(cg); 6617 cgprintf(cg, "{\n"); 6618 6619 ++cg->indent; 6620 codegen(cg, decl->contentenv->stmts); 6621 --cg->indent; 6622 6623 cgindent(cg); 6624 cgprintf(cg, "}\n"); 6625 cg->hasclause = true; 6626 } else if (decl->kind == DPARAM || decl->kind == DVAR) { 6627 if (isrecordenv(decl->parentenv)) 6628 return; 6629 6630 if (decl->u.content) { 6631 cgprintf(cg, " = "); 6632 codegen(cg, decl->u.content); 6633 } 6634 } 6635 } 6636 6637 static void 6638 cgsubexpr(CodeGen *cg, Node *expr) 6639 { 6640 if (isatomnode(expr->kind)) { 6641 codegen(cg, expr); 6642 return; 6643 } 6644 6645 cgprintf(cg, "("); 6646 codegen(cg, expr); 6647 cgprintf(cg, ")"); 6648 } 6649 6650 static void 6651 cgunaryprefixop(CodeGen *cg, Node *expr, const char *op) 6652 { 6653 cgprintf(cg, "%s", op); 6654 cgsubexpr(cg, expr->lhs); 6655 } 6656 6657 static void 6658 cgbinaryop(CodeGen *cg, Node *expr, const char *op) 6659 { 6660 cgsubexpr(cg, expr->lhs); 6661 cgprintf(cg, " %s ", op); 6662 cgsubexpr(cg, expr->rhs); 6663 } 6664 6665 static void 6666 cgprintclause(CodeGen *cg, Node *clause) 6667 { 6668 cgprintf(cg, " {\n"); 6669 ++cg->indent; 6670 codegen(cg, clause); 6671 --cg->indent; 6672 cgindent(cg); 6673 cgprintf(cg, "}"); 6674 cg->hasclause = true; 6675 } 6676 6677 static void 6678 codegen(CodeGen *cg, Node *expr) 6679 { 6680 assert(expr); 6681 6682 switch (expr->kind) { 6683 case IDENT: 6684 cgprintf(cg, "%s", getstring(idents, expr->u.key)); 6685 break; 6686 case CHAR: 6687 cgprintf(cg, "'"); 6688 cgmapchar(cg, (uchar) expr->u.u); 6689 cgprintf(cg, "'"); 6690 break; 6691 case TYPE: 6692 break; 6693 case NUMBER: 6694 cgnumber(cg, expr); 6695 break; 6696 case STRING: 6697 cgprintf(cg, "\""); 6698 do { 6699 const int length = getlength(strings, expr->u.key); 6700 const char *string = getstring(strings, expr->u.key); 6701 6702 int i; 6703 6704 /* @note string must have at least one char 6705 * (null-char at the end) which is not printed */ 6706 assert(length); 6707 for (i = 0; i < length - 1; ++i) { 6708 cgmapchar(cg, string[i]); 6709 } 6710 } while (0); 6711 cgprintf(cg, "\""); 6712 break; 6713 case ACOMPOUND: 6714 cgprintf(cg, "(("); 6715 cgbasetype(cg, expr->type); 6716 cgprintf(cg, ") {"); 6717 ++cg->indent; 6718 codegen(cg, expr->rhs); 6719 --cg->indent; 6720 cgindent(cg); 6721 cgprintf(cg, "})"); 6722 break; 6723 case AFIELDINIT: 6724 codegen(cg, expr->rhs); 6725 break; 6726 case KTRUE: 6727 cgprintf(cg, "true"); 6728 break; 6729 case KFALSE: 6730 cgprintf(cg, "false"); 6731 break; 6732 case KNULL: 6733 cgprintf(cg, "NULL"); 6734 break; 6735 case KSIZEOF: 6736 /* @todo consider dynamic arrays? */ 6737 cgprintf(cg, "(%zu)", expr->type->size); 6738 break; 6739 case KALIGNOF: 6740 cgprintf(cg, "(%zu)", expr->type->align); 6741 break; 6742 case KLENGTHOF: 6743 /* @todo implement lengthof */ 6744 break; 6745 case ADECLREF: 6746 cgdeclname(cg, expr->u.declref); 6747 break; 6748 case ALABEL: 6749 case ASWITCH: 6750 case ACASE: 6751 break; 6752 case ACONV: 6753 codegen(cg, expr->lhs); 6754 break; 6755 case KDO: 6756 /* @todo implement c version correctly */ 6757 case ASCOPE: 6758 do { 6759 Env *env = cg->env; 6760 Node *curr = expr->lhs; 6761 if (expr->u.env) 6762 cg->env = expr->u.env; 6763 while (curr) { 6764 cgindent(cg); 6765 codegen(cg, curr); 6766 if (curr->kind == ASTMT) 6767 curr = curr->rhs; 6768 else 6769 break; 6770 } 6771 cg->env = env; 6772 } while (0); 6773 break; 6774 case AENV: 6775 assert(expr->lhs); 6776 codegen(cg, expr->lhs); 6777 break; 6778 case ASTMT: 6779 cg->hasclause = false; 6780 codegen(cg, expr->lhs); 6781 if (!cg->hasclause) 6782 cgprintf(cg, "; /* statement */\n"); 6783 cg->hasclause = false; 6784 break; 6785 case ADECL: 6786 cgdeclaration(cg, expr); 6787 break; 6788 case OSUFINC: 6789 cgsubexpr(cg, expr->lhs); 6790 cgprintf(cg, "++"); 6791 break; 6792 case OSUFDEC: 6793 cgsubexpr(cg, expr->lhs); 6794 cgprintf(cg, "++"); 6795 break; 6796 case OARRAY: 6797 cgsubexpr(cg, expr->lhs); 6798 cgprintf(cg, "["); 6799 codegen(cg, expr->rhs); 6800 cgprintf(cg, "]"); 6801 break; 6802 case ODISP: 6803 cgsubexpr(cg, expr->lhs); 6804 cgprintf(cg, "."); 6805 codegen(cg, expr->rhs); 6806 break; 6807 case OCALL: 6808 cgsubexpr(cg, expr->lhs); 6809 cgprintf(cg, "("); 6810 if (expr->rhs) 6811 codegen(cg, expr->rhs); 6812 cgprintf(cg, ")"); 6813 break; 6814 case OADDR: 6815 case AADDR: 6816 cgunaryprefixop(cg, expr, "&"); 6817 break; 6818 case ODEREF: 6819 case ADEREF: 6820 cgunaryprefixop(cg, expr, "*"); 6821 break; 6822 case OINC: 6823 cgunaryprefixop(cg, expr, "++"); 6824 break; 6825 case ODEC: 6826 cgunaryprefixop(cg, expr, "--"); 6827 break; 6828 case OBNOT: 6829 cgunaryprefixop(cg, expr, "~"); 6830 break; 6831 case OLNOT: 6832 cgunaryprefixop(cg, expr, "!"); 6833 break; 6834 case OPLUS: 6835 cgunaryprefixop(cg, expr, "+"); 6836 break; 6837 case OMINUS: 6838 cgunaryprefixop(cg, expr, "-"); 6839 break; 6840 case OCAST: 6841 /* @todo implement c version correctly */ 6842 cgprintf(cg, "("); 6843 codegen(cg, expr->lhs); 6844 cgprintf(cg, ")"); 6845 break; 6846 case OMUL: 6847 cgbinaryop(cg, expr, "*"); 6848 break; 6849 case ODIV: 6850 cgbinaryop(cg, expr, "/"); 6851 break; 6852 case OMOD: 6853 cgbinaryop(cg, expr, "%"); 6854 break; 6855 case OBAND: 6856 cgbinaryop(cg, expr, "&"); 6857 break; 6858 case OLSH: 6859 cgbinaryop(cg, expr, "<<"); 6860 break; 6861 case OARSH: 6862 /* @todo implement c version correctly */ 6863 cgbinaryop(cg, expr, ">>>"); 6864 break; 6865 case ORSH: 6866 cgbinaryop(cg, expr, ">>"); 6867 break; 6868 case OADD: 6869 cgbinaryop(cg, expr, "+"); 6870 break; 6871 case OSUB: 6872 cgbinaryop(cg, expr, "-"); 6873 break; 6874 case OBOR: 6875 cgbinaryop(cg, expr, "|"); 6876 break; 6877 case OXOR: 6878 cgbinaryop(cg, expr, "^"); 6879 break; 6880 case OFLIP: 6881 case ORANGE: 6882 /* @todo implement c version correctly */ 6883 cgbinaryop(cg, expr, "~"); 6884 break; 6885 case OLEQ: 6886 cgbinaryop(cg, expr, "<="); 6887 break; 6888 case OLET: 6889 cgbinaryop(cg, expr, "<"); 6890 break; 6891 case OGEQ: 6892 cgbinaryop(cg, expr, ">="); 6893 break; 6894 case OGRT: 6895 cgbinaryop(cg, expr, ">"); 6896 break; 6897 case ONEQ: 6898 cgbinaryop(cg, expr, "!="); 6899 break; 6900 case OEQU: 6901 cgbinaryop(cg, expr, "=="); 6902 break; 6903 case OIDENT: 6904 /* @todo implement c version correctly */ 6905 cgbinaryop(cg, expr, "=="); 6906 break; 6907 case OLAND: 6908 cgbinaryop(cg, expr, "&&"); 6909 break; 6910 case OLOR: 6911 cgbinaryop(cg, expr, "||"); 6912 break; 6913 case OASS: 6914 cgbinaryop(cg, expr, "="); 6915 break; 6916 case OMULA: 6917 cgbinaryop(cg, expr, "*="); 6918 break; 6919 case ODIVA: 6920 cgbinaryop(cg, expr, "/="); 6921 break; 6922 case OMODA: 6923 cgbinaryop(cg, expr, "%="); 6924 break; 6925 case OLSHA: 6926 cgbinaryop(cg, expr, "<<="); 6927 break; 6928 case OARSHA: 6929 /* @todo implement c version correctly */ 6930 cgbinaryop(cg, expr, ">>>="); 6931 break; 6932 case ORSHA: 6933 cgbinaryop(cg, expr, ">>="); 6934 break; 6935 case OANDA: 6936 cgbinaryop(cg, expr, "&="); 6937 break; 6938 case OADDA: 6939 cgbinaryop(cg, expr, "+="); 6940 break; 6941 case OSUBA: 6942 cgbinaryop(cg, expr, "-="); 6943 break; 6944 case OXORA: 6945 cgbinaryop(cg, expr, "^="); 6946 break; 6947 case OORA: 6948 cgbinaryop(cg, expr, "|="); 6949 break; 6950 case KBREAK: 6951 cgprintf(cg, "break"); 6952 break; 6953 case KCONTINUE: 6954 cgprintf(cg, "continue"); 6955 break; 6956 case KGOTO: 6957 cgprintf(cg, "goto %s", getstring(idents, expr->u.key)); 6958 break; 6959 case KRETURN: 6960 cgprintf(cg, "return "); 6961 if (expr->rhs) 6962 codegen(cg, expr->rhs); 6963 break; 6964 case KWHILE: 6965 cgprintf(cg, "while ("); 6966 goto joinif; 6967 case KFOR: 6968 cgprintf(cg, "for ("); 6969 goto joinif; 6970 case KIF: 6971 cgprintf(cg, "if ("); 6972 joinif: 6973 if (expr->u.payload) 6974 codegen(cg, expr->u.payload); 6975 cgprintf(cg, ") "); 6976 if (expr->lhs) 6977 cgprintclause(cg, expr->lhs); 6978 if (expr->rhs) { 6979 cgprintf(cg, " else "); 6980 cgprintclause(cg, expr->rhs); 6981 } 6982 cgprintf(cg, "\n"); 6983 break; 6984 case AFORSTEP: 6985 assert(expr->lhs); 6986 assert(expr->rhs); 6987 assert(expr->u.payload); 6988 assert(expr->lhs->kind == ADECL || expr->lhs->kind == ADECLREF); 6989 codegen(cg, expr->lhs); 6990 cgprintf(cg, "; %s < (", getstring(idents, expr->lhs->u.declref->key)); 6991 codegen(cg, expr->rhs); 6992 cgprintf(cg, "); %s += (", getstring(idents, expr->lhs->u.declref->key)); 6993 codegen(cg, expr->u.payload); 6994 cgprintf(cg, ")"); 6995 break; 6996 case AFOREACH: 6997 break; 6998 case KLOOP: 6999 cgprintf(cg, "for (;;) "); 7000 if (expr->lhs) 7001 cgprintclause(cg, expr->lhs); 7002 /* @todo implement else-case properly? */ 7003 /* @note else-clause might be useless for an infinite loop */ 7004 /* 7005 if (expr->rhs) { 7006 cgprintf(cg, " else "); 7007 cgprintclause(cg, expr->rhs); 7008 } 7009 */ 7010 cgprintf(cg, "\n"); 7011 break; 7012 case ALOOPUNTIL: 7013 cgprintf(cg, "do "); 7014 if (expr->lhs) 7015 cgprintclause(cg, expr->lhs); 7016 cgprintf(cg, " while (!("); 7017 if (expr->u.payload) 7018 codegen(cg, expr->u.payload); 7019 cgprintf(cg, "));\n"); 7020 /* @todo implement else-case properly */ 7021 /* 7022 if (expr->rhs) { 7023 cgprintf(cg, " else "); 7024 cgprintclause(cg, expr->rhs); 7025 } 7026 */ 7027 break; 7028 case KCASE: 7029 case KOF: 7030 case KUNTIL: 7031 /* @todo implement c version correctly */ 7032 break; 7033 case ACOMMA: 7034 codegen(cg, expr->lhs); 7035 cgprintf(cg, ", "); 7036 ++cg->commacount; 7037 codegen(cg, expr->rhs); 7038 --cg->commacount; 7039 break; 7040 case KUNION: 7041 cgprintf(cg, "union "); 7042 goto joinstruct; 7043 case KSTRUCT: 7044 cgprintf(cg, "struct "); 7045 7046 joinstruct: 7047 assert(expr->type); 7048 if (expr->type->module) 7049 cgdeclname(cg, expr->type->module); 7050 7051 cgprintf(cg, " {\n"); 7052 ++cg->indent; 7053 if (expr->rhs) 7054 codegen(cg, expr->rhs); 7055 --cg->indent; 7056 cgindent(cg); 7057 cgprintf(cg, "}"); 7058 break; 7059 case INVALID: 7060 case LINEDELIM: 7061 case SEMIDELIM: 7062 case COMMADELIM: 7063 case COLONDELIM: 7064 case LCURLDELIM: 7065 case LSQRDELIM: 7066 case LPARDELIM: 7067 case RCURLDELIM: 7068 case RSQRDELIM: 7069 case RPARDELIM: 7070 case ANNOT: 7071 case KVOID: 7072 case KBOOL: 7073 case KU8: 7074 case KS8: 7075 case KU16: 7076 case KS16: 7077 case KU32: 7078 case KS32: 7079 case KU64: 7080 case KS64: 7081 case KF32: 7082 case KF64: 7083 case KUCHAR: 7084 case KCHAR: 7085 case KUSHORT: 7086 case KSHORT: 7087 case KUINT: 7088 case KINT: 7089 case KULONG: 7090 case KLONG: 7091 case KULLONG: 7092 case KLLONG: 7093 case KFLOAT: 7094 case KDOUBLE: 7095 case KLDOUBLE: 7096 case KUSIZE: 7097 case KSSIZE: 7098 case KUSE: 7099 case KNOT: 7100 case KAND: 7101 case KOR: 7102 case KIS: 7103 case KBITCAST: 7104 case KEXTERN: 7105 case KINTERN: 7106 case KSTATIC: 7107 case KCONST: 7108 case KVAR: 7109 case KELSE: 7110 case MAXKINDS: 7111 case ENDOFFILE: 7112 cgprintf(cg, "<not implemented: '%s' ", nodestrings[expr->kind]); 7113 if (expr->lhs) 7114 codegen(cg, expr->lhs); 7115 cgprintf(cg, " "); 7116 if (expr->rhs) 7117 codegen(cg, expr->rhs); 7118 cgprintf(cg, ">"); 7119 break; 7120 } 7121 } 7122 7123 7124 7125 // }}} 7126 7127 // @section print ast {{{ 7128 7129 static void 7130 promptenvpath(Env* currenv) 7131 { 7132 const char *envstring = "environment"; 7133 7134 if (currenv && currenv->kind != STOPLEVEL) { 7135 promptenvpath(currenv->below); 7136 7137 switch (currenv->kind) { 7138 case SFUNCTION: 7139 case SPARAMLIST: 7140 envstring = "function"; 7141 break; 7142 case SSTRUCT: 7143 envstring = "struct"; 7144 break; 7145 case SUNION: 7146 envstring = "union"; 7147 break; 7148 case SSCOPE: 7149 envstring = "scope"; 7150 break; 7151 case SIF: 7152 envstring = "if"; 7153 break; 7154 case SELSE: 7155 envstring = "else"; 7156 break; 7157 case SDO: 7158 envstring = "do"; 7159 break; 7160 case SLOOP: 7161 envstring = "loop"; 7162 break; 7163 case SWHILE: 7164 envstring = "while"; 7165 break; 7166 default: 7167 break; 7168 } 7169 7170 if (currenv->envdecl) { 7171 int key = currenv->envdecl->key; 7172 envstring = getstring(idents, key); 7173 } 7174 7175 fprintf(stdout, "# scope: %s/", envstring); 7176 } 7177 } 7178 7179 static void 7180 tryprompt(Source *source, const char ch) 7181 { 7182 if (source->handlereplprompt) { 7183 Env *currenv = source->currenv; 7184 7185 if (ch == '.' && currenv && currenv->kind != STOPLEVEL) { 7186 fputs("\x1b[1;30m", stdout); 7187 promptenvpath(currenv); 7188 fprintf(stdout, "\n\x1b[35m%c \x1b[0m", ch); 7189 } else { 7190 fprintf(stdout, "\x1b[35m%c \x1b[0m", ch); 7191 } 7192 7193 } else if (source->filein == stdin) { 7194 source->handlereplprompt = true; 7195 } 7196 } 7197 7198 typedef 7199 enum Highlight { 7200 HLNONE = 0, 7201 HLDELIM = 1, 7202 HLUNKNOWN = 2, 7203 HLKEYWORD = 3, 7204 HLNUMBER = 4, 7205 HLSTRING = 5, 7206 HLTYPE = 6, 7207 HLFUNCTION = 7, 7208 HLPARAM = 8, 7209 #if 0 7210 HLFUNCTIONDECL = 9, 7211 HLPARAMDECL = 10, 7212 HLDECL = 11, 7213 #endif 7214 HLSPECIAL = 12, 7215 HLINFO = 13, 7216 HLPROMPT = 14 7217 } Highlight; 7218 7219 #define HLFUNCTIONDECL HLFUNCTION 7220 #define HLPARAMDECL HLPARAM 7221 #define HLDECL HLIDENT 7222 7223 #define HLOP HLDELIM 7224 #define HLCHAR HLSTRING 7225 #define HLIDENT HLNONE 7226 7227 Highlight lasthighlight; 7228 7229 static int 7230 highlight(FILE *out, Highlight kind) 7231 { 7232 int n = 0; 7233 7234 if (out != stdout) 7235 return 0; 7236 7237 if (lasthighlight == kind) 7238 return 0; 7239 7240 if (kind == HLNONE) 7241 return lasthighlight = kind, fprintf(out, "\x1b[0m"); 7242 7243 if (lasthighlight == HLDELIM || kind == HLDELIM || 7244 lasthighlight == HLFUNCTION || kind == HLFUNCTION || 7245 lasthighlight == HLPARAM || kind == HLPARAM || 7246 #if 0 7247 lasthighlight == HLFUNCTIONDECL || kind == HLFUNCTIONDECL || 7248 lasthighlight == HLPARAMDECL || kind == HLPARAMDECL || 7249 lasthighlight == HLDECL || kind == HLDECL || 7250 #endif 7251 lasthighlight == HLSPECIAL || 7252 lasthighlight == HLUNKNOWN || kind == HLUNKNOWN) 7253 n += fprintf(out, "\x1b[0m"); 7254 7255 switch (kind) { 7256 case HLDELIM: 7257 n += fprintf(out, "\x1b[2m"); 7258 break; 7259 7260 case HLUNKNOWN: 7261 n += fprintf(out, "\x1b[41;30m"); 7262 break; 7263 7264 case HLKEYWORD: 7265 n += fprintf(out, "\x1b[35m"); 7266 break; 7267 7268 case HLNUMBER: 7269 n += fprintf(out, "\x1b[36m"); 7270 break; 7271 7272 case HLSTRING: 7273 n += fprintf(out, "\x1b[31m"); 7274 break; 7275 7276 case HLTYPE: 7277 n += fprintf(out, "\x1b[34m"); 7278 break; 7279 7280 case HLFUNCTION: 7281 n += fprintf(out, "\x1b[1;3m"); 7282 break; 7283 7284 case HLPARAM: 7285 n += fprintf(out, "\x1b[3m"); 7286 break; 7287 7288 #if 0 7289 case HLFUNCTIONDECL: 7290 n += fprintf(out, "\x1b[1;4;3m"); 7291 break; 7292 7293 case HLPARAMDECL: 7294 n += fprintf(out, "\x1b[4;3m"); 7295 break; 7296 7297 case HLDECL: 7298 n += fprintf(out, "\x1b[4m"); 7299 break; 7300 #endif 7301 7302 case HLSPECIAL: 7303 n += fprintf(out, "\x1b[3;36m"); 7304 break; 7305 7306 case HLINFO: 7307 n += fprintf(out, "\x1b[33m"); 7308 break; 7309 7310 case HLPROMPT: 7311 n += fprintf(out, "\x1b[35m"); 7312 break; 7313 default: 7314 break; 7315 } 7316 7317 lasthighlight = kind; 7318 return n; 7319 } 7320 7321 static int 7322 printexpr(FILE *out, Node *expr, int indent); 7323 7324 static int 7325 printtypetail(FILE *out, Type *type, int indent) 7326 { 7327 int n = 0; 7328 7329 if (!type) 7330 return 0; 7331 7332 if (type->kind == TFUNCTION) { 7333 n += printtypetail(out, type->u.rtarget, indent); 7334 n += fprintf(out, " function("); 7335 if (type->target) 7336 n += printtypetail(out, type->target, indent); 7337 n += fprintf(out, ")"); 7338 return n; 7339 } 7340 7341 if (type->kind != TTUPLE && type->target && 7342 type->target->kind == TTUPLE) 7343 { 7344 n += fprintf(out, "("); 7345 n += printtypetail(out, type->target, indent); 7346 n += fprintf(out, ")"); 7347 } else { 7348 n += printtypetail(out, type->target, indent); 7349 } 7350 7351 if (type->module) { 7352 n += fprintf(out, "%s", getstring(idents, type->module->key)); 7353 return n; 7354 } 7355 7356 switch (type->kind) { 7357 case TARRAY: 7358 n += fprintf(out, "["); 7359 7360 /* @note the value may be always set in the future */ 7361 if (type->u.val) 7362 n += printexpr(out, type->u.val, indent); 7363 7364 n += fprintf(out, "]"); 7365 break; 7366 7367 case TTUPLE: 7368 n += fprintf(out, ", "); 7369 if (type->u.rtarget && type->u.rtarget->kind == TTUPLE) { 7370 n += fprintf(out, "("); 7371 n += printtypetail(out, type->u.rtarget, indent); 7372 n += fprintf(out, ")"); 7373 } else { 7374 n += printtypetail(out, type->u.rtarget, indent); 7375 } 7376 7377 break; 7378 7379 #define typecase(type, str) \ 7380 case type: n += fprintf(out, str); break 7381 7382 typecase(TERRTYPE, "<error-type>"); 7383 typecase(TUNDEFINED, "<undefined-type>"); 7384 typecase(TPTR, "*"); 7385 typecase(TVOID, "void" ); typecase(TBOOL, "bool" ); 7386 typecase(TINFER, "infer"); typecase(TUINFER, "uinfer"); 7387 typecase(TS8, "char" ); typecase(TU8, "uchar" ); 7388 typecase(TS16, "s16" ); typecase(TU16, "u16" ); 7389 typecase(TS32, "int" ); typecase(TU32, "uint" ); 7390 typecase(TS64, "s64" ); typecase(TU64, "u64" ); 7391 typecase(TF32, "float"); typecase(TF64, "double"); 7392 7393 #undef typecase 7394 default:; 7395 } 7396 7397 return n; 7398 } 7399 7400 static int 7401 printtype(FILE *out, Type *type, int indent) 7402 { 7403 if (type && type->kind == TTUPLE) { 7404 int n = 0; 7405 7406 n += fprintf(out, "("); 7407 n += printtypetail(out, type, indent); 7408 7409 return n + fprintf(out, ")"); 7410 } 7411 7412 return printtypetail(out, type, indent); 7413 } 7414 7415 static int 7416 printtypesuffix(FILE *out, Type *type) 7417 { 7418 int n = 0; 7419 7420 if (!type) 7421 return 0; 7422 7423 switch (type->kind) { 7424 #define typecase(type, str) \ 7425 case type: n += fprintf(out, str); break 7426 7427 typecase(TINFER, "i" ); typecase(TUINFER, "u" ); 7428 typecase(TS8, "s8" ); typecase(TU8, "u8" ); 7429 typecase(TS16, "s16" ); typecase(TU16, "u16" ); 7430 typecase(TS32, "s32" ); typecase(TU32, "u32" ); 7431 typecase(TS64, "s64" ); typecase(TU64, "u64" ); 7432 typecase(TF32, "f32" ); typecase(TF64, "f64" ); 7433 7434 #undef typecase 7435 default:; 7436 } 7437 7438 return n; 7439 } 7440 7441 static bool 7442 isclauseorempty(Node *expr) 7443 { 7444 Kind kind; 7445 7446 while (expr && (expr->kind == ASCOPE || expr->kind == ASTMT)) 7447 expr = expr->lhs; 7448 7449 if (!expr) 7450 return true; 7451 7452 kind = expr->kind; 7453 return kind == KDO || kind == KIF || kind == KFOR || 7454 kind == KGOTO || kind == KRETURN || kind == KBREAK || 7455 kind == KCONTINUE; 7456 } 7457 7458 static int 7459 printclause(FILE *out, Node *expr, int indent) 7460 { 7461 int n = 0; 7462 7463 if (!expr) 7464 return 0; 7465 7466 if (isclauseorempty(expr)) { 7467 n += fprintf(out, " "); 7468 n += printexpr(out, expr, indent); 7469 } else { 7470 n += fprintf(out, "\n"); 7471 n += printexpr(out, expr, indent + 1); 7472 } 7473 7474 return n; 7475 } 7476 7477 static int 7478 printstring(FILE *out, Node *string) 7479 { 7480 const char *str = getstring(strings, string->u.key); 7481 int len = getlength(strings, string->u.key); 7482 int i, n = fprintf(out, "\""); 7483 7484 for (i = 0; i < len; ++i) { 7485 switch (str[i]) { 7486 case '\\': 7487 n += fprintf(out, "\\\\"); 7488 break; 7489 7490 case '\n': 7491 n += fprintf(out, "\\n"); 7492 break; 7493 7494 case '\r': 7495 n += fprintf(out, "\\r"); 7496 break; 7497 7498 case '\t': 7499 n += fprintf(out, "\\t"); 7500 break; 7501 7502 case '\"': 7503 n += fprintf(out, "\\\""); 7504 break; 7505 7506 case '\'': 7507 n += fprintf(out, "\\\'"); 7508 break; 7509 7510 case 0: 7511 n += fprintf(out, "\\0"); 7512 break; 7513 7514 default: 7515 putc(str[i], out); 7516 ++n; 7517 } 7518 } 7519 7520 return n + fprintf(out, "\""); 7521 } 7522 7523 static int 7524 printoperant(FILE *out, Node *expr, int opprec, bool braceequalprec, int indent) 7525 { 7526 int prec, n = 0; 7527 7528 if (!expr) 7529 return 0; 7530 7531 prec = getprec(expr->kind); 7532 if (!isatomnode(expr->kind) && (!getnumops(expr->kind) || 7533 prec < opprec || 7534 (braceequalprec && prec == opprec))) { 7535 n += highlight(out, HLDELIM); 7536 7537 n += fprintf(out, "("); 7538 n += highlight(out, HLNONE); 7539 n += printexpr(out, expr, indent); 7540 n += highlight(out, HLDELIM); 7541 n += fprintf(out, ")"); 7542 7543 n += highlight(out, HLNONE); 7544 } else { 7545 n += printexpr(out, expr, indent); 7546 } 7547 7548 return n; 7549 } 7550 7551 static int 7552 printsubexpr(FILE *out, Node *expr, bool islhs, int indent) 7553 { 7554 int n = 0; 7555 7556 if (!expr) 7557 return 0; 7558 7559 if ((islhs && expr->kind == ACOMMA) || expr->kind == ADECL) 7560 n += printexpr(out, expr, indent); 7561 else 7562 n += printoperant(out, expr, PSTART, !islhs, indent); 7563 7564 return n; 7565 } 7566 7567 static int 7568 printdeclmodule(FILE *out, Decl *module) 7569 { 7570 int n = 0; 7571 7572 if (module->module) 7573 printdeclmodule(out, module->module); 7574 7575 if (module->kind == DTYPE) { 7576 n += highlight(out, HLTYPE); 7577 fprintf(out, "%s", getstring(idents, module->key)); 7578 n += highlight(out, HLDELIM); 7579 } else { 7580 n += highlight(out, HLDELIM); 7581 fprintf(out, "%s", getstring(idents, module->key)); 7582 } 7583 n += fprintf(out, "."); 7584 7585 return n; 7586 } 7587 7588 static int 7589 printdeclname(FILE *out, Decl *decl, bool isdecl) 7590 { 7591 int n = 0; 7592 7593 if (decl->module) 7594 printdeclmodule(out, decl->module); 7595 7596 if (isdecl) { 7597 n += highlight(out, 7598 decl->kind == DFUNCTION ? HLFUNCTIONDECL : 7599 decl->kind == DPARAM ? ( 7600 decl->flags & MSPECIAL ? HLSPECIAL : HLPARAMDECL 7601 ) : HLDECL); 7602 } else { 7603 n += highlight(out, decl->kind == DFUNCTION ? 7604 HLFUNCTION : decl->kind == DPARAM ? ( 7605 decl->flags & MSPECIAL ? HLSPECIAL : HLPARAM 7606 ) : HLIDENT); 7607 } 7608 n += fprintf(out, "%s", getstring(idents, decl->key)); 7609 7610 return n; 7611 } 7612 7613 static int 7614 printdeclaration(FILE *out, Decl *decl, int indent) 7615 { 7616 int n = 0; 7617 7618 assert(decl); 7619 7620 n += highlight(out, HLTYPE); 7621 if (decl->kind == DFUNCTION) { 7622 n += printtype(out, decl->type->u.rtarget, indent); 7623 } else { 7624 n += printtype(out, decl->type, indent); 7625 } 7626 7627 n += fprintf(out, " "); 7628 printdeclname(out, decl, true); 7629 7630 if (decl->kind == DFUNCTION) { 7631 Decl *param, *head = NULL; 7632 7633 n += highlight(out, HLDELIM); 7634 n += fprintf(out, "("); 7635 7636 if (decl->contentenv) { 7637 head = decl->contentenv->head; 7638 } 7639 7640 for (param = head; param; param = param->next) { 7641 if (param->kind != DPARAM) 7642 break; 7643 7644 if (param != head) { 7645 n += highlight(out, HLDELIM); 7646 n += fprintf(out, ", "); 7647 } 7648 7649 n += printdeclaration(out, param, indent + 1); 7650 } 7651 7652 n += highlight(out, HLDELIM); 7653 n += fprintf(out, ")"); 7654 7655 if (decl->u.content) { 7656 n += fprintf(out, "\n"); 7657 n += printexpr(out, decl->u.content, indent + 1); 7658 } 7659 } else if (decl->u.content) { 7660 n += highlight(out, HLDELIM); 7661 n += fprintf(out, " = "); 7662 n += printoperant(out, decl->u.content, PASSIGN, false, indent); 7663 } 7664 7665 return n; 7666 } 7667 7668 static int 7669 printexpr(FILE *out, Node *expr, int indent) 7670 { 7671 int n = 0; 7672 7673 if (expr->kind == 0) { 7674 n += highlight(out, HLKEYWORD); 7675 n += fprintf(out, "_"); 7676 return 0; 7677 } 7678 7679 if (getnumops(expr->kind) == 2) { 7680 n += printoperant(out, expr->lhs, 7681 getprec(expr->kind), 7682 israssoc(expr->kind), 7683 indent); 7684 7685 n += highlight(out, HLDELIM); 7686 n += fprintf(out, " %s ", nodestrings[expr->kind]); 7687 7688 n += printoperant(out, expr->rhs, 7689 getprec(expr->kind), 7690 !israssoc(expr->kind), 7691 indent); 7692 goto finish; 7693 } 7694 7695 if (getnumops(expr->kind) == 1) { 7696 if (getprec(expr->kind) == PUNSUF) { 7697 printoperant(out, expr->lhs, PUNSUF, false, indent); 7698 7699 switch (expr->kind) { 7700 case OARRAY: 7701 case OCALL: 7702 n += highlight(out, HLDELIM); 7703 n += fprintf(out, "%c", nodestrings[expr->kind][0]); 7704 7705 if (expr->rhs) 7706 n += printexpr(out, expr->rhs, indent); 7707 7708 n += highlight(out, HLDELIM); 7709 n += fprintf(out, "%c", nodestrings[expr->kind][1]); 7710 break; 7711 7712 case ODISP: 7713 n += highlight(out, HLDELIM); 7714 n += fprintf(out, "."); 7715 if (expr->rhs && expr->rhs->kind == IDENT) { 7716 n += highlight(out, HLIDENT); 7717 n += fprintf(out, "%s", 7718 getstring(idents, expr->rhs->u.key)); 7719 } else { 7720 /* @note this might be unnecessary */ 7721 n += printexpr(out, expr->rhs, indent); 7722 } 7723 break; 7724 7725 default: 7726 n += highlight(out, HLDELIM); 7727 n += fprintf(out, "%s", nodestrings[expr->kind]); 7728 } 7729 7730 } else { 7731 switch (expr->kind) { 7732 case OCAST: 7733 n += highlight(out, HLDELIM); 7734 putc('(', out), ++n; 7735 n += highlight(out, HLTYPE); 7736 n += printtype(out, expr->type, indent); 7737 n += highlight(out, HLDELIM); 7738 putc(')', out), ++n; 7739 break; 7740 7741 default: 7742 n += highlight(out, HLDELIM); 7743 n += fprintf(out, "%s", nodestrings[expr->kind]); 7744 7745 if (getprec(expr->lhs->kind) == PUNARY && 7746 expr->kind != ODEREF && 7747 expr->kind != OADDR) 7748 { 7749 putc(' ', out), ++n; 7750 } 7751 } 7752 7753 n += printoperant(out, expr->lhs, PUNARY, false, indent); 7754 } 7755 7756 goto finish; 7757 } 7758 7759 switch (expr->kind) { 7760 case IDENT: 7761 n += highlight(out, HLUNKNOWN); 7762 n += fprintf(out, "%s?", getstring(idents, expr->u.key)); 7763 n += highlight(out, HLNONE); 7764 break; 7765 7766 case NUMBER: 7767 n += highlight(out, HLNUMBER); 7768 7769 switch (expr->type->kind) { 7770 case TF32: case TF64: 7771 /* case TLDOUBLE: */ 7772 n += fprintf(out, "%f", expr->u.d); 7773 n += printtypesuffix(out, expr->type); 7774 break; 7775 7776 case TINFER: 7777 case TS8: case TS16: case TS32: case TS64: 7778 n += fprintf(out, "%lli", expr->u.s); 7779 n += printtypesuffix(out, expr->type); 7780 break; 7781 7782 case TUINFER: 7783 case TU8: case TU16: case TU32: case TU64: 7784 n += fprintf(out, "%llu", expr->u.s); 7785 n += printtypesuffix(out, expr->type); 7786 break; 7787 7788 case TBOOL: 7789 if (expr->u.u == 0) 7790 n += fprintf(out, "false"); 7791 else if (expr->u.u == 1) 7792 n += fprintf(out, "true"); 7793 else 7794 n += fprintf(out, "0x%016llx", expr->u.u); 7795 7796 break; 7797 7798 case TPTR: 7799 if (expr->u.u == 0) 7800 n += fprintf(out, "null"); 7801 else 7802 n += fprintf(out, "0x%016llx", expr->u.u); 7803 break; 7804 7805 case TVOID: 7806 default: 7807 n += fprintf(out, "---"); 7808 break; 7809 7810 } 7811 7812 break; 7813 7814 case CHAR: 7815 /* @todo print chars correctly */ 7816 n += highlight(out, HLCHAR); 7817 n += fprintf(out, "'%c'", (uchar) expr->u.u); 7818 break; 7819 7820 case STRING: 7821 n += highlight(out, HLSTRING); 7822 n += printstring(out, expr); 7823 break; 7824 7825 case TYPE: 7826 /* @note might be unnecessary (only used for ACOMPOUND) */ 7827 n += highlight(out, HLTYPE); 7828 n += printtype(out, expr->type, indent); 7829 break; 7830 7831 case ADECLREF: 7832 printdeclname(out, expr->u.declref, false); 7833 break; 7834 7835 case ADECL: 7836 n += printdeclaration(out, expr->u.declref, indent); 7837 break; 7838 7839 case ACOMMA: 7840 n += printsubexpr(out, expr->lhs, true, indent); 7841 n += highlight(out, HLDELIM); 7842 n += printf(", "); 7843 n += printsubexpr(out, expr->rhs, false, indent); 7844 break; 7845 7846 case KSIZEOF: 7847 case KALIGNOF: 7848 case KLENGTHOF: 7849 n += highlight(out, HLKEYWORD); 7850 n += fprintf(out, "%s", nodestrings[expr->kind]); 7851 n += highlight(out, HLDELIM); 7852 7853 n += fprintf(out, "("); 7854 n += printexpr(out, expr->lhs, indent); 7855 n += highlight(out, HLDELIM); 7856 n += fprintf(out, ")"); 7857 break; 7858 7859 case KBITCAST: 7860 n += highlight(out, HLKEYWORD); 7861 n += fprintf(out, "bitcast"); 7862 n += highlight(out, HLDELIM); 7863 n += fprintf(out, "("); 7864 7865 n += highlight(out, HLTYPE); 7866 n += printtype(out, expr->rhs->type, indent); 7867 n += highlight(out, HLDELIM); 7868 7869 n += fprintf(out, ") ("); 7870 n += printexpr(out, expr->lhs, indent); 7871 n += highlight(out, HLDELIM); 7872 n += fprintf(out, ")"); 7873 break; 7874 7875 case KRETURN: 7876 n += highlight(out, HLKEYWORD); 7877 if (expr->rhs) { 7878 n += fprintf(out, "return "); 7879 n += printexpr(out, expr->rhs, indent); 7880 } else { 7881 n += fprintf(out, "return"); 7882 } 7883 break; 7884 7885 case KBREAK: 7886 n += highlight(out, HLKEYWORD); 7887 n += fprintf(out, "break"); 7888 break; 7889 7890 case KCONTINUE: 7891 n += highlight(out, HLKEYWORD); 7892 n += fprintf(out, "continue"); 7893 break; 7894 case KWHILE: 7895 n += highlight(out, HLKEYWORD); 7896 n += fprintf(out, "while "); 7897 goto joinifbody; 7898 7899 case KFOR: 7900 n += highlight(out, HLKEYWORD); 7901 n += fprintf(out, "for "); 7902 goto joinifbody; 7903 7904 case AFORSTEP: 7905 n += printexpr(out, expr->lhs, indent); 7906 n += highlight(out, HLKEYWORD); 7907 n += fprintf(out, " to "); 7908 n += printexpr(out, expr->rhs, indent); 7909 7910 assert(expr->u.payload); 7911 if (expr->u.payload->kind == NUMBER && false) { 7912 if (isfloattype(expr->u.payload->type) 7913 && expr->u.payload->u.d == 1.0) 7914 break; 7915 if (isinttype(expr->u.payload->type) 7916 && expr->u.payload->u.u == 1) 7917 break; 7918 } 7919 n += highlight(out, HLKEYWORD); 7920 n += fprintf(out, " step "); 7921 n += printexpr(out, expr->u.payload, indent); 7922 break; 7923 7924 case KIF: 7925 n += highlight(out, HLKEYWORD); 7926 n += fprintf(out, "if "); 7927 /* FALLTHROUGH */ 7928 joinifbody: 7929 n += printexpr(out, expr->u.payload, indent); 7930 n += printclause(out, expr->lhs, indent); 7931 7932 if (expr->rhs) { 7933 int i; 7934 7935 n += fprintf(out, "\n"); 7936 7937 for (i = 0; i < indent; ++i) 7938 n += fprintf(out, "\t"); 7939 7940 n += highlight(out, HLKEYWORD); 7941 n += fprintf(out, "else"); 7942 n += printclause(out, expr->rhs, indent); 7943 } 7944 break; 7945 7946 case KLOOP: 7947 case ALOOPUNTIL: 7948 n += highlight(out, HLKEYWORD); 7949 n += fprintf(out, "loop"); 7950 n += printclause(out, expr->lhs, indent); 7951 if (expr->kind == KLOOP) 7952 break; 7953 7954 do { 7955 int i; 7956 n += fprintf(out, "\n"); 7957 7958 for (i = 0; i < indent; ++i) 7959 n += fprintf(out, "\t"); 7960 7961 } while (0); 7962 7963 n += highlight(out, HLKEYWORD); 7964 n += fprintf(out, "until "); 7965 n += printexpr(out, expr->u.payload, indent); 7966 7967 if (expr->rhs) { 7968 n += highlight(out, HLKEYWORD); 7969 n += fprintf(out, " else"); 7970 n += printclause(out, expr->rhs, indent); 7971 } 7972 break; 7973 7974 7975 case KDO: 7976 n += highlight(out, HLKEYWORD); 7977 n += fprintf(out, "do"); 7978 n += printclause(out, expr->lhs, indent); 7979 break; 7980 7981 case KUNION: 7982 case KSTRUCT: 7983 n += highlight(out, HLKEYWORD); 7984 7985 n += fprintf(out, 7986 expr->kind == KSTRUCT ? "struct" : "union"); 7987 7988 if (expr->lhs && expr->lhs->kind == IDENT) { 7989 n += highlight(out, HLTYPE); 7990 n += fprintf(out, " %s", 7991 getstring(idents, expr->lhs->u.key)); 7992 } 7993 7994 if (expr->rhs) 7995 n += printclause(out, expr->rhs, indent); 7996 7997 break; 7998 7999 case ASTMT: 8000 advancestmt: 8001 do { 8002 int i; 8003 8004 for (i = 0; i < indent; ++i) 8005 n += fprintf(out, "\t"); 8006 } while (0); 8007 8008 n += printexpr(out, expr->lhs, indent); 8009 8010 if (expr->rhs) { 8011 assert(expr->rhs->kind == ASTMT); 8012 n += fprintf(out, "\n"); 8013 expr = expr->rhs; 8014 goto advancestmt; 8015 } 8016 8017 break; 8018 8019 case ASCOPE: 8020 /* @todo improve this piece of code */ 8021 if (expr->lhs && 8022 expr->lhs->kind == ASTMT && 8023 expr->u.env && 8024 !isrecordenv(expr->u.env)) 8025 { 8026 Node *stmt = expr->lhs; 8027 8028 if (!stmt->rhs && isclauseorempty(stmt)) { 8029 n += printexpr(out, stmt->lhs, indent); 8030 break; 8031 } 8032 } 8033 n += printexpr(out, expr->lhs, indent); 8034 // n += fprintf(out, "\n"); /* blank line */ 8035 break; 8036 8037 case AENV: 8038 n += printexpr(out, expr->lhs, indent); 8039 break; 8040 8041 case ACONV: 8042 n += highlight(out, HLNUMBER); 8043 n += fprintf(out, "conv("); 8044 8045 n += highlight(out, HLTYPE); 8046 n += printtype(out, expr->type, indent); 8047 n += highlight(out, HLDELIM); 8048 8049 n += fprintf(out, ") "); 8050 n += printoperant(out, expr->lhs, PUNARY, false, indent); 8051 break; 8052 8053 case AADDR: 8054 n += highlight(out, HLDELIM); 8055 n += fputs("&{", out); 8056 n += printoperant(out, expr->lhs, PUNARY, false, indent); 8057 n += highlight(out, HLDELIM); 8058 n += fputs("}", out); 8059 break; 8060 8061 case ADEREF: 8062 n += highlight(out, HLDELIM); 8063 n += fputs("*{", out); 8064 n += printoperant(out, expr->lhs, PUNARY, false, indent); 8065 n += highlight(out, HLDELIM); 8066 n += fputs("}", out); 8067 break; 8068 8069 case ACOMPOUND: 8070 n += highlight(out, HLTYPE); 8071 n += printtype(out, expr->type, indent); 8072 n += highlight(out, HLDELIM); 8073 n += fputs("{", out); 8074 n += printexpr(out, expr->rhs, indent); 8075 n += highlight(out, HLDELIM); 8076 n += fputs("}", out); 8077 break; 8078 8079 case AFIELDINIT: 8080 if (expr->lhs) { 8081 n += highlight(out, HLDELIM); 8082 n += fprintf(out, "%s: ", getstring(idents, expr->u.key)); 8083 } 8084 n += printexpr(out, expr->rhs, indent); 8085 break; 8086 8087 case ASELFDISP: 8088 n += printexpr(out, expr->lhs, indent); 8089 n += highlight(out, HLNONE); 8090 /* @todo use printexpr when typechecked */ 8091 n += fprintf(out, ":%s", getstring(idents, expr->rhs->u.key)); 8092 break; 8093 8094 default: 8095 n += highlight(out, HLINFO); 8096 n += fprintf(out, "node(%u)", expr->kind); 8097 8098 if (expr->lhs) { 8099 n += fprintf(out, " -> "); 8100 n += printsubexpr(out, expr->lhs, true, indent); 8101 } 8102 if (expr->rhs) { 8103 n += highlight(out, HLINFO); 8104 n += fprintf(out, " => "); 8105 n += printsubexpr(out, expr->rhs, false, indent); 8106 } 8107 8108 break; 8109 } 8110 8111 finish: 8112 #if 0 8113 if (expr->kind == ASTMT && expr->next) { 8114 n += fprintf(out, "\n"); 8115 } else if (expr->next) { 8116 n += highlight(out, HLDELIM); 8117 n += fprintf(out, ", "); 8118 } 8119 #endif 8120 8121 return n; 8122 } 8123 8124 8125 8126 // }}} 8127 8128 // @section toplevel bundle & use {{{ 8129 8130 #if 0 8131 typedef struct String String; 8132 struct String { 8133 char *string; 8134 int length; 8135 }; 8136 8137 static String 8138 makestring(char *string) 8139 { 8140 String result; 8141 8142 result.string = string; 8143 result.length = strlen(string); 8144 8145 return result; 8146 } 8147 8148 static bool 8149 endswithcase(String name, String ending) 8150 { 8151 const int delta = name.length - ending.length; 8152 int i; 8153 8154 if (name.length < ending.length) 8155 return false; 8156 8157 for (i = 0; i < ending.length; ++i) { 8158 const int j = i + delta; 8159 if (tolower(name.string[j]) != ending.string[i]) 8160 return false; 8161 } 8162 8163 return true; 8164 } 8165 8166 static bool 8167 beginswith(String name, String beginning) 8168 { 8169 int i; 8170 8171 if (name.length < beginning.length) 8172 return false; 8173 8174 for (i = 0; i < beginning.length; ++i) { 8175 if (name.string[i] != beginning.string[i]) 8176 return false; 8177 } 8178 8179 return true; 8180 } 8181 8182 static String 8183 duplicatestring(String s) 8184 { 8185 String copy; 8186 8187 copy.string = (char *) calloc(s.length + 1, sizeof*(s.string)); 8188 copy.length = s.length; 8189 8190 assert(copy.string); 8191 strncpy(copy.string, s.string, s.length); 8192 8193 return copy; 8194 } 8195 #endif 8196 8197 // }}} 8198 8199 // @section init source {{{ 8200 8201 static void 8202 initsource(Source *source, Source *parent, Compiler *compiler, 8203 const char *filename, FILE *file) 8204 { 8205 source->filein = file; 8206 source->currloc.filename = filename; 8207 source->tok.loc.filename = filename; 8208 source->tabwidth = 8; 8209 source->haspendingenv = false; 8210 source->handlereplprompt = false; 8211 8212 source->pendingcount = 0; 8213 8214 source->implicitenv = myalloc(&arenas->env, Env); 8215 8216 gettok(source); 8217 if (getkind(source) == LINEDELIM) 8218 gettok(source); 8219 8220 source->compiler = compiler; 8221 source->parent = parent; 8222 if (parent) 8223 listappend(parent, source); 8224 } 8225 8226 static void 8227 disposesource(Source *source) 8228 { 8229 fclose(source->filein); 8230 } 8231 8232 8233 8234 // }}} 8235 8236 // @section main-routine {{{ 8237 8238 static const char * 8239 isolatecommand(char **string) 8240 { 8241 char *commandline = *string; 8242 const char *command; 8243 8244 while (isspace(*commandline)) 8245 ++commandline; 8246 8247 command = commandline; 8248 8249 while (!isspace(*commandline) && *commandline) 8250 ++commandline; 8251 8252 if (*commandline) 8253 *commandline = 0, ++commandline; 8254 8255 *string = commandline; 8256 8257 return command; 8258 } 8259 8260 static bool 8261 processcommand(Source *source) 8262 { 8263 char *commandline = source->line + 1; 8264 8265 const char *command = isolatecommand(&commandline); 8266 8267 if (!strcmp(command, "exit")) { 8268 source->line[0] = 0; 8269 return false; 8270 } 8271 8272 if (!strcmp(command, "memory")) { 8273 int i; 8274 8275 printf("ast-nodes: %5u, deletes: %5u, total: %5u\n", 8276 arenas->node.top, poolednodecount, totalnodecount); 8277 8278 printf("type-nodes: %5u\n", arenas->type.top); 8279 printf("declarations: %5u\n", arenas->decl.top); 8280 printf("environments: %5u\n", arenas->env.top); 8281 8282 for (i = 0; i < arenas->node.top; ++i) { 8283 Node *node = getalloc(&arenas->node, i); 8284 8285 if (node->kind == 0) 8286 continue; 8287 8288 highlight(stdout, HLINFO); 8289 printf("node[%u]:\n", i); 8290 printexpr(stdout, node, 0); 8291 printf("\n"); 8292 } 8293 8294 goto finish; 8295 } 8296 8297 if (!strcmp(command, "delete")) { 8298 command = isolatecommand(&commandline); 8299 8300 if (!strcmp(command, "node") || 8301 !strcmp(command, "ast-node") || 8302 isdigit(*command)) 8303 { 8304 int i; 8305 8306 if (!isdigit(*command)) 8307 command = isolatecommand(&commandline); 8308 8309 i = atoi(command); 8310 8311 if (i < 4096 && i >= 0) { 8312 Node *node = getalloc(&arenas->node, i); 8313 8314 if (node->kind != 0) 8315 deletenode(node); 8316 else 8317 printf("already deleted.\n"); 8318 } else { 8319 fprintf(stderr, "error: invalid number.\n"); 8320 } 8321 } else { 8322 fprintf(stderr, "error: unknown argument '%s'.\n", 8323 command); 8324 } 8325 8326 goto finish; 8327 } 8328 8329 fprintf(stderr, "error: unknown command '%s'.\n", command); 8330 finish: 8331 return mygetline(source); 8332 } 8333 8334 static void 8335 handlelineending(Source *source); 8336 8337 char bundlenamebuffer[1024 * 4]; 8338 int bundlenamelength = 0; 8339 8340 static void 8341 processfile(Source *source, CodeGen *cg); 8342 8343 static bool 8344 processtopleveluse(Source *source, SrcLoc *loc, 8345 const int bundlepath[], int count) 8346 { 8347 static const char prefix[] = "arialib/"; 8348 static const char suffix[] = ".co"; 8349 8350 FILE *importfile = NULL; 8351 const char *filename = NULL; 8352 Source *curr = NULL; 8353 8354 int i; 8355 8356 if (sizeof(prefix) - 1 > sizeof(bundlenamebuffer) - 1) 8357 goto errorlength; 8358 8359 bundlenamelength = sizeof(prefix) - 1; 8360 memcpy(bundlenamebuffer, prefix, sizeof(prefix) - 1); 8361 8362 for (i = 0; i < count; ++i) { 8363 const int key = bundlepath[i]; 8364 const char *string = getstring(idents, key); 8365 const int length = getlength(idents, key); 8366 8367 if (length + bundlenamelength > sizeof(bundlenamebuffer) - 1) 8368 goto errorlength; 8369 8370 memcpy(bundlenamebuffer + bundlenamelength, string, length); 8371 bundlenamelength += length; 8372 8373 if (i >= count - 1) 8374 continue; 8375 8376 if (bundlenamelength + 1 > sizeof(bundlenamebuffer) - 1) 8377 goto errorlength; 8378 8379 bundlenamebuffer[bundlenamelength++] = '/'; 8380 } 8381 8382 if (bundlenamelength + sizeof(suffix) - 1 > sizeof(bundlenamebuffer) - 1) 8383 goto errorlength; 8384 8385 memcpy(bundlenamebuffer + bundlenamelength, suffix, sizeof(suffix) - 1); 8386 bundlenamelength += sizeof(suffix) - 1; 8387 bundlenamebuffer[bundlenamelength] = '\0'; 8388 8389 /* check for cyclic import */ 8390 for (curr = source; curr; curr = curr->parent) { 8391 if (!strcmp(curr->currloc.filename, bundlenamebuffer)) { 8392 error("cyclic import of file '%s'", bundlenamebuffer); 8393 return false; 8394 } 8395 } 8396 8397 filename = calloc(bundlenamelength + 1, sizeof*(bundlenamebuffer)); 8398 8399 if (!filename) { 8400 error(loc, "out of memory"); 8401 return false; 8402 } 8403 8404 memcpy(filename, bundlenamebuffer, bundlenamelength); 8405 8406 importfile = fopen(filename, "r"); 8407 8408 if (!importfile) { 8409 error(loc, "could not open bundle file '%s'", filename); 8410 return false; 8411 } 8412 8413 warn(loc, "using bundle '%s'", filename); 8414 8415 curr = calloc(1, sizeof*(curr)); 8416 initsource(curr, source, source->compiler, filename, importfile); 8417 processfile(curr, &source->compiler->cg); 8418 disposesource(curr); 8419 8420 free(filename); 8421 8422 return true; 8423 8424 errorlength: 8425 error(loc, "bundle path is too long"); 8426 return false; 8427 } 8428 8429 static bool 8430 isnodepending(Source *source, Node *ast) 8431 { 8432 Decl *decl; 8433 8434 if (ast->kind != ADECL) 8435 return false; 8436 8437 decl = ast->u.declref; 8438 if (decl->kind != DFUNCTION) 8439 return false; 8440 8441 assert(decl->contentenv); 8442 return decl->contentenv->pending; 8443 } 8444 8445 static Node * 8446 toplevel(Source *source, Block *block) 8447 { 8448 Node *ast; 8449 8450 redo: 8451 readannots(source); 8452 if (getkind(source) == KBUNDLE) { 8453 SrcLoc loc = *getloc(source); 8454 #if 0 8455 int bundlekey = 0; 8456 gettok(source); 8457 while (getkind(source) == IDENT) { 8458 char *name = getstring(idents, source->tok.u.key); 8459 int length = getlength(idents, source->tok.u.key); 8460 8461 /* @fixme check name length */ 8462 memcpy(bundlenamebuffer + bundlenamelength, name, length); 8463 bundlenamelength += length; 8464 gettok(source); 8465 bundlenamebuffer[bundlenamelength] = '\0'; 8466 8467 if (getkind(source) != ODISP) 8468 break; 8469 8470 gettok(source); 8471 bundlenamebuffer[bundlenamelength++] = '_'; 8472 bundlenamebuffer[bundlenamelength] = '\0'; 8473 } 8474 8475 if (bundlenamelength) { 8476 bundlekey = getstringkey(&idents, bundlenamebuffer, 8477 bundlenamelength); 8478 assert(source->currenv); 8479 source->currenv->bundle = makedecl(source, bundlekey, 8480 DBUNDLE); 8481 source->currenv->loc = loc; 8482 } 8483 #else 8484 Decl *bundle = NULL; 8485 gettok(source); 8486 while (getkind(source) == IDENT) { 8487 const int bundlekey = source->tok.u.key; 8488 8489 assert(source->currenv); 8490 bundle = makebundle(source, bundlekey, bundle); 8491 8492 gettok(source); 8493 8494 if (getkind(source) != ODISP) 8495 break; 8496 8497 gettok(source); 8498 } 8499 8500 if (bundle) { 8501 source->currenv->bundle = bundle; 8502 source->currenv->loc = loc; 8503 } else { 8504 /* @note is this correct? */ 8505 source->currenv->bundle = NULL; 8506 } 8507 #endif 8508 8509 handlelineending(source); 8510 goto redo; 8511 } 8512 8513 if (getkind(source) == KUSE) { 8514 int bundlepath[64]; 8515 int bundlepathtop = 0; 8516 8517 SrcLoc loc = *getloc(source); 8518 8519 gettok(source); 8520 while (getkind(source) == IDENT) { 8521 const int bundlekey = source->tok.u.key; 8522 8523 bundlepath[bundlepathtop++] = bundlekey; 8524 8525 gettok(source); 8526 8527 if (getkind(source) != ODISP) 8528 break; 8529 8530 gettok(source); 8531 } 8532 8533 handlelineending(source); 8534 8535 processtopleveluse(source, &loc, bundlepath, bundlepathtop); 8536 goto redo; 8537 } 8538 ast = exprlist(source, false, NULL); 8539 /* ast = readexpr(source, PSTART); */ 8540 /* 8541 printast(ast, 0); 8542 printf("\n"); 8543 */ 8544 if ((ast->kind != ADECL 8545 || !ast->u.payload 8546 || ast->u.payload->kind != ASCOPE) 8547 && !isnodepending(source, ast)) 8548 { 8549 ast = typecheck(source->currenv, ast); 8550 ast = foldexpr(source->currenv, ast); 8551 dataflow(block, ast); 8552 } 8553 ast = extractnestedfunctions(source->currenv, ast); 8554 8555 return ast; 8556 } 8557 8558 static void 8559 processpendingenvs(Source *source, Block *block) 8560 { 8561 Env *p; 8562 8563 for (p = source->pendingenvhead; p; p = p->pendingnext) { 8564 if (p->stmts) { 8565 p->stmts = typecheck(source->currenv, p->stmts); 8566 p->stmts = foldexpr(source->currenv, p->stmts); 8567 dataflow(block, p->stmts); 8568 8569 /* debug prints: */ 8570 highlight(stdout, HLINFO); 8571 printf("statements:\n"); 8572 highlight(stdout, HLNONE); 8573 printexpr(stdout, p->stmts, 1); 8574 8575 highlight(stdout, HLINFO); 8576 fputs(" : ", stdout); 8577 printtype(stdout, p->stmts->type, 0); 8578 highlight(stdout, HLNONE); 8579 8580 printf("\n"); 8581 } 8582 } 8583 8584 } 8585 8586 static void 8587 handlelineending(Source *source) 8588 { 8589 if (getkind(source) == LINEDELIM) { 8590 if (source->filein == stdin) { 8591 highlight(stdout, HLPROMPT); 8592 printf("> "); 8593 highlight(stdout, HLNONE); 8594 source->handlereplprompt = false; 8595 } 8596 gettok(source); 8597 } else if (getkind(source) == SEMIDELIM) { 8598 gettok(source); 8599 } 8600 8601 if (source->lastkind != SEMIDELIM && source->lastkind != LINEDELIM){ 8602 error(getloc(source), "expected new line"); 8603 while (getkind(source) != SEMIDELIM && 8604 getkind(source) != LINEDELIM && 8605 getkind(source) != 0) 8606 { 8607 gettok(source); 8608 } 8609 8610 if (source->filein == stdin) { 8611 highlight(stdout, HLPROMPT); 8612 printf("> "); 8613 highlight(stdout, HLNONE); 8614 source->handlereplprompt = false; 8615 } 8616 8617 if (getkind(source) != 0) 8618 gettok(source); 8619 } 8620 } 8621 8622 static void 8623 makeintrinsic(Source *source, const char *name, Type *type, bool isfunction) 8624 { 8625 Decl *r; 8626 const int key = getstringkey(&idents, name, strlen(name)); 8627 8628 if (isfunction) { 8629 r = makedecl(source, key, DFUNCTION); 8630 r->type = maketype(&source->arenas, &source->tok.loc, 8631 primitive(TFUNCTION), NULL); 8632 r->type->u.rtarget = type; 8633 } else { 8634 r = makedecl(source, key, DVAR); 8635 r->type = type; 8636 } 8637 } 8638 8639 static void 8640 initintrinsics(Source *source) 8641 { 8642 Type *tint = primitive(TINT); 8643 Type *tvoid = primitive(TVOID); 8644 Type *voidptr = maketype(&source->arenas, &source->tok.loc, 8645 primitive(TPTR), primitive(TVOID)); 8646 8647 #define intfunc(name, rtype) \ 8648 makeintrinsic(source, name, rtype, true) 8649 8650 intfunc("puts", tint); 8651 intfunc("printf", tint); 8652 intfunc("vprintf", tint); 8653 intfunc("fprintf", tint); 8654 intfunc("vfprintf", tint); 8655 intfunc("sprintf", tint); 8656 intfunc("vsprintf", tint); 8657 intfunc("fopen", voidptr); 8658 intfunc("ftell", tint); 8659 intfunc("fseek", tint); 8660 intfunc("fread", tint); 8661 intfunc("fwrite", tint); 8662 intfunc("fflush", tint); 8663 intfunc("fclose", tint); 8664 8665 intfunc("calloc", voidptr); 8666 intfunc("malloc", voidptr); 8667 intfunc("realloc", voidptr); 8668 8669 intfunc("free", tvoid); 8670 8671 makeintrinsic(source, "SEEK_SET", tint, false); 8672 makeintrinsic(source, "SEEK_CUR", tint, false); 8673 makeintrinsic(source, "SEEK_END", tint, false); 8674 8675 #undef intfunc 8676 } 8677 8678 static void 8679 processfile(Source *source, CodeGen *cg) 8680 { 8681 Env *save; 8682 Block *block; 8683 8684 pushenv(source, STOPLEVEL); 8685 block = makeblock(BTOPLEVEL, source->currenv); 8686 appendconduct(block, CSCOPE, NULL); 8687 8688 initintrinsics(source); 8689 8690 save = cg->env; 8691 cg->env = source->currenv; 8692 while (getkind(source) != 0) { 8693 /* printf("token:%i:%i: %c '%.*s'\n", lastline, lastcol + 1, 8694 tok.u.id, currcol - lastcol, line + lastcol);*/ 8695 Node *ast = toplevel(source, block); 8696 8697 highlight(stdout, HLINFO); 8698 printf("number of nested functions: %u\n", extractedtop - 1); 8699 highlight(stdout, HLNONE); 8700 8701 if (source->filein == stdin) { 8702 highlight(stdout, HLINFO); 8703 fputs("= ", stdout); 8704 highlight(stdout, HLNONE); 8705 } 8706 8707 printexpr(stdout, ast, 0); 8708 highlight(stdout, HLNONE); 8709 8710 if (source->filein == stdin) { 8711 highlight(stdout, HLINFO); 8712 fputs(" : ", stdout); 8713 printtype(stdout, ast->type, 0); 8714 highlight(stdout, HLNONE); 8715 } 8716 printf("\n"); 8717 8718 cgtoplevel(source, ast, cg); 8719 handlelineending(source); 8720 } 8721 8722 highlight(stdout, HLINFO); 8723 puts("dump pending environments ..."); 8724 highlight(stdout, HLNONE); 8725 8726 processpendingenvs(source, block); 8727 cgtoplevelfinish(source, cg); 8728 /* dfpopconduct(); */ 8729 popenv(source); 8730 8731 highlight(stdout, HLINFO); 8732 printf("exiting with %u errors and %u warnings ...\n", 8733 errorcount, warningcount); 8734 highlight(stdout, HLNONE); 8735 cg->env = save; 8736 } 8737 8738 int 8739 main(int argc, char **argv) 8740 { 8741 Compiler compiler = {}; 8742 Source *source = &testsource; 8743 arenas = &source->arenas; 8744 8745 initkeywords(); 8746 initstrmap(&idents); 8747 initstrmap(&strings); 8748 8749 auxthen = getstringkey(&idents, "then", 4); 8750 auxin = getstringkey(&idents, "in", 2); 8751 auxto = getstringkey(&idents, "to", 2); 8752 auxstep = getstringkey(&idents, "step", 4); 8753 8754 auxself = getstringkey(&idents, "self", 4); 8755 8756 if (argc >= 2) { 8757 initsource(source, NULL, &compiler, 8758 argv[1], fopen(argv[1], "rb")); 8759 assert(source->filein); 8760 } else { 8761 highlight(stdout, HLPROMPT); 8762 printf("> "); 8763 highlight(stdout, HLNONE); 8764 initsource(source, NULL, &compiler, "<stdin>", stdin); 8765 } 8766 8767 cginit(&compiler.cg, fopen("out.c", "wb")); 8768 processfile(source, &compiler.cg); 8769 fclose(compiler.cg.out); 8770 8771 highlight(stdout, HLINFO); 8772 printf("number of nodes: % 6zu\n", arenas->node.top); 8773 printf("number of types: % 6zu\n", arenas->type.top); 8774 printf("number of environments: % 6zu\n", arenas->env.top); 8775 printf("number of declarations: % 6zu\n", arenas->decl.top); 8776 printf("number of annotations: % 6zu\n", arenas->annot.top); 8777 printf("number of dockets: % 6zu\n", arenas->docket.top); 8778 printf("number of records: % 6zu\n", arenas->record.top); 8779 printf("number of fields: % 6zu\n", arenas->field.top); 8780 printf("number of blocks: % 6zu\n", arenas->block.top); 8781 printf("number of conducts: % 6zu\n", arenas->conduct.top); 8782 printf("number of gists: % 6zu\n", arenas->gist.top); 8783 highlight(stdout, HLNONE); 8784 printf("\x1b[0m"); 8785 8786 /* fclose(source->filein); */ 8787 /* disposestrmap(&strings); */ 8788 /* disposestrmap(&idents); */ 8789 8790 return !!errorcount; 8791 } 8792 8793 // }}}