[
  {
    "path": ".gitignore",
    "content": "**/*~\n**/\\#*\n**/*.o\n**/*.s\n**/a.out\n/tmp*\n/thirdparty\n/chibicc\n/test/*.exe\n/stage2\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Rui Ueyama\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "CFLAGS=-std=c11 -g -fno-common -Wall -Wno-switch\n\nSRCS=$(wildcard *.c)\nOBJS=$(SRCS:.c=.o)\n\nTEST_SRCS=$(wildcard test/*.c)\nTESTS=$(TEST_SRCS:.c=.exe)\n\n# Stage 1\n\nchibicc: $(OBJS)\n\t$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)\n\n$(OBJS): chibicc.h\n\ntest/%.exe: chibicc test/%.c\n\t./chibicc -Iinclude -Itest -c -o test/$*.o test/$*.c\n\t$(CC) -pthread -o $@ test/$*.o -xc test/common\n\ntest: $(TESTS)\n\tfor i in $^; do echo $$i; ./$$i || exit 1; echo; done\n\ttest/driver.sh ./chibicc\n\ntest-all: test test-stage2\n\n# Stage 2\n\nstage2/chibicc: $(OBJS:%=stage2/%)\n\t$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)\n\nstage2/%.o: chibicc %.c\n\tmkdir -p stage2/test\n\t./chibicc -c -o $(@D)/$*.o $*.c\n\nstage2/test/%.exe: stage2/chibicc test/%.c\n\tmkdir -p stage2/test\n\t./stage2/chibicc -Iinclude -Itest -c -o stage2/test/$*.o test/$*.c\n\t$(CC) -pthread -o $@ stage2/test/$*.o -xc test/common\n\ntest-stage2: $(TESTS:test/%=stage2/test/%)\n\tfor i in $^; do echo $$i; ./$$i || exit 1; echo; done\n\ttest/driver.sh ./stage2/chibicc\n\n# Misc.\n\nclean:\n\trm -rf chibicc tmp* $(TESTS) test/*.s test/*.exe stage2\n\tfind * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';'\n\n.PHONY: test clean test-stage2\n"
  },
  {
    "path": "README.md",
    "content": "# chibicc: A Small C Compiler\n\n(The old master has moved to\n[historical/old](https://github.com/rui314/chibicc/tree/historical/old)\nbranch. This is a new one uploaded in September 2020.)\n\nchibicc is yet another small C compiler that implements most C11\nfeatures. Even though it still probably falls into the \"toy compilers\"\ncategory just like other small compilers do, chibicc can compile\nseveral real-world programs, including [Git](https://git-scm.com/),\n[SQLite](https://sqlite.org),\n[libpng](http://www.libpng.org/pub/png/libpng.html) and chibicc\nitself, without making modifications to the compiled programs.\nGenerated executables of these programs pass their corresponding test\nsuites. So, chibicc actually supports a wide variety of C11 features\nand is able to compile hundreds of thousands of lines of real-world C\ncode correctly.\n\nchibicc is developed as the reference implementation for a book I'm\ncurrently writing about the C compiler and the low-level programming.\nThe book covers the vast topic with an incremental approach; in the first\nchapter, readers will implement a \"compiler\" that accepts just a single\nnumber as a \"language\", which will then gain one feature at a time in each\nsection of the book until the language that the compiler accepts matches\nwhat the C11 spec specifies. I took this incremental approach from [the\npaper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz\nGhuloum.\n\nEach commit of this project corresponds to a section of the book. For this\npurpose, not only the final state of the project but each commit was\ncarefully written with readability in mind. Readers should be able to learn\nhow a C language feature can be implemented just by reading one or a few\ncommits of this project. For example, this is how\n[while](https://github.com/rui314/chibicc/commit/773115ab2a9c4b96f804311b95b20e9771f0190a),\n[[]](https://github.com/rui314/chibicc/commit/75fbd3dd6efde12eac8225d8b5723093836170a5),\n[?:](https://github.com/rui314/chibicc/commit/1d0e942fd567a35d296d0f10b7693e98b3dd037c),\nand [thread-local\nvariable](https://github.com/rui314/chibicc/commit/79644e54cc1805e54428cde68b20d6d493b76d34)\nare implemented. If you have plenty of spare time, it might be fun to read\nit from the [first\ncommit](https://github.com/rui314/chibicc/commit/0522e2d77e3ab82d3b80a5be8dbbdc8d4180561c).\n\nIf you like this project, please consider purchasing a copy of the book\nwhen it becomes available! 😀 I publish the source code here to give people\nearly access to it, because I was planing to do that anyway with a\npermissive open-source license after publishing the book. If I don't charge\nfor the source code, it doesn't make much sense to me to keep it private. I\nhope to publish the book in 2021.\nYou can sign up [here](https://forms.gle/sgrMWHGeGjeeEJcX7) to receive a\nnotification when a free chapter is available online or the book is published.\n\nI pronounce chibicc as _chee bee cee cee_. \"chibi\" means \"mini\" or\n\"small\" in Japanese. \"cc\" stands for C compiler.\n\n## Status\n\nchibicc supports almost all mandatory features and most optional\nfeatures of C11 as well as a few GCC language extensions.\n\nFeatures that are often missing in a small compiler but supported by\nchibicc include (but not limited to):\n\n- Preprocessor\n- float, double and long double (x87 80-bit floating point numbers)\n- Bit-fields\n- alloca()\n- Variable-length arrays\n- Compound literals\n- Thread-local variables\n- Atomic variables\n- Common symbols\n- Designated initializers\n- L, u, U and u8 string literals\n- Functions that take or return structs as values, as specified by the\n  x86-64 SystemV ABI\n\nchibicc does not support complex numbers, K&R-style function prototypes\nand GCC-style inline assembly. Digraphs and trigraphs are intentionally\nleft out.\n\nchibicc outputs a simple but nice error message when it finds an error in\nsource code.\n\nThere's no optimization pass. chibicc emits terrible code which is probably\ntwice or more slower than GCC's output. I have a plan to add an\noptimization pass once the frontend is done.\n\nI'm using Ubuntu 20.04 for x86-64 as a development platform. I made a\nfew small changes so that chibicc works on Ubuntu 18.04, Fedora 32 and\nGentoo 2.6, but portability is not my goal at this moment. It may or\nmay not work on systems other than Ubuntu 20.04.\n\n## Internals\n\nchibicc consists of the following stages:\n\n- Tokenize: A tokenizer takes a string as an input, breaks it into a list\n  of tokens and returns them.\n\n- Preprocess: A preprocessor takes as an input a list of tokens and output\n  a new list of macro-expanded tokens. It interprets preprocessor\n  directives while expanding macros.\n\n- Parse: A recursive descendent parser constructs abstract syntax trees\n  from the output of the preprocessor. It also adds a type to each AST\n  node.\n\n- Codegen: A code generator emits an assembly text for given AST nodes.\n\n## Contributing\n\nWhen I find a bug in this compiler, I go back to the original commit that\nintroduced the bug and rewrite the commit history as if there were no such\nbug from the beginning. This is an unusual way of fixing bugs, but as a\npart of a book, it is important to keep every commit bug-free.\n\nThus, I do not take pull requests in this repo. You can send me a pull\nrequest if you find a bug, but it is very likely that I will read your\npatch and then apply that to my previous commits by rewriting history. I'll\ncredit your name somewhere, but your changes will be rewritten by me before\nsubmitted to this repository.\n\nAlso, please assume that I will occasionally force-push my local repository\nto this public one to rewrite history. If you clone this project and make\nlocal commits on top of it, your changes will have to be rebased by hand\nwhen I force-push new commits.\n\n## Design principles\n\nchibicc's core value is its simplicity and the reability of its source\ncode. To achieve this goal, I was careful not to be too clever when\nwriting code. Let me explain what that means.\n\nOftentimes, as you get used to the code base, you are tempted to\n_improve_ the code using more abstractions and clever tricks.\nBut that kind of _improvements_ don't always improve readability for\nfirst-time readers and can actually hurts it. I tried to avoid the\npitfall as much as possible. I wrote this code not for me but for\nfirst-time readers.\n\nIf you take a look at the source code, you'll find a couple of\ndumb-looking pieces of code. These are written intentionally that way\n(but at some places I might be actually missing something,\nthough). Here is a few notable examples:\n\n- The recursive descendent parser contains many similar-looking functions\n  for similar-looking generative grammar rules. You might be tempted\n  to _improve_ it to reduce the duplication using higher-order functions\n  or macros, but I thought that that's too complicated. It's better to\n  allow small duplications instead.\n\n- chibicc doesn't try too hard to save memory. An entire input source\n  file is read to memory first before the tokenizer kicks in, for example.\n\n- Slow algorithms are fine if we know that n isn't too big.\n  For example, we use a linked list as a set in the preprocessor, so\n  the membership check takes O(n) where n is the size of the set.  But\n  that's fine because we know n is usually very small.\n  And even if n can be very big, I stick with a simple slow algorithm\n  until it is proved by benchmarks that that's a bottleneck.\n\n- Each AST node type uses only a few members of the `Node` struct members.\n  Other unused `Node` members are just a waste of memory at runtime.\n  We could save memory using unions, but I decided to simply put everything\n  in the same struct instead. I believe the inefficiency is negligible.\n  Even if it matters, we can always change the code to use unions\n  at any time. I wanted to avoid premature optimization.\n\n- chibicc always allocates heap memory using `calloc`, which is a\n  variant of `malloc` that clears memory with zero. `calloc` is\n  slightly slower than `malloc`, but that should be neligible.\n\n- Last but not least, chibicc allocates memory using `calloc` but never\n  calls `free`. Allocated heap memory is not freed until the process exits.\n  I'm sure that this memory management policy (or lack thereof) looks\n  very odd, but it makes sense for short-lived programs such as compilers.\n  DMD, a compiler for the D programming language, uses the same memory\n  management scheme for the same reason, for example [1].\n\n## About the Author\n\nI'm Rui Ueyama. I'm the creator of [8cc](https://github.com/rui314/8cc),\nwhich is a hobby C compiler, and also the original creator of the current\nversion of [LLVM lld](https://lld.llvm.org) linker, which is a\nproduction-quality linker used by various operating systems and large-scale\nbuild systems.\n\n## References\n\n- [tcc](https://bellard.org/tcc/): A small C compiler written by Fabrice\n  Bellard. I learned a lot from this compiler, but the design of tcc and\n  chibicc are different. In particular, tcc is a one-pass compiler, while\n  chibicc is a multi-pass one.\n\n- [lcc](https://github.com/drh/lcc): Another small C compiler. The creators\n  wrote a [book](https://sites.google.com/site/lccretargetablecompiler/)\n  about the internals of lcc, which I found a good resource to see how a\n  compiler is implemented.\n\n- [An Incremental Approach to Compiler\n  Construction](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf)\n\n- [Rob Pike's 5 Rules of Programming](https://users.ece.utexas.edu/~adnan/pike.html)\n\n[1] https://www.drdobbs.com/cpp/increasing-compiler-speed-by-over-75/240158941\n\n> DMD does memory allocation in a bit of a sneaky way. Since compilers\n> are short-lived programs, and speed is of the essence, DMD just\n> mallocs away, and never frees.\n"
  },
  {
    "path": "chibicc.h",
    "content": "#define _POSIX_C_SOURCE 200809L\n#include <assert.h>\n#include <ctype.h>\n#include <errno.h>\n#include <glob.h>\n#include <libgen.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdnoreturn.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <sys/wait.h>\n#include <time.h>\n#include <unistd.h>\n\n#define MAX(x, y) ((x) < (y) ? (y) : (x))\n#define MIN(x, y) ((x) < (y) ? (x) : (y))\n\n#ifndef __GNUC__\n# define __attribute__(x)\n#endif\n\ntypedef struct Type Type;\ntypedef struct Node Node;\ntypedef struct Member Member;\ntypedef struct Relocation Relocation;\ntypedef struct Hideset Hideset;\n\n//\n// strings.c\n//\n\ntypedef struct {\n  char **data;\n  int capacity;\n  int len;\n} StringArray;\n\nvoid strarray_push(StringArray *arr, char *s);\nchar *format(char *fmt, ...) __attribute__((format(printf, 1, 2)));\n\n//\n// tokenize.c\n//\n\n// Token\ntypedef enum {\n  TK_IDENT,   // Identifiers\n  TK_PUNCT,   // Punctuators\n  TK_KEYWORD, // Keywords\n  TK_STR,     // String literals\n  TK_NUM,     // Numeric literals\n  TK_PP_NUM,  // Preprocessing numbers\n  TK_EOF,     // End-of-file markers\n} TokenKind;\n\ntypedef struct {\n  char *name;\n  int file_no;\n  char *contents;\n\n  // For #line directive\n  char *display_name;\n  int line_delta;\n} File;\n\n// Token type\ntypedef struct Token Token;\nstruct Token {\n  TokenKind kind;   // Token kind\n  Token *next;      // Next token\n  int64_t val;      // If kind is TK_NUM, its value\n  long double fval; // If kind is TK_NUM, its value\n  char *loc;        // Token location\n  int len;          // Token length\n  Type *ty;         // Used if TK_NUM or TK_STR\n  char *str;        // String literal contents including terminating '\\0'\n\n  File *file;       // Source location\n  char *filename;   // Filename\n  int line_no;      // Line number\n  int line_delta;   // Line number\n  bool at_bol;      // True if this token is at beginning of line\n  bool has_space;   // True if this token follows a space character\n  Hideset *hideset; // For macro expansion\n  Token *origin;    // If this is expanded from a macro, the original token\n};\n\nnoreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));\nnoreturn void error_at(char *loc, char *fmt, ...) __attribute__((format(printf, 2, 3)));\nnoreturn void error_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));\nvoid warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));\nbool equal(Token *tok, char *op);\nToken *skip(Token *tok, char *op);\nbool consume(Token **rest, Token *tok, char *str);\nvoid convert_pp_tokens(Token *tok);\nFile **get_input_files(void);\nFile *new_file(char *name, int file_no, char *contents);\nToken *tokenize_string_literal(Token *tok, Type *basety);\nToken *tokenize(File *file);\nToken *tokenize_file(char *filename);\n\n#define unreachable() \\\n  error(\"internal error at %s:%d\", __FILE__, __LINE__)\n\n//\n// preprocess.c\n//\n\nchar *search_include_paths(char *filename);\nvoid init_macros(void);\nvoid define_macro(char *name, char *buf);\nvoid undef_macro(char *name);\nToken *preprocess(Token *tok);\n\n//\n// parse.c\n//\n\n// Variable or function\ntypedef struct Obj Obj;\nstruct Obj {\n  Obj *next;\n  char *name;    // Variable name\n  Type *ty;      // Type\n  Token *tok;    // representative token\n  bool is_local; // local or global/function\n  int align;     // alignment\n\n  // Local variable\n  int offset;\n\n  // Global variable or function\n  bool is_function;\n  bool is_definition;\n  bool is_static;\n\n  // Global variable\n  bool is_tentative;\n  bool is_tls;\n  char *init_data;\n  Relocation *rel;\n\n  // Function\n  bool is_inline;\n  Obj *params;\n  Node *body;\n  Obj *locals;\n  Obj *va_area;\n  Obj *alloca_bottom;\n  int stack_size;\n\n  // Static inline function\n  bool is_live;\n  bool is_root;\n  StringArray refs;\n};\n\n// Global variable can be initialized either by a constant expression\n// or a pointer to another global variable. This struct represents the\n// latter.\ntypedef struct Relocation Relocation;\nstruct Relocation {\n  Relocation *next;\n  int offset;\n  char **label;\n  long addend;\n};\n\n// AST node\ntypedef enum {\n  ND_NULL_EXPR, // Do nothing\n  ND_ADD,       // +\n  ND_SUB,       // -\n  ND_MUL,       // *\n  ND_DIV,       // /\n  ND_NEG,       // unary -\n  ND_MOD,       // %\n  ND_BITAND,    // &\n  ND_BITOR,     // |\n  ND_BITXOR,    // ^\n  ND_SHL,       // <<\n  ND_SHR,       // >>\n  ND_EQ,        // ==\n  ND_NE,        // !=\n  ND_LT,        // <\n  ND_LE,        // <=\n  ND_ASSIGN,    // =\n  ND_COND,      // ?:\n  ND_COMMA,     // ,\n  ND_MEMBER,    // . (struct member access)\n  ND_ADDR,      // unary &\n  ND_DEREF,     // unary *\n  ND_NOT,       // !\n  ND_BITNOT,    // ~\n  ND_LOGAND,    // &&\n  ND_LOGOR,     // ||\n  ND_RETURN,    // \"return\"\n  ND_IF,        // \"if\"\n  ND_FOR,       // \"for\" or \"while\"\n  ND_DO,        // \"do\"\n  ND_SWITCH,    // \"switch\"\n  ND_CASE,      // \"case\"\n  ND_BLOCK,     // { ... }\n  ND_GOTO,      // \"goto\"\n  ND_GOTO_EXPR, // \"goto\" labels-as-values\n  ND_LABEL,     // Labeled statement\n  ND_LABEL_VAL, // [GNU] Labels-as-values\n  ND_FUNCALL,   // Function call\n  ND_EXPR_STMT, // Expression statement\n  ND_STMT_EXPR, // Statement expression\n  ND_VAR,       // Variable\n  ND_VLA_PTR,   // VLA designator\n  ND_NUM,       // Integer\n  ND_CAST,      // Type cast\n  ND_MEMZERO,   // Zero-clear a stack variable\n  ND_ASM,       // \"asm\"\n  ND_CAS,       // Atomic compare-and-swap\n  ND_EXCH,      // Atomic exchange\n} NodeKind;\n\n// AST node type\nstruct Node {\n  NodeKind kind; // Node kind\n  Node *next;    // Next node\n  Type *ty;      // Type, e.g. int or pointer to int\n  Token *tok;    // Representative token\n\n  Node *lhs;     // Left-hand side\n  Node *rhs;     // Right-hand side\n\n  // \"if\" or \"for\" statement\n  Node *cond;\n  Node *then;\n  Node *els;\n  Node *init;\n  Node *inc;\n\n  // \"break\" and \"continue\" labels\n  char *brk_label;\n  char *cont_label;\n\n  // Block or statement expression\n  Node *body;\n\n  // Struct member access\n  Member *member;\n\n  // Function call\n  Type *func_ty;\n  Node *args;\n  bool pass_by_stack;\n  Obj *ret_buffer;\n\n  // Goto or labeled statement, or labels-as-values\n  char *label;\n  char *unique_label;\n  Node *goto_next;\n\n  // Switch\n  Node *case_next;\n  Node *default_case;\n\n  // Case\n  long begin;\n  long end;\n\n  // \"asm\" string literal\n  char *asm_str;\n\n  // Atomic compare-and-swap\n  Node *cas_addr;\n  Node *cas_old;\n  Node *cas_new;\n\n  // Atomic op= operators\n  Obj *atomic_addr;\n  Node *atomic_expr;\n\n  // Variable\n  Obj *var;\n\n  // Numeric literal\n  int64_t val;\n  long double fval;\n};\n\nNode *new_cast(Node *expr, Type *ty);\nint64_t const_expr(Token **rest, Token *tok);\nObj *parse(Token *tok);\n\n//\n// type.c\n//\n\ntypedef enum {\n  TY_VOID,\n  TY_BOOL,\n  TY_CHAR,\n  TY_SHORT,\n  TY_INT,\n  TY_LONG,\n  TY_FLOAT,\n  TY_DOUBLE,\n  TY_LDOUBLE,\n  TY_ENUM,\n  TY_PTR,\n  TY_FUNC,\n  TY_ARRAY,\n  TY_VLA, // variable-length array\n  TY_STRUCT,\n  TY_UNION,\n} TypeKind;\n\nstruct Type {\n  TypeKind kind;\n  int size;           // sizeof() value\n  int align;          // alignment\n  bool is_unsigned;   // unsigned or signed\n  bool is_atomic;     // true if _Atomic\n  Type *origin;       // for type compatibility check\n\n  // Pointer-to or array-of type. We intentionally use the same member\n  // to represent pointer/array duality in C.\n  //\n  // In many contexts in which a pointer is expected, we examine this\n  // member instead of \"kind\" member to determine whether a type is a\n  // pointer or not. That means in many contexts \"array of T\" is\n  // naturally handled as if it were \"pointer to T\", as required by\n  // the C spec.\n  Type *base;\n\n  // Declaration\n  Token *name;\n  Token *name_pos;\n\n  // Array\n  int array_len;\n\n  // Variable-length array\n  Node *vla_len; // # of elements\n  Obj *vla_size; // sizeof() value\n\n  // Struct\n  Member *members;\n  bool is_flexible;\n  bool is_packed;\n\n  // Function type\n  Type *return_ty;\n  Type *params;\n  bool is_variadic;\n  Type *next;\n};\n\n// Struct member\nstruct Member {\n  Member *next;\n  Type *ty;\n  Token *tok; // for error message\n  Token *name;\n  int idx;\n  int align;\n  int offset;\n\n  // Bitfield\n  bool is_bitfield;\n  int bit_offset;\n  int bit_width;\n};\n\nextern Type *ty_void;\nextern Type *ty_bool;\n\nextern Type *ty_char;\nextern Type *ty_short;\nextern Type *ty_int;\nextern Type *ty_long;\n\nextern Type *ty_uchar;\nextern Type *ty_ushort;\nextern Type *ty_uint;\nextern Type *ty_ulong;\n\nextern Type *ty_float;\nextern Type *ty_double;\nextern Type *ty_ldouble;\n\nbool is_integer(Type *ty);\nbool is_flonum(Type *ty);\nbool is_numeric(Type *ty);\nbool is_compatible(Type *t1, Type *t2);\nType *copy_type(Type *ty);\nType *pointer_to(Type *base);\nType *func_type(Type *return_ty);\nType *array_of(Type *base, int size);\nType *vla_of(Type *base, Node *expr);\nType *enum_type(void);\nType *struct_type(void);\nvoid add_type(Node *node);\n\n//\n// codegen.c\n//\n\nvoid codegen(Obj *prog, FILE *out);\nint align_to(int n, int align);\n\n//\n// unicode.c\n//\n\nint encode_utf8(char *buf, uint32_t c);\nuint32_t decode_utf8(char **new_pos, char *p);\nbool is_ident1(uint32_t c);\nbool is_ident2(uint32_t c);\nint display_width(char *p, int len);\n\n//\n// hashmap.c\n//\n\ntypedef struct {\n  char *key;\n  int keylen;\n  void *val;\n} HashEntry;\n\ntypedef struct {\n  HashEntry *buckets;\n  int capacity;\n  int used;\n} HashMap;\n\nvoid *hashmap_get(HashMap *map, char *key);\nvoid *hashmap_get2(HashMap *map, char *key, int keylen);\nvoid hashmap_put(HashMap *map, char *key, void *val);\nvoid hashmap_put2(HashMap *map, char *key, int keylen, void *val);\nvoid hashmap_delete(HashMap *map, char *key);\nvoid hashmap_delete2(HashMap *map, char *key, int keylen);\nvoid hashmap_test(void);\n\n//\n// main.c\n//\n\nbool file_exists(char *path);\n\nextern StringArray include_paths;\nextern bool opt_fpic;\nextern bool opt_fcommon;\nextern char *base_file;\n"
  },
  {
    "path": "codegen.c",
    "content": "#include \"chibicc.h\"\n\n#define GP_MAX 6\n#define FP_MAX 8\n\nstatic FILE *output_file;\nstatic int depth;\nstatic char *argreg8[] = {\"%dil\", \"%sil\", \"%dl\", \"%cl\", \"%r8b\", \"%r9b\"};\nstatic char *argreg16[] = {\"%di\", \"%si\", \"%dx\", \"%cx\", \"%r8w\", \"%r9w\"};\nstatic char *argreg32[] = {\"%edi\", \"%esi\", \"%edx\", \"%ecx\", \"%r8d\", \"%r9d\"};\nstatic char *argreg64[] = {\"%rdi\", \"%rsi\", \"%rdx\", \"%rcx\", \"%r8\", \"%r9\"};\nstatic Obj *current_fn;\n\nstatic void gen_expr(Node *node);\nstatic void gen_stmt(Node *node);\n\n__attribute__((format(printf, 1, 2)))\nstatic void println(char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n  vfprintf(output_file, fmt, ap);\n  va_end(ap);\n  fprintf(output_file, \"\\n\");\n}\n\nstatic int count(void) {\n  static int i = 1;\n  return i++;\n}\n\nstatic void push(void) {\n  println(\"  push %%rax\");\n  depth++;\n}\n\nstatic void pop(char *arg) {\n  println(\"  pop %s\", arg);\n  depth--;\n}\n\nstatic void pushf(void) {\n  println(\"  sub $8, %%rsp\");\n  println(\"  movsd %%xmm0, (%%rsp)\");\n  depth++;\n}\n\nstatic void popf(int reg) {\n  println(\"  movsd (%%rsp), %%xmm%d\", reg);\n  println(\"  add $8, %%rsp\");\n  depth--;\n}\n\n// Round up `n` to the nearest multiple of `align`. For instance,\n// align_to(5, 8) returns 8 and align_to(11, 8) returns 16.\nint align_to(int n, int align) {\n  return (n + align - 1) / align * align;\n}\n\nstatic char *reg_dx(int sz) {\n  switch (sz) {\n  case 1: return \"%dl\";\n  case 2: return \"%dx\";\n  case 4: return \"%edx\";\n  case 8: return \"%rdx\";\n  }\n  unreachable();\n}\n\nstatic char *reg_ax(int sz) {\n  switch (sz) {\n  case 1: return \"%al\";\n  case 2: return \"%ax\";\n  case 4: return \"%eax\";\n  case 8: return \"%rax\";\n  }\n  unreachable();\n}\n\n// Compute the absolute address of a given node.\n// It's an error if a given node does not reside in memory.\nstatic void gen_addr(Node *node) {\n  switch (node->kind) {\n  case ND_VAR:\n    // Variable-length array, which is always local.\n    if (node->var->ty->kind == TY_VLA) {\n      println(\"  mov %d(%%rbp), %%rax\", node->var->offset);\n      return;\n    }\n\n    // Local variable\n    if (node->var->is_local) {\n      println(\"  lea %d(%%rbp), %%rax\", node->var->offset);\n      return;\n    }\n\n    if (opt_fpic) {\n      // Thread-local variable\n      if (node->var->is_tls) {\n        println(\"  data16 lea %s@tlsgd(%%rip), %%rdi\", node->var->name);\n        println(\"  .value 0x6666\");\n        println(\"  rex64\");\n        println(\"  call __tls_get_addr@PLT\");\n        return;\n      }\n\n      // Function or global variable\n      println(\"  mov %s@GOTPCREL(%%rip), %%rax\", node->var->name);\n      return;\n    }\n\n    // Thread-local variable\n    if (node->var->is_tls) {\n      println(\"  mov %%fs:0, %%rax\");\n      println(\"  add $%s@tpoff, %%rax\", node->var->name);\n      return;\n    }\n\n    // Here, we generate an absolute address of a function or a global\n    // variable. Even though they exist at a certain address at runtime,\n    // their addresses are not known at link-time for the following\n    // two reasons.\n    //\n    //  - Address randomization: Executables are loaded to memory as a\n    //    whole but it is not known what address they are loaded to.\n    //    Therefore, at link-time, relative address in the same\n    //    exectuable (i.e. the distance between two functions in the\n    //    same executable) is known, but the absolute address is not\n    //    known.\n    //\n    //  - Dynamic linking: Dynamic shared objects (DSOs) or .so files\n    //    are loaded to memory alongside an executable at runtime and\n    //    linked by the runtime loader in memory. We know nothing\n    //    about addresses of global stuff that may be defined by DSOs\n    //    until the runtime relocation is complete.\n    //\n    // In order to deal with the former case, we use RIP-relative\n    // addressing, denoted by `(%rip)`. For the latter, we obtain an\n    // address of a stuff that may be in a shared object file from the\n    // Global Offset Table using `@GOTPCREL(%rip)` notation.\n\n    // Function\n    if (node->ty->kind == TY_FUNC) {\n      if (node->var->is_definition)\n        println(\"  lea %s(%%rip), %%rax\", node->var->name);\n      else\n        println(\"  mov %s@GOTPCREL(%%rip), %%rax\", node->var->name);\n      return;\n    }\n\n    // Global variable\n    println(\"  lea %s(%%rip), %%rax\", node->var->name);\n    return;\n  case ND_DEREF:\n    gen_expr(node->lhs);\n    return;\n  case ND_COMMA:\n    gen_expr(node->lhs);\n    gen_addr(node->rhs);\n    return;\n  case ND_MEMBER:\n    gen_addr(node->lhs);\n    println(\"  add $%d, %%rax\", node->member->offset);\n    return;\n  case ND_FUNCALL:\n    if (node->ret_buffer) {\n      gen_expr(node);\n      return;\n    }\n    break;\n  case ND_ASSIGN:\n  case ND_COND:\n    if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) {\n      gen_expr(node);\n      return;\n    }\n    break;\n  case ND_VLA_PTR:\n    println(\"  lea %d(%%rbp), %%rax\", node->var->offset);\n    return;\n  }\n\n  error_tok(node->tok, \"not an lvalue\");\n}\n\n// Load a value from where %rax is pointing to.\nstatic void load(Type *ty) {\n  switch (ty->kind) {\n  case TY_ARRAY:\n  case TY_STRUCT:\n  case TY_UNION:\n  case TY_FUNC:\n  case TY_VLA:\n    // If it is an array, do not attempt to load a value to the\n    // register because in general we can't load an entire array to a\n    // register. As a result, the result of an evaluation of an array\n    // becomes not the array itself but the address of the array.\n    // This is where \"array is automatically converted to a pointer to\n    // the first element of the array in C\" occurs.\n    return;\n  case TY_FLOAT:\n    println(\"  movss (%%rax), %%xmm0\");\n    return;\n  case TY_DOUBLE:\n    println(\"  movsd (%%rax), %%xmm0\");\n    return;\n  case TY_LDOUBLE:\n    println(\"  fldt (%%rax)\");\n    return;\n  }\n\n  char *insn = ty->is_unsigned ? \"movz\" : \"movs\";\n\n  // When we load a char or a short value to a register, we always\n  // extend them to the size of int, so we can assume the lower half of\n  // a register always contains a valid value. The upper half of a\n  // register for char, short and int may contain garbage. When we load\n  // a long value to a register, it simply occupies the entire register.\n  if (ty->size == 1)\n    println(\"  %sbl (%%rax), %%eax\", insn);\n  else if (ty->size == 2)\n    println(\"  %swl (%%rax), %%eax\", insn);\n  else if (ty->size == 4)\n    println(\"  movsxd (%%rax), %%rax\");\n  else\n    println(\"  mov (%%rax), %%rax\");\n}\n\n// Store %rax to an address that the stack top is pointing to.\nstatic void store(Type *ty) {\n  pop(\"%rdi\");\n\n  switch (ty->kind) {\n  case TY_STRUCT:\n  case TY_UNION:\n    for (int i = 0; i < ty->size; i++) {\n      println(\"  mov %d(%%rax), %%r8b\", i);\n      println(\"  mov %%r8b, %d(%%rdi)\", i);\n    }\n    return;\n  case TY_FLOAT:\n    println(\"  movss %%xmm0, (%%rdi)\");\n    return;\n  case TY_DOUBLE:\n    println(\"  movsd %%xmm0, (%%rdi)\");\n    return;\n  case TY_LDOUBLE:\n    println(\"  fstpt (%%rdi)\");\n    return;\n  }\n\n  if (ty->size == 1)\n    println(\"  mov %%al, (%%rdi)\");\n  else if (ty->size == 2)\n    println(\"  mov %%ax, (%%rdi)\");\n  else if (ty->size == 4)\n    println(\"  mov %%eax, (%%rdi)\");\n  else\n    println(\"  mov %%rax, (%%rdi)\");\n}\n\nstatic void cmp_zero(Type *ty) {\n  switch (ty->kind) {\n  case TY_FLOAT:\n    println(\"  xorps %%xmm1, %%xmm1\");\n    println(\"  ucomiss %%xmm1, %%xmm0\");\n    return;\n  case TY_DOUBLE:\n    println(\"  xorpd %%xmm1, %%xmm1\");\n    println(\"  ucomisd %%xmm1, %%xmm0\");\n    return;\n  case TY_LDOUBLE:\n    println(\"  fldz\");\n    println(\"  fucomip\");\n    println(\"  fstp %%st(0)\");\n    return;\n  }\n\n  if (is_integer(ty) && ty->size <= 4)\n    println(\"  cmp $0, %%eax\");\n  else\n    println(\"  cmp $0, %%rax\");\n}\n\nenum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80 };\n\nstatic int getTypeId(Type *ty) {\n  switch (ty->kind) {\n  case TY_CHAR:\n    return ty->is_unsigned ? U8 : I8;\n  case TY_SHORT:\n    return ty->is_unsigned ? U16 : I16;\n  case TY_INT:\n    return ty->is_unsigned ? U32 : I32;\n  case TY_LONG:\n    return ty->is_unsigned ? U64 : I64;\n  case TY_FLOAT:\n    return F32;\n  case TY_DOUBLE:\n    return F64;\n  case TY_LDOUBLE:\n    return F80;\n  }\n  return U64;\n}\n\n// The table for type casts\nstatic char i32i8[] = \"movsbl %al, %eax\";\nstatic char i32u8[] = \"movzbl %al, %eax\";\nstatic char i32i16[] = \"movswl %ax, %eax\";\nstatic char i32u16[] = \"movzwl %ax, %eax\";\nstatic char i32f32[] = \"cvtsi2ssl %eax, %xmm0\";\nstatic char i32i64[] = \"movsxd %eax, %rax\";\nstatic char i32f64[] = \"cvtsi2sdl %eax, %xmm0\";\nstatic char i32f80[] = \"mov %eax, -4(%rsp); fildl -4(%rsp)\";\n\nstatic char u32f32[] = \"mov %eax, %eax; cvtsi2ssq %rax, %xmm0\";\nstatic char u32i64[] = \"mov %eax, %eax\";\nstatic char u32f64[] = \"mov %eax, %eax; cvtsi2sdq %rax, %xmm0\";\nstatic char u32f80[] = \"mov %eax, %eax; mov %rax, -8(%rsp); fildll -8(%rsp)\";\n\nstatic char i64f32[] = \"cvtsi2ssq %rax, %xmm0\";\nstatic char i64f64[] = \"cvtsi2sdq %rax, %xmm0\";\nstatic char i64f80[] = \"movq %rax, -8(%rsp); fildll -8(%rsp)\";\n\nstatic char u64f32[] = \"cvtsi2ssq %rax, %xmm0\";\nstatic char u64f64[] =\n  \"test %rax,%rax; js 1f; pxor %xmm0,%xmm0; cvtsi2sd %rax,%xmm0; jmp 2f; \"\n  \"1: mov %rax,%rdi; and $1,%eax; pxor %xmm0,%xmm0; shr %rdi; \"\n  \"or %rax,%rdi; cvtsi2sd %rdi,%xmm0; addsd %xmm0,%xmm0; 2:\";\nstatic char u64f80[] =\n  \"mov %rax, -8(%rsp); fildq -8(%rsp); test %rax, %rax; jns 1f;\"\n  \"mov $1602224128, %eax; mov %eax, -4(%rsp); fadds -4(%rsp); 1:\";\n\nstatic char f32i8[] = \"cvttss2sil %xmm0, %eax; movsbl %al, %eax\";\nstatic char f32u8[] = \"cvttss2sil %xmm0, %eax; movzbl %al, %eax\";\nstatic char f32i16[] = \"cvttss2sil %xmm0, %eax; movswl %ax, %eax\";\nstatic char f32u16[] = \"cvttss2sil %xmm0, %eax; movzwl %ax, %eax\";\nstatic char f32i32[] = \"cvttss2sil %xmm0, %eax\";\nstatic char f32u32[] = \"cvttss2siq %xmm0, %rax\";\nstatic char f32i64[] = \"cvttss2siq %xmm0, %rax\";\nstatic char f32u64[] = \"cvttss2siq %xmm0, %rax\";\nstatic char f32f64[] = \"cvtss2sd %xmm0, %xmm0\";\nstatic char f32f80[] = \"movss %xmm0, -4(%rsp); flds -4(%rsp)\";\n\nstatic char f64i8[] = \"cvttsd2sil %xmm0, %eax; movsbl %al, %eax\";\nstatic char f64u8[] = \"cvttsd2sil %xmm0, %eax; movzbl %al, %eax\";\nstatic char f64i16[] = \"cvttsd2sil %xmm0, %eax; movswl %ax, %eax\";\nstatic char f64u16[] = \"cvttsd2sil %xmm0, %eax; movzwl %ax, %eax\";\nstatic char f64i32[] = \"cvttsd2sil %xmm0, %eax\";\nstatic char f64u32[] = \"cvttsd2siq %xmm0, %rax\";\nstatic char f64i64[] = \"cvttsd2siq %xmm0, %rax\";\nstatic char f64u64[] = \"cvttsd2siq %xmm0, %rax\";\nstatic char f64f32[] = \"cvtsd2ss %xmm0, %xmm0\";\nstatic char f64f80[] = \"movsd %xmm0, -8(%rsp); fldl -8(%rsp)\";\n\n#define FROM_F80_1                                           \\\n  \"fnstcw -10(%rsp); movzwl -10(%rsp), %eax; or $12, %ah; \" \\\n  \"mov %ax, -12(%rsp); fldcw -12(%rsp); \"\n\n#define FROM_F80_2 \" -24(%rsp); fldcw -10(%rsp); \"\n\nstatic char f80i8[] = FROM_F80_1 \"fistps\" FROM_F80_2 \"movsbl -24(%rsp), %eax\";\nstatic char f80u8[] = FROM_F80_1 \"fistps\" FROM_F80_2 \"movzbl -24(%rsp), %eax\";\nstatic char f80i16[] = FROM_F80_1 \"fistps\" FROM_F80_2 \"movzbl -24(%rsp), %eax\";\nstatic char f80u16[] = FROM_F80_1 \"fistpl\" FROM_F80_2 \"movswl -24(%rsp), %eax\";\nstatic char f80i32[] = FROM_F80_1 \"fistpl\" FROM_F80_2 \"mov -24(%rsp), %eax\";\nstatic char f80u32[] = FROM_F80_1 \"fistpl\" FROM_F80_2 \"mov -24(%rsp), %eax\";\nstatic char f80i64[] = FROM_F80_1 \"fistpq\" FROM_F80_2 \"mov -24(%rsp), %rax\";\nstatic char f80u64[] = FROM_F80_1 \"fistpq\" FROM_F80_2 \"mov -24(%rsp), %rax\";\nstatic char f80f32[] = \"fstps -8(%rsp); movss -8(%rsp), %xmm0\";\nstatic char f80f64[] = \"fstpl -8(%rsp); movsd -8(%rsp), %xmm0\";\n\nstatic char *cast_table[][11] = {\n  // i8   i16     i32     i64     u8     u16     u32     u64     f32     f64     f80\n  {NULL,  NULL,   NULL,   i32i64, i32u8, i32u16, NULL,   i32i64, i32f32, i32f64, i32f80}, // i8\n  {i32i8, NULL,   NULL,   i32i64, i32u8, i32u16, NULL,   i32i64, i32f32, i32f64, i32f80}, // i16\n  {i32i8, i32i16, NULL,   i32i64, i32u8, i32u16, NULL,   i32i64, i32f32, i32f64, i32f80}, // i32\n  {i32i8, i32i16, NULL,   NULL,   i32u8, i32u16, NULL,   NULL,   i64f32, i64f64, i64f80}, // i64\n\n  {i32i8, NULL,   NULL,   i32i64, NULL,  NULL,   NULL,   i32i64, i32f32, i32f64, i32f80}, // u8\n  {i32i8, i32i16, NULL,   i32i64, i32u8, NULL,   NULL,   i32i64, i32f32, i32f64, i32f80}, // u16\n  {i32i8, i32i16, NULL,   u32i64, i32u8, i32u16, NULL,   u32i64, u32f32, u32f64, u32f80}, // u32\n  {i32i8, i32i16, NULL,   NULL,   i32u8, i32u16, NULL,   NULL,   u64f32, u64f64, u64f80}, // u64\n\n  {f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL,   f32f64, f32f80}, // f32\n  {f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL,   f64f80}, // f64\n  {f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL},   // f80\n};\n\nstatic void cast(Type *from, Type *to) {\n  if (to->kind == TY_VOID)\n    return;\n\n  if (to->kind == TY_BOOL) {\n    cmp_zero(from);\n    println(\"  setne %%al\");\n    println(\"  movzx %%al, %%eax\");\n    return;\n  }\n\n  int t1 = getTypeId(from);\n  int t2 = getTypeId(to);\n  if (cast_table[t1][t2])\n    println(\"  %s\", cast_table[t1][t2]);\n}\n\n// Structs or unions equal or smaller than 16 bytes are passed\n// using up to two registers.\n//\n// If the first 8 bytes contains only floating-point type members,\n// they are passed in an XMM register. Otherwise, they are passed\n// in a general-purpose register.\n//\n// If a struct/union is larger than 8 bytes, the same rule is\n// applied to the the next 8 byte chunk.\n//\n// This function returns true if `ty` has only floating-point\n// members in its byte range [lo, hi).\nstatic bool has_flonum(Type *ty, int lo, int hi, int offset) {\n  if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) {\n    for (Member *mem = ty->members; mem; mem = mem->next)\n      if (!has_flonum(mem->ty, lo, hi, offset + mem->offset))\n        return false;\n    return true;\n  }\n\n  if (ty->kind == TY_ARRAY) {\n    for (int i = 0; i < ty->array_len; i++)\n      if (!has_flonum(ty->base, lo, hi, offset + ty->base->size * i))\n        return false;\n    return true;\n  }\n\n  return offset < lo || hi <= offset || ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE;\n}\n\nstatic bool has_flonum1(Type *ty) {\n  return has_flonum(ty, 0, 8, 0);\n}\n\nstatic bool has_flonum2(Type *ty) {\n  return has_flonum(ty, 8, 16, 0);\n}\n\nstatic void push_struct(Type *ty) {\n  int sz = align_to(ty->size, 8);\n  println(\"  sub $%d, %%rsp\", sz);\n  depth += sz / 8;\n\n  for (int i = 0; i < ty->size; i++) {\n    println(\"  mov %d(%%rax), %%r10b\", i);\n    println(\"  mov %%r10b, %d(%%rsp)\", i);\n  }\n}\n\nstatic void push_args2(Node *args, bool first_pass) {\n  if (!args)\n    return;\n  push_args2(args->next, first_pass);\n\n  if ((first_pass && !args->pass_by_stack) || (!first_pass && args->pass_by_stack))\n    return;\n\n  gen_expr(args);\n\n  switch (args->ty->kind) {\n  case TY_STRUCT:\n  case TY_UNION:\n    push_struct(args->ty);\n    break;\n  case TY_FLOAT:\n  case TY_DOUBLE:\n    pushf();\n    break;\n  case TY_LDOUBLE:\n    println(\"  sub $16, %%rsp\");\n    println(\"  fstpt (%%rsp)\");\n    depth += 2;\n    break;\n  default:\n    push();\n  }\n}\n\n// Load function call arguments. Arguments are already evaluated and\n// stored to the stack as local variables. What we need to do in this\n// function is to load them to registers or push them to the stack as\n// specified by the x86-64 psABI. Here is what the spec says:\n//\n// - Up to 6 arguments of integral type are passed using RDI, RSI,\n//   RDX, RCX, R8 and R9.\n//\n// - Up to 8 arguments of floating-point type are passed using XMM0 to\n//   XMM7.\n//\n// - If all registers of an appropriate type are already used, push an\n//   argument to the stack in the right-to-left order.\n//\n// - Each argument passed on the stack takes 8 bytes, and the end of\n//   the argument area must be aligned to a 16 byte boundary.\n//\n// - If a function is variadic, set the number of floating-point type\n//   arguments to RAX.\nstatic int push_args(Node *node) {\n  int stack = 0, gp = 0, fp = 0;\n\n  // If the return type is a large struct/union, the caller passes\n  // a pointer to a buffer as if it were the first argument.\n  if (node->ret_buffer && node->ty->size > 16)\n    gp++;\n\n  // Load as many arguments to the registers as possible.\n  for (Node *arg = node->args; arg; arg = arg->next) {\n    Type *ty = arg->ty;\n\n    switch (ty->kind) {\n    case TY_STRUCT:\n    case TY_UNION:\n      if (ty->size > 16) {\n        arg->pass_by_stack = true;\n        stack += align_to(ty->size, 8) / 8;\n      } else {\n        bool fp1 = has_flonum1(ty);\n        bool fp2 = has_flonum2(ty);\n\n        if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {\n          fp = fp + fp1 + fp2;\n          gp = gp + !fp1 + !fp2;\n        } else {\n          arg->pass_by_stack = true;\n          stack += align_to(ty->size, 8) / 8;\n        }\n      }\n      break;\n    case TY_FLOAT:\n    case TY_DOUBLE:\n      if (fp++ >= FP_MAX) {\n        arg->pass_by_stack = true;\n        stack++;\n      }\n      break;\n    case TY_LDOUBLE:\n      arg->pass_by_stack = true;\n      stack += 2;\n      break;\n    default:\n      if (gp++ >= GP_MAX) {\n        arg->pass_by_stack = true;\n        stack++;\n      }\n    }\n  }\n\n  if ((depth + stack) % 2 == 1) {\n    println(\"  sub $8, %%rsp\");\n    depth++;\n    stack++;\n  }\n\n  push_args2(node->args, true);\n  push_args2(node->args, false);\n\n  // If the return type is a large struct/union, the caller passes\n  // a pointer to a buffer as if it were the first argument.\n  if (node->ret_buffer && node->ty->size > 16) {\n    println(\"  lea %d(%%rbp), %%rax\", node->ret_buffer->offset);\n    push();\n  }\n\n  return stack;\n}\n\nstatic void copy_ret_buffer(Obj *var) {\n  Type *ty = var->ty;\n  int gp = 0, fp = 0;\n\n  if (has_flonum1(ty)) {\n    assert(ty->size == 4 || 8 <= ty->size);\n    if (ty->size == 4)\n      println(\"  movss %%xmm0, %d(%%rbp)\", var->offset);\n    else\n      println(\"  movsd %%xmm0, %d(%%rbp)\", var->offset);\n    fp++;\n  } else {\n    for (int i = 0; i < MIN(8, ty->size); i++) {\n      println(\"  mov %%al, %d(%%rbp)\", var->offset + i);\n      println(\"  shr $8, %%rax\");\n    }\n    gp++;\n  }\n\n  if (ty->size > 8) {\n    if (has_flonum2(ty)) {\n      assert(ty->size == 12 || ty->size == 16);\n      if (ty->size == 12)\n        println(\"  movss %%xmm%d, %d(%%rbp)\", fp, var->offset + 8);\n      else\n        println(\"  movsd %%xmm%d, %d(%%rbp)\", fp, var->offset + 8);\n    } else {\n      char *reg1 = (gp == 0) ? \"%al\" : \"%dl\";\n      char *reg2 = (gp == 0) ? \"%rax\" : \"%rdx\";\n      for (int i = 8; i < MIN(16, ty->size); i++) {\n        println(\"  mov %s, %d(%%rbp)\", reg1, var->offset + i);\n        println(\"  shr $8, %s\", reg2);\n      }\n    }\n  }\n}\n\nstatic void copy_struct_reg(void) {\n  Type *ty = current_fn->ty->return_ty;\n  int gp = 0, fp = 0;\n\n  println(\"  mov %%rax, %%rdi\");\n\n  if (has_flonum(ty, 0, 8, 0)) {\n    assert(ty->size == 4 || 8 <= ty->size);\n    if (ty->size == 4)\n      println(\"  movss (%%rdi), %%xmm0\");\n    else\n      println(\"  movsd (%%rdi), %%xmm0\");\n    fp++;\n  } else {\n    println(\"  mov $0, %%rax\");\n    for (int i = MIN(8, ty->size) - 1; i >= 0; i--) {\n      println(\"  shl $8, %%rax\");\n      println(\"  mov %d(%%rdi), %%al\", i);\n    }\n    gp++;\n  }\n\n  if (ty->size > 8) {\n    if (has_flonum(ty, 8, 16, 0)) {\n      assert(ty->size == 12 || ty->size == 16);\n      if (ty->size == 4)\n        println(\"  movss 8(%%rdi), %%xmm%d\", fp);\n      else\n        println(\"  movsd 8(%%rdi), %%xmm%d\", fp);\n    } else {\n      char *reg1 = (gp == 0) ? \"%al\" : \"%dl\";\n      char *reg2 = (gp == 0) ? \"%rax\" : \"%rdx\";\n      println(\"  mov $0, %s\", reg2);\n      for (int i = MIN(16, ty->size) - 1; i >= 8; i--) {\n        println(\"  shl $8, %s\", reg2);\n        println(\"  mov %d(%%rdi), %s\", i, reg1);\n      }\n    }\n  }\n}\n\nstatic void copy_struct_mem(void) {\n  Type *ty = current_fn->ty->return_ty;\n  Obj *var = current_fn->params;\n\n  println(\"  mov %d(%%rbp), %%rdi\", var->offset);\n\n  for (int i = 0; i < ty->size; i++) {\n    println(\"  mov %d(%%rax), %%dl\", i);\n    println(\"  mov %%dl, %d(%%rdi)\", i);\n  }\n}\n\nstatic void builtin_alloca(void) {\n  // Align size to 16 bytes.\n  println(\"  add $15, %%rdi\");\n  println(\"  and $0xfffffff0, %%edi\");\n\n  // Shift the temporary area by %rdi.\n  println(\"  mov %d(%%rbp), %%rcx\", current_fn->alloca_bottom->offset);\n  println(\"  sub %%rsp, %%rcx\");\n  println(\"  mov %%rsp, %%rax\");\n  println(\"  sub %%rdi, %%rsp\");\n  println(\"  mov %%rsp, %%rdx\");\n  println(\"1:\");\n  println(\"  cmp $0, %%rcx\");\n  println(\"  je 2f\");\n  println(\"  mov (%%rax), %%r8b\");\n  println(\"  mov %%r8b, (%%rdx)\");\n  println(\"  inc %%rdx\");\n  println(\"  inc %%rax\");\n  println(\"  dec %%rcx\");\n  println(\"  jmp 1b\");\n  println(\"2:\");\n\n  // Move alloca_bottom pointer.\n  println(\"  mov %d(%%rbp), %%rax\", current_fn->alloca_bottom->offset);\n  println(\"  sub %%rdi, %%rax\");\n  println(\"  mov %%rax, %d(%%rbp)\", current_fn->alloca_bottom->offset);\n}\n\n// Generate code for a given node.\nstatic void gen_expr(Node *node) {\n  println(\"  .loc %d %d\", node->tok->file->file_no, node->tok->line_no);\n\n  switch (node->kind) {\n  case ND_NULL_EXPR:\n    return;\n  case ND_NUM: {\n    switch (node->ty->kind) {\n    case TY_FLOAT: {\n      union { float f32; uint32_t u32; } u = { node->fval };\n      println(\"  mov $%u, %%eax  # float %Lf\", u.u32, node->fval);\n      println(\"  movq %%rax, %%xmm0\");\n      return;\n    }\n    case TY_DOUBLE: {\n      union { double f64; uint64_t u64; } u = { node->fval };\n      println(\"  mov $%lu, %%rax  # double %Lf\", u.u64, node->fval);\n      println(\"  movq %%rax, %%xmm0\");\n      return;\n    }\n    case TY_LDOUBLE: {\n      union { long double f80; uint64_t u64[2]; } u;\n      memset(&u, 0, sizeof(u));\n      u.f80 = node->fval;\n      println(\"  mov $%lu, %%rax  # long double %Lf\", u.u64[0], node->fval);\n      println(\"  mov %%rax, -16(%%rsp)\");\n      println(\"  mov $%lu, %%rax\", u.u64[1]);\n      println(\"  mov %%rax, -8(%%rsp)\");\n      println(\"  fldt -16(%%rsp)\");\n      return;\n    }\n    }\n\n    println(\"  mov $%ld, %%rax\", node->val);\n    return;\n  }\n  case ND_NEG:\n    gen_expr(node->lhs);\n\n    switch (node->ty->kind) {\n    case TY_FLOAT:\n      println(\"  mov $1, %%rax\");\n      println(\"  shl $31, %%rax\");\n      println(\"  movq %%rax, %%xmm1\");\n      println(\"  xorps %%xmm1, %%xmm0\");\n      return;\n    case TY_DOUBLE:\n      println(\"  mov $1, %%rax\");\n      println(\"  shl $63, %%rax\");\n      println(\"  movq %%rax, %%xmm1\");\n      println(\"  xorpd %%xmm1, %%xmm0\");\n      return;\n    case TY_LDOUBLE:\n      println(\"  fchs\");\n      return;\n    }\n\n    println(\"  neg %%rax\");\n    return;\n  case ND_VAR:\n    gen_addr(node);\n    load(node->ty);\n    return;\n  case ND_MEMBER: {\n    gen_addr(node);\n    load(node->ty);\n\n    Member *mem = node->member;\n    if (mem->is_bitfield) {\n      println(\"  shl $%d, %%rax\", 64 - mem->bit_width - mem->bit_offset);\n      if (mem->ty->is_unsigned)\n        println(\"  shr $%d, %%rax\", 64 - mem->bit_width);\n      else\n        println(\"  sar $%d, %%rax\", 64 - mem->bit_width);\n    }\n    return;\n  }\n  case ND_DEREF:\n    gen_expr(node->lhs);\n    load(node->ty);\n    return;\n  case ND_ADDR:\n    gen_addr(node->lhs);\n    return;\n  case ND_ASSIGN:\n    gen_addr(node->lhs);\n    push();\n    gen_expr(node->rhs);\n\n    if (node->lhs->kind == ND_MEMBER && node->lhs->member->is_bitfield) {\n      println(\"  mov %%rax, %%r8\");\n\n      // If the lhs is a bitfield, we need to read the current value\n      // from memory and merge it with a new value.\n      Member *mem = node->lhs->member;\n      println(\"  mov %%rax, %%rdi\");\n      println(\"  and $%ld, %%rdi\", (1L << mem->bit_width) - 1);\n      println(\"  shl $%d, %%rdi\", mem->bit_offset);\n\n      println(\"  mov (%%rsp), %%rax\");\n      load(mem->ty);\n\n      long mask = ((1L << mem->bit_width) - 1) << mem->bit_offset;\n      println(\"  mov $%ld, %%r9\", ~mask);\n      println(\"  and %%r9, %%rax\");\n      println(\"  or %%rdi, %%rax\");\n      store(node->ty);\n      println(\"  mov %%r8, %%rax\");\n      return;\n    }\n\n    store(node->ty);\n    return;\n  case ND_STMT_EXPR:\n    for (Node *n = node->body; n; n = n->next)\n      gen_stmt(n);\n    return;\n  case ND_COMMA:\n    gen_expr(node->lhs);\n    gen_expr(node->rhs);\n    return;\n  case ND_CAST:\n    gen_expr(node->lhs);\n    cast(node->lhs->ty, node->ty);\n    return;\n  case ND_MEMZERO:\n    // `rep stosb` is equivalent to `memset(%rdi, %al, %rcx)`.\n    println(\"  mov $%d, %%rcx\", node->var->ty->size);\n    println(\"  lea %d(%%rbp), %%rdi\", node->var->offset);\n    println(\"  mov $0, %%al\");\n    println(\"  rep stosb\");\n    return;\n  case ND_COND: {\n    int c = count();\n    gen_expr(node->cond);\n    cmp_zero(node->cond->ty);\n    println(\"  je .L.else.%d\", c);\n    gen_expr(node->then);\n    println(\"  jmp .L.end.%d\", c);\n    println(\".L.else.%d:\", c);\n    gen_expr(node->els);\n    println(\".L.end.%d:\", c);\n    return;\n  }\n  case ND_NOT:\n    gen_expr(node->lhs);\n    cmp_zero(node->lhs->ty);\n    println(\"  sete %%al\");\n    println(\"  movzx %%al, %%rax\");\n    return;\n  case ND_BITNOT:\n    gen_expr(node->lhs);\n    println(\"  not %%rax\");\n    return;\n  case ND_LOGAND: {\n    int c = count();\n    gen_expr(node->lhs);\n    cmp_zero(node->lhs->ty);\n    println(\"  je .L.false.%d\", c);\n    gen_expr(node->rhs);\n    cmp_zero(node->rhs->ty);\n    println(\"  je .L.false.%d\", c);\n    println(\"  mov $1, %%rax\");\n    println(\"  jmp .L.end.%d\", c);\n    println(\".L.false.%d:\", c);\n    println(\"  mov $0, %%rax\");\n    println(\".L.end.%d:\", c);\n    return;\n  }\n  case ND_LOGOR: {\n    int c = count();\n    gen_expr(node->lhs);\n    cmp_zero(node->lhs->ty);\n    println(\"  jne .L.true.%d\", c);\n    gen_expr(node->rhs);\n    cmp_zero(node->rhs->ty);\n    println(\"  jne .L.true.%d\", c);\n    println(\"  mov $0, %%rax\");\n    println(\"  jmp .L.end.%d\", c);\n    println(\".L.true.%d:\", c);\n    println(\"  mov $1, %%rax\");\n    println(\".L.end.%d:\", c);\n    return;\n  }\n  case ND_FUNCALL: {\n    if (node->lhs->kind == ND_VAR && !strcmp(node->lhs->var->name, \"alloca\")) {\n      gen_expr(node->args);\n      println(\"  mov %%rax, %%rdi\");\n      builtin_alloca();\n      return;\n    }\n\n    int stack_args = push_args(node);\n    gen_expr(node->lhs);\n\n    int gp = 0, fp = 0;\n\n    // If the return type is a large struct/union, the caller passes\n    // a pointer to a buffer as if it were the first argument.\n    if (node->ret_buffer && node->ty->size > 16)\n      pop(argreg64[gp++]);\n\n    for (Node *arg = node->args; arg; arg = arg->next) {\n      Type *ty = arg->ty;\n\n      switch (ty->kind) {\n      case TY_STRUCT:\n      case TY_UNION:\n        if (ty->size > 16)\n          continue;\n\n        bool fp1 = has_flonum1(ty);\n        bool fp2 = has_flonum2(ty);\n\n        if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {\n          if (fp1)\n            popf(fp++);\n          else\n            pop(argreg64[gp++]);\n\n          if (ty->size > 8) {\n            if (fp2)\n              popf(fp++);\n            else\n              pop(argreg64[gp++]);\n          }\n        }\n        break;\n      case TY_FLOAT:\n      case TY_DOUBLE:\n        if (fp < FP_MAX)\n          popf(fp++);\n        break;\n      case TY_LDOUBLE:\n        break;\n      default:\n        if (gp < GP_MAX)\n          pop(argreg64[gp++]);\n      }\n    }\n\n    println(\"  mov %%rax, %%r10\");\n    println(\"  mov $%d, %%rax\", fp);\n    println(\"  call *%%r10\");\n    println(\"  add $%d, %%rsp\", stack_args * 8);\n\n    depth -= stack_args;\n\n    // It looks like the most significant 48 or 56 bits in RAX may\n    // contain garbage if a function return type is short or bool/char,\n    // respectively. We clear the upper bits here.\n    switch (node->ty->kind) {\n    case TY_BOOL:\n      println(\"  movzx %%al, %%eax\");\n      return;\n    case TY_CHAR:\n      if (node->ty->is_unsigned)\n        println(\"  movzbl %%al, %%eax\");\n      else\n        println(\"  movsbl %%al, %%eax\");\n      return;\n    case TY_SHORT:\n      if (node->ty->is_unsigned)\n        println(\"  movzwl %%ax, %%eax\");\n      else\n        println(\"  movswl %%ax, %%eax\");\n      return;\n    }\n\n    // If the return type is a small struct, a value is returned\n    // using up to two registers.\n    if (node->ret_buffer && node->ty->size <= 16) {\n      copy_ret_buffer(node->ret_buffer);\n      println(\"  lea %d(%%rbp), %%rax\", node->ret_buffer->offset);\n    }\n\n    return;\n  }\n  case ND_LABEL_VAL:\n    println(\"  lea %s(%%rip), %%rax\", node->unique_label);\n    return;\n  case ND_CAS: {\n    gen_expr(node->cas_addr);\n    push();\n    gen_expr(node->cas_new);\n    push();\n    gen_expr(node->cas_old);\n    println(\"  mov %%rax, %%r8\");\n    load(node->cas_old->ty->base);\n    pop(\"%rdx\"); // new\n    pop(\"%rdi\"); // addr\n\n    int sz = node->cas_addr->ty->base->size;\n    println(\"  lock cmpxchg %s, (%%rdi)\", reg_dx(sz));\n    println(\"  sete %%cl\");\n    println(\"  je 1f\");\n    println(\"  mov %s, (%%r8)\", reg_ax(sz));\n    println(\"1:\");\n    println(\"  movzbl %%cl, %%eax\");\n    return;\n  }\n  case ND_EXCH: {\n    gen_expr(node->lhs);\n    push();\n    gen_expr(node->rhs);\n    pop(\"%rdi\");\n\n    int sz = node->lhs->ty->base->size;\n    println(\"  xchg %s, (%%rdi)\", reg_ax(sz));\n    return;\n  }\n  }\n\n  switch (node->lhs->ty->kind) {\n  case TY_FLOAT:\n  case TY_DOUBLE: {\n    gen_expr(node->rhs);\n    pushf();\n    gen_expr(node->lhs);\n    popf(1);\n\n    char *sz = (node->lhs->ty->kind == TY_FLOAT) ? \"ss\" : \"sd\";\n\n    switch (node->kind) {\n    case ND_ADD:\n      println(\"  add%s %%xmm1, %%xmm0\", sz);\n      return;\n    case ND_SUB:\n      println(\"  sub%s %%xmm1, %%xmm0\", sz);\n      return;\n    case ND_MUL:\n      println(\"  mul%s %%xmm1, %%xmm0\", sz);\n      return;\n    case ND_DIV:\n      println(\"  div%s %%xmm1, %%xmm0\", sz);\n      return;\n    case ND_EQ:\n    case ND_NE:\n    case ND_LT:\n    case ND_LE:\n      println(\"  ucomi%s %%xmm0, %%xmm1\", sz);\n\n      if (node->kind == ND_EQ) {\n        println(\"  sete %%al\");\n        println(\"  setnp %%dl\");\n        println(\"  and %%dl, %%al\");\n      } else if (node->kind == ND_NE) {\n        println(\"  setne %%al\");\n        println(\"  setp %%dl\");\n        println(\"  or %%dl, %%al\");\n      } else if (node->kind == ND_LT) {\n        println(\"  seta %%al\");\n      } else {\n        println(\"  setae %%al\");\n      }\n\n      println(\"  and $1, %%al\");\n      println(\"  movzb %%al, %%rax\");\n      return;\n    }\n\n    error_tok(node->tok, \"invalid expression\");\n  }\n  case TY_LDOUBLE: {\n    gen_expr(node->lhs);\n    gen_expr(node->rhs);\n\n    switch (node->kind) {\n    case ND_ADD:\n      println(\"  faddp\");\n      return;\n    case ND_SUB:\n      println(\"  fsubrp\");\n      return;\n    case ND_MUL:\n      println(\"  fmulp\");\n      return;\n    case ND_DIV:\n      println(\"  fdivrp\");\n      return;\n    case ND_EQ:\n    case ND_NE:\n    case ND_LT:\n    case ND_LE:\n      println(\"  fcomip\");\n      println(\"  fstp %%st(0)\");\n\n      if (node->kind == ND_EQ)\n        println(\"  sete %%al\");\n      else if (node->kind == ND_NE)\n        println(\"  setne %%al\");\n      else if (node->kind == ND_LT)\n        println(\"  seta %%al\");\n      else\n        println(\"  setae %%al\");\n\n      println(\"  movzb %%al, %%rax\");\n      return;\n    }\n\n    error_tok(node->tok, \"invalid expression\");\n  }\n  }\n\n  gen_expr(node->rhs);\n  push();\n  gen_expr(node->lhs);\n  pop(\"%rdi\");\n\n  char *ax, *di, *dx;\n\n  if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) {\n    ax = \"%rax\";\n    di = \"%rdi\";\n    dx = \"%rdx\";\n  } else {\n    ax = \"%eax\";\n    di = \"%edi\";\n    dx = \"%edx\";\n  }\n\n  switch (node->kind) {\n  case ND_ADD:\n    println(\"  add %s, %s\", di, ax);\n    return;\n  case ND_SUB:\n    println(\"  sub %s, %s\", di, ax);\n    return;\n  case ND_MUL:\n    println(\"  imul %s, %s\", di, ax);\n    return;\n  case ND_DIV:\n  case ND_MOD:\n    if (node->ty->is_unsigned) {\n      println(\"  mov $0, %s\", dx);\n      println(\"  div %s\", di);\n    } else {\n      if (node->lhs->ty->size == 8)\n        println(\"  cqo\");\n      else\n        println(\"  cdq\");\n      println(\"  idiv %s\", di);\n    }\n\n    if (node->kind == ND_MOD)\n      println(\"  mov %%rdx, %%rax\");\n    return;\n  case ND_BITAND:\n    println(\"  and %s, %s\", di, ax);\n    return;\n  case ND_BITOR:\n    println(\"  or %s, %s\", di, ax);\n    return;\n  case ND_BITXOR:\n    println(\"  xor %s, %s\", di, ax);\n    return;\n  case ND_EQ:\n  case ND_NE:\n  case ND_LT:\n  case ND_LE:\n    println(\"  cmp %s, %s\", di, ax);\n\n    if (node->kind == ND_EQ) {\n      println(\"  sete %%al\");\n    } else if (node->kind == ND_NE) {\n      println(\"  setne %%al\");\n    } else if (node->kind == ND_LT) {\n      if (node->lhs->ty->is_unsigned)\n        println(\"  setb %%al\");\n      else\n        println(\"  setl %%al\");\n    } else if (node->kind == ND_LE) {\n      if (node->lhs->ty->is_unsigned)\n        println(\"  setbe %%al\");\n      else\n        println(\"  setle %%al\");\n    }\n\n    println(\"  movzb %%al, %%rax\");\n    return;\n  case ND_SHL:\n    println(\"  mov %%rdi, %%rcx\");\n    println(\"  shl %%cl, %s\", ax);\n    return;\n  case ND_SHR:\n    println(\"  mov %%rdi, %%rcx\");\n    if (node->lhs->ty->is_unsigned)\n      println(\"  shr %%cl, %s\", ax);\n    else\n      println(\"  sar %%cl, %s\", ax);\n    return;\n  }\n\n  error_tok(node->tok, \"invalid expression\");\n}\n\nstatic void gen_stmt(Node *node) {\n  println(\"  .loc %d %d\", node->tok->file->file_no, node->tok->line_no);\n\n  switch (node->kind) {\n  case ND_IF: {\n    int c = count();\n    gen_expr(node->cond);\n    cmp_zero(node->cond->ty);\n    println(\"  je  .L.else.%d\", c);\n    gen_stmt(node->then);\n    println(\"  jmp .L.end.%d\", c);\n    println(\".L.else.%d:\", c);\n    if (node->els)\n      gen_stmt(node->els);\n    println(\".L.end.%d:\", c);\n    return;\n  }\n  case ND_FOR: {\n    int c = count();\n    if (node->init)\n      gen_stmt(node->init);\n    println(\".L.begin.%d:\", c);\n    if (node->cond) {\n      gen_expr(node->cond);\n      cmp_zero(node->cond->ty);\n      println(\"  je %s\", node->brk_label);\n    }\n    gen_stmt(node->then);\n    println(\"%s:\", node->cont_label);\n    if (node->inc)\n      gen_expr(node->inc);\n    println(\"  jmp .L.begin.%d\", c);\n    println(\"%s:\", node->brk_label);\n    return;\n  }\n  case ND_DO: {\n    int c = count();\n    println(\".L.begin.%d:\", c);\n    gen_stmt(node->then);\n    println(\"%s:\", node->cont_label);\n    gen_expr(node->cond);\n    cmp_zero(node->cond->ty);\n    println(\"  jne .L.begin.%d\", c);\n    println(\"%s:\", node->brk_label);\n    return;\n  }\n  case ND_SWITCH:\n    gen_expr(node->cond);\n\n    for (Node *n = node->case_next; n; n = n->case_next) {\n      char *ax = (node->cond->ty->size == 8) ? \"%rax\" : \"%eax\";\n      char *di = (node->cond->ty->size == 8) ? \"%rdi\" : \"%edi\";\n\n      if (n->begin == n->end) {\n        println(\"  cmp $%ld, %s\", n->begin, ax);\n        println(\"  je %s\", n->label);\n        continue;\n      }\n\n      // [GNU] Case ranges\n      println(\"  mov %s, %s\", ax, di);\n      println(\"  sub $%ld, %s\", n->begin, di);\n      println(\"  cmp $%ld, %s\", n->end - n->begin, di);\n      println(\"  jbe %s\", n->label);\n    }\n\n    if (node->default_case)\n      println(\"  jmp %s\", node->default_case->label);\n\n    println(\"  jmp %s\", node->brk_label);\n    gen_stmt(node->then);\n    println(\"%s:\", node->brk_label);\n    return;\n  case ND_CASE:\n    println(\"%s:\", node->label);\n    gen_stmt(node->lhs);\n    return;\n  case ND_BLOCK:\n    for (Node *n = node->body; n; n = n->next)\n      gen_stmt(n);\n    return;\n  case ND_GOTO:\n    println(\"  jmp %s\", node->unique_label);\n    return;\n  case ND_GOTO_EXPR:\n    gen_expr(node->lhs);\n    println(\"  jmp *%%rax\");\n    return;\n  case ND_LABEL:\n    println(\"%s:\", node->unique_label);\n    gen_stmt(node->lhs);\n    return;\n  case ND_RETURN:\n    if (node->lhs) {\n      gen_expr(node->lhs);\n      Type *ty = node->lhs->ty;\n\n      switch (ty->kind) {\n      case TY_STRUCT:\n      case TY_UNION:\n        if (ty->size <= 16)\n          copy_struct_reg();\n        else\n          copy_struct_mem();\n        break;\n      }\n    }\n\n    println(\"  jmp .L.return.%s\", current_fn->name);\n    return;\n  case ND_EXPR_STMT:\n    gen_expr(node->lhs);\n    return;\n  case ND_ASM:\n    println(\"  %s\", node->asm_str);\n    return;\n  }\n\n  error_tok(node->tok, \"invalid statement\");\n}\n\n// Assign offsets to local variables.\nstatic void assign_lvar_offsets(Obj *prog) {\n  for (Obj *fn = prog; fn; fn = fn->next) {\n    if (!fn->is_function)\n      continue;\n\n    // If a function has many parameters, some parameters are\n    // inevitably passed by stack rather than by register.\n    // The first passed-by-stack parameter resides at RBP+16.\n    int top = 16;\n    int bottom = 0;\n\n    int gp = 0, fp = 0;\n\n    // Assign offsets to pass-by-stack parameters.\n    for (Obj *var = fn->params; var; var = var->next) {\n      Type *ty = var->ty;\n\n      switch (ty->kind) {\n      case TY_STRUCT:\n      case TY_UNION:\n        if (ty->size <= 16) {\n          bool fp1 = has_flonum(ty, 0, 8, 0);\n          bool fp2 = has_flonum(ty, 8, 16, 8);\n          if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {\n            fp = fp + fp1 + fp2;\n            gp = gp + !fp1 + !fp2;\n            continue;\n          }\n        }\n        break;\n      case TY_FLOAT:\n      case TY_DOUBLE:\n        if (fp++ < FP_MAX)\n          continue;\n        break;\n      case TY_LDOUBLE:\n        break;\n      default:\n        if (gp++ < GP_MAX)\n          continue;\n      }\n\n      top = align_to(top, 8);\n      var->offset = top;\n      top += var->ty->size;\n    }\n\n    // Assign offsets to pass-by-register parameters and local variables.\n    for (Obj *var = fn->locals; var; var = var->next) {\n      if (var->offset)\n        continue;\n\n      // AMD64 System V ABI has a special alignment rule for an array of\n      // length at least 16 bytes. We need to align such array to at least\n      // 16-byte boundaries. See p.14 of\n      // https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-draft.pdf.\n      int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16)\n        ? MAX(16, var->align) : var->align;\n\n      bottom += var->ty->size;\n      bottom = align_to(bottom, align);\n      var->offset = -bottom;\n    }\n\n    fn->stack_size = align_to(bottom, 16);\n  }\n}\n\nstatic void emit_data(Obj *prog) {\n  for (Obj *var = prog; var; var = var->next) {\n    if (var->is_function || !var->is_definition)\n      continue;\n\n    if (var->is_static)\n      println(\"  .local %s\", var->name);\n    else\n      println(\"  .globl %s\", var->name);\n\n    int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16)\n      ? MAX(16, var->align) : var->align;\n\n    // Common symbol\n    if (opt_fcommon && var->is_tentative) {\n      println(\"  .comm %s, %d, %d\", var->name, var->ty->size, align);\n      continue;\n    }\n\n    // .data or .tdata\n    if (var->init_data) {\n      if (var->is_tls)\n        println(\"  .section .tdata,\\\"awT\\\",@progbits\");\n      else\n        println(\"  .data\");\n\n      println(\"  .type %s, @object\", var->name);\n      println(\"  .size %s, %d\", var->name, var->ty->size);\n      println(\"  .align %d\", align);\n      println(\"%s:\", var->name);\n\n      Relocation *rel = var->rel;\n      int pos = 0;\n      while (pos < var->ty->size) {\n        if (rel && rel->offset == pos) {\n          println(\"  .quad %s%+ld\", *rel->label, rel->addend);\n          rel = rel->next;\n          pos += 8;\n        } else {\n          println(\"  .byte %d\", var->init_data[pos++]);\n        }\n      }\n      continue;\n    }\n\n    // .bss or .tbss\n    if (var->is_tls)\n      println(\"  .section .tbss,\\\"awT\\\",@nobits\");\n    else\n      println(\"  .bss\");\n\n    println(\"  .align %d\", align);\n    println(\"%s:\", var->name);\n    println(\"  .zero %d\", var->ty->size);\n  }\n}\n\nstatic void store_fp(int r, int offset, int sz) {\n  switch (sz) {\n  case 4:\n    println(\"  movss %%xmm%d, %d(%%rbp)\", r, offset);\n    return;\n  case 8:\n    println(\"  movsd %%xmm%d, %d(%%rbp)\", r, offset);\n    return;\n  }\n  unreachable();\n}\n\nstatic void store_gp(int r, int offset, int sz) {\n  switch (sz) {\n  case 1:\n    println(\"  mov %s, %d(%%rbp)\", argreg8[r], offset);\n    return;\n  case 2:\n    println(\"  mov %s, %d(%%rbp)\", argreg16[r], offset);\n    return;\n  case 4:\n    println(\"  mov %s, %d(%%rbp)\", argreg32[r], offset);\n    return;\n  case 8:\n    println(\"  mov %s, %d(%%rbp)\", argreg64[r], offset);\n    return;\n  default:\n    for (int i = 0; i < sz; i++) {\n      println(\"  mov %s, %d(%%rbp)\", argreg8[r], offset + i);\n      println(\"  shr $8, %s\", argreg64[r]);\n    }\n    return;\n  }\n}\n\nstatic void emit_text(Obj *prog) {\n  for (Obj *fn = prog; fn; fn = fn->next) {\n    if (!fn->is_function || !fn->is_definition)\n      continue;\n\n    // No code is emitted for \"static inline\" functions\n    // if no one is referencing them.\n    if (!fn->is_live)\n      continue;\n\n    if (fn->is_static)\n      println(\"  .local %s\", fn->name);\n    else\n      println(\"  .globl %s\", fn->name);\n\n    println(\"  .text\");\n    println(\"  .type %s, @function\", fn->name);\n    println(\"%s:\", fn->name);\n    current_fn = fn;\n\n    // Prologue\n    println(\"  push %%rbp\");\n    println(\"  mov %%rsp, %%rbp\");\n    println(\"  sub $%d, %%rsp\", fn->stack_size);\n    println(\"  mov %%rsp, %d(%%rbp)\", fn->alloca_bottom->offset);\n\n    // Save arg registers if function is variadic\n    if (fn->va_area) {\n      int gp = 0, fp = 0;\n      for (Obj *var = fn->params; var; var = var->next) {\n        if (is_flonum(var->ty))\n          fp++;\n        else\n          gp++;\n      }\n\n      int off = fn->va_area->offset;\n\n      // va_elem\n      println(\"  movl $%d, %d(%%rbp)\", gp * 8, off);          // gp_offset\n      println(\"  movl $%d, %d(%%rbp)\", fp * 8 + 48, off + 4); // fp_offset\n      println(\"  movq %%rbp, %d(%%rbp)\", off + 8);            // overflow_arg_area\n      println(\"  addq $16, %d(%%rbp)\", off + 8);\n      println(\"  movq %%rbp, %d(%%rbp)\", off + 16);           // reg_save_area\n      println(\"  addq $%d, %d(%%rbp)\", off + 24, off + 16);\n\n      // __reg_save_area__\n      println(\"  movq %%rdi, %d(%%rbp)\", off + 24);\n      println(\"  movq %%rsi, %d(%%rbp)\", off + 32);\n      println(\"  movq %%rdx, %d(%%rbp)\", off + 40);\n      println(\"  movq %%rcx, %d(%%rbp)\", off + 48);\n      println(\"  movq %%r8, %d(%%rbp)\", off + 56);\n      println(\"  movq %%r9, %d(%%rbp)\", off + 64);\n      println(\"  movsd %%xmm0, %d(%%rbp)\", off + 72);\n      println(\"  movsd %%xmm1, %d(%%rbp)\", off + 80);\n      println(\"  movsd %%xmm2, %d(%%rbp)\", off + 88);\n      println(\"  movsd %%xmm3, %d(%%rbp)\", off + 96);\n      println(\"  movsd %%xmm4, %d(%%rbp)\", off + 104);\n      println(\"  movsd %%xmm5, %d(%%rbp)\", off + 112);\n      println(\"  movsd %%xmm6, %d(%%rbp)\", off + 120);\n      println(\"  movsd %%xmm7, %d(%%rbp)\", off + 128);\n    }\n\n    // Save passed-by-register arguments to the stack\n    int gp = 0, fp = 0;\n    for (Obj *var = fn->params; var; var = var->next) {\n      if (var->offset > 0)\n        continue;\n\n      Type *ty = var->ty;\n\n      switch (ty->kind) {\n      case TY_STRUCT:\n      case TY_UNION:\n        assert(ty->size <= 16);\n        if (has_flonum(ty, 0, 8, 0))\n          store_fp(fp++, var->offset, MIN(8, ty->size));\n        else\n          store_gp(gp++, var->offset, MIN(8, ty->size));\n\n        if (ty->size > 8) {\n          if (has_flonum(ty, 8, 16, 0))\n            store_fp(fp++, var->offset + 8, ty->size - 8);\n          else\n            store_gp(gp++, var->offset + 8, ty->size - 8);\n        }\n        break;\n      case TY_FLOAT:\n      case TY_DOUBLE:\n        store_fp(fp++, var->offset, ty->size);\n        break;\n      default:\n        store_gp(gp++, var->offset, ty->size);\n      }\n    }\n\n    // Emit code\n    gen_stmt(fn->body);\n    assert(depth == 0);\n\n    // [https://www.sigbus.info/n1570#5.1.2.2.3p1] The C spec defines\n    // a special rule for the main function. Reaching the end of the\n    // main function is equivalent to returning 0, even though the\n    // behavior is undefined for the other functions.\n    if (strcmp(fn->name, \"main\") == 0)\n      println(\"  mov $0, %%rax\");\n\n    // Epilogue\n    println(\".L.return.%s:\", fn->name);\n    println(\"  mov %%rbp, %%rsp\");\n    println(\"  pop %%rbp\");\n    println(\"  ret\");\n  }\n}\n\nvoid codegen(Obj *prog, FILE *out) {\n  output_file = out;\n\n  File **files = get_input_files();\n  for (int i = 0; files[i]; i++)\n    println(\"  .file %d \\\"%s\\\"\", files[i]->file_no, files[i]->name);\n\n  assign_lvar_offsets(prog);\n  emit_data(prog);\n  emit_text(prog);\n}\n"
  },
  {
    "path": "hashmap.c",
    "content": "// This is an implementation of the open-addressing hash table.\n\n#include \"chibicc.h\"\n\n// Initial hash bucket size\n#define INIT_SIZE 16\n\n// Rehash if the usage exceeds 70%.\n#define HIGH_WATERMARK 70\n\n// We'll keep the usage below 50% after rehashing.\n#define LOW_WATERMARK 50\n\n// Represents a deleted hash entry\n#define TOMBSTONE ((void *)-1)\n\nstatic uint64_t fnv_hash(char *s, int len) {\n  uint64_t hash = 0xcbf29ce484222325;\n  for (int i = 0; i < len; i++) {\n    hash *= 0x100000001b3;\n    hash ^= (unsigned char)s[i];\n  }\n  return hash;\n}\n\n// Make room for new entires in a given hashmap by removing\n// tombstones and possibly extending the bucket size.\nstatic void rehash(HashMap *map) {\n  // Compute the size of the new hashmap.\n  int nkeys = 0;\n  for (int i = 0; i < map->capacity; i++)\n    if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE)\n      nkeys++;\n\n  int cap = map->capacity;\n  while ((nkeys * 100) / cap >= LOW_WATERMARK)\n    cap = cap * 2;\n  assert(cap > 0);\n\n  // Create a new hashmap and copy all key-values.\n  HashMap map2 = {};\n  map2.buckets = calloc(cap, sizeof(HashEntry));\n  map2.capacity = cap;\n\n  for (int i = 0; i < map->capacity; i++) {\n    HashEntry *ent = &map->buckets[i];\n    if (ent->key && ent->key != TOMBSTONE)\n      hashmap_put2(&map2, ent->key, ent->keylen, ent->val);\n  }\n\n  assert(map2.used == nkeys);\n  *map = map2;\n}\n\nstatic bool match(HashEntry *ent, char *key, int keylen) {\n  return ent->key && ent->key != TOMBSTONE &&\n         ent->keylen == keylen && memcmp(ent->key, key, keylen) == 0;\n}\n\nstatic HashEntry *get_entry(HashMap *map, char *key, int keylen) {\n  if (!map->buckets)\n    return NULL;\n\n  uint64_t hash = fnv_hash(key, keylen);\n\n  for (int i = 0; i < map->capacity; i++) {\n    HashEntry *ent = &map->buckets[(hash + i) % map->capacity];\n    if (match(ent, key, keylen))\n      return ent;\n    if (ent->key == NULL)\n      return NULL;\n  }\n  unreachable();\n}\n\nstatic HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {\n  if (!map->buckets) {\n    map->buckets = calloc(INIT_SIZE, sizeof(HashEntry));\n    map->capacity = INIT_SIZE;\n  } else if ((map->used * 100) / map->capacity >= HIGH_WATERMARK) {\n    rehash(map);\n  }\n\n  uint64_t hash = fnv_hash(key, keylen);\n\n  for (int i = 0; i < map->capacity; i++) {\n    HashEntry *ent = &map->buckets[(hash + i) % map->capacity];\n\n    if (match(ent, key, keylen))\n      return ent;\n\n    if (ent->key == TOMBSTONE) {\n      ent->key = key;\n      ent->keylen = keylen;\n      return ent;\n    }\n\n    if (ent->key == NULL) {\n      ent->key = key;\n      ent->keylen = keylen;\n      map->used++;\n      return ent;\n    }\n  }\n  unreachable();\n}\n\nvoid *hashmap_get(HashMap *map, char *key) {\n  return hashmap_get2(map, key, strlen(key));\n}\n\nvoid *hashmap_get2(HashMap *map, char *key, int keylen) {\n  HashEntry *ent = get_entry(map, key, keylen);\n  return ent ? ent->val : NULL;\n}\n\nvoid hashmap_put(HashMap *map, char *key, void *val) {\n   hashmap_put2(map, key, strlen(key), val);\n}\n\nvoid hashmap_put2(HashMap *map, char *key, int keylen, void *val) {\n  HashEntry *ent = get_or_insert_entry(map, key, keylen);\n  ent->val = val;\n}\n\nvoid hashmap_delete(HashMap *map, char *key) {\n  hashmap_delete2(map, key, strlen(key));\n}\n\nvoid hashmap_delete2(HashMap *map, char *key, int keylen) {\n  HashEntry *ent = get_entry(map, key, keylen);\n  if (ent)\n    ent->key = TOMBSTONE;\n}\n\nvoid hashmap_test(void) {\n  HashMap *map = calloc(1, sizeof(HashMap));\n\n  for (int i = 0; i < 5000; i++)\n    hashmap_put(map, format(\"key %d\", i), (void *)(size_t)i);\n  for (int i = 1000; i < 2000; i++)\n    hashmap_delete(map, format(\"key %d\", i));\n  for (int i = 1500; i < 1600; i++)\n    hashmap_put(map, format(\"key %d\", i), (void *)(size_t)i);\n  for (int i = 6000; i < 7000; i++)\n    hashmap_put(map, format(\"key %d\", i), (void *)(size_t)i);\n\n  for (int i = 0; i < 1000; i++)\n    assert((size_t)hashmap_get(map, format(\"key %d\", i)) == i);\n  for (int i = 1000; i < 1500; i++)\n    assert(hashmap_get(map, \"no such key\") == NULL);\n  for (int i = 1500; i < 1600; i++)\n    assert((size_t)hashmap_get(map, format(\"key %d\", i)) == i);\n  for (int i = 1600; i < 2000; i++)\n    assert(hashmap_get(map, \"no such key\") == NULL);\n  for (int i = 2000; i < 5000; i++)\n    assert((size_t)hashmap_get(map, format(\"key %d\", i)) == i);\n  for (int i = 5000; i < 6000; i++)\n    assert(hashmap_get(map, \"no such key\") == NULL);\n  for (int i = 6000; i < 7000; i++)\n    hashmap_put(map, format(\"key %d\", i), (void *)(size_t)i);\n\n  assert(hashmap_get(map, \"no such key\") == NULL);\n  printf(\"OK\\n\");\n}\n"
  },
  {
    "path": "include/float.h",
    "content": "#ifndef __STDFLOAT_H\n#define __STDFLOAT_H\n\n#define DECIMAL_DIG 21\n#define FLT_EVAL_METHOD 0 // C11 5.2.4.2.2p9\n#define FLT_RADIX 2\n#define FLT_ROUNDS 1      // C11 5.2.4.2.2p8: to nearest\n\n#define FLT_DIG 6\n#define FLT_EPSILON 0x1p-23\n#define FLT_MANT_DIG 24\n#define FLT_MAX 0x1.fffffep+127\n#define FLT_MAX_10_EXP 38\n#define FLT_MAX_EXP 128\n#define FLT_MIN 0x1p-126\n#define FLT_MIN_10_EXP -37\n#define FLT_MIN_EXP -125\n#define FLT_TRUE_MIN 0x1p-149\n\n#define DBL_DIG 15\n#define DBL_EPSILON 0x1p-52\n#define DBL_MANT_DIG 53\n#define DBL_MAX 0x1.fffffffffffffp+1023\n#define DBL_MAX_10_EXP 308\n#define DBL_MAX_EXP 1024\n#define DBL_MIN 0x1p-1022\n#define DBL_MIN_10_EXP -307\n#define DBL_MIN_EXP -1021\n#define DBL_TRUE_MIN 0x0.0000000000001p-1022\n\n#define LDBL_DIG 15\n#define LDBL_EPSILON 0x1p-52\n#define LDBL_MANT_DIG 53\n#define LDBL_MAX 0x1.fffffffffffffp+1023\n#define LDBL_MAX_10_EXP 308\n#define LDBL_MAX_EXP 1024\n#define LDBL_MIN 0x1p-1022\n#define LDBL_MIN_10_EXP -307\n#define LDBL_MIN_EXP -1021\n#define LDBL_TRUE_MIN 0x0.0000000000001p-1022\n\n#endif\n"
  },
  {
    "path": "include/stdalign.h",
    "content": "#ifndef __STDALIGN_H\n#define __STDALIGN_H\n\n#define alignas _Alignas\n#define alignof _Alignof\n#define __alignas_is_defined 1\n#define __alignof_is_defined 1\n\n#endif\n"
  },
  {
    "path": "include/stdarg.h",
    "content": "#ifndef __STDARG_H\n#define __STDARG_H\n\ntypedef struct {\n  unsigned int gp_offset;\n  unsigned int fp_offset;\n  void *overflow_arg_area;\n  void *reg_save_area;\n} __va_elem;\n\ntypedef __va_elem va_list[1];\n\n#define va_start(ap, last) \\\n  do { *(ap) = *(__va_elem *)__va_area__; } while (0)\n\n#define va_end(ap)\n\nstatic void *__va_arg_mem(__va_elem *ap, int sz, int align) {\n  void *p = ap->overflow_arg_area;\n  if (align > 8)\n    p = (p + 15) / 16 * 16;\n  ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;\n  return p;\n}\n\nstatic void *__va_arg_gp(__va_elem *ap, int sz, int align) {\n  if (ap->gp_offset >= 48)\n    return __va_arg_mem(ap, sz, align);\n\n  void *r = ap->reg_save_area + ap->gp_offset;\n  ap->gp_offset += 8;\n  return r;\n}\n\nstatic void *__va_arg_fp(__va_elem *ap, int sz, int align) {\n  if (ap->fp_offset >= 112)\n    return __va_arg_mem(ap, sz, align);\n\n  void *r = ap->reg_save_area + ap->fp_offset;\n  ap->fp_offset += 8;\n  return r;\n}\n\n#define va_arg(ap, ty)                                                  \\\n  ({                                                                    \\\n    int klass = __builtin_reg_class(ty);                                \\\n    *(ty *)(klass == 0 ? __va_arg_gp(ap, sizeof(ty), _Alignof(ty)) :    \\\n            klass == 1 ? __va_arg_fp(ap, sizeof(ty), _Alignof(ty)) :    \\\n            __va_arg_mem(ap, sizeof(ty), _Alignof(ty)));                \\\n  })\n\n#define va_copy(dest, src) ((dest)[0] = (src)[0])\n\n#define __GNUC_VA_LIST 1\ntypedef va_list __gnuc_va_list;\n\n#endif\n"
  },
  {
    "path": "include/stdatomic.h",
    "content": "#ifndef __STDATOMIC_H\n#define __STDATOMIC_H\n\n#define ATOMIC_BOOL_LOCK_FREE 1\n#define ATOMIC_CHAR_LOCK_FREE 1\n#define ATOMIC_CHAR16_T_LOCK_FREE 1\n#define ATOMIC_CHAR32_T_LOCK_FREE 1\n#define ATOMIC_WCHAR_T_LOCK_FREE 1\n#define ATOMIC_SHORT_LOCK_FREE 1\n#define ATOMIC_INT_LOCK_FREE 1\n#define ATOMIC_LONG_LOCK_FREE 1\n#define ATOMIC_LLONG_LOCK_FREE 1\n#define ATOMIC_POINTER_LOCK_FREE 1\n\ntypedef enum {\n  memory_order_relaxed,\n  memory_order_consume,\n  memory_order_acquire,\n  memory_order_release,\n  memory_order_acq_rel,\n  memory_order_seq_cst,\n} memory_order;\n\n#define ATOMIC_FLAG_INIT(x) (x)\n#define atomic_init(addr, val) (*(addr) = (val))\n#define kill_dependency(x) (x)\n#define atomic_thread_fence(order)\n#define atomic_signal_fence(order)\n#define atomic_is_lock_free(x) 1\n\n#define atomic_load(addr) (*(addr))\n#define atomic_store(addr, val) (*(addr) = (val))\n\n#define atomic_load_explicit(addr, order) (*(addr))\n#define atomic_store_explicit(addr, val, order) (*(addr) = (val))\n\n#define atomic_fetch_add(obj, val) (*(obj) += (val))\n#define atomic_fetch_sub(obj, val) (*(obj) -= (val))\n#define atomic_fetch_or(obj, val) (*(obj) |= (val))\n#define atomic_fetch_xor(obj, val) (*(obj) ^= (val))\n#define atomic_fetch_and(obj, val) (*(obj) &= (val))\n\n#define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val))\n#define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val))\n#define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val))\n#define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val))\n#define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val))\n\n#define atomic_compare_exchange_weak(p, old, new) \\\n  __builtin_compare_and_swap((p), (old), (new))\n\n#define atomic_compare_exchange_strong(p, old, new) \\\n  __builtin_compare_and_swap((p), (old), (new))\n\n#define atomic_exchange(obj, val) __builtin_atomic_exchange((obj), (val))\n#define atomic_exchange_explicit(obj, val, order) __builtin_atomic_exchange((obj), (val))\n\n#define atomic_flag_test_and_set(obj) atomic_exchange((obj), 1)\n#define atomic_flag_test_and_set_explicit(obj, order) atomic_exchange((obj), 1)\n#define atomic_flag_clear(obj) (*(obj) = 0)\n#define atomic_flag_clear_explicit(obj, order) (*(obj) = 0)\n\ntypedef _Atomic _Bool atomic_flag;\ntypedef _Atomic _Bool atomic_bool;\ntypedef _Atomic char atomic_char;\ntypedef _Atomic signed char atomic_schar;\ntypedef _Atomic unsigned char atomic_uchar;\ntypedef _Atomic short atomic_short;\ntypedef _Atomic unsigned short atomic_ushort;\ntypedef _Atomic int atomic_int;\ntypedef _Atomic unsigned int atomic_uint;\ntypedef _Atomic long atomic_long;\ntypedef _Atomic unsigned long atomic_ulong;\ntypedef _Atomic long long atomic_llong;\ntypedef _Atomic unsigned long long atomic_ullong;\ntypedef _Atomic unsigned short atomic_char16_t;\ntypedef _Atomic unsigned atomic_char32_t;\ntypedef _Atomic unsigned atomic_wchar_t;\ntypedef _Atomic signed char atomic_int_least8_t;\ntypedef _Atomic unsigned char atomic_uint_least8_t;\ntypedef _Atomic short atomic_int_least16_t;\ntypedef _Atomic unsigned short atomic_uint_least16_t;\ntypedef _Atomic int atomic_int_least32_t;\ntypedef _Atomic unsigned int atomic_uint_least32_t;\ntypedef _Atomic long atomic_int_least64_t;\ntypedef _Atomic unsigned long atomic_uint_least64_t;\ntypedef _Atomic signed char atomic_int_fast8_t;\ntypedef _Atomic unsigned char atomic_uint_fast8_t;\ntypedef _Atomic short atomic_int_fast16_t;\ntypedef _Atomic unsigned short atomic_uint_fast16_t;\ntypedef _Atomic int atomic_int_fast32_t;\ntypedef _Atomic unsigned int atomic_uint_fast32_t;\ntypedef _Atomic long atomic_int_fast64_t;\ntypedef _Atomic unsigned long atomic_uint_fast64_t;\ntypedef _Atomic long atomic_intptr_t;\ntypedef _Atomic unsigned long atomic_uintptr_t;\ntypedef _Atomic unsigned long atomic_size_t;\ntypedef _Atomic long atomic_ptrdiff_t;\ntypedef _Atomic long atomic_intmax_t;\ntypedef _Atomic unsigned long atomic_uintmax_t;\n\n#endif\n"
  },
  {
    "path": "include/stdbool.h",
    "content": "#ifndef __STDBOOL_H\n#define __STDBOOL_H\n\n#define bool _Bool\n#define true 1\n#define false 0\n#define __bool_true_false_are_defined 1\n\n#endif\n"
  },
  {
    "path": "include/stddef.h",
    "content": "#ifndef __STDDEF_H\n#define __STDDEF_H\n\n#define NULL ((void *)0)\n\ntypedef unsigned long size_t;\ntypedef long ptrdiff_t;\ntypedef unsigned int wchar_t;\ntypedef long max_align_t;\n\n#define offsetof(type, member) ((size_t)&(((type *)0)->member))\n\n#endif\n"
  },
  {
    "path": "include/stdnoreturn.h",
    "content": "#ifndef __STDNORETURN_H\n#define __STDNORETURN_H\n\n#define noreturn _Noreturn\n\n#endif\n"
  },
  {
    "path": "main.c",
    "content": "#include \"chibicc.h\"\n\ntypedef enum {\n  FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO,\n} FileType;\n\nStringArray include_paths;\nbool opt_fcommon = true;\nbool opt_fpic;\n\nstatic FileType opt_x;\nstatic StringArray opt_include;\nstatic bool opt_E;\nstatic bool opt_M;\nstatic bool opt_MD;\nstatic bool opt_MMD;\nstatic bool opt_MP;\nstatic bool opt_S;\nstatic bool opt_c;\nstatic bool opt_cc1;\nstatic bool opt_hash_hash_hash;\nstatic bool opt_static;\nstatic bool opt_shared;\nstatic char *opt_MF;\nstatic char *opt_MT;\nstatic char *opt_o;\n\nstatic StringArray ld_extra_args;\nstatic StringArray std_include_paths;\n\nchar *base_file;\nstatic char *output_file;\n\nstatic StringArray input_paths;\nstatic StringArray tmpfiles;\n\nstatic void usage(int status) {\n  fprintf(stderr, \"chibicc [ -o <path> ] <file>\\n\");\n  exit(status);\n}\n\nstatic bool take_arg(char *arg) {\n  char *x[] = {\n    \"-o\", \"-I\", \"-idirafter\", \"-include\", \"-x\", \"-MF\", \"-MT\", \"-Xlinker\",\n  };\n\n  for (int i = 0; i < sizeof(x) / sizeof(*x); i++)\n    if (!strcmp(arg, x[i]))\n      return true;\n  return false;\n}\n\nstatic void add_default_include_paths(char *argv0) {\n  // We expect that chibicc-specific include files are installed\n  // to ./include relative to argv[0].\n  strarray_push(&include_paths, format(\"%s/include\", dirname(strdup(argv0))));\n\n  // Add standard include paths.\n  strarray_push(&include_paths, \"/usr/local/include\");\n  strarray_push(&include_paths, \"/usr/include/x86_64-linux-gnu\");\n  strarray_push(&include_paths, \"/usr/include\");\n\n  // Keep a copy of the standard include paths for -MMD option.\n  for (int i = 0; i < include_paths.len; i++)\n    strarray_push(&std_include_paths, include_paths.data[i]);\n}\n\nstatic void define(char *str) {\n  char *eq = strchr(str, '=');\n  if (eq)\n    define_macro(strndup(str, eq - str), eq + 1);\n  else\n    define_macro(str, \"1\");\n}\n\nstatic FileType parse_opt_x(char *s) {\n  if (!strcmp(s, \"c\"))\n    return FILE_C;\n  if (!strcmp(s, \"assembler\"))\n    return FILE_ASM;\n  if (!strcmp(s, \"none\"))\n    return FILE_NONE;\n  error(\"<command line>: unknown argument for -x: %s\", s);\n}\n\nstatic char *quote_makefile(char *s) {\n  char *buf = calloc(1, strlen(s) * 2 + 1);\n\n  for (int i = 0, j = 0; s[i]; i++) {\n    switch (s[i]) {\n    case '$':\n      buf[j++] = '$';\n      buf[j++] = '$';\n      break;\n    case '#':\n      buf[j++] = '\\\\';\n      buf[j++] = '#';\n      break;\n    case ' ':\n    case '\\t':\n      for (int k = i - 1; k >= 0 && s[k] == '\\\\'; k--)\n        buf[j++] = '\\\\';\n      buf[j++] = '\\\\';\n      buf[j++] = s[i];\n      break;\n    default:\n      buf[j++] = s[i];\n      break;\n    }\n  }\n  return buf;\n}\n\nstatic void parse_args(int argc, char **argv) {\n  // Make sure that all command line options that take an argument\n  // have an argument.\n  for (int i = 1; i < argc; i++)\n    if (take_arg(argv[i]))\n      if (!argv[++i])\n        usage(1);\n\n  StringArray idirafter = {};\n\n  for (int i = 1; i < argc; i++) {\n    if (!strcmp(argv[i], \"-###\")) {\n      opt_hash_hash_hash = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-cc1\")) {\n      opt_cc1 = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"--help\"))\n      usage(0);\n\n    if (!strcmp(argv[i], \"-o\")) {\n      opt_o = argv[++i];\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-o\", 2)) {\n      opt_o = argv[i] + 2;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-S\")) {\n      opt_S = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-fcommon\")) {\n      opt_fcommon = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-fno-common\")) {\n      opt_fcommon = false;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-c\")) {\n      opt_c = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-E\")) {\n      opt_E = true;\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-I\", 2)) {\n      strarray_push(&include_paths, argv[i] + 2);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-D\")) {\n      define(argv[++i]);\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-D\", 2)) {\n      define(argv[i] + 2);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-U\")) {\n      undef_macro(argv[++i]);\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-U\", 2)) {\n      undef_macro(argv[i] + 2);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-include\")) {\n      strarray_push(&opt_include, argv[++i]);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-x\")) {\n      opt_x = parse_opt_x(argv[++i]);\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-x\", 2)) {\n      opt_x = parse_opt_x(argv[i] + 2);\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-l\", 2) || !strncmp(argv[i], \"-Wl,\", 4)) {\n      strarray_push(&input_paths, argv[i]);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-Xlinker\")) {\n      strarray_push(&ld_extra_args, argv[++i]);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-s\")) {\n      strarray_push(&ld_extra_args, \"-s\");\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-M\")) {\n      opt_M = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MF\")) {\n      opt_MF = argv[++i];\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MP\")) {\n      opt_MP = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MT\")) {\n      if (opt_MT == NULL)\n        opt_MT = argv[++i];\n      else\n        opt_MT = format(\"%s %s\", opt_MT, argv[++i]);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MD\")) {\n      opt_MD = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MQ\")) {\n      if (opt_MT == NULL)\n        opt_MT = quote_makefile(argv[++i]);\n      else\n        opt_MT = format(\"%s %s\", opt_MT, quote_makefile(argv[++i]));\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-MMD\")) {\n      opt_MD = opt_MMD = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-fpic\") || !strcmp(argv[i], \"-fPIC\")) {\n      opt_fpic = true;\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-cc1-input\")) {\n      base_file = argv[++i];\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-cc1-output\")) {\n      output_file = argv[++i];\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-idirafter\")) {\n      strarray_push(&idirafter, argv[i++]);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-static\")) {\n      opt_static = true;\n      strarray_push(&ld_extra_args, \"-static\");\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-shared\")) {\n      opt_shared = true;\n      strarray_push(&ld_extra_args, \"-shared\");\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-L\")) {\n      strarray_push(&ld_extra_args, \"-L\");\n      strarray_push(&ld_extra_args, argv[++i]);\n      continue;\n    }\n\n    if (!strncmp(argv[i], \"-L\", 2)) {\n      strarray_push(&ld_extra_args, \"-L\");\n      strarray_push(&ld_extra_args, argv[i] + 2);\n      continue;\n    }\n\n    if (!strcmp(argv[i], \"-hashmap-test\")) {\n      hashmap_test();\n      exit(0);\n    }\n\n    // These options are ignored for now.\n    if (!strncmp(argv[i], \"-O\", 2) ||\n        !strncmp(argv[i], \"-W\", 2) ||\n        !strncmp(argv[i], \"-g\", 2) ||\n        !strncmp(argv[i], \"-std=\", 5) ||\n        !strcmp(argv[i], \"-ffreestanding\") ||\n        !strcmp(argv[i], \"-fno-builtin\") ||\n        !strcmp(argv[i], \"-fno-omit-frame-pointer\") ||\n        !strcmp(argv[i], \"-fno-stack-protector\") ||\n        !strcmp(argv[i], \"-fno-strict-aliasing\") ||\n        !strcmp(argv[i], \"-m64\") ||\n        !strcmp(argv[i], \"-mno-red-zone\") ||\n        !strcmp(argv[i], \"-w\"))\n      continue;\n\n    if (argv[i][0] == '-' && argv[i][1] != '\\0')\n      error(\"unknown argument: %s\", argv[i]);\n\n    strarray_push(&input_paths, argv[i]);\n  }\n\n  for (int i = 0; i < idirafter.len; i++)\n    strarray_push(&include_paths, idirafter.data[i]);\n\n  if (input_paths.len == 0)\n    error(\"no input files\");\n\n  // -E implies that the input is the C macro language.\n  if (opt_E)\n    opt_x = FILE_C;\n}\n\nstatic FILE *open_file(char *path) {\n  if (!path || strcmp(path, \"-\") == 0)\n    return stdout;\n\n  FILE *out = fopen(path, \"w\");\n  if (!out)\n    error(\"cannot open output file: %s: %s\", path, strerror(errno));\n  return out;\n}\n\nstatic bool endswith(char *p, char *q) {\n  int len1 = strlen(p);\n  int len2 = strlen(q);\n  return (len1 >= len2) && !strcmp(p + len1 - len2, q);\n}\n\n// Replace file extension\nstatic char *replace_extn(char *tmpl, char *extn) {\n  char *filename = basename(strdup(tmpl));\n  char *dot = strrchr(filename, '.');\n  if (dot)\n    *dot = '\\0';\n  return format(\"%s%s\", filename, extn);\n}\n\nstatic void cleanup(void) {\n  for (int i = 0; i < tmpfiles.len; i++)\n    unlink(tmpfiles.data[i]);\n}\n\nstatic char *create_tmpfile(void) {\n  char *path = strdup(\"/tmp/chibicc-XXXXXX\");\n  int fd = mkstemp(path);\n  if (fd == -1)\n    error(\"mkstemp failed: %s\", strerror(errno));\n  close(fd);\n\n  strarray_push(&tmpfiles, path);\n  return path;\n}\n\nstatic void run_subprocess(char **argv) {\n  // If -### is given, dump the subprocess's command line.\n  if (opt_hash_hash_hash) {\n    fprintf(stderr, \"%s\", argv[0]);\n    for (int i = 1; argv[i]; i++)\n      fprintf(stderr, \" %s\", argv[i]);\n    fprintf(stderr, \"\\n\");\n  }\n\n  if (fork() == 0) {\n    // Child process. Run a new command.\n    execvp(argv[0], argv);\n    fprintf(stderr, \"exec failed: %s: %s\\n\", argv[0], strerror(errno));\n    _exit(1);\n  }\n\n  // Wait for the child process to finish.\n  int status;\n  while (wait(&status) > 0);\n  if (status != 0)\n    exit(1);\n}\n\nstatic void run_cc1(int argc, char **argv, char *input, char *output) {\n  char **args = calloc(argc + 10, sizeof(char *));\n  memcpy(args, argv, argc * sizeof(char *));\n  args[argc++] = \"-cc1\";\n\n  if (input) {\n    args[argc++] = \"-cc1-input\";\n    args[argc++] = input;\n  }\n\n  if (output) {\n    args[argc++] = \"-cc1-output\";\n    args[argc++] = output;\n  }\n\n  run_subprocess(args);\n}\n\n// Print tokens to stdout. Used for -E.\nstatic void print_tokens(Token *tok) {\n  FILE *out = open_file(opt_o ? opt_o : \"-\");\n\n  int line = 1;\n  for (; tok->kind != TK_EOF; tok = tok->next) {\n    if (line > 1 && tok->at_bol)\n      fprintf(out, \"\\n\");\n    if (tok->has_space && !tok->at_bol)\n      fprintf(out, \" \");\n    fprintf(out, \"%.*s\", tok->len, tok->loc);\n    line++;\n  }\n  fprintf(out, \"\\n\");\n}\n\nstatic bool in_std_include_path(char *path) {\n  for (int i = 0; i < std_include_paths.len; i++) {\n    char *dir = std_include_paths.data[i];\n    int len = strlen(dir);\n    if (strncmp(dir, path, len) == 0 && path[len] == '/')\n      return true;\n  }\n  return false;\n}\n\n// If -M options is given, the compiler write a list of input files to\n// stdout in a format that \"make\" command can read. This feature is\n// used to automate file dependency management.\nstatic void print_dependencies(void) {\n  char *path;\n  if (opt_MF)\n    path = opt_MF;\n  else if (opt_MD)\n    path = replace_extn(opt_o ? opt_o : base_file, \".d\");\n  else if (opt_o)\n    path = opt_o;\n  else\n    path = \"-\";\n\n  FILE *out = open_file(path);\n  if (opt_MT)\n    fprintf(out, \"%s:\", opt_MT);\n  else\n    fprintf(out, \"%s:\", quote_makefile(replace_extn(base_file, \".o\")));\n\n  File **files = get_input_files();\n\n  for (int i = 0; files[i]; i++) {\n    if (opt_MMD && in_std_include_path(files[i]->name))\n      continue;\n    fprintf(out, \" \\\\\\n  %s\", files[i]->name);\n  }\n\n  fprintf(out, \"\\n\\n\");\n\n  if (opt_MP) {\n    for (int i = 1; files[i]; i++) {\n      if (opt_MMD && in_std_include_path(files[i]->name))\n        continue;\n      fprintf(out, \"%s:\\n\\n\", quote_makefile(files[i]->name));\n    }\n  }\n}\n\nstatic Token *must_tokenize_file(char *path) {\n  Token *tok = tokenize_file(path);\n  if (!tok)\n    error(\"%s: %s\", path, strerror(errno));\n  return tok;\n}\n\nstatic Token *append_tokens(Token *tok1, Token *tok2) {\n  if (!tok1 || tok1->kind == TK_EOF)\n    return tok2;\n\n  Token *t = tok1;\n  while (t->next->kind != TK_EOF)\n    t = t->next;\n  t->next = tok2;\n  return tok1;\n}\n\nstatic void cc1(void) {\n  Token *tok = NULL;\n\n  // Process -include option\n  for (int i = 0; i < opt_include.len; i++) {\n    char *incl = opt_include.data[i];\n\n    char *path;\n    if (file_exists(incl)) {\n      path = incl;\n    } else {\n      path = search_include_paths(incl);\n      if (!path)\n        error(\"-include: %s: %s\", incl, strerror(errno));\n    }\n\n    Token *tok2 = must_tokenize_file(path);\n    tok = append_tokens(tok, tok2);\n  }\n\n  // Tokenize and parse.\n  Token *tok2 = must_tokenize_file(base_file);\n  tok = append_tokens(tok, tok2);\n  tok = preprocess(tok);\n\n  // If -M or -MD are given, print file dependencies.\n  if (opt_M || opt_MD) {\n    print_dependencies();\n    if (opt_M)\n      return;\n  }\n\n  // If -E is given, print out preprocessed C code as a result.\n  if (opt_E) {\n    print_tokens(tok);\n    return;\n  }\n\n  Obj *prog = parse(tok);\n\n  // Open a temporary output buffer.\n  char *buf;\n  size_t buflen;\n  FILE *output_buf = open_memstream(&buf, &buflen);\n\n  // Traverse the AST to emit assembly.\n  codegen(prog, output_buf);\n  fclose(output_buf);\n\n  // Write the asembly text to a file.\n  FILE *out = open_file(output_file);\n  fwrite(buf, buflen, 1, out);\n  fclose(out);\n}\n\nstatic void assemble(char *input, char *output) {\n  char *cmd[] = {\"as\", \"-c\", input, \"-o\", output, NULL};\n  run_subprocess(cmd);\n}\n\nstatic char *find_file(char *pattern) {\n  char *path = NULL;\n  glob_t buf = {};\n  glob(pattern, 0, NULL, &buf);\n  if (buf.gl_pathc > 0)\n    path = strdup(buf.gl_pathv[buf.gl_pathc - 1]);\n  globfree(&buf);\n  return path;\n}\n\n// Returns true if a given file exists.\nbool file_exists(char *path) {\n  struct stat st;\n  return !stat(path, &st);\n}\n\nstatic char *find_libpath(void) {\n  if (file_exists(\"/usr/lib/x86_64-linux-gnu/crti.o\"))\n    return \"/usr/lib/x86_64-linux-gnu\";\n  if (file_exists(\"/usr/lib64/crti.o\"))\n    return \"/usr/lib64\";\n  error(\"library path is not found\");\n}\n\nstatic char *find_gcc_libpath(void) {\n  char *paths[] = {\n    \"/usr/lib/gcc/x86_64-linux-gnu/*/crtbegin.o\",\n    \"/usr/lib/gcc/x86_64-pc-linux-gnu/*/crtbegin.o\", // For Gentoo\n    \"/usr/lib/gcc/x86_64-redhat-linux/*/crtbegin.o\", // For Fedora\n  };\n\n  for (int i = 0; i < sizeof(paths) / sizeof(*paths); i++) {\n    char *path = find_file(paths[i]);\n    if (path)\n      return dirname(path);\n  }\n\n  error(\"gcc library path is not found\");\n}\n\nstatic void run_linker(StringArray *inputs, char *output) {\n  StringArray arr = {};\n\n  strarray_push(&arr, \"ld\");\n  strarray_push(&arr, \"-o\");\n  strarray_push(&arr, output);\n  strarray_push(&arr, \"-m\");\n  strarray_push(&arr, \"elf_x86_64\");\n\n  char *libpath = find_libpath();\n  char *gcc_libpath = find_gcc_libpath();\n\n  if (opt_shared) {\n    strarray_push(&arr, format(\"%s/crti.o\", libpath));\n    strarray_push(&arr, format(\"%s/crtbeginS.o\", gcc_libpath));\n  } else {\n    strarray_push(&arr, format(\"%s/crt1.o\", libpath));\n    strarray_push(&arr, format(\"%s/crti.o\", libpath));\n    strarray_push(&arr, format(\"%s/crtbegin.o\", gcc_libpath));\n  }\n\n  strarray_push(&arr, format(\"-L%s\", gcc_libpath));\n  strarray_push(&arr, \"-L/usr/lib/x86_64-linux-gnu\");\n  strarray_push(&arr, \"-L/usr/lib64\");\n  strarray_push(&arr, \"-L/lib64\");\n  strarray_push(&arr, \"-L/usr/lib/x86_64-linux-gnu\");\n  strarray_push(&arr, \"-L/usr/lib/x86_64-pc-linux-gnu\");\n  strarray_push(&arr, \"-L/usr/lib/x86_64-redhat-linux\");\n  strarray_push(&arr, \"-L/usr/lib\");\n  strarray_push(&arr, \"-L/lib\");\n\n  if (!opt_static) {\n    strarray_push(&arr, \"-dynamic-linker\");\n    strarray_push(&arr, \"/lib64/ld-linux-x86-64.so.2\");\n  }\n\n  for (int i = 0; i < ld_extra_args.len; i++)\n    strarray_push(&arr, ld_extra_args.data[i]);\n\n  for (int i = 0; i < inputs->len; i++)\n    strarray_push(&arr, inputs->data[i]);\n\n  if (opt_static) {\n    strarray_push(&arr, \"--start-group\");\n    strarray_push(&arr, \"-lgcc\");\n    strarray_push(&arr, \"-lgcc_eh\");\n    strarray_push(&arr, \"-lc\");\n    strarray_push(&arr, \"--end-group\");\n  } else {\n    strarray_push(&arr, \"-lc\");\n    strarray_push(&arr, \"-lgcc\");\n    strarray_push(&arr, \"--as-needed\");\n    strarray_push(&arr, \"-lgcc_s\");\n    strarray_push(&arr, \"--no-as-needed\");\n  }\n\n  if (opt_shared)\n    strarray_push(&arr, format(\"%s/crtendS.o\", gcc_libpath));\n  else\n    strarray_push(&arr, format(\"%s/crtend.o\", gcc_libpath));\n\n  strarray_push(&arr, format(\"%s/crtn.o\", libpath));\n  strarray_push(&arr, NULL);\n\n  run_subprocess(arr.data);\n}\n\nstatic FileType get_file_type(char *filename) {\n  if (opt_x != FILE_NONE)\n    return opt_x;\n\n  if (endswith(filename, \".a\"))\n    return FILE_AR;\n  if (endswith(filename, \".so\"))\n    return FILE_DSO;\n  if (endswith(filename, \".o\"))\n    return FILE_OBJ;\n  if (endswith(filename, \".c\"))\n    return FILE_C;\n  if (endswith(filename, \".s\"))\n    return FILE_ASM;\n\n  error(\"<command line>: unknown file extension: %s\", filename);\n}\n\nint main(int argc, char **argv) {\n  atexit(cleanup);\n  init_macros();\n  parse_args(argc, argv);\n\n  if (opt_cc1) {\n    add_default_include_paths(argv[0]);\n    cc1();\n    return 0;\n  }\n\n  if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))\n    error(\"cannot specify '-o' with '-c,' '-S' or '-E' with multiple files\");\n\n  StringArray ld_args = {};\n\n  for (int i = 0; i < input_paths.len; i++) {\n    char *input = input_paths.data[i];\n\n    if (!strncmp(input, \"-l\", 2)) {\n      strarray_push(&ld_args, input);\n      continue;\n    }\n\n    if (!strncmp(input, \"-Wl,\", 4)) {\n      char *s = strdup(input + 4);\n      char *arg = strtok(s, \",\");\n      while (arg) {\n        strarray_push(&ld_args, arg);\n        arg = strtok(NULL, \",\");\n      }\n      continue;\n    }\n\n    char *output;\n    if (opt_o)\n      output = opt_o;\n    else if (opt_S)\n      output = replace_extn(input, \".s\");\n    else\n      output = replace_extn(input, \".o\");\n\n    FileType type = get_file_type(input);\n\n    // Handle .o or .a\n    if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) {\n      strarray_push(&ld_args, input);\n      continue;\n    }\n\n    // Handle .s\n    if (type == FILE_ASM) {\n      if (!opt_S)\n        assemble(input, output);\n      continue;\n    }\n\n    assert(type == FILE_C);\n\n    // Just preprocess\n    if (opt_E || opt_M) {\n      run_cc1(argc, argv, input, NULL);\n      continue;\n    }\n\n    // Compile\n    if (opt_S) {\n      run_cc1(argc, argv, input, output);\n      continue;\n    }\n\n    // Compile and assemble\n    if (opt_c) {\n      char *tmp = create_tmpfile();\n      run_cc1(argc, argv, input, tmp);\n      assemble(tmp, output);\n      continue;\n    }\n\n    // Compile, assemble and link\n    char *tmp1 = create_tmpfile();\n    char *tmp2 = create_tmpfile();\n    run_cc1(argc, argv, input, tmp1);\n    assemble(tmp1, tmp2);\n    strarray_push(&ld_args, tmp2);\n    continue;\n  }\n\n  if (ld_args.len > 0)\n    run_linker(&ld_args, opt_o ? opt_o : \"a.out\");\n  return 0;\n}\n"
  },
  {
    "path": "parse.c",
    "content": "// This file contains a recursive descent parser for C.\n//\n// Most functions in this file are named after the symbols they are\n// supposed to read from an input token list. For example, stmt() is\n// responsible for reading a statement from a token list. The function\n// then construct an AST node representing a statement.\n//\n// Each function conceptually returns two values, an AST node and\n// remaining part of the input tokens. Since C doesn't support\n// multiple return values, the remaining tokens are returned to the\n// caller via a pointer argument.\n//\n// Input tokens are represented by a linked list. Unlike many recursive\n// descent parsers, we don't have the notion of the \"input token stream\".\n// Most parsing functions don't change the global state of the parser.\n// So it is very easy to lookahead arbitrary number of tokens in this\n// parser.\n\n#include \"chibicc.h\"\n\n// Scope for local variables, global variables, typedefs\n// or enum constants\ntypedef struct {\n  Obj *var;\n  Type *type_def;\n  Type *enum_ty;\n  int enum_val;\n} VarScope;\n\n// Represents a block scope.\ntypedef struct Scope Scope;\nstruct Scope {\n  Scope *next;\n\n  // C has two block scopes; one is for variables/typedefs and\n  // the other is for struct/union/enum tags.\n  HashMap vars;\n  HashMap tags;\n};\n\n// Variable attributes such as typedef or extern.\ntypedef struct {\n  bool is_typedef;\n  bool is_static;\n  bool is_extern;\n  bool is_inline;\n  bool is_tls;\n  int align;\n} VarAttr;\n\n// This struct represents a variable initializer. Since initializers\n// can be nested (e.g. `int x[2][2] = {{1, 2}, {3, 4}}`), this struct\n// is a tree data structure.\ntypedef struct Initializer Initializer;\nstruct Initializer {\n  Initializer *next;\n  Type *ty;\n  Token *tok;\n  bool is_flexible;\n\n  // If it's not an aggregate type and has an initializer,\n  // `expr` has an initialization expression.\n  Node *expr;\n\n  // If it's an initializer for an aggregate type (e.g. array or struct),\n  // `children` has initializers for its children.\n  Initializer **children;\n\n  // Only one member can be initialized for a union.\n  // `mem` is used to clarify which member is initialized.\n  Member *mem;\n};\n\n// For local variable initializer.\ntypedef struct InitDesg InitDesg;\nstruct InitDesg {\n  InitDesg *next;\n  int idx;\n  Member *member;\n  Obj *var;\n};\n\n// All local variable instances created during parsing are\n// accumulated to this list.\nstatic Obj *locals;\n\n// Likewise, global variables are accumulated to this list.\nstatic Obj *globals;\n\nstatic Scope *scope = &(Scope){};\n\n// Points to the function object the parser is currently parsing.\nstatic Obj *current_fn;\n\n// Lists of all goto statements and labels in the curent function.\nstatic Node *gotos;\nstatic Node *labels;\n\n// Current \"goto\" and \"continue\" jump targets.\nstatic char *brk_label;\nstatic char *cont_label;\n\n// Points to a node representing a switch if we are parsing\n// a switch statement. Otherwise, NULL.\nstatic Node *current_switch;\n\nstatic Obj *builtin_alloca;\n\nstatic bool is_typename(Token *tok);\nstatic Type *declspec(Token **rest, Token *tok, VarAttr *attr);\nstatic Type *typename(Token **rest, Token *tok);\nstatic Type *enum_specifier(Token **rest, Token *tok);\nstatic Type *typeof_specifier(Token **rest, Token *tok);\nstatic Type *type_suffix(Token **rest, Token *tok, Type *ty);\nstatic Type *declarator(Token **rest, Token *tok, Type *ty);\nstatic Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr);\nstatic void array_initializer2(Token **rest, Token *tok, Initializer *init, int i);\nstatic void struct_initializer2(Token **rest, Token *tok, Initializer *init, Member *mem);\nstatic void initializer2(Token **rest, Token *tok, Initializer *init);\nstatic Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty);\nstatic Node *lvar_initializer(Token **rest, Token *tok, Obj *var);\nstatic void gvar_initializer(Token **rest, Token *tok, Obj *var);\nstatic Node *compound_stmt(Token **rest, Token *tok);\nstatic Node *stmt(Token **rest, Token *tok);\nstatic Node *expr_stmt(Token **rest, Token *tok);\nstatic Node *expr(Token **rest, Token *tok);\nstatic int64_t eval(Node *node);\nstatic int64_t eval2(Node *node, char ***label);\nstatic int64_t eval_rval(Node *node, char ***label);\nstatic bool is_const_expr(Node *node);\nstatic Node *assign(Token **rest, Token *tok);\nstatic Node *logor(Token **rest, Token *tok);\nstatic double eval_double(Node *node);\nstatic Node *conditional(Token **rest, Token *tok);\nstatic Node *logand(Token **rest, Token *tok);\nstatic Node *bitor(Token **rest, Token *tok);\nstatic Node *bitxor(Token **rest, Token *tok);\nstatic Node *bitand(Token **rest, Token *tok);\nstatic Node *equality(Token **rest, Token *tok);\nstatic Node *relational(Token **rest, Token *tok);\nstatic Node *shift(Token **rest, Token *tok);\nstatic Node *add(Token **rest, Token *tok);\nstatic Node *new_add(Node *lhs, Node *rhs, Token *tok);\nstatic Node *new_sub(Node *lhs, Node *rhs, Token *tok);\nstatic Node *mul(Token **rest, Token *tok);\nstatic Node *cast(Token **rest, Token *tok);\nstatic Member *get_struct_member(Type *ty, Token *tok);\nstatic Type *struct_decl(Token **rest, Token *tok);\nstatic Type *union_decl(Token **rest, Token *tok);\nstatic Node *postfix(Token **rest, Token *tok);\nstatic Node *funcall(Token **rest, Token *tok, Node *node);\nstatic Node *unary(Token **rest, Token *tok);\nstatic Node *primary(Token **rest, Token *tok);\nstatic Token *parse_typedef(Token *tok, Type *basety);\nstatic bool is_function(Token *tok);\nstatic Token *function(Token *tok, Type *basety, VarAttr *attr);\nstatic Token *global_variable(Token *tok, Type *basety, VarAttr *attr);\n\nstatic int align_down(int n, int align) {\n  return align_to(n - align + 1, align);\n}\n\nstatic void enter_scope(void) {\n  Scope *sc = calloc(1, sizeof(Scope));\n  sc->next = scope;\n  scope = sc;\n}\n\nstatic void leave_scope(void) {\n  scope = scope->next;\n}\n\n// Find a variable by name.\nstatic VarScope *find_var(Token *tok) {\n  for (Scope *sc = scope; sc; sc = sc->next) {\n    VarScope *sc2 = hashmap_get2(&sc->vars, tok->loc, tok->len);\n    if (sc2)\n      return sc2;\n  }\n  return NULL;\n}\n\nstatic Type *find_tag(Token *tok) {\n  for (Scope *sc = scope; sc; sc = sc->next) {\n    Type *ty = hashmap_get2(&sc->tags, tok->loc, tok->len);\n    if (ty)\n      return ty;\n  }\n  return NULL;\n}\n\nstatic Node *new_node(NodeKind kind, Token *tok) {\n  Node *node = calloc(1, sizeof(Node));\n  node->kind = kind;\n  node->tok = tok;\n  return node;\n}\n\nstatic Node *new_binary(NodeKind kind, Node *lhs, Node *rhs, Token *tok) {\n  Node *node = new_node(kind, tok);\n  node->lhs = lhs;\n  node->rhs = rhs;\n  return node;\n}\n\nstatic Node *new_unary(NodeKind kind, Node *expr, Token *tok) {\n  Node *node = new_node(kind, tok);\n  node->lhs = expr;\n  return node;\n}\n\nstatic Node *new_num(int64_t val, Token *tok) {\n  Node *node = new_node(ND_NUM, tok);\n  node->val = val;\n  return node;\n}\n\nstatic Node *new_long(int64_t val, Token *tok) {\n  Node *node = new_node(ND_NUM, tok);\n  node->val = val;\n  node->ty = ty_long;\n  return node;\n}\n\nstatic Node *new_ulong(long val, Token *tok) {\n  Node *node = new_node(ND_NUM, tok);\n  node->val = val;\n  node->ty = ty_ulong;\n  return node;\n}\n\nstatic Node *new_var_node(Obj *var, Token *tok) {\n  Node *node = new_node(ND_VAR, tok);\n  node->var = var;\n  return node;\n}\n\nstatic Node *new_vla_ptr(Obj *var, Token *tok) {\n  Node *node = new_node(ND_VLA_PTR, tok);\n  node->var = var;\n  return node;\n}\n\nNode *new_cast(Node *expr, Type *ty) {\n  add_type(expr);\n\n  Node *node = calloc(1, sizeof(Node));\n  node->kind = ND_CAST;\n  node->tok = expr->tok;\n  node->lhs = expr;\n  node->ty = copy_type(ty);\n  return node;\n}\n\nstatic VarScope *push_scope(char *name) {\n  VarScope *sc = calloc(1, sizeof(VarScope));\n  hashmap_put(&scope->vars, name, sc);\n  return sc;\n}\n\nstatic Initializer *new_initializer(Type *ty, bool is_flexible) {\n  Initializer *init = calloc(1, sizeof(Initializer));\n  init->ty = ty;\n\n  if (ty->kind == TY_ARRAY) {\n    if (is_flexible && ty->size < 0) {\n      init->is_flexible = true;\n      return init;\n    }\n\n    init->children = calloc(ty->array_len, sizeof(Initializer *));\n    for (int i = 0; i < ty->array_len; i++)\n      init->children[i] = new_initializer(ty->base, false);\n    return init;\n  }\n\n  if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) {\n    // Count the number of struct members.\n    int len = 0;\n    for (Member *mem = ty->members; mem; mem = mem->next)\n      len++;\n\n    init->children = calloc(len, sizeof(Initializer *));\n\n    for (Member *mem = ty->members; mem; mem = mem->next) {\n      if (is_flexible && ty->is_flexible && !mem->next) {\n        Initializer *child = calloc(1, sizeof(Initializer));\n        child->ty = mem->ty;\n        child->is_flexible = true;\n        init->children[mem->idx] = child;\n      } else {\n        init->children[mem->idx] = new_initializer(mem->ty, false);\n      }\n    }\n    return init;\n  }\n\n  return init;\n}\n\nstatic Obj *new_var(char *name, Type *ty) {\n  Obj *var = calloc(1, sizeof(Obj));\n  var->name = name;\n  var->ty = ty;\n  var->align = ty->align;\n  push_scope(name)->var = var;\n  return var;\n}\n\nstatic Obj *new_lvar(char *name, Type *ty) {\n  Obj *var = new_var(name, ty);\n  var->is_local = true;\n  var->next = locals;\n  locals = var;\n  return var;\n}\n\nstatic Obj *new_gvar(char *name, Type *ty) {\n  Obj *var = new_var(name, ty);\n  var->next = globals;\n  var->is_static = true;\n  var->is_definition = true;\n  globals = var;\n  return var;\n}\n\nstatic char *new_unique_name(void) {\n  static int id = 0;\n  return format(\".L..%d\", id++);\n}\n\nstatic Obj *new_anon_gvar(Type *ty) {\n  return new_gvar(new_unique_name(), ty);\n}\n\nstatic Obj *new_string_literal(char *p, Type *ty) {\n  Obj *var = new_anon_gvar(ty);\n  var->init_data = p;\n  return var;\n}\n\nstatic char *get_ident(Token *tok) {\n  if (tok->kind != TK_IDENT)\n    error_tok(tok, \"expected an identifier\");\n  return strndup(tok->loc, tok->len);\n}\n\nstatic Type *find_typedef(Token *tok) {\n  if (tok->kind == TK_IDENT) {\n    VarScope *sc = find_var(tok);\n    if (sc)\n      return sc->type_def;\n  }\n  return NULL;\n}\n\nstatic void push_tag_scope(Token *tok, Type *ty) {\n  hashmap_put2(&scope->tags, tok->loc, tok->len, ty);\n}\n\n// declspec = (\"void\" | \"_Bool\" | \"char\" | \"short\" | \"int\" | \"long\"\n//             | \"typedef\" | \"static\" | \"extern\" | \"inline\"\n//             | \"_Thread_local\" | \"__thread\"\n//             | \"signed\" | \"unsigned\"\n//             | struct-decl | union-decl | typedef-name\n//             | enum-specifier | typeof-specifier\n//             | \"const\" | \"volatile\" | \"auto\" | \"register\" | \"restrict\"\n//             | \"__restrict\" | \"__restrict__\" | \"_Noreturn\")+\n//\n// The order of typenames in a type-specifier doesn't matter. For\n// example, `int long static` means the same as `static long int`.\n// That can also be written as `static long` because you can omit\n// `int` if `long` or `short` are specified. However, something like\n// `char int` is not a valid type specifier. We have to accept only a\n// limited combinations of the typenames.\n//\n// In this function, we count the number of occurrences of each typename\n// while keeping the \"current\" type object that the typenames up\n// until that point represent. When we reach a non-typename token,\n// we returns the current type object.\nstatic Type *declspec(Token **rest, Token *tok, VarAttr *attr) {\n  // We use a single integer as counters for all typenames.\n  // For example, bits 0 and 1 represents how many times we saw the\n  // keyword \"void\" so far. With this, we can use a switch statement\n  // as you can see below.\n  enum {\n    VOID     = 1 << 0,\n    BOOL     = 1 << 2,\n    CHAR     = 1 << 4,\n    SHORT    = 1 << 6,\n    INT      = 1 << 8,\n    LONG     = 1 << 10,\n    FLOAT    = 1 << 12,\n    DOUBLE   = 1 << 14,\n    OTHER    = 1 << 16,\n    SIGNED   = 1 << 17,\n    UNSIGNED = 1 << 18,\n  };\n\n  Type *ty = ty_int;\n  int counter = 0;\n  bool is_atomic = false;\n\n  while (is_typename(tok)) {\n    // Handle storage class specifiers.\n    if (equal(tok, \"typedef\") || equal(tok, \"static\") || equal(tok, \"extern\") ||\n        equal(tok, \"inline\") || equal(tok, \"_Thread_local\") || equal(tok, \"__thread\")) {\n      if (!attr)\n        error_tok(tok, \"storage class specifier is not allowed in this context\");\n\n      if (equal(tok, \"typedef\"))\n        attr->is_typedef = true;\n      else if (equal(tok, \"static\"))\n        attr->is_static = true;\n      else if (equal(tok, \"extern\"))\n        attr->is_extern = true;\n      else if (equal(tok, \"inline\"))\n        attr->is_inline = true;\n      else\n        attr->is_tls = true;\n\n      if (attr->is_typedef &&\n          attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls > 1)\n        error_tok(tok, \"typedef may not be used together with static,\"\n                  \" extern, inline, __thread or _Thread_local\");\n      tok = tok->next;\n      continue;\n    }\n\n    // These keywords are recognized but ignored.\n    if (consume(&tok, tok, \"const\") || consume(&tok, tok, \"volatile\") ||\n        consume(&tok, tok, \"auto\") || consume(&tok, tok, \"register\") ||\n        consume(&tok, tok, \"restrict\") || consume(&tok, tok, \"__restrict\") ||\n        consume(&tok, tok, \"__restrict__\") || consume(&tok, tok, \"_Noreturn\"))\n      continue;\n\n    if (equal(tok, \"_Atomic\")) {\n      tok = tok->next;\n      if (equal(tok , \"(\")) {\n        ty = typename(&tok, tok->next);\n        tok = skip(tok, \")\");\n      }\n      is_atomic = true;\n      continue;\n    }\n\n    if (equal(tok, \"_Alignas\")) {\n      if (!attr)\n        error_tok(tok, \"_Alignas is not allowed in this context\");\n      tok = skip(tok->next, \"(\");\n\n      if (is_typename(tok))\n        attr->align = typename(&tok, tok)->align;\n      else\n        attr->align = const_expr(&tok, tok);\n      tok = skip(tok, \")\");\n      continue;\n    }\n\n    // Handle user-defined types.\n    Type *ty2 = find_typedef(tok);\n    if (equal(tok, \"struct\") || equal(tok, \"union\") || equal(tok, \"enum\") ||\n        equal(tok, \"typeof\") || ty2) {\n      if (counter)\n        break;\n\n      if (equal(tok, \"struct\")) {\n        ty = struct_decl(&tok, tok->next);\n      } else if (equal(tok, \"union\")) {\n        ty = union_decl(&tok, tok->next);\n      } else if (equal(tok, \"enum\")) {\n        ty = enum_specifier(&tok, tok->next);\n      } else if (equal(tok, \"typeof\")) {\n        ty = typeof_specifier(&tok, tok->next);\n      } else {\n        ty = ty2;\n        tok = tok->next;\n      }\n\n      counter += OTHER;\n      continue;\n    }\n\n    // Handle built-in types.\n    if (equal(tok, \"void\"))\n      counter += VOID;\n    else if (equal(tok, \"_Bool\"))\n      counter += BOOL;\n    else if (equal(tok, \"char\"))\n      counter += CHAR;\n    else if (equal(tok, \"short\"))\n      counter += SHORT;\n    else if (equal(tok, \"int\"))\n      counter += INT;\n    else if (equal(tok, \"long\"))\n      counter += LONG;\n    else if (equal(tok, \"float\"))\n      counter += FLOAT;\n    else if (equal(tok, \"double\"))\n      counter += DOUBLE;\n    else if (equal(tok, \"signed\"))\n      counter |= SIGNED;\n    else if (equal(tok, \"unsigned\"))\n      counter |= UNSIGNED;\n    else\n      unreachable();\n\n    switch (counter) {\n    case VOID:\n      ty = ty_void;\n      break;\n    case BOOL:\n      ty = ty_bool;\n      break;\n    case CHAR:\n    case SIGNED + CHAR:\n      ty = ty_char;\n      break;\n    case UNSIGNED + CHAR:\n      ty = ty_uchar;\n      break;\n    case SHORT:\n    case SHORT + INT:\n    case SIGNED + SHORT:\n    case SIGNED + SHORT + INT:\n      ty = ty_short;\n      break;\n    case UNSIGNED + SHORT:\n    case UNSIGNED + SHORT + INT:\n      ty = ty_ushort;\n      break;\n    case INT:\n    case SIGNED:\n    case SIGNED + INT:\n      ty = ty_int;\n      break;\n    case UNSIGNED:\n    case UNSIGNED + INT:\n      ty = ty_uint;\n      break;\n    case LONG:\n    case LONG + INT:\n    case LONG + LONG:\n    case LONG + LONG + INT:\n    case SIGNED + LONG:\n    case SIGNED + LONG + INT:\n    case SIGNED + LONG + LONG:\n    case SIGNED + LONG + LONG + INT:\n      ty = ty_long;\n      break;\n    case UNSIGNED + LONG:\n    case UNSIGNED + LONG + INT:\n    case UNSIGNED + LONG + LONG:\n    case UNSIGNED + LONG + LONG + INT:\n      ty = ty_ulong;\n      break;\n    case FLOAT:\n      ty = ty_float;\n      break;\n    case DOUBLE:\n      ty = ty_double;\n      break;\n    case LONG + DOUBLE:\n      ty = ty_ldouble;\n      break;\n    default:\n      error_tok(tok, \"invalid type\");\n    }\n\n    tok = tok->next;\n  }\n\n  if (is_atomic) {\n    ty = copy_type(ty);\n    ty->is_atomic = true;\n  }\n\n  *rest = tok;\n  return ty;\n}\n\n// func-params = (\"void\" | param (\",\" param)* (\",\" \"...\")?)? \")\"\n// param       = declspec declarator\nstatic Type *func_params(Token **rest, Token *tok, Type *ty) {\n  if (equal(tok, \"void\") && equal(tok->next, \")\")) {\n    *rest = tok->next->next;\n    return func_type(ty);\n  }\n\n  Type head = {};\n  Type *cur = &head;\n  bool is_variadic = false;\n\n  while (!equal(tok, \")\")) {\n    if (cur != &head)\n      tok = skip(tok, \",\");\n\n    if (equal(tok, \"...\")) {\n      is_variadic = true;\n      tok = tok->next;\n      skip(tok, \")\");\n      break;\n    }\n\n    Type *ty2 = declspec(&tok, tok, NULL);\n    ty2 = declarator(&tok, tok, ty2);\n\n    Token *name = ty2->name;\n\n    if (ty2->kind == TY_ARRAY) {\n      // \"array of T\" is converted to \"pointer to T\" only in the parameter\n      // context. For example, *argv[] is converted to **argv by this.\n      ty2 = pointer_to(ty2->base);\n      ty2->name = name;\n    } else if (ty2->kind == TY_FUNC) {\n      // Likewise, a function is converted to a pointer to a function\n      // only in the parameter context.\n      ty2 = pointer_to(ty2);\n      ty2->name = name;\n    }\n\n    cur = cur->next = copy_type(ty2);\n  }\n\n  if (cur == &head)\n    is_variadic = true;\n\n  ty = func_type(ty);\n  ty->params = head.next;\n  ty->is_variadic = is_variadic;\n  *rest = tok->next;\n  return ty;\n}\n\n// array-dimensions = (\"static\" | \"restrict\")* const-expr? \"]\" type-suffix\nstatic Type *array_dimensions(Token **rest, Token *tok, Type *ty) {\n  while (equal(tok, \"static\") || equal(tok, \"restrict\"))\n    tok = tok->next;\n\n  if (equal(tok, \"]\")) {\n    ty = type_suffix(rest, tok->next, ty);\n    return array_of(ty, -1);\n  }\n\n  Node *expr = conditional(&tok, tok);\n  tok = skip(tok, \"]\");\n  ty = type_suffix(rest, tok, ty);\n\n  if (ty->kind == TY_VLA || !is_const_expr(expr))\n    return vla_of(ty, expr);\n  return array_of(ty, eval(expr));\n}\n\n// type-suffix = \"(\" func-params\n//             | \"[\" array-dimensions\n//             | ε\nstatic Type *type_suffix(Token **rest, Token *tok, Type *ty) {\n  if (equal(tok, \"(\"))\n    return func_params(rest, tok->next, ty);\n\n  if (equal(tok, \"[\"))\n    return array_dimensions(rest, tok->next, ty);\n\n  *rest = tok;\n  return ty;\n}\n\n// pointers = (\"*\" (\"const\" | \"volatile\" | \"restrict\")*)*\nstatic Type *pointers(Token **rest, Token *tok, Type *ty) {\n  while (consume(&tok, tok, \"*\")) {\n    ty = pointer_to(ty);\n    while (equal(tok, \"const\") || equal(tok, \"volatile\") || equal(tok, \"restrict\") ||\n           equal(tok, \"__restrict\") || equal(tok, \"__restrict__\"))\n      tok = tok->next;\n  }\n  *rest = tok;\n  return ty;\n}\n\n// declarator = pointers (\"(\" ident \")\" | \"(\" declarator \")\" | ident) type-suffix\nstatic Type *declarator(Token **rest, Token *tok, Type *ty) {\n  ty = pointers(&tok, tok, ty);\n\n  if (equal(tok, \"(\")) {\n    Token *start = tok;\n    Type dummy = {};\n    declarator(&tok, start->next, &dummy);\n    tok = skip(tok, \")\");\n    ty = type_suffix(rest, tok, ty);\n    return declarator(&tok, start->next, ty);\n  }\n\n  Token *name = NULL;\n  Token *name_pos = tok;\n\n  if (tok->kind == TK_IDENT) {\n    name = tok;\n    tok = tok->next;\n  }\n\n  ty = type_suffix(rest, tok, ty);\n  ty->name = name;\n  ty->name_pos = name_pos;\n  return ty;\n}\n\n// abstract-declarator = pointers (\"(\" abstract-declarator \")\")? type-suffix\nstatic Type *abstract_declarator(Token **rest, Token *tok, Type *ty) {\n  ty = pointers(&tok, tok, ty);\n\n  if (equal(tok, \"(\")) {\n    Token *start = tok;\n    Type dummy = {};\n    abstract_declarator(&tok, start->next, &dummy);\n    tok = skip(tok, \")\");\n    ty = type_suffix(rest, tok, ty);\n    return abstract_declarator(&tok, start->next, ty);\n  }\n\n  return type_suffix(rest, tok, ty);\n}\n\n// type-name = declspec abstract-declarator\nstatic Type *typename(Token **rest, Token *tok) {\n  Type *ty = declspec(&tok, tok, NULL);\n  return abstract_declarator(rest, tok, ty);\n}\n\nstatic bool is_end(Token *tok) {\n  return equal(tok, \"}\") || (equal(tok, \",\") && equal(tok->next, \"}\"));\n}\n\nstatic bool consume_end(Token **rest, Token *tok) {\n  if (equal(tok, \"}\")) {\n    *rest = tok->next;\n    return true;\n  }\n\n  if (equal(tok, \",\") && equal(tok->next, \"}\")) {\n    *rest = tok->next->next;\n    return true;\n  }\n\n  return false;\n}\n\n// enum-specifier = ident? \"{\" enum-list? \"}\"\n//                | ident (\"{\" enum-list? \"}\")?\n//\n// enum-list      = ident (\"=\" num)? (\",\" ident (\"=\" num)?)* \",\"?\nstatic Type *enum_specifier(Token **rest, Token *tok) {\n  Type *ty = enum_type();\n\n  // Read a struct tag.\n  Token *tag = NULL;\n  if (tok->kind == TK_IDENT) {\n    tag = tok;\n    tok = tok->next;\n  }\n\n  if (tag && !equal(tok, \"{\")) {\n    Type *ty = find_tag(tag);\n    if (!ty)\n      error_tok(tag, \"unknown enum type\");\n    if (ty->kind != TY_ENUM)\n      error_tok(tag, \"not an enum tag\");\n    *rest = tok;\n    return ty;\n  }\n\n  tok = skip(tok, \"{\");\n\n  // Read an enum-list.\n  int i = 0;\n  int val = 0;\n  while (!consume_end(rest, tok)) {\n    if (i++ > 0)\n      tok = skip(tok, \",\");\n\n    char *name = get_ident(tok);\n    tok = tok->next;\n\n    if (equal(tok, \"=\"))\n      val = const_expr(&tok, tok->next);\n\n    VarScope *sc = push_scope(name);\n    sc->enum_ty = ty;\n    sc->enum_val = val++;\n  }\n\n  if (tag)\n    push_tag_scope(tag, ty);\n  return ty;\n}\n\n// typeof-specifier = \"(\" (expr | typename) \")\"\nstatic Type *typeof_specifier(Token **rest, Token *tok) {\n  tok = skip(tok, \"(\");\n\n  Type *ty;\n  if (is_typename(tok)) {\n    ty = typename(&tok, tok);\n  } else {\n    Node *node = expr(&tok, tok);\n    add_type(node);\n    ty = node->ty;\n  }\n  *rest = skip(tok, \")\");\n  return ty;\n}\n\n// Generate code for computing a VLA size.\nstatic Node *compute_vla_size(Type *ty, Token *tok) {\n  Node *node = new_node(ND_NULL_EXPR, tok);\n  if (ty->base)\n    node = new_binary(ND_COMMA, node, compute_vla_size(ty->base, tok), tok);\n\n  if (ty->kind != TY_VLA)\n    return node;\n\n  Node *base_sz;\n  if (ty->base->kind == TY_VLA)\n    base_sz = new_var_node(ty->base->vla_size, tok);\n  else\n    base_sz = new_num(ty->base->size, tok);\n\n  ty->vla_size = new_lvar(\"\", ty_ulong);\n  Node *expr = new_binary(ND_ASSIGN, new_var_node(ty->vla_size, tok),\n                          new_binary(ND_MUL, ty->vla_len, base_sz, tok),\n                          tok);\n  return new_binary(ND_COMMA, node, expr, tok);\n}\n\nstatic Node *new_alloca(Node *sz) {\n  Node *node = new_unary(ND_FUNCALL, new_var_node(builtin_alloca, sz->tok), sz->tok);\n  node->func_ty = builtin_alloca->ty;\n  node->ty = builtin_alloca->ty->return_ty;\n  node->args = sz;\n  add_type(sz);\n  return node;\n}\n\n// declaration = declspec (declarator (\"=\" expr)? (\",\" declarator (\"=\" expr)?)*)? \";\"\nstatic Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr) {\n  Node head = {};\n  Node *cur = &head;\n  int i = 0;\n\n  while (!equal(tok, \";\")) {\n    if (i++ > 0)\n      tok = skip(tok, \",\");\n\n    Type *ty = declarator(&tok, tok, basety);\n    if (ty->kind == TY_VOID)\n      error_tok(tok, \"variable declared void\");\n    if (!ty->name)\n      error_tok(ty->name_pos, \"variable name omitted\");\n\n    if (attr && attr->is_static) {\n      // static local variable\n      Obj *var = new_anon_gvar(ty);\n      push_scope(get_ident(ty->name))->var = var;\n      if (equal(tok, \"=\"))\n        gvar_initializer(&tok, tok->next, var);\n      continue;\n    }\n\n    // Generate code for computing a VLA size. We need to do this\n    // even if ty is not VLA because ty may be a pointer to VLA\n    // (e.g. int (*foo)[n][m] where n and m are variables.)\n    cur = cur->next = new_unary(ND_EXPR_STMT, compute_vla_size(ty, tok), tok);\n\n    if (ty->kind == TY_VLA) {\n      if (equal(tok, \"=\"))\n        error_tok(tok, \"variable-sized object may not be initialized\");\n\n      // Variable length arrays (VLAs) are translated to alloca() calls.\n      // For example, `int x[n+2]` is translated to `tmp = n + 2,\n      // x = alloca(tmp)`.\n      Obj *var = new_lvar(get_ident(ty->name), ty);\n      Token *tok = ty->name;\n      Node *expr = new_binary(ND_ASSIGN, new_vla_ptr(var, tok),\n                              new_alloca(new_var_node(ty->vla_size, tok)),\n                              tok);\n\n      cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);\n      continue;\n    }\n\n    Obj *var = new_lvar(get_ident(ty->name), ty);\n    if (attr && attr->align)\n      var->align = attr->align;\n\n    if (equal(tok, \"=\")) {\n      Node *expr = lvar_initializer(&tok, tok->next, var);\n      cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);\n    }\n\n    if (var->ty->size < 0)\n      error_tok(ty->name, \"variable has incomplete type\");\n    if (var->ty->kind == TY_VOID)\n      error_tok(ty->name, \"variable declared void\");\n  }\n\n  Node *node = new_node(ND_BLOCK, tok);\n  node->body = head.next;\n  *rest = tok->next;\n  return node;\n}\n\nstatic Token *skip_excess_element(Token *tok) {\n  if (equal(tok, \"{\")) {\n    tok = skip_excess_element(tok->next);\n    return skip(tok, \"}\");\n  }\n\n  assign(&tok, tok);\n  return tok;\n}\n\n// string-initializer = string-literal\nstatic void string_initializer(Token **rest, Token *tok, Initializer *init) {\n  if (init->is_flexible)\n    *init = *new_initializer(array_of(init->ty->base, tok->ty->array_len), false);\n\n  int len = MIN(init->ty->array_len, tok->ty->array_len);\n\n  switch (init->ty->base->size) {\n  case 1: {\n    char *str = tok->str;\n    for (int i = 0; i < len; i++)\n      init->children[i]->expr = new_num(str[i], tok);\n    break;\n  }\n  case 2: {\n    uint16_t *str = (uint16_t *)tok->str;\n    for (int i = 0; i < len; i++)\n      init->children[i]->expr = new_num(str[i], tok);\n    break;\n  }\n  case 4: {\n    uint32_t *str = (uint32_t *)tok->str;\n    for (int i = 0; i < len; i++)\n      init->children[i]->expr = new_num(str[i], tok);\n    break;\n  }\n  default:\n    unreachable();\n  }\n\n  *rest = tok->next;\n}\n\n// array-designator = \"[\" const-expr \"]\"\n//\n// C99 added the designated initializer to the language, which allows\n// programmers to move the \"cursor\" of an initializer to any element.\n// The syntax looks like this:\n//\n//   int x[10] = { 1, 2, [5]=3, 4, 5, 6, 7 };\n//\n// `[5]` moves the cursor to the 5th element, so the 5th element of x\n// is set to 3. Initialization then continues forward in order, so\n// 6th, 7th, 8th and 9th elements are initialized with 4, 5, 6 and 7,\n// respectively. Unspecified elements (in this case, 3rd and 4th\n// elements) are initialized with zero.\n//\n// Nesting is allowed, so the following initializer is valid:\n//\n//   int x[5][10] = { [5][8]=1, 2, 3 };\n//\n// It sets x[5][8], x[5][9] and x[6][0] to 1, 2 and 3, respectively.\n//\n// Use `.fieldname` to move the cursor for a struct initializer. E.g.\n//\n//   struct { int a, b, c; } x = { .c=5 };\n//\n// The above initializer sets x.c to 5.\nstatic void array_designator(Token **rest, Token *tok, Type *ty, int *begin, int *end) {\n  *begin = const_expr(&tok, tok->next);\n  if (*begin >= ty->array_len)\n    error_tok(tok, \"array designator index exceeds array bounds\");\n\n  if (equal(tok, \"...\")) {\n    *end = const_expr(&tok, tok->next);\n    if (*end >= ty->array_len)\n      error_tok(tok, \"array designator index exceeds array bounds\");\n    if (*end < *begin)\n      error_tok(tok, \"array designator range [%d, %d] is empty\", *begin, *end);\n  } else {\n    *end = *begin;\n  }\n\n  *rest = skip(tok, \"]\");\n}\n\n// struct-designator = \".\" ident\nstatic Member *struct_designator(Token **rest, Token *tok, Type *ty) {\n  Token *start = tok;\n  tok = skip(tok, \".\");\n  if (tok->kind != TK_IDENT)\n    error_tok(tok, \"expected a field designator\");\n\n  for (Member *mem = ty->members; mem; mem = mem->next) {\n    // Anonymous struct member\n    if (mem->ty->kind == TY_STRUCT && !mem->name) {\n      if (get_struct_member(mem->ty, tok)) {\n        *rest = start;\n        return mem;\n      }\n      continue;\n    }\n\n    // Regular struct member\n    if (mem->name->len == tok->len && !strncmp(mem->name->loc, tok->loc, tok->len)) {\n      *rest = tok->next;\n      return mem;\n    }\n  }\n\n  error_tok(tok, \"struct has no such member\");\n}\n\n// designation = (\"[\" const-expr \"]\" | \".\" ident)* \"=\"? initializer\nstatic void designation(Token **rest, Token *tok, Initializer *init) {\n  if (equal(tok, \"[\")) {\n    if (init->ty->kind != TY_ARRAY)\n      error_tok(tok, \"array index in non-array initializer\");\n\n    int begin, end;\n    array_designator(&tok, tok, init->ty, &begin, &end);\n\n    Token *tok2;\n    for (int i = begin; i <= end; i++)\n      designation(&tok2, tok, init->children[i]);\n    array_initializer2(rest, tok2, init, begin + 1);\n    return;\n  }\n\n  if (equal(tok, \".\") && init->ty->kind == TY_STRUCT) {\n    Member *mem = struct_designator(&tok, tok, init->ty);\n    designation(&tok, tok, init->children[mem->idx]);\n    init->expr = NULL;\n    struct_initializer2(rest, tok, init, mem->next);\n    return;\n  }\n\n  if (equal(tok, \".\") && init->ty->kind == TY_UNION) {\n    Member *mem = struct_designator(&tok, tok, init->ty);\n    init->mem = mem;\n    designation(rest, tok, init->children[mem->idx]);\n    return;\n  }\n\n  if (equal(tok, \".\"))\n    error_tok(tok, \"field name not in struct or union initializer\");\n\n  if (equal(tok, \"=\"))\n    tok = tok->next;\n  initializer2(rest, tok, init);\n}\n\n// An array length can be omitted if an array has an initializer\n// (e.g. `int x[] = {1,2,3}`). If it's omitted, count the number\n// of initializer elements.\nstatic int count_array_init_elements(Token *tok, Type *ty) {\n  bool first = true;\n  Initializer *dummy = new_initializer(ty->base, true);\n\n  int i = 0, max = 0;\n\n  while (!consume_end(&tok, tok)) {\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    if (equal(tok, \"[\")) {\n      i = const_expr(&tok, tok->next);\n      if (equal(tok, \"...\"))\n        i = const_expr(&tok, tok->next);\n      tok = skip(tok, \"]\");\n      designation(&tok, tok, dummy);\n    } else {\n      initializer2(&tok, tok, dummy);\n    }\n\n    i++;\n    max = MAX(max, i);\n  }\n  return max;\n}\n\n// array-initializer1 = \"{\" initializer (\",\" initializer)* \",\"? \"}\"\nstatic void array_initializer1(Token **rest, Token *tok, Initializer *init) {\n  tok = skip(tok, \"{\");\n\n  if (init->is_flexible) {\n    int len = count_array_init_elements(tok, init->ty);\n    *init = *new_initializer(array_of(init->ty->base, len), false);\n  }\n\n  bool first = true;\n\n  if (init->is_flexible) {\n    int len = count_array_init_elements(tok, init->ty);\n    *init = *new_initializer(array_of(init->ty->base, len), false);\n  }\n\n  for (int i = 0; !consume_end(rest, tok); i++) {\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    if (equal(tok, \"[\")) {\n      int begin, end;\n      array_designator(&tok, tok, init->ty, &begin, &end);\n\n      Token *tok2;\n      for (int j = begin; j <= end; j++)\n        designation(&tok2, tok, init->children[j]);\n      tok = tok2;\n      i = end;\n      continue;\n    }\n\n    if (i < init->ty->array_len)\n      initializer2(&tok, tok, init->children[i]);\n    else\n      tok = skip_excess_element(tok);\n  }\n}\n\n// array-initializer2 = initializer (\",\" initializer)*\nstatic void array_initializer2(Token **rest, Token *tok, Initializer *init, int i) {\n  if (init->is_flexible) {\n    int len = count_array_init_elements(tok, init->ty);\n    *init = *new_initializer(array_of(init->ty->base, len), false);\n  }\n\n  for (; i < init->ty->array_len && !is_end(tok); i++) {\n    Token *start = tok;\n    if (i > 0)\n      tok = skip(tok, \",\");\n\n    if (equal(tok, \"[\") || equal(tok, \".\")) {\n      *rest = start;\n      return;\n    }\n\n    initializer2(&tok, tok, init->children[i]);\n  }\n  *rest = tok;\n}\n\n// struct-initializer1 = \"{\" initializer (\",\" initializer)* \",\"? \"}\"\nstatic void struct_initializer1(Token **rest, Token *tok, Initializer *init) {\n  tok = skip(tok, \"{\");\n\n  Member *mem = init->ty->members;\n  bool first = true;\n\n  while (!consume_end(rest, tok)) {\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    if (equal(tok, \".\")) {\n      mem = struct_designator(&tok, tok, init->ty);\n      designation(&tok, tok, init->children[mem->idx]);\n      mem = mem->next;\n      continue;\n    }\n\n    if (mem) {\n      initializer2(&tok, tok, init->children[mem->idx]);\n      mem = mem->next;\n    } else {\n      tok = skip_excess_element(tok);\n    }\n  }\n}\n\n// struct-initializer2 = initializer (\",\" initializer)*\nstatic void struct_initializer2(Token **rest, Token *tok, Initializer *init, Member *mem) {\n  bool first = true;\n\n  for (; mem && !is_end(tok); mem = mem->next) {\n    Token *start = tok;\n\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    if (equal(tok, \"[\") || equal(tok, \".\")) {\n      *rest = start;\n      return;\n    }\n\n    initializer2(&tok, tok, init->children[mem->idx]);\n  }\n  *rest = tok;\n}\n\nstatic void union_initializer(Token **rest, Token *tok, Initializer *init) {\n  // Unlike structs, union initializers take only one initializer,\n  // and that initializes the first union member by default.\n  // You can initialize other member using a designated initializer.\n  if (equal(tok, \"{\") && equal(tok->next, \".\")) {\n    Member *mem = struct_designator(&tok, tok->next, init->ty);\n    init->mem = mem;\n    designation(&tok, tok, init->children[mem->idx]);\n    *rest = skip(tok, \"}\");\n    return;\n  }\n\n  init->mem = init->ty->members;\n\n  if (equal(tok, \"{\")) {\n    initializer2(&tok, tok->next, init->children[0]);\n    consume(&tok, tok, \",\");\n    *rest = skip(tok, \"}\");\n  } else {\n    initializer2(rest, tok, init->children[0]);\n  }\n}\n\n// initializer = string-initializer | array-initializer\n//             | struct-initializer | union-initializer\n//             | assign\nstatic void initializer2(Token **rest, Token *tok, Initializer *init) {\n  if (init->ty->kind == TY_ARRAY && tok->kind == TK_STR) {\n    string_initializer(rest, tok, init);\n    return;\n  }\n\n  if (init->ty->kind == TY_ARRAY) {\n    if (equal(tok, \"{\"))\n      array_initializer1(rest, tok, init);\n    else\n      array_initializer2(rest, tok, init, 0);\n    return;\n  }\n\n  if (init->ty->kind == TY_STRUCT) {\n    if (equal(tok, \"{\")) {\n      struct_initializer1(rest, tok, init);\n      return;\n    }\n\n    // A struct can be initialized with another struct. E.g.\n    // `struct T x = y;` where y is a variable of type `struct T`.\n    // Handle that case first.\n    Node *expr = assign(rest, tok);\n    add_type(expr);\n    if (expr->ty->kind == TY_STRUCT) {\n      init->expr = expr;\n      return;\n    }\n\n    struct_initializer2(rest, tok, init, init->ty->members);\n    return;\n  }\n\n  if (init->ty->kind == TY_UNION) {\n    union_initializer(rest, tok, init);\n    return;\n  }\n\n  if (equal(tok, \"{\")) {\n    // An initializer for a scalar variable can be surrounded by\n    // braces. E.g. `int x = {3};`. Handle that case.\n    initializer2(&tok, tok->next, init);\n    *rest = skip(tok, \"}\");\n    return;\n  }\n\n  init->expr = assign(rest, tok);\n}\n\nstatic Type *copy_struct_type(Type *ty) {\n  ty = copy_type(ty);\n\n  Member head = {};\n  Member *cur = &head;\n  for (Member *mem = ty->members; mem; mem = mem->next) {\n    Member *m = calloc(1, sizeof(Member));\n    *m = *mem;\n    cur = cur->next = m;\n  }\n\n  ty->members = head.next;\n  return ty;\n}\n\nstatic Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty) {\n  Initializer *init = new_initializer(ty, true);\n  initializer2(rest, tok, init);\n\n  if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION) && ty->is_flexible) {\n    ty = copy_struct_type(ty);\n\n    Member *mem = ty->members;\n    while (mem->next)\n      mem = mem->next;\n    mem->ty = init->children[mem->idx]->ty;\n    ty->size += mem->ty->size;\n\n    *new_ty = ty;\n    return init;\n  }\n\n  *new_ty = init->ty;\n  return init;\n}\n\nstatic Node *init_desg_expr(InitDesg *desg, Token *tok) {\n  if (desg->var)\n    return new_var_node(desg->var, tok);\n\n  if (desg->member) {\n    Node *node = new_unary(ND_MEMBER, init_desg_expr(desg->next, tok), tok);\n    node->member = desg->member;\n    return node;\n  }\n\n  Node *lhs = init_desg_expr(desg->next, tok);\n  Node *rhs = new_num(desg->idx, tok);\n  return new_unary(ND_DEREF, new_add(lhs, rhs, tok), tok);\n}\n\nstatic Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token *tok) {\n  if (ty->kind == TY_ARRAY) {\n    Node *node = new_node(ND_NULL_EXPR, tok);\n    for (int i = 0; i < ty->array_len; i++) {\n      InitDesg desg2 = {desg, i};\n      Node *rhs = create_lvar_init(init->children[i], ty->base, &desg2, tok);\n      node = new_binary(ND_COMMA, node, rhs, tok);\n    }\n    return node;\n  }\n\n  if (ty->kind == TY_STRUCT && !init->expr) {\n    Node *node = new_node(ND_NULL_EXPR, tok);\n\n    for (Member *mem = ty->members; mem; mem = mem->next) {\n      InitDesg desg2 = {desg, 0, mem};\n      Node *rhs = create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok);\n      node = new_binary(ND_COMMA, node, rhs, tok);\n    }\n    return node;\n  }\n\n  if (ty->kind == TY_UNION) {\n    Member *mem = init->mem ? init->mem : ty->members;\n    InitDesg desg2 = {desg, 0, mem};\n    return create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok);\n  }\n\n  if (!init->expr)\n    return new_node(ND_NULL_EXPR, tok);\n\n  Node *lhs = init_desg_expr(desg, tok);\n  return new_binary(ND_ASSIGN, lhs, init->expr, tok);\n}\n\n// A variable definition with an initializer is a shorthand notation\n// for a variable definition followed by assignments. This function\n// generates assignment expressions for an initializer. For example,\n// `int x[2][2] = {{6, 7}, {8, 9}}` is converted to the following\n// expressions:\n//\n//   x[0][0] = 6;\n//   x[0][1] = 7;\n//   x[1][0] = 8;\n//   x[1][1] = 9;\nstatic Node *lvar_initializer(Token **rest, Token *tok, Obj *var) {\n  Initializer *init = initializer(rest, tok, var->ty, &var->ty);\n  InitDesg desg = {NULL, 0, NULL, var};\n\n  // If a partial initializer list is given, the standard requires\n  // that unspecified elements are set to 0. Here, we simply\n  // zero-initialize the entire memory region of a variable before\n  // initializing it with user-supplied values.\n  Node *lhs = new_node(ND_MEMZERO, tok);\n  lhs->var = var;\n\n  Node *rhs = create_lvar_init(init, var->ty, &desg, tok);\n  return new_binary(ND_COMMA, lhs, rhs, tok);\n}\n\nstatic uint64_t read_buf(char *buf, int sz) {\n  if (sz == 1)\n    return *buf;\n  if (sz == 2)\n    return *(uint16_t *)buf;\n  if (sz == 4)\n    return *(uint32_t *)buf;\n  if (sz == 8)\n    return *(uint64_t *)buf;\n  unreachable();\n}\n\nstatic void write_buf(char *buf, uint64_t val, int sz) {\n  if (sz == 1)\n    *buf = val;\n  else if (sz == 2)\n    *(uint16_t *)buf = val;\n  else if (sz == 4)\n    *(uint32_t *)buf = val;\n  else if (sz == 8)\n    *(uint64_t *)buf = val;\n  else\n    unreachable();\n}\n\nstatic Relocation *\nwrite_gvar_data(Relocation *cur, Initializer *init, Type *ty, char *buf, int offset) {\n  if (ty->kind == TY_ARRAY) {\n    int sz = ty->base->size;\n    for (int i = 0; i < ty->array_len; i++)\n      cur = write_gvar_data(cur, init->children[i], ty->base, buf, offset + sz * i);\n    return cur;\n  }\n\n  if (ty->kind == TY_STRUCT) {\n    for (Member *mem = ty->members; mem; mem = mem->next) {\n      if (mem->is_bitfield) {\n        Node *expr = init->children[mem->idx]->expr;\n        if (!expr)\n          break;\n\n        char *loc = buf + offset + mem->offset;\n        uint64_t oldval = read_buf(loc, mem->ty->size);\n        uint64_t newval = eval(expr);\n        uint64_t mask = (1L << mem->bit_width) - 1;\n        uint64_t combined = oldval | ((newval & mask) << mem->bit_offset);\n        write_buf(loc, combined, mem->ty->size);\n      } else {\n        cur = write_gvar_data(cur, init->children[mem->idx], mem->ty, buf,\n                              offset + mem->offset);\n      }\n    }\n    return cur;\n  }\n\n  if (ty->kind == TY_UNION) {\n    if (!init->mem)\n      return cur;\n    return write_gvar_data(cur, init->children[init->mem->idx],\n                           init->mem->ty, buf, offset);\n  }\n\n  if (!init->expr)\n    return cur;\n\n  if (ty->kind == TY_FLOAT) {\n    *(float *)(buf + offset) = eval_double(init->expr);\n    return cur;\n  }\n\n  if (ty->kind == TY_DOUBLE) {\n    *(double *)(buf + offset) = eval_double(init->expr);\n    return cur;\n  }\n\n  char **label = NULL;\n  uint64_t val = eval2(init->expr, &label);\n\n  if (!label) {\n    write_buf(buf + offset, val, ty->size);\n    return cur;\n  }\n\n  Relocation *rel = calloc(1, sizeof(Relocation));\n  rel->offset = offset;\n  rel->label = label;\n  rel->addend = val;\n  cur->next = rel;\n  return cur->next;\n}\n\n// Initializers for global variables are evaluated at compile-time and\n// embedded to .data section. This function serializes Initializer\n// objects to a flat byte array. It is a compile error if an\n// initializer list contains a non-constant expression.\nstatic void gvar_initializer(Token **rest, Token *tok, Obj *var) {\n  Initializer *init = initializer(rest, tok, var->ty, &var->ty);\n\n  Relocation head = {};\n  char *buf = calloc(1, var->ty->size);\n  write_gvar_data(&head, init, var->ty, buf, 0);\n  var->init_data = buf;\n  var->rel = head.next;\n}\n\n// Returns true if a given token represents a type.\nstatic bool is_typename(Token *tok) {\n  static HashMap map;\n\n  if (map.capacity == 0) {\n    static char *kw[] = {\n      \"void\", \"_Bool\", \"char\", \"short\", \"int\", \"long\", \"struct\", \"union\",\n      \"typedef\", \"enum\", \"static\", \"extern\", \"_Alignas\", \"signed\", \"unsigned\",\n      \"const\", \"volatile\", \"auto\", \"register\", \"restrict\", \"__restrict\",\n      \"__restrict__\", \"_Noreturn\", \"float\", \"double\", \"typeof\", \"inline\",\n      \"_Thread_local\", \"__thread\", \"_Atomic\",\n    };\n\n    for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)\n      hashmap_put(&map, kw[i], (void *)1);\n  }\n\n  return hashmap_get2(&map, tok->loc, tok->len) || find_typedef(tok);\n}\n\n// asm-stmt = \"asm\" (\"volatile\" | \"inline\")* \"(\" string-literal \")\"\nstatic Node *asm_stmt(Token **rest, Token *tok) {\n  Node *node = new_node(ND_ASM, tok);\n  tok = tok->next;\n\n  while (equal(tok, \"volatile\") || equal(tok, \"inline\"))\n    tok = tok->next;\n\n  tok = skip(tok, \"(\");\n  if (tok->kind != TK_STR || tok->ty->base->kind != TY_CHAR)\n    error_tok(tok, \"expected string literal\");\n  node->asm_str = tok->str;\n  *rest = skip(tok->next, \")\");\n  return node;\n}\n\n// stmt = \"return\" expr? \";\"\n//      | \"if\" \"(\" expr \")\" stmt (\"else\" stmt)?\n//      | \"switch\" \"(\" expr \")\" stmt\n//      | \"case\" const-expr (\"...\" const-expr)? \":\" stmt\n//      | \"default\" \":\" stmt\n//      | \"for\" \"(\" expr-stmt expr? \";\" expr? \")\" stmt\n//      | \"while\" \"(\" expr \")\" stmt\n//      | \"do\" stmt \"while\" \"(\" expr \")\" \";\"\n//      | \"asm\" asm-stmt\n//      | \"goto\" (ident | \"*\" expr) \";\"\n//      | \"break\" \";\"\n//      | \"continue\" \";\"\n//      | ident \":\" stmt\n//      | \"{\" compound-stmt\n//      | expr-stmt\nstatic Node *stmt(Token **rest, Token *tok) {\n  if (equal(tok, \"return\")) {\n    Node *node = new_node(ND_RETURN, tok);\n    if (consume(rest, tok->next, \";\"))\n      return node;\n\n    Node *exp = expr(&tok, tok->next);\n    *rest = skip(tok, \";\");\n\n    add_type(exp);\n    Type *ty = current_fn->ty->return_ty;\n    if (ty->kind != TY_STRUCT && ty->kind != TY_UNION)\n      exp = new_cast(exp, current_fn->ty->return_ty);\n\n    node->lhs = exp;\n    return node;\n  }\n\n  if (equal(tok, \"if\")) {\n    Node *node = new_node(ND_IF, tok);\n    tok = skip(tok->next, \"(\");\n    node->cond = expr(&tok, tok);\n    tok = skip(tok, \")\");\n    node->then = stmt(&tok, tok);\n    if (equal(tok, \"else\"))\n      node->els = stmt(&tok, tok->next);\n    *rest = tok;\n    return node;\n  }\n\n  if (equal(tok, \"switch\")) {\n    Node *node = new_node(ND_SWITCH, tok);\n    tok = skip(tok->next, \"(\");\n    node->cond = expr(&tok, tok);\n    tok = skip(tok, \")\");\n\n    Node *sw = current_switch;\n    current_switch = node;\n\n    char *brk = brk_label;\n    brk_label = node->brk_label = new_unique_name();\n\n    node->then = stmt(rest, tok);\n\n    current_switch = sw;\n    brk_label = brk;\n    return node;\n  }\n\n  if (equal(tok, \"case\")) {\n    if (!current_switch)\n      error_tok(tok, \"stray case\");\n\n    Node *node = new_node(ND_CASE, tok);\n    int begin = const_expr(&tok, tok->next);\n    int end;\n\n    if (equal(tok, \"...\")) {\n      // [GNU] Case ranges, e.g. \"case 1 ... 5:\"\n      end = const_expr(&tok, tok->next);\n      if (end < begin)\n        error_tok(tok, \"empty case range specified\");\n    } else {\n      end = begin;\n    }\n\n    tok = skip(tok, \":\");\n    node->label = new_unique_name();\n    node->lhs = stmt(rest, tok);\n    node->begin = begin;\n    node->end = end;\n    node->case_next = current_switch->case_next;\n    current_switch->case_next = node;\n    return node;\n  }\n\n  if (equal(tok, \"default\")) {\n    if (!current_switch)\n      error_tok(tok, \"stray default\");\n\n    Node *node = new_node(ND_CASE, tok);\n    tok = skip(tok->next, \":\");\n    node->label = new_unique_name();\n    node->lhs = stmt(rest, tok);\n    current_switch->default_case = node;\n    return node;\n  }\n\n  if (equal(tok, \"for\")) {\n    Node *node = new_node(ND_FOR, tok);\n    tok = skip(tok->next, \"(\");\n\n    enter_scope();\n\n    char *brk = brk_label;\n    char *cont = cont_label;\n    brk_label = node->brk_label = new_unique_name();\n    cont_label = node->cont_label = new_unique_name();\n\n    if (is_typename(tok)) {\n      Type *basety = declspec(&tok, tok, NULL);\n      node->init = declaration(&tok, tok, basety, NULL);\n    } else {\n      node->init = expr_stmt(&tok, tok);\n    }\n\n    if (!equal(tok, \";\"))\n      node->cond = expr(&tok, tok);\n    tok = skip(tok, \";\");\n\n    if (!equal(tok, \")\"))\n      node->inc = expr(&tok, tok);\n    tok = skip(tok, \")\");\n\n    node->then = stmt(rest, tok);\n\n    leave_scope();\n    brk_label = brk;\n    cont_label = cont;\n    return node;\n  }\n\n  if (equal(tok, \"while\")) {\n    Node *node = new_node(ND_FOR, tok);\n    tok = skip(tok->next, \"(\");\n    node->cond = expr(&tok, tok);\n    tok = skip(tok, \")\");\n\n    char *brk = brk_label;\n    char *cont = cont_label;\n    brk_label = node->brk_label = new_unique_name();\n    cont_label = node->cont_label = new_unique_name();\n\n    node->then = stmt(rest, tok);\n\n    brk_label = brk;\n    cont_label = cont;\n    return node;\n  }\n\n  if (equal(tok, \"do\")) {\n    Node *node = new_node(ND_DO, tok);\n\n    char *brk = brk_label;\n    char *cont = cont_label;\n    brk_label = node->brk_label = new_unique_name();\n    cont_label = node->cont_label = new_unique_name();\n\n    node->then = stmt(&tok, tok->next);\n\n    brk_label = brk;\n    cont_label = cont;\n\n    tok = skip(tok, \"while\");\n    tok = skip(tok, \"(\");\n    node->cond = expr(&tok, tok);\n    tok = skip(tok, \")\");\n    *rest = skip(tok, \";\");\n    return node;\n  }\n\n  if (equal(tok, \"asm\"))\n    return asm_stmt(rest, tok);\n\n  if (equal(tok, \"goto\")) {\n    if (equal(tok->next, \"*\")) {\n      // [GNU] `goto *ptr` jumps to the address specified by `ptr`.\n      Node *node = new_node(ND_GOTO_EXPR, tok);\n      node->lhs = expr(&tok, tok->next->next);\n      *rest = skip(tok, \";\");\n      return node;\n    }\n\n    Node *node = new_node(ND_GOTO, tok);\n    node->label = get_ident(tok->next);\n    node->goto_next = gotos;\n    gotos = node;\n    *rest = skip(tok->next->next, \";\");\n    return node;\n  }\n\n  if (equal(tok, \"break\")) {\n    if (!brk_label)\n      error_tok(tok, \"stray break\");\n    Node *node = new_node(ND_GOTO, tok);\n    node->unique_label = brk_label;\n    *rest = skip(tok->next, \";\");\n    return node;\n  }\n\n  if (equal(tok, \"continue\")) {\n    if (!cont_label)\n      error_tok(tok, \"stray continue\");\n    Node *node = new_node(ND_GOTO, tok);\n    node->unique_label = cont_label;\n    *rest = skip(tok->next, \";\");\n    return node;\n  }\n\n  if (tok->kind == TK_IDENT && equal(tok->next, \":\")) {\n    Node *node = new_node(ND_LABEL, tok);\n    node->label = strndup(tok->loc, tok->len);\n    node->unique_label = new_unique_name();\n    node->lhs = stmt(rest, tok->next->next);\n    node->goto_next = labels;\n    labels = node;\n    return node;\n  }\n\n  if (equal(tok, \"{\"))\n    return compound_stmt(rest, tok->next);\n\n  return expr_stmt(rest, tok);\n}\n\n// compound-stmt = (typedef | declaration | stmt)* \"}\"\nstatic Node *compound_stmt(Token **rest, Token *tok) {\n  Node *node = new_node(ND_BLOCK, tok);\n  Node head = {};\n  Node *cur = &head;\n\n  enter_scope();\n\n  while (!equal(tok, \"}\")) {\n    if (is_typename(tok) && !equal(tok->next, \":\")) {\n      VarAttr attr = {};\n      Type *basety = declspec(&tok, tok, &attr);\n\n      if (attr.is_typedef) {\n        tok = parse_typedef(tok, basety);\n        continue;\n      }\n\n      if (is_function(tok)) {\n        tok = function(tok, basety, &attr);\n        continue;\n      }\n\n      if (attr.is_extern) {\n        tok = global_variable(tok, basety, &attr);\n        continue;\n      }\n\n      cur = cur->next = declaration(&tok, tok, basety, &attr);\n    } else {\n      cur = cur->next = stmt(&tok, tok);\n    }\n    add_type(cur);\n  }\n\n  leave_scope();\n\n  node->body = head.next;\n  *rest = tok->next;\n  return node;\n}\n\n// expr-stmt = expr? \";\"\nstatic Node *expr_stmt(Token **rest, Token *tok) {\n  if (equal(tok, \";\")) {\n    *rest = tok->next;\n    return new_node(ND_BLOCK, tok);\n  }\n\n  Node *node = new_node(ND_EXPR_STMT, tok);\n  node->lhs = expr(&tok, tok);\n  *rest = skip(tok, \";\");\n  return node;\n}\n\n// expr = assign (\",\" expr)?\nstatic Node *expr(Token **rest, Token *tok) {\n  Node *node = assign(&tok, tok);\n\n  if (equal(tok, \",\"))\n    return new_binary(ND_COMMA, node, expr(rest, tok->next), tok);\n\n  *rest = tok;\n  return node;\n}\n\nstatic int64_t eval(Node *node) {\n  return eval2(node, NULL);\n}\n\n// Evaluate a given node as a constant expression.\n//\n// A constant expression is either just a number or ptr+n where ptr\n// is a pointer to a global variable and n is a postiive/negative\n// number. The latter form is accepted only as an initialization\n// expression for a global variable.\nstatic int64_t eval2(Node *node, char ***label) {\n  add_type(node);\n\n  if (is_flonum(node->ty))\n    return eval_double(node);\n\n  switch (node->kind) {\n  case ND_ADD:\n    return eval2(node->lhs, label) + eval(node->rhs);\n  case ND_SUB:\n    return eval2(node->lhs, label) - eval(node->rhs);\n  case ND_MUL:\n    return eval(node->lhs) * eval(node->rhs);\n  case ND_DIV:\n    if (node->ty->is_unsigned)\n      return (uint64_t)eval(node->lhs) / eval(node->rhs);\n    return eval(node->lhs) / eval(node->rhs);\n  case ND_NEG:\n    return -eval(node->lhs);\n  case ND_MOD:\n    if (node->ty->is_unsigned)\n      return (uint64_t)eval(node->lhs) % eval(node->rhs);\n    return eval(node->lhs) % eval(node->rhs);\n  case ND_BITAND:\n    return eval(node->lhs) & eval(node->rhs);\n  case ND_BITOR:\n    return eval(node->lhs) | eval(node->rhs);\n  case ND_BITXOR:\n    return eval(node->lhs) ^ eval(node->rhs);\n  case ND_SHL:\n    return eval(node->lhs) << eval(node->rhs);\n  case ND_SHR:\n    if (node->ty->is_unsigned && node->ty->size == 8)\n      return (uint64_t)eval(node->lhs) >> eval(node->rhs);\n    return eval(node->lhs) >> eval(node->rhs);\n  case ND_EQ:\n    return eval(node->lhs) == eval(node->rhs);\n  case ND_NE:\n    return eval(node->lhs) != eval(node->rhs);\n  case ND_LT:\n    if (node->lhs->ty->is_unsigned)\n      return (uint64_t)eval(node->lhs) < eval(node->rhs);\n    return eval(node->lhs) < eval(node->rhs);\n  case ND_LE:\n    if (node->lhs->ty->is_unsigned)\n      return (uint64_t)eval(node->lhs) <= eval(node->rhs);\n    return eval(node->lhs) <= eval(node->rhs);\n  case ND_COND:\n    return eval(node->cond) ? eval2(node->then, label) : eval2(node->els, label);\n  case ND_COMMA:\n    return eval2(node->rhs, label);\n  case ND_NOT:\n    return !eval(node->lhs);\n  case ND_BITNOT:\n    return ~eval(node->lhs);\n  case ND_LOGAND:\n    return eval(node->lhs) && eval(node->rhs);\n  case ND_LOGOR:\n    return eval(node->lhs) || eval(node->rhs);\n  case ND_CAST: {\n    int64_t val = eval2(node->lhs, label);\n    if (is_integer(node->ty)) {\n      switch (node->ty->size) {\n      case 1: return node->ty->is_unsigned ? (uint8_t)val : (int8_t)val;\n      case 2: return node->ty->is_unsigned ? (uint16_t)val : (int16_t)val;\n      case 4: return node->ty->is_unsigned ? (uint32_t)val : (int32_t)val;\n      }\n    }\n    return val;\n  }\n  case ND_ADDR:\n    return eval_rval(node->lhs, label);\n  case ND_LABEL_VAL:\n    *label = &node->unique_label;\n    return 0;\n  case ND_MEMBER:\n    if (!label)\n      error_tok(node->tok, \"not a compile-time constant\");\n    if (node->ty->kind != TY_ARRAY)\n      error_tok(node->tok, \"invalid initializer\");\n    return eval_rval(node->lhs, label) + node->member->offset;\n  case ND_VAR:\n    if (!label)\n      error_tok(node->tok, \"not a compile-time constant\");\n    if (node->var->ty->kind != TY_ARRAY && node->var->ty->kind != TY_FUNC)\n      error_tok(node->tok, \"invalid initializer\");\n    *label = &node->var->name;\n    return 0;\n  case ND_NUM:\n    return node->val;\n  }\n\n  error_tok(node->tok, \"not a compile-time constant\");\n}\n\nstatic int64_t eval_rval(Node *node, char ***label) {\n  switch (node->kind) {\n  case ND_VAR:\n    if (node->var->is_local)\n      error_tok(node->tok, \"not a compile-time constant\");\n    *label = &node->var->name;\n    return 0;\n  case ND_DEREF:\n    return eval2(node->lhs, label);\n  case ND_MEMBER:\n    return eval_rval(node->lhs, label) + node->member->offset;\n  }\n\n  error_tok(node->tok, \"invalid initializer\");\n}\n\nstatic bool is_const_expr(Node *node) {\n  add_type(node);\n\n  switch (node->kind) {\n  case ND_ADD:\n  case ND_SUB:\n  case ND_MUL:\n  case ND_DIV:\n  case ND_BITAND:\n  case ND_BITOR:\n  case ND_BITXOR:\n  case ND_SHL:\n  case ND_SHR:\n  case ND_EQ:\n  case ND_NE:\n  case ND_LT:\n  case ND_LE:\n  case ND_LOGAND:\n  case ND_LOGOR:\n    return is_const_expr(node->lhs) && is_const_expr(node->rhs);\n  case ND_COND:\n    if (!is_const_expr(node->cond))\n      return false;\n    return is_const_expr(eval(node->cond) ? node->then : node->els);\n  case ND_COMMA:\n    return is_const_expr(node->rhs);\n  case ND_NEG:\n  case ND_NOT:\n  case ND_BITNOT:\n  case ND_CAST:\n    return is_const_expr(node->lhs);\n  case ND_NUM:\n    return true;\n  }\n\n  return false;\n}\n\nint64_t const_expr(Token **rest, Token *tok) {\n  Node *node = conditional(rest, tok);\n  return eval(node);\n}\n\nstatic double eval_double(Node *node) {\n  add_type(node);\n\n  if (is_integer(node->ty)) {\n    if (node->ty->is_unsigned)\n      return (unsigned long)eval(node);\n    return eval(node);\n  }\n\n  switch (node->kind) {\n  case ND_ADD:\n    return eval_double(node->lhs) + eval_double(node->rhs);\n  case ND_SUB:\n    return eval_double(node->lhs) - eval_double(node->rhs);\n  case ND_MUL:\n    return eval_double(node->lhs) * eval_double(node->rhs);\n  case ND_DIV:\n    return eval_double(node->lhs) / eval_double(node->rhs);\n  case ND_NEG:\n    return -eval_double(node->lhs);\n  case ND_COND:\n    return eval_double(node->cond) ? eval_double(node->then) : eval_double(node->els);\n  case ND_COMMA:\n    return eval_double(node->rhs);\n  case ND_CAST:\n    if (is_flonum(node->lhs->ty))\n      return eval_double(node->lhs);\n    return eval(node->lhs);\n  case ND_NUM:\n    return node->fval;\n  }\n\n  error_tok(node->tok, \"not a compile-time constant\");\n}\n\n// Convert op= operators to expressions containing an assignment.\n//\n// In general, `A op= C` is converted to ``tmp = &A, *tmp = *tmp op B`.\n// However, if a given expression is of form `A.x op= C`, the input is\n// converted to `tmp = &A, (*tmp).x = (*tmp).x op C` to handle assignments\n// to bitfields.\nstatic Node *to_assign(Node *binary) {\n  add_type(binary->lhs);\n  add_type(binary->rhs);\n  Token *tok = binary->tok;\n\n  // Convert `A.x op= C` to `tmp = &A, (*tmp).x = (*tmp).x op C`.\n  if (binary->lhs->kind == ND_MEMBER) {\n    Obj *var = new_lvar(\"\", pointer_to(binary->lhs->lhs->ty));\n\n    Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok),\n                             new_unary(ND_ADDR, binary->lhs->lhs, tok), tok);\n\n    Node *expr2 = new_unary(ND_MEMBER,\n                            new_unary(ND_DEREF, new_var_node(var, tok), tok),\n                            tok);\n    expr2->member = binary->lhs->member;\n\n    Node *expr3 = new_unary(ND_MEMBER,\n                            new_unary(ND_DEREF, new_var_node(var, tok), tok),\n                            tok);\n    expr3->member = binary->lhs->member;\n\n    Node *expr4 = new_binary(ND_ASSIGN, expr2,\n                             new_binary(binary->kind, expr3, binary->rhs, tok),\n                             tok);\n\n    return new_binary(ND_COMMA, expr1, expr4, tok);\n  }\n\n  // If A is an atomic type, Convert `A op= B` to\n  //\n  // ({\n  //   T1 *addr = &A; T2 val = (B); T1 old = *addr; T1 new;\n  //   do {\n  //    new = old op val;\n  //   } while (!atomic_compare_exchange_strong(addr, &old, new));\n  //   new;\n  // })\n  if (binary->lhs->ty->is_atomic) {\n    Node head = {};\n    Node *cur = &head;\n\n    Obj *addr = new_lvar(\"\", pointer_to(binary->lhs->ty));\n    Obj *val = new_lvar(\"\", binary->rhs->ty);\n    Obj *old = new_lvar(\"\", binary->lhs->ty);\n    Obj *new = new_lvar(\"\", binary->lhs->ty);\n\n    cur = cur->next =\n      new_unary(ND_EXPR_STMT,\n                new_binary(ND_ASSIGN, new_var_node(addr, tok),\n                           new_unary(ND_ADDR, binary->lhs, tok), tok),\n                tok);\n\n    cur = cur->next =\n      new_unary(ND_EXPR_STMT,\n                new_binary(ND_ASSIGN, new_var_node(val, tok), binary->rhs, tok),\n                tok);\n\n    cur = cur->next =\n      new_unary(ND_EXPR_STMT,\n                new_binary(ND_ASSIGN, new_var_node(old, tok),\n                           new_unary(ND_DEREF, new_var_node(addr, tok), tok), tok),\n                tok);\n\n    Node *loop = new_node(ND_DO, tok);\n    loop->brk_label = new_unique_name();\n    loop->cont_label = new_unique_name();\n\n    Node *body = new_binary(ND_ASSIGN,\n                            new_var_node(new, tok),\n                            new_binary(binary->kind, new_var_node(old, tok),\n                                       new_var_node(val, tok), tok),\n                            tok);\n\n    loop->then = new_node(ND_BLOCK, tok);\n    loop->then->body = new_unary(ND_EXPR_STMT, body, tok);\n\n    Node *cas = new_node(ND_CAS, tok);\n    cas->cas_addr = new_var_node(addr, tok);\n    cas->cas_old = new_unary(ND_ADDR, new_var_node(old, tok), tok);\n    cas->cas_new = new_var_node(new, tok);\n    loop->cond = new_unary(ND_NOT, cas, tok);\n\n    cur = cur->next = loop;\n    cur = cur->next = new_unary(ND_EXPR_STMT, new_var_node(new, tok), tok);\n\n    Node *node = new_node(ND_STMT_EXPR, tok);\n    node->body = head.next;\n    return node;\n  }\n\n  // Convert `A op= B` to ``tmp = &A, *tmp = *tmp op B`.\n  Obj *var = new_lvar(\"\", pointer_to(binary->lhs->ty));\n\n  Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok),\n                           new_unary(ND_ADDR, binary->lhs, tok), tok);\n\n  Node *expr2 =\n    new_binary(ND_ASSIGN,\n               new_unary(ND_DEREF, new_var_node(var, tok), tok),\n               new_binary(binary->kind,\n                          new_unary(ND_DEREF, new_var_node(var, tok), tok),\n                          binary->rhs,\n                          tok),\n               tok);\n\n  return new_binary(ND_COMMA, expr1, expr2, tok);\n}\n\n// assign    = conditional (assign-op assign)?\n// assign-op = \"=\" | \"+=\" | \"-=\" | \"*=\" | \"/=\" | \"%=\" | \"&=\" | \"|=\" | \"^=\"\n//           | \"<<=\" | \">>=\"\nstatic Node *assign(Token **rest, Token *tok) {\n  Node *node = conditional(&tok, tok);\n\n  if (equal(tok, \"=\"))\n    return new_binary(ND_ASSIGN, node, assign(rest, tok->next), tok);\n\n  if (equal(tok, \"+=\"))\n    return to_assign(new_add(node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"-=\"))\n    return to_assign(new_sub(node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"*=\"))\n    return to_assign(new_binary(ND_MUL, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"/=\"))\n    return to_assign(new_binary(ND_DIV, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"%=\"))\n    return to_assign(new_binary(ND_MOD, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"&=\"))\n    return to_assign(new_binary(ND_BITAND, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"|=\"))\n    return to_assign(new_binary(ND_BITOR, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"^=\"))\n    return to_assign(new_binary(ND_BITXOR, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \"<<=\"))\n    return to_assign(new_binary(ND_SHL, node, assign(rest, tok->next), tok));\n\n  if (equal(tok, \">>=\"))\n    return to_assign(new_binary(ND_SHR, node, assign(rest, tok->next), tok));\n\n  *rest = tok;\n  return node;\n}\n\n// conditional = logor (\"?\" expr? \":\" conditional)?\nstatic Node *conditional(Token **rest, Token *tok) {\n  Node *cond = logor(&tok, tok);\n\n  if (!equal(tok, \"?\")) {\n    *rest = tok;\n    return cond;\n  }\n\n  if (equal(tok->next, \":\")) {\n    // [GNU] Compile `a ?: b` as `tmp = a, tmp ? tmp : b`.\n    add_type(cond);\n    Obj *var = new_lvar(\"\", cond->ty);\n    Node *lhs = new_binary(ND_ASSIGN, new_var_node(var, tok), cond, tok);\n    Node *rhs = new_node(ND_COND, tok);\n    rhs->cond = new_var_node(var, tok);\n    rhs->then = new_var_node(var, tok);\n    rhs->els = conditional(rest, tok->next->next);\n    return new_binary(ND_COMMA, lhs, rhs, tok);\n  }\n\n  Node *node = new_node(ND_COND, tok);\n  node->cond = cond;\n  node->then = expr(&tok, tok->next);\n  tok = skip(tok, \":\");\n  node->els = conditional(rest, tok);\n  return node;\n}\n\n// logor = logand (\"||\" logand)*\nstatic Node *logor(Token **rest, Token *tok) {\n  Node *node = logand(&tok, tok);\n  while (equal(tok, \"||\")) {\n    Token *start = tok;\n    node = new_binary(ND_LOGOR, node, logand(&tok, tok->next), start);\n  }\n  *rest = tok;\n  return node;\n}\n\n// logand = bitor (\"&&\" bitor)*\nstatic Node *logand(Token **rest, Token *tok) {\n  Node *node = bitor(&tok, tok);\n  while (equal(tok, \"&&\")) {\n    Token *start = tok;\n    node = new_binary(ND_LOGAND, node, bitor(&tok, tok->next), start);\n  }\n  *rest = tok;\n  return node;\n}\n\n// bitor = bitxor (\"|\" bitxor)*\nstatic Node *bitor(Token **rest, Token *tok) {\n  Node *node = bitxor(&tok, tok);\n  while (equal(tok, \"|\")) {\n    Token *start = tok;\n    node = new_binary(ND_BITOR, node, bitxor(&tok, tok->next), start);\n  }\n  *rest = tok;\n  return node;\n}\n\n// bitxor = bitand (\"^\" bitand)*\nstatic Node *bitxor(Token **rest, Token *tok) {\n  Node *node = bitand(&tok, tok);\n  while (equal(tok, \"^\")) {\n    Token *start = tok;\n    node = new_binary(ND_BITXOR, node, bitand(&tok, tok->next), start);\n  }\n  *rest = tok;\n  return node;\n}\n\n// bitand = equality (\"&\" equality)*\nstatic Node *bitand(Token **rest, Token *tok) {\n  Node *node = equality(&tok, tok);\n  while (equal(tok, \"&\")) {\n    Token *start = tok;\n    node = new_binary(ND_BITAND, node, equality(&tok, tok->next), start);\n  }\n  *rest = tok;\n  return node;\n}\n\n// equality = relational (\"==\" relational | \"!=\" relational)*\nstatic Node *equality(Token **rest, Token *tok) {\n  Node *node = relational(&tok, tok);\n\n  for (;;) {\n    Token *start = tok;\n\n    if (equal(tok, \"==\")) {\n      node = new_binary(ND_EQ, node, relational(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \"!=\")) {\n      node = new_binary(ND_NE, node, relational(&tok, tok->next), start);\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// relational = shift (\"<\" shift | \"<=\" shift | \">\" shift | \">=\" shift)*\nstatic Node *relational(Token **rest, Token *tok) {\n  Node *node = shift(&tok, tok);\n\n  for (;;) {\n    Token *start = tok;\n\n    if (equal(tok, \"<\")) {\n      node = new_binary(ND_LT, node, shift(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \"<=\")) {\n      node = new_binary(ND_LE, node, shift(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \">\")) {\n      node = new_binary(ND_LT, shift(&tok, tok->next), node, start);\n      continue;\n    }\n\n    if (equal(tok, \">=\")) {\n      node = new_binary(ND_LE, shift(&tok, tok->next), node, start);\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// shift = add (\"<<\" add | \">>\" add)*\nstatic Node *shift(Token **rest, Token *tok) {\n  Node *node = add(&tok, tok);\n\n  for (;;) {\n    Token *start = tok;\n\n    if (equal(tok, \"<<\")) {\n      node = new_binary(ND_SHL, node, add(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \">>\")) {\n      node = new_binary(ND_SHR, node, add(&tok, tok->next), start);\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// In C, `+` operator is overloaded to perform the pointer arithmetic.\n// If p is a pointer, p+n adds not n but sizeof(*p)*n to the value of p,\n// so that p+n points to the location n elements (not bytes) ahead of p.\n// In other words, we need to scale an integer value before adding to a\n// pointer value. This function takes care of the scaling.\nstatic Node *new_add(Node *lhs, Node *rhs, Token *tok) {\n  add_type(lhs);\n  add_type(rhs);\n\n  // num + num\n  if (is_numeric(lhs->ty) && is_numeric(rhs->ty))\n    return new_binary(ND_ADD, lhs, rhs, tok);\n\n  if (lhs->ty->base && rhs->ty->base)\n    error_tok(tok, \"invalid operands\");\n\n  // Canonicalize `num + ptr` to `ptr + num`.\n  if (!lhs->ty->base && rhs->ty->base) {\n    Node *tmp = lhs;\n    lhs = rhs;\n    rhs = tmp;\n  }\n\n  // VLA + num\n  if (lhs->ty->base->kind == TY_VLA) {\n    rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok);\n    return new_binary(ND_ADD, lhs, rhs, tok);\n  }\n\n  // ptr + num\n  rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok);\n  return new_binary(ND_ADD, lhs, rhs, tok);\n}\n\n// Like `+`, `-` is overloaded for the pointer type.\nstatic Node *new_sub(Node *lhs, Node *rhs, Token *tok) {\n  add_type(lhs);\n  add_type(rhs);\n\n  // num - num\n  if (is_numeric(lhs->ty) && is_numeric(rhs->ty))\n    return new_binary(ND_SUB, lhs, rhs, tok);\n\n  // VLA + num\n  if (lhs->ty->base->kind == TY_VLA) {\n    rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok);\n    add_type(rhs);\n    Node *node = new_binary(ND_SUB, lhs, rhs, tok);\n    node->ty = lhs->ty;\n    return node;\n  }\n\n  // ptr - num\n  if (lhs->ty->base && is_integer(rhs->ty)) {\n    rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok);\n    add_type(rhs);\n    Node *node = new_binary(ND_SUB, lhs, rhs, tok);\n    node->ty = lhs->ty;\n    return node;\n  }\n\n  // ptr - ptr, which returns how many elements are between the two.\n  if (lhs->ty->base && rhs->ty->base) {\n    Node *node = new_binary(ND_SUB, lhs, rhs, tok);\n    node->ty = ty_long;\n    return new_binary(ND_DIV, node, new_num(lhs->ty->base->size, tok), tok);\n  }\n\n  error_tok(tok, \"invalid operands\");\n}\n\n// add = mul (\"+\" mul | \"-\" mul)*\nstatic Node *add(Token **rest, Token *tok) {\n  Node *node = mul(&tok, tok);\n\n  for (;;) {\n    Token *start = tok;\n\n    if (equal(tok, \"+\")) {\n      node = new_add(node, mul(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \"-\")) {\n      node = new_sub(node, mul(&tok, tok->next), start);\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// mul = cast (\"*\" cast | \"/\" cast | \"%\" cast)*\nstatic Node *mul(Token **rest, Token *tok) {\n  Node *node = cast(&tok, tok);\n\n  for (;;) {\n    Token *start = tok;\n\n    if (equal(tok, \"*\")) {\n      node = new_binary(ND_MUL, node, cast(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \"/\")) {\n      node = new_binary(ND_DIV, node, cast(&tok, tok->next), start);\n      continue;\n    }\n\n    if (equal(tok, \"%\")) {\n      node = new_binary(ND_MOD, node, cast(&tok, tok->next), start);\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// cast = \"(\" type-name \")\" cast | unary\nstatic Node *cast(Token **rest, Token *tok) {\n  if (equal(tok, \"(\") && is_typename(tok->next)) {\n    Token *start = tok;\n    Type *ty = typename(&tok, tok->next);\n    tok = skip(tok, \")\");\n\n    // compound literal\n    if (equal(tok, \"{\"))\n      return unary(rest, start);\n\n    // type cast\n    Node *node = new_cast(cast(rest, tok), ty);\n    node->tok = start;\n    return node;\n  }\n\n  return unary(rest, tok);\n}\n\n// unary = (\"+\" | \"-\" | \"*\" | \"&\" | \"!\" | \"~\") cast\n//       | (\"++\" | \"--\") unary\n//       | \"&&\" ident\n//       | postfix\nstatic Node *unary(Token **rest, Token *tok) {\n  if (equal(tok, \"+\"))\n    return cast(rest, tok->next);\n\n  if (equal(tok, \"-\"))\n    return new_unary(ND_NEG, cast(rest, tok->next), tok);\n\n  if (equal(tok, \"&\")) {\n    Node *lhs = cast(rest, tok->next);\n    add_type(lhs);\n    if (lhs->kind == ND_MEMBER && lhs->member->is_bitfield)\n      error_tok(tok, \"cannot take address of bitfield\");\n    return new_unary(ND_ADDR, lhs, tok);\n  }\n\n  if (equal(tok, \"*\")) {\n    // [https://www.sigbus.info/n1570#6.5.3.2p4] This is an oddity\n    // in the C spec, but dereferencing a function shouldn't do\n    // anything. If foo is a function, `*foo`, `**foo` or `*****foo`\n    // are all equivalent to just `foo`.\n    Node *node = cast(rest, tok->next);\n    add_type(node);\n    if (node->ty->kind == TY_FUNC)\n      return node;\n    return new_unary(ND_DEREF, node, tok);\n  }\n\n  if (equal(tok, \"!\"))\n    return new_unary(ND_NOT, cast(rest, tok->next), tok);\n\n  if (equal(tok, \"~\"))\n    return new_unary(ND_BITNOT, cast(rest, tok->next), tok);\n\n  // Read ++i as i+=1\n  if (equal(tok, \"++\"))\n    return to_assign(new_add(unary(rest, tok->next), new_num(1, tok), tok));\n\n  // Read --i as i-=1\n  if (equal(tok, \"--\"))\n    return to_assign(new_sub(unary(rest, tok->next), new_num(1, tok), tok));\n\n  // [GNU] labels-as-values\n  if (equal(tok, \"&&\")) {\n    Node *node = new_node(ND_LABEL_VAL, tok);\n    node->label = get_ident(tok->next);\n    node->goto_next = gotos;\n    gotos = node;\n    *rest = tok->next->next;\n    return node;\n  }\n\n  return postfix(rest, tok);\n}\n\n// struct-members = (declspec declarator (\",\"  declarator)* \";\")*\nstatic void struct_members(Token **rest, Token *tok, Type *ty) {\n  Member head = {};\n  Member *cur = &head;\n  int idx = 0;\n\n  while (!equal(tok, \"}\")) {\n    VarAttr attr = {};\n    Type *basety = declspec(&tok, tok, &attr);\n    bool first = true;\n\n    // Anonymous struct member\n    if ((basety->kind == TY_STRUCT || basety->kind == TY_UNION) &&\n        consume(&tok, tok, \";\")) {\n      Member *mem = calloc(1, sizeof(Member));\n      mem->ty = basety;\n      mem->idx = idx++;\n      mem->align = attr.align ? attr.align : mem->ty->align;\n      cur = cur->next = mem;\n      continue;\n    }\n\n    // Regular struct members\n    while (!consume(&tok, tok, \";\")) {\n      if (!first)\n        tok = skip(tok, \",\");\n      first = false;\n\n      Member *mem = calloc(1, sizeof(Member));\n      mem->ty = declarator(&tok, tok, basety);\n      mem->name = mem->ty->name;\n      mem->idx = idx++;\n      mem->align = attr.align ? attr.align : mem->ty->align;\n\n      if (consume(&tok, tok, \":\")) {\n        mem->is_bitfield = true;\n        mem->bit_width = const_expr(&tok, tok);\n      }\n\n      cur = cur->next = mem;\n    }\n  }\n\n  // If the last element is an array of incomplete type, it's\n  // called a \"flexible array member\". It should behave as if\n  // if were a zero-sized array.\n  if (cur != &head && cur->ty->kind == TY_ARRAY && cur->ty->array_len < 0) {\n    cur->ty = array_of(cur->ty->base, 0);\n    ty->is_flexible = true;\n  }\n\n  *rest = tok->next;\n  ty->members = head.next;\n}\n\n// attribute = (\"__attribute__\" \"(\" \"(\" \"packed\" \")\" \")\")*\nstatic Token *attribute_list(Token *tok, Type *ty) {\n  while (consume(&tok, tok, \"__attribute__\")) {\n    tok = skip(tok, \"(\");\n    tok = skip(tok, \"(\");\n\n    bool first = true;\n\n    while (!consume(&tok, tok, \")\")) {\n      if (!first)\n        tok = skip(tok, \",\");\n      first = false;\n\n      if (consume(&tok, tok, \"packed\")) {\n        ty->is_packed = true;\n        continue;\n      }\n\n      if (consume(&tok, tok, \"aligned\")) {\n        tok = skip(tok, \"(\");\n        ty->align = const_expr(&tok, tok);\n        tok = skip(tok, \")\");\n        continue;\n      }\n\n      error_tok(tok, \"unknown attribute\");\n    }\n\n    tok = skip(tok, \")\");\n  }\n\n  return tok;\n}\n\n// struct-union-decl = attribute? ident? (\"{\" struct-members)?\nstatic Type *struct_union_decl(Token **rest, Token *tok) {\n  Type *ty = struct_type();\n  tok = attribute_list(tok, ty);\n\n  // Read a tag.\n  Token *tag = NULL;\n  if (tok->kind == TK_IDENT) {\n    tag = tok;\n    tok = tok->next;\n  }\n\n  if (tag && !equal(tok, \"{\")) {\n    *rest = tok;\n\n    Type *ty2 = find_tag(tag);\n    if (ty2)\n      return ty2;\n\n    ty->size = -1;\n    push_tag_scope(tag, ty);\n    return ty;\n  }\n\n  tok = skip(tok, \"{\");\n\n  // Construct a struct object.\n  struct_members(&tok, tok, ty);\n  *rest = attribute_list(tok, ty);\n\n  if (tag) {\n    // If this is a redefinition, overwrite a previous type.\n    // Otherwise, register the struct type.\n    Type *ty2 = hashmap_get2(&scope->tags, tag->loc, tag->len);\n    if (ty2) {\n      *ty2 = *ty;\n      return ty2;\n    }\n\n    push_tag_scope(tag, ty);\n  }\n\n  return ty;\n}\n\n// struct-decl = struct-union-decl\nstatic Type *struct_decl(Token **rest, Token *tok) {\n  Type *ty = struct_union_decl(rest, tok);\n  ty->kind = TY_STRUCT;\n\n  if (ty->size < 0)\n    return ty;\n\n  // Assign offsets within the struct to members.\n  int bits = 0;\n\n  for (Member *mem = ty->members; mem; mem = mem->next) {\n    if (mem->is_bitfield && mem->bit_width == 0) {\n      // Zero-width anonymous bitfield has a special meaning.\n      // It affects only alignment.\n      bits = align_to(bits, mem->ty->size * 8);\n    } else if (mem->is_bitfield) {\n      int sz = mem->ty->size;\n      if (bits / (sz * 8) != (bits + mem->bit_width - 1) / (sz * 8))\n        bits = align_to(bits, sz * 8);\n\n      mem->offset = align_down(bits / 8, sz);\n      mem->bit_offset = bits % (sz * 8);\n      bits += mem->bit_width;\n    } else {\n      if (!ty->is_packed)\n        bits = align_to(bits, mem->align * 8);\n      mem->offset = bits / 8;\n      bits += mem->ty->size * 8;\n    }\n\n    if (!ty->is_packed && ty->align < mem->align)\n      ty->align = mem->align;\n  }\n\n  ty->size = align_to(bits, ty->align * 8) / 8;\n  return ty;\n}\n\n// union-decl = struct-union-decl\nstatic Type *union_decl(Token **rest, Token *tok) {\n  Type *ty = struct_union_decl(rest, tok);\n  ty->kind = TY_UNION;\n\n  if (ty->size < 0)\n    return ty;\n\n  // If union, we don't have to assign offsets because they\n  // are already initialized to zero. We need to compute the\n  // alignment and the size though.\n  for (Member *mem = ty->members; mem; mem = mem->next) {\n    if (ty->align < mem->align)\n      ty->align = mem->align;\n    if (ty->size < mem->ty->size)\n      ty->size = mem->ty->size;\n  }\n  ty->size = align_to(ty->size, ty->align);\n  return ty;\n}\n\n// Find a struct member by name.\nstatic Member *get_struct_member(Type *ty, Token *tok) {\n  for (Member *mem = ty->members; mem; mem = mem->next) {\n    // Anonymous struct member\n    if ((mem->ty->kind == TY_STRUCT || mem->ty->kind == TY_UNION) &&\n        !mem->name) {\n      if (get_struct_member(mem->ty, tok))\n        return mem;\n      continue;\n    }\n\n    // Regular struct member\n    if (mem->name->len == tok->len &&\n        !strncmp(mem->name->loc, tok->loc, tok->len))\n      return mem;\n  }\n  return NULL;\n}\n\n// Create a node representing a struct member access, such as foo.bar\n// where foo is a struct and bar is a member name.\n//\n// C has a feature called \"anonymous struct\" which allows a struct to\n// have another unnamed struct as a member like this:\n//\n//   struct { struct { int a; }; int b; } x;\n//\n// The members of an anonymous struct belong to the outer struct's\n// member namespace. Therefore, in the above example, you can access\n// member \"a\" of the anonymous struct as \"x.a\".\n//\n// This function takes care of anonymous structs.\nstatic Node *struct_ref(Node *node, Token *tok) {\n  add_type(node);\n  if (node->ty->kind != TY_STRUCT && node->ty->kind != TY_UNION)\n    error_tok(node->tok, \"not a struct nor a union\");\n\n  Type *ty = node->ty;\n\n  for (;;) {\n    Member *mem = get_struct_member(ty, tok);\n    if (!mem)\n      error_tok(tok, \"no such member\");\n    node = new_unary(ND_MEMBER, node, tok);\n    node->member = mem;\n    if (mem->name)\n      break;\n    ty = mem->ty;\n  }\n  return node;\n}\n\n// Convert A++ to `(typeof A)((A += 1) - 1)`\nstatic Node *new_inc_dec(Node *node, Token *tok, int addend) {\n  add_type(node);\n  return new_cast(new_add(to_assign(new_add(node, new_num(addend, tok), tok)),\n                          new_num(-addend, tok), tok),\n                  node->ty);\n}\n\n// postfix = \"(\" type-name \")\" \"{\" initializer-list \"}\"\n//         = ident \"(\" func-args \")\" postfix-tail*\n//         | primary postfix-tail*\n//\n// postfix-tail = \"[\" expr \"]\"\n//              | \"(\" func-args \")\"\n//              | \".\" ident\n//              | \"->\" ident\n//              | \"++\"\n//              | \"--\"\nstatic Node *postfix(Token **rest, Token *tok) {\n  if (equal(tok, \"(\") && is_typename(tok->next)) {\n    // Compound literal\n    Token *start = tok;\n    Type *ty = typename(&tok, tok->next);\n    tok = skip(tok, \")\");\n\n    if (scope->next == NULL) {\n      Obj *var = new_anon_gvar(ty);\n      gvar_initializer(rest, tok, var);\n      return new_var_node(var, start);\n    }\n\n    Obj *var = new_lvar(\"\", ty);\n    Node *lhs = lvar_initializer(rest, tok, var);\n    Node *rhs = new_var_node(var, tok);\n    return new_binary(ND_COMMA, lhs, rhs, start);\n  }\n\n  Node *node = primary(&tok, tok);\n\n  for (;;) {\n    if (equal(tok, \"(\")) {\n      node = funcall(&tok, tok->next, node);\n      continue;\n    }\n\n    if (equal(tok, \"[\")) {\n      // x[y] is short for *(x+y)\n      Token *start = tok;\n      Node *idx = expr(&tok, tok->next);\n      tok = skip(tok, \"]\");\n      node = new_unary(ND_DEREF, new_add(node, idx, start), start);\n      continue;\n    }\n\n    if (equal(tok, \".\")) {\n      node = struct_ref(node, tok->next);\n      tok = tok->next->next;\n      continue;\n    }\n\n    if (equal(tok, \"->\")) {\n      // x->y is short for (*x).y\n      node = new_unary(ND_DEREF, node, tok);\n      node = struct_ref(node, tok->next);\n      tok = tok->next->next;\n      continue;\n    }\n\n    if (equal(tok, \"++\")) {\n      node = new_inc_dec(node, tok, 1);\n      tok = tok->next;\n      continue;\n    }\n\n    if (equal(tok, \"--\")) {\n      node = new_inc_dec(node, tok, -1);\n      tok = tok->next;\n      continue;\n    }\n\n    *rest = tok;\n    return node;\n  }\n}\n\n// funcall = (assign (\",\" assign)*)? \")\"\nstatic Node *funcall(Token **rest, Token *tok, Node *fn) {\n  add_type(fn);\n\n  if (fn->ty->kind != TY_FUNC &&\n      (fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC))\n    error_tok(fn->tok, \"not a function\");\n\n  Type *ty = (fn->ty->kind == TY_FUNC) ? fn->ty : fn->ty->base;\n  Type *param_ty = ty->params;\n\n  Node head = {};\n  Node *cur = &head;\n\n  while (!equal(tok, \")\")) {\n    if (cur != &head)\n      tok = skip(tok, \",\");\n\n    Node *arg = assign(&tok, tok);\n    add_type(arg);\n\n    if (!param_ty && !ty->is_variadic)\n      error_tok(tok, \"too many arguments\");\n\n    if (param_ty) {\n      if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION)\n        arg = new_cast(arg, param_ty);\n      param_ty = param_ty->next;\n    } else if (arg->ty->kind == TY_FLOAT) {\n      // If parameter type is omitted (e.g. in \"...\"), float\n      // arguments are promoted to double.\n      arg = new_cast(arg, ty_double);\n    }\n\n    cur = cur->next = arg;\n  }\n\n  if (param_ty)\n    error_tok(tok, \"too few arguments\");\n\n  *rest = skip(tok, \")\");\n\n  Node *node = new_unary(ND_FUNCALL, fn, tok);\n  node->func_ty = ty;\n  node->ty = ty->return_ty;\n  node->args = head.next;\n\n  // If a function returns a struct, it is caller's responsibility\n  // to allocate a space for the return value.\n  if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION)\n    node->ret_buffer = new_lvar(\"\", node->ty);\n  return node;\n}\n\n// generic-selection = \"(\" assign \",\" generic-assoc (\",\" generic-assoc)* \")\"\n//\n// generic-assoc = type-name \":\" assign\n//               | \"default\" \":\" assign\nstatic Node *generic_selection(Token **rest, Token *tok) {\n  Token *start = tok;\n  tok = skip(tok, \"(\");\n\n  Node *ctrl = assign(&tok, tok);\n  add_type(ctrl);\n\n  Type *t1 = ctrl->ty;\n  if (t1->kind == TY_FUNC)\n    t1 = pointer_to(t1);\n  else if (t1->kind == TY_ARRAY)\n    t1 = pointer_to(t1->base);\n\n  Node *ret = NULL;\n\n  while (!consume(rest, tok, \")\")) {\n    tok = skip(tok, \",\");\n\n    if (equal(tok, \"default\")) {\n      tok = skip(tok->next, \":\");\n      Node *node = assign(&tok, tok);\n      if (!ret)\n        ret = node;\n      continue;\n    }\n\n    Type *t2 = typename(&tok, tok);\n    tok = skip(tok, \":\");\n    Node *node = assign(&tok, tok);\n    if (is_compatible(t1, t2))\n      ret = node;\n  }\n\n  if (!ret)\n    error_tok(start, \"controlling expression type not compatible with\"\n              \" any generic association type\");\n  return ret;\n}\n\n// primary = \"(\" \"{\" stmt+ \"}\" \")\"\n//         | \"(\" expr \")\"\n//         | \"sizeof\" \"(\" type-name \")\"\n//         | \"sizeof\" unary\n//         | \"_Alignof\" \"(\" type-name \")\"\n//         | \"_Alignof\" unary\n//         | \"_Generic\" generic-selection\n//         | \"__builtin_types_compatible_p\" \"(\" type-name, type-name, \")\"\n//         | \"__builtin_reg_class\" \"(\" type-name \")\"\n//         | ident\n//         | str\n//         | num\nstatic Node *primary(Token **rest, Token *tok) {\n  Token *start = tok;\n\n  if (equal(tok, \"(\") && equal(tok->next, \"{\")) {\n    // This is a GNU statement expresssion.\n    Node *node = new_node(ND_STMT_EXPR, tok);\n    node->body = compound_stmt(&tok, tok->next->next)->body;\n    *rest = skip(tok, \")\");\n    return node;\n  }\n\n  if (equal(tok, \"(\")) {\n    Node *node = expr(&tok, tok->next);\n    *rest = skip(tok, \")\");\n    return node;\n  }\n\n  if (equal(tok, \"sizeof\") && equal(tok->next, \"(\") && is_typename(tok->next->next)) {\n    Type *ty = typename(&tok, tok->next->next);\n    *rest = skip(tok, \")\");\n\n    if (ty->kind == TY_VLA) {\n      if (ty->vla_size)\n        return new_var_node(ty->vla_size, tok);\n\n      Node *lhs = compute_vla_size(ty, tok);\n      Node *rhs = new_var_node(ty->vla_size, tok);\n      return new_binary(ND_COMMA, lhs, rhs, tok);\n    }\n\n    return new_ulong(ty->size, start);\n  }\n\n  if (equal(tok, \"sizeof\")) {\n    Node *node = unary(rest, tok->next);\n    add_type(node);\n    if (node->ty->kind == TY_VLA)\n      return new_var_node(node->ty->vla_size, tok);\n    return new_ulong(node->ty->size, tok);\n  }\n\n  if (equal(tok, \"_Alignof\") && equal(tok->next, \"(\") && is_typename(tok->next->next)) {\n    Type *ty = typename(&tok, tok->next->next);\n    *rest = skip(tok, \")\");\n    return new_ulong(ty->align, tok);\n  }\n\n  if (equal(tok, \"_Alignof\")) {\n    Node *node = unary(rest, tok->next);\n    add_type(node);\n    return new_ulong(node->ty->align, tok);\n  }\n\n  if (equal(tok, \"_Generic\"))\n    return generic_selection(rest, tok->next);\n\n  if (equal(tok, \"__builtin_types_compatible_p\")) {\n    tok = skip(tok->next, \"(\");\n    Type *t1 = typename(&tok, tok);\n    tok = skip(tok, \",\");\n    Type *t2 = typename(&tok, tok);\n    *rest = skip(tok, \")\");\n    return new_num(is_compatible(t1, t2), start);\n  }\n\n  if (equal(tok, \"__builtin_reg_class\")) {\n    tok = skip(tok->next, \"(\");\n    Type *ty = typename(&tok, tok);\n    *rest = skip(tok, \")\");\n\n    if (is_integer(ty) || ty->kind == TY_PTR)\n      return new_num(0, start);\n    if (is_flonum(ty))\n      return new_num(1, start);\n    return new_num(2, start);\n  }\n\n  if (equal(tok, \"__builtin_compare_and_swap\")) {\n    Node *node = new_node(ND_CAS, tok);\n    tok = skip(tok->next, \"(\");\n    node->cas_addr = assign(&tok, tok);\n    tok = skip(tok, \",\");\n    node->cas_old = assign(&tok, tok);\n    tok = skip(tok, \",\");\n    node->cas_new = assign(&tok, tok);\n    *rest = skip(tok, \")\");\n    return node;\n  }\n\n  if (equal(tok, \"__builtin_atomic_exchange\")) {\n    Node *node = new_node(ND_EXCH, tok);\n    tok = skip(tok->next, \"(\");\n    node->lhs = assign(&tok, tok);\n    tok = skip(tok, \",\");\n    node->rhs = assign(&tok, tok);\n    *rest = skip(tok, \")\");\n    return node;\n  }\n\n  if (tok->kind == TK_IDENT) {\n    // Variable or enum constant\n    VarScope *sc = find_var(tok);\n    *rest = tok->next;\n\n    // For \"static inline\" function\n    if (sc && sc->var && sc->var->is_function) {\n      if (current_fn)\n        strarray_push(&current_fn->refs, sc->var->name);\n      else\n        sc->var->is_root = true;\n    }\n\n    if (sc) {\n      if (sc->var)\n        return new_var_node(sc->var, tok);\n      if (sc->enum_ty)\n        return new_num(sc->enum_val, tok);\n    }\n\n    if (equal(tok->next, \"(\"))\n      error_tok(tok, \"implicit declaration of a function\");\n    error_tok(tok, \"undefined variable\");\n  }\n\n  if (tok->kind == TK_STR) {\n    Obj *var = new_string_literal(tok->str, tok->ty);\n    *rest = tok->next;\n    return new_var_node(var, tok);\n  }\n\n  if (tok->kind == TK_NUM) {\n    Node *node;\n    if (is_flonum(tok->ty)) {\n      node = new_node(ND_NUM, tok);\n      node->fval = tok->fval;\n    } else {\n      node = new_num(tok->val, tok);\n    }\n\n    node->ty = tok->ty;\n    *rest = tok->next;\n    return node;\n  }\n\n  error_tok(tok, \"expected an expression\");\n}\n\nstatic Token *parse_typedef(Token *tok, Type *basety) {\n  bool first = true;\n\n  while (!consume(&tok, tok, \";\")) {\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    Type *ty = declarator(&tok, tok, basety);\n    if (!ty->name)\n      error_tok(ty->name_pos, \"typedef name omitted\");\n    push_scope(get_ident(ty->name))->type_def = ty;\n  }\n  return tok;\n}\n\nstatic void create_param_lvars(Type *param) {\n  if (param) {\n    create_param_lvars(param->next);\n    if (!param->name)\n      error_tok(param->name_pos, \"parameter name omitted\");\n    new_lvar(get_ident(param->name), param);\n  }\n}\n\n// This function matches gotos or labels-as-values with labels.\n//\n// We cannot resolve gotos as we parse a function because gotos\n// can refer a label that appears later in the function.\n// So, we need to do this after we parse the entire function.\nstatic void resolve_goto_labels(void) {\n  for (Node *x = gotos; x; x = x->goto_next) {\n    for (Node *y = labels; y; y = y->goto_next) {\n      if (!strcmp(x->label, y->label)) {\n        x->unique_label = y->unique_label;\n        break;\n      }\n    }\n\n    if (x->unique_label == NULL)\n      error_tok(x->tok->next, \"use of undeclared label\");\n  }\n\n  gotos = labels = NULL;\n}\n\nstatic Obj *find_func(char *name) {\n  Scope *sc = scope;\n  while (sc->next)\n    sc = sc->next;\n\n  VarScope *sc2 = hashmap_get(&sc->vars, name);\n  if (sc2 && sc2->var && sc2->var->is_function)\n    return sc2->var;\n  return NULL;\n}\n\nstatic void mark_live(Obj *var) {\n  if (!var->is_function || var->is_live)\n    return;\n  var->is_live = true;\n\n  for (int i = 0; i < var->refs.len; i++) {\n    Obj *fn = find_func(var->refs.data[i]);\n    if (fn)\n      mark_live(fn);\n  }\n}\n\nstatic Token *function(Token *tok, Type *basety, VarAttr *attr) {\n  Type *ty = declarator(&tok, tok, basety);\n  if (!ty->name)\n    error_tok(ty->name_pos, \"function name omitted\");\n  char *name_str = get_ident(ty->name);\n\n  Obj *fn = find_func(name_str);\n  if (fn) {\n    // Redeclaration\n    if (!fn->is_function)\n      error_tok(tok, \"redeclared as a different kind of symbol\");\n    if (fn->is_definition && equal(tok, \"{\"))\n      error_tok(tok, \"redefinition of %s\", name_str);\n    if (!fn->is_static && attr->is_static)\n      error_tok(tok, \"static declaration follows a non-static declaration\");\n    fn->is_definition = fn->is_definition || equal(tok, \"{\");\n  } else {\n    fn = new_gvar(name_str, ty);\n    fn->is_function = true;\n    fn->is_definition = equal(tok, \"{\");\n    fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern);\n    fn->is_inline = attr->is_inline;\n  }\n\n  fn->is_root = !(fn->is_static && fn->is_inline);\n\n  if (consume(&tok, tok, \";\"))\n    return tok;\n\n  current_fn = fn;\n  locals = NULL;\n  enter_scope();\n  create_param_lvars(ty->params);\n\n  // A buffer for a struct/union return value is passed\n  // as the hidden first parameter.\n  Type *rty = ty->return_ty;\n  if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16)\n    new_lvar(\"\", pointer_to(rty));\n\n  fn->params = locals;\n\n  if (ty->is_variadic)\n    fn->va_area = new_lvar(\"__va_area__\", array_of(ty_char, 136));\n  fn->alloca_bottom = new_lvar(\"__alloca_size__\", pointer_to(ty_char));\n\n  tok = skip(tok, \"{\");\n\n  // [https://www.sigbus.info/n1570#6.4.2.2p1] \"__func__\" is\n  // automatically defined as a local variable containing the\n  // current function name.\n  push_scope(\"__func__\")->var =\n    new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));\n\n  // [GNU] __FUNCTION__ is yet another name of __func__.\n  push_scope(\"__FUNCTION__\")->var =\n    new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));\n\n  fn->body = compound_stmt(&tok, tok);\n  fn->locals = locals;\n  leave_scope();\n  resolve_goto_labels();\n  return tok;\n}\n\nstatic Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {\n  bool first = true;\n\n  while (!consume(&tok, tok, \";\")) {\n    if (!first)\n      tok = skip(tok, \",\");\n    first = false;\n\n    Type *ty = declarator(&tok, tok, basety);\n    if (!ty->name)\n      error_tok(ty->name_pos, \"variable name omitted\");\n\n    Obj *var = new_gvar(get_ident(ty->name), ty);\n    var->is_definition = !attr->is_extern;\n    var->is_static = attr->is_static;\n    var->is_tls = attr->is_tls;\n    if (attr->align)\n      var->align = attr->align;\n\n    if (equal(tok, \"=\"))\n      gvar_initializer(&tok, tok->next, var);\n    else if (!attr->is_extern && !attr->is_tls)\n      var->is_tentative = true;\n  }\n  return tok;\n}\n\n// Lookahead tokens and returns true if a given token is a start\n// of a function definition or declaration.\nstatic bool is_function(Token *tok) {\n  if (equal(tok, \";\"))\n    return false;\n\n  Type dummy = {};\n  Type *ty = declarator(&tok, tok, &dummy);\n  return ty->kind == TY_FUNC;\n}\n\n// Remove redundant tentative definitions.\nstatic void scan_globals(void) {\n  Obj head;\n  Obj *cur = &head;\n\n  for (Obj *var = globals; var; var = var->next) {\n    if (!var->is_tentative) {\n      cur = cur->next = var;\n      continue;\n    }\n\n    // Find another definition of the same identifier.\n    Obj *var2 = globals;\n    for (; var2; var2 = var2->next)\n      if (var != var2 && var2->is_definition && !strcmp(var->name, var2->name))\n        break;\n\n    // If there's another definition, the tentative definition\n    // is redundant\n    if (!var2)\n      cur = cur->next = var;\n  }\n\n  cur->next = NULL;\n  globals = head.next;\n}\n\nstatic void declare_builtin_functions(void) {\n  Type *ty = func_type(pointer_to(ty_void));\n  ty->params = copy_type(ty_int);\n  builtin_alloca = new_gvar(\"alloca\", ty);\n  builtin_alloca->is_definition = false;\n}\n\n// program = (typedef | function-definition | global-variable)*\nObj *parse(Token *tok) {\n  declare_builtin_functions();\n  globals = NULL;\n\n  while (tok->kind != TK_EOF) {\n    VarAttr attr = {};\n    Type *basety = declspec(&tok, tok, &attr);\n\n    // Typedef\n    if (attr.is_typedef) {\n      tok = parse_typedef(tok, basety);\n      continue;\n    }\n\n    // Function\n    if (is_function(tok)) {\n      tok = function(tok, basety, &attr);\n      continue;\n    }\n\n    // Global variable\n    tok = global_variable(tok, basety, &attr);\n  }\n\n  for (Obj *var = globals; var; var = var->next)\n    if (var->is_root)\n      mark_live(var);\n\n  // Remove redundant tentative definitions.\n  scan_globals();\n  return globals;\n}\n"
  },
  {
    "path": "preprocess.c",
    "content": "// This file implements the C preprocessor.\n//\n// The preprocessor takes a list of tokens as an input and returns a\n// new list of tokens as an output.\n//\n// The preprocessing language is designed in such a way that that's\n// guaranteed to stop even if there is a recursive macro.\n// Informally speaking, a macro is applied only once for each token.\n// That is, if a macro token T appears in a result of direct or\n// indirect macro expansion of T, T won't be expanded any further.\n// For example, if T is defined as U, and U is defined as T, then\n// token T is expanded to U and then to T and the macro expansion\n// stops at that point.\n//\n// To achieve the above behavior, we attach for each token a set of\n// macro names from which the token is expanded. The set is called\n// \"hideset\". Hideset is initially empty, and every time we expand a\n// macro, the macro name is added to the resulting tokens' hidesets.\n//\n// The above macro expansion algorithm is explained in this document\n// written by Dave Prossor, which is used as a basis for the\n// standard's wording:\n// https://github.com/rui314/chibicc/wiki/cpp.algo.pdf\n\n#include \"chibicc.h\"\n\ntypedef struct MacroParam MacroParam;\nstruct MacroParam {\n  MacroParam *next;\n  char *name;\n};\n\ntypedef struct MacroArg MacroArg;\nstruct MacroArg {\n  MacroArg *next;\n  char *name;\n  bool is_va_args;\n  Token *tok;\n};\n\ntypedef Token *macro_handler_fn(Token *);\n\ntypedef struct Macro Macro;\nstruct Macro {\n  char *name;\n  bool is_objlike; // Object-like or function-like\n  MacroParam *params;\n  char *va_args_name;\n  Token *body;\n  macro_handler_fn *handler;\n};\n\n// `#if` can be nested, so we use a stack to manage nested `#if`s.\ntypedef struct CondIncl CondIncl;\nstruct CondIncl {\n  CondIncl *next;\n  enum { IN_THEN, IN_ELIF, IN_ELSE } ctx;\n  Token *tok;\n  bool included;\n};\n\ntypedef struct Hideset Hideset;\nstruct Hideset {\n  Hideset *next;\n  char *name;\n};\n\nstatic HashMap macros;\nstatic CondIncl *cond_incl;\nstatic HashMap pragma_once;\nstatic int include_next_idx;\n\nstatic Token *preprocess2(Token *tok);\nstatic Macro *find_macro(Token *tok);\n\nstatic bool is_hash(Token *tok) {\n  return tok->at_bol && equal(tok, \"#\");\n}\n\n// Some preprocessor directives such as #include allow extraneous\n// tokens before newline. This function skips such tokens.\nstatic Token *skip_line(Token *tok) {\n  if (tok->at_bol)\n    return tok;\n  warn_tok(tok, \"extra token\");\n  while (tok->at_bol)\n    tok = tok->next;\n  return tok;\n}\n\nstatic Token *copy_token(Token *tok) {\n  Token *t = calloc(1, sizeof(Token));\n  *t = *tok;\n  t->next = NULL;\n  return t;\n}\n\nstatic Token *new_eof(Token *tok) {\n  Token *t = copy_token(tok);\n  t->kind = TK_EOF;\n  t->len = 0;\n  return t;\n}\n\nstatic Hideset *new_hideset(char *name) {\n  Hideset *hs = calloc(1, sizeof(Hideset));\n  hs->name = name;\n  return hs;\n}\n\nstatic Hideset *hideset_union(Hideset *hs1, Hideset *hs2) {\n  Hideset head = {};\n  Hideset *cur = &head;\n\n  for (; hs1; hs1 = hs1->next)\n    cur = cur->next = new_hideset(hs1->name);\n  cur->next = hs2;\n  return head.next;\n}\n\nstatic bool hideset_contains(Hideset *hs, char *s, int len) {\n  for (; hs; hs = hs->next)\n    if (strlen(hs->name) == len && !strncmp(hs->name, s, len))\n      return true;\n  return false;\n}\n\nstatic Hideset *hideset_intersection(Hideset *hs1, Hideset *hs2) {\n  Hideset head = {};\n  Hideset *cur = &head;\n\n  for (; hs1; hs1 = hs1->next)\n    if (hideset_contains(hs2, hs1->name, strlen(hs1->name)))\n      cur = cur->next = new_hideset(hs1->name);\n  return head.next;\n}\n\nstatic Token *add_hideset(Token *tok, Hideset *hs) {\n  Token head = {};\n  Token *cur = &head;\n\n  for (; tok; tok = tok->next) {\n    Token *t = copy_token(tok);\n    t->hideset = hideset_union(t->hideset, hs);\n    cur = cur->next = t;\n  }\n  return head.next;\n}\n\n// Append tok2 to the end of tok1.\nstatic Token *append(Token *tok1, Token *tok2) {\n  if (tok1->kind == TK_EOF)\n    return tok2;\n\n  Token head = {};\n  Token *cur = &head;\n\n  for (; tok1->kind != TK_EOF; tok1 = tok1->next)\n    cur = cur->next = copy_token(tok1);\n  cur->next = tok2;\n  return head.next;\n}\n\nstatic Token *skip_cond_incl2(Token *tok) {\n  while (tok->kind != TK_EOF) {\n    if (is_hash(tok) &&\n        (equal(tok->next, \"if\") || equal(tok->next, \"ifdef\") ||\n         equal(tok->next, \"ifndef\"))) {\n      tok = skip_cond_incl2(tok->next->next);\n      continue;\n    }\n    if (is_hash(tok) && equal(tok->next, \"endif\"))\n      return tok->next->next;\n    tok = tok->next;\n  }\n  return tok;\n}\n\n// Skip until next `#else`, `#elif` or `#endif`.\n// Nested `#if` and `#endif` are skipped.\nstatic Token *skip_cond_incl(Token *tok) {\n  while (tok->kind != TK_EOF) {\n    if (is_hash(tok) &&\n        (equal(tok->next, \"if\") || equal(tok->next, \"ifdef\") ||\n         equal(tok->next, \"ifndef\"))) {\n      tok = skip_cond_incl2(tok->next->next);\n      continue;\n    }\n\n    if (is_hash(tok) &&\n        (equal(tok->next, \"elif\") || equal(tok->next, \"else\") ||\n         equal(tok->next, \"endif\")))\n      break;\n    tok = tok->next;\n  }\n  return tok;\n}\n\n// Double-quote a given string and returns it.\nstatic char *quote_string(char *str) {\n  int bufsize = 3;\n  for (int i = 0; str[i]; i++) {\n    if (str[i] == '\\\\' || str[i] == '\"')\n      bufsize++;\n    bufsize++;\n  }\n\n  char *buf = calloc(1, bufsize);\n  char *p = buf;\n  *p++ = '\"';\n  for (int i = 0; str[i]; i++) {\n    if (str[i] == '\\\\' || str[i] == '\"')\n      *p++ = '\\\\';\n    *p++ = str[i];\n  }\n  *p++ = '\"';\n  *p++ = '\\0';\n  return buf;\n}\n\nstatic Token *new_str_token(char *str, Token *tmpl) {\n  char *buf = quote_string(str);\n  return tokenize(new_file(tmpl->file->name, tmpl->file->file_no, buf));\n}\n\n// Copy all tokens until the next newline, terminate them with\n// an EOF token and then returns them. This function is used to\n// create a new list of tokens for `#if` arguments.\nstatic Token *copy_line(Token **rest, Token *tok) {\n  Token head = {};\n  Token *cur = &head;\n\n  for (; !tok->at_bol; tok = tok->next)\n    cur = cur->next = copy_token(tok);\n\n  cur->next = new_eof(tok);\n  *rest = tok;\n  return head.next;\n}\n\nstatic Token *new_num_token(int val, Token *tmpl) {\n  char *buf = format(\"%d\\n\", val);\n  return tokenize(new_file(tmpl->file->name, tmpl->file->file_no, buf));\n}\n\nstatic Token *read_const_expr(Token **rest, Token *tok) {\n  tok = copy_line(rest, tok);\n\n  Token head = {};\n  Token *cur = &head;\n\n  while (tok->kind != TK_EOF) {\n    // \"defined(foo)\" or \"defined foo\" becomes \"1\" if macro \"foo\"\n    // is defined. Otherwise \"0\".\n    if (equal(tok, \"defined\")) {\n      Token *start = tok;\n      bool has_paren = consume(&tok, tok->next, \"(\");\n\n      if (tok->kind != TK_IDENT)\n        error_tok(start, \"macro name must be an identifier\");\n      Macro *m = find_macro(tok);\n      tok = tok->next;\n\n      if (has_paren)\n        tok = skip(tok, \")\");\n\n      cur = cur->next = new_num_token(m ? 1 : 0, start);\n      continue;\n    }\n\n    cur = cur->next = tok;\n    tok = tok->next;\n  }\n\n  cur->next = tok;\n  return head.next;\n}\n\n// Read and evaluate a constant expression.\nstatic long eval_const_expr(Token **rest, Token *tok) {\n  Token *start = tok;\n  Token *expr = read_const_expr(rest, tok->next);\n  expr = preprocess2(expr);\n\n  if (expr->kind == TK_EOF)\n    error_tok(start, \"no expression\");\n\n  // [https://www.sigbus.info/n1570#6.10.1p4] The standard requires\n  // we replace remaining non-macro identifiers with \"0\" before\n  // evaluating a constant expression. For example, `#if foo` is\n  // equivalent to `#if 0` if foo is not defined.\n  for (Token *t = expr; t->kind != TK_EOF; t = t->next) {\n    if (t->kind == TK_IDENT) {\n      Token *next = t->next;\n      *t = *new_num_token(0, t);\n      t->next = next;\n    }\n  }\n\n  // Convert pp-numbers to regular numbers\n  convert_pp_tokens(expr);\n\n  Token *rest2;\n  long val = const_expr(&rest2, expr);\n  if (rest2->kind != TK_EOF)\n    error_tok(rest2, \"extra token\");\n  return val;\n}\n\nstatic CondIncl *push_cond_incl(Token *tok, bool included) {\n  CondIncl *ci = calloc(1, sizeof(CondIncl));\n  ci->next = cond_incl;\n  ci->ctx = IN_THEN;\n  ci->tok = tok;\n  ci->included = included;\n  cond_incl = ci;\n  return ci;\n}\n\nstatic Macro *find_macro(Token *tok) {\n  if (tok->kind != TK_IDENT)\n    return NULL;\n  return hashmap_get2(&macros, tok->loc, tok->len);\n}\n\nstatic Macro *add_macro(char *name, bool is_objlike, Token *body) {\n  Macro *m = calloc(1, sizeof(Macro));\n  m->name = name;\n  m->is_objlike = is_objlike;\n  m->body = body;\n  hashmap_put(&macros, name, m);\n  return m;\n}\n\nstatic MacroParam *read_macro_params(Token **rest, Token *tok, char **va_args_name) {\n  MacroParam head = {};\n  MacroParam *cur = &head;\n\n  while (!equal(tok, \")\")) {\n    if (cur != &head)\n      tok = skip(tok, \",\");\n\n    if (equal(tok, \"...\")) {\n      *va_args_name = \"__VA_ARGS__\";\n      *rest = skip(tok->next, \")\");\n      return head.next;\n    }\n\n    if (tok->kind != TK_IDENT)\n      error_tok(tok, \"expected an identifier\");\n\n    if (equal(tok->next, \"...\")) {\n      *va_args_name = strndup(tok->loc, tok->len);\n      *rest = skip(tok->next->next, \")\");\n      return head.next;\n    }\n\n    MacroParam *m = calloc(1, sizeof(MacroParam));\n    m->name = strndup(tok->loc, tok->len);\n    cur = cur->next = m;\n    tok = tok->next;\n  }\n\n  *rest = tok->next;\n  return head.next;\n}\n\nstatic void read_macro_definition(Token **rest, Token *tok) {\n  if (tok->kind != TK_IDENT)\n    error_tok(tok, \"macro name must be an identifier\");\n  char *name = strndup(tok->loc, tok->len);\n  tok = tok->next;\n\n  if (!tok->has_space && equal(tok, \"(\")) {\n    // Function-like macro\n    char *va_args_name = NULL;\n    MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);\n\n    Macro *m = add_macro(name, false, copy_line(rest, tok));\n    m->params = params;\n    m->va_args_name = va_args_name;\n  } else {\n    // Object-like macro\n    add_macro(name, true, copy_line(rest, tok));\n  }\n}\n\nstatic MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {\n  Token head = {};\n  Token *cur = &head;\n  int level = 0;\n\n  for (;;) {\n    if (level == 0 && equal(tok, \")\"))\n      break;\n    if (level == 0 && !read_rest && equal(tok, \",\"))\n      break;\n\n    if (tok->kind == TK_EOF)\n      error_tok(tok, \"premature end of input\");\n\n    if (equal(tok, \"(\"))\n      level++;\n    else if (equal(tok, \")\"))\n      level--;\n\n    cur = cur->next = copy_token(tok);\n    tok = tok->next;\n  }\n\n  cur->next = new_eof(tok);\n\n  MacroArg *arg = calloc(1, sizeof(MacroArg));\n  arg->tok = head.next;\n  *rest = tok;\n  return arg;\n}\n\nstatic MacroArg *\nread_macro_args(Token **rest, Token *tok, MacroParam *params, char *va_args_name) {\n  Token *start = tok;\n  tok = tok->next->next;\n\n  MacroArg head = {};\n  MacroArg *cur = &head;\n\n  MacroParam *pp = params;\n  for (; pp; pp = pp->next) {\n    if (cur != &head)\n      tok = skip(tok, \",\");\n    cur = cur->next = read_macro_arg_one(&tok, tok, false);\n    cur->name = pp->name;\n  }\n\n  if (va_args_name) {\n    MacroArg *arg;\n    if (equal(tok, \")\")) {\n      arg = calloc(1, sizeof(MacroArg));\n      arg->tok = new_eof(tok);\n    } else {\n      if (pp != params)\n        tok = skip(tok, \",\");\n      arg = read_macro_arg_one(&tok, tok, true);\n    }\n    arg->name = va_args_name;;\n    arg->is_va_args = true;\n    cur = cur->next = arg;\n  } else if (pp) {\n    error_tok(start, \"too many arguments\");\n  }\n\n  skip(tok, \")\");\n  *rest = tok;\n  return head.next;\n}\n\nstatic MacroArg *find_arg(MacroArg *args, Token *tok) {\n  for (MacroArg *ap = args; ap; ap = ap->next)\n    if (tok->len == strlen(ap->name) && !strncmp(tok->loc, ap->name, tok->len))\n      return ap;\n  return NULL;\n}\n\n// Concatenates all tokens in `tok` and returns a new string.\nstatic char *join_tokens(Token *tok, Token *end) {\n  // Compute the length of the resulting token.\n  int len = 1;\n  for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {\n    if (t != tok && t->has_space)\n      len++;\n    len += t->len;\n  }\n\n  char *buf = calloc(1, len);\n\n  // Copy token texts.\n  int pos = 0;\n  for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {\n    if (t != tok && t->has_space)\n      buf[pos++] = ' ';\n    strncpy(buf + pos, t->loc, t->len);\n    pos += t->len;\n  }\n  buf[pos] = '\\0';\n  return buf;\n}\n\n// Concatenates all tokens in `arg` and returns a new string token.\n// This function is used for the stringizing operator (#).\nstatic Token *stringize(Token *hash, Token *arg) {\n  // Create a new string token. We need to set some value to its\n  // source location for error reporting function, so we use a macro\n  // name token as a template.\n  char *s = join_tokens(arg, NULL);\n  return new_str_token(s, hash);\n}\n\n// Concatenate two tokens to create a new token.\nstatic Token *paste(Token *lhs, Token *rhs) {\n  // Paste the two tokens.\n  char *buf = format(\"%.*s%.*s\", lhs->len, lhs->loc, rhs->len, rhs->loc);\n\n  // Tokenize the resulting string.\n  Token *tok = tokenize(new_file(lhs->file->name, lhs->file->file_no, buf));\n  if (tok->next->kind != TK_EOF)\n    error_tok(lhs, \"pasting forms '%s', an invalid token\", buf);\n  return tok;\n}\n\nstatic bool has_varargs(MacroArg *args) {\n  for (MacroArg *ap = args; ap; ap = ap->next)\n    if (!strcmp(ap->name, \"__VA_ARGS__\"))\n      return ap->tok->kind != TK_EOF;\n  return false;\n}\n\n// Replace func-like macro parameters with given arguments.\nstatic Token *subst(Token *tok, MacroArg *args) {\n  Token head = {};\n  Token *cur = &head;\n\n  while (tok->kind != TK_EOF) {\n    // \"#\" followed by a parameter is replaced with stringized actuals.\n    if (equal(tok, \"#\")) {\n      MacroArg *arg = find_arg(args, tok->next);\n      if (!arg)\n        error_tok(tok->next, \"'#' is not followed by a macro parameter\");\n      cur = cur->next = stringize(tok, arg->tok);\n      tok = tok->next->next;\n      continue;\n    }\n\n    // [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded\n    // to the empty token list. Otherwise, its expaned to `,` and\n    // __VA_ARGS__.\n    if (equal(tok, \",\") && equal(tok->next, \"##\")) {\n      MacroArg *arg = find_arg(args, tok->next->next);\n      if (arg && arg->is_va_args) {\n        if (arg->tok->kind == TK_EOF) {\n          tok = tok->next->next->next;\n        } else {\n          cur = cur->next = copy_token(tok);\n          tok = tok->next->next;\n        }\n        continue;\n      }\n    }\n\n    if (equal(tok, \"##\")) {\n      if (cur == &head)\n        error_tok(tok, \"'##' cannot appear at start of macro expansion\");\n\n      if (tok->next->kind == TK_EOF)\n        error_tok(tok, \"'##' cannot appear at end of macro expansion\");\n\n      MacroArg *arg = find_arg(args, tok->next);\n      if (arg) {\n        if (arg->tok->kind != TK_EOF) {\n          *cur = *paste(cur, arg->tok);\n          for (Token *t = arg->tok->next; t->kind != TK_EOF; t = t->next)\n            cur = cur->next = copy_token(t);\n        }\n        tok = tok->next->next;\n        continue;\n      }\n\n      *cur = *paste(cur, tok->next);\n      tok = tok->next->next;\n      continue;\n    }\n\n    MacroArg *arg = find_arg(args, tok);\n\n    if (arg && equal(tok->next, \"##\")) {\n      Token *rhs = tok->next->next;\n\n      if (arg->tok->kind == TK_EOF) {\n        MacroArg *arg2 = find_arg(args, rhs);\n        if (arg2) {\n          for (Token *t = arg2->tok; t->kind != TK_EOF; t = t->next)\n            cur = cur->next = copy_token(t);\n        } else {\n          cur = cur->next = copy_token(rhs);\n        }\n        tok = rhs->next;\n        continue;\n      }\n\n      for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)\n        cur = cur->next = copy_token(t);\n      tok = tok->next;\n      continue;\n    }\n\n    // If __VA_ARG__ is empty, __VA_OPT__(x) is expanded to the\n    // empty token list. Otherwise, __VA_OPT__(x) is expanded to x.\n    if (equal(tok, \"__VA_OPT__\") && equal(tok->next, \"(\")) {\n      MacroArg *arg = read_macro_arg_one(&tok, tok->next->next, true);\n      if (has_varargs(args))\n        for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)\n          cur = cur->next = t;\n      tok = skip(tok, \")\");\n      continue;\n    }\n\n    // Handle a macro token. Macro arguments are completely macro-expanded\n    // before they are substituted into a macro body.\n    if (arg) {\n      Token *t = preprocess2(arg->tok);\n      t->at_bol = tok->at_bol;\n      t->has_space = tok->has_space;\n      for (; t->kind != TK_EOF; t = t->next)\n        cur = cur->next = copy_token(t);\n      tok = tok->next;\n      continue;\n    }\n\n    // Handle a non-macro token.\n    cur = cur->next = copy_token(tok);\n    tok = tok->next;\n    continue;\n  }\n\n  cur->next = tok;\n  return head.next;\n}\n\n// If tok is a macro, expand it and return true.\n// Otherwise, do nothing and return false.\nstatic bool expand_macro(Token **rest, Token *tok) {\n  if (hideset_contains(tok->hideset, tok->loc, tok->len))\n    return false;\n\n  Macro *m = find_macro(tok);\n  if (!m)\n    return false;\n\n  // Built-in dynamic macro application such as __LINE__\n  if (m->handler) {\n    *rest = m->handler(tok);\n    (*rest)->next = tok->next;\n    return true;\n  }\n\n  // Object-like macro application\n  if (m->is_objlike) {\n    Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));\n    Token *body = add_hideset(m->body, hs);\n    for (Token *t = body; t->kind != TK_EOF; t = t->next)\n      t->origin = tok;\n    *rest = append(body, tok->next);\n    (*rest)->at_bol = tok->at_bol;\n    (*rest)->has_space = tok->has_space;\n    return true;\n  }\n\n  // If a funclike macro token is not followed by an argument list,\n  // treat it as a normal identifier.\n  if (!equal(tok->next, \"(\"))\n    return false;\n\n  // Function-like macro application\n  Token *macro_token = tok;\n  MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name);\n  Token *rparen = tok;\n\n  // Tokens that consist a func-like macro invocation may have different\n  // hidesets, and if that's the case, it's not clear what the hideset\n  // for the new tokens should be. We take the interesection of the\n  // macro token and the closing parenthesis and use it as a new hideset\n  // as explained in the Dave Prossor's algorithm.\n  Hideset *hs = hideset_intersection(macro_token->hideset, rparen->hideset);\n  hs = hideset_union(hs, new_hideset(m->name));\n\n  Token *body = subst(m->body, args);\n  body = add_hideset(body, hs);\n  for (Token *t = body; t->kind != TK_EOF; t = t->next)\n    t->origin = macro_token;\n  *rest = append(body, tok->next);\n  (*rest)->at_bol = macro_token->at_bol;\n  (*rest)->has_space = macro_token->has_space;\n  return true;\n}\n\nchar *search_include_paths(char *filename) {\n  if (filename[0] == '/')\n    return filename;\n\n  static HashMap cache;\n  char *cached = hashmap_get(&cache, filename);\n  if (cached)\n    return cached;\n\n  // Search a file from the include paths.\n  for (int i = 0; i < include_paths.len; i++) {\n    char *path = format(\"%s/%s\", include_paths.data[i], filename);\n    if (!file_exists(path))\n      continue;\n    hashmap_put(&cache, filename, path);\n    include_next_idx = i + 1;\n    return path;\n  }\n  return NULL;\n}\n\nstatic char *search_include_next(char *filename) {\n  for (; include_next_idx < include_paths.len; include_next_idx++) {\n    char *path = format(\"%s/%s\", include_paths.data[include_next_idx], filename);\n    if (file_exists(path))\n      return path;\n  }\n  return NULL;\n}\n\n// Read an #include argument.\nstatic char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {\n  // Pattern 1: #include \"foo.h\"\n  if (tok->kind == TK_STR) {\n    // A double-quoted filename for #include is a special kind of\n    // token, and we don't want to interpret any escape sequences in it.\n    // For example, \"\\f\" in \"C:\\foo\" is not a formfeed character but\n    // just two non-control characters, backslash and f.\n    // So we don't want to use token->str.\n    *is_dquote = true;\n    *rest = skip_line(tok->next);\n    return strndup(tok->loc + 1, tok->len - 2);\n  }\n\n  // Pattern 2: #include <foo.h>\n  if (equal(tok, \"<\")) {\n    // Reconstruct a filename from a sequence of tokens between\n    // \"<\" and \">\".\n    Token *start = tok;\n\n    // Find closing \">\".\n    for (; !equal(tok, \">\"); tok = tok->next)\n      if (tok->at_bol || tok->kind == TK_EOF)\n        error_tok(tok, \"expected '>'\");\n\n    *is_dquote = false;\n    *rest = skip_line(tok->next);\n    return join_tokens(start->next, tok);\n  }\n\n  // Pattern 3: #include FOO\n  // In this case FOO must be macro-expanded to either\n  // a single string token or a sequence of \"<\" ... \">\".\n  if (tok->kind == TK_IDENT) {\n    Token *tok2 = preprocess2(copy_line(rest, tok));\n    return read_include_filename(&tok2, tok2, is_dquote);\n  }\n\n  error_tok(tok, \"expected a filename\");\n}\n\n// Detect the following \"include guard\" pattern.\n//\n//   #ifndef FOO_H\n//   #define FOO_H\n//   ...\n//   #endif\nstatic char *detect_include_guard(Token *tok) {\n  // Detect the first two lines.\n  if (!is_hash(tok) || !equal(tok->next, \"ifndef\"))\n    return NULL;\n  tok = tok->next->next;\n\n  if (tok->kind != TK_IDENT)\n    return NULL;\n\n  char *macro = strndup(tok->loc, tok->len);\n  tok = tok->next;\n\n  if (!is_hash(tok) || !equal(tok->next, \"define\") || !equal(tok->next->next, macro))\n    return NULL;\n\n  // Read until the end of the file.\n  while (tok->kind != TK_EOF) {\n    if (!is_hash(tok)) {\n      tok = tok->next;\n      continue;\n    }\n\n    if (equal(tok->next, \"endif\") && tok->next->next->kind == TK_EOF)\n      return macro;\n\n    if (equal(tok, \"if\") || equal(tok, \"ifdef\") || equal(tok, \"ifndef\"))\n      tok = skip_cond_incl(tok->next);\n    else\n      tok = tok->next;\n  }\n  return NULL;\n}\n\nstatic Token *include_file(Token *tok, char *path, Token *filename_tok) {\n  // Check for \"#pragma once\"\n  if (hashmap_get(&pragma_once, path))\n    return tok;\n\n  // If we read the same file before, and if the file was guarded\n  // by the usual #ifndef ... #endif pattern, we may be able to\n  // skip the file without opening it.\n  static HashMap include_guards;\n  char *guard_name = hashmap_get(&include_guards, path);\n  if (guard_name && hashmap_get(&macros, guard_name))\n    return tok;\n\n  Token *tok2 = tokenize_file(path);\n  if (!tok2)\n    error_tok(filename_tok, \"%s: cannot open file: %s\", path, strerror(errno));\n\n  guard_name = detect_include_guard(tok2);\n  if (guard_name)\n    hashmap_put(&include_guards, path, guard_name);\n\n  return append(tok2, tok);\n}\n\n// Read #line arguments\nstatic void read_line_marker(Token **rest, Token *tok) {\n  Token *start = tok;\n  tok = preprocess(copy_line(rest, tok));\n\n  if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)\n    error_tok(tok, \"invalid line marker\");\n  start->file->line_delta = tok->val - start->line_no;\n\n  tok = tok->next;\n  if (tok->kind == TK_EOF)\n    return;\n\n  if (tok->kind != TK_STR)\n    error_tok(tok, \"filename expected\");\n  start->file->display_name = tok->str;\n}\n\n// Visit all tokens in `tok` while evaluating preprocessing\n// macros and directives.\nstatic Token *preprocess2(Token *tok) {\n  Token head = {};\n  Token *cur = &head;\n\n  while (tok->kind != TK_EOF) {\n    // If it is a macro, expand it.\n    if (expand_macro(&tok, tok))\n      continue;\n\n    // Pass through if it is not a \"#\".\n    if (!is_hash(tok)) {\n      tok->line_delta = tok->file->line_delta;\n      tok->filename = tok->file->display_name;\n      cur = cur->next = tok;\n      tok = tok->next;\n      continue;\n    }\n\n    Token *start = tok;\n    tok = tok->next;\n\n    if (equal(tok, \"include\")) {\n      bool is_dquote;\n      char *filename = read_include_filename(&tok, tok->next, &is_dquote);\n\n      if (filename[0] != '/' && is_dquote) {\n        char *path = format(\"%s/%s\", dirname(strdup(start->file->name)), filename);\n        if (file_exists(path)) {\n          tok = include_file(tok, path, start->next->next);\n          continue;\n        }\n      }\n\n      char *path = search_include_paths(filename);\n      tok = include_file(tok, path ? path : filename, start->next->next);\n      continue;\n    }\n\n    if (equal(tok, \"include_next\")) {\n      bool ignore;\n      char *filename = read_include_filename(&tok, tok->next, &ignore);\n      char *path = search_include_next(filename);\n      tok = include_file(tok, path ? path : filename, start->next->next);\n      continue;\n    }\n\n    if (equal(tok, \"define\")) {\n      read_macro_definition(&tok, tok->next);\n      continue;\n    }\n\n    if (equal(tok, \"undef\")) {\n      tok = tok->next;\n      if (tok->kind != TK_IDENT)\n        error_tok(tok, \"macro name must be an identifier\");\n      undef_macro(strndup(tok->loc, tok->len));\n      tok = skip_line(tok->next);\n      continue;\n    }\n\n    if (equal(tok, \"if\")) {\n      long val = eval_const_expr(&tok, tok);\n      push_cond_incl(start, val);\n      if (!val)\n        tok = skip_cond_incl(tok);\n      continue;\n    }\n\n    if (equal(tok, \"ifdef\")) {\n      bool defined = find_macro(tok->next);\n      push_cond_incl(tok, defined);\n      tok = skip_line(tok->next->next);\n      if (!defined)\n        tok = skip_cond_incl(tok);\n      continue;\n    }\n\n    if (equal(tok, \"ifndef\")) {\n      bool defined = find_macro(tok->next);\n      push_cond_incl(tok, !defined);\n      tok = skip_line(tok->next->next);\n      if (defined)\n        tok = skip_cond_incl(tok);\n      continue;\n    }\n\n    if (equal(tok, \"elif\")) {\n      if (!cond_incl || cond_incl->ctx == IN_ELSE)\n        error_tok(start, \"stray #elif\");\n      cond_incl->ctx = IN_ELIF;\n\n      if (!cond_incl->included && eval_const_expr(&tok, tok))\n        cond_incl->included = true;\n      else\n        tok = skip_cond_incl(tok);\n      continue;\n    }\n\n    if (equal(tok, \"else\")) {\n      if (!cond_incl || cond_incl->ctx == IN_ELSE)\n        error_tok(start, \"stray #else\");\n      cond_incl->ctx = IN_ELSE;\n      tok = skip_line(tok->next);\n\n      if (cond_incl->included)\n        tok = skip_cond_incl(tok);\n      continue;\n    }\n\n    if (equal(tok, \"endif\")) {\n      if (!cond_incl)\n        error_tok(start, \"stray #endif\");\n      cond_incl = cond_incl->next;\n      tok = skip_line(tok->next);\n      continue;\n    }\n\n    if (equal(tok, \"line\")) {\n      read_line_marker(&tok, tok->next);\n      continue;\n    }\n\n    if (tok->kind == TK_PP_NUM) {\n      read_line_marker(&tok, tok);\n      continue;\n    }\n\n    if (equal(tok, \"pragma\") && equal(tok->next, \"once\")) {\n      hashmap_put(&pragma_once, tok->file->name, (void *)1);\n      tok = skip_line(tok->next->next);\n      continue;\n    }\n\n    if (equal(tok, \"pragma\")) {\n      do {\n        tok = tok->next;\n      } while (!tok->at_bol);\n      continue;\n    }\n\n    if (equal(tok, \"error\"))\n      error_tok(tok, \"error\");\n\n    // `#`-only line is legal. It's called a null directive.\n    if (tok->at_bol)\n      continue;\n\n    error_tok(tok, \"invalid preprocessor directive\");\n  }\n\n  cur->next = tok;\n  return head.next;\n}\n\nvoid define_macro(char *name, char *buf) {\n  Token *tok = tokenize(new_file(\"<built-in>\", 1, buf));\n  add_macro(name, true, tok);\n}\n\nvoid undef_macro(char *name) {\n  hashmap_delete(&macros, name);\n}\n\nstatic Macro *add_builtin(char *name, macro_handler_fn *fn) {\n  Macro *m = add_macro(name, true, NULL);\n  m->handler = fn;\n  return m;\n}\n\nstatic Token *file_macro(Token *tmpl) {\n  while (tmpl->origin)\n    tmpl = tmpl->origin;\n  return new_str_token(tmpl->file->display_name, tmpl);\n}\n\nstatic Token *line_macro(Token *tmpl) {\n  while (tmpl->origin)\n    tmpl = tmpl->origin;\n  int i = tmpl->line_no + tmpl->file->line_delta;\n  return new_num_token(i, tmpl);\n}\n\n// __COUNTER__ is expanded to serial values starting from 0.\nstatic Token *counter_macro(Token *tmpl) {\n  static int i = 0;\n  return new_num_token(i++, tmpl);\n}\n\n// __TIMESTAMP__ is expanded to a string describing the last\n// modification time of the current file. E.g.\n// \"Fri Jul 24 01:32:50 2020\"\nstatic Token *timestamp_macro(Token *tmpl) {\n  struct stat st;\n  if (stat(tmpl->file->name, &st) != 0)\n    return new_str_token(\"??? ??? ?? ??:??:?? ????\", tmpl);\n\n  char buf[30];\n  ctime_r(&st.st_mtime, buf);\n  buf[24] = '\\0';\n  return new_str_token(buf, tmpl);\n}\n\nstatic Token *base_file_macro(Token *tmpl) {\n  return new_str_token(base_file, tmpl);\n}\n\n// __DATE__ is expanded to the current date, e.g. \"May 17 2020\".\nstatic char *format_date(struct tm *tm) {\n  static char mon[][4] = {\n    \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n    \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n  };\n\n  return format(\"\\\"%s %2d %d\\\"\", mon[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);\n}\n\n// __TIME__ is expanded to the current time, e.g. \"13:34:03\".\nstatic char *format_time(struct tm *tm) {\n  return format(\"\\\"%02d:%02d:%02d\\\"\", tm->tm_hour, tm->tm_min, tm->tm_sec);\n}\n\nvoid init_macros(void) {\n  // Define predefined macros\n  define_macro(\"_LP64\", \"1\");\n  define_macro(\"__C99_MACRO_WITH_VA_ARGS\", \"1\");\n  define_macro(\"__ELF__\", \"1\");\n  define_macro(\"__LP64__\", \"1\");\n  define_macro(\"__SIZEOF_DOUBLE__\", \"8\");\n  define_macro(\"__SIZEOF_FLOAT__\", \"4\");\n  define_macro(\"__SIZEOF_INT__\", \"4\");\n  define_macro(\"__SIZEOF_LONG_DOUBLE__\", \"8\");\n  define_macro(\"__SIZEOF_LONG_LONG__\", \"8\");\n  define_macro(\"__SIZEOF_LONG__\", \"8\");\n  define_macro(\"__SIZEOF_POINTER__\", \"8\");\n  define_macro(\"__SIZEOF_PTRDIFF_T__\", \"8\");\n  define_macro(\"__SIZEOF_SHORT__\", \"2\");\n  define_macro(\"__SIZEOF_SIZE_T__\", \"8\");\n  define_macro(\"__SIZE_TYPE__\", \"unsigned long\");\n  define_macro(\"__STDC_HOSTED__\", \"1\");\n  define_macro(\"__STDC_NO_COMPLEX__\", \"1\");\n  define_macro(\"__STDC_UTF_16__\", \"1\");\n  define_macro(\"__STDC_UTF_32__\", \"1\");\n  define_macro(\"__STDC_VERSION__\", \"201112L\");\n  define_macro(\"__STDC__\", \"1\");\n  define_macro(\"__USER_LABEL_PREFIX__\", \"\");\n  define_macro(\"__alignof__\", \"_Alignof\");\n  define_macro(\"__amd64\", \"1\");\n  define_macro(\"__amd64__\", \"1\");\n  define_macro(\"__chibicc__\", \"1\");\n  define_macro(\"__const__\", \"const\");\n  define_macro(\"__gnu_linux__\", \"1\");\n  define_macro(\"__inline__\", \"inline\");\n  define_macro(\"__linux\", \"1\");\n  define_macro(\"__linux__\", \"1\");\n  define_macro(\"__signed__\", \"signed\");\n  define_macro(\"__typeof__\", \"typeof\");\n  define_macro(\"__unix\", \"1\");\n  define_macro(\"__unix__\", \"1\");\n  define_macro(\"__volatile__\", \"volatile\");\n  define_macro(\"__x86_64\", \"1\");\n  define_macro(\"__x86_64__\", \"1\");\n  define_macro(\"linux\", \"1\");\n  define_macro(\"unix\", \"1\");\n\n  add_builtin(\"__FILE__\", file_macro);\n  add_builtin(\"__LINE__\", line_macro);\n  add_builtin(\"__COUNTER__\", counter_macro);\n  add_builtin(\"__TIMESTAMP__\", timestamp_macro);\n  add_builtin(\"__BASE_FILE__\", base_file_macro);\n\n  time_t now = time(NULL);\n  struct tm *tm = localtime(&now);\n  define_macro(\"__DATE__\", format_date(tm));\n  define_macro(\"__TIME__\", format_time(tm));\n}\n\ntypedef enum {\n  STR_NONE, STR_UTF8, STR_UTF16, STR_UTF32, STR_WIDE,\n} StringKind;\n\nstatic StringKind getStringKind(Token *tok) {\n  if (!strcmp(tok->loc, \"u8\"))\n    return STR_UTF8;\n\n  switch (tok->loc[0]) {\n  case '\"': return STR_NONE;\n  case 'u': return STR_UTF16;\n  case 'U': return STR_UTF32;\n  case 'L': return STR_WIDE;\n  }\n  unreachable();\n}\n\n// Concatenate adjacent string literals into a single string literal\n// as per the C spec.\nstatic void join_adjacent_string_literals(Token *tok) {\n  // First pass: If regular string literals are adjacent to wide\n  // string literals, regular string literals are converted to a wide\n  // type before concatenation. In this pass, we do the conversion.\n  for (Token *tok1 = tok; tok1->kind != TK_EOF;) {\n    if (tok1->kind != TK_STR || tok1->next->kind != TK_STR) {\n      tok1 = tok1->next;\n      continue;\n    }\n\n    StringKind kind = getStringKind(tok1);\n    Type *basety = tok1->ty->base;\n\n    for (Token *t = tok1->next; t->kind == TK_STR; t = t->next) {\n      StringKind k = getStringKind(t);\n      if (kind == STR_NONE) {\n        kind = k;\n        basety = t->ty->base;\n      } else if (k != STR_NONE && kind != k) {\n        error_tok(t, \"unsupported non-standard concatenation of string literals\");\n      }\n    }\n\n    if (basety->size > 1)\n      for (Token *t = tok1; t->kind == TK_STR; t = t->next)\n        if (t->ty->base->size == 1)\n          *t = *tokenize_string_literal(t, basety);\n\n    while (tok1->kind == TK_STR)\n      tok1 = tok1->next;\n  }\n\n  // Second pass: concatenate adjacent string literals.\n  for (Token *tok1 = tok; tok1->kind != TK_EOF;) {\n    if (tok1->kind != TK_STR || tok1->next->kind != TK_STR) {\n      tok1 = tok1->next;\n      continue;\n    }\n\n    Token *tok2 = tok1->next;\n    while (tok2->kind == TK_STR)\n      tok2 = tok2->next;\n\n    int len = tok1->ty->array_len;\n    for (Token *t = tok1->next; t != tok2; t = t->next)\n      len = len + t->ty->array_len - 1;\n\n    char *buf = calloc(tok1->ty->base->size, len);\n\n    int i = 0;\n    for (Token *t = tok1; t != tok2; t = t->next) {\n      memcpy(buf + i, t->str, t->ty->size);\n      i = i + t->ty->size - t->ty->base->size;\n    }\n\n    *tok1 = *copy_token(tok1);\n    tok1->ty = array_of(tok1->ty->base, len);\n    tok1->str = buf;\n    tok1->next = tok2;\n    tok1 = tok2;\n  }\n}\n\n// Entry point function of the preprocessor.\nToken *preprocess(Token *tok) {\n  tok = preprocess2(tok);\n  if (cond_incl)\n    error_tok(cond_incl->tok, \"unterminated conditional directive\");\n  convert_pp_tokens(tok);\n  join_adjacent_string_literals(tok);\n\n  for (Token *t = tok; t; t = t->next)\n    t->line_no += t->line_delta;\n  return tok;\n}\n"
  },
  {
    "path": "strings.c",
    "content": "#include \"chibicc.h\"\n\nvoid strarray_push(StringArray *arr, char *s) {\n  if (!arr->data) {\n    arr->data = calloc(8, sizeof(char *));\n    arr->capacity = 8;\n  }\n\n  if (arr->capacity == arr->len) {\n    arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);\n    arr->capacity *= 2;\n    for (int i = arr->len; i < arr->capacity; i++)\n      arr->data[i] = NULL;\n  }\n\n  arr->data[arr->len++] = s;\n}\n\n// Takes a printf-style format string and returns a formatted string.\nchar *format(char *fmt, ...) {\n  char *buf;\n  size_t buflen;\n  FILE *out = open_memstream(&buf, &buflen);\n\n  va_list ap;\n  va_start(ap, fmt);\n  vfprintf(out, fmt, ap);\n  va_end(ap);\n  fclose(out);\n  return buf;\n}\n"
  },
  {
    "path": "test/alignof.c",
    "content": "#include \"test.h\"\n\nint _Alignas(512) g1;\nint _Alignas(512) g2;\nchar g3;\nint g4;\nlong g5;\nchar g6;\n\nint main() {\n  ASSERT(1, _Alignof(char));\n  ASSERT(2, _Alignof(short));\n  ASSERT(4, _Alignof(int));\n  ASSERT(8, _Alignof(long));\n  ASSERT(8, _Alignof(long long));\n  ASSERT(1, _Alignof(char[3]));\n  ASSERT(4, _Alignof(int[3]));\n  ASSERT(1, _Alignof(struct {char a; char b;}[2]));\n  ASSERT(8, _Alignof(struct {char a; long b;}[2]));\n\n  ASSERT(1, ({ _Alignas(char) char x, y; &y-&x; }));\n  ASSERT(8, ({ _Alignas(long) char x, y; &y-&x; }));\n  ASSERT(32, ({ _Alignas(32) char x, y; &y-&x; }));\n  ASSERT(32, ({ _Alignas(32) int *x, *y; ((char *)&y)-((char *)&x); }));\n  ASSERT(16, ({ struct { _Alignas(16) char x, y; } a; &a.y-&a.x; }));\n  ASSERT(8, ({ struct T { _Alignas(8) char a; }; _Alignof(struct T); }));\n\n  ASSERT(0, (long)(char *)&g1 % 512);\n  ASSERT(0, (long)(char *)&g2 % 512);\n  ASSERT(0, (long)(char *)&g4 % 4);\n  ASSERT(0, (long)(char *)&g5 % 8);\n\n  ASSERT(1, ({ char x; _Alignof(x); }));\n  ASSERT(4, ({ int x; _Alignof(x); }));\n  ASSERT(1, ({ char x; _Alignof x; }));\n  ASSERT(4, ({ int x; _Alignof x; }));\n\n  ASSERT(1, _Alignof(char) << 31 >> 31);\n  ASSERT(1, _Alignof(char) << 63 >> 63);\n  ASSERT(1, ({ char x; _Alignof(x) << 63 >> 63; }));\n\n  ASSERT(0, ({ char x[16]; (unsigned long)&x % 16; }));\n  ASSERT(0, ({ char x[17]; (unsigned long)&x % 16; }));\n  ASSERT(0, ({ char x[100]; (unsigned long)&x % 16; }));\n  ASSERT(0, ({ char x[101]; (unsigned long)&x % 16; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/alloca.c",
    "content": "#include \"test.h\"\n\nvoid *fn(int x, void *p, int y) { return p; }\n\nint main() {\n  int i = 0;\n\n  char *p1 = alloca(16);\n  char *p2 = alloca(16);\n  char *p3 = 1 + (char *)alloca(3) + 1;\n  p3 -= 2;\n  char *p4 = fn(1, alloca(16), 3);\n\n  ASSERT(16, p1 - p2);\n  ASSERT(16, p2 - p3);\n  ASSERT(16, p3 - p4);\n\n  memcpy(p1, \"0123456789abcdef\", 16);\n  memcpy(p2, \"ghijklmnopqrstuv\", 16);\n  memcpy(p3, \"wxy\", 3);\n\n  ASSERT(0, memcmp(p1, \"0123456789abcdef\", 16));\n  ASSERT(0, memcmp(p2, \"ghijklmnopqrstuv\", 16));\n  ASSERT(0, memcmp(p3, \"wxy\", 3));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/arith.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(0, 0);\n  ASSERT(42, 42);\n  ASSERT(21, 5+20-4);\n  ASSERT(41,  12 + 34 - 5 );\n  ASSERT(47, 5+6*7);\n  ASSERT(15, 5*(9-6));\n  ASSERT(4, (3+5)/2);\n  ASSERT(10, -10+20);\n  ASSERT(10, - -10);\n  ASSERT(10, - - +10);\n\n  ASSERT(0, 0==1);\n  ASSERT(1, 42==42);\n  ASSERT(1, 0!=1);\n  ASSERT(0, 42!=42);\n\n  ASSERT(1, 0<1);\n  ASSERT(0, 1<1);\n  ASSERT(0, 2<1);\n  ASSERT(1, 0<=1);\n  ASSERT(1, 1<=1);\n  ASSERT(0, 2<=1);\n\n  ASSERT(1, 1>0);\n  ASSERT(0, 1>1);\n  ASSERT(0, 1>2);\n  ASSERT(1, 1>=0);\n  ASSERT(1, 1>=1);\n  ASSERT(0, 1>=2);\n\n  ASSERT(0, 1073741824 * 100 / 100);\n\n  ASSERT(7, ({ int i=2; i+=5; i; }));\n  ASSERT(7, ({ int i=2; i+=5; }));\n  ASSERT(3, ({ int i=5; i-=2; i; }));\n  ASSERT(3, ({ int i=5; i-=2; }));\n  ASSERT(6, ({ int i=3; i*=2; i; }));\n  ASSERT(6, ({ int i=3; i*=2; }));\n  ASSERT(3, ({ int i=6; i/=2; i; }));\n  ASSERT(3, ({ int i=6; i/=2; }));\n\n  ASSERT(3, ({ int i=2; ++i; }));\n  ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; ++*p; }));\n  ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; --*p; }));\n\n  ASSERT(2, ({ int i=2; i++; }));\n  ASSERT(2, ({ int i=2; i--; }));\n  ASSERT(3, ({ int i=2; i++; i; }));\n  ASSERT(1, ({ int i=2; i--; i; }));\n  ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p++; }));\n  ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p--; }));\n\n  ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; }));\n  ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*(p--))--; a[1]; }));\n  ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; a[2]; }));\n  ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; p++; *p; }));\n\n  ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; }));\n  ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[1]; }));\n  ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[2]; }));\n  ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; *p; }));\n\n  ASSERT(0, !1);\n  ASSERT(0, !2);\n  ASSERT(1, !0);\n  ASSERT(1, !(char)0);\n  ASSERT(0, !(long)3);\n  ASSERT(4, sizeof(!(char)0));\n  ASSERT(4, sizeof(!(long)0));\n\n  ASSERT(-1, ~0);\n  ASSERT(0, ~-1);\n\n  ASSERT(5, 17%6);\n  ASSERT(5, ((long)17)%6);\n  ASSERT(2, ({ int i=10; i%=4; i; }));\n  ASSERT(2, ({ long i=10; i%=4; i; }));\n\n  ASSERT(0, 0&1);\n  ASSERT(1, 3&1);\n  ASSERT(3, 7&3);\n  ASSERT(10, -1&10);\n\n  ASSERT(1, 0|1);\n  ASSERT(0b10011, 0b10000|0b00011);\n\n  ASSERT(0, 0^0);\n  ASSERT(0, 0b1111^0b1111);\n  ASSERT(0b110100, 0b111000^0b001100);\n\n  ASSERT(2, ({ int i=6; i&=3; i; }));\n  ASSERT(7, ({ int i=6; i|=3; i; }));\n  ASSERT(10, ({ int i=15; i^=5; i; }));\n\n  ASSERT(1, 1<<0);\n  ASSERT(8, 1<<3);\n  ASSERT(10, 5<<1);\n  ASSERT(2, 5>>1);\n  ASSERT(-1, -1>>1);\n  ASSERT(1, ({ int i=1; i<<=0; i; }));\n  ASSERT(8, ({ int i=1; i<<=3; i; }));\n  ASSERT(10, ({ int i=5; i<<=1; i; }));\n  ASSERT(2, ({ int i=5; i>>=1; i; }));\n  ASSERT(-1, -1);\n  ASSERT(-1, ({ int i=-1; i; }));\n  ASSERT(-1, ({ int i=-1; i>>=1; i; }));\n\n  ASSERT(2, 0?1:2);\n  ASSERT(1, 1?1:2);\n  ASSERT(-1, 0?-2:-1);\n  ASSERT(-2, 1?-2:-1);\n  ASSERT(4, sizeof(0?1:2));\n  ASSERT(8, sizeof(0?(long)1:(long)2));\n  ASSERT(-1, 0?(long)-2:-1);\n  ASSERT(-1, 0?-2:(long)-1);\n  ASSERT(-2, 1?(long)-2:-1);\n  ASSERT(-2, 1?-2:(long)-1);\n\n  1 ? -2 : (void)-1;\n\n  ASSERT(20, ({ int x; int *p=&x; p+20-p; }));\n  ASSERT(1, ({ int x; int *p=&x; p+20-p>0; }));\n  ASSERT(-20, ({ int x; int *p=&x; p-20-p; }));\n  ASSERT(1, ({ int x; int *p=&x; p-20-p<0; }));\n\n  ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0);\n  ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff);\n  ASSERT(1, (void *)0xffffffffffffffff > (void *)0);\n\n  ASSERT(3, 3?:5);\n  ASSERT(5, 0?:5);\n  ASSERT(4, ({ int i = 3; ++i?:10; }));\n\n  ASSERT(3, (long double)3);\n  ASSERT(5, (long double)3+2);\n  ASSERT(6, (long double)3*2);\n  ASSERT(5, (long double)3+2.0);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/asm.c",
    "content": "#include \"test.h\"\n\nchar *asm_fn1(void) {\n  asm(\"mov $50, %rax\\n\\t\"\n      \"mov %rbp, %rsp\\n\\t\"\n      \"pop %rbp\\n\\t\"\n      \"ret\");\n}\n\nchar *asm_fn2(void) {\n  asm inline volatile(\"mov $55, %rax\\n\\t\"\n                      \"mov %rbp, %rsp\\n\\t\"\n                      \"pop %rbp\\n\\t\"\n                      \"ret\");\n}\n\nint main() {\n  ASSERT(50, asm_fn1());\n  ASSERT(55, asm_fn2());\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/atomic.c",
    "content": "#include \"test.h\"\n#include <stdatomic.h>\n#include <pthread.h>\n\nstatic int incr(_Atomic int *p) {\n  int oldval = *p;\n  int newval;\n  do {\n    newval = oldval + 1;\n  } while (!atomic_compare_exchange_weak(p, &oldval, newval));\n  return newval;\n}\n\nstatic int add1(void *arg) {\n  _Atomic int *x = arg;\n  for (int i = 0; i < 1000*1000; i++)\n    incr(x);\n  return 0;\n}\n\nstatic int add2(void *arg) {\n  _Atomic int *x = arg;\n  for (int i = 0; i < 1000*1000; i++)\n    (*x)++;\n  return 0;\n}\n\nstatic int add3(void *arg) {\n  _Atomic int *x = arg;\n  for (int i = 0; i < 1000*1000; i++)\n    *x += 5;\n  return 0;\n}\n\nstatic int add_millions(void) {\n  _Atomic int x = 0;\n\n  pthread_t thr1;\n  pthread_t thr2;\n  pthread_t thr3;\n\n  pthread_create(&thr1, NULL, add1, &x);\n  pthread_create(&thr2, NULL, add2, &x);\n  pthread_create(&thr3, NULL, add3, &x);\n\n  for (int i = 0; i < 1000*1000; i++)\n    x--;\n\n  pthread_join(thr1, NULL);\n  pthread_join(thr2, NULL);\n  pthread_join(thr3, NULL);\n  return x;\n}\n\nint main() {\n  ASSERT(6*1000*1000, add_millions());\n\n  ASSERT(3, ({ int x=3; atomic_exchange(&x, 5); }));\n  ASSERT(5, ({ int x=3; atomic_exchange(&x, 5); x; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/attribute.c",
    "content": "#include \"test.h\"\n#include \"stddef.h\"\n\nint main() {\n  ASSERT(5, ({ struct { char a; int b; } __attribute__((packed)) x; sizeof(x); }));\n  ASSERT(0, offsetof(struct __attribute__((packed)) { char a; int b; }, a));\n  ASSERT(1, offsetof(struct __attribute__((packed)) { char a; int b; }, b));\n\n  ASSERT(5, ({ struct __attribute__((packed)) { char a; int b; } x; sizeof(x); }));\n  ASSERT(0, offsetof(struct { char a; int b; } __attribute__((packed)), a));\n  ASSERT(1, offsetof(struct { char a; int b; } __attribute__((packed)), b));\n\n  ASSERT(9, ({ typedef struct { char a; int b[2]; } __attribute__((packed)) T; sizeof(T); }));\n  ASSERT(9, ({ typedef struct __attribute__((packed)) { char a; int b[2]; } T; sizeof(T); }));\n\n  ASSERT(1, offsetof(struct __attribute__((packed)) T { char a; int b[2]; }, b));\n  ASSERT(1, _Alignof(struct __attribute__((packed)) { char a; int b[2]; }));\n\n  ASSERT(8, ({ struct __attribute__((aligned(8))) { int a; } x; _Alignof(x); }));\n  ASSERT(8, ({ struct { int a; } __attribute__((aligned(8))) x; _Alignof(x); }));\n\n  ASSERT(8, ({ struct __attribute__((aligned(8), packed)) { char a; int b; } x; _Alignof(x); }));\n  ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8), packed)) x; _Alignof(x); }));\n  ASSERT(1, offsetof(struct __attribute__((aligned(8), packed)) { char a; int b; }, b));\n  ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8), packed)), b));\n\n  ASSERT(8, ({ struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; } x; _Alignof(x); }));\n  ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)) x; _Alignof(x); }));\n  ASSERT(1, offsetof(struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; }, b));\n  ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)), b));\n\n  ASSERT(8, ({ struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)) x; _Alignof(x); }));\n  ASSERT(1, offsetof(struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)), b));\n\n  ASSERT(16, ({ struct __attribute__((aligned(8+8))) { char a; int b; } x; _Alignof(x); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/bitfield.c",
    "content": "#include \"test.h\"\n\nstruct {\n  char a;\n  int b : 5;\n  int c : 10;\n} g45 = {1, 2, 3}, g46={};\n\nint main() {\n  ASSERT(4, sizeof(struct {int x:1; }));\n  ASSERT(8, sizeof(struct {long x:1; }));\n\n  struct bit1 {\n    short a;\n    char b;\n    int c : 2;\n    int d : 3;\n    int e : 3;\n  };\n\n  ASSERT(4, sizeof(struct bit1));\n  ASSERT(1, ({ struct bit1 x; x.a=1; x.b=2; x.c=3; x.d=4; x.e=5; x.a; }));\n  ASSERT(1, ({ struct bit1 x={1,2,3,4,5}; x.a; }));\n  ASSERT(2, ({ struct bit1 x={1,2,3,4,5}; x.b; }));\n  ASSERT(-1, ({ struct bit1 x={1,2,3,4,5}; x.c; }));\n  ASSERT(-4, ({ struct bit1 x={1,2,3,4,5}; x.d; }));\n  ASSERT(-3, ({ struct bit1 x={1,2,3,4,5}; x.e; }));\n\n  ASSERT(1, g45.a);\n  ASSERT(2, g45.b);\n  ASSERT(3, g45.c);\n\n  ASSERT(0, g46.a);\n  ASSERT(0, g46.b);\n  ASSERT(0, g46.c);\n\n  typedef struct {\n    int a : 10;\n    int b : 10;\n    int c : 10;\n  } T3;\n\n  ASSERT(1, ({ T3 x={1,2,3}; x.a++; }));\n  ASSERT(2, ({ T3 x={1,2,3}; x.b++; }));\n  ASSERT(3, ({ T3 x={1,2,3}; x.c++; }));\n\n  ASSERT(2, ({ T3 x={1,2,3}; ++x.a; }));\n  ASSERT(3, ({ T3 x={1,2,3}; ++x.b; }));\n  ASSERT(4, ({ T3 x={1,2,3}; ++x.c; }));\n\n  ASSERT(4, sizeof(struct {int a:3; int c:1; int c:5;}));\n  ASSERT(8, sizeof(struct {int a:3; int:0; int c:5;}));\n  ASSERT(4, sizeof(struct {int a:3; int:0;}));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/builtin.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(1, __builtin_types_compatible_p(int, int));\n  ASSERT(1, __builtin_types_compatible_p(double, double));\n  ASSERT(0, __builtin_types_compatible_p(int, long));\n  ASSERT(0, __builtin_types_compatible_p(long, float));\n  ASSERT(1, __builtin_types_compatible_p(int *, int *));\n  ASSERT(0, __builtin_types_compatible_p(short *, int *));\n  ASSERT(0, __builtin_types_compatible_p(int **, int *));\n  ASSERT(1, __builtin_types_compatible_p(const int, int));\n  ASSERT(0, __builtin_types_compatible_p(unsigned, int));\n  ASSERT(1, __builtin_types_compatible_p(signed, int));\n  ASSERT(0, __builtin_types_compatible_p(struct {int a;}, struct {int a;}));\n\n  ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void)));\n  ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int)));\n  ASSERT(1, __builtin_types_compatible_p(void (*)(int, double), void (*)(int, double)));\n  ASSERT(1, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double)));\n  ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int));\n  ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float)));\n  ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double, int)));\n  ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...)));\n  ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void)));\n\n  ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, T); }));\n  ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, const T); }));\n\n  ASSERT(1, ({ struct {int a; int b;} x; __builtin_types_compatible_p(typeof(x.a), typeof(x.b)); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/cast.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(131585, (int)8590066177);\n  ASSERT(513, (short)8590066177);\n  ASSERT(1, (char)8590066177);\n  ASSERT(1, (long)1);\n  ASSERT(0, (long)&*(int *)0);\n  ASSERT(513, ({ int x=512; *(char *)&x=1; x; }));\n  ASSERT(5, ({ int x=5; long y=(long)&x; *(int*)y; }));\n\n  (void)1;\n\n  ASSERT(-1, (char)255);\n  ASSERT(-1, (signed char)255);\n  ASSERT(255, (unsigned char)255);\n  ASSERT(-1, (short)65535);\n  ASSERT(65535, (unsigned short)65535);\n  ASSERT(-1, (int)0xffffffff);\n  ASSERT(0xffffffff, (unsigned)0xffffffff);\n\n  ASSERT(1, -1<1);\n  ASSERT(0, -1<(unsigned)1);\n  ASSERT(254, (char)127+(char)127);\n  ASSERT(65534, (short)32767+(short)32767);\n  ASSERT(-1, -1>>1);\n  ASSERT(-1, (unsigned long)-1);\n  ASSERT(2147483647, ((unsigned)-1)>>1);\n  ASSERT(-50, (-100)/2);\n  ASSERT(2147483598, ((unsigned)-100)/2);\n  ASSERT(9223372036854775758, ((unsigned long)-100)/2);\n  ASSERT(0, ((long)-1)/(unsigned)100);\n  ASSERT(-2, (-100)%7);\n  ASSERT(2, ((unsigned)-100)%7);\n  ASSERT(6, ((unsigned long)-100)%9);\n\n  ASSERT(65535, (int)(unsigned short)65535);\n  ASSERT(65535, ({ unsigned short x = 65535; x; }));\n  ASSERT(65535, ({ unsigned short x = 65535; (int)x; }));\n\n  ASSERT(-1, ({ typedef short T; T x = 65535; (int)x; }));\n  ASSERT(65535, ({ typedef unsigned short T; T x = 65535; (int)x; }));\n\n  ASSERT(0, (_Bool)0.0);\n  ASSERT(1, (_Bool)0.1);\n  ASSERT(3, (char)3.0);\n  ASSERT(1000, (short)1000.3);\n  ASSERT(3, (int)3.99);\n  ASSERT(2000000000000000, (long)2e15);\n  ASSERT(3, (float)3.5);\n  ASSERT(5, (double)(float)5.5);\n  ASSERT(3, (float)3);\n  ASSERT(3, (double)3);\n  ASSERT(3, (float)3L);\n  ASSERT(3, (double)3L);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/common",
    "content": "#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nvoid assert(int expected, int actual, char *code) {\n  if (expected == actual) {\n    printf(\"%s => %d\\n\", code, actual);\n  } else {\n    printf(\"%s => %d expected but got %d\\n\", code, expected, actual);\n    exit(1);\n  }\n}\n\nstatic int static_fn() { return 5; }\nint ext1 = 5;\nint *ext2 = &ext1;\nint ext3 = 7;\nint ext_fn1(int x) { return x; }\nint ext_fn2(int x) { return x; }\nint common_ext2 = 3;\nstatic int common_local;\n\nint false_fn() { return 512; }\nint true_fn() { return 513; }\nint char_fn() { return (2<<8)+3; }\nint short_fn() { return (2<<16)+5; }\n\nint uchar_fn() { return (2<<10)-1-4; }\nint ushort_fn() { return (2<<20)-1-7; }\n\nint schar_fn() { return (2<<10)-1-4; }\nint sshort_fn() { return (2<<20)-1-7; }\n\nint add_all(int n, ...) {\n  va_list ap;\n  va_start(ap, n);\n\n  int sum = 0;\n  for (int i = 0; i < n; i++)\n    sum += va_arg(ap, int);\n  return sum;\n}\n\nfloat add_float(float x, float y) {\n  return x + y;\n}\n\ndouble add_double(double x, double y) {\n  return x + y;\n}\n\nint add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10) {\n  return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;\n}\n\nfloat add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10) {\n  return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;\n}\n\ndouble add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10) {\n  return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;\n}\n\ntypedef struct { int a,b; short c; char d; } Ty4;\ntypedef struct { int a; float b; double c; } Ty5;\ntypedef struct { unsigned char a[3]; } Ty6;\ntypedef struct { long a, b, c; } Ty7;\n\nint struct_test4(Ty4 x, int n) {\n  switch (n) {\n  case 0: return x.a;\n  case 1: return x.b;\n  case 2: return x.c;\n  default: return x.d;\n  }\n}\n\nint struct_test5(Ty5 x, int n) {\n  switch (n) {\n  case 0: return x.a;\n  case 1: return x.b;\n  default: return x.c;\n  }\n}\n\nint struct_test6(Ty6 x, int n) {\n  return x.a[n];\n}\n\nint struct_test7(Ty7 x, int n) {\n  switch (n) {\n  case 0: return x.a;\n  case 1: return x.b;\n  default: return x.c;\n  }\n}\n\nTy4 struct_test24(void) {\n  return (Ty4){10, 20, 30, 40};\n}\n\nTy5 struct_test25(void) {\n  return (Ty5){10, 20, 30};\n}\n\nTy6 struct_test26(void) {\n  return (Ty6){10, 20, 30};\n}\n\ntypedef struct { unsigned char a[10]; } Ty20;\ntypedef struct { unsigned char a[20]; } Ty21;\n\nTy20 struct_test27(void) {\n  return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};\n}\n\nTy21 struct_test28(void) {\n  return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};\n}\n"
  },
  {
    "path": "test/commonsym.c",
    "content": "#include \"test.h\"\n\nint x;\nint x = 5;\nint y = 7;\nint y;\nint common_ext1;\nint common_ext2;\nstatic int common_local;\n\nint main() {\n  ASSERT(5, x);\n  ASSERT(7, y);\n  ASSERT(0, common_ext1);\n  ASSERT(3, common_ext2);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/compat.c",
    "content": "#include \"test.h\"\n\n_Noreturn noreturn_fn(int restrict x) {\n  exit(0);\n}\n\nvoid funcy_type(int arg[restrict static 3]) {}\n\nint main() {\n  { volatile x; }\n  { int volatile x; }\n  { volatile int x; }\n  { volatile int volatile volatile x; }\n  { int volatile * volatile volatile x; }\n  { auto ** restrict __restrict __restrict__ const volatile *x; }\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/complit.c",
    "content": "#include \"test.h\"\n\ntypedef struct Tree {\n  int val;\n  struct Tree *lhs;\n  struct Tree *rhs;\n} Tree;\n\nTree *tree = &(Tree){\n  1,\n  &(Tree){\n    2,\n    &(Tree){ 3, 0, 0 },\n    &(Tree){ 4, 0, 0 }\n  },\n  0\n};\n\nint main() {\n  ASSERT(1, (int){1});\n  ASSERT(2, ((int[]){0,1,2})[2]);\n  ASSERT('a', ((struct {char a; int b;}){'a', 3}).a);\n  ASSERT(3, ({ int x=3; (int){x}; }));\n  (int){3} = 5;\n\n  ASSERT(1, tree->val);\n  ASSERT(2, tree->lhs->val);\n  ASSERT(3, tree->lhs->lhs->val);\n  ASSERT(4, tree->lhs->rhs->val);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/const.c",
    "content": "#include \"test.h\"\n\nint main() {\n  { const x; }\n  { int const x; }\n  { const int x; }\n  { const int const const x; }\n  ASSERT(5, ({ const x = 5; x; }));\n  ASSERT(8, ({ const x = 8; int *const y=&x; *y; }));\n  ASSERT(6, ({ const x = 6; *(const * const)&x; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/constexpr.c",
    "content": "#include \"test.h\"\n\nfloat g40 = 1.5;\ndouble g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0);\n\nint main() {\n  ASSERT(10, ({ enum { ten=1+2+3+4 }; ten; }));\n  ASSERT(1, ({ int i=0; switch(3) { case 5-2+0*3: i++; } i; }));\n  ASSERT(8, ({ int x[1+1]; sizeof(x); }));\n  ASSERT(6, ({ char x[8-2]; sizeof(x); }));\n  ASSERT(6, ({ char x[2*3]; sizeof(x); }));\n  ASSERT(3, ({ char x[12/4]; sizeof(x); }));\n  ASSERT(2, ({ char x[12%10]; sizeof(x); }));\n  ASSERT(0b100, ({ char x[0b110&0b101]; sizeof(x); }));\n  ASSERT(0b111, ({ char x[0b110|0b101]; sizeof(x); }));\n  ASSERT(0b110, ({ char x[0b111^0b001]; sizeof(x); }));\n  ASSERT(4, ({ char x[1<<2]; sizeof(x); }));\n  ASSERT(2, ({ char x[4>>1]; sizeof(x); }));\n  ASSERT(2, ({ char x[(1==1)+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(1!=1)+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(1<1)+1]; sizeof(x); }));\n  ASSERT(2, ({ char x[(1<=1)+1]; sizeof(x); }));\n  ASSERT(2, ({ char x[1?2:3]; sizeof(x); }));\n  ASSERT(3, ({ char x[0?2:3]; sizeof(x); }));\n  ASSERT(3, ({ char x[(1,3)]; sizeof(x); }));\n  ASSERT(2, ({ char x[!0+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[!1+1]; sizeof(x); }));\n  ASSERT(2, ({ char x[~-3]; sizeof(x); }));\n  ASSERT(2, ({ char x[(5||6)+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(0||0)+1]; sizeof(x); }));\n  ASSERT(2, ({ char x[(1&&1)+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(1&&0)+1]; sizeof(x); }));\n  ASSERT(3, ({ char x[(int)3]; sizeof(x); }));\n  ASSERT(15, ({ char x[(char)0xffffff0f]; sizeof(x); }));\n  ASSERT(0x10f, ({ char x[(short)0xffff010f]; sizeof(x); }));\n  ASSERT(4, ({ char x[(int)0xfffffffffff+5]; sizeof(x); }));\n  ASSERT(8, ({ char x[(int*)0+2]; sizeof(x); }));\n  ASSERT(12, ({ char x[(int*)16-1]; sizeof(x); }));\n  ASSERT(3, ({ char x[(int*)16-(int*)4]; sizeof(x); }));\n\n  ASSERT(4, ({ char x[(-1>>31)+5]; sizeof(x); }));\n  ASSERT(255, ({ char x[(unsigned char)0xffffffff]; sizeof(x); }));\n  ASSERT(0x800f, ({ char x[(unsigned short)0xffff800f]; sizeof(x); }));\n  ASSERT(1, ({ char x[(unsigned int)0xfffffffffff>>31]; sizeof(x); }));\n  ASSERT(1, ({ char x[(long)-1/((long)1<<62)+1]; sizeof(x); }));\n  ASSERT(4, ({ char x[(unsigned long)-1/((long)1<<62)+1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(unsigned)1<-1]; sizeof(x); }));\n  ASSERT(1, ({ char x[(unsigned)1<=-1]; sizeof(x); }));\n\n  ASSERT(1, g40==1.5);\n  ASSERT(1, g41==11);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/control.c",
    "content": "#include \"test.h\"\n\n/*\n * This is a block comment.\n */\n\nint main() {\n  ASSERT(3, ({ int x; if (0) x=2; else x=3; x; }));\n  ASSERT(3, ({ int x; if (1-1) x=2; else x=3; x; }));\n  ASSERT(2, ({ int x; if (1) x=2; else x=3; x; }));\n  ASSERT(2, ({ int x; if (2-1) x=2; else x=3; x; }));\n\n  ASSERT(55, ({ int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; j; }));\n\n  ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; }));\n\n  ASSERT(3, ({ 1; {2;} 3; }));\n  ASSERT(5, ({ ;;; 5; }));\n\n  ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; }));\n  ASSERT(55, ({ int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} j; }));\n\n  ASSERT(3, (1,2,3));\n  ASSERT(5, ({ int i=2, j=3; (i=5,j)=6; i; }));\n  ASSERT(6, ({ int i=2, j=3; (i=5,j)=6; j; }));\n\n  ASSERT(55, ({ int j=0; for (int i=0; i<=10; i=i+1) j=j+i; j; }));\n  ASSERT(3, ({ int i=3; int j=0; for (int i=0; i<=10; i=i+1) j=j+i; i; }));\n\n  ASSERT(1, 0||1);\n  ASSERT(1, 0||(2-2)||5);\n  ASSERT(0, 0||0);\n  ASSERT(0, 0||(2-2));\n\n  ASSERT(0, 0&&1);\n  ASSERT(0, (2-2)&&5);\n  ASSERT(1, 1&&5);\n\n  ASSERT(3, ({ int i=0; goto a; a: i++; b: i++; c: i++; i; }));\n  ASSERT(2, ({ int i=0; goto e; d: i++; e: i++; f: i++; i; }));\n  ASSERT(1, ({ int i=0; goto i; g: i++; h: i++; i: i++; i; }));\n\n  ASSERT(1, ({ typedef int foo; goto foo; foo:; 1; }));\n\n  ASSERT(3, ({ int i=0; for(;i<10;i++) { if (i == 3) break; } i; }));\n  ASSERT(4, ({ int i=0; while (1) { if (i++ == 3) break; } i; }));\n  ASSERT(3, ({ int i=0; for(;i<10;i++) { for (;;) break; if (i == 3) break; } i; }));\n  ASSERT(4, ({ int i=0; while (1) { while(1) break; if (i++ == 3) break; } i; }));\n\n  ASSERT(10, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } i; }));\n  ASSERT(6, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } j; }));\n  ASSERT(10, ({ int i=0; int j=0; for(;!i;) { for (;j!=10;j++) continue; break; } j; }));\n  ASSERT(11, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } i; }));\n  ASSERT(5, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } j; }));\n  ASSERT(11, ({ int i=0; int j=0; while(!i) { while (j++!=10) continue; break; } j; }));\n\n  ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; }));\n  ASSERT(6, ({ int i=0; switch(1) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; }));\n  ASSERT(7, ({ int i=0; switch(2) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; }));\n  ASSERT(0, ({ int i=0; switch(3) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; }));\n  ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; default:i=7; } i; }));\n  ASSERT(7, ({ int i=0; switch(1) { case 0:i=5;break; default:i=7; } i; }));\n  ASSERT(2, ({ int i=0; switch(1) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; }));\n  ASSERT(0, ({ int i=0; switch(3) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; }));\n\n  ASSERT(3, ({ int i=0; switch(-1) { case 0xffffffff: i=3; break; } i; }));\n\n  ASSERT(7, ({ int i=0; int j=0; do { j++; } while (i++ < 6); j; }));\n  ASSERT(4, ({ int i=0; int j=0; int k=0; do { if (++j > 3) break; continue; k++; } while (1); j; }));\n\n  ASSERT(0, 0.0 && 0.0);\n  ASSERT(0, 0.0 && 0.1);\n  ASSERT(0, 0.3 && 0.0);\n  ASSERT(1, 0.3 && 0.5);\n  ASSERT(0, 0.0 || 0.0);\n  ASSERT(1, 0.0 || 0.1);\n  ASSERT(1, 0.3 || 0.0);\n  ASSERT(1, 0.3 || 0.5);\n  ASSERT(5, ({ int x; if (0.0) x=3; else x=5; x; }));\n  ASSERT(3, ({ int x; if (0.1) x=3; else x=5; x; }));\n  ASSERT(5, ({ int x=5; if (0.0) x=3; x; }));\n  ASSERT(3, ({ int x=5; if (0.1) x=3; x; }));\n  ASSERT(10, ({ double i=10.0; int j=0; for (; i; i--, j++); j; }));\n  ASSERT(10, ({ double i=10.0; int j=0; do j++; while(--i); j; }));\n\n  ASSERT(2, ({ int i=0; switch(7) { case 0 ... 5: i=1; break; case 6 ... 20: i=2; break; } i; }));\n  ASSERT(1, ({ int i=0; switch(7) { case 0 ... 7: i=1; break; case 8 ... 10: i=2; break; } i; }));\n  ASSERT(1, ({ int i=0; switch(7) { case 0: i=1; break; case 7 ... 7: i=1; break; } i; }));\n\n  ASSERT(3, ({ void *p = &&v11; int i=0; goto *p; v11:i++; v12:i++; v13:i++; i; }));\n  ASSERT(2, ({ void *p = &&v22; int i=0; goto *p; v21:i++; v22:i++; v23:i++; i; }));\n  ASSERT(1, ({ void *p = &&v33; int i=0; goto *p; v31:i++; v32:i++; v33:i++; i; }));\n\n  ASSERT(3, ({ static void *p[]={&&v41,&&v42,&&v43}; int i=0; goto *p[0]; v41:i++; v42:i++; v43:i++; i; }));\n  ASSERT(2, ({ static void *p[]={&&v52,&&v52,&&v53}; int i=0; goto *p[1]; v51:i++; v52:i++; v53:i++; i; }));\n  ASSERT(1, ({ static void *p[]={&&v62,&&v62,&&v63}; int i=0; goto *p[2]; v61:i++; v62:i++; v63:i++; i; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/decl.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(1, ({ char x; sizeof(x); }));\n  ASSERT(2, ({ short int x; sizeof(x); }));\n  ASSERT(2, ({ int short x; sizeof(x); }));\n  ASSERT(4, ({ int x; sizeof(x); }));\n  ASSERT(8, ({ long int x; sizeof(x); }));\n  ASSERT(8, ({ int long x; sizeof(x); }));\n\n  ASSERT(8, ({ long long x; sizeof(x); }));\n\n  ASSERT(0, ({ _Bool x=0; x; }));\n  ASSERT(1, ({ _Bool x=1; x; }));\n  ASSERT(1, ({ _Bool x=2; x; }));\n  ASSERT(1, (_Bool)1);\n  ASSERT(1, (_Bool)2);\n  ASSERT(0, (_Bool)(char)256);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/driver.sh",
    "content": "#!/bin/bash\nchibicc=$1\n\ntmp=`mktemp -d /tmp/chibicc-test-XXXXXX`\ntrap 'rm -rf $tmp' INT TERM HUP EXIT\necho > $tmp/empty.c\n\ncheck() {\n    if [ $? -eq 0 ]; then\n        echo \"testing $1 ... passed\"\n    else\n        echo \"testing $1 ... failed\"\n        exit 1\n    fi\n}\n\n# -o\nrm -f $tmp/out\n./chibicc -c -o $tmp/out $tmp/empty.c\n[ -f $tmp/out ]\ncheck -o\n\n# --help\n$chibicc --help 2>&1 | grep -q chibicc\ncheck --help\n\n# -S\necho 'int main() {}' | $chibicc -S -o- -xc - | grep -q 'main:'\ncheck -S\n\n# Default output file\nrm -f $tmp/out.o $tmp/out.s\necho 'int main() {}' > $tmp/out.c\n(cd $tmp; $OLDPWD/$chibicc -c out.c)\n[ -f $tmp/out.o ]\ncheck 'default output file'\n\n(cd $tmp; $OLDPWD/$chibicc -c -S out.c)\n[ -f $tmp/out.s ]\ncheck 'default output file'\n\n# Multiple input files\nrm -f $tmp/foo.o $tmp/bar.o\necho 'int x;' > $tmp/foo.c\necho 'int y;' > $tmp/bar.c\n(cd $tmp; $OLDPWD/$chibicc -c $tmp/foo.c $tmp/bar.c)\n[ -f $tmp/foo.o ] && [ -f $tmp/bar.o ]\ncheck 'multiple input files'\n\nrm -f $tmp/foo.s $tmp/bar.s\necho 'int x;' > $tmp/foo.c\necho 'int y;' > $tmp/bar.c\n(cd $tmp; $OLDPWD/$chibicc -c -S $tmp/foo.c $tmp/bar.c)\n[ -f $tmp/foo.s ] && [ -f $tmp/bar.s ]\ncheck 'multiple input files'\n\n# Run linker\nrm -f $tmp/foo\necho 'int main() { return 0; }' | $chibicc -o $tmp/foo -xc -xc -\n$tmp/foo\ncheck linker\n\nrm -f $tmp/foo\necho 'int bar(); int main() { return bar(); }' > $tmp/foo.c\necho 'int bar() { return 42; }' > $tmp/bar.c\n$chibicc -o $tmp/foo $tmp/foo.c $tmp/bar.c\n$tmp/foo\n[ \"$?\" = 42 ]\ncheck linker\n\n# a.out\nrm -f $tmp/a.out\necho 'int main() {}' > $tmp/foo.c\n(cd $tmp; $OLDPWD/$chibicc foo.c)\n[ -f $tmp/a.out ]\ncheck a.out\n\n# -E\necho foo > $tmp/out\necho \"#include \\\"$tmp/out\\\"\" | $chibicc -E -xc - | grep -q foo\ncheck -E\n\necho foo > $tmp/out1\necho \"#include \\\"$tmp/out1\\\"\" | $chibicc -E -o $tmp/out2 -xc -\ncat $tmp/out2 | grep -q foo\ncheck '-E and -o'\n\n# -I\nmkdir $tmp/dir\necho foo > $tmp/dir/i-option-test\necho \"#include \\\"i-option-test\\\"\" | $chibicc -I$tmp/dir -E -xc - | grep -q foo\ncheck -I\n\n# -D\necho foo | $chibicc -Dfoo -E -xc - | grep -q 1\ncheck -D\n\n# -D\necho foo | $chibicc -Dfoo=bar -E -xc - | grep -q bar\ncheck -D\n\n# -U\necho foo | $chibicc -Dfoo=bar -Ufoo -E -xc - | grep -q foo\ncheck -U\n\n# ignored options\n$chibicc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \\\n         -fno-omit-frame-pointer -fno-stack-protector -fno-strict-aliasing \\\n         -m64 -mno-red-zone -w -o /dev/null $tmp/empty.c\ncheck 'ignored options'\n\n# BOM marker\nprintf '\\xef\\xbb\\xbfxyz\\n' | $chibicc -E -o- -xc - | grep -q '^xyz'\ncheck 'BOM marker'\n\n# Inline functions\necho 'inline void foo() {}' > $tmp/inline1.c\necho 'inline void foo() {}' > $tmp/inline2.c\necho 'int main() { return 0; }' > $tmp/inline3.c\n$chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c $tmp/inline3.c\ncheck inline\n\necho 'extern inline void foo() {}' > $tmp/inline1.c\necho 'int foo(); int main() { foo(); }' > $tmp/inline2.c\n$chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c\ncheck inline\n\necho 'static inline void f1() {}' | $chibicc -o- -S -xc - | grep -v -q f1:\ncheck inline\n\necho 'static inline void f1() {} void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1:\ncheck inline\n\necho 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1:\ncheck inline\n\necho 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -v -q f2:\ncheck inline\n\necho 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1:\ncheck inline\n\necho 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f1:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $chibicc -o- -S -xc - | grep -v -q f2:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f1:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $chibicc -o- -S -xc - | grep -q f2:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f1:\ncheck inline\n\necho 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $chibicc -o- -S -xc - | grep -q f2:\ncheck inline\n\n# -idirafter\nmkdir -p $tmp/dir1 $tmp/dir2\necho foo > $tmp/dir1/idirafter\necho bar > $tmp/dir2/idirafter\necho \"#include \\\"idirafter\\\"\" | $chibicc -I$tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q foo\ncheck -idirafter\necho \"#include \\\"idirafter\\\"\" | $chibicc -idirafter $tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q bar\ncheck -idirafter\n\n# -fcommon\necho 'int foo;' | $chibicc -S -o- -xc - | grep -q '\\.comm foo'\ncheck '-fcommon (default)'\n\necho 'int foo;' | $chibicc -fcommon -S -o- -xc - | grep -q '\\.comm foo'\ncheck '-fcommon'\n\n# -fno-common\necho 'int foo;' | $chibicc -fno-common -S -o- -xc - | grep -q '^foo:'\ncheck '-fno-common'\n\n# -include\necho foo > $tmp/out.h\necho bar | $chibicc -include $tmp/out.h -E -o- -xc - | grep -q -z 'foo.*bar'\ncheck -include\necho NULL | $chibicc -Iinclude -include stdio.h -E -o- -xc - | grep -q 0\ncheck -include\n\n# -x\necho 'int x;' | $chibicc -c -xc -o $tmp/foo.o -\ncheck -xc\necho 'x:' | $chibicc -c -x assembler -o $tmp/foo.o -\ncheck '-x assembler'\n\necho 'int x;' > $tmp/foo.c\n$chibicc -c -x assembler -x none -o $tmp/foo.o $tmp/foo.c\ncheck '-x none'\n\n# -E\necho foo | $chibicc -E - | grep -q foo\ncheck -E\n\n# .a file\necho 'void foo() {}' | $chibicc -c -xc -o $tmp/foo.o -\necho 'void bar() {}' | $chibicc -c -xc -o $tmp/bar.o -\nar rcs $tmp/foo.a $tmp/foo.o $tmp/bar.o\necho 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c\n$chibicc -o $tmp/foo $tmp/main.c $tmp/foo.a\ncheck '.a'\n\n# .so file\necho 'void foo() {}' | cc -fPIC -c -xc -o $tmp/foo.o -\necho 'void bar() {}' | cc -fPIC -c -xc -o $tmp/bar.o -\ncc -shared -o $tmp/foo.so $tmp/foo.o $tmp/bar.o\necho 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c\n$chibicc -o $tmp/foo $tmp/main.c $tmp/foo.so\ncheck '.so'\n\n$chibicc -hashmap-test\ncheck 'hashmap'\n\n# -M\necho '#include \"out2.h\"' > $tmp/out.c\necho '#include \"out3.h\"' >> $tmp/out.c\ntouch $tmp/out2.h $tmp/out3.h\n$chibicc -M -I$tmp $tmp/out.c | grep -q -z '^out.o: .*/out\\.c .*/out2\\.h .*/out3\\.h'\ncheck -M\n\n# -MF\n$chibicc -MF $tmp/mf -M -I$tmp $tmp/out.c\ngrep -q -z '^out.o: .*/out\\.c .*/out2\\.h .*/out3\\.h' $tmp/mf\ncheck -MF\n\n# -MP\n$chibicc -MF $tmp/mp -MP -M -I$tmp $tmp/out.c\ngrep -q '^.*/out2.h:' $tmp/mp\ncheck -MP\ngrep -q '^.*/out3.h:' $tmp/mp\ncheck -MP\n\n# -MT\n$chibicc -MT foo -M -I$tmp $tmp/out.c | grep -q '^foo:'\ncheck -MT\n$chibicc -MT foo -MT bar -M -I$tmp $tmp/out.c | grep -q '^foo bar:'\ncheck -MT\n\n# -MD\necho '#include \"out2.h\"' > $tmp/md2.c\necho '#include \"out3.h\"' > $tmp/md3.c\n(cd $tmp; $OLDPWD/$chibicc -c -MD -I. md2.c md3.c)\ngrep -q -z '^md2.o:.* md2\\.c .* ./out2\\.h' $tmp/md2.d\ncheck -MD\ngrep -q -z '^md3.o:.* md3\\.c .* ./out3\\.h' $tmp/md3.d\ncheck -MD\n\n$chibicc -c -MD -MF $tmp/md-mf.d -I. $tmp/md2.c\ngrep -q -z '^md2.o:.*md2\\.c .*/out2\\.h' $tmp/md-mf.d\ncheck -MD\n\necho 'extern int bar; int foo() { return bar; }' | $chibicc -fPIC -xc -c -o $tmp/foo.o -\ncc -shared -o $tmp/foo.so $tmp/foo.o\necho 'int foo(); int bar=3; int main() { foo(); }' > $tmp/main.c\n$chibicc -o $tmp/foo $tmp/main.c $tmp/foo.so\ncheck -fPIC\n\n# #include_next\nmkdir -p $tmp/next1 $tmp/next2 $tmp/next3\necho '#include \"file1.h\"' > $tmp/file.c\necho '#include_next \"file1.h\"' > $tmp/next1/file1.h\necho '#include_next \"file2.h\"' > $tmp/next2/file1.h\necho 'foo' > $tmp/next3/file2.h\n$chibicc -I$tmp/next1 -I$tmp/next2 -I$tmp/next3 -E $tmp/file.c | grep -q foo\ncheck '#include_next'\n\n# -static\necho 'extern int bar; int foo() { return bar; }' > $tmp/foo.c\necho 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c\n$chibicc -static -o $tmp/foo $tmp/foo.c $tmp/bar.c\ncheck -static\nfile $tmp/foo | grep -q 'statically linked'\ncheck -static\n\n# -shared\necho 'extern int bar; int foo() { return bar; }' > $tmp/foo.c\necho 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c\n$chibicc -fPIC -shared -o $tmp/foo.so $tmp/foo.c $tmp/bar.c\ncheck -shared\n\n# -L\necho 'extern int bar; int foo() { return bar; }' > $tmp/foo.c\n$chibicc -fPIC -shared -o $tmp/libfoobar.so $tmp/foo.c\necho 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c\n$chibicc -o $tmp/foo $tmp/bar.c -L$tmp -lfoobar\ncheck -L\n\n# -Wl,\necho 'int foo() {}' | $chibicc -c -o $tmp/foo.o -xc -\necho 'int foo() {}' | $chibicc -c -o $tmp/bar.o -xc -\necho 'int main() {}' | $chibicc -c -o $tmp/baz.o -xc -\ncc -Wl,-z,muldefs,--gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o\ncheck -Wl,\n\n# -Xlinker\necho 'int foo() {}' | $chibicc -c -o $tmp/foo.o -xc -\necho 'int foo() {}' | $chibicc -c -o $tmp/bar.o -xc -\necho 'int main() {}' | $chibicc -c -o $tmp/baz.o -xc -\ncc -Xlinker -z -Xlinker muldefs -Xlinker --gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o\ncheck -Xlinker\n\necho OK\n"
  },
  {
    "path": "test/enum.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(0, ({ enum { zero, one, two }; zero; }));\n  ASSERT(1, ({ enum { zero, one, two }; one; }));\n  ASSERT(2, ({ enum { zero, one, two }; two; }));\n  ASSERT(5, ({ enum { five=5, six, seven }; five; }));\n  ASSERT(6, ({ enum { five=5, six, seven }; six; }));\n  ASSERT(0, ({ enum { zero, five=5, three=3, four }; zero; }));\n  ASSERT(5, ({ enum { zero, five=5, three=3, four }; five; }));\n  ASSERT(3, ({ enum { zero, five=5, three=3, four }; three; }));\n  ASSERT(4, ({ enum { zero, five=5, three=3, four }; four; }));\n  ASSERT(4, ({ enum { zero, one, two } x; sizeof(x); }));\n  ASSERT(4, ({ enum t { zero, one, two }; enum t y; sizeof(y); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/extern.c",
    "content": "#include \"test.h\"\n\nextern int ext1;\nextern int *ext2;\n\ninline int inline_fn(void) {\n  return 3;\n}\n\nint main() {\n  ASSERT(5, ext1);\n  ASSERT(5, *ext2);\n\n  extern int ext3;\n  ASSERT(7, ext3);\n\n  int ext_fn1(int x);\n  ASSERT(5, ext_fn1(5));\n\n  extern int ext_fn2(int x);\n  ASSERT(8, ext_fn2(8));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/float.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(35, (float)(char)35);\n  ASSERT(35, (float)(short)35);\n  ASSERT(35, (float)(int)35);\n  ASSERT(35, (float)(long)35);\n  ASSERT(35, (float)(unsigned char)35);\n  ASSERT(35, (float)(unsigned short)35);\n  ASSERT(35, (float)(unsigned int)35);\n  ASSERT(35, (float)(unsigned long)35);\n\n  ASSERT(35, (double)(char)35);\n  ASSERT(35, (double)(short)35);\n  ASSERT(35, (double)(int)35);\n  ASSERT(35, (double)(long)35);\n  ASSERT(35, (double)(unsigned char)35);\n  ASSERT(35, (double)(unsigned short)35);\n  ASSERT(35, (double)(unsigned int)35);\n  ASSERT(35, (double)(unsigned long)35);\n\n  ASSERT(35, (char)(float)35);\n  ASSERT(35, (short)(float)35);\n  ASSERT(35, (int)(float)35);\n  ASSERT(35, (long)(float)35);\n  ASSERT(35, (unsigned char)(float)35);\n  ASSERT(35, (unsigned short)(float)35);\n  ASSERT(35, (unsigned int)(float)35);\n  ASSERT(35, (unsigned long)(float)35);\n\n  ASSERT(35, (char)(double)35);\n  ASSERT(35, (short)(double)35);\n  ASSERT(35, (int)(double)35);\n  ASSERT(35, (long)(double)35);\n  ASSERT(35, (unsigned char)(double)35);\n  ASSERT(35, (unsigned short)(double)35);\n  ASSERT(35, (unsigned int)(double)35);\n  ASSERT(35, (unsigned long)(double)35);\n\n  ASSERT(-2147483648, (double)(unsigned long)(long)-1);\n\n  ASSERT(1, 2e3==2e3);\n  ASSERT(0, 2e3==2e5);\n  ASSERT(1, 2.0==2);\n  ASSERT(0, 5.1<5);\n  ASSERT(0, 5.0<5);\n  ASSERT(1, 4.9<5);\n  ASSERT(0, 5.1<=5);\n  ASSERT(1, 5.0<=5);\n  ASSERT(1, 4.9<=5);\n\n  ASSERT(1, 2e3f==2e3);\n  ASSERT(0, 2e3f==2e5);\n  ASSERT(1, 2.0f==2);\n  ASSERT(0, 5.1f<5);\n  ASSERT(0, 5.0f<5);\n  ASSERT(1, 4.9f<5);\n  ASSERT(0, 5.1f<=5);\n  ASSERT(1, 5.0f<=5);\n  ASSERT(1, 4.9f<=5);\n\n  ASSERT(6, 2.3+3.8);\n  ASSERT(-1, 2.3-3.8);\n  ASSERT(-3, -3.8);\n  ASSERT(13, 3.3*4);\n  ASSERT(2, 5.0/2);\n\n  ASSERT(6, 2.3f+3.8f);\n  ASSERT(6, 2.3f+3.8);\n  ASSERT(-1, 2.3f-3.8);\n  ASSERT(-3, -3.8f);\n  ASSERT(13, 3.3f*4);\n  ASSERT(2, 5.0f/2);\n\n  ASSERT(0, 0.0/0.0 == 0.0/0.0);\n  ASSERT(1, 0.0/0.0 != 0.0/0.0);\n\n  ASSERT(0, 0.0/0.0 < 0);\n  ASSERT(0, 0.0/0.0 <= 0);\n  ASSERT(0, 0.0/0.0 > 0);\n  ASSERT(0, 0.0/0.0 >= 0);\n\n  ASSERT(0, !3.);\n  ASSERT(1, !0.);\n  ASSERT(0, !3.f);\n  ASSERT(1, !0.f);\n\n  ASSERT(5, 0.0 ? 3 : 5);\n  ASSERT(3, 1.2 ? 3 : 5);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/function.c",
    "content": "#include \"test.h\"\n\nint ret3(void) {\n  return 3;\n  return 5;\n}\n\nint add2(int x, int y) {\n  return x + y;\n}\n\nint sub2(int x, int y) {\n  return x - y;\n}\n\nint add6(int a, int b, int c, int d, int e, int f) {\n  return a + b + c + d + e + f;\n}\n\nint addx(int *x, int y) {\n  return *x + y;\n}\n\nint sub_char(char a, char b, char c) {\n  return a - b - c;\n}\n\nint fib(int x) {\n  if (x<=1)\n    return 1;\n  return fib(x-1) + fib(x-2);\n}\n\nint sub_long(long a, long b, long c) {\n  return a - b - c;\n}\n\nint sub_short(short a, short b, short c) {\n  return a - b - c;\n}\n\nint g1;\n\nint *g1_ptr(void) { return &g1; }\nchar int_to_char(int x) { return x; }\n\nint div_long(long a, long b) {\n  return a / b;\n}\n\n_Bool bool_fn_add(_Bool x) { return x + 1; }\n_Bool bool_fn_sub(_Bool x) { return x - 1; }\n\nstatic int static_fn(void) { return 3; }\n\nint param_decay(int x[]) { return x[0]; }\n\nint counter() {\n  static int i;\n  static int j = 1+1;\n  return i++ + j++;\n}\n\nvoid ret_none() {\n  return;\n}\n\n_Bool true_fn();\n_Bool false_fn();\nchar char_fn();\nshort short_fn();\n\nunsigned char uchar_fn();\nunsigned short ushort_fn();\n\nchar schar_fn();\nshort sshort_fn();\n\nint add_all(int n, ...);\n\ntypedef struct {\n  int gp_offset;\n  int fp_offset;\n  void *overflow_arg_area;\n  void *reg_save_area;\n} __va_elem;\n\ntypedef __va_elem va_list[1];\n\nint add_all(int n, ...);\nint sprintf(char *buf, char *fmt, ...);\nint vsprintf(char *buf, char *fmt, va_list ap);\n\nchar *fmt(char *buf, char *fmt, ...) {\n  va_list ap;\n  *ap = *(__va_elem *)__va_area__;\n  vsprintf(buf, fmt, ap);\n}\n\ndouble add_double(double x, double y);\nfloat add_float(float x, float y);\n\nfloat add_float3(float x, float y, float z) {\n  return x + y + z;\n}\n\ndouble add_double3(double x, double y, double z) {\n  return x + y + z;\n}\n\nint (*fnptr(int (*fn)(int n, ...)))(int, ...) {\n  return fn;\n}\n\nint param_decay2(int x()) { return x(); }\n\nchar *func_fn(void) {\n  return __func__;\n}\n\nchar *function_fn(void) {\n  return __FUNCTION__;\n}\n\nint add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10);\nfloat add10_float(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10);\ndouble add10_double(double x1, double x2, double x3, double x4, double x5, double x6, double x7, double x8, double x9, double x10);\n\nint many_args1(int a, int b, int c, int d, int e, int f, int g, int h) {\n  return g / h;\n}\n\ndouble many_args2(double a, double b, double c, double d, double e,\n                  double f, double g, double h, double i, double j) {\n  return i / j;\n}\n\nint many_args3(int a, double b, int c, int d, double e, int f,\n               double g, int h, double i, double j, double k,\n               double l, double m, int n, int o, double p) {\n  return o / p;\n}\n\ntypedef struct { int a,b; short c; char d; } Ty4;\ntypedef struct { int a; float b; double c; } Ty5;\ntypedef struct { unsigned char a[3]; } Ty6;\ntypedef struct { long a, b, c; } Ty7;\n\nint struct_test5(Ty5 x, int n);\nint struct_test4(Ty4 x, int n);\nint struct_test6(Ty6 x, int n);\nint struct_test7(Ty7 x, int n);\n\nint struct_test14(Ty4 x, int n) {\n  switch (n) {\n  case 0: return x.a;\n  case 1: return x.b;\n  case 2: return x.c;\n  default: return x.d;\n  }\n}\n\nint struct_test15(Ty5 x, int n) {\n  switch (n) {\n  case 0: return x.a;\n  case 1: return x.b;\n  default: return x.c;\n  }\n}\n\ntypedef struct { unsigned char a[10]; } Ty20;\ntypedef struct { unsigned char a[20]; } Ty21;\n\nTy4 struct_test24(void);\nTy5 struct_test25(void);\nTy6 struct_test26(void);\nTy20 struct_test27(void);\nTy21 struct_test28(void);\n\nTy4 struct_test34(void) {\n  return (Ty4){10, 20, 30, 40};\n}\n\nTy5 struct_test35(void) {\n  return (Ty5){10, 20, 30};\n}\n\nTy6 struct_test36(void) {\n  return (Ty6){10, 20, 30};\n}\n\nTy20 struct_test37(void) {\n  return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};\n}\n\nTy21 struct_test38(void) {\n  return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};\n}\n\ninline int inline_fn(void) {\n  return 3;\n}\n\ndouble to_double(long double x) {\n  return x;\n}\n\nlong double to_ldouble(int x) {\n  return x;\n}\n\nint main() {\n  ASSERT(3, ret3());\n  ASSERT(8, add2(3, 5));\n  ASSERT(2, sub2(5, 3));\n  ASSERT(21, add6(1,2,3,4,5,6));\n  ASSERT(66, add6(1,2,add6(3,4,5,6,7,8),9,10,11));\n  ASSERT(136, add6(1,2,add6(3,add6(4,5,6,7,8,9),10,11,12,13),14,15,16));\n\n  ASSERT(7, add2(3,4));\n  ASSERT(1, sub2(4,3));\n  ASSERT(55, fib(9));\n\n  ASSERT(1, ({ sub_char(7, 3, 3); }));\n\n  ASSERT(1, sub_long(7, 3, 3));\n  ASSERT(1, sub_short(7, 3, 3));\n\n  g1 = 3;\n\n  ASSERT(3, *g1_ptr());\n  ASSERT(5, int_to_char(261));\n  ASSERT(5, int_to_char(261));\n  ASSERT(-5, div_long(-10, 2));\n\n  ASSERT(1, bool_fn_add(3));\n  ASSERT(0, bool_fn_sub(3));\n  ASSERT(1, bool_fn_add(-3));\n  ASSERT(0, bool_fn_sub(-3));\n  ASSERT(1, bool_fn_add(0));\n  ASSERT(1, bool_fn_sub(0));\n\n  ASSERT(3, static_fn());\n\n  ASSERT(3, ({ int x[2]; x[0]=3; param_decay(x); }));\n\n  ASSERT(2, counter());\n  ASSERT(4, counter());\n  ASSERT(6, counter());\n\n  ret_none();\n\n  ASSERT(1, true_fn());\n  ASSERT(0, false_fn());\n  ASSERT(3, char_fn());\n  ASSERT(5, short_fn());\n\n  ASSERT(6, add_all(3,1,2,3));\n  ASSERT(5, add_all(4,1,2,3,-1));\n\n  { char buf[100]; fmt(buf, \"%d %d %s\", 1, 2, \"foo\"); printf(\"%s\\n\", buf); }\n\n  ASSERT(0, ({ char buf[100]; sprintf(buf, \"%d %d %s\", 1, 2, \"foo\"); strcmp(\"1 2 foo\", buf); }));\n\n  ASSERT(0, ({ char buf[100]; fmt(buf, \"%d %d %s\", 1, 2, \"foo\"); strcmp(\"1 2 foo\", buf); }));\n\n  ASSERT(251, uchar_fn());\n  ASSERT(65528, ushort_fn());\n  ASSERT(-5, schar_fn());\n  ASSERT(-8, sshort_fn());\n\n  ASSERT(6, add_float(2.3, 3.8));\n  ASSERT(6, add_double(2.3, 3.8));\n\n  ASSERT(7, add_float3(2.5, 2.5, 2.5));\n  ASSERT(7, add_double3(2.5, 2.5, 2.5));\n\n  ASSERT(0, ({ char buf[100]; sprintf(buf, \"%.1f\", (float)3.5); strcmp(buf, \"3.5\"); }));\n\n  ASSERT(0, ({ char buf[100]; fmt(buf, \"%.1f\", (float)3.5); strcmp(buf, \"3.5\"); }));\n\n  ASSERT(5, (add2)(2,3));\n  ASSERT(5, (&add2)(2,3));\n  ASSERT(7, ({ int (*fn)(int,int) = add2; fn(2,5); }));\n  ASSERT(6, fnptr(add_all)(3, 1, 2, 3));\n\n  ASSERT(3, param_decay2(ret3));\n\n  ASSERT(5, sizeof(__func__));\n  ASSERT(0, strcmp(\"main\", __func__));\n  ASSERT(0, strcmp(\"func_fn\", func_fn()));\n  ASSERT(0, strcmp(\"main\", __FUNCTION__));\n  ASSERT(0, strcmp(\"function_fn\", function_fn()));\n\n\n  ASSERT(55, add10_int(1,2,3,4,5,6,7,8,9,10));\n  ASSERT(55, add10_float(1,2,3,4,5,6,7,8,9,10));\n  ASSERT(55, add10_double(1,2,3,4,5,6,7,8,9,10));\n\n  ASSERT(0, ({ char buf[200]; sprintf(buf, \"%d %.1f %.1f %.1f %d %d %.1f %d %d %d %d %.1f %d %d %.1f %.1f %.1f %.1f %d\", 1, 1.0, 1.0, 1.0, 1, 1, 1.0, 1, 1, 1, 1, 1.0, 1, 1, 1.0, 1.0, 1.0, 1.0, 1); strcmp(\"1 1.0 1.0 1.0 1 1 1.0 1 1 1 1 1.0 1 1 1.0 1.0 1.0 1.0 1\", buf); }));\n\n  ASSERT(4, many_args1(1,2,3,4,5,6,40,10));\n  ASSERT(4, many_args2(1,2,3,4,5,6,7,8,40,10));\n  ASSERT(8, many_args3(1,2,3,4,5,6,7,8,9,10,11,12,13,14,80,10));\n\n  ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test4(x, 0); }));\n  ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test4(x, 1); }));\n  ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test4(x, 2); }));\n  ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test4(x, 3); }));\n\n  ASSERT(10, ({ Ty5 x={10,20,30}; struct_test5(x, 0); }));\n  ASSERT(20, ({ Ty5 x={10,20,30}; struct_test5(x, 1); }));\n  ASSERT(30, ({ Ty5 x={10,20,30}; struct_test5(x, 2); }));\n\n  ASSERT(10, ({ Ty6 x={10,20,30}; struct_test6(x, 0); }));\n  ASSERT(20, ({ Ty6 x={10,20,30}; struct_test6(x, 1); }));\n  ASSERT(30, ({ Ty6 x={10,20,30}; struct_test6(x, 2); }));\n\n  ASSERT(10, ({ Ty7 x={10,20,30}; struct_test7(x, 0); }));\n  ASSERT(20, ({ Ty7 x={10,20,30}; struct_test7(x, 1); }));\n  ASSERT(30, ({ Ty7 x={10,20,30}; struct_test7(x, 2); }));\n\n  ASSERT(10, ({ Ty4 x={10,20,30,40}; struct_test14(x, 0); }));\n  ASSERT(20, ({ Ty4 x={10,20,30,40}; struct_test14(x, 1); }));\n  ASSERT(30, ({ Ty4 x={10,20,30,40}; struct_test14(x, 2); }));\n  ASSERT(40, ({ Ty4 x={10,20,30,40}; struct_test14(x, 3); }));\n\n  ASSERT(10, ({ Ty5 x={10,20,30}; struct_test15(x, 0); }));\n  ASSERT(20, ({ Ty5 x={10,20,30}; struct_test15(x, 1); }));\n  ASSERT(30, ({ Ty5 x={10,20,30}; struct_test15(x, 2); }));\n\n  ASSERT(10, struct_test24().a);\n  ASSERT(20, struct_test24().b);\n  ASSERT(30, struct_test24().c);\n  ASSERT(40, struct_test24().d);\n\n  ASSERT(10, struct_test25().a);\n  ASSERT(20, struct_test25().b);\n  ASSERT(30, struct_test25().c);\n\n  ASSERT(10, struct_test26().a[0]);\n  ASSERT(20, struct_test26().a[1]);\n  ASSERT(30, struct_test26().a[2]);\n\n  ASSERT(10, struct_test27().a[0]);\n  ASSERT(60, struct_test27().a[5]);\n  ASSERT(100, struct_test27().a[9]);\n\n  ASSERT(1, struct_test28().a[0]);\n  ASSERT(5, struct_test28().a[4]);\n  ASSERT(10, struct_test28().a[9]);\n  ASSERT(15, struct_test28().a[14]);\n  ASSERT(20, struct_test28().a[19]);\n\n  ASSERT(10, struct_test34().a);\n  ASSERT(20, struct_test34().b);\n  ASSERT(30, struct_test34().c);\n  ASSERT(40, struct_test34().d);\n\n  ASSERT(10, struct_test35().a);\n  ASSERT(20, struct_test35().b);\n  ASSERT(30, struct_test35().c);\n\n  ASSERT(10, struct_test36().a[0]);\n  ASSERT(20, struct_test36().a[1]);\n  ASSERT(30, struct_test36().a[2]);\n\n  ASSERT(10, struct_test37().a[0]);\n  ASSERT(60, struct_test37().a[5]);\n  ASSERT(100, struct_test37().a[9]);\n\n  ASSERT(1, struct_test38().a[0]);\n  ASSERT(5, struct_test38().a[4]);\n  ASSERT(10, struct_test38().a[9]);\n  ASSERT(15, struct_test38().a[14]);\n  ASSERT(20, struct_test38().a[19]);\n\n  ASSERT(5, (***add2)(2,3));\n\n  ASSERT(3, inline_fn());\n\n  ASSERT(0, ({ char buf[100]; sprintf(buf, \"%Lf\", (long double)12.3); strncmp(buf, \"12.3\", 4); }));\n\n  ASSERT(1, to_double(3.5) == 3.5);\n  ASSERT(0, to_double(3.5) == 3);\n\n  ASSERT(1, (long double)5.0 == (long double)5.0);\n  ASSERT(0, (long double)5.0 == (long double)5.2);\n\n  ASSERT(1, to_ldouble(5.0) == 5.0);\n  ASSERT(0, to_ldouble(5.0) == 5.2);\n\n  printf(\"OK\\n\");\n}\n"
  },
  {
    "path": "test/generic.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(1, _Generic(100.0, double: 1, int *: 2, int: 3, float: 4));\n  ASSERT(2, _Generic((int *)0, double: 1, int *: 2, int: 3, float: 4));\n  ASSERT(2, _Generic((int[3]){}, double: 1, int *: 2, int: 3, float: 4));\n  ASSERT(3, _Generic(100, double: 1, int *: 2, int: 3, float: 4));\n  ASSERT(4, _Generic(100f, double: 1, int *: 2, int: 3, float: 4));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/include1.h",
    "content": "#include \"include2.h\"\n\nchar *include1_filename = __FILE__;\nint include1_line = __LINE__;\n\nint include1 = 5;\n"
  },
  {
    "path": "test/include2.h",
    "content": "int include2 = 7;\n"
  },
  {
    "path": "test/include3.h",
    "content": "#define foo 3\n"
  },
  {
    "path": "test/include4.h",
    "content": "#define foo 4\n"
  },
  {
    "path": "test/initializer.c",
    "content": "#include \"test.h\"\n\nchar g3 = 3;\nshort g4 = 4;\nint g5 = 5;\nlong g6 = 6;\nint g9[3] = {0, 1, 2};\nstruct {char a; int b;} g11[2] = {{1, 2}, {3, 4}};\nstruct {int a[2];} g12[2] = {{{1, 2}}};\nunion { int a; char b[8]; } g13[2] = {0x01020304, 0x05060708};\nchar g17[] = \"foobar\";\nchar g18[10] = \"foobar\";\nchar g19[3] = \"foobar\";\nchar *g20 = g17+0;\nchar *g21 = g17+3;\nchar *g22 = &g17-3;\nchar *g23[] = {g17+0, g17+3, g17-3};\nint g24=3;\nint *g25=&g24;\nint g26[3] = {1, 2, 3};\nint *g27 = g26 + 1;\nint *g28 = &g11[1].a;\nlong g29 = (long)(long)g26;\nstruct { struct { int a[3]; } a; } g30 = {{{1,2,3}}};\nint *g31=g30.a.a;\nstruct {int a[2];} g40[2] = {{1, 2}, 3, 4};\nstruct {int a[2];} g41[2] = {1, 2, 3, 4};\nchar g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};\nchar *g44 = {\"foo\"};\nunion { int a; char b[4]; } g50 = {.b[2]=0x12};\nunion { int a; } g51[2] = {};\n\ntypedef char T60[];\nT60 g60 = {1, 2, 3};\nT60 g61 = {1, 2, 3, 4, 5, 6};\n\ntypedef struct { char a, b[]; } T65;\nT65 g65 = {'f','o','o',0};\nT65 g66 = {'f','o','o','b','a','r',0};\n\nint main() {\n  ASSERT(1, ({ int x[3]={1,2,3}; x[0]; }));\n  ASSERT(2, ({ int x[3]={1,2,3}; x[1]; }));\n  ASSERT(3, ({ int x[3]={1,2,3}; x[2]; }));\n  ASSERT(3, ({ int x[3]={1,2,3}; x[2]; }));\n\n  ASSERT(2, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[0][1]; }));\n  ASSERT(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; }));\n  ASSERT(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; }));\n\n  ASSERT(0, ({ int x[3]={}; x[0]; }));\n  ASSERT(0, ({ int x[3]={}; x[1]; }));\n  ASSERT(0, ({ int x[3]={}; x[2]; }));\n\n  ASSERT(2, ({ int x[2][3]={{1,2}}; x[0][1]; }));\n  ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][0]; }));\n  ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][2]; }));\n\n  ASSERT('a', ({ char x[4]=\"abc\"; x[0]; }));\n  ASSERT('c', ({ char x[4]=\"abc\"; x[2]; }));\n  ASSERT(0, ({ char x[4]=\"abc\"; x[3]; }));\n  ASSERT('a', ({ char x[2][4]={\"abc\",\"def\"}; x[0][0]; }));\n  ASSERT(0, ({ char x[2][4]={\"abc\",\"def\"}; x[0][3]; }));\n  ASSERT('d', ({ char x[2][4]={\"abc\",\"def\"}; x[1][0]; }));\n  ASSERT('f', ({ char x[2][4]={\"abc\",\"def\"}; x[1][2]; }));\n\n  ASSERT(4, ({ int x[]={1,2,3,4}; x[3]; }));\n  ASSERT(16, ({ int x[]={1,2,3,4}; sizeof(x); }));\n  ASSERT(4, ({ char x[]=\"foo\"; sizeof(x); }));\n\n  ASSERT(4, ({ typedef char T[]; T x=\"foo\"; T y=\"x\"; sizeof(x); }));\n  ASSERT(2, ({ typedef char T[]; T x=\"foo\"; T y=\"x\"; sizeof(y); }));\n  ASSERT(2, ({ typedef char T[]; T x=\"x\"; T y=\"foo\"; sizeof(x); }));\n  ASSERT(4, ({ typedef char T[]; T x=\"x\"; T y=\"foo\"; sizeof(y); }));\n\n  ASSERT(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; }));\n  ASSERT(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; }));\n  ASSERT(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; }));\n  ASSERT(1, ({ struct {int a; int b; int c;} x={1}; x.a; }));\n  ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.b; }));\n  ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.c; }));\n\n  ASSERT(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; }));\n  ASSERT(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; }));\n  ASSERT(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; }));\n  ASSERT(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; }));\n\n  ASSERT(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; }));\n\n  ASSERT(0, ({ struct {int a; int b;} x={}; x.a; }));\n  ASSERT(0, ({ struct {int a; int b;} x={}; x.b; }));\n\n  ASSERT(5, ({ typedef struct {int a,b,c,d,e,f;} T; T x={1,2,3,4,5,6}; T y; y=x; y.e; }));\n  ASSERT(2, ({ typedef struct {int a,b;} T; T x={1,2}; T y, z; z=y=x; z.b; }));\n\n  ASSERT(1, ({ typedef struct {int a,b;} T; T x={1,2}; T y=x; y.a; }));\n\n  ASSERT(4, ({ union { int a; char b[4]; } x={0x01020304}; x.b[0]; }));\n  ASSERT(3, ({ union { int a; char b[4]; } x={0x01020304}; x.b[1]; }));\n\n  ASSERT(0x01020304, ({ union { struct { char a,b,c,d; } e; int f; } x={{4,3,2,1}}; x.f; }));\n\n  ASSERT(3, g3);\n  ASSERT(4, g4);\n  ASSERT(5, g5);\n  ASSERT(6, g6);\n\n  ASSERT(0, g9[0]);\n  ASSERT(1, g9[1]);\n  ASSERT(2, g9[2]);\n\n  ASSERT(1, g11[0].a);\n  ASSERT(2, g11[0].b);\n  ASSERT(3, g11[1].a);\n  ASSERT(4, g11[1].b);\n\n  ASSERT(1, g12[0].a[0]);\n  ASSERT(2, g12[0].a[1]);\n  ASSERT(0, g12[1].a[0]);\n  ASSERT(0, g12[1].a[1]);\n\n  ASSERT(4, g13[0].b[0]);\n  ASSERT(3, g13[0].b[1]);\n  ASSERT(8, g13[1].b[0]);\n  ASSERT(7, g13[1].b[1]);\n\n  ASSERT(7, sizeof(g17));\n  ASSERT(10, sizeof(g18));\n  ASSERT(3, sizeof(g19));\n\n  ASSERT(0, memcmp(g17, \"foobar\", 7));\n  ASSERT(0, memcmp(g18, \"foobar\\0\\0\\0\", 10));\n  ASSERT(0, memcmp(g19, \"foo\", 3));\n\n  ASSERT(0, strcmp(g20, \"foobar\"));\n  ASSERT(0, strcmp(g21, \"bar\"));\n  ASSERT(0, strcmp(g22+3, \"foobar\"));\n\n  ASSERT(0, strcmp(g23[0], \"foobar\"));\n  ASSERT(0, strcmp(g23[1], \"bar\"));\n  ASSERT(0, strcmp(g23[2]+3, \"foobar\"));\n\n  ASSERT(3, g24);\n  ASSERT(3, *g25);\n  ASSERT(2, *g27);\n  ASSERT(3, *g28);\n  ASSERT(1, *(int *)g29);\n\n  ASSERT(1, g31[0]);\n  ASSERT(2, g31[1]);\n  ASSERT(3, g31[2]);\n\n  ASSERT(1, g40[0].a[0]);\n  ASSERT(2, g40[0].a[1]);\n  ASSERT(3, g40[1].a[0]);\n  ASSERT(4, g40[1].a[1]);\n\n  ASSERT(1, g41[0].a[0]);\n  ASSERT(2, g41[0].a[1]);\n  ASSERT(3, g41[1].a[0]);\n  ASSERT(4, g41[1].a[1]);\n\n  ASSERT(0, ({ int x[2][3]={0,1,2,3,4,5}; x[0][0]; }));\n  ASSERT(3, ({ int x[2][3]={0,1,2,3,4,5}; x[1][0]; }));\n\n  ASSERT(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; }));\n  ASSERT(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; }));\n\n  ASSERT(0, strcmp(g43[0], \"foo\"));\n  ASSERT(0, strcmp(g43[1], \"bar\"));\n  ASSERT(0, strcmp(g44, \"foo\"));\n\n  ASSERT(3, ({ int a[]={1,2,3,}; a[2]; }));\n  ASSERT(1, ({ struct {int a,b,c;} x={1,2,3,}; x.a; }));\n  ASSERT(1, ({ union {int a; char b;} x={1,}; x.a; }));\n  ASSERT(2, ({ enum {x,y,z,}; z; }));\n\n  ASSERT(3, sizeof(g60));\n  ASSERT(6, sizeof(g61));\n\n  ASSERT(4, sizeof(g65));\n  ASSERT(7, sizeof(g66));\n  ASSERT(0, strcmp(g65.b, \"oo\"));\n  ASSERT(0, strcmp(g66.b, \"oobar\"));\n\n  ASSERT(4, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[0]; }));\n  ASSERT(5, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[1]; }));\n  ASSERT(3, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[2]; }));\n\n  ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][0]; }));\n  ASSERT(11, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][1]; }));\n  ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][2]; }));\n  ASSERT(12, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][0]; }));\n  ASSERT(5, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][1]; }));\n  ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][2]; }));\n\n  ASSERT(7, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][0]; }));\n  ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][1]; }));\n  ASSERT(3, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][2]; }));\n  ASSERT(9, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][0]; }));\n  ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][1]; }));\n  ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][2]; }));\n\n  ASSERT(7, ((int[10]){ [3]=7 })[3]);\n  ASSERT(0, ((int[10]){ [3]=7 })[4]);\n\n  ASSERT(10, ({ char x[]={[10-3]=1,2,3}; sizeof(x); }));\n  ASSERT(20, ({ char x[][2]={[8][1]=1,2}; sizeof(x); }));\n\n  ASSERT(3, sizeof(g60));\n  ASSERT(6, sizeof(g61));\n\n  ASSERT(4, sizeof(g65));\n  ASSERT(7, sizeof(g66));\n  ASSERT(0, strcmp(g65.b, \"oo\"));\n  ASSERT(0, strcmp(g66.b, \"oobar\"));\n\n  ASSERT(7, ((int[10]){ [3] 7 })[3]);\n  ASSERT(0, ((int[10]){ [3] 7 })[4]);\n\n  ASSERT(4, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.a; }));\n  ASSERT(3, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.b; }));\n\n  ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.a; }));\n  ASSERT(2, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.b; }));\n\n  ASSERT(0, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.a; }));\n  ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.b; }));\n\n  ASSERT(1, ({ struct { int a[2]; } x={.a=1,2}; x.a[0]; }));\n  ASSERT(2, ({ struct { int a[2]; } x={.a=1,2}; x.a[1]; }));\n\n  ASSERT(0, ({ struct { int a[2]; } x={.a[1]=1}; x.a[0]; }));\n  ASSERT(1, ({ struct { int a[2]; } x={.a[1]=1}; x.a[1]; }));\n\n  ASSERT(3, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].a; }));\n  ASSERT(4, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].b; }));\n  ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].a; }));\n  ASSERT(1, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].b; }));\n  ASSERT(2, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].a; }));\n  ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].b; }));\n\n  ASSERT(1, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].a; }));\n  ASSERT(2, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].b; }));\n  ASSERT(0, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].a; }));\n  ASSERT(3, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].b; }));\n\n  ASSERT(5, ((struct { int a,b,c; }){ .c=5 }).c);\n  ASSERT(0, ((struct { int a,b,c; }){ .c=5 }).a);\n\n  ASSERT(0x00ff, ({ union { unsigned short a; char b[2]; } x={.b[0]=0xff}; x.a; }));\n  ASSERT(0xff00, ({ union { unsigned short a; char b[2]; } x={.b[1]=0xff}; x.a; }));\n\n  ASSERT(0x00120000, g50.a);\n  ASSERT(0, g51[0].a);\n  ASSERT(0, g51[1].a);\n\n  ASSERT(1, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.a; }));\n  ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; }));\n  ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; }));\n\n  ASSERT(16, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; sizeof(x); }));\n  ASSERT(0, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; memcmp(x, \"\\0\\0adddabaaa\\0\\0\\0\\0c\", 16); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/line.c",
    "content": "#include \"test.h\"\n\nint main() {\n#line 500 \"foo\"\n  ASSERT(501, __LINE__);\n  ASSERT(0, strcmp(__FILE__, \"foo\"));\n\n#line 800 \"bar\"\n  ASSERT(801, __LINE__);\n  ASSERT(0, strcmp(__FILE__, \"bar\"));\n\n#line 1\n  ASSERT(2, __LINE__);\n\n# 200 \"xyz\" 2 3\n  ASSERT(201, __LINE__);\n  ASSERT(0, strcmp(__FILE__, \"xyz\"));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/literal.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(97, 'a');\n  ASSERT(10, '\\n');\n  ASSERT(-128, '\\x80');\n\n  ASSERT(511, 0777);\n  ASSERT(0, 0x0);\n  ASSERT(10, 0xa);\n  ASSERT(10, 0XA);\n  ASSERT(48879, 0xbeef);\n  ASSERT(48879, 0xBEEF);\n  ASSERT(48879, 0XBEEF);\n  ASSERT(0, 0b0);\n  ASSERT(1, 0b1);\n  ASSERT(47, 0b101111);\n  ASSERT(47, 0B101111);\n\n  ASSERT(4, sizeof(0));\n  ASSERT(8, sizeof(0L));\n  ASSERT(8, sizeof(0LU));\n  ASSERT(8, sizeof(0UL));\n  ASSERT(8, sizeof(0LL));\n  ASSERT(8, sizeof(0LLU));\n  ASSERT(8, sizeof(0Ull));\n  ASSERT(8, sizeof(0l));\n  ASSERT(8, sizeof(0ll));\n  ASSERT(8, sizeof(0x0L));\n  ASSERT(8, sizeof(0b0L));\n  ASSERT(4, sizeof(2147483647));\n  ASSERT(8, sizeof(2147483648));\n  ASSERT(-1, 0xffffffffffffffff);\n  ASSERT(8, sizeof(0xffffffffffffffff));\n  ASSERT(4, sizeof(4294967295U));\n  ASSERT(8, sizeof(4294967296U));\n\n  ASSERT(3, -1U>>30);\n  ASSERT(3, -1Ul>>62);\n  ASSERT(3, -1ull>>62);\n\n  ASSERT(1, 0xffffffffffffffffl>>63);\n  ASSERT(1, 0xffffffffffffffffll>>63);\n\n  ASSERT(-1, 18446744073709551615);\n  ASSERT(8, sizeof(18446744073709551615));\n  ASSERT(-1, 18446744073709551615>>63);\n\n  ASSERT(-1, 0xffffffffffffffff);\n  ASSERT(8, sizeof(0xffffffffffffffff));\n  ASSERT(1, 0xffffffffffffffff>>63);\n\n  ASSERT(-1, 01777777777777777777777);\n  ASSERT(8, sizeof(01777777777777777777777));\n  ASSERT(1, 01777777777777777777777>>63);\n\n  ASSERT(-1, 0b1111111111111111111111111111111111111111111111111111111111111111);\n  ASSERT(8, sizeof(0b1111111111111111111111111111111111111111111111111111111111111111));\n  ASSERT(1, 0b1111111111111111111111111111111111111111111111111111111111111111>>63);\n\n  ASSERT(8, sizeof(2147483648));\n  ASSERT(4, sizeof(2147483647));\n\n  ASSERT(8, sizeof(0x1ffffffff));\n  ASSERT(4, sizeof(0xffffffff));\n  ASSERT(1, 0xffffffff>>31);\n\n  ASSERT(8, sizeof(040000000000));\n  ASSERT(4, sizeof(037777777777));\n  ASSERT(1, 037777777777>>31);\n\n  ASSERT(8, sizeof(0b111111111111111111111111111111111));\n  ASSERT(4, sizeof(0b11111111111111111111111111111111));\n  ASSERT(1, 0b11111111111111111111111111111111>>31);\n\n  ASSERT(-1, 1 << 31 >> 31);\n  ASSERT(-1, 01 << 31 >> 31);\n  ASSERT(-1, 0x1 << 31 >> 31);\n  ASSERT(-1, 0b1 << 31 >> 31);\n\n  0.0;\n  1.0;\n  3e+8;\n  0x10.1p0;\n  .1E4f;\n\n  ASSERT(4, sizeof(8f));\n  ASSERT(4, sizeof(0.3F));\n  ASSERT(8, sizeof(0.));\n  ASSERT(8, sizeof(.0));\n  ASSERT(16, sizeof(5.l));\n  ASSERT(16, sizeof(2.0L));\n\n  assert(1, size\\\nof(char), \\\n         \"sizeof(char)\");\n\n  ASSERT(4, sizeof(L'\\0'));\n  ASSERT(97, L'a');\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/macro.c",
    "content": "#include \"test.h\"\n#include \"include1.h\"\n\nchar *main_filename1 = __FILE__;\nint main_line1 = __LINE__;\n#define LINE() __LINE__\nint main_line2 = LINE();\n\n#\n\n/* */ #\n\nint ret3(void) { return 3; }\nint dbl(int x) { return x*x; }\n\nint add2(int x, int y) {\n  return x + y;\n}\n\nint add6(int a, int b, int c, int d, int e, int f) {\n  return a + b + c + d + e + f;\n}\n\nint main() {\n  ASSERT(5, include1);\n  ASSERT(7, include2);\n\n#if 0\n#include \"/no/such/file\"\n  ASSERT(0, 1);\n#if nested\n#endif\n#endif\n\n  int m = 0;\n\n#if 1\n  m = 5;\n#endif\n  ASSERT(5, m);\n\n#if 1\n# if 0\n#  if 1\n    foo bar\n#  endif\n# endif\n      m = 3;\n#endif\n    ASSERT(3, m);\n\n#if 1-1\n# if 1\n# endif\n# if 1\n# else\n# endif\n# if 0\n# else\n# endif\n  m = 2;\n#else\n# if 1\n  m = 3;\n# endif\n#endif\n  ASSERT(3, m);\n\n#if 1\n  m = 2;\n#else\n  m = 3;\n#endif\n  ASSERT(2, m);\n\n#if 1\n  m = 2;\n#else\n  m = 3;\n#endif\n  ASSERT(2, m);\n\n#if 0\n  m = 1;\n#elif 0\n  m = 2;\n#elif 3+5\n  m = 3;\n#elif 1*5\n  m = 4;\n#endif\n  ASSERT(3, m);\n\n#if 1+5\n  m = 1;\n#elif 1\n  m = 2;\n#elif 3\n  m = 2;\n#endif\n  ASSERT(1, m);\n\n#if 0\n  m = 1;\n#elif 1\n# if 1\n  m = 2;\n# else\n  m = 3;\n# endif\n#else\n  m = 5;\n#endif\n  ASSERT(2, m);\n\n  int M1 = 5;\n\n#define M1 3\n  ASSERT(3, M1);\n#define M1 4\n  ASSERT(4, M1);\n\n#define M1 3+4+\n  ASSERT(12, M1 5);\n\n#define M1 3+4\n  ASSERT(23, M1*5);\n\n#define ASSERT_ assert(\n#define if 5\n#define five \"5\"\n#define END )\n  ASSERT_ 5, if, five END;\n\n#undef ASSERT_\n#undef if\n#undef five\n#undef END\n\n  if (0);\n\n#define M 5\n#if M\n  m = 5;\n#else\n  m = 6;\n#endif\n  ASSERT(5, m);\n\n#define M 5\n#if M-5\n  m = 6;\n#elif M\n  m = 5;\n#endif\n  ASSERT(5, m);\n\n  int M2 = 6;\n#define M2 M2 + 3\n  ASSERT(9, M2);\n\n#define M3 M2 + 3\n  ASSERT(12, M3);\n\n  int M4 = 3;\n#define M4 M5 * 5\n#define M5 M4 + 2\n  ASSERT(13, M4);\n\n#ifdef M6\n  m = 5;\n#else\n  m = 3;\n#endif\n  ASSERT(3, m);\n\n#define M6\n#ifdef M6\n  m = 5;\n#else\n  m = 3;\n#endif\n  ASSERT(5, m);\n\n#ifndef M7\n  m = 3;\n#else\n  m = 5;\n#endif\n  ASSERT(3, m);\n\n#define M7\n#ifndef M7\n  m = 3;\n#else\n  m = 5;\n#endif\n  ASSERT(5, m);\n\n#if 0\n#ifdef NO_SUCH_MACRO\n#endif\n#ifndef NO_SUCH_MACRO\n#endif\n#else\n#endif\n\n#define M7() 1\n  int M7 = 5;\n  ASSERT(1, M7());\n  ASSERT(5, M7);\n\n#define M7 ()\n  ASSERT(3, ret3 M7);\n\n#define M8(x,y) x+y\n  ASSERT(7, M8(3, 4));\n\n#define M8(x,y) x*y\n  ASSERT(24, M8(3+4, 4+5));\n\n#define M8(x,y) (x)*(y)\n  ASSERT(63, M8(3+4, 4+5));\n\n#define M8(x,y) x y\n  ASSERT(9, M8(, 4+5));\n\n#define M8(x,y) x*y\n  ASSERT(20, M8((2+3), 4));\n\n#define M8(x,y) x*y\n  ASSERT(12, M8((2,3), 4));\n\n#define dbl(x) M10(x) * x\n#define M10(x) dbl(x) + 3\n  ASSERT(10, dbl(2));\n\n#define M11(x) #x\n  ASSERT('a', M11( a!b  `\"\"c)[0]);\n  ASSERT('!', M11( a!b  `\"\"c)[1]);\n  ASSERT('b', M11( a!b  `\"\"c)[2]);\n  ASSERT(' ', M11( a!b  `\"\"c)[3]);\n  ASSERT('`', M11( a!b  `\"\"c)[4]);\n  ASSERT('\"', M11( a!b  `\"\"c)[5]);\n  ASSERT('\"', M11( a!b  `\"\"c)[6]);\n  ASSERT('c', M11( a!b  `\"\"c)[7]);\n  ASSERT(0, M11( a!b  `\"\"c)[8]);\n\n#define paste(x,y) x##y\n  ASSERT(15, paste(1,5));\n  ASSERT(255, paste(0,xff));\n  ASSERT(3, ({ int foobar=3; paste(foo,bar); }));\n  ASSERT(5, paste(5,));\n  ASSERT(5, paste(,5));\n\n#define i 5\n  ASSERT(101, ({ int i3=100; paste(1+i,3); }));\n#undef i\n\n#define paste2(x) x##5\n  ASSERT(26, paste2(1+2));\n\n#define paste3(x) 2##x\n  ASSERT(23, paste3(1+2));\n\n#define paste4(x, y, z) x##y##z\n  ASSERT(123, paste4(1,2,3));\n\n#define M12\n#if defined(M12)\n  m = 3;\n#else\n  m = 4;\n#endif\n  ASSERT(3, m);\n\n#define M12\n#if defined M12\n  m = 3;\n#else\n  m = 4;\n#endif\n  ASSERT(3, m);\n\n#if defined(M12) - 1\n  m = 3;\n#else\n  m = 4;\n#endif\n  ASSERT(4, m);\n\n#if defined(NO_SUCH_MACRO)\n  m = 3;\n#else\n  m = 4;\n#endif\n  ASSERT(4, m);\n\n#if no_such_symbol == 0\n  m = 5;\n#else\n  m = 6;\n#endif\n  ASSERT(5, m);\n\n#define STR(x) #x\n#define M12(x) STR(x)\n#define M13(x) M12(foo.x)\n  ASSERT(0, strcmp(M13(bar), \"foo.bar\"));\n\n#define M13(x) M12(foo. x)\n  ASSERT(0, strcmp(M13(bar), \"foo. bar\"));\n\n#define M12 foo\n#define M13(x) STR(x)\n#define M14(x) M13(x.M12)\n  ASSERT(0, strcmp(M14(bar), \"bar.foo\"));\n\n#define M14(x) M13(x. M12)\n  ASSERT(0, strcmp(M14(bar), \"bar. foo\"));\n\n#include \"include3.h\"\n  ASSERT(3, foo);\n\n#include \"include4.h\"\n  ASSERT(4, foo);\n\n#define M13 \"include3.h\"\n#include M13\n  ASSERT(3, foo);\n\n#define M13 < include4.h\n#include M13 >\n  ASSERT(4, foo);\n\n#undef foo\n\n  ASSERT(1, __STDC__);\n\n  ASSERT(0, strcmp(main_filename1, \"test/macro.c\"));\n  ASSERT(5, main_line1);\n  ASSERT(7, main_line2);\n  ASSERT(0, strcmp(include1_filename, \"test/include1.h\"));\n  ASSERT(4, include1_line);\n\n#define M14(...) 3\n  ASSERT(3, M14());\n\n#define M14(...) __VA_ARGS__\n  ASSERT(2, M14() 2);\n  ASSERT(5, M14(5));\n\n#define M14(...) add2(__VA_ARGS__)\n  ASSERT(8, M14(2, 6));\n\n#define M14(...) add6(1,2,__VA_ARGS__,6)\n  ASSERT(21, M14(3,4,5));\n\n#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)\n  ASSERT(21, M14(3,4,5));\n\n#define M14(args...) 3\n  ASSERT(3, M14());\n\n#define M14(x, ...) x\n  ASSERT(5, M14(5));\n\n#define M14(args...) args\n  ASSERT(2, M14() 2);\n  ASSERT(5, M14(5));\n\n#define M14(args...) add2(args)\n  ASSERT(8, M14(2, 6));\n\n#define M14(args...) add6(1,2,args,6)\n  ASSERT(21, M14(3,4,5));\n\n#define M14(x, args...) add6(1,2,x,args,6)\n  ASSERT(21, M14(3,4,5));\n\n#define M14(x, args...) x\n  ASSERT(5, M14(5));\n\n#define CONCAT(x,y) x##y\n  ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); }));\n  ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));\n\n  ASSERT(11, strlen(__DATE__));\n  ASSERT(8, strlen(__TIME__));\n\n  ASSERT(0, __COUNTER__);\n  ASSERT(1, __COUNTER__);\n  ASSERT(2, __COUNTER__);\n\n  ASSERT(24, strlen(__TIMESTAMP__));\n\n  ASSERT(0, strcmp(__BASE_FILE__, \"test/macro.c\"));\n\n#define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(,) __VA_ARGS__)\n  ASSERT(0, ({ char buf[100]; M30(buf, \"foo\"); strcmp(buf, \"foo\"); }));\n  ASSERT(0, ({ char buf[100]; M30(buf, \"foo%d\", 3); strcmp(buf, \"foo3\"); }));\n  ASSERT(0, ({ char buf[100]; M30(buf, \"foo%d%d\", 3, 5); strcmp(buf, \"foo35\"); }));\n\n#define M31(buf, fmt, ...) sprintf(buf, fmt, ## __VA_ARGS__)\n  ASSERT(0, ({ char buf[100]; M31(buf, \"foo\"); strcmp(buf, \"foo\"); }));\n  ASSERT(0, ({ char buf[100]; M31(buf, \"foo%d\", 3); strcmp(buf, \"foo3\"); }));\n  ASSERT(0, ({ char buf[100]; M31(buf, \"foo%d%d\", 3, 5); strcmp(buf, \"foo35\"); }));\n\n#define M31(x, y) (1, ##x y)\n  ASSERT(3, M31(, 3));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/offsetof.c",
    "content": "#include \"test.h\"\n#include <stddef.h>\n\ntypedef struct {\n  int a;\n  char b;\n  int c;\n  double d;\n} T;\n\nint main() {\n  ASSERT(0, offsetof(T, a));\n  ASSERT(4, offsetof(T, b));\n  ASSERT(8, offsetof(T, c));\n  ASSERT(16, offsetof(T, d));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/pointer.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(3, ({ int x=3; *&x; }));\n  ASSERT(3, ({ int x=3; int *y=&x; int **z=&y; **z; }));\n  ASSERT(5, ({ int x=3; int y=5; *(&x+1); }));\n  ASSERT(3, ({ int x=3; int y=5; *(&y-1); }));\n  ASSERT(5, ({ int x=3; int y=5; *(&x-(-1)); }));\n  ASSERT(5, ({ int x=3; int *y=&x; *y=5; x; }));\n  ASSERT(7, ({ int x=3; int y=5; *(&x+1)=7; y; }));\n  ASSERT(7, ({ int x=3; int y=5; *(&y-2+1)=7; x; }));\n  ASSERT(5, ({ int x=3; (&x+2)-&x+3; }));\n  ASSERT(8, ({ int x, y; x=3; y=5; x+y; }));\n  ASSERT(8, ({ int x=3, y=5; x+y; }));\n\n  ASSERT(3, ({ int x[2]; int *y=&x; *y=3; *x; }));\n\n  ASSERT(3, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *x; }));\n  ASSERT(4, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+1); }));\n  ASSERT(5, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+2); }));\n\n  ASSERT(0, ({ int x[2][3]; int *y=x; *y=0; **x; }));\n  ASSERT(1, ({ int x[2][3]; int *y=x; *(y+1)=1; *(*x+1); }));\n  ASSERT(2, ({ int x[2][3]; int *y=x; *(y+2)=2; *(*x+2); }));\n  ASSERT(3, ({ int x[2][3]; int *y=x; *(y+3)=3; **(x+1); }));\n  ASSERT(4, ({ int x[2][3]; int *y=x; *(y+4)=4; *(*(x+1)+1); }));\n  ASSERT(5, ({ int x[2][3]; int *y=x; *(y+5)=5; *(*(x+1)+2); }));\n\n  ASSERT(3, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *x; }));\n  ASSERT(4, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+1); }));\n  ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); }));\n  ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); }));\n  ASSERT(5, ({ int x[3]; *x=3; x[1]=4; 2[x]=5; *(x+2); }));\n\n  ASSERT(0, ({ int x[2][3]; int *y=x; y[0]=0; x[0][0]; }));\n  ASSERT(1, ({ int x[2][3]; int *y=x; y[1]=1; x[0][1]; }));\n  ASSERT(2, ({ int x[2][3]; int *y=x; y[2]=2; x[0][2]; }));\n  ASSERT(3, ({ int x[2][3]; int *y=x; y[3]=3; x[1][0]; }));\n  ASSERT(4, ({ int x[2][3]; int *y=x; y[4]=4; x[1][1]; }));\n  ASSERT(5, ({ int x[2][3]; int *y=x; y[5]=5; x[1][2]; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/pragma-once.c",
    "content": "#include \"test.h\"\n\n#pragma once\n\n#include \"test/pragma-once.c\"\n\nint main() {\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/sizeof.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(1, sizeof(char));\n  ASSERT(2, sizeof(short));\n  ASSERT(2, sizeof(short int));\n  ASSERT(2, sizeof(int short));\n  ASSERT(4, sizeof(int));\n  ASSERT(8, sizeof(long));\n  ASSERT(8, sizeof(long int));\n  ASSERT(8, sizeof(long int));\n  ASSERT(8, sizeof(char *));\n  ASSERT(8, sizeof(int *));\n  ASSERT(8, sizeof(long *));\n  ASSERT(8, sizeof(int **));\n  ASSERT(8, sizeof(int(*)[4]));\n  ASSERT(32, sizeof(int*[4]));\n  ASSERT(16, sizeof(int[4]));\n  ASSERT(48, sizeof(int[3][4]));\n  ASSERT(8, sizeof(struct {int a; int b;}));\n\n  ASSERT(8, sizeof(-10 + (long)5));\n  ASSERT(8, sizeof(-10 - (long)5));\n  ASSERT(8, sizeof(-10 * (long)5));\n  ASSERT(8, sizeof(-10 / (long)5));\n  ASSERT(8, sizeof((long)-10 + 5));\n  ASSERT(8, sizeof((long)-10 - 5));\n  ASSERT(8, sizeof((long)-10 * 5));\n  ASSERT(8, sizeof((long)-10 / 5));\n\n  ASSERT(1, ({ char i; sizeof(++i); }));\n  ASSERT(1, ({ char i; sizeof(i++); }));\n\n  ASSERT(8, sizeof(int(*)[10]));\n  ASSERT(8, sizeof(int(*)[][10]));\n\n  ASSERT(4, sizeof(struct { int x, y[]; }));\n\n  ASSERT(1, sizeof(char));\n  ASSERT(1, sizeof(signed char));\n  ASSERT(1, sizeof(signed char signed));\n  ASSERT(1, sizeof(unsigned char));\n  ASSERT(1, sizeof(unsigned char unsigned));\n\n  ASSERT(2, sizeof(short));\n  ASSERT(2, sizeof(int short));\n  ASSERT(2, sizeof(short int));\n  ASSERT(2, sizeof(signed short));\n  ASSERT(2, sizeof(int short signed));\n  ASSERT(2, sizeof(unsigned short));\n  ASSERT(2, sizeof(int short unsigned));\n\n  ASSERT(4, sizeof(int));\n  ASSERT(4, sizeof(signed int));\n  ASSERT(4, sizeof(signed));\n  ASSERT(4, sizeof(signed signed));\n  ASSERT(4, sizeof(unsigned int));\n  ASSERT(4, sizeof(unsigned));\n  ASSERT(4, sizeof(unsigned unsigned));\n\n  ASSERT(8, sizeof(long));\n  ASSERT(8, sizeof(signed long));\n  ASSERT(8, sizeof(signed long int));\n  ASSERT(8, sizeof(unsigned long));\n  ASSERT(8, sizeof(unsigned long int));\n\n  ASSERT(8, sizeof(long long));\n  ASSERT(8, sizeof(signed long long));\n  ASSERT(8, sizeof(signed long long int));\n  ASSERT(8, sizeof(unsigned long long));\n  ASSERT(8, sizeof(unsigned long long int));\n\n  ASSERT(1, sizeof((char)1));\n  ASSERT(2, sizeof((short)1));\n  ASSERT(4, sizeof((int)1));\n  ASSERT(8, sizeof((long)1));\n\n  ASSERT(4, sizeof((char)1 + (char)1));\n  ASSERT(4, sizeof((short)1 + (short)1));\n  ASSERT(4, sizeof(1?2:3));\n  ASSERT(4, sizeof(1?(short)2:(char)3));\n  ASSERT(8, sizeof(1?(long)2:(char)3));\n\n  ASSERT(1, sizeof(char) << 31 >> 31);\n  ASSERT(1, sizeof(char) << 63 >> 63);\n\n  ASSERT(4, sizeof(float));\n  ASSERT(8, sizeof(double));\n\n  ASSERT(4, sizeof(1f+2));\n  ASSERT(8, sizeof(1.0+2));\n  ASSERT(4, sizeof(1f-2));\n  ASSERT(8, sizeof(1.0-2));\n  ASSERT(4, sizeof(1f*2));\n  ASSERT(8, sizeof(1.0*2));\n  ASSERT(4, sizeof(1f/2));\n  ASSERT(8, sizeof(1.0/2));\n\n  ASSERT(16, sizeof(long double));\n\n  ASSERT(1, sizeof(main));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/stdhdr.c",
    "content": "#include \"test.h\"\n#include <float.h>\n#include <stdalign.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdnoreturn.h>\n\nint main() {\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/string.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(0, \"\"[0]);\n  ASSERT(1, sizeof(\"\"));\n\n  ASSERT(97, \"abc\"[0]);\n  ASSERT(98, \"abc\"[1]);\n  ASSERT(99, \"abc\"[2]);\n  ASSERT(0, \"abc\"[3]);\n  ASSERT(4, sizeof(\"abc\"));\n\n  ASSERT(7, \"\\a\"[0]);\n  ASSERT(8, \"\\b\"[0]);\n  ASSERT(9, \"\\t\"[0]);\n  ASSERT(10, \"\\n\"[0]);\n  ASSERT(11, \"\\v\"[0]);\n  ASSERT(12, \"\\f\"[0]);\n  ASSERT(13, \"\\r\"[0]);\n  ASSERT(27, \"\\e\"[0]);\n\n  ASSERT(106, \"\\j\"[0]);\n  ASSERT(107, \"\\k\"[0]);\n  ASSERT(108, \"\\l\"[0]);\n\n  ASSERT(7, \"\\ax\\ny\"[0]);\n  ASSERT(120, \"\\ax\\ny\"[1]);\n  ASSERT(10, \"\\ax\\ny\"[2]);\n  ASSERT(121, \"\\ax\\ny\"[3]);\n\n  ASSERT(0, \"\\0\"[0]);\n  ASSERT(16, \"\\20\"[0]);\n  ASSERT(65, \"\\101\"[0]);\n  ASSERT(104, \"\\1500\"[0]);\n  ASSERT(0, \"\\x00\"[0]);\n  ASSERT(119, \"\\x77\"[0]);\n\n  ASSERT(7, sizeof(\"abc\" \"def\"));\n  ASSERT(9, sizeof(\"abc\" \"d\" \"efgh\"));\n  ASSERT(0, strcmp(\"abc\" \"d\" \"\\nefgh\", \"abcd\\nefgh\"));\n  ASSERT(0, !strcmp(\"abc\" \"d\", \"abcd\\nefgh\"));\n  ASSERT(0, strcmp(\"\\x9\" \"0\", \"\\t0\"));\n\n  ASSERT(16, sizeof(L\"abc\" \"\"));\n\n  ASSERT(28, sizeof(L\"abc\" \"def\"));\n  ASSERT(28, sizeof(L\"abc\" L\"def\"));\n  ASSERT(14, sizeof(u\"abc\" \"def\"));\n  ASSERT(14, sizeof(u\"abc\" u\"def\"));\n\n  ASSERT(L'a', (L\"abc\" \"def\")[0]);\n  ASSERT(L'd', (L\"abc\" \"def\")[3]);\n  ASSERT(L'\\0', (L\"abc\" \"def\")[6]);\n\n  ASSERT(u'a', (u\"abc\" \"def\")[0]);\n  ASSERT(u'd', (u\"abc\" \"def\")[3]);\n  ASSERT(u'\\0', (u\"abc\" \"def\")[6]);\n\n  ASSERT(L'あ', (\"あ\" L\"\")[0]);\n  ASSERT(0343, (\"\\343\\201\\202\" L\"\")[0]);\n  ASSERT(0201, (\"\\343\\201\\202\" L\"\")[1]);\n  ASSERT(0202, (\"\\343\\201\\202\" L\"\")[2]);\n  ASSERT(0, (\"\\343\\201\\202\" L\"\")[3]);\n\n  ASSERT(L'a', (\"a\" \"b\" L\"c\")[0]);\n  ASSERT(L'b', (\"a\" \"b\" L\"c\")[1]);\n  ASSERT(L'c', (\"a\" \"b\" L\"c\")[2]);\n  ASSERT(0, (\"a\" \"b\" L\"c\")[3]);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/struct.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(1, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.a; }));\n  ASSERT(2, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.b; }));\n  ASSERT(1, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.a; }));\n  ASSERT(2, ({ struct {char a; int b; char c;} x; x.b=1; x.b=2; x.c=3; x.b; }));\n  ASSERT(3, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.c; }));\n\n  ASSERT(0, ({ struct {char a; char b;} x[3]; char *p=x; p[0]=0; x[0].a; }));\n  ASSERT(1, ({ struct {char a; char b;} x[3]; char *p=x; p[1]=1; x[0].b; }));\n  ASSERT(2, ({ struct {char a; char b;} x[3]; char *p=x; p[2]=2; x[1].a; }));\n  ASSERT(3, ({ struct {char a; char b;} x[3]; char *p=x; p[3]=3; x[1].b; }));\n\n  ASSERT(6, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.a[0]=6; p[0]; }));\n  ASSERT(7, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.b[0]=7; p[3]; }));\n\n  ASSERT(6, ({ struct { struct { char b; } a; } x; x.a.b=6; x.a.b; }));\n\n  ASSERT(4, ({ struct {int a;} x; sizeof(x); }));\n  ASSERT(8, ({ struct {int a; int b;} x; sizeof(x); }));\n  ASSERT(8, ({ struct {int a, b;} x; sizeof(x); }));\n  ASSERT(12, ({ struct {int a[3];} x; sizeof(x); }));\n  ASSERT(16, ({ struct {int a;} x[4]; sizeof(x); }));\n  ASSERT(24, ({ struct {int a[3];} x[2]; sizeof(x); }));\n  ASSERT(2, ({ struct {char a; char b;} x; sizeof(x); }));\n  ASSERT(0, ({ struct {} x; sizeof(x); }));\n  ASSERT(8, ({ struct {char a; int b;} x; sizeof(x); }));\n  ASSERT(8, ({ struct {int a; char b;} x; sizeof(x); }));\n\n  ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); }));\n  ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); }));\n  ASSERT(2, ({ struct t {char a[2];}; { struct t {char a[4];}; } struct t y; sizeof(y); }));\n  ASSERT(3, ({ struct t {int x;}; int t=1; struct t y; y.x=2; t+y.x; }));\n\n  ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; x.a=3; y->a; }));\n  ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; y->a=3; x.a; }));\n\n  ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; }));\n  ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; }));\n  ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; }));\n  ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; }));\n\n  ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; }));\n  ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; }));\n  ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; }));\n  ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; }));\n\n  ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); }));\n  ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); }));\n\n  ASSERT(16, ({ struct {char a; long b;} x; sizeof(x); }));\n  ASSERT(4, ({ struct {char a; short b;} x; sizeof(x); }));\n\n  ASSERT(8, ({ struct foo *bar; sizeof(bar); }));\n  ASSERT(4, ({ struct T *foo; struct T {int x;}; sizeof(struct T); }));\n  ASSERT(1, ({ struct T { struct T *next; int x; } a; struct T b; b.x=1; a.next=&b; a.next->x; }));\n  ASSERT(4, ({ typedef struct T T; struct T { int x; }; sizeof(T); }));\n\n  ASSERT(2, ({ struct {int a;} x={1}, y={2}; (x=y).a; }));\n  ASSERT(1, ({ struct {int a;} x={1}, y={2}; (1?x:y).a; }));\n  ASSERT(2, ({ struct {int a;} x={1}, y={2}; (0?x:y).a; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/test.h",
    "content": "#define ASSERT(x, y) assert(x, y, #y)\n\nvoid assert(int expected, int actual, char *code);\nint printf(char *fmt, ...);\nint sprintf(char *buf, char *fmt, ...);\nint vsprintf(char *buf, char *fmt, void *ap);\nint strcmp(char *p, char *q);\nint strncmp(char *p, char *q, long n);\nint memcmp(char *p, char *q, long n);\nvoid exit(int n);\nint vsprintf();\nlong strlen(char *s);\nvoid *memcpy(void *dest, void *src, long n);\nvoid *memset(void *s, int c, long n);\n"
  },
  {
    "path": "test/thirdparty/common",
    "content": "make=\"make -j$(nproc)\"\nchibicc=`pwd`/chibicc\n\ndir=$(basename -s .git $repo)\n\nset -e -x\n\nmkdir -p thirdparty\ncd thirdparty\n[ -d $dir ] || git clone $repo\ncd $dir\n"
  },
  {
    "path": "test/thirdparty/cpython.sh",
    "content": "#!/bin/bash\nrepo='git@github.com:python/cpython.git'\n. test/thirdparty/common\ngit reset --hard c75330605d4795850ec74fdc4d69aa5d92f76c00\n\n# Python's './configure' command misidentifies chibicc as icc\n# (Intel C Compiler) because icc is a substring of chibicc.\n# Modify the configure file as a workaround.\nsed -i -e 1996,2011d configure.ac\nautoreconf\n\nCC=$chibicc ./configure\n$make clean\n$make\n$make test\n"
  },
  {
    "path": "test/thirdparty/git.sh",
    "content": "#!/bin/bash\nrepo='git@github.com:git/git.git'\n. test/thirdparty/common\ngit reset --hard 54e85e7af1ac9e9a92888060d6811ae767fea1bc\n\n$make clean\n$make V=1 CC=$chibicc test\n"
  },
  {
    "path": "test/thirdparty/libpng.sh",
    "content": "#!/bin/bash\nrepo='git@github.com:rui314/libpng.git'\n. test/thirdparty/common\ngit reset --hard dbe3e0c43e549a1602286144d94b0666549b18e6\n\nCC=$chibicc ./configure\nsed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool\n$make clean\n$make\n$make test\n"
  },
  {
    "path": "test/thirdparty/sqlite.sh",
    "content": "#!/bin/bash\nrepo='git@github.com:sqlite/sqlite.git'\n. test/thirdparty/common\ngit reset --hard 86f477edaa17767b39c7bae5b67cac8580f7a8c1\n\nCC=$chibicc CFLAGS=-D_GNU_SOURCE ./configure\nsed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool\n$make clean\n$make\n$make test\n"
  },
  {
    "path": "test/thirdparty/tinycc.sh",
    "content": "#!/bin/bash\nrepo='git@github.com:TinyCC/tinycc.git'\n. test/thirdparty/common\ngit reset --hard df67d8617b7d1d03a480a28f9f901848ffbfb7ec\n\n./configure --cc=$chibicc\n$make clean\n$make\n$make CC=cc test\n"
  },
  {
    "path": "test/tls.c",
    "content": "#include \"test.h\"\n#include <stdio.h>\n#include <pthread.h>\n\n_Thread_local int v1;\n_Thread_local int v2 = 5;\nint v3 = 7;\n\nint thread_main(void *unused) {\n  ASSERT(0, v1);\n  ASSERT(5, v2);\n  ASSERT(7, v3);\n\n  v1 = 1;\n  v2 = 2;\n  v3 = 3;\n\n  ASSERT(1, v1);\n  ASSERT(2, v2);\n  ASSERT(3, v3);\n\n  return 0;\n}\n\nint main() {\n  pthread_t thr;\n\n  ASSERT(0, v1);\n  ASSERT(5, v2);\n  ASSERT(7, v3);\n\n  ASSERT(0, pthread_create(&thr, NULL, thread_main, NULL));\n  ASSERT(0, pthread_join(thr, NULL));\n\n  ASSERT(0, v1);\n  ASSERT(5, v2);\n  ASSERT(3, v3);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/typedef.c",
    "content": "#include \"test.h\"\n\ntypedef int MyInt, MyInt2[4];\ntypedef int;\n\nint main() {\n  ASSERT(1, ({ typedef int t; t x=1; x; }));\n  ASSERT(1, ({ typedef struct {int a;} t; t x; x.a=1; x.a; }));\n  ASSERT(1, ({ typedef int t; t t=1; t; }));\n  ASSERT(2, ({ typedef struct {int a;} t; { typedef int t; } t x; x.a=2; x.a; }));\n  ASSERT(4, ({ typedef t; t x; sizeof(x); }));\n  ASSERT(3, ({ MyInt x=3; x; }));\n  ASSERT(16, ({ MyInt2 x; sizeof(x); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/typeof.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(3, ({ typeof(int) x=3; x; }));\n  ASSERT(3, ({ typeof(1) x=3; x; }));\n  ASSERT(4, ({ int x; typeof(x) y; sizeof(y); }));\n  ASSERT(8, ({ int x; typeof(&x) y; sizeof(y); }));\n  ASSERT(4, ({ typeof(\"foo\") x; sizeof(x); }));\n  ASSERT(12, sizeof(typeof(struct { int a,b,c; })));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/unicode.c",
    "content": "#include \"test.h\"\n\n#define STR(x) #x\n\ntypedef unsigned short char16_t;\ntypedef unsigned int char32_t;\ntypedef int wchar_t;\n\nint π = 3;\n\nint main() {\n  ASSERT(4, sizeof(L'\\0'));\n  ASSERT(97, L'a');\n\n  ASSERT(0, strcmp(\"αβγ\", \"\\u03B1\\u03B2\\u03B3\"));\n  ASSERT(0, strcmp(\"日本語\", \"\\u65E5\\u672C\\u8A9E\"));\n  ASSERT(0, strcmp(\"日本語\", \"\\U000065E5\\U0000672C\\U00008A9E\"));\n  ASSERT(0, strcmp(\"🌮\", \"\\U0001F32E\"));\n\n  ASSERT(-1, L'\\xffffffff'>>31);\n  ASSERT(946, L'β');\n  ASSERT(12354, L'あ');\n  ASSERT(127843, L'🍣');\n\n  ASSERT(2, sizeof(u'\\0'));\n  ASSERT(1, u'\\xffff'>>15);\n  ASSERT(97, u'a');\n  ASSERT(946, u'β');\n  ASSERT(12354, u'あ');\n  ASSERT(62307, u'🍣');\n\n  ASSERT(0, strcmp(STR(u'a'), \"u'a'\"));\n\n  ASSERT(4, sizeof(U'\\0'));\n  ASSERT(1, U'\\xffffffff'>>31);\n  ASSERT(97, U'a');\n  ASSERT(946, U'β');\n  ASSERT(12354, U'あ');\n  ASSERT(127843, U'🍣');\n\n  ASSERT(0, strcmp(STR(U'a'), \"U'a'\"));\n\n  ASSERT(4, sizeof(u8\"abc\"));\n  ASSERT(0, strcmp(u8\"abc\", \"abc\"));\n\n  ASSERT(0, strcmp(STR(u8\"a\"), \"u8\\\"a\\\"\"));\n\n  ASSERT(2, sizeof(u\"\"));\n  ASSERT(10, sizeof(u\"\\xffzzz\"));\n  ASSERT(0, memcmp(u\"\", \"\\0\\0\", 2));\n  ASSERT(0, memcmp(u\"abc\", \"a\\0b\\0c\\0\\0\\0\", 8));\n  ASSERT(0, memcmp(u\"日本語\", \"\\345e,g\\236\\212\\0\\0\", 8));\n  ASSERT(0, memcmp(u\"🍣\", \"<\\330c\\337\\0\\0\", 6));\n  ASSERT(u'β', u\"βb\"[0]);\n  ASSERT(u'b', u\"βb\"[1]);\n  ASSERT(0, u\"βb\"[2]);\n\n  ASSERT(0, strcmp(STR(u\"a\"), \"u\\\"a\\\"\"));\n\n  ASSERT(4, sizeof(U\"\"));\n  ASSERT(20, sizeof(U\"\\xffzzz\"));\n  ASSERT(0, memcmp(U\"\", \"\\0\\0\\0\\0\", 4));\n  ASSERT(0, memcmp(U\"abc\", \"a\\0\\0\\0b\\0\\0\\0c\\0\\0\\0\\0\\0\\0\\0\", 16));\n  ASSERT(0, memcmp(U\"日本語\", \"\\345e\\0\\0,g\\0\\0\\236\\212\\0\\0\\0\\0\\0\\0\", 16));\n  ASSERT(0, memcmp(U\"🍣\", \"c\\363\\001\\0\\0\\0\\0\\0\", 8));\n  ASSERT(u'β', U\"βb\"[0]);\n  ASSERT(u'b', U\"βb\"[1]);\n  ASSERT(0, U\"βb\"[2]);\n  ASSERT(1, U\"\\xffffffff\"[0] >> 31);\n\n  ASSERT(0, strcmp(STR(U\"a\"), \"U\\\"a\\\"\"));\n\n  ASSERT(4, sizeof(L\"\"));\n  ASSERT(20, sizeof(L\"\\xffzzz\"));\n  ASSERT(0, memcmp(L\"\", \"\\0\\0\\0\\0\", 4));\n  ASSERT(0, memcmp(L\"abc\", \"a\\0\\0\\0b\\0\\0\\0c\\0\\0\\0\\0\\0\\0\\0\", 16));\n  ASSERT(0, memcmp(L\"日本語\", \"\\345e\\0\\0,g\\0\\0\\236\\212\\0\\0\\0\\0\\0\\0\", 16));\n  ASSERT(0, memcmp(L\"🍣\", \"c\\363\\001\\0\\0\\0\\0\\0\", 8));\n  ASSERT(u'β', L\"βb\"[0]);\n  ASSERT(u'b', L\"βb\"[1]);\n  ASSERT(0, L\"βb\"[2]);\n  ASSERT(-1, L\"\\xffffffff\"[0] >> 31);\n\n  ASSERT(0, strcmp(STR(L\"a\"), \"L\\\"a\\\"\"));\n\n  ASSERT(u'α', ({ char16_t x[] = u\"αβ\"; x[0]; }));\n  ASSERT(u'β', ({ char16_t x[] = u\"αβ\"; x[1]; }));\n  ASSERT(6, ({ char16_t x[] = u\"αβ\"; sizeof(x); }));\n\n  ASSERT(U'🤔', ({ char32_t x[] = U\"🤔x\"; x[0]; }));\n  ASSERT(U'x', ({ char32_t x[] = U\"🤔x\"; x[1]; }));\n  ASSERT(12, ({ char32_t x[] = U\"🤔x\"; sizeof(x); }));\n\n  ASSERT(L'🤔', ({ wchar_t x[] = L\"🤔x\"; x[0]; }));\n  ASSERT(L'x', ({ wchar_t x[] = L\"🤔x\"; x[1]; }));\n  ASSERT(12, ({ wchar_t x[] = L\"🤔x\"; sizeof(x); }));\n\n  ASSERT(3, π);\n  ASSERT(3, ({ int あβ0¾=3; あβ0¾; }));\n  ASSERT(5, ({ int $$$=5; $$$; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/union.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(8, ({ union { int a; char b[6]; } x; sizeof(x); }));\n  ASSERT(3, ({ union { int a; char b[4]; } x; x.a = 515; x.b[0]; }));\n  ASSERT(2, ({ union { int a; char b[4]; } x; x.a = 515; x.b[1]; }));\n  ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[2]; }));\n  ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[3]; }));\n\n  ASSERT(3, ({ union {int a,b;} x,y; x.a=3; y.a=5; y=x; y.a; }));\n  ASSERT(3, ({ union {struct {int a,b;} c;} x,y; x.c.b=3; y.c.b=5; y=x; y.c.b; }));\n\n  ASSERT(0xef, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.a; }));\n  ASSERT(0xbe, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.b; }));\n  ASSERT(0xad, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.c; }));\n  ASSERT(0xde, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.d; }));\n\n  ASSERT(3, ({struct { union { int a,b; }; union { int c,d; }; } x; x.a=3; x.b; }));\n  ASSERT(5, ({struct { union { int a,b; }; union { int c,d; }; } x; x.d=5; x.c; }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/usualconv.c",
    "content": "#include \"test.h\"\n\nstatic int ret10(void) { return 10; }\n\nint main() {\n  ASSERT((long)-5, -10 + (long)5);\n  ASSERT((long)-15, -10 - (long)5);\n  ASSERT((long)-50, -10 * (long)5);\n  ASSERT((long)-2, -10 / (long)5);\n\n  ASSERT(1, -2 < (long)-1);\n  ASSERT(1, -2 <= (long)-1);\n  ASSERT(0, -2 > (long)-1);\n  ASSERT(0, -2 >= (long)-1);\n\n  ASSERT(1, (long)-2 < -1);\n  ASSERT(1, (long)-2 <= -1);\n  ASSERT(0, (long)-2 > -1);\n  ASSERT(0, (long)-2 >= -1);\n\n  ASSERT(0, 2147483647 + 2147483647 + 2);\n  ASSERT((long)-1, ({ long x; x=-1; x; }));\n\n  ASSERT(1, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[0]; }));\n  ASSERT(0, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[-1]; }));\n  ASSERT(5, ({ struct t {char a;} x, y; x.a=5; y=x; y.a; }));\n\n  ASSERT(10, (1 ? ret10 : (void *)0)());\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/varargs.c",
    "content": "#include \"test.h\"\n#include <stdarg.h>\n\nint sum1(int x, ...) {\n  va_list ap;\n  va_start(ap, x);\n\n  for (;;) {\n    int y = va_arg(ap, int);\n    if (y == 0)\n      return x;\n    x += y;\n  }\n}\n\nint sum2(int x, ...) {\n  va_list ap;\n  va_start(ap, x);\n\n  for (;;) {\n    double y = va_arg(ap, double);\n    x += y;\n\n    int z = va_arg(ap, int);\n    if (z == 0)\n      return x;\n    x += z;\n  }\n}\n\nvoid fmt(char *buf, char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n\n  va_list ap2;\n  va_copy(ap2, ap);\n  vsprintf(buf, fmt, ap2);\n  va_end(buf);\n}\n\nint main() {\n  ASSERT(6, sum1(1, 2, 3, 0));\n  ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0));\n  ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));\n  ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));\n  ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0));\n  ASSERT(0, ({ char buf[100]; fmt(buf, \"%d %d\", 2, 3); strcmp(buf, \"2 3\"); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/variable.c",
    "content": "#include \"test.h\"\n\nint g1, g2[4];\nstatic int g3 = 3;\n\nint main() {\n  ASSERT(3, ({ int a; a=3; a; }));\n  ASSERT(3, ({ int a=3; a; }));\n  ASSERT(8, ({ int a=3; int z=5; a+z; }));\n\n  ASSERT(3, ({ int a=3; a; }));\n  ASSERT(8, ({ int a=3; int z=5; a+z; }));\n  ASSERT(6, ({ int a; int b; a=b=3; a+b; }));\n  ASSERT(3, ({ int foo=3; foo; }));\n  ASSERT(8, ({ int foo123=3; int bar=5; foo123+bar; }));\n\n  ASSERT(4, ({ int x; sizeof(x); }));\n  ASSERT(4, ({ int x; sizeof x; }));\n  ASSERT(8, ({ int *x; sizeof(x); }));\n  ASSERT(16, ({ int x[4]; sizeof(x); }));\n  ASSERT(48, ({ int x[3][4]; sizeof(x); }));\n  ASSERT(16, ({ int x[3][4]; sizeof(*x); }));\n  ASSERT(4, ({ int x[3][4]; sizeof(**x); }));\n  ASSERT(5, ({ int x[3][4]; sizeof(**x) + 1; }));\n  ASSERT(5, ({ int x[3][4]; sizeof **x + 1; }));\n  ASSERT(4, ({ int x[3][4]; sizeof(**x + 1); }));\n  ASSERT(4, ({ int x=1; sizeof(x=2); }));\n  ASSERT(1, ({ int x=1; sizeof(x=2); x; }));\n\n  ASSERT(0, g1);\n  ASSERT(3, ({ g1=3; g1; }));\n  ASSERT(0, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[0]; }));\n  ASSERT(1, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[1]; }));\n  ASSERT(2, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[2]; }));\n  ASSERT(3, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[3]; }));\n\n  ASSERT(4, sizeof(g1));\n  ASSERT(16, sizeof(g2));\n\n  ASSERT(1, ({ char x=1; x; }));\n  ASSERT(1, ({ char x=1; char y=2; x; }));\n  ASSERT(2, ({ char x=1; char y=2; y; }));\n\n  ASSERT(1, ({ char x; sizeof(x); }));\n  ASSERT(10, ({ char x[10]; sizeof(x); }));\n\n  ASSERT(2, ({ int x=2; { int x=3; } x; }));\n  ASSERT(2, ({ int x=2; { int x=3; } int y=4; x; }));\n  ASSERT(3, ({ int x=2; { x=3; } x; }));\n\n  ASSERT(7, ({ int x; int y; char z; char *a=&y; char *b=&z; b-a; }));\n  ASSERT(1, ({ int x; char y; int z; char *a=&y; char *b=&z; b-a; }));\n\n  ASSERT(8, ({ long x; sizeof(x); }));\n  ASSERT(2, ({ short x; sizeof(x); }));\n\n  ASSERT(24, ({ char *x[3]; sizeof(x); }));\n  ASSERT(8, ({ char (*x)[3]; sizeof(x); }));\n  ASSERT(1, ({ char (x); sizeof(x); }));\n  ASSERT(3, ({ char (x)[3]; sizeof(x); }));\n  ASSERT(12, ({ char (x[3])[4]; sizeof(x); }));\n  ASSERT(4, ({ char (x[3])[4]; sizeof(x[0]); }));\n  ASSERT(3, ({ char *x[3]; char y; x[0]=&y; y=3; x[0][0]; }));\n  ASSERT(4, ({ char x[3]; char (*y)[3]=x; y[0][0]=4; y[0][0]; }));\n\n  { void *x; }\n\n  ASSERT(3, g3);\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "test/vla.c",
    "content": "#include \"test.h\"\n\nint main() {\n  ASSERT(20, ({ int n=5; int x[n]; sizeof(x); }));\n  ASSERT((5+1)*(8*2)*4, ({ int m=5, n=8; int x[m+1][n*2]; sizeof(x); }));\n\n  ASSERT(8, ({ char n=10; int (*x)[n][n+2]; sizeof(x); }));\n  ASSERT(480, ({ char n=10; int (*x)[n][n+2]; sizeof(*x); }));\n  ASSERT(48, ({ char n=10; int (*x)[n][n+2]; sizeof(**x); }));\n  ASSERT(4, ({ char n=10; int (*x)[n][n+2]; sizeof(***x); }));\n\n  ASSERT(60, ({ char n=3; int x[5][n]; sizeof(x); }));\n  ASSERT(12, ({ char n=3; int x[5][n]; sizeof(*x); }));\n\n  ASSERT(60, ({ char n=3; int x[n][5]; sizeof(x); }));\n  ASSERT(20, ({ char n=3; int x[n][5]; sizeof(*x); }));\n\n  ASSERT(0, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i<sizeof(x)/4; i++) p[i]=i; x[0][0]; }));\n  ASSERT(5, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i<sizeof(x)/4; i++) p[i]=i; x[0][5]; }));\n  ASSERT(5*16+2, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i<sizeof(x)/4; i++) p[i]=i; x[5][2]; }));\n\n  ASSERT(10, ({ int n=5; sizeof(char[2][n]); }));\n\n  printf(\"OK\\n\");\n  return 0;\n}\n"
  },
  {
    "path": "tokenize.c",
    "content": "#include \"chibicc.h\"\n\n// Input file\nstatic File *current_file;\n\n// A list of all input files.\nstatic File **input_files;\n\n// True if the current position is at the beginning of a line\nstatic bool at_bol;\n\n// True if the current position follows a space character\nstatic bool has_space;\n\n// Reports an error and exit.\nvoid error(char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n  vfprintf(stderr, fmt, ap);\n  fprintf(stderr, \"\\n\");\n  exit(1);\n}\n\n// Reports an error message in the following format.\n//\n// foo.c:10: x = y + 1;\n//               ^ <error message here>\nstatic void verror_at(char *filename, char *input, int line_no,\n                      char *loc, char *fmt, va_list ap) {\n  // Find a line containing `loc`.\n  char *line = loc;\n  while (input < line && line[-1] != '\\n')\n    line--;\n\n  char *end = loc;\n  while (*end && *end != '\\n')\n    end++;\n\n  // Print out the line.\n  int indent = fprintf(stderr, \"%s:%d: \", filename, line_no);\n  fprintf(stderr, \"%.*s\\n\", (int)(end - line), line);\n\n  // Show the error message.\n  int pos = display_width(line, loc - line) + indent;\n\n  fprintf(stderr, \"%*s\", pos, \"\"); // print pos spaces.\n  fprintf(stderr, \"^ \");\n  vfprintf(stderr, fmt, ap);\n  fprintf(stderr, \"\\n\");\n}\n\nvoid error_at(char *loc, char *fmt, ...) {\n  int line_no = 1;\n  for (char *p = current_file->contents; p < loc; p++)\n    if (*p == '\\n')\n      line_no++;\n\n  va_list ap;\n  va_start(ap, fmt);\n  verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap);\n  exit(1);\n}\n\nvoid error_tok(Token *tok, char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n  verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap);\n  exit(1);\n}\n\nvoid warn_tok(Token *tok, char *fmt, ...) {\n  va_list ap;\n  va_start(ap, fmt);\n  verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap);\n  va_end(ap);\n}\n\n// Consumes the current token if it matches `op`.\nbool equal(Token *tok, char *op) {\n  return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\\0';\n}\n\n// Ensure that the current token is `op`.\nToken *skip(Token *tok, char *op) {\n  if (!equal(tok, op))\n    error_tok(tok, \"expected '%s'\", op);\n  return tok->next;\n}\n\nbool consume(Token **rest, Token *tok, char *str) {\n  if (equal(tok, str)) {\n    *rest = tok->next;\n    return true;\n  }\n  *rest = tok;\n  return false;\n}\n\n// Create a new token.\nstatic Token *new_token(TokenKind kind, char *start, char *end) {\n  Token *tok = calloc(1, sizeof(Token));\n  tok->kind = kind;\n  tok->loc = start;\n  tok->len = end - start;\n  tok->file = current_file;\n  tok->filename = current_file->display_name;\n  tok->at_bol = at_bol;\n  tok->has_space = has_space;\n\n  at_bol = has_space = false;\n  return tok;\n}\n\nstatic bool startswith(char *p, char *q) {\n  return strncmp(p, q, strlen(q)) == 0;\n}\n\n// Read an identifier and returns the length of it.\n// If p does not point to a valid identifier, 0 is returned.\nstatic int read_ident(char *start) {\n  char *p = start;\n  uint32_t c = decode_utf8(&p, p);\n  if (!is_ident1(c))\n    return 0;\n\n  for (;;) {\n    char *q;\n    c = decode_utf8(&q, p);\n    if (!is_ident2(c))\n      return p - start;\n    p = q;\n  }\n}\n\nstatic int from_hex(char c) {\n  if ('0' <= c && c <= '9')\n    return c - '0';\n  if ('a' <= c && c <= 'f')\n    return c - 'a' + 10;\n  return c - 'A' + 10;\n}\n\n// Read a punctuator token from p and returns its length.\nstatic int read_punct(char *p) {\n  static char *kw[] = {\n    \"<<=\", \">>=\", \"...\", \"==\", \"!=\", \"<=\", \">=\", \"->\", \"+=\",\n    \"-=\", \"*=\", \"/=\", \"++\", \"--\", \"%=\", \"&=\", \"|=\", \"^=\", \"&&\",\n    \"||\", \"<<\", \">>\", \"##\",\n  };\n\n  for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)\n    if (startswith(p, kw[i]))\n      return strlen(kw[i]);\n\n  return ispunct(*p) ? 1 : 0;\n}\n\nstatic bool is_keyword(Token *tok) {\n  static HashMap map;\n\n  if (map.capacity == 0) {\n    static char *kw[] = {\n      \"return\", \"if\", \"else\", \"for\", \"while\", \"int\", \"sizeof\", \"char\",\n      \"struct\", \"union\", \"short\", \"long\", \"void\", \"typedef\", \"_Bool\",\n      \"enum\", \"static\", \"goto\", \"break\", \"continue\", \"switch\", \"case\",\n      \"default\", \"extern\", \"_Alignof\", \"_Alignas\", \"do\", \"signed\",\n      \"unsigned\", \"const\", \"volatile\", \"auto\", \"register\", \"restrict\",\n      \"__restrict\", \"__restrict__\", \"_Noreturn\", \"float\", \"double\",\n      \"typeof\", \"asm\", \"_Thread_local\", \"__thread\", \"_Atomic\",\n      \"__attribute__\",\n    };\n\n    for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)\n      hashmap_put(&map, kw[i], (void *)1);\n  }\n\n  return hashmap_get2(&map, tok->loc, tok->len);\n}\n\nstatic int read_escaped_char(char **new_pos, char *p) {\n  if ('0' <= *p && *p <= '7') {\n    // Read an octal number.\n    int c = *p++ - '0';\n    if ('0' <= *p && *p <= '7') {\n      c = (c << 3) + (*p++ - '0');\n      if ('0' <= *p && *p <= '7')\n        c = (c << 3) + (*p++ - '0');\n    }\n    *new_pos = p;\n    return c;\n  }\n\n  if (*p == 'x') {\n    // Read a hexadecimal number.\n    p++;\n    if (!isxdigit(*p))\n      error_at(p, \"invalid hex escape sequence\");\n\n    int c = 0;\n    for (; isxdigit(*p); p++)\n      c = (c << 4) + from_hex(*p);\n    *new_pos = p;\n    return c;\n  }\n\n  *new_pos = p + 1;\n\n  // Escape sequences are defined using themselves here. E.g.\n  // '\\n' is implemented using '\\n'. This tautological definition\n  // works because the compiler that compiles our compiler knows\n  // what '\\n' actually is. In other words, we \"inherit\" the ASCII\n  // code of '\\n' from the compiler that compiles our compiler,\n  // so we don't have to teach the actual code here.\n  //\n  // This fact has huge implications not only for the correctness\n  // of the compiler but also for the security of the generated code.\n  // For more info, read \"Reflections on Trusting Trust\" by Ken Thompson.\n  // https://github.com/rui314/chibicc/wiki/thompson1984.pdf\n  switch (*p) {\n  case 'a': return '\\a';\n  case 'b': return '\\b';\n  case 't': return '\\t';\n  case 'n': return '\\n';\n  case 'v': return '\\v';\n  case 'f': return '\\f';\n  case 'r': return '\\r';\n  // [GNU] \\e for the ASCII escape character is a GNU C extension.\n  case 'e': return 27;\n  default: return *p;\n  }\n}\n\n// Find a closing double-quote.\nstatic char *string_literal_end(char *p) {\n  char *start = p;\n  for (; *p != '\"'; p++) {\n    if (*p == '\\n' || *p == '\\0')\n      error_at(start, \"unclosed string literal\");\n    if (*p == '\\\\')\n      p++;\n  }\n  return p;\n}\n\nstatic Token *read_string_literal(char *start, char *quote) {\n  char *end = string_literal_end(quote + 1);\n  char *buf = calloc(1, end - quote);\n  int len = 0;\n\n  for (char *p = quote + 1; p < end;) {\n    if (*p == '\\\\')\n      buf[len++] = read_escaped_char(&p, p + 1);\n    else\n      buf[len++] = *p++;\n  }\n\n  Token *tok = new_token(TK_STR, start, end + 1);\n  tok->ty = array_of(ty_char, len + 1);\n  tok->str = buf;\n  return tok;\n}\n\n// Read a UTF-8-encoded string literal and transcode it in UTF-16.\n//\n// UTF-16 is yet another variable-width encoding for Unicode. Code\n// points smaller than U+10000 are encoded in 2 bytes. Code points\n// equal to or larger than that are encoded in 4 bytes. Each 2 bytes\n// in the 4 byte sequence is called \"surrogate\", and a 4 byte sequence\n// is called a \"surrogate pair\".\nstatic Token *read_utf16_string_literal(char *start, char *quote) {\n  char *end = string_literal_end(quote + 1);\n  uint16_t *buf = calloc(2, end - start);\n  int len = 0;\n\n  for (char *p = quote + 1; p < end;) {\n    if (*p == '\\\\') {\n      buf[len++] = read_escaped_char(&p, p + 1);\n      continue;\n    }\n\n    uint32_t c = decode_utf8(&p, p);\n    if (c < 0x10000) {\n      // Encode a code point in 2 bytes.\n      buf[len++] = c;\n    } else {\n      // Encode a code point in 4 bytes.\n      c -= 0x10000;\n      buf[len++] = 0xd800 + ((c >> 10) & 0x3ff);\n      buf[len++] = 0xdc00 + (c & 0x3ff);\n    }\n  }\n\n  Token *tok = new_token(TK_STR, start, end + 1);\n  tok->ty = array_of(ty_ushort, len + 1);\n  tok->str = (char *)buf;\n  return tok;\n}\n\n// Read a UTF-8-encoded string literal and transcode it in UTF-32.\n//\n// UTF-32 is a fixed-width encoding for Unicode. Each code point is\n// encoded in 4 bytes.\nstatic Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {\n  char *end = string_literal_end(quote + 1);\n  uint32_t *buf = calloc(4, end - quote);\n  int len = 0;\n\n  for (char *p = quote + 1; p < end;) {\n    if (*p == '\\\\')\n      buf[len++] = read_escaped_char(&p, p + 1);\n    else\n      buf[len++] = decode_utf8(&p, p);\n  }\n\n  Token *tok = new_token(TK_STR, start, end + 1);\n  tok->ty = array_of(ty, len + 1);\n  tok->str = (char *)buf;\n  return tok;\n}\n\nstatic Token *read_char_literal(char *start, char *quote, Type *ty) {\n  char *p = quote + 1;\n  if (*p == '\\0')\n    error_at(start, \"unclosed char literal\");\n\n  int c;\n  if (*p == '\\\\')\n    c = read_escaped_char(&p, p + 1);\n  else\n    c = decode_utf8(&p, p);\n\n  char *end = strchr(p, '\\'');\n  if (!end)\n    error_at(p, \"unclosed char literal\");\n\n  Token *tok = new_token(TK_NUM, start, end + 1);\n  tok->val = c;\n  tok->ty = ty;\n  return tok;\n}\n\nstatic bool convert_pp_int(Token *tok) {\n  char *p = tok->loc;\n\n  // Read a binary, octal, decimal or hexadecimal number.\n  int base = 10;\n  if (!strncasecmp(p, \"0x\", 2) && isxdigit(p[2])) {\n    p += 2;\n    base = 16;\n  } else if (!strncasecmp(p, \"0b\", 2) && (p[2] == '0' || p[2] == '1')) {\n    p += 2;\n    base = 2;\n  } else if (*p == '0') {\n    base = 8;\n  }\n\n  int64_t val = strtoul(p, &p, base);\n\n  // Read U, L or LL suffixes.\n  bool l = false;\n  bool u = false;\n\n  if (startswith(p, \"LLU\") || startswith(p, \"LLu\") ||\n      startswith(p, \"llU\") || startswith(p, \"llu\") ||\n      startswith(p, \"ULL\") || startswith(p, \"Ull\") ||\n      startswith(p, \"uLL\") || startswith(p, \"ull\")) {\n    p += 3;\n    l = u = true;\n  } else if (!strncasecmp(p, \"lu\", 2) || !strncasecmp(p, \"ul\", 2)) {\n    p += 2;\n    l = u = true;\n  } else if (startswith(p, \"LL\") || startswith(p, \"ll\")) {\n    p += 2;\n    l = true;\n  } else if (*p == 'L' || *p == 'l') {\n    p++;\n    l = true;\n  } else if (*p == 'U' || *p == 'u') {\n    p++;\n    u = true;\n  }\n\n  if (p != tok->loc + tok->len)\n    return false;\n\n  // Infer a type.\n  Type *ty;\n  if (base == 10) {\n    if (l && u)\n      ty = ty_ulong;\n    else if (l)\n      ty = ty_long;\n    else if (u)\n      ty = (val >> 32) ? ty_ulong : ty_uint;\n    else\n      ty = (val >> 31) ? ty_long : ty_int;\n  } else {\n    if (l && u)\n      ty = ty_ulong;\n    else if (l)\n      ty = (val >> 63) ? ty_ulong : ty_long;\n    else if (u)\n      ty = (val >> 32) ? ty_ulong : ty_uint;\n    else if (val >> 63)\n      ty = ty_ulong;\n    else if (val >> 32)\n      ty = ty_long;\n    else if (val >> 31)\n      ty = ty_uint;\n    else\n      ty = ty_int;\n  }\n\n  tok->kind = TK_NUM;\n  tok->val = val;\n  tok->ty = ty;\n  return true;\n}\n\n// The definition of the numeric literal at the preprocessing stage\n// is more relaxed than the definition of that at the later stages.\n// In order to handle that, a numeric literal is tokenized as a\n// \"pp-number\" token first and then converted to a regular number\n// token after preprocessing.\n//\n// This function converts a pp-number token to a regular number token.\nstatic void convert_pp_number(Token *tok) {\n  // Try to parse as an integer constant.\n  if (convert_pp_int(tok))\n    return;\n\n  // If it's not an integer, it must be a floating point constant.\n  char *end;\n  long double val = strtold(tok->loc, &end);\n\n  Type *ty;\n  if (*end == 'f' || *end == 'F') {\n    ty = ty_float;\n    end++;\n  } else if (*end == 'l' || *end == 'L') {\n    ty = ty_ldouble;\n    end++;\n  } else {\n    ty = ty_double;\n  }\n\n  if (tok->loc + tok->len != end)\n    error_tok(tok, \"invalid numeric constant\");\n\n  tok->kind = TK_NUM;\n  tok->fval = val;\n  tok->ty = ty;\n}\n\nvoid convert_pp_tokens(Token *tok) {\n  for (Token *t = tok; t->kind != TK_EOF; t = t->next) {\n    if (is_keyword(t))\n      t->kind = TK_KEYWORD;\n    else if (t->kind == TK_PP_NUM)\n      convert_pp_number(t);\n  }\n}\n\n// Initialize line info for all tokens.\nstatic void add_line_numbers(Token *tok) {\n  char *p = current_file->contents;\n  int n = 1;\n\n  do {\n    if (p == tok->loc) {\n      tok->line_no = n;\n      tok = tok->next;\n    }\n    if (*p == '\\n')\n      n++;\n  } while (*p++);\n}\n\nToken *tokenize_string_literal(Token *tok, Type *basety) {\n  Token *t;\n  if (basety->size == 2)\n    t = read_utf16_string_literal(tok->loc, tok->loc);\n  else\n    t = read_utf32_string_literal(tok->loc, tok->loc, basety);\n  t->next = tok->next;\n  return t;\n}\n\n// Tokenize a given string and returns new tokens.\nToken *tokenize(File *file) {\n  current_file = file;\n\n  char *p = file->contents;\n  Token head = {};\n  Token *cur = &head;\n\n  at_bol = true;\n  has_space = false;\n\n  while (*p) {\n    // Skip line comments.\n    if (startswith(p, \"//\")) {\n      p += 2;\n      while (*p != '\\n')\n        p++;\n      has_space = true;\n      continue;\n    }\n\n    // Skip block comments.\n    if (startswith(p, \"/*\")) {\n      char *q = strstr(p + 2, \"*/\");\n      if (!q)\n        error_at(p, \"unclosed block comment\");\n      p = q + 2;\n      has_space = true;\n      continue;\n    }\n\n    // Skip newline.\n    if (*p == '\\n') {\n      p++;\n      at_bol = true;\n      has_space = false;\n      continue;\n    }\n\n    // Skip whitespace characters.\n    if (isspace(*p)) {\n      p++;\n      has_space = true;\n      continue;\n    }\n\n    // Numeric literal\n    if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {\n      char *q = p++;\n      for (;;) {\n        if (p[0] && p[1] && strchr(\"eEpP\", p[0]) && strchr(\"+-\", p[1]))\n          p += 2;\n        else if (isalnum(*p) || *p == '.')\n          p++;\n        else\n          break;\n      }\n      cur = cur->next = new_token(TK_PP_NUM, q, p);\n      continue;\n    }\n\n    // String literal\n    if (*p == '\"') {\n      cur = cur->next = read_string_literal(p, p);\n      p += cur->len;\n      continue;\n    }\n\n    // UTF-8 string literal\n    if (startswith(p, \"u8\\\"\")) {\n      cur = cur->next = read_string_literal(p, p + 2);\n      p += cur->len;\n      continue;\n    }\n\n    // UTF-16 string literal\n    if (startswith(p, \"u\\\"\")) {\n      cur = cur->next = read_utf16_string_literal(p, p + 1);\n      p += cur->len;\n      continue;\n    }\n\n    // Wide string literal\n    if (startswith(p, \"L\\\"\")) {\n      cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);\n      p += cur->len;\n      continue;\n    }\n\n    // UTF-32 string literal\n    if (startswith(p, \"U\\\"\")) {\n      cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);\n      p += cur->len;\n      continue;\n    }\n\n    // Character literal\n    if (*p == '\\'') {\n      cur = cur->next = read_char_literal(p, p, ty_int);\n      cur->val = (char)cur->val;\n      p += cur->len;\n      continue;\n    }\n\n    // UTF-16 character literal\n    if (startswith(p, \"u'\")) {\n      cur = cur->next = read_char_literal(p, p + 1, ty_ushort);\n      cur->val &= 0xffff;\n      p += cur->len;\n      continue;\n    }\n\n    // Wide character literal\n    if (startswith(p, \"L'\")) {\n      cur = cur->next = read_char_literal(p, p + 1, ty_int);\n      p += cur->len;\n      continue;\n    }\n\n    // UTF-32 character literal\n    if (startswith(p, \"U'\")) {\n      cur = cur->next = read_char_literal(p, p + 1, ty_uint);\n      p += cur->len;\n      continue;\n    }\n\n    // Identifier or keyword\n    int ident_len = read_ident(p);\n    if (ident_len) {\n      cur = cur->next = new_token(TK_IDENT, p, p + ident_len);\n      p += cur->len;\n      continue;\n    }\n\n    // Punctuators\n    int punct_len = read_punct(p);\n    if (punct_len) {\n      cur = cur->next = new_token(TK_PUNCT, p, p + punct_len);\n      p += cur->len;\n      continue;\n    }\n\n    error_at(p, \"invalid token\");\n  }\n\n  cur = cur->next = new_token(TK_EOF, p, p);\n  add_line_numbers(head.next);\n  return head.next;\n}\n\n// Returns the contents of a given file.\nstatic char *read_file(char *path) {\n  FILE *fp;\n\n  if (strcmp(path, \"-\") == 0) {\n    // By convention, read from stdin if a given filename is \"-\".\n    fp = stdin;\n  } else {\n    fp = fopen(path, \"r\");\n    if (!fp)\n      return NULL;\n  }\n\n  char *buf;\n  size_t buflen;\n  FILE *out = open_memstream(&buf, &buflen);\n\n  // Read the entire file.\n  for (;;) {\n    char buf2[4096];\n    int n = fread(buf2, 1, sizeof(buf2), fp);\n    if (n == 0)\n      break;\n    fwrite(buf2, 1, n, out);\n  }\n\n  if (fp != stdin)\n    fclose(fp);\n\n  // Make sure that the last line is properly terminated with '\\n'.\n  fflush(out);\n  if (buflen == 0 || buf[buflen - 1] != '\\n')\n    fputc('\\n', out);\n  fputc('\\0', out);\n  fclose(out);\n  return buf;\n}\n\nFile **get_input_files(void) {\n  return input_files;\n}\n\nFile *new_file(char *name, int file_no, char *contents) {\n  File *file = calloc(1, sizeof(File));\n  file->name = name;\n  file->display_name = name;\n  file->file_no = file_no;\n  file->contents = contents;\n  return file;\n}\n\n// Replaces \\r or \\r\\n with \\n.\nstatic void canonicalize_newline(char *p) {\n  int i = 0, j = 0;\n\n  while (p[i]) {\n    if (p[i] == '\\r' && p[i + 1] == '\\n') {\n      i += 2;\n      p[j++] = '\\n';\n    } else if (p[i] == '\\r') {\n      i++;\n      p[j++] = '\\n';\n    } else {\n      p[j++] = p[i++];\n    }\n  }\n\n  p[j] = '\\0';\n}\n\n// Removes backslashes followed by a newline.\nstatic void remove_backslash_newline(char *p) {\n  int i = 0, j = 0;\n\n  // We want to keep the number of newline characters so that\n  // the logical line number matches the physical one.\n  // This counter maintain the number of newlines we have removed.\n  int n = 0;\n\n  while (p[i]) {\n    if (p[i] == '\\\\' && p[i + 1] == '\\n') {\n      i += 2;\n      n++;\n    } else if (p[i] == '\\n') {\n      p[j++] = p[i++];\n      for (; n > 0; n--)\n        p[j++] = '\\n';\n    } else {\n      p[j++] = p[i++];\n    }\n  }\n\n  for (; n > 0; n--)\n    p[j++] = '\\n';\n  p[j] = '\\0';\n}\n\nstatic uint32_t read_universal_char(char *p, int len) {\n  uint32_t c = 0;\n  for (int i = 0; i < len; i++) {\n    if (!isxdigit(p[i]))\n      return 0;\n    c = (c << 4) | from_hex(p[i]);\n  }\n  return c;\n}\n\n// Replace \\u or \\U escape sequences with corresponding UTF-8 bytes.\nstatic void convert_universal_chars(char *p) {\n  char *q = p;\n\n  while (*p) {\n    if (startswith(p, \"\\\\u\")) {\n      uint32_t c = read_universal_char(p + 2, 4);\n      if (c) {\n        p += 6;\n        q += encode_utf8(q, c);\n      } else {\n        *q++ = *p++;\n      }\n    } else if (startswith(p, \"\\\\U\")) {\n      uint32_t c = read_universal_char(p + 2, 8);\n      if (c) {\n        p += 10;\n        q += encode_utf8(q, c);\n      } else {\n        *q++ = *p++;\n      }\n    } else if (p[0] == '\\\\') {\n      *q++ = *p++;\n      *q++ = *p++;\n    } else {\n      *q++ = *p++;\n    }\n  }\n\n  *q = '\\0';\n}\n\nToken *tokenize_file(char *path) {\n  char *p = read_file(path);\n  if (!p)\n    return NULL;\n\n  // UTF-8 texts may start with a 3-byte \"BOM\" marker sequence.\n  // If exists, just skip them because they are useless bytes.\n  // (It is actually not recommended to add BOM markers to UTF-8\n  // texts, but it's not uncommon particularly on Windows.)\n  if (!memcmp(p, \"\\xef\\xbb\\xbf\", 3))\n    p += 3;\n\n  canonicalize_newline(p);\n  remove_backslash_newline(p);\n  convert_universal_chars(p);\n\n  // Save the filename for assembler .file directive.\n  static int file_no;\n  File *file = new_file(path, file_no + 1, p);\n\n  // Save the filename for assembler .file directive.\n  input_files = realloc(input_files, sizeof(char *) * (file_no + 2));\n  input_files[file_no] = file;\n  input_files[file_no + 1] = NULL;\n  file_no++;\n\n  return tokenize(file);\n}\n"
  },
  {
    "path": "type.c",
    "content": "#include \"chibicc.h\"\n\nType *ty_void = &(Type){TY_VOID, 1, 1};\nType *ty_bool = &(Type){TY_BOOL, 1, 1};\n\nType *ty_char = &(Type){TY_CHAR, 1, 1};\nType *ty_short = &(Type){TY_SHORT, 2, 2};\nType *ty_int = &(Type){TY_INT, 4, 4};\nType *ty_long = &(Type){TY_LONG, 8, 8};\n\nType *ty_uchar = &(Type){TY_CHAR, 1, 1, true};\nType *ty_ushort = &(Type){TY_SHORT, 2, 2, true};\nType *ty_uint = &(Type){TY_INT, 4, 4, true};\nType *ty_ulong = &(Type){TY_LONG, 8, 8, true};\n\nType *ty_float = &(Type){TY_FLOAT, 4, 4};\nType *ty_double = &(Type){TY_DOUBLE, 8, 8};\nType *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};\n\nstatic Type *new_type(TypeKind kind, int size, int align) {\n  Type *ty = calloc(1, sizeof(Type));\n  ty->kind = kind;\n  ty->size = size;\n  ty->align = align;\n  return ty;\n}\n\nbool is_integer(Type *ty) {\n  TypeKind k = ty->kind;\n  return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT ||\n         k == TY_INT  || k == TY_LONG || k == TY_ENUM;\n}\n\nbool is_flonum(Type *ty) {\n  return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE ||\n         ty->kind == TY_LDOUBLE;\n}\n\nbool is_numeric(Type *ty) {\n  return is_integer(ty) || is_flonum(ty);\n}\n\nbool is_compatible(Type *t1, Type *t2) {\n  if (t1 == t2)\n    return true;\n\n  if (t1->origin)\n    return is_compatible(t1->origin, t2);\n\n  if (t2->origin)\n    return is_compatible(t1, t2->origin);\n\n  if (t1->kind != t2->kind)\n    return false;\n\n  switch (t1->kind) {\n  case TY_CHAR:\n  case TY_SHORT:\n  case TY_INT:\n  case TY_LONG:\n    return t1->is_unsigned == t2->is_unsigned;\n  case TY_FLOAT:\n  case TY_DOUBLE:\n  case TY_LDOUBLE:\n    return true;\n  case TY_PTR:\n    return is_compatible(t1->base, t2->base);\n  case TY_FUNC: {\n    if (!is_compatible(t1->return_ty, t2->return_ty))\n      return false;\n    if (t1->is_variadic != t2->is_variadic)\n      return false;\n\n    Type *p1 = t1->params;\n    Type *p2 = t2->params;\n    for (; p1 && p2; p1 = p1->next, p2 = p2->next)\n      if (!is_compatible(p1, p2))\n        return false;\n    return p1 == NULL && p2 == NULL;\n  }\n  case TY_ARRAY:\n    if (!is_compatible(t1->base, t2->base))\n      return false;\n    return t1->array_len < 0 && t2->array_len < 0 &&\n           t1->array_len == t2->array_len;\n  }\n  return false;\n}\n\nType *copy_type(Type *ty) {\n  Type *ret = calloc(1, sizeof(Type));\n  *ret = *ty;\n  ret->origin = ty;\n  return ret;\n}\n\nType *pointer_to(Type *base) {\n  Type *ty = new_type(TY_PTR, 8, 8);\n  ty->base = base;\n  ty->is_unsigned = true;\n  return ty;\n}\n\nType *func_type(Type *return_ty) {\n  // The C spec disallows sizeof(<function type>), but\n  // GCC allows that and the expression is evaluated to 1.\n  Type *ty = new_type(TY_FUNC, 1, 1);\n  ty->return_ty = return_ty;\n  return ty;\n}\n\nType *array_of(Type *base, int len) {\n  Type *ty = new_type(TY_ARRAY, base->size * len, base->align);\n  ty->base = base;\n  ty->array_len = len;\n  return ty;\n}\n\nType *vla_of(Type *base, Node *len) {\n  Type *ty = new_type(TY_VLA, 8, 8);\n  ty->base = base;\n  ty->vla_len = len;\n  return ty;\n}\n\nType *enum_type(void) {\n  return new_type(TY_ENUM, 4, 4);\n}\n\nType *struct_type(void) {\n  return new_type(TY_STRUCT, 0, 1);\n}\n\nstatic Type *get_common_type(Type *ty1, Type *ty2) {\n  if (ty1->base)\n    return pointer_to(ty1->base);\n\n  if (ty1->kind == TY_FUNC)\n    return pointer_to(ty1);\n  if (ty2->kind == TY_FUNC)\n    return pointer_to(ty2);\n\n  if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE)\n    return ty_ldouble;\n  if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE)\n    return ty_double;\n  if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT)\n    return ty_float;\n\n  if (ty1->size < 4)\n    ty1 = ty_int;\n  if (ty2->size < 4)\n    ty2 = ty_int;\n\n  if (ty1->size != ty2->size)\n    return (ty1->size < ty2->size) ? ty2 : ty1;\n\n  if (ty2->is_unsigned)\n    return ty2;\n  return ty1;\n}\n\n// For many binary operators, we implicitly promote operands so that\n// both operands have the same type. Any integral type smaller than\n// int is always promoted to int. If the type of one operand is larger\n// than the other's (e.g. \"long\" vs. \"int\"), the smaller operand will\n// be promoted to match with the other.\n//\n// This operation is called the \"usual arithmetic conversion\".\nstatic void usual_arith_conv(Node **lhs, Node **rhs) {\n  Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty);\n  *lhs = new_cast(*lhs, ty);\n  *rhs = new_cast(*rhs, ty);\n}\n\nvoid add_type(Node *node) {\n  if (!node || node->ty)\n    return;\n\n  add_type(node->lhs);\n  add_type(node->rhs);\n  add_type(node->cond);\n  add_type(node->then);\n  add_type(node->els);\n  add_type(node->init);\n  add_type(node->inc);\n\n  for (Node *n = node->body; n; n = n->next)\n    add_type(n);\n  for (Node *n = node->args; n; n = n->next)\n    add_type(n);\n\n  switch (node->kind) {\n  case ND_NUM:\n    node->ty = ty_int;\n    return;\n  case ND_ADD:\n  case ND_SUB:\n  case ND_MUL:\n  case ND_DIV:\n  case ND_MOD:\n  case ND_BITAND:\n  case ND_BITOR:\n  case ND_BITXOR:\n    usual_arith_conv(&node->lhs, &node->rhs);\n    node->ty = node->lhs->ty;\n    return;\n  case ND_NEG: {\n    Type *ty = get_common_type(ty_int, node->lhs->ty);\n    node->lhs = new_cast(node->lhs, ty);\n    node->ty = ty;\n    return;\n  }\n  case ND_ASSIGN:\n    if (node->lhs->ty->kind == TY_ARRAY)\n      error_tok(node->lhs->tok, \"not an lvalue\");\n    if (node->lhs->ty->kind != TY_STRUCT)\n      node->rhs = new_cast(node->rhs, node->lhs->ty);\n    node->ty = node->lhs->ty;\n    return;\n  case ND_EQ:\n  case ND_NE:\n  case ND_LT:\n  case ND_LE:\n    usual_arith_conv(&node->lhs, &node->rhs);\n    node->ty = ty_int;\n    return;\n  case ND_FUNCALL:\n    node->ty = node->func_ty->return_ty;\n    return;\n  case ND_NOT:\n  case ND_LOGOR:\n  case ND_LOGAND:\n    node->ty = ty_int;\n    return;\n  case ND_BITNOT:\n  case ND_SHL:\n  case ND_SHR:\n    node->ty = node->lhs->ty;\n    return;\n  case ND_VAR:\n  case ND_VLA_PTR:\n    node->ty = node->var->ty;\n    return;\n  case ND_COND:\n    if (node->then->ty->kind == TY_VOID || node->els->ty->kind == TY_VOID) {\n      node->ty = ty_void;\n    } else {\n      usual_arith_conv(&node->then, &node->els);\n      node->ty = node->then->ty;\n    }\n    return;\n  case ND_COMMA:\n    node->ty = node->rhs->ty;\n    return;\n  case ND_MEMBER:\n    node->ty = node->member->ty;\n    return;\n  case ND_ADDR: {\n    Type *ty = node->lhs->ty;\n    if (ty->kind == TY_ARRAY)\n      node->ty = pointer_to(ty->base);\n    else\n      node->ty = pointer_to(ty);\n    return;\n  }\n  case ND_DEREF:\n    if (!node->lhs->ty->base)\n      error_tok(node->tok, \"invalid pointer dereference\");\n    if (node->lhs->ty->base->kind == TY_VOID)\n      error_tok(node->tok, \"dereferencing a void pointer\");\n\n    node->ty = node->lhs->ty->base;\n    return;\n  case ND_STMT_EXPR:\n    if (node->body) {\n      Node *stmt = node->body;\n      while (stmt->next)\n        stmt = stmt->next;\n      if (stmt->kind == ND_EXPR_STMT) {\n        node->ty = stmt->lhs->ty;\n        return;\n      }\n    }\n    error_tok(node->tok, \"statement expression returning void is not supported\");\n    return;\n  case ND_LABEL_VAL:\n    node->ty = pointer_to(ty_void);\n    return;\n  case ND_CAS:\n    add_type(node->cas_addr);\n    add_type(node->cas_old);\n    add_type(node->cas_new);\n    node->ty = ty_bool;\n\n    if (node->cas_addr->ty->kind != TY_PTR)\n      error_tok(node->cas_addr->tok, \"pointer expected\");\n    if (node->cas_old->ty->kind != TY_PTR)\n      error_tok(node->cas_old->tok, \"pointer expected\");\n    return;\n  case ND_EXCH:\n    if (node->lhs->ty->kind != TY_PTR)\n      error_tok(node->cas_addr->tok, \"pointer expected\");\n    node->ty = node->lhs->ty->base;\n    return;\n  }\n}\n"
  },
  {
    "path": "unicode.c",
    "content": "#include \"chibicc.h\"\n\n// Encode a given character in UTF-8.\nint encode_utf8(char *buf, uint32_t c) {\n  if (c <= 0x7F) {\n    buf[0] = c;\n    return 1;\n  }\n\n  if (c <= 0x7FF) {\n    buf[0] = 0b11000000 | (c >> 6);\n    buf[1] = 0b10000000 | (c & 0b00111111);\n    return 2;\n  }\n\n  if (c <= 0xFFFF) {\n    buf[0] = 0b11100000 | (c >> 12);\n    buf[1] = 0b10000000 | ((c >> 6) & 0b00111111);\n    buf[2] = 0b10000000 | (c & 0b00111111);\n    return 3;\n  }\n\n  buf[0] = 0b11110000 | (c >> 18);\n  buf[1] = 0b10000000 | ((c >> 12) & 0b00111111);\n  buf[2] = 0b10000000 | ((c >> 6) & 0b00111111);\n  buf[3] = 0b10000000 | (c & 0b00111111);\n  return 4;\n}\n\n// Read a UTF-8-encoded Unicode code point from a source file.\n// We assume that source files are always in UTF-8.\n//\n// UTF-8 is a variable-width encoding in which one code point is\n// encoded in one to four bytes. One byte UTF-8 code points are\n// identical to ASCII. Non-ASCII characters are encoded using more\n// than one byte.\nuint32_t decode_utf8(char **new_pos, char *p) {\n  if ((unsigned char)*p < 128) {\n    *new_pos = p + 1;\n    return *p;\n  }\n\n  char *start = p;\n  int len;\n  uint32_t c;\n\n  if ((unsigned char)*p >= 0b11110000) {\n    len = 4;\n    c = *p & 0b111;\n  } else if ((unsigned char)*p >= 0b11100000) {\n    len = 3;\n    c = *p & 0b1111;\n  } else if ((unsigned char)*p >= 0b11000000) {\n    len = 2;\n    c = *p & 0b11111;\n  } else {\n    error_at(start, \"invalid UTF-8 sequence\");\n  }\n\n  for (int i = 1; i < len; i++) {\n    if ((unsigned char)p[i] >> 6 != 0b10)\n      error_at(start, \"invalid UTF-8 sequence\");\n    c = (c << 6) | (p[i] & 0b111111);\n  }\n\n  *new_pos = p + len;\n  return c;\n}\n\nstatic bool in_range(uint32_t *range, uint32_t c) {\n  for (int i = 0; range[i] != -1; i += 2)\n    if (range[i] <= c && c <= range[i + 1])\n      return true;\n  return false;\n}\n\n// [https://www.sigbus.info/n1570#D] C11 allows not only ASCII but\n// some multibyte characters in certan Unicode ranges to be used in an\n// identifier.\n//\n// This function returns true if a given character is acceptable as\n// the first character of an identifier.\n//\n// For example, ¾ (U+00BE) is a valid identifier because characters in\n// 0x00BE-0x00C0 are allowed, while neither ⟘ (U+27D8) nor '　'\n// (U+3000, full-width space) are allowed because they are out of range.\nbool is_ident1(uint32_t c) {\n  static uint32_t range[] = {\n    '_', '_', 'a', 'z', 'A', 'Z', '$', '$',\n    0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,\n    0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,\n    0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,\n    0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D,\n    0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F,\n    0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793,\n    0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F,\n    0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF,\n    0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD,\n    0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD,\n    0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD,\n    0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD,\n    0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, -1,\n  };\n\n  return in_range(range, c);\n}\n\n// Returns true if a given character is acceptable as a non-first\n// character of an identifier.\nbool is_ident2(uint32_t c) {\n  static uint32_t range[] = {\n    '0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF,\n    0xFE20, 0xFE2F, -1,\n  };\n\n  return is_ident1(c) || in_range(range, c);\n}\n\n// Returns the number of columns needed to display a given\n// character in a fixed-width font.\n//\n// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\nstatic int char_width(uint32_t c) {\n  static uint32_t range1[] = {\n    0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,\n    0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,\n    0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,\n    0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,\n    0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,\n    0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,\n    0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,\n    0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,\n    0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,\n    0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,\n    0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,\n    0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,\n    0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,\n    0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,\n    0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,\n    0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,\n    0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,\n    0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,\n    0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,\n    0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,\n    0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,\n    0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,\n    0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,\n    0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,\n    0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,\n    0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,\n    0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,\n    0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,\n    0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,\n    0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,\n    0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,\n    0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,\n    0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,\n    0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,\n    0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,\n    0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,\n    -1,\n  };\n\n  if (in_range(range1, c))\n    return 0;\n\n  static uint32_t range2[] = {\n    0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,\n    0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,\n    0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,\n    0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1,\n  };\n\n  if (in_range(range2, c))\n    return 2;\n  return 1;\n}\n\n// Returns the number of columns needed to display a given\n// string in a fixed-width font.\nint display_width(char *p, int len) {\n  char *start = p;\n  int w = 0;\n  while (p - start < len) {\n    uint32_t c = decode_utf8(&p, p);\n    w += char_width(c);\n  }\n  return w;\n}\n"
  }
]