Add chibicc
This program popped up on Hacker News recently. It's the only modern compiler I've ever seen that doesn't have dependencies and is easily modified. So I added all of the missing GNU extensions I like to use which means it might be possible soon to build on non-Linux and have third party not vendor gcc binaries.
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Rui Ueyama
|
||||
Copyright (c) 2020 Justine Alexandra Roberts Tunney
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
30
third_party/chibicc/README.cosmo
vendored
Normal file
30
third_party/chibicc/README.cosmo
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
chibicc is the simplest/tiniest/hackable/readable c11 compiler in the
|
||||
world that can build projects like python but goes 2x slower than gcc
|
||||
with 2x the code size, because it doesn't optimize or color registers
|
||||
although it can compile code at 5x the speed and could be even faster
|
||||
which is great, considering it's a 220kb αcτµαlly pδrταblε εxεcµταblε
|
||||
|
||||
local enhancements
|
||||
|
||||
- support __asm__
|
||||
- support __int128
|
||||
- support __vector_size__
|
||||
- support __builtin_memcpy
|
||||
- support __builtin_constant_p, __builtin_likely, etc.
|
||||
- support __builtin_isunordered, __builtin_islessgreater, etc.
|
||||
- support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc.
|
||||
- support __constructor__, __destructor__, __section__, __cold__, etc.
|
||||
- improve error messages to trace macro expansions
|
||||
- reduce #lines of generated assembly by a third
|
||||
- reduce #bytes of generated binary by a third
|
||||
|
||||
local bug fixes
|
||||
|
||||
- fix 64-bit bug in generated code for struct bitfields
|
||||
|
||||
local changes
|
||||
|
||||
- use tabs in generated output
|
||||
- generated code no longer assumes red zone
|
||||
- emit .size directives for function definitions
|
||||
- use fisttp long double conversions if built w/ -msse3
|
||||
134
third_party/chibicc/README.md
vendored
Normal file
134
third_party/chibicc/README.md
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
# chibicc: A Small C Compiler
|
||||
|
||||
(The old master has moved to
|
||||
[historical/old](https://github.com/rui314/chibicc/tree/historical/old)
|
||||
branch. This is a new one uploaded in September 2020.)
|
||||
|
||||
chibicc is yet another small C compiler that implements most C11
|
||||
features. Even though it still probably falls into the "toy compilers"
|
||||
category just like other small compilers do, chibicc can compile several
|
||||
real-world programs, including [Git](https://git-scm.com/),
|
||||
[SQLite](https://sqlite.org) and
|
||||
[libpng](http://www.libpng.org/pub/png/libpng.html), without making
|
||||
modifications to the compiled programs. Generated executables of these
|
||||
programs pass their corresponding test suites. So, chibicc actually
|
||||
supports a wide variety of C11 features and is able to compile hundreds of
|
||||
thousands of lines of real-world C code correctly.
|
||||
|
||||
chibicc is developed as the reference implementation for a book I'm
|
||||
currently writing about the C compiler and the low-level programming.
|
||||
The book covers the vast topic with an incremental approach; in the first
|
||||
chapter, readers will implement a "compiler" that accepts just a single
|
||||
number as a "language", which will then gain one feature at a time in each
|
||||
section of the book until the language that the compiler accepts matches
|
||||
what the C11 spec specifies. I took this incremental approach from [the
|
||||
paper](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz
|
||||
Ghuloum.
|
||||
|
||||
Each commit of this project corresponds to a section of the book. For this
|
||||
purpose, not only the final state of the project but each commit was
|
||||
carefully written with readability in mind. Readers should be able to learn
|
||||
how a C language feature can be implemented just by reading one or a few
|
||||
commits of this project. For example, this is how
|
||||
[while](https://github.com/rui314/chibicc/commit/773115ab2a9c4b96f804311b95b20e9771f0190a),
|
||||
[[]](https://github.com/rui314/chibicc/commit/75fbd3dd6efde12eac8225d8b5723093836170a5),
|
||||
[?:](https://github.com/rui314/chibicc/commit/1d0e942fd567a35d296d0f10b7693e98b3dd037c),
|
||||
and [thread-local
|
||||
variable](https://github.com/rui314/chibicc/commit/79644e54cc1805e54428cde68b20d6d493b76d34)
|
||||
are implemented. If you have plenty of spare time, it might be fun to read
|
||||
it from the [first
|
||||
commit](https://github.com/rui314/chibicc/commit/0522e2d77e3ab82d3b80a5be8dbbdc8d4180561c).
|
||||
|
||||
If you like this project, please consider purchasing a copy of the book
|
||||
when it becomes available! 😀 I publish the source code here to give people
|
||||
early access to it, because I was planing to do that anyway with a
|
||||
permissive open-source license after publishing the book. If I don't charge
|
||||
for the source code, it doesn't make much sense to me to keep it private. I
|
||||
hope to publish the book in 2021.
|
||||
|
||||
I pronounce chibicc as _chee bee cee cee_. "chibi" means "mini" or
|
||||
"small" in Japanese. "cc" stands for C compiler.
|
||||
|
||||
## Status
|
||||
|
||||
Features that are often missing in a small compiler but supported by
|
||||
chibicc include (but not limited to):
|
||||
|
||||
- Preprocessor
|
||||
- long double (x87 80-bit floting point numbers)
|
||||
- Bit-field
|
||||
- alloca()
|
||||
- Variable-length array
|
||||
- Thread-local variable
|
||||
- Atomic variable
|
||||
- Common symbol
|
||||
- Designated initializer
|
||||
- L, u, U and u8 string literals
|
||||
|
||||
chibicc does not support digraphs, trigraphs, complex numbers, K&R-style
|
||||
function prototype, and inline assembly.
|
||||
|
||||
chibicc outputs a simple but nice error message when it finds an error in
|
||||
source code.
|
||||
|
||||
There's no optimization pass. chibicc emits terrible code which is probably
|
||||
twice or more slower than GCC's output. I have a plan to add an
|
||||
optimization pass once the frontend is done.
|
||||
|
||||
## Internals
|
||||
|
||||
chibicc consists of the following stages:
|
||||
|
||||
- Tokenize: A tokenizer takes a string as an input, breaks it into a list
|
||||
of tokens and returns them.
|
||||
|
||||
- Preprocess: A preprocessor takes as an input a list of tokens and output
|
||||
a new list of macro-expanded tokens. It interprets preprocessor
|
||||
directives while expanding macros.
|
||||
|
||||
- Parse: A recursive descendent parser constructs abstract syntax trees
|
||||
from the output of the preprocessor. It also adds a type to each AST
|
||||
node.
|
||||
|
||||
- Codegen: A code generator emits an assembly text for given AST nodes.
|
||||
|
||||
## Contributing
|
||||
|
||||
When I find a bug in this compiler, I go back to the original commit that
|
||||
introduced the bug and rewrite the commit history as if there were no such
|
||||
bug from the beginning. This is an unusual way of fixing bugs, but as a a
|
||||
part of a book, it is important to keep every commit bug-free.
|
||||
|
||||
Thus, I do not take pull requests in this repo. You can send me a pull
|
||||
request if you find a bug, but it is very likely that I will read your
|
||||
patch and then apply that to my previous commits by rewriting history. I'll
|
||||
credit your name somewhere, but your changes will be rewritten by me before
|
||||
submitted to this repository.
|
||||
|
||||
Also, please assume that I will occasionally force-push my local repository
|
||||
to this public one to rewrite history. If you clone this project and make
|
||||
local commits on top of it, your changes will have to be rebased by hand
|
||||
when I force-push new commits.
|
||||
|
||||
## About the Author
|
||||
|
||||
I'm Rui Ueyama. I'm the creator of [8cc](https://github.com/rui314/8cc),
|
||||
which is a hobby C compiler, and also the original creator of the current
|
||||
version of [LLVM lld](https://lld.llvm.org) linker, which is a
|
||||
production-quality linker used by various operating systems and large-scale
|
||||
build systems.
|
||||
|
||||
## References
|
||||
|
||||
- [tcc](https://bellard.org/tcc/): A small C compiler written by Fabrice
|
||||
Bellard. I learned a lot from this compiler, but the design of tcc and
|
||||
chibicc are different. In particular, tcc is a one-pass compiler, while
|
||||
chibicc is a multi-pass one.
|
||||
|
||||
- [lcc](https://github.com/drh/lcc): Another small C compiler. The creators
|
||||
wrote a [book](https://sites.google.com/site/lccretargetablecompiler/)
|
||||
about the internals of lcc, which I found a good resource to see how a
|
||||
compiler is implemented.
|
||||
|
||||
- [An Incremental Approach to Compiler
|
||||
Construction](http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf)
|
||||
751
third_party/chibicc/asm.c
vendored
Normal file
751
third_party/chibicc/asm.c
vendored
Normal file
@ -0,0 +1,751 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
#define PRECIOUS 0b1111000000101000 // bx,bp,r12-r15
|
||||
|
||||
static const char kGreg[4][16][5] = {
|
||||
{"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b",
|
||||
"r11b", "r12b", "r13b", "r14b", "r15b"},
|
||||
{"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w",
|
||||
"r11w", "r12w", "r13w", "r14w", "r15w"},
|
||||
{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d",
|
||||
"r10d", "r11d", "r12d", "r13d", "r14d", "r15d"},
|
||||
{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10",
|
||||
"r11", "r12", "r13", "r14", "r15"},
|
||||
};
|
||||
|
||||
StaticAsm *staticasms;
|
||||
|
||||
static void DecodeAsmConstraints(AsmOperand *op) {
|
||||
int i;
|
||||
char c;
|
||||
for (i = 0;;) {
|
||||
switch ((c = op->str[i++])) {
|
||||
case '\0':
|
||||
case ',': // alternative group
|
||||
return;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': // reference
|
||||
case '=': // output
|
||||
case '+': // output and input
|
||||
op->flow = c;
|
||||
break;
|
||||
case 'm': // memory
|
||||
case 'o': // memory offsetable
|
||||
op->type |= kAsmMem;
|
||||
op->regmask |= 0b1111111111111111;
|
||||
break;
|
||||
case 'i': // int literal, c/asm constexpr, ld embedding
|
||||
case 'n': // integer literal or compiler constexpr?
|
||||
case 's': // integer constexpr but not literal (or known at link time?)
|
||||
case 'M': // i∊[0,3] for index scaling, e.g. "mov\t(?,?,1<<%0),?"
|
||||
case 'I': // i∊[0,31] 5 bits for 32-bit shifts
|
||||
case 'J': // i∊[0,63] 6 bits for 64-bit shifts
|
||||
case 'N': // i∊[0,255] in/out immediate byte
|
||||
case 'K': // i∊[-128,127] signed byte integer
|
||||
case 'Z': // i∊[0,2³²) for zero-extending
|
||||
case 'L': // i∊{0xFF,0xFFFF,0xFFFFFFFF}
|
||||
op->type |= kAsmImm;
|
||||
break;
|
||||
case 'a': // ax
|
||||
op->regmask |= 0b0000000000000001;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'c': // cx
|
||||
op->regmask |= 0b0000000000000010;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'd': // dx
|
||||
op->regmask |= 0b0000000000000100;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'b': // bx
|
||||
op->regmask |= 0b0000000000001000;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'S': // si
|
||||
op->regmask |= 0b0000000001000000;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'D': // di
|
||||
op->regmask |= 0b0000000010000000;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'r': // general register
|
||||
op->regmask |= 0b1111111111111111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'q': // greg lo-byte accessible
|
||||
op->regmask |= 0b1111111111111111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'Q': // greg hi-byte accessible
|
||||
op->regmask |= 0b0000000000001111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'U': // greg call-clobbered
|
||||
op->regmask |= 0b0000111111000111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'R': // greg all models
|
||||
op->regmask |= 0b0000000011111111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'l': // index register
|
||||
op->regmask |= 0b1111111111101111;
|
||||
op->type |= kAsmReg;
|
||||
break;
|
||||
case 'y': // mmx
|
||||
op->type |= kAsmMmx;
|
||||
op->regmask |= 0b0000000011111111;
|
||||
break;
|
||||
case 'x': // xmm
|
||||
op->type |= kAsmXmm;
|
||||
op->regmask |= 0b1111111111111111;
|
||||
break;
|
||||
case 'g': // rmi
|
||||
op->type |= kAsmImm | kAsmMem | kAsmReg;
|
||||
op->regmask |= 0b1111111111111111;
|
||||
break;
|
||||
case 'X': // anything
|
||||
op->type |= kAsmImm | kAsmMem | kAsmReg | kAsmXmm | kAsmFpu | kAsmRaw;
|
||||
op->regmask |= 0b1111111111111111;
|
||||
op->x87mask |= 0b11111111;
|
||||
break;
|
||||
case 't': // %st
|
||||
op->type |= kAsmFpu;
|
||||
op->x87mask |= 0b00000001;
|
||||
break;
|
||||
case 'u': // %st(1)
|
||||
op->type |= kAsmFpu;
|
||||
op->x87mask |= 0b00000010;
|
||||
break;
|
||||
case 'f': // %st(0..7)
|
||||
op->type |= kAsmFpu;
|
||||
op->x87mask |= 0b11111111;
|
||||
break;
|
||||
case 'A': // ax+dx
|
||||
error_tok(op->tok, "ax dx constraint not implemented");
|
||||
case '@': // flags
|
||||
if (op->flow != '=' || strlen(op->str + i) < 3 ||
|
||||
(op->str[i] != 'c' || op->str[i + 1] != 'c')) {
|
||||
error_tok(op->tok, "invalid flag constraint");
|
||||
}
|
||||
if (!is_integer(op->node->ty) || op->node->ty->size != 1) {
|
||||
error_tok(op->node->tok, "invalid output flag type");
|
||||
}
|
||||
op->type = kAsmFlag;
|
||||
op->predicate = i + 2;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsLvalue(AsmOperand *op) {
|
||||
switch (op->node->kind) {
|
||||
case ND_VAR:
|
||||
case ND_DEREF:
|
||||
case ND_MEMBER:
|
||||
case ND_VLA_PTR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanUseReg(Node *n) {
|
||||
return is_integer(n->ty) || n->ty->kind == TY_PTR;
|
||||
}
|
||||
|
||||
static bool CanUseXmm(Node *n) {
|
||||
return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE ||
|
||||
n->ty->kind == TY_PTR ||
|
||||
(n->ty->kind == TY_ARRAY && n->ty->size == 16);
|
||||
}
|
||||
|
||||
static bool CanUseMmx(Node *n) {
|
||||
return n->ty->kind == TY_FLOAT || n->ty->kind == TY_DOUBLE ||
|
||||
n->ty->kind == TY_PTR || (n->ty->kind == TY_ARRAY && n->ty->size == 8);
|
||||
}
|
||||
|
||||
static int PickAsmReferenceType(AsmOperand *op, AsmOperand *ref) {
|
||||
switch (ref->type) {
|
||||
case kAsmImm:
|
||||
case kAsmMem:
|
||||
error_tok(op->tok, "bad reference");
|
||||
case kAsmReg:
|
||||
if (!CanUseReg(op->node)) {
|
||||
error_tok(op->tok, "expected integral expression");
|
||||
}
|
||||
op->regmask = 0;
|
||||
return ref->type;
|
||||
case kAsmXmm:
|
||||
if (!CanUseXmm(op->node)) {
|
||||
error_tok(op->tok, "expected xmm expression");
|
||||
}
|
||||
return ref->type;
|
||||
case kAsmFpu:
|
||||
if (op->node->ty->kind != TY_LDOUBLE) {
|
||||
error_tok(op->tok, "expected long double expression");
|
||||
}
|
||||
op->x87mask = 0;
|
||||
return ref->type;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static int PickAsmOperandType(Asm *a, AsmOperand *op) {
|
||||
if (op->flow == '=' || op->flow == '+') {
|
||||
op->type &= ~kAsmImm;
|
||||
if (!IsLvalue(op)) error_tok(op->tok, "lvalue required");
|
||||
}
|
||||
if ((op->type & kAsmImm) && is_const_expr(op->node)) {
|
||||
op->val = eval2(op->node, &op->label);
|
||||
return kAsmImm;
|
||||
}
|
||||
if ((op->type & kAsmMem) && op->node->ty->kind != TY_VOID) return kAsmMem;
|
||||
if ((op->type & kAsmFpu) && op->node->ty->kind == TY_LDOUBLE) return kAsmFpu;
|
||||
if ((op->type & kAsmXmm) && CanUseXmm(op->node)) return kAsmXmm;
|
||||
if ((op->type & kAsmMmx) && CanUseMmx(op->node)) return kAsmMmx;
|
||||
if ((op->type & kAsmReg) && CanUseReg(op->node)) return kAsmReg;
|
||||
if (op->type & kAsmFlag) return kAsmFlag;
|
||||
if (op->type & kAsmRaw) return kAsmRaw;
|
||||
error_tok(op->tok, "constraint mismatch");
|
||||
}
|
||||
|
||||
static Token *ParseAsmOperand(Asm *a, AsmOperand *op, Token *tok) {
|
||||
int i;
|
||||
op->tok = tok;
|
||||
op->str = ConsumeStringLiteral(&tok, tok);
|
||||
tok = skip(tok, "(");
|
||||
op->node = expr(&tok, tok);
|
||||
add_type(op->node);
|
||||
DecodeAsmConstraints(op);
|
||||
if (isdigit(op->flow)) {
|
||||
if ((i = op->flow - '0') >= a->n) error_tok(op->tok, "bad reference");
|
||||
op->type = PickAsmReferenceType(op, a->ops + i);
|
||||
} else {
|
||||
op->type = PickAsmOperandType(a, op);
|
||||
}
|
||||
return skip(tok, ")");
|
||||
}
|
||||
|
||||
static Token *ParseAsmOperands(Asm *a, Token *tok) {
|
||||
if (EQUAL(tok, ":")) return tok;
|
||||
for (;;) {
|
||||
if (a->n == ARRAYLEN(a->ops)) {
|
||||
error_tok(tok, "too many asm operands");
|
||||
}
|
||||
tok = ParseAsmOperand(a, &a->ops[a->n], tok);
|
||||
++a->n;
|
||||
if (!EQUAL(tok, ",")) break;
|
||||
tok = skip(tok, ",");
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
static void CouldNotAllocateRegister(AsmOperand *op) {
|
||||
error_tok(op->tok, "could not allocate register");
|
||||
}
|
||||
|
||||
static void PickAsmRegisters(Asm *a) {
|
||||
int i, j, m, regset, xmmset, x87sts;
|
||||
regset = 0b0000111111000111; // exclude bx,sp,bp,r12-r15
|
||||
xmmset = 0b1111111111111111;
|
||||
x87sts = 0b0000000011111111;
|
||||
regset ^= regset & a->regclob; // don't allocate from clobber list
|
||||
xmmset ^= xmmset & a->xmmclob;
|
||||
x87sts ^= x87sts & a->x87clob;
|
||||
for (j = 1; j <= 16; ++j) { // iterate from most to least restrictive
|
||||
for (i = 0; i < a->n; ++i) {
|
||||
switch (a->ops[i].type) {
|
||||
case kAsmMem:
|
||||
case kAsmReg:
|
||||
if (!(m = a->ops[i].regmask)) break;
|
||||
if (popcnt(m) != j) break;
|
||||
if (!(m &= regset)) CouldNotAllocateRegister(&a->ops[i]);
|
||||
regset &= ~(1 << (a->ops[i].reg = bsf(m)));
|
||||
a->ops[i].regmask = 0;
|
||||
break;
|
||||
case kAsmXmm:
|
||||
if (!(m = a->ops[i].regmask)) break;
|
||||
if (!(m &= xmmset)) CouldNotAllocateRegister(&a->ops[i]);
|
||||
xmmset &= ~(1 << (a->ops[i].reg = bsf(m)));
|
||||
a->ops[i].regmask = 0;
|
||||
break;
|
||||
case kAsmFpu:
|
||||
if (!(m = a->ops[i].x87mask)) break;
|
||||
if (popcnt(m) != j) break;
|
||||
if (!(m &= x87sts)) CouldNotAllocateRegister(&a->ops[i]);
|
||||
x87sts &= ~(1 << (a->ops[i].reg = bsf(m)));
|
||||
a->ops[i].x87mask = 0;
|
||||
break;
|
||||
default:
|
||||
a->ops[i].regmask = 0;
|
||||
a->ops[i].x87mask = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < a->n; ++i) {
|
||||
assert(!a->ops[i].regmask);
|
||||
assert(!a->ops[i].x87mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void MarkUsedAsmOperands(Asm *a) {
|
||||
char c, *p;
|
||||
if (!a->isgnu) return;
|
||||
for (p = a->str; (c = *p++);) {
|
||||
if (c == '%') {
|
||||
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
|
||||
if (c == '%') continue;
|
||||
if (!isdigit(c)) {
|
||||
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
|
||||
if (!isdigit(c)) {
|
||||
error_tok(a->tok, "bad asm specifier");
|
||||
}
|
||||
}
|
||||
a->ops[c - '0'].isused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int GetIndexOfRegisterName(const char *s) {
|
||||
int i, j;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
if (!strcmp(s, kGreg[j][i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Token *ParseAsmClobbers(Asm *a, Token *tok) {
|
||||
int i;
|
||||
char *s;
|
||||
Token *stok;
|
||||
for (;;) {
|
||||
stok = tok;
|
||||
s = ConsumeStringLiteral(&tok, tok);
|
||||
if (*s == '%') ++s;
|
||||
if (!strcmp(s, "cc")) {
|
||||
a->flagclob = true;
|
||||
} else if ((i = GetIndexOfRegisterName(s)) != -1) {
|
||||
a->regclob |= 1 << i;
|
||||
} else if (startswith(s, "xmm") && isdigit(s[3]) &&
|
||||
(!s[4] || isdigit(s[4]))) {
|
||||
i = s[3] - '0';
|
||||
if (s[4]) {
|
||||
i *= 10;
|
||||
i += s[4] - '0';
|
||||
}
|
||||
i &= 15;
|
||||
a->xmmclob |= 1 << i;
|
||||
} else if (!strcmp(s, "st")) {
|
||||
a->x87clob |= 1;
|
||||
} else if (startswith(s, "st(") && isdigit(s[3]) && s[4] == ')') {
|
||||
i = s[3] - '0';
|
||||
i &= 7;
|
||||
a->x87clob |= 1 << i;
|
||||
} else {
|
||||
error_tok(stok, "unknown clobber register");
|
||||
}
|
||||
if (!EQUAL(tok, ",")) break;
|
||||
tok = skip(tok, ",");
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
// parses ansi c11 asm statement officially defined as follows
|
||||
//
|
||||
// asm-stmt = "asm" ("volatile" | "inline")* "(" string-literal ")"
|
||||
//
|
||||
// gnu c defines a notation for inputs, outputs, and clobbers, e.g.
|
||||
//
|
||||
// asm("foo %1,%0"
|
||||
// : "=r"(x)
|
||||
// : "r"(x)
|
||||
// : "cc");
|
||||
//
|
||||
Asm *asm_stmt(Token **rest, Token *tok) {
|
||||
Asm *a = calloc(1, sizeof(Asm));
|
||||
tok = tok->next;
|
||||
while (EQUAL(tok, "volatile") || EQUAL(tok, "inline")) tok = tok->next;
|
||||
tok = skip(tok, "(");
|
||||
a->tok = tok;
|
||||
a->str = ConsumeStringLiteral(&tok, tok);
|
||||
if (!EQUAL(tok, ")")) {
|
||||
a->isgnu = true;
|
||||
tok = skip(tok, ":");
|
||||
tok = ParseAsmOperands(a, tok);
|
||||
if (!EQUAL(tok, ")")) {
|
||||
tok = skip(tok, ":");
|
||||
tok = ParseAsmOperands(a, tok);
|
||||
if (!EQUAL(tok, ")")) {
|
||||
tok = skip(tok, ":");
|
||||
tok = ParseAsmClobbers(a, tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
PickAsmRegisters(a);
|
||||
MarkUsedAsmOperands(a);
|
||||
*rest = skip(tok, ")");
|
||||
return a;
|
||||
}
|
||||
|
||||
static void PrintAsmConstant(AsmOperand *op) {
|
||||
if (op->label) {
|
||||
fprintf(output_stream, "%s%+ld", *op->label, op->val);
|
||||
} else {
|
||||
fprintf(output_stream, "%ld", op->val);
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitAsmSpecifier(AsmOperand *op, int q, int z) {
|
||||
if (!q) {
|
||||
switch (op->type) {
|
||||
case kAsmImm:
|
||||
fputc('$', output_stream);
|
||||
PrintAsmConstant(op);
|
||||
break;
|
||||
case kAsmMem:
|
||||
fprintf(output_stream, "(%%%s)", kGreg[3][op->reg]);
|
||||
break;
|
||||
case kAsmReg:
|
||||
fprintf(output_stream, "%%%s", kGreg[z][op->reg]);
|
||||
break;
|
||||
case kAsmXmm:
|
||||
fprintf(output_stream, "%%xmm%d", op->reg);
|
||||
break;
|
||||
case kAsmFpu:
|
||||
fprintf(output_stream, "%%st(%d)", op->reg);
|
||||
break;
|
||||
case kAsmRaw:
|
||||
fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
switch (q) {
|
||||
case 'h': // hi byte
|
||||
fprintf(output_stream, "%%%ch", "acdb"[op->reg]);
|
||||
break;
|
||||
case 'b': // lo byte
|
||||
fprintf(output_stream, "%%%s", kGreg[0][op->reg]);
|
||||
break;
|
||||
case 'w': // word
|
||||
fprintf(output_stream, "%%%s", kGreg[1][op->reg]);
|
||||
break;
|
||||
case 'k': // dword
|
||||
fprintf(output_stream, "%%%s", kGreg[2][op->reg]);
|
||||
break;
|
||||
case 'q': // qword
|
||||
fprintf(output_stream, "%%%s", kGreg[3][op->reg]);
|
||||
break;
|
||||
case 'z': // print suffix
|
||||
fprintf(output_stream, "%c", "bwlq"[z]);
|
||||
break;
|
||||
case 'p': // print raw
|
||||
fprintf(output_stream, "%.*s", op->node->tok->len, op->node->tok->loc);
|
||||
break;
|
||||
case 'a': // print address
|
||||
PrintAsmConstant(op);
|
||||
break;
|
||||
case 'c': // print constant w/o punctuation
|
||||
PrintAsmConstant(op);
|
||||
break;
|
||||
case 'P': // print w/ @plt
|
||||
PrintAsmConstant(op);
|
||||
fprintf(output_stream, "@plt");
|
||||
break;
|
||||
case 'l': // print label w/o punctuation
|
||||
if (!op->label) {
|
||||
error_tok(op->tok, "qualifier expected label");
|
||||
}
|
||||
fprintf(output_stream, "%s", *op->label);
|
||||
break;
|
||||
case 'V': // print register w/o punctuation
|
||||
if (op->type != kAsmReg) {
|
||||
error_tok(op->tok, "qualifier expected register");
|
||||
}
|
||||
fprintf(output_stream, "%s", kGreg[z][op->reg]);
|
||||
break;
|
||||
default:
|
||||
error_tok(op->tok, "bad asm qualifier %%%`'c", q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *HandleAsmSpecifier(Asm *a, char *p) {
|
||||
int c, i, q, z;
|
||||
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
|
||||
if (c == '%') {
|
||||
fputc('%', output_stream);
|
||||
return p;
|
||||
}
|
||||
if (c == '=') {
|
||||
fprintf(output_stream, "%d", count());
|
||||
return p;
|
||||
}
|
||||
if (isdigit(c)) {
|
||||
q = '\0';
|
||||
} else {
|
||||
q = c;
|
||||
if (!(c = *p++)) error_tok(a->tok, "unexpected nul");
|
||||
if (!isdigit(c)) {
|
||||
error_tok(a->tok, "bad asm specifier at offset %d", p - a->str);
|
||||
}
|
||||
}
|
||||
if ((i = c - '0') >= a->n) {
|
||||
error_tok(a->tok, "bad asm reference at offset %d", p - a->str);
|
||||
}
|
||||
z = bsr(a->ops[i].node->ty->size);
|
||||
if (z > 3 && a->ops[i].type == kAsmReg) {
|
||||
error_tok(a->tok, "bad asm op size");
|
||||
}
|
||||
EmitAsmSpecifier(&a->ops[i], q, z);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void EmitAsmText(Asm *a) {
|
||||
char c, *p;
|
||||
if (a->isgnu) {
|
||||
flushln();
|
||||
fprintf(output_stream, "\t");
|
||||
for (p = a->str;;) {
|
||||
switch ((c = *p++)) {
|
||||
case '\0':
|
||||
fputc('\n', output_stream);
|
||||
return;
|
||||
case '%':
|
||||
p = HandleAsmSpecifier(a, p);
|
||||
break;
|
||||
default:
|
||||
fputc(c, output_stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println("\t%s", a->str);
|
||||
}
|
||||
}
|
||||
|
||||
static void PushAsmInput(AsmOperand *op) {
|
||||
gen_expr(op->node);
|
||||
push();
|
||||
}
|
||||
|
||||
static void PushAsmInputs(Asm *a) {
|
||||
int i;
|
||||
for (i = 0; i < a->n; ++i) {
|
||||
if (a->ops[i].flow == '=') continue;
|
||||
switch (a->ops[i].type) {
|
||||
case kAsmReg:
|
||||
PushAsmInput(&a->ops[i]);
|
||||
break;
|
||||
case kAsmMem:
|
||||
if (a->ops[i].isused) {
|
||||
PushAsmInput(&a->ops[i]);
|
||||
}
|
||||
break;
|
||||
case kAsmXmm:
|
||||
gen_expr(a->ops[i].node);
|
||||
println("\tsub\t$16,%%rsp");
|
||||
switch (a->ops[i].node->ty->kind) {
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
println("\tmovdqu\t%%xmm0,(%%rsp)");
|
||||
break;
|
||||
default:
|
||||
println("\tmovdqu\t(%%rax),%%xmm0");
|
||||
println("\tmovdqu\t%%xmm0,(%%rsp)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kAsmMmx:
|
||||
gen_expr(a->ops[i].node);
|
||||
println("\tsub\t$8,%%rsp");
|
||||
switch (a->ops[i].node->ty->kind) {
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
println("\tmovq\t%%mm0,(%%rsp)");
|
||||
break;
|
||||
default:
|
||||
println("\tmovq\t(%%rax),%%mm0");
|
||||
println("\tmovq\t%%mm0,(%%rsp)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kAsmFpu: /* TODO: How does this work in non-simple case? */
|
||||
gen_expr(a->ops[i].node);
|
||||
println("\tsub\t$16,%%rsp");
|
||||
println("\tfstpt\t(%%rsp)");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PopAsmInput(Asm *a, AsmOperand *op) {
|
||||
if (isdigit(op->flow)) {
|
||||
popreg(kGreg[3][a->ops[op->flow - '0'].reg]);
|
||||
} else {
|
||||
popreg(kGreg[3][op->reg]);
|
||||
}
|
||||
}
|
||||
|
||||
static void PopAsmInputs(Asm *a) {
|
||||
int i;
|
||||
for (i = a->n; i--;) {
|
||||
if (a->ops[i].flow == '=') continue;
|
||||
switch (a->ops[i].type) {
|
||||
case kAsmReg:
|
||||
PopAsmInput(a, &a->ops[i]);
|
||||
break;
|
||||
case kAsmMem:
|
||||
if (a->ops[i].isused) {
|
||||
PopAsmInput(a, &a->ops[i]);
|
||||
}
|
||||
break;
|
||||
case kAsmXmm:
|
||||
println("\tmovdqu\t(%%rsp),%%xmm%d", a->ops[i].reg);
|
||||
println("\tadd\t$16,%%rsp");
|
||||
break;
|
||||
case kAsmMmx:
|
||||
println("\tmovq\t(%%rsp),%%mm%d", a->ops[i].reg);
|
||||
println("\tadd\t$8,%%rsp");
|
||||
break;
|
||||
case kAsmFpu: /* TODO: How does this work in non-simple case? */
|
||||
println("\tfldt\t(%%rsp)");
|
||||
println("\tadd\t$16,%%rsp");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void StoreAsmOutputs(Asm *a) {
|
||||
int i, z, x0, x1;
|
||||
for (i = 0; i < a->n; ++i) {
|
||||
if (a->ops[i].flow == '=' || a->ops[i].flow == '+') {
|
||||
switch (a->ops[i].type) {
|
||||
case kAsmFlag:
|
||||
gen_addr(a->ops[i].node);
|
||||
println("\tset%s\t(%%rax)", a->ops[i].str + a->ops[i].predicate);
|
||||
break;
|
||||
case kAsmReg:
|
||||
if (a->ops[i].reg) {
|
||||
gen_addr(a->ops[i].node);
|
||||
z = bsr(a->ops[i].node->ty->size);
|
||||
if (z > 3) error_tok(a->tok, "bad asm out size");
|
||||
println("\tmov\t%%%s,(%%rax)", kGreg[z][a->ops[i].reg]);
|
||||
} else {
|
||||
println("\tpush\t%%rbx");
|
||||
push();
|
||||
pop("%rbx");
|
||||
gen_addr(a->ops[i].node);
|
||||
println("\tmov\t%%rbx,(%%rax)");
|
||||
println("\tpop\t%%rbx");
|
||||
}
|
||||
break;
|
||||
case kAsmXmm:
|
||||
gen_addr(a->ops[i].node);
|
||||
switch (a->ops[i].node->ty->kind) {
|
||||
case TY_FLOAT:
|
||||
println("\tmovss\t%%xmm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
case TY_DOUBLE:
|
||||
println("\tmovsd\t%%xmm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
default:
|
||||
println("\tmovdqu\t%%xmm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kAsmMmx:
|
||||
gen_addr(a->ops[i].node);
|
||||
switch (a->ops[i].node->ty->kind) {
|
||||
case TY_FLOAT:
|
||||
println("\tmovss\t%%mm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
case TY_DOUBLE:
|
||||
println("\tmovsd\t%%mm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
default:
|
||||
println("\tmovq\t%%mm%d,(%%rax)", a->ops[i].reg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kAsmFpu: /* TODO: How does this work in non-simple case? */
|
||||
gen_addr(a->ops[i].node);
|
||||
println("\tfstpt\t(%%rax)");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PushClobbers(Asm *a) {
|
||||
int i, regs = a->regclob & PRECIOUS;
|
||||
while (regs) {
|
||||
i = bsf(regs);
|
||||
pushreg(kGreg[3][i]);
|
||||
regs &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
static void PopClobbers(Asm *a) {
|
||||
int i, regs = a->regclob & PRECIOUS;
|
||||
while (regs) {
|
||||
i = bsr(regs);
|
||||
popreg(kGreg[3][i]);
|
||||
regs &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
// generates shocking horrible code for parsed asm statement
|
||||
void gen_asm(Asm *a) {
|
||||
PushAsmInputs(a);
|
||||
print_loc(a->tok->file->file_no, a->tok->line_no);
|
||||
PopAsmInputs(a);
|
||||
PushClobbers(a);
|
||||
EmitAsmText(a);
|
||||
StoreAsmOutputs(a);
|
||||
PopClobbers(a);
|
||||
}
|
||||
179
third_party/chibicc/cast.c
vendored
Normal file
179
third_party/chibicc/cast.c
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
#define REDZONE(X) \
|
||||
"sub\t$16,%rsp\n" \
|
||||
"\t" X "\n" \
|
||||
"\tadd\t$16,%rsp"
|
||||
|
||||
#define PUSHPOPRAX(X) \
|
||||
"push\t%rax\n" \
|
||||
"\t" X "\n" \
|
||||
"\tpop\t%rax"
|
||||
|
||||
#ifdef __SSE3__
|
||||
#define FIST(X) REDZONE("fistt" X)
|
||||
#else
|
||||
#define FIST(X) \
|
||||
REDZONE("fnstcw\t8(%rsp)\n" \
|
||||
"\tmovzwl\t8(%rsp),%eax\n" \
|
||||
"\tor\t$12,%ah\n" \
|
||||
"\tmov\t%ax,10(%rsp)\n" \
|
||||
"\tfldcw\t10(%rsp)\n" \
|
||||
"\tfist" X "\n" \
|
||||
"\tfldcw\t8(%rsp)")
|
||||
#endif
|
||||
|
||||
#define u64f64 \
|
||||
"test\t%rax,%rax\n" \
|
||||
"\tjs\t1f\n" \
|
||||
"\tpxor\t%xmm0,%xmm0\n" \
|
||||
"\tcvtsi2sd %rax,%xmm0\n" \
|
||||
"\tjmp\t2f\n" \
|
||||
"1:\n" \
|
||||
"\tmov\t%rax,%rdi\n" \
|
||||
"\tand\t$1,%eax\n" \
|
||||
"\tpxor\t%xmm0,%xmm0\n" \
|
||||
"\tshr\t%rdi\n" \
|
||||
"\tor\t%rax,%rdi\n" \
|
||||
"\tcvtsi2sd %rdi,%xmm0\n" \
|
||||
"\taddsd\t%xmm0,%xmm0\n" \
|
||||
"2:"
|
||||
|
||||
#define u64f80 \
|
||||
PUSHPOPRAX("fildq\t(%rsp)\n" \
|
||||
"\ttest\t%rax,%rax\n" \
|
||||
"\tjns\t1f\n" \
|
||||
"\tmov\t$0x5f800000,(%rsp)\n" \
|
||||
"\tfadds\t(%rsp)\n" \
|
||||
"1:")
|
||||
|
||||
#define i32i8 "movsbl\t%al,%eax"
|
||||
#define i32u8 "movzbl\t%al,%eax"
|
||||
#define i32i16 "cwtl"
|
||||
#define i32u16 "movzwl\t%ax,%eax"
|
||||
#define i32f32 "cvtsi2ssl %eax,%xmm0"
|
||||
#define i32i64 "cltq"
|
||||
#define i32f64 "cvtsi2sdl %eax,%xmm0"
|
||||
#define u32i64 "mov\t%eax,%eax"
|
||||
#define i64f32 "cvtsi2ssq %rax,%xmm0"
|
||||
#define i64f64 "cvtsi2sdq %rax,%xmm0"
|
||||
#define f32i32 "cvttss2sil %xmm0,%eax"
|
||||
#define f32u32 "cvttss2siq %xmm0,%rax"
|
||||
#define f32i64 "cvttss2siq %xmm0,%rax"
|
||||
#define f32u64 "cvttss2siq %xmm0,%rax"
|
||||
#define f32f64 "cvtss2sd %xmm0,%xmm0"
|
||||
#define f64i32 "cvttsd2sil %xmm0,%eax"
|
||||
#define f64u32 "cvttsd2siq %xmm0,%rax"
|
||||
#define f64i64 "cvttsd2siq %xmm0,%rax"
|
||||
#define f64u64 "cvttsd2siq %xmm0,%rax"
|
||||
#define f64f32 "cvtsd2ss %xmm0,%xmm0"
|
||||
#define u64f32 "cvtsi2ssq %rax,%xmm0"
|
||||
#define f32i8 "cvttss2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
|
||||
#define f32u8 "cvttss2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
|
||||
#define f32i16 "cvttss2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
|
||||
#define f32u16 "cvttss2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
|
||||
#define f64i8 "cvttsd2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
|
||||
#define f64u8 "cvttsd2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
|
||||
#define f64i16 "cvttsd2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
|
||||
#define f64u16 "cvttsd2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
|
||||
#define f64f80 REDZONE("movsd\t%xmm0,(%rsp)\n\tfldl\t(%rsp)")
|
||||
#define f80i8 FIST("ps\t(%rsp)\n\tmovsbl\t(%rsp),%eax")
|
||||
#define f80u8 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
|
||||
#define f80i16 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
|
||||
#define f80u16 FIST("pl\t(%rsp)\n\tmovswl\t(%rsp),%eax")
|
||||
#define f80i32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
|
||||
#define f80u32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
|
||||
#define f80i64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
|
||||
#define f80u64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
|
||||
#define f80f32 REDZONE("fstps\t(%rsp)\n\tmovss\t(%rsp),%xmm0")
|
||||
#define f80f64 REDZONE("fstpl\t(%rsp)\n\tmovsd\t(%rsp),%xmm0")
|
||||
#define i32f80 PUSHPOPRAX("fildl\t(%rsp)")
|
||||
#define u32f32 "mov\t%eax,%eax\n\tcvtsi2ssq %rax,%xmm0"
|
||||
#define u32f64 "mov\t%eax,%eax\n\tcvtsi2sdq %rax,%xmm0"
|
||||
#define u32f80 "mov\t%eax,%eax\n\tpush %rax\n\tfildll\t(%rsp)\n\tpop\t%rax"
|
||||
#define i64f80 PUSHPOPRAX("fildll\t(%rsp)")
|
||||
#define f32f80 REDZONE("movss\t%xmm0,(%rsp)\n\tflds\t(%rsp)")
|
||||
#define i8i128 "movsbq\t%al,%rax\n\tcqto"
|
||||
#define i16i128 "movswq\t%ax,%rax\n\tcqto"
|
||||
#define i32i128 "cltq\n\tcqto"
|
||||
#define i64i128 "cqto"
|
||||
#define u8i128 "movzbq\t%al,%rax\n\txor\t%edx,%edx"
|
||||
#define u16i128 "movzwq\t%ax,%rax\n\txor\t%edx,%edx"
|
||||
#define u32i128 "cltq\n\txor\t%edx,%edx"
|
||||
#define u64i128 "xor\t%edx,%edx"
|
||||
#define i128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattisf"
|
||||
#define i128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattidf"
|
||||
#define i128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattixf"
|
||||
#define u128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntisf"
|
||||
#define u128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntidf"
|
||||
#define u128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntixf"
|
||||
#define f32i128 "call\t__fixsfti"
|
||||
#define f64i128 "call\t__fixdfti"
|
||||
#define f80i128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixxfti")
|
||||
#define f32u128 "call\t__fixunssfti"
|
||||
#define f64u128 "call\t__fixunsdfti"
|
||||
#define f80u128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixunsxfti")
|
||||
|
||||
enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80, I128, U128 };
|
||||
static const char *const cast_table[13][13] = /* clang-format off */ {
|
||||
// i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80 i128 u128
|
||||
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i8
|
||||
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i16
|
||||
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i32
|
||||
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80, i64i128, i64i128}, // i64
|
||||
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u8
|
||||
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u16
|
||||
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80, u32i128, i32i128}, // u32
|
||||
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80, u64i128, u64i128}, // u64
|
||||
{f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80, f32i128, f32u128}, // f32
|
||||
{f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80, f64i128, f64u128}, // f64
|
||||
{f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL, f80i128, f80u128}, // f80
|
||||
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i128f32, i128f64, i128f80, NULL, NULL }, // i128
|
||||
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u128f32, u128f64, u128f80, NULL, NULL }, // u128
|
||||
} /* clang-format on */;
|
||||
|
||||
static int getTypeId(Type *ty) {
|
||||
switch (ty->kind) {
|
||||
case TY_CHAR:
|
||||
return ty->is_unsigned ? U8 : I8;
|
||||
case TY_SHORT:
|
||||
return ty->is_unsigned ? U16 : I16;
|
||||
case TY_INT:
|
||||
return ty->is_unsigned ? U32 : I32;
|
||||
case TY_LONG:
|
||||
return ty->is_unsigned ? U64 : I64;
|
||||
case TY_INT128:
|
||||
return ty->is_unsigned ? U128 : I128;
|
||||
case TY_FLOAT:
|
||||
return F32;
|
||||
case TY_DOUBLE:
|
||||
return F64;
|
||||
case TY_LDOUBLE:
|
||||
return F80;
|
||||
}
|
||||
return U64;
|
||||
}
|
||||
|
||||
void gen_cast(Type *from, Type *to) {
|
||||
bool skew;
|
||||
if (to->kind == TY_VOID) return;
|
||||
if (to->kind == TY_BOOL) {
|
||||
cmp_zero(from);
|
||||
println("\tsetne\t%%al");
|
||||
println("\tmovzbl\t%%al,%%eax");
|
||||
return;
|
||||
}
|
||||
int t1 = getTypeId(from);
|
||||
int t2 = getTypeId(to);
|
||||
if (cast_table[t1][t2]) {
|
||||
if ((skew = (depth & 1) && strstr(cast_table[t1][t2], "call"))) {
|
||||
println("\tsub\t$8,%%rsp");
|
||||
depth++;
|
||||
}
|
||||
println("\t%s", cast_table[t1][t2]);
|
||||
if (skew) {
|
||||
println("\tadd\t$8,%%rsp");
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
377
third_party/chibicc/chibicc.c
vendored
377
third_party/chibicc/chibicc.c
vendored
@ -1,20 +1,30 @@
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
chibicc (MIT/ISC License)\\n\
|
||||
Copyright 2019 Rui Ueyama\\n\
|
||||
Copyright 2020 Justine Alexandra Roberts Tunney\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
typedef enum {
|
||||
FILE_NONE,
|
||||
FILE_C,
|
||||
FILE_ASM,
|
||||
FILE_ASM_CPP,
|
||||
FILE_OBJ,
|
||||
FILE_AR,
|
||||
FILE_DSO,
|
||||
} FileType;
|
||||
|
||||
StringArray include_paths;
|
||||
bool opt_fcommon = true;
|
||||
bool opt_fpic;
|
||||
bool opt_verbose;
|
||||
bool opt_mpopcnt;
|
||||
bool opt_pg;
|
||||
bool opt_mfentry;
|
||||
bool opt_mnop_mcount;
|
||||
bool opt_mrecord_mcount;
|
||||
|
||||
static FileType opt_x;
|
||||
static StringArray opt_include;
|
||||
static bool opt_E;
|
||||
static bool opt_M;
|
||||
static bool opt_MD;
|
||||
@ -25,19 +35,20 @@ static bool opt_c;
|
||||
static bool opt_cc1;
|
||||
static bool opt_hash_hash_hash;
|
||||
static bool opt_static;
|
||||
static bool opt_shared;
|
||||
static char *opt_MF;
|
||||
static char *opt_MT;
|
||||
static char *opt_o;
|
||||
static FileType opt_x;
|
||||
static StringArray opt_include;
|
||||
|
||||
StringArray include_paths;
|
||||
static StringArray ld_extra_args;
|
||||
static StringArray as_extra_args;
|
||||
static StringArray std_include_paths;
|
||||
|
||||
char *base_file;
|
||||
static char *output_file;
|
||||
|
||||
static StringArray input_paths;
|
||||
|
||||
static char **tmpfiles;
|
||||
|
||||
static void usage(int status) {
|
||||
@ -46,48 +57,49 @@ static void usage(int status) {
|
||||
}
|
||||
|
||||
static bool take_arg(char *arg) {
|
||||
char *x[] = {
|
||||
"-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(x) / sizeof(*x); i++)
|
||||
if (!strcmp(arg, x[i])) return true;
|
||||
char *x[] = {"-o", "-I", "-idirafter", "-include",
|
||||
"-x", "-MF", "-MT", "-Xlinker"};
|
||||
for (int i = 0; i < sizeof(x) / sizeof(*x); i++) {
|
||||
if (!strcmp(arg, x[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_default_include_paths(char *argv0) {
|
||||
// We expect that chibicc-specific include files are installed
|
||||
// to ./include relative to argv[0].
|
||||
char *buf = calloc(1, strlen(argv0) + 10);
|
||||
sprintf(buf, "%s/include", dirname(strdup(argv0)));
|
||||
strarray_push(&include_paths, buf);
|
||||
|
||||
/* char *buf = calloc(1, strlen(argv0) + 10); */
|
||||
/* sprintf(buf, "%s/include", dirname(strdup(argv0))); */
|
||||
/* strarray_push(&include_paths, buf); */
|
||||
// Add standard include paths.
|
||||
strarray_push(&include_paths, ".");
|
||||
|
||||
/* strarray_push(&include_paths, "."); */
|
||||
// Keep a copy of the standard include paths for -MMD option.
|
||||
for (int i = 0; i < include_paths.len; i++)
|
||||
for (int i = 0; i < include_paths.len; i++) {
|
||||
strarray_push(&std_include_paths, include_paths.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void define(char *str) {
|
||||
char *eq = strchr(str, '=');
|
||||
if (eq)
|
||||
if (eq) {
|
||||
define_macro(strndup(str, eq - str), eq + 1);
|
||||
else
|
||||
} else {
|
||||
define_macro(str, "1");
|
||||
}
|
||||
}
|
||||
|
||||
static FileType parse_opt_x(char *s) {
|
||||
if (!strcmp(s, "c")) return FILE_C;
|
||||
if (!strcmp(s, "assembler")) return FILE_ASM;
|
||||
if (!strcmp(s, "assembler-with-cpp")) return FILE_ASM_CPP;
|
||||
if (!strcmp(s, "none")) return FILE_NONE;
|
||||
error("<command line>: unknown argument for -x: %s", s);
|
||||
}
|
||||
|
||||
static char *quote_makefile(char *s) {
|
||||
char *buf = calloc(1, strlen(s) * 2 + 1);
|
||||
|
||||
for (int i = 0, j = 0; s[i]; i++) {
|
||||
switch (s[i]) {
|
||||
case '$':
|
||||
@ -112,255 +124,254 @@ static char *quote_makefile(char *s) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void PrintMemoryUsage(void) {
|
||||
struct mallinfo mi;
|
||||
mi = mallinfo();
|
||||
fprintf(stderr, "allocated %,ld bytes of memory\n", mi.arena);
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char **argv) {
|
||||
// Make sure that all command line options that take an argument
|
||||
// have an argument.
|
||||
for (int i = 1; i < argc; i++)
|
||||
if (take_arg(argv[i]))
|
||||
if (!argv[++i]) usage(1);
|
||||
|
||||
StringArray idirafter = {};
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-###")) {
|
||||
opt_hash_hash_hash = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-cc1")) {
|
||||
opt_cc1 = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "--help")) usage(0);
|
||||
|
||||
if (!strcmp(argv[i], "-v")) {
|
||||
opt_verbose = true;
|
||||
atexit(PrintMemoryUsage);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-o")) {
|
||||
opt_o = argv[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-o", 2)) {
|
||||
opt_o = argv[i] + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-S")) {
|
||||
opt_S = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-fcommon")) {
|
||||
opt_fcommon = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-fno-common")) {
|
||||
opt_fcommon = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-c")) {
|
||||
opt_c = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-E")) {
|
||||
opt_E = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-I", 2)) {
|
||||
strarray_push(&include_paths, argv[i] + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-D")) {
|
||||
define(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-D", 2)) {
|
||||
define(argv[i] + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-U")) {
|
||||
undef_macro(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-U", 2)) {
|
||||
undef_macro(argv[i] + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-include")) {
|
||||
strarray_push(&opt_include, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-x")) {
|
||||
opt_x = parse_opt_x(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-x", 2)) {
|
||||
opt_x = parse_opt_x(argv[i] + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
|
||||
strarray_push(&input_paths, argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-Xassembler")) {
|
||||
strarray_push(&as_extra_args, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-Xlinker")) {
|
||||
strarray_push(&ld_extra_args, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-s")) {
|
||||
strarray_push(&ld_extra_args, "-s");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-M")) {
|
||||
opt_M = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MF")) {
|
||||
opt_MF = argv[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MP")) {
|
||||
opt_MP = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MT")) {
|
||||
if (opt_MT == NULL)
|
||||
opt_MT = argv[++i];
|
||||
else
|
||||
opt_MT = format("%s %s", opt_MT, argv[++i]);
|
||||
opt_MT = xasprintf("%s %s", opt_MT, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MD")) {
|
||||
opt_MD = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MQ")) {
|
||||
if (opt_MT == NULL)
|
||||
opt_MT = quote_makefile(argv[++i]);
|
||||
else
|
||||
opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i]));
|
||||
opt_MT = xasprintf("%s %s", opt_MT, quote_makefile(argv[++i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-MMD")) {
|
||||
opt_MD = opt_MMD = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) {
|
||||
if (!strcmp(argv[i], "-fpie") || !strcmp(argv[i], "-fpic") ||
|
||||
!strcmp(argv[i], "-fPIC")) {
|
||||
opt_fpic = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-pg")) {
|
||||
opt_pg = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-mfentry")) {
|
||||
opt_mfentry = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-mrecord-mcount")) {
|
||||
opt_mrecord_mcount = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-mnop-mcount")) {
|
||||
opt_mnop_mcount = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-mpopcnt")) {
|
||||
opt_mpopcnt = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-cc1-input")) {
|
||||
base_file = argv[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-cc1-output")) {
|
||||
output_file = argv[++i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-idirafter")) {
|
||||
strarray_push(&idirafter, argv[i++]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-static")) {
|
||||
opt_static = true;
|
||||
strarray_push(&ld_extra_args, "-static");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-shared")) {
|
||||
opt_shared = true;
|
||||
strarray_push(&ld_extra_args, "-shared");
|
||||
continue;
|
||||
fprintf(stderr, "error: -shared not supported\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "-L")) {
|
||||
strarray_push(&ld_extra_args, "-L");
|
||||
strarray_push(&ld_extra_args, argv[++i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[i], "-L", 2)) {
|
||||
strarray_push(&ld_extra_args, "-L");
|
||||
strarray_push(&ld_extra_args, argv[i] + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!strcmp(argv[i], "-hashmap-test")) {
|
||||
hashmap_test();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
// These options are ignored for now.
|
||||
if (!strncmp(argv[i], "-O", 2) || !strncmp(argv[i], "-W", 2) ||
|
||||
!strncmp(argv[i], "-g", 2) || !strncmp(argv[i], "-std=", 5) ||
|
||||
!strcmp(argv[i], "-ffreestanding") ||
|
||||
if (startswith(argv[i], "-O") || startswith(argv[i], "-W") ||
|
||||
startswith(argv[i], "-g") || startswith(argv[i], "-std=") ||
|
||||
startswith(argv[i], "-fno-") || startswith(argv[i], "-mno-") ||
|
||||
startswith(argv[i], "-fsanitize") ||
|
||||
startswith(argv[i], "-fdebug-prefix-map") ||
|
||||
!strcmp(argv[i], "-fwrapv") || !strcmp(argv[i], "-nostdlib") ||
|
||||
!strcmp(argv[i], "-nostdinc") || !strcmp(argv[i], "-ffreestanding") ||
|
||||
!strcmp(argv[i], "-fstrict-aliasing") ||
|
||||
!strcmp(argv[i], "-fstrict-overflow") ||
|
||||
!strcmp(argv[i], "-frecord-gcc-switches") ||
|
||||
!strcmp(argv[i], "-fsignaling-nans") ||
|
||||
!strcmp(argv[i], "-frounding-math") ||
|
||||
!strcmp(argv[i], "-fcx-limited-range") ||
|
||||
!strcmp(argv[i], "-fmodulo-sched") ||
|
||||
!strcmp(argv[i], "-fmerge-constants") ||
|
||||
!strcmp(argv[i], "-fmerge-all-constants") ||
|
||||
!strcmp(argv[i], "-fno-builtin") ||
|
||||
!strcmp(argv[i], "-fno-omit-frame-pointer") ||
|
||||
!strcmp(argv[i], "-fno-stack-protector") ||
|
||||
!strcmp(argv[i], "-fno-strict-aliasing") || !strcmp(argv[i], "-m64") ||
|
||||
!strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w"))
|
||||
!strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w")) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (argv[i][0] == '-' && argv[i][1] != '\0')
|
||||
error("unknown argument: %s", argv[i]);
|
||||
|
||||
strarray_push(&input_paths, argv[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < idirafter.len; i++)
|
||||
strarray_push(&include_paths, idirafter.data[i]);
|
||||
|
||||
if (input_paths.len == 0) error("no input files");
|
||||
|
||||
// -E implies that the input is the C macro language.
|
||||
if (opt_E) opt_x = FILE_C;
|
||||
}
|
||||
|
||||
static FILE *open_file(char *path) {
|
||||
if (!path || strcmp(path, "-") == 0) return stdout;
|
||||
|
||||
FILE *out = fopen(path, "w");
|
||||
if (!out) error("cannot open output file: %s: %s", path, strerror(errno));
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool ends_with(char *p, char *q) {
|
||||
int len1 = strlen(p);
|
||||
int len2 = strlen(q);
|
||||
return (len1 >= len2) && !strcmp(p + len1 - len2, q);
|
||||
}
|
||||
|
||||
// Replace file extension
|
||||
static char *replace_extn(char *tmpl, char *extn) {
|
||||
char *filename = basename(strdup(tmpl));
|
||||
int len1 = strlen(filename);
|
||||
int len2 = strlen(extn);
|
||||
char *buf = calloc(1, len1 + len2 + 2);
|
||||
|
||||
char *dot = strrchr(filename, '.');
|
||||
if (dot) *dot = '\0';
|
||||
sprintf(buf, "%s%s", filename, extn);
|
||||
@ -368,25 +379,23 @@ static char *replace_extn(char *tmpl, char *extn) {
|
||||
}
|
||||
|
||||
static void cleanup(void) {
|
||||
if (tmpfiles)
|
||||
for (int i = 0; tmpfiles[i]; i++) unlink(tmpfiles[i]);
|
||||
if (tmpfiles) {
|
||||
for (int i = 0; tmpfiles[i]; i++) {
|
||||
unlink(tmpfiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *create_tmpfile(void) {
|
||||
char tmpl[] = "/tmp/chibicc-XXXXXX";
|
||||
char *path = calloc(1, sizeof(tmpl));
|
||||
memcpy(path, tmpl, sizeof(tmpl));
|
||||
|
||||
char *path = xstrcat(kTmpPath, "chibicc-XXXXXX");
|
||||
int fd = mkstemp(path);
|
||||
if (fd == -1) error("mkstemp failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
|
||||
static int len = 2;
|
||||
tmpfiles = realloc(tmpfiles, sizeof(char *) * len);
|
||||
tmpfiles[len - 2] = path;
|
||||
tmpfiles[len - 1] = NULL;
|
||||
len++;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -397,43 +406,41 @@ static void run_subprocess(char **argv) {
|
||||
for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (fork() == 0) {
|
||||
// Child process. Run a new command.
|
||||
execvp(argv[0], argv);
|
||||
fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Wait for the child process to finish.
|
||||
int status;
|
||||
while (wait(&status) > 0)
|
||||
;
|
||||
if (status != 0) exit(1);
|
||||
for (;;) {
|
||||
if (wait(&status) <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_cc1(int argc, char **argv, char *input, char *output) {
|
||||
char **args = calloc(argc + 10, sizeof(char *));
|
||||
memcpy(args, argv, argc * sizeof(char *));
|
||||
args[argc++] = "-cc1";
|
||||
|
||||
if (input) {
|
||||
args[argc++] = "-cc1-input";
|
||||
args[argc++] = input;
|
||||
}
|
||||
|
||||
if (output) {
|
||||
args[argc++] = "-cc1-output";
|
||||
args[argc++] = output;
|
||||
}
|
||||
|
||||
run_subprocess(args);
|
||||
}
|
||||
|
||||
// Print tokens to stdout. Used for -E.
|
||||
static void print_tokens(Token *tok) {
|
||||
FILE *out = open_file(opt_o ? opt_o : "-");
|
||||
|
||||
int line = 1;
|
||||
for (; tok->kind != TK_EOF; tok = tok->next) {
|
||||
if (line > 1 && tok->at_bol) fprintf(out, "\n");
|
||||
@ -458,30 +465,26 @@ static bool in_std_include_path(char *path) {
|
||||
// used to automate file dependency management.
|
||||
static void print_dependencies(void) {
|
||||
char *path;
|
||||
if (opt_MF)
|
||||
if (opt_MF) {
|
||||
path = opt_MF;
|
||||
else if (opt_MD)
|
||||
} else if (opt_MD) {
|
||||
path = replace_extn(opt_o ? opt_o : base_file, ".d");
|
||||
else if (opt_o)
|
||||
} else if (opt_o) {
|
||||
path = opt_o;
|
||||
else
|
||||
} else {
|
||||
path = "-";
|
||||
|
||||
}
|
||||
FILE *out = open_file(path);
|
||||
if (opt_MT)
|
||||
fprintf(out, "%s:", opt_MT);
|
||||
else
|
||||
fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o")));
|
||||
|
||||
File **files = get_input_files();
|
||||
|
||||
for (int i = 0; files[i]; i++) {
|
||||
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
|
||||
fprintf(out, " \\\n %s", files[i]->name);
|
||||
}
|
||||
|
||||
fprintf(out, "\n\n");
|
||||
|
||||
if (opt_MP) {
|
||||
for (int i = 1; files[i]; i++) {
|
||||
if (opt_MMD && in_std_include_path(files[i]->name)) continue;
|
||||
@ -498,51 +501,52 @@ static Token *must_tokenize_file(char *path) {
|
||||
|
||||
static Token *append_tokens(Token *tok1, Token *tok2) {
|
||||
if (!tok1 || tok1->kind == TK_EOF) return tok2;
|
||||
|
||||
Token *t = tok1;
|
||||
while (t->next->kind != TK_EOF) t = t->next;
|
||||
t->next = tok2;
|
||||
return tok1;
|
||||
}
|
||||
|
||||
static FileType get_file_type(char *filename) {
|
||||
if (opt_x != FILE_NONE) return opt_x;
|
||||
if (endswith(filename, ".a")) return FILE_AR;
|
||||
if (endswith(filename, ".o")) return FILE_OBJ;
|
||||
if (endswith(filename, ".c")) return FILE_C;
|
||||
if (endswith(filename, ".s")) return FILE_ASM;
|
||||
if (endswith(filename, ".S")) return FILE_ASM_CPP;
|
||||
error("<command line>: unknown file extension: %s", filename);
|
||||
}
|
||||
|
||||
static void cc1(void) {
|
||||
Token *tok = NULL;
|
||||
|
||||
// Process -include option
|
||||
for (int i = 0; i < opt_include.len; i++) {
|
||||
char *incl = opt_include.data[i];
|
||||
|
||||
char *path;
|
||||
if (file_exists(incl)) {
|
||||
if (fileexists(incl)) {
|
||||
path = incl;
|
||||
} else {
|
||||
path = search_include_paths(incl);
|
||||
if (!path) error("-include: %s: %s", incl, strerror(errno));
|
||||
}
|
||||
|
||||
Token *tok2 = must_tokenize_file(path);
|
||||
tok = append_tokens(tok, tok2);
|
||||
}
|
||||
|
||||
// Tokenize and parse.
|
||||
Token *tok2 = must_tokenize_file(base_file);
|
||||
tok = append_tokens(tok, tok2);
|
||||
tok = preprocess(tok);
|
||||
|
||||
// If -M or -MD are given, print file dependencies.
|
||||
if (opt_M || opt_MD) {
|
||||
print_dependencies();
|
||||
if (opt_M) return;
|
||||
}
|
||||
|
||||
// If -E is given, print out preprocessed C code as a result.
|
||||
if (opt_E) {
|
||||
if (opt_E || get_file_type(base_file) == FILE_ASM_CPP) {
|
||||
print_tokens(tok);
|
||||
return;
|
||||
}
|
||||
|
||||
Obj *prog = parse(tok);
|
||||
|
||||
// Traverse the AST to emit assembly.
|
||||
FILE *out = open_file(output_file);
|
||||
codegen(prog, out);
|
||||
@ -550,108 +554,72 @@ static void cc1(void) {
|
||||
}
|
||||
|
||||
static void assemble(char *input, char *output) {
|
||||
char *cmd[] = {"as", "-W", "-I.", "-c", input, "-o", output, NULL};
|
||||
run_subprocess(cmd);
|
||||
char *as = getenv("AS");
|
||||
if (!as || !*as) as = "as";
|
||||
StringArray arr = {};
|
||||
strarray_push(&arr, as);
|
||||
strarray_push(&arr, "-W");
|
||||
strarray_push(&arr, "-I.");
|
||||
strarray_push(&arr, "-c");
|
||||
for (int i = 0; i < as_extra_args.len; i++) {
|
||||
strarray_push(&arr, as_extra_args.data[i]);
|
||||
}
|
||||
strarray_push(&arr, input);
|
||||
strarray_push(&arr, "-o");
|
||||
strarray_push(&arr, output);
|
||||
strarray_push(&arr, NULL);
|
||||
run_subprocess(arr.data);
|
||||
}
|
||||
|
||||
static void run_linker(StringArray *inputs, char *output) {
|
||||
char *ld = getenv("LD");
|
||||
if (!ld || !*ld) ld = "ld";
|
||||
StringArray arr = {};
|
||||
|
||||
strarray_push(&arr, "ld");
|
||||
strarray_push(&arr, ld);
|
||||
strarray_push(&arr, "-o");
|
||||
strarray_push(&arr, output);
|
||||
strarray_push(&arr, "-m");
|
||||
strarray_push(&arr, "elf_x86_64");
|
||||
|
||||
if (opt_shared) {
|
||||
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
|
||||
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o");
|
||||
} else {
|
||||
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crt1.o");
|
||||
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crti.o");
|
||||
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtbegin.o");
|
||||
}
|
||||
|
||||
strarray_push(&arr, "-L/usr/lib/gcc/x86_64-linux-gnu/9");
|
||||
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
|
||||
strarray_push(&arr, "-L/usr/lib64");
|
||||
strarray_push(&arr, "-L/lib/x86_64-linux-gnu");
|
||||
strarray_push(&arr, "-L/lib64");
|
||||
strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
|
||||
strarray_push(&arr, "-L/usr/lib");
|
||||
strarray_push(&arr, "-L/lib");
|
||||
|
||||
if (!opt_static) {
|
||||
strarray_push(&arr, "-dynamic-linker");
|
||||
strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2");
|
||||
}
|
||||
|
||||
for (int i = 0; i < ld_extra_args.len; i++)
|
||||
strarray_push(&arr, "-z");
|
||||
strarray_push(&arr, "max-page-size=0x1000");
|
||||
strarray_push(&arr, "-mnostdlib");
|
||||
strarray_push(&arr, "--gc-sections");
|
||||
strarray_push(&arr, "--build-id=none");
|
||||
strarray_push(&arr, "--no-dynamic-linker");
|
||||
strarray_push(&arr, "-Ttext-segment=0x400000");
|
||||
strarray_push(&arr, "-T");
|
||||
strarray_push(&arr, LDS);
|
||||
strarray_push(&arr, APE);
|
||||
strarray_push(&arr, CRT);
|
||||
for (int i = 0; i < ld_extra_args.len; i++) {
|
||||
strarray_push(&arr, ld_extra_args.data[i]);
|
||||
|
||||
for (int i = 0; i < inputs->len; i++) strarray_push(&arr, inputs->data[i]);
|
||||
|
||||
if (opt_static) {
|
||||
strarray_push(&arr, "--start-group");
|
||||
strarray_push(&arr, "-lgcc");
|
||||
strarray_push(&arr, "-lgcc_eh");
|
||||
strarray_push(&arr, "-lc");
|
||||
strarray_push(&arr, "--end-group");
|
||||
} else {
|
||||
strarray_push(&arr, "-lc");
|
||||
strarray_push(&arr, "-lgcc");
|
||||
strarray_push(&arr, "--as-needed");
|
||||
strarray_push(&arr, "-lgcc_s");
|
||||
strarray_push(&arr, "--no-as-needed");
|
||||
}
|
||||
|
||||
if (opt_shared)
|
||||
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o");
|
||||
else
|
||||
strarray_push(&arr, "/usr/lib/gcc/x86_64-linux-gnu/9/crtend.o");
|
||||
|
||||
strarray_push(&arr, "/usr/lib/x86_64-linux-gnu/crtn.o");
|
||||
for (int i = 0; i < inputs->len; i++) {
|
||||
strarray_push(&arr, inputs->data[i]);
|
||||
}
|
||||
strarray_push(&arr, NULL);
|
||||
|
||||
run_subprocess(arr.data);
|
||||
}
|
||||
|
||||
static FileType get_file_type(char *filename) {
|
||||
if (opt_x != FILE_NONE) return opt_x;
|
||||
|
||||
if (ends_with(filename, ".a")) return FILE_AR;
|
||||
if (ends_with(filename, ".so")) return FILE_DSO;
|
||||
if (ends_with(filename, ".o")) return FILE_OBJ;
|
||||
if (ends_with(filename, ".c")) return FILE_C;
|
||||
if (ends_with(filename, ".s")) return FILE_ASM;
|
||||
|
||||
error("<command line>: unknown file extension: %s", filename);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
showcrashreports();
|
||||
atexit(cleanup);
|
||||
init_macros();
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (opt_cc1) {
|
||||
add_default_include_paths(argv[0]);
|
||||
cc1();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))
|
||||
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
|
||||
|
||||
StringArray ld_args = {};
|
||||
|
||||
for (int i = 0; i < input_paths.len; i++) {
|
||||
char *input = input_paths.data[i];
|
||||
|
||||
if (!strncmp(input, "-l", 2)) {
|
||||
strarray_push(&ld_args, input);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(input, "-Wl,", 4)) {
|
||||
char *s = strdup(input + 4);
|
||||
char *arg = strtok(s, ",");
|
||||
@ -661,43 +629,38 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
char *output;
|
||||
if (opt_o)
|
||||
if (opt_o) {
|
||||
output = opt_o;
|
||||
else if (opt_S)
|
||||
} else if (opt_S) {
|
||||
output = replace_extn(input, ".s");
|
||||
else
|
||||
} else {
|
||||
output = replace_extn(input, ".o");
|
||||
|
||||
}
|
||||
FileType type = get_file_type(input);
|
||||
|
||||
// Handle .o or .a
|
||||
if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) {
|
||||
strarray_push(&ld_args, input);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle .s
|
||||
if (type == FILE_ASM) {
|
||||
if (!opt_S) assemble(input, output);
|
||||
if (!opt_S) {
|
||||
assemble(input, output);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(type == FILE_C);
|
||||
|
||||
// Just preprocess
|
||||
if (opt_E || opt_M) {
|
||||
run_cc1(argc, argv, input, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile
|
||||
if (opt_S) {
|
||||
run_cc1(argc, argv, input, output);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile and assemble
|
||||
if (opt_c) {
|
||||
char *tmp = create_tmpfile();
|
||||
@ -705,7 +668,6 @@ int main(int argc, char **argv) {
|
||||
assemble(tmp, output);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile, assemble and link
|
||||
char *tmp1 = create_tmpfile();
|
||||
char *tmp2 = create_tmpfile();
|
||||
@ -714,7 +676,8 @@ int main(int argc, char **argv) {
|
||||
strarray_push(&ld_args, tmp2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ld_args.len > 0) run_linker(&ld_args, opt_o ? opt_o : "a.out");
|
||||
if (ld_args.len > 0) {
|
||||
run_linker(&ld_args, opt_o ? opt_o : "a.out");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
537
third_party/chibicc/chibicc.h
vendored
537
third_party/chibicc/chibicc.h
vendored
@ -1,21 +1,21 @@
|
||||
#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
@ -25,30 +25,38 @@ COSMOPOLITAN_C_START_
|
||||
#include "libc/unicode/unicode.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wswitch"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
typedef struct Type Type;
|
||||
typedef struct Node Node;
|
||||
typedef struct Member Member;
|
||||
typedef struct Relocation Relocation;
|
||||
typedef struct Asm Asm;
|
||||
typedef struct AsmOperand AsmOperand;
|
||||
typedef struct File File;
|
||||
typedef struct FpClassify FpClassify;
|
||||
typedef struct Hideset Hideset;
|
||||
typedef struct Member Member;
|
||||
typedef struct Node Node;
|
||||
typedef struct Obj Obj;
|
||||
typedef struct Relocation Relocation;
|
||||
typedef struct Relocation Relocation;
|
||||
typedef struct StaticAsm StaticAsm;
|
||||
typedef struct StringArray StringArray;
|
||||
typedef struct Token Token;
|
||||
typedef struct TokenStack TokenStack;
|
||||
typedef struct Type Type;
|
||||
|
||||
//
|
||||
// strarray.c
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
struct StringArray {
|
||||
char **data;
|
||||
int capacity;
|
||||
int len;
|
||||
} StringArray;
|
||||
};
|
||||
|
||||
void strarray_push(StringArray *arr, char *s);
|
||||
void strarray_push(StringArray *, char *);
|
||||
|
||||
//
|
||||
// tokenize.c
|
||||
@ -64,74 +72,144 @@ typedef enum {
|
||||
TK_EOF, // End-of-file markers
|
||||
} TokenKind;
|
||||
|
||||
typedef struct {
|
||||
struct File {
|
||||
char *name;
|
||||
int file_no;
|
||||
char *contents;
|
||||
|
||||
// For #line directive
|
||||
char *display_name;
|
||||
int line_delta;
|
||||
} File;
|
||||
};
|
||||
|
||||
// Token type
|
||||
typedef struct Token Token;
|
||||
struct Token {
|
||||
TokenKind kind; // Token kind
|
||||
Token *next; // Next token
|
||||
int64_t val; // If kind is TK_NUM, its value
|
||||
long double fval; // If kind is TK_NUM, its value
|
||||
char *loc; // Token location
|
||||
int len; // Token length
|
||||
Type *ty; // Used if TK_NUM or TK_STR
|
||||
char *str; // String literal contents including terminating '\0'
|
||||
|
||||
File *file; // Source location
|
||||
char *filename; // Filename
|
||||
int line_no; // Line number
|
||||
int line_delta; // Line number
|
||||
bool at_bol; // True if this token is at beginning of line
|
||||
bool has_space; // True if this token follows a space character
|
||||
Token *next; // Next token
|
||||
char *loc; // Token location
|
||||
Type *ty; // Used if TK_NUM or TK_STR
|
||||
File *file; // Source location
|
||||
char *filename; // Filename
|
||||
Hideset *hideset; // For macro expansion
|
||||
Token *origin; // If this is expanded from a macro, the original token
|
||||
union {
|
||||
int64_t val; // If kind is TK_NUM, its value
|
||||
long double fval; // If kind is TK_NUM, its value
|
||||
char *str; // String literal contents including terminating '\0'
|
||||
};
|
||||
};
|
||||
|
||||
noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
noreturn void error_at(char *loc, char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
noreturn void error_tok(Token *tok, char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
bool equal(Token *tok, char *op);
|
||||
Token *skip(Token *tok, char *op);
|
||||
bool consume(Token **rest, Token *tok, char *str);
|
||||
void convert_pp_tokens(Token *tok);
|
||||
File **get_input_files(void);
|
||||
File *new_file(char *name, int file_no, char *contents);
|
||||
Token *tokenize_string_literal(Token *tok, Type *basety);
|
||||
Token *tokenize(File *file);
|
||||
Token *tokenize_file(char *filename);
|
||||
void error(char *, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 1, 2)));
|
||||
void error_at(char *, char *, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
|
||||
void error_tok(Token *, char *, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
|
||||
void warn_tok(Token *, char *, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3)));
|
||||
|
||||
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
|
||||
File **get_input_files(void);
|
||||
File *new_file(char *, int, char *);
|
||||
Token *skip(Token *, char *);
|
||||
Token *tokenize(File *);
|
||||
Token *tokenize_file(char *);
|
||||
Token *tokenize_string_literal(Token *, Type *);
|
||||
bool consume(Token **, Token *, char *, size_t);
|
||||
bool equal(Token *, char *, size_t);
|
||||
void convert_pp_tokens(Token *);
|
||||
|
||||
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
|
||||
#define EQUAL(T, S) equal(T, S, strlen(S))
|
||||
#define CONSUME(R, T, S) consume(R, T, S, strlen(S))
|
||||
|
||||
//
|
||||
// preprocess.c
|
||||
//
|
||||
|
||||
char *format(char *fmt, ...);
|
||||
char *search_include_paths(char *filename);
|
||||
bool file_exists(char *path);
|
||||
char *search_include_paths(char *);
|
||||
void init_macros(void);
|
||||
void define_macro(char *name, char *buf);
|
||||
void undef_macro(char *name);
|
||||
Token *preprocess(Token *tok);
|
||||
void define_macro(char *, char *);
|
||||
void undef_macro(char *);
|
||||
Token *preprocess(Token *);
|
||||
|
||||
//
|
||||
// asm.c
|
||||
//
|
||||
|
||||
#define kAsmImm 1
|
||||
#define kAsmMem 2
|
||||
#define kAsmReg 4
|
||||
#define kAsmMmx 8
|
||||
#define kAsmXmm 16
|
||||
#define kAsmFpu 32
|
||||
#define kAsmRaw 64
|
||||
#define kAsmFlag 128
|
||||
|
||||
struct AsmOperand {
|
||||
uint8_t reg;
|
||||
uint8_t type;
|
||||
char flow;
|
||||
char x87mask;
|
||||
bool isused;
|
||||
int regmask;
|
||||
int predicate;
|
||||
char *str;
|
||||
Node *node;
|
||||
Token *tok;
|
||||
int64_t val;
|
||||
char **label;
|
||||
};
|
||||
|
||||
struct Asm {
|
||||
int n;
|
||||
char *str;
|
||||
Token *tok;
|
||||
AsmOperand ops[20];
|
||||
bool isgnu;
|
||||
bool flagclob;
|
||||
uint8_t x87clob;
|
||||
uint16_t regclob;
|
||||
uint16_t xmmclob;
|
||||
};
|
||||
|
||||
struct StaticAsm {
|
||||
StaticAsm *next;
|
||||
Asm *body;
|
||||
};
|
||||
|
||||
extern StaticAsm *staticasms;
|
||||
|
||||
Asm *asm_stmt(Token **, Token *);
|
||||
void flushln(void);
|
||||
void gen_addr(Node *);
|
||||
void gen_asm(Asm *);
|
||||
void gen_expr(Node *);
|
||||
void pop(char *);
|
||||
void popreg(char *);
|
||||
void print_loc(int64_t, int64_t);
|
||||
void push(void);
|
||||
void pushreg(char *);
|
||||
|
||||
//
|
||||
// fpclassify.c
|
||||
//
|
||||
|
||||
struct FpClassify {
|
||||
Node *node;
|
||||
int args[5];
|
||||
};
|
||||
|
||||
void gen_fpclassify(FpClassify *);
|
||||
|
||||
//
|
||||
// parse.c
|
||||
//
|
||||
|
||||
// Variable or function
|
||||
typedef struct Obj Obj;
|
||||
struct Obj {
|
||||
Obj *next;
|
||||
char *name; // Variable name
|
||||
@ -139,31 +217,36 @@ struct Obj {
|
||||
Token *tok; // representative token
|
||||
bool is_local; // local or global/function
|
||||
int align; // alignment
|
||||
|
||||
// Local variable
|
||||
int offset;
|
||||
|
||||
// Global variable or function
|
||||
bool is_function;
|
||||
bool is_definition;
|
||||
bool is_static;
|
||||
|
||||
bool is_weak;
|
||||
bool is_externally_visible;
|
||||
char *asmname;
|
||||
char *section;
|
||||
char *visibility;
|
||||
// Global variable
|
||||
bool is_tentative;
|
||||
bool is_string_literal;
|
||||
bool is_tls;
|
||||
char *init_data;
|
||||
Relocation *rel;
|
||||
|
||||
// Function
|
||||
bool is_inline;
|
||||
bool is_aligned;
|
||||
bool is_noreturn;
|
||||
bool is_destructor;
|
||||
bool is_constructor;
|
||||
int stack_size;
|
||||
Obj *params;
|
||||
Node *body;
|
||||
Obj *locals;
|
||||
Obj *va_area;
|
||||
Obj *alloca_bottom;
|
||||
int stack_size;
|
||||
|
||||
// Static inline function
|
||||
// Dead Code Elimination
|
||||
bool is_live;
|
||||
bool is_root;
|
||||
StringArray refs;
|
||||
@ -172,7 +255,6 @@ struct Obj {
|
||||
// Global variable can be initialized either by a constant expression
|
||||
// or a pointer to another global variable. This struct represents the
|
||||
// latter.
|
||||
typedef struct Relocation Relocation;
|
||||
struct Relocation {
|
||||
Relocation *next;
|
||||
int offset;
|
||||
@ -180,127 +262,139 @@ struct Relocation {
|
||||
long addend;
|
||||
};
|
||||
|
||||
// AST node
|
||||
typedef enum {
|
||||
ND_NULL_EXPR, // Do nothing
|
||||
ND_ADD, // +
|
||||
ND_SUB, // -
|
||||
ND_MUL, // *
|
||||
ND_DIV, // /
|
||||
ND_NEG, // unary -
|
||||
ND_MOD, // %
|
||||
ND_BITAND, // &
|
||||
ND_BITOR, // |
|
||||
ND_BITXOR, // ^
|
||||
ND_SHL, // <<
|
||||
ND_SHR, // >>
|
||||
ND_EQ, // ==
|
||||
ND_NE, // !=
|
||||
ND_LT, // <
|
||||
ND_LE, // <=
|
||||
ND_ASSIGN, // =
|
||||
ND_COND, // ?:
|
||||
ND_COMMA, // ,
|
||||
ND_MEMBER, // . (struct member access)
|
||||
ND_ADDR, // unary &
|
||||
ND_DEREF, // unary *
|
||||
ND_NOT, // !
|
||||
ND_BITNOT, // ~
|
||||
ND_LOGAND, // &&
|
||||
ND_LOGOR, // ||
|
||||
ND_RETURN, // "return"
|
||||
ND_IF, // "if"
|
||||
ND_FOR, // "for" or "while"
|
||||
ND_DO, // "do"
|
||||
ND_SWITCH, // "switch"
|
||||
ND_CASE, // "case"
|
||||
ND_BLOCK, // { ... }
|
||||
ND_GOTO, // "goto"
|
||||
ND_GOTO_EXPR, // "goto" labels-as-values
|
||||
ND_LABEL, // Labeled statement
|
||||
ND_LABEL_VAL, // [GNU] Labels-as-values
|
||||
ND_FUNCALL, // Function call
|
||||
ND_EXPR_STMT, // Expression statement
|
||||
ND_STMT_EXPR, // Statement expression
|
||||
ND_VAR, // Variable
|
||||
ND_VLA_PTR, // VLA designator
|
||||
ND_NUM, // Integer
|
||||
ND_CAST, // Type cast
|
||||
ND_MEMZERO, // Zero-clear a stack variable
|
||||
ND_ASM, // "asm"
|
||||
ND_CAS, // Atomic compare-and-swap
|
||||
ND_EXCH, // Atomic exchange
|
||||
ND_NULL_EXPR, // Do nothing
|
||||
ND_ADD, // +
|
||||
ND_SUB, // -
|
||||
ND_MUL, // *
|
||||
ND_DIV, // /
|
||||
ND_NEG, // unary -
|
||||
ND_MOD, // %
|
||||
ND_BITAND, // &
|
||||
ND_BITOR, // |
|
||||
ND_BITXOR, // ^
|
||||
ND_SHL, // <<
|
||||
ND_SHR, // >>
|
||||
ND_EQ, // ==
|
||||
ND_NE, // !=
|
||||
ND_LT, // <
|
||||
ND_LE, // <=
|
||||
ND_ASSIGN, // =
|
||||
ND_COND, // ?:
|
||||
ND_COMMA, // ,
|
||||
ND_MEMBER, // . (struct member access)
|
||||
ND_ADDR, // unary &
|
||||
ND_DEREF, // unary *
|
||||
ND_NOT, // !
|
||||
ND_BITNOT, // ~
|
||||
ND_LOGAND, // &&
|
||||
ND_LOGOR, // ||
|
||||
ND_RETURN, // "return"
|
||||
ND_IF, // "if"
|
||||
ND_FOR, // "for" or "while"
|
||||
ND_DO, // "do"
|
||||
ND_SWITCH, // "switch"
|
||||
ND_CASE, // "case"
|
||||
ND_BLOCK, // { ... }
|
||||
ND_GOTO, // "goto"
|
||||
ND_GOTO_EXPR, // "goto" labels-as-values
|
||||
ND_LABEL, // Labeled statement
|
||||
ND_LABEL_VAL, // [GNU] Labels-as-values
|
||||
ND_FUNCALL, // Function call
|
||||
ND_EXPR_STMT, // Expression statement
|
||||
ND_STMT_EXPR, // Statement expression
|
||||
ND_VAR, // Variable
|
||||
ND_VLA_PTR, // VLA designator
|
||||
ND_NUM, // Integer
|
||||
ND_CAST, // Type cast
|
||||
ND_MEMZERO, // Zero-clear a stack variable
|
||||
ND_ASM, // "asm"
|
||||
ND_CAS, // Atomic compare-and-swap
|
||||
ND_EXCH, // Atomic exchange
|
||||
ND_FPCLASSIFY, // floating point classify
|
||||
} NodeKind;
|
||||
|
||||
// AST node type
|
||||
struct Node {
|
||||
NodeKind kind; // Node kind
|
||||
Node *next; // Next node
|
||||
Type *ty; // Type, e.g. int or pointer to int
|
||||
Token *tok; // Representative token
|
||||
|
||||
Node *lhs; // Left-hand side
|
||||
Node *rhs; // Right-hand side
|
||||
|
||||
Node *lhs; // Left-hand side
|
||||
Node *rhs; // Right-hand side
|
||||
// "if" or "for" statement
|
||||
Node *cond;
|
||||
Node *then;
|
||||
Node *els;
|
||||
Node *init;
|
||||
Node *inc;
|
||||
|
||||
// "break" and "continue" labels
|
||||
char *brk_label;
|
||||
char *cont_label;
|
||||
|
||||
// Block or statement expression
|
||||
Node *body;
|
||||
|
||||
// Struct member access
|
||||
Member *member;
|
||||
|
||||
// Function call
|
||||
Type *func_ty;
|
||||
Node *args;
|
||||
bool pass_by_stack;
|
||||
Obj *ret_buffer;
|
||||
|
||||
// Goto or labeled statement, or labels-as-values
|
||||
char *label;
|
||||
char *unique_label;
|
||||
Node *goto_next;
|
||||
|
||||
// Switch
|
||||
Node *case_next;
|
||||
Node *default_case;
|
||||
|
||||
// Case
|
||||
long begin;
|
||||
long end;
|
||||
|
||||
// "asm" string literal
|
||||
char *asm_str;
|
||||
|
||||
// Atomic compare-and-swap
|
||||
Node *cas_addr;
|
||||
Node *cas_old;
|
||||
Node *cas_new;
|
||||
|
||||
// Atomic op= operators
|
||||
Obj *atomic_addr;
|
||||
Node *atomic_expr;
|
||||
|
||||
// Variable
|
||||
Obj *var;
|
||||
|
||||
// Numeric literal
|
||||
int64_t val;
|
||||
long double fval;
|
||||
union {
|
||||
struct {
|
||||
// Function call
|
||||
Type *func_ty;
|
||||
Node *args;
|
||||
bool pass_by_stack;
|
||||
Obj *ret_buffer;
|
||||
};
|
||||
struct {
|
||||
// Switch
|
||||
Node *case_next;
|
||||
Node *default_case;
|
||||
// Goto or labeled statement, or labels-as-values
|
||||
char *label;
|
||||
char *unique_label;
|
||||
Node *goto_next;
|
||||
// "break" and "continue" labels
|
||||
char *brk_label;
|
||||
char *cont_label;
|
||||
// Case
|
||||
long begin;
|
||||
long end;
|
||||
};
|
||||
struct {
|
||||
// Struct member access
|
||||
Member *member;
|
||||
};
|
||||
struct {
|
||||
// Assembly
|
||||
Asm *azm;
|
||||
};
|
||||
struct {
|
||||
// Atomic compare-and-swap
|
||||
Node *cas_addr;
|
||||
Node *cas_old;
|
||||
Node *cas_new;
|
||||
};
|
||||
struct {
|
||||
// Atomic op= operators
|
||||
Obj *atomic_addr;
|
||||
Node *atomic_expr;
|
||||
};
|
||||
struct {
|
||||
// Variable
|
||||
Obj *var;
|
||||
};
|
||||
struct {
|
||||
// Numeric literal
|
||||
int64_t val;
|
||||
long double fval;
|
||||
};
|
||||
struct {
|
||||
FpClassify *fpc;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Node *new_cast(Node *expr, Type *ty);
|
||||
int64_t const_expr(Token **rest, Token *tok);
|
||||
Obj *parse(Token *tok);
|
||||
Node *expr(Token **, Token *);
|
||||
Node *new_cast(Node *, Type *);
|
||||
Node *new_node(NodeKind, Token *);
|
||||
Obj *parse(Token *);
|
||||
bool is_const_expr(Node *);
|
||||
char *ConsumeStringLiteral(Token **, Token *);
|
||||
int64_t const_expr(Token **, Token *);
|
||||
int64_t eval(Node *);
|
||||
int64_t eval2(Node *, char ***);
|
||||
|
||||
//
|
||||
// type.c
|
||||
@ -313,6 +407,7 @@ typedef enum {
|
||||
TY_SHORT,
|
||||
TY_INT,
|
||||
TY_LONG,
|
||||
TY_INT128,
|
||||
TY_FLOAT,
|
||||
TY_DOUBLE,
|
||||
TY_LDOUBLE,
|
||||
@ -332,7 +427,6 @@ struct Type {
|
||||
bool is_unsigned; // unsigned or signed
|
||||
bool is_atomic; // true if _Atomic
|
||||
Type *origin; // for type compatibility check
|
||||
|
||||
// Pointer-to or array-of type. We intentionally use the same member
|
||||
// to represent pointer/array duality in C.
|
||||
//
|
||||
@ -342,23 +436,20 @@ struct Type {
|
||||
// naturally handled as if it were "pointer to T", as required by
|
||||
// the C spec.
|
||||
Type *base;
|
||||
|
||||
// Declaration
|
||||
Token *name;
|
||||
Token *name_pos;
|
||||
|
||||
// Array
|
||||
int array_len;
|
||||
|
||||
int vector_size;
|
||||
// Variable-length array
|
||||
Node *vla_len; // # of elements
|
||||
Obj *vla_size; // sizeof() value
|
||||
|
||||
// Struct
|
||||
Member *members;
|
||||
bool is_flexible;
|
||||
bool is_packed;
|
||||
|
||||
bool is_aligned;
|
||||
// Function type
|
||||
Type *return_ty;
|
||||
Type *params;
|
||||
@ -375,59 +466,70 @@ struct Member {
|
||||
int idx;
|
||||
int align;
|
||||
int offset;
|
||||
|
||||
// Bitfield
|
||||
bool is_bitfield;
|
||||
int bit_offset;
|
||||
int bit_width;
|
||||
};
|
||||
|
||||
extern Type *ty_void;
|
||||
extern Type *ty_bool;
|
||||
extern Type ty_void[1];
|
||||
extern Type ty_bool[1];
|
||||
extern Type ty_char[1];
|
||||
extern Type ty_short[1];
|
||||
extern Type ty_int[1];
|
||||
extern Type ty_long[1];
|
||||
extern Type ty_int128[1];
|
||||
extern Type ty_uchar[1];
|
||||
extern Type ty_ushort[1];
|
||||
extern Type ty_uint[1];
|
||||
extern Type ty_ulong[1];
|
||||
extern Type ty_uint128[1];
|
||||
extern Type ty_float[1];
|
||||
extern Type ty_double[1];
|
||||
extern Type ty_ldouble[1];
|
||||
|
||||
extern Type *ty_char;
|
||||
extern Type *ty_short;
|
||||
extern Type *ty_int;
|
||||
extern Type *ty_long;
|
||||
|
||||
extern Type *ty_uchar;
|
||||
extern Type *ty_ushort;
|
||||
extern Type *ty_uint;
|
||||
extern Type *ty_ulong;
|
||||
|
||||
extern Type *ty_float;
|
||||
extern Type *ty_double;
|
||||
extern Type *ty_ldouble;
|
||||
|
||||
bool is_integer(Type *ty);
|
||||
bool is_flonum(Type *ty);
|
||||
bool is_numeric(Type *ty);
|
||||
bool is_compatible(Type *t1, Type *t2);
|
||||
Type *copy_type(Type *ty);
|
||||
Type *pointer_to(Type *base);
|
||||
Type *func_type(Type *return_ty);
|
||||
Type *array_of(Type *base, int size);
|
||||
Type *vla_of(Type *base, Node *expr);
|
||||
bool is_integer(Type *);
|
||||
bool is_flonum(Type *);
|
||||
bool is_numeric(Type *);
|
||||
bool is_compatible(Type *, Type *);
|
||||
Type *copy_type(Type *);
|
||||
Type *pointer_to(Type *);
|
||||
Type *func_type(Type *);
|
||||
Type *array_of(Type *, int);
|
||||
Type *vla_of(Type *, Node *);
|
||||
Type *enum_type(void);
|
||||
Type *struct_type(void);
|
||||
void add_type(Node *node);
|
||||
void add_type(Node *);
|
||||
|
||||
//
|
||||
// cast.c
|
||||
//
|
||||
|
||||
void gen_cast(Type *, Type *);
|
||||
|
||||
//
|
||||
// codegen.c
|
||||
//
|
||||
|
||||
void codegen(Obj *prog, FILE *out);
|
||||
int align_to(int n, int align);
|
||||
extern int depth;
|
||||
extern FILE *output_stream;
|
||||
|
||||
int align_to(int, int);
|
||||
int count(void);
|
||||
void cmp_zero(Type *);
|
||||
void codegen(Obj *, FILE *);
|
||||
void gen_stmt(Node *);
|
||||
void println(char *, ...) __attribute__((__format__(__printf__, 1, 2)));
|
||||
|
||||
//
|
||||
// unicode.c
|
||||
//
|
||||
|
||||
int encode_utf8(char *buf, uint32_t c);
|
||||
uint32_t decode_utf8(char **new_pos, char *p);
|
||||
bool is_ident1(uint32_t c);
|
||||
bool is_ident2(uint32_t c);
|
||||
int str_width(char *p, int len);
|
||||
int encode_utf8(char *, uint32_t);
|
||||
uint32_t decode_utf8(char **, char *);
|
||||
bool is_ident1(uint32_t);
|
||||
bool is_ident2(uint32_t);
|
||||
int str_width(char *, int);
|
||||
|
||||
//
|
||||
// hashmap.c
|
||||
@ -445,29 +547,28 @@ typedef struct {
|
||||
int used;
|
||||
} HashMap;
|
||||
|
||||
void *hashmap_get(HashMap *map, char *key);
|
||||
void *hashmap_get2(HashMap *map, char *key, int keylen);
|
||||
void hashmap_put(HashMap *map, char *key, void *val);
|
||||
void hashmap_put2(HashMap *map, char *key, int keylen, void *val);
|
||||
void hashmap_delete(HashMap *map, char *key);
|
||||
void hashmap_delete2(HashMap *map, char *key, int keylen);
|
||||
void *hashmap_get(HashMap *, char *);
|
||||
void *hashmap_get2(HashMap *, char *, int);
|
||||
void hashmap_put(HashMap *, char *, void *);
|
||||
void hashmap_put2(HashMap *, char *, int, void *);
|
||||
void hashmap_delete(HashMap *, char *);
|
||||
void hashmap_delete2(HashMap *, char *, int);
|
||||
void hashmap_test(void);
|
||||
|
||||
//
|
||||
// main.c
|
||||
// chibicc.c
|
||||
//
|
||||
|
||||
extern StringArray include_paths;
|
||||
extern bool opt_fpic;
|
||||
extern bool opt_fcommon;
|
||||
extern bool opt_fpic;
|
||||
extern bool opt_verbose;
|
||||
extern bool opt_mpopcnt;
|
||||
extern char *base_file;
|
||||
|
||||
typedef struct StaticAsm {
|
||||
struct StaticAsm *next;
|
||||
Node *body;
|
||||
} StaticAsm;
|
||||
|
||||
extern struct StaticAsm *staticasms;
|
||||
extern bool opt_pg;
|
||||
extern bool opt_mfentry;
|
||||
extern bool opt_mnop_mcount;
|
||||
extern bool opt_mrecord_mcount;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
131
third_party/chibicc/chibicc.mk
vendored
131
third_party/chibicc/chibicc.mk
vendored
@ -1,70 +1,109 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# C Compiler
|
||||
#
|
||||
# OVERVIEW
|
||||
#
|
||||
# This makefile compiles and runs each test twice. The first with
|
||||
# GCC-built chibicc, and a second time with chibicc-built chibicc
|
||||
|
||||
CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com.dbg
|
||||
CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
|
||||
CHIBICC_FLAGS = \
|
||||
-fno-common \
|
||||
-include libc/integral/normalize.inc
|
||||
|
||||
PKGS += THIRD_PARTY_CHIBICC
|
||||
|
||||
THIRD_PARTY_CHIBICC_ARTIFACTS += THIRD_PARTY_CHIBICC_A
|
||||
THIRD_PARTY_CHIBICC = $(THIRD_PARTY_CHIBICC_A_DEPS) $(THIRD_PARTY_CHIBICC_A)
|
||||
THIRD_PARTY_CHIBICC_A = o/$(MODE)/third_party/chibicc/chibicc.a
|
||||
THIRD_PARTY_CHIBICC_A_FILES := $(wildcard third_party/chibicc/*)
|
||||
THIRD_PARTY_CHIBICC_A_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
THIRD_PARTY_CHIBICC_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
THIRD_PARTY_CHIBICC_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
THIRD_PARTY_CHIBICC_A_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_A_FILES))
|
||||
|
||||
THIRD_PARTY_CHIBICC_BINS = \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com
|
||||
THIRD_PARTY_CHIBICC_BINS = \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com \
|
||||
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg \
|
||||
o/$(MODE)/third_party/chibicc/chibicc2.com
|
||||
|
||||
THIRD_PARTY_CHIBICC_A_SRCS = \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS_S) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS_C)
|
||||
THIRD_PARTY_CHIBICC_A_OBJS = \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.o)
|
||||
|
||||
THIRD_PARTY_CHIBICC_A_OBJS = \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
THIRD_PARTY_CHIBICC_A_CHECKS = \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
THIRD_PARTY_CHIBICC_A_CHECKS = \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_FMT \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_UNICODE \
|
||||
LIBC_STDIO \
|
||||
LIBC_MEM \
|
||||
LIBC_LOG \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_TIME \
|
||||
LIBC_X \
|
||||
LIBC_CONV \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_LOG \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_TIME \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA
|
||||
|
||||
THIRD_PARTY_CHIBICC_A_DEPS := \
|
||||
THIRD_PARTY_CHIBICC_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_A): \
|
||||
third_party/chibicc/ \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(THIRD_PARTY_CHIBICC_A): \
|
||||
third_party/chibicc/ \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(THIRD_PARTY_CHIBICC_A_OBJS)
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_OBJS) \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_CHIBICC_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/%.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
o/$(MODE)/third_party/chibicc/%.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.o) \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/chibicc.o: \
|
||||
CPPFLAGS += \
|
||||
-DCRT=\"$(CRT)\" \
|
||||
-DAPE=\"o/$(MODE)/ape/ape.o\" \
|
||||
-DLDS=\"o/$(MODE)/ape/ape.lds\"
|
||||
|
||||
o/$(MODE)/third_party/chibicc/chibicc.chibicc.s: \
|
||||
CHIBICC_FLAGS += \
|
||||
-DCRT=\"$(CRT)\" \
|
||||
-DAPE=\"o/$(MODE)/ape/ape.o\" \
|
||||
-DLDS=\"o/$(MODE)/ape/ape.lds\"
|
||||
|
||||
o/$(MODE)/%.chibicc.s: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg
|
||||
@ACTION=CHIBICC TARGET=$@ build/do $(CHIBICC) $(CHIBICC_FLAGS) -S -o $@ $<
|
||||
o/$(MODE)/%.chibicc2.s: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg
|
||||
@ACTION=CHIBICC2 TARGET=$@ build/do $(CHIBICC2) $(CHIBICC_FLAGS) -S -o $@ $<
|
||||
|
||||
THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)))
|
||||
THIRD_PARTY_CHIBICC_SRCS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_SRCS))
|
||||
THIRD_PARTY_CHIBICC_HDRS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_HDRS))
|
||||
@ -73,6 +112,8 @@ THIRD_PARTY_CHIBICC_OBJS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x)_O
|
||||
$(THIRD_PARTY_CHIBICC_OBJS): $(BUILD_FILES) third_party/chibicc/chibicc.mk
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/chibicc
|
||||
o/$(MODE)/third_party/chibicc: \
|
||||
$(THIRD_PARTY_CHIBICC_BINS) \
|
||||
$(THIRD_PARTY_CHIBICC_CHECKS)
|
||||
o/$(MODE)/third_party/chibicc: \
|
||||
o/$(MODE)/third_party/chibicc/test \
|
||||
$(THIRD_PARTY_CHIBICC_BINS) \
|
||||
$(THIRD_PARTY_CHIBICC_CHECKS) \
|
||||
$(THIRD_PARTY_CHIBICC_A_SRCS:%.c=o/$(MODE)/%.chibicc.s)
|
||||
|
||||
1890
third_party/chibicc/codegen.c
vendored
1890
third_party/chibicc/codegen.c
vendored
File diff suppressed because it is too large
Load Diff
145
third_party/chibicc/fpclassify.c
vendored
Normal file
145
third_party/chibicc/fpclassify.c
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
/**
|
||||
* @fileoverview __builtin_fpclassify() implementation
|
||||
*/
|
||||
|
||||
#define FPCLASSIFY_FLOAT \
|
||||
"\tmovaps\t%%xmm0,%%xmm1\n\
|
||||
\tmov\t$0x7fffffff,%%eax\n\
|
||||
\tmovd\t%%eax,%%xmm2\n\
|
||||
\tandps\t%%xmm2,%%xmm1\n\
|
||||
\tmov\t$%d,%%eax\n\
|
||||
\tucomiss\t%%xmm1,%%xmm1\n\
|
||||
\tjp\t9f\n\
|
||||
\tmov\t$0x7f7fffff,%%edi\n\
|
||||
\tmovd\t%%edi,%%xmm2\n\
|
||||
\tucomiss\t%%xmm2,%%xmm1\n\
|
||||
\tja\t2f\n\
|
||||
\tmov\t$0x00800000,%%edi\n\
|
||||
\tmovd\t%%edi,%%xmm2\n\
|
||||
\tucomiss\t%%xmm2,%%xmm1\n\
|
||||
\tjnb\t3f\n\
|
||||
\txorps\t%%xmm1,%%xmm1\n\
|
||||
\tucomiss\t%%xmm1,%%xmm0\n\
|
||||
\tjp\t1f\n\
|
||||
\tmovl\t$%d,%%eax\n\
|
||||
\tje\t9f\n\
|
||||
1:\tmovl\t$%d,%%eax\n\
|
||||
\tjmp\t9f\n\
|
||||
2:\tmovl\t$%d,%%eax\n\
|
||||
\tjmp\t9f\n\
|
||||
3:\tmovl\t$%d,%%eax\n\
|
||||
9:"
|
||||
|
||||
#define FPCLASSIFY_DOUBLE \
|
||||
"\tmovapd\t%%xmm0,%%xmm1\n\
|
||||
\tmov\t$0x7fffffffffffffff,%%rax\n\
|
||||
\tmovq\t%%rax,%%xmm2\n\
|
||||
\tandps\t%%xmm2,%%xmm1\n\
|
||||
\tmov\t$%d,%%eax\n\
|
||||
\tucomisd\t%%xmm1,%%xmm1\n\
|
||||
\tjp\t9f\n\
|
||||
\tmov\t$0x7fefffffffffffff,%%rdi\n\
|
||||
\tmovq\t%%rdi,%%xmm2\n\
|
||||
\tucomisd\t%%xmm2,%%xmm1\n\
|
||||
\tja\t2f\n\
|
||||
\tmov\t$0x0010000000000000,%%rdi\n\
|
||||
\tmovq\t%%rdi,%%xmm2\n\
|
||||
\tucomisd\t%%xmm2,%%xmm1\n\
|
||||
\tjnb\t3f\n\
|
||||
\txorps\t%%xmm1,%%xmm1\n\
|
||||
\tucomisd\t%%xmm1,%%xmm0\n\
|
||||
\tjp\t1f\n\
|
||||
\tmovl\t$%d,%%eax\n\
|
||||
\tje\t9f\n\
|
||||
1:\tmovl\t$%d,%%eax\n\
|
||||
\tjmp\t9f\n\
|
||||
2:\tmovl\t$%d,%%eax\n\
|
||||
\tjmp\t9f\n\
|
||||
3:\tmovl\t$%d,%%eax\n\
|
||||
9:"
|
||||
|
||||
#define FPCLASSIFY_LDOUBLE \
|
||||
"\tmov\t$%d,%%eax\n\
|
||||
\tfld\t%%st\n\
|
||||
\tfabs\n\
|
||||
\tfucomi\t%%st,%%st\n\
|
||||
\tjp\t6f\n\
|
||||
\tpush\t$0x7ffe\n\
|
||||
\tpush\t$-1\n\
|
||||
\tfldt\t(%%rsp)\n\
|
||||
\tadd\t$16,%%rsp\n\
|
||||
\tfxch\n\
|
||||
\tmov\t$%d,%%eax\n\
|
||||
\tfucomi\n\
|
||||
\tfstp\t%%st(1)\n\
|
||||
\tja\t7f\n\
|
||||
\tmov\t$1,%%edi\n\
|
||||
\tpush\t%%rdi\n\
|
||||
\tror\t%%rdi\n\
|
||||
\tpush\t%%rdi\n\
|
||||
\tfldt\t(%%rsp)\n\
|
||||
\tadd\t$16,%%rsp\n\
|
||||
\tfxch\n\
|
||||
\tmov\t$%d,%%eax\n\
|
||||
\tfucomip\n\
|
||||
\tfstp\t%%st\n\
|
||||
\tjnb\t8f\n\
|
||||
\tfldz\n\
|
||||
\tfxch\n\
|
||||
\tfucomip\n\
|
||||
\tfstp\t%%st\n\
|
||||
\tjp\t5f\n\
|
||||
\tmov\t$%d,%%eax\n\
|
||||
\tje\t9f\n\
|
||||
5:\tmov\t$%d,%%eax\n\
|
||||
\tjmp\t9f\n\
|
||||
6:\tfstp\t%%st\n\
|
||||
\tfstp\t%%st\n\
|
||||
\tjmp\t9f\n\
|
||||
7:\tfstp\t%%st\n\
|
||||
\tfstp\t%%st\n\
|
||||
\tjmp\t9f\n\
|
||||
8:\tfstp\t%%st\n\
|
||||
9:"
|
||||
|
||||
void gen_fpclassify(FpClassify *fpc) {
|
||||
int fpnan = fpc->args[0];
|
||||
int fpinf = fpc->args[1];
|
||||
int fpnorm = fpc->args[2];
|
||||
int fpsubnorm = fpc->args[3];
|
||||
int fpzero = fpc->args[4];
|
||||
gen_expr(fpc->node);
|
||||
switch (fpc->node->ty->kind) {
|
||||
case TY_FLOAT:
|
||||
println(FPCLASSIFY_FLOAT, fpnan, fpzero, fpsubnorm, fpinf, fpnorm);
|
||||
break;
|
||||
case TY_DOUBLE:
|
||||
println(FPCLASSIFY_DOUBLE, fpnan, fpzero, fpsubnorm, fpinf, fpnorm);
|
||||
break;
|
||||
case TY_LDOUBLE:
|
||||
println(FPCLASSIFY_LDOUBLE, fpnan, fpinf, fpnorm, fpzero, fpsubnorm);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
24
third_party/chibicc/hashmap.c
vendored
24
third_party/chibicc/hashmap.c
vendored
@ -20,7 +20,7 @@ static void rehash(HashMap *map) {
|
||||
int nkeys = 0;
|
||||
for (int i = 0; i < map->capacity; i++)
|
||||
if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE) nkeys++;
|
||||
int cap = map->capacity;
|
||||
size_t cap = map->capacity;
|
||||
while ((nkeys * 100) / cap >= 50) cap = cap * 2;
|
||||
// Create a new hashmap and copy all key-values.
|
||||
HashMap map2 = {};
|
||||
@ -44,7 +44,7 @@ static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
|
||||
if (!map->buckets) return NULL;
|
||||
uint64_t hash = fnv_hash(key, keylen);
|
||||
for (int i = 0; i < map->capacity; i++) {
|
||||
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
|
||||
HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)];
|
||||
if (match(ent, key, keylen)) return ent;
|
||||
if (ent->key == NULL) return NULL;
|
||||
}
|
||||
@ -58,7 +58,7 @@ static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {
|
||||
if ((map->used * 100) / map->capacity >= 70) rehash(map);
|
||||
uint64_t hash = fnv_hash(key, keylen);
|
||||
for (int i = 0; i < map->capacity; i++) {
|
||||
HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
|
||||
HashEntry *ent = &map->buckets[(hash + i) & (map->capacity - 1)];
|
||||
if (match(ent, key, keylen)) return ent;
|
||||
if (ent->key == TOMBSTONE) {
|
||||
ent->key = key;
|
||||
@ -102,29 +102,31 @@ void hashmap_delete2(HashMap *map, char *key, int keylen) {
|
||||
if (ent) ent->key = TOMBSTONE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void hashmap_test(void) {
|
||||
HashMap *map = calloc(1, sizeof(HashMap));
|
||||
for (int i = 0; i < 5000; i++)
|
||||
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
|
||||
for (int i = 1000; i < 2000; i++) hashmap_delete(map, format("key %d", i));
|
||||
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
|
||||
for (int i = 1000; i < 2000; i++) hashmap_delete(map, xasprintf("key %d", i));
|
||||
for (int i = 1500; i < 1600; i++)
|
||||
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
|
||||
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
|
||||
for (int i = 6000; i < 7000; i++)
|
||||
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
|
||||
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
|
||||
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
|
||||
for (int i = 1000; i < 1500; i++)
|
||||
assert(hashmap_get(map, "no such key") == NULL);
|
||||
for (int i = 1500; i < 1600; i++)
|
||||
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
|
||||
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
|
||||
for (int i = 1600; i < 2000; i++)
|
||||
assert(hashmap_get(map, "no such key") == NULL);
|
||||
for (int i = 2000; i < 5000; i++)
|
||||
assert((size_t)hashmap_get(map, format("key %d", i)) == i);
|
||||
assert((size_t)hashmap_get(map, xasprintf("key %d", i)) == i);
|
||||
for (int i = 5000; i < 6000; i++)
|
||||
assert(hashmap_get(map, "no such key") == NULL);
|
||||
for (int i = 6000; i < 7000; i++)
|
||||
hashmap_put(map, format("key %d", i), (void *)(size_t)i);
|
||||
hashmap_put(map, xasprintf("key %d", i), (void *)(size_t)i);
|
||||
assert(hashmap_get(map, "no such key") == NULL);
|
||||
printf("OK\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
1521
third_party/chibicc/parse.c
vendored
1521
third_party/chibicc/parse.c
vendored
File diff suppressed because it is too large
Load Diff
587
third_party/chibicc/preprocess.c
vendored
587
third_party/chibicc/preprocess.c
vendored
@ -24,13 +24,27 @@
|
||||
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
typedef struct CondIncl CondIncl;
|
||||
typedef struct Hideset Hideset;
|
||||
typedef struct Macro Macro;
|
||||
typedef struct MacroArg MacroArg;
|
||||
typedef struct MacroParam MacroParam;
|
||||
|
||||
typedef Token *macro_handler_fn(Token *);
|
||||
|
||||
typedef enum {
|
||||
STR_NONE,
|
||||
STR_UTF8,
|
||||
STR_UTF16,
|
||||
STR_UTF32,
|
||||
STR_WIDE,
|
||||
} StringKind;
|
||||
|
||||
struct MacroParam {
|
||||
MacroParam *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
typedef struct MacroArg MacroArg;
|
||||
struct MacroArg {
|
||||
MacroArg *next;
|
||||
char *name;
|
||||
@ -38,9 +52,6 @@ struct MacroArg {
|
||||
Token *tok;
|
||||
};
|
||||
|
||||
typedef Token *macro_handler_fn(Token *);
|
||||
|
||||
typedef struct Macro Macro;
|
||||
struct Macro {
|
||||
char *name;
|
||||
bool is_objlike; // Object-like or function-like
|
||||
@ -51,7 +62,6 @@ struct Macro {
|
||||
};
|
||||
|
||||
// `#if` can be nested, so we use a stack to manage nested `#if`s.
|
||||
typedef struct CondIncl CondIncl;
|
||||
struct CondIncl {
|
||||
CondIncl *next;
|
||||
enum { IN_THEN, IN_ELIF, IN_ELSE } ctx;
|
||||
@ -59,7 +69,6 @@ struct CondIncl {
|
||||
bool included;
|
||||
};
|
||||
|
||||
typedef struct Hideset Hideset;
|
||||
struct Hideset {
|
||||
Hideset *next;
|
||||
char *name;
|
||||
@ -70,20 +79,11 @@ static CondIncl *cond_incl;
|
||||
static HashMap pragma_once;
|
||||
static int include_next_idx;
|
||||
|
||||
static Token *preprocess2(Token *tok);
|
||||
static Macro *find_macro(Token *tok);
|
||||
|
||||
char *format(char *fmt, ...) {
|
||||
char *res;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = xvasprintf(fmt, va);
|
||||
va_end(va);
|
||||
return res;
|
||||
}
|
||||
static Token *preprocess2(Token *);
|
||||
static Macro *find_macro(Token *);
|
||||
|
||||
static bool is_hash(Token *tok) {
|
||||
return tok->at_bol && equal(tok, "#");
|
||||
return tok->at_bol && EQUAL(tok, "#");
|
||||
}
|
||||
|
||||
// Some preprocessor directives such as #include allow extraneous
|
||||
@ -118,23 +118,30 @@ static Hideset *new_hideset(char *name) {
|
||||
static Hideset *hideset_union(Hideset *hs1, Hideset *hs2) {
|
||||
Hideset head = {};
|
||||
Hideset *cur = &head;
|
||||
for (; hs1; hs1 = hs1->next) cur = cur->next = new_hideset(hs1->name);
|
||||
for (; hs1; hs1 = hs1->next) {
|
||||
cur = cur->next = new_hideset(hs1->name);
|
||||
}
|
||||
cur->next = hs2;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
static bool hideset_contains(Hideset *hs, char *s, int len) {
|
||||
for (; hs; hs = hs->next)
|
||||
if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) return true;
|
||||
for (; hs; hs = hs->next) {
|
||||
if (strlen(hs->name) == len && !strncmp(hs->name, s, len)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Hideset *hideset_intersection(Hideset *hs1, Hideset *hs2) {
|
||||
Hideset head = {};
|
||||
Hideset *cur = &head;
|
||||
for (; hs1; hs1 = hs1->next)
|
||||
if (hideset_contains(hs2, hs1->name, strlen(hs1->name)))
|
||||
for (; hs1; hs1 = hs1->next) {
|
||||
if (hideset_contains(hs2, hs1->name, strlen(hs1->name))) {
|
||||
cur = cur->next = new_hideset(hs1->name);
|
||||
}
|
||||
}
|
||||
return head.next;
|
||||
}
|
||||
|
||||
@ -162,12 +169,12 @@ static Token *append(Token *tok1, Token *tok2) {
|
||||
|
||||
static Token *skip_cond_incl2(Token *tok) {
|
||||
while (tok->kind != TK_EOF) {
|
||||
if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
|
||||
equal(tok->next, "ifndef"))) {
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
|
||||
EQUAL(tok->next, "ifndef"))) {
|
||||
tok = skip_cond_incl2(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
if (is_hash(tok) && equal(tok->next, "endif")) return tok->next->next;
|
||||
if (is_hash(tok) && EQUAL(tok->next, "endif")) return tok->next->next;
|
||||
tok = tok->next;
|
||||
}
|
||||
return tok;
|
||||
@ -177,13 +184,13 @@ static Token *skip_cond_incl2(Token *tok) {
|
||||
// Nested `#if` and `#endif` are skipped.
|
||||
static Token *skip_cond_incl(Token *tok) {
|
||||
while (tok->kind != TK_EOF) {
|
||||
if (is_hash(tok) && (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
|
||||
equal(tok->next, "ifndef"))) {
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "if") || EQUAL(tok->next, "ifdef") ||
|
||||
EQUAL(tok->next, "ifndef"))) {
|
||||
tok = skip_cond_incl2(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
if (is_hash(tok) && (equal(tok->next, "elif") || equal(tok->next, "else") ||
|
||||
equal(tok->next, "endif")))
|
||||
if (is_hash(tok) && (EQUAL(tok->next, "elif") || EQUAL(tok->next, "else") ||
|
||||
EQUAL(tok->next, "endif")))
|
||||
break;
|
||||
tok = tok->next;
|
||||
}
|
||||
@ -239,9 +246,9 @@ static Token *read_const_expr(Token **rest, Token *tok) {
|
||||
while (tok->kind != TK_EOF) {
|
||||
// "defined(foo)" or "defined foo" becomes "1" if macro "foo"
|
||||
// is defined. Otherwise "0".
|
||||
if (equal(tok, "defined")) {
|
||||
if (EQUAL(tok, "defined")) {
|
||||
Token *start = tok;
|
||||
bool has_paren = consume(&tok, tok->next, "(");
|
||||
bool has_paren = CONSUME(&tok, tok->next, "(");
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(start, "macro name must be an identifier");
|
||||
Macro *m = find_macro(tok);
|
||||
@ -310,15 +317,15 @@ static MacroParam *read_macro_params(Token **rest, Token *tok,
|
||||
char **va_args_name) {
|
||||
MacroParam head = {};
|
||||
MacroParam *cur = &head;
|
||||
while (!equal(tok, ")")) {
|
||||
while (!EQUAL(tok, ")")) {
|
||||
if (cur != &head) tok = skip(tok, ",");
|
||||
if (equal(tok, "...")) {
|
||||
if (EQUAL(tok, "...")) {
|
||||
*va_args_name = "__VA_ARGS__";
|
||||
*rest = skip(tok->next, ")");
|
||||
return head.next;
|
||||
}
|
||||
if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier");
|
||||
if (equal(tok->next, "...")) {
|
||||
if (EQUAL(tok->next, "...")) {
|
||||
*va_args_name = strndup(tok->loc, tok->len);
|
||||
*rest = skip(tok->next->next, ")");
|
||||
return head.next;
|
||||
@ -336,7 +343,7 @@ static void read_macro_definition(Token **rest, Token *tok) {
|
||||
if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier");
|
||||
char *name = strndup(tok->loc, tok->len);
|
||||
tok = tok->next;
|
||||
if (!tok->has_space && equal(tok, "(")) {
|
||||
if (!tok->has_space && EQUAL(tok, "(")) {
|
||||
// Function-like macro
|
||||
char *va_args_name = NULL;
|
||||
MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
|
||||
@ -354,12 +361,12 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
|
||||
Token *cur = &head;
|
||||
int level = 0;
|
||||
for (;;) {
|
||||
if (level == 0 && equal(tok, ")")) break;
|
||||
if (level == 0 && !read_rest && equal(tok, ",")) break;
|
||||
if (level == 0 && EQUAL(tok, ")")) break;
|
||||
if (level == 0 && !read_rest && EQUAL(tok, ",")) break;
|
||||
if (tok->kind == TK_EOF) error_tok(tok, "premature end of input");
|
||||
if (equal(tok, "("))
|
||||
if (EQUAL(tok, "("))
|
||||
level++;
|
||||
else if (equal(tok, ")"))
|
||||
else if (EQUAL(tok, ")"))
|
||||
level--;
|
||||
cur = cur->next = copy_token(tok);
|
||||
tok = tok->next;
|
||||
@ -385,7 +392,7 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params,
|
||||
}
|
||||
if (va_args_name) {
|
||||
MacroArg *arg;
|
||||
if (equal(tok, ")")) {
|
||||
if (EQUAL(tok, ")")) {
|
||||
arg = calloc(1, sizeof(MacroArg));
|
||||
arg->tok = new_eof(tok);
|
||||
} else {
|
||||
@ -454,8 +461,11 @@ static Token *paste(Token *lhs, Token *rhs) {
|
||||
}
|
||||
|
||||
static bool has_varargs(MacroArg *args) {
|
||||
for (MacroArg *ap = args; ap; ap = ap->next)
|
||||
if (!strcmp(ap->name, "__VA_ARGS__")) return ap->tok->kind != TK_EOF;
|
||||
for (MacroArg *ap = args; ap; ap = ap->next) {
|
||||
if (!strcmp(ap->name, "__VA_ARGS__")) {
|
||||
return ap->tok->kind != TK_EOF;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -463,10 +473,9 @@ static bool has_varargs(MacroArg *args) {
|
||||
static Token *subst(Token *tok, MacroArg *args) {
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
|
||||
while (tok->kind != TK_EOF) {
|
||||
// "#" followed by a parameter is replaced with stringized actuals.
|
||||
if (equal(tok, "#")) {
|
||||
if (EQUAL(tok, "#")) {
|
||||
MacroArg *arg = find_arg(args, tok->next);
|
||||
if (!arg)
|
||||
error_tok(tok->next, "'#' is not followed by a macro parameter");
|
||||
@ -474,11 +483,10 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded
|
||||
// to the empty token list. Otherwise, its expaned to `,` and
|
||||
// __VA_ARGS__.
|
||||
if (equal(tok, ",") && equal(tok->next, "##")) {
|
||||
if (EQUAL(tok, ",") && EQUAL(tok->next, "##")) {
|
||||
MacroArg *arg = find_arg(args, tok->next->next);
|
||||
if (arg && arg->is_va_args) {
|
||||
if (arg->tok->kind == TK_EOF) {
|
||||
@ -490,14 +498,11 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(tok, "##")) {
|
||||
if (EQUAL(tok, "##")) {
|
||||
if (cur == &head)
|
||||
error_tok(tok, "'##' cannot appear at start of macro expansion");
|
||||
|
||||
if (tok->next->kind == TK_EOF)
|
||||
error_tok(tok, "'##' cannot appear at end of macro expansion");
|
||||
|
||||
MacroArg *arg = find_arg(args, tok->next);
|
||||
if (arg) {
|
||||
if (arg->tok->kind != TK_EOF) {
|
||||
@ -508,17 +513,13 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
*cur = *paste(cur, tok->next);
|
||||
tok = tok->next->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
MacroArg *arg = find_arg(args, tok);
|
||||
|
||||
if (arg && equal(tok->next, "##")) {
|
||||
if (arg && EQUAL(tok->next, "##")) {
|
||||
Token *rhs = tok->next->next;
|
||||
|
||||
if (arg->tok->kind == TK_EOF) {
|
||||
MacroArg *arg2 = find_arg(args, rhs);
|
||||
if (arg2) {
|
||||
@ -530,16 +531,14 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
tok = rhs->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
|
||||
cur = cur->next = copy_token(t);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If __VA_ARG__ is empty, __VA_OPT__(x) is expanded to the
|
||||
// empty token list. Otherwise, __VA_OPT__(x) is expanded to x.
|
||||
if (equal(tok, "__VA_OPT__") && equal(tok->next, "(")) {
|
||||
if (EQUAL(tok, "__VA_OPT__") && EQUAL(tok->next, "(")) {
|
||||
MacroArg *arg = read_macro_arg_one(&tok, tok->next->next, true);
|
||||
if (has_varargs(args))
|
||||
for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
|
||||
@ -547,7 +546,6 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
tok = skip(tok, ")");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle a macro token. Macro arguments are completely macro-expanded
|
||||
// before they are substituted into a macro body.
|
||||
if (arg) {
|
||||
@ -558,13 +556,11 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle a non-macro token.
|
||||
cur = cur->next = copy_token(tok);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->next = tok;
|
||||
return head.next;
|
||||
}
|
||||
@ -585,7 +581,9 @@ static bool expand_macro(Token **rest, Token *tok) {
|
||||
if (m->is_objlike) {
|
||||
Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
|
||||
Token *body = add_hideset(m->body, hs);
|
||||
for (Token *t = body; t->kind != TK_EOF; t = t->next) t->origin = tok;
|
||||
for (Token *t = body; t->kind != TK_EOF; t = t->next) {
|
||||
t->origin = tok;
|
||||
}
|
||||
*rest = append(body, tok->next);
|
||||
(*rest)->at_bol = tok->at_bol;
|
||||
(*rest)->has_space = tok->has_space;
|
||||
@ -593,7 +591,7 @@ static bool expand_macro(Token **rest, Token *tok) {
|
||||
}
|
||||
// If a funclike macro token is not followed by an argument list,
|
||||
// treat it as a normal identifier.
|
||||
if (!equal(tok->next, "(")) return false;
|
||||
if (!EQUAL(tok->next, "(")) return false;
|
||||
// Function-like macro application
|
||||
Token *macro_token = tok;
|
||||
MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name);
|
||||
@ -614,12 +612,6 @@ static bool expand_macro(Token **rest, Token *tok) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if a given file exists.
|
||||
bool file_exists(char *path) {
|
||||
struct stat st;
|
||||
return !stat(path, &st);
|
||||
}
|
||||
|
||||
char *search_include_paths(char *filename) {
|
||||
if (filename[0] == '/') return filename;
|
||||
static HashMap cache;
|
||||
@ -627,8 +619,8 @@ char *search_include_paths(char *filename) {
|
||||
if (cached) return cached;
|
||||
// Search a file from the include paths.
|
||||
for (int i = 0; i < include_paths.len; i++) {
|
||||
char *path = format("%s/%s", include_paths.data[i], filename);
|
||||
if (!file_exists(path)) continue;
|
||||
char *path = xasprintf("%s/%s", include_paths.data[i], filename);
|
||||
if (!fileexists(path)) continue;
|
||||
hashmap_put(&cache, filename, path);
|
||||
include_next_idx = i + 1;
|
||||
return path;
|
||||
@ -639,8 +631,8 @@ char *search_include_paths(char *filename) {
|
||||
static char *search_include_next(char *filename) {
|
||||
for (; include_next_idx < include_paths.len; include_next_idx++) {
|
||||
char *path =
|
||||
format("%s/%s", include_paths.data[include_next_idx], filename);
|
||||
if (file_exists(path)) return path;
|
||||
xasprintf("%s/%s", include_paths.data[include_next_idx], filename);
|
||||
if (fileexists(path)) return path;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -659,12 +651,12 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {
|
||||
return strndup(tok->loc + 1, tok->len - 2);
|
||||
}
|
||||
// Pattern 2: #include <foo.h>
|
||||
if (equal(tok, "<")) {
|
||||
if (EQUAL(tok, "<")) {
|
||||
// Reconstruct a filename from a sequence of tokens between
|
||||
// "<" and ">".
|
||||
Token *start = tok;
|
||||
// Find closing ">".
|
||||
for (; !equal(tok, ">"); tok = tok->next)
|
||||
for (; !EQUAL(tok, ">"); tok = tok->next)
|
||||
if (tok->at_bol || tok->kind == TK_EOF) error_tok(tok, "expected '>'");
|
||||
*is_dquote = false;
|
||||
*rest = skip_line(tok->next);
|
||||
@ -688,13 +680,13 @@ static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {
|
||||
// #endif
|
||||
static char *detect_include_guard(Token *tok) {
|
||||
// Detect the first two lines.
|
||||
if (!is_hash(tok) || !equal(tok->next, "ifndef")) return NULL;
|
||||
if (!is_hash(tok) || !EQUAL(tok->next, "ifndef")) return NULL;
|
||||
tok = tok->next->next;
|
||||
if (tok->kind != TK_IDENT) return NULL;
|
||||
char *macro = strndup(tok->loc, tok->len);
|
||||
tok = tok->next;
|
||||
if (!is_hash(tok) || !equal(tok->next, "define") ||
|
||||
!equal(tok->next->next, macro))
|
||||
if (!is_hash(tok) || !EQUAL(tok->next, "define") ||
|
||||
!EQUAL(tok->next->next, macro))
|
||||
return NULL;
|
||||
// Read until the end of the file.
|
||||
while (tok->kind != TK_EOF) {
|
||||
@ -702,9 +694,9 @@ static char *detect_include_guard(Token *tok) {
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
if (equal(tok->next, "endif") && tok->next->next->kind == TK_EOF)
|
||||
if (EQUAL(tok->next, "endif") && tok->next->next->kind == TK_EOF)
|
||||
return macro;
|
||||
if (equal(tok, "if") || equal(tok, "ifdef") || equal(tok, "ifndef"))
|
||||
if (EQUAL(tok, "if") || EQUAL(tok, "ifdef") || EQUAL(tok, "ifndef"))
|
||||
tok = skip_cond_incl(tok->next);
|
||||
else
|
||||
tok = tok->next;
|
||||
@ -732,14 +724,11 @@ static Token *include_file(Token *tok, char *path) {
|
||||
static void read_line_marker(Token **rest, Token *tok) {
|
||||
Token *start = tok;
|
||||
tok = preprocess(copy_line(rest, tok));
|
||||
|
||||
if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)
|
||||
error_tok(tok, "invalid line marker");
|
||||
start->file->line_delta = tok->val - start->line_no;
|
||||
|
||||
tok = tok->next;
|
||||
if (tok->kind == TK_EOF) return;
|
||||
|
||||
if (tok->kind != TK_STR) error_tok(tok, "filename expected");
|
||||
start->file->display_name = tok->str;
|
||||
}
|
||||
@ -749,11 +738,9 @@ static void read_line_marker(Token **rest, Token *tok) {
|
||||
static Token *preprocess2(Token *tok) {
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
|
||||
while (tok->kind != TK_EOF) {
|
||||
// If it is a macro, expand it.
|
||||
if (expand_macro(&tok, tok)) continue;
|
||||
|
||||
// Pass through if it is not a "#".
|
||||
if (!is_hash(tok)) {
|
||||
tok->line_delta = tok->file->line_delta;
|
||||
@ -762,42 +749,35 @@ static Token *preprocess2(Token *tok) {
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Token *start = tok;
|
||||
tok = tok->next;
|
||||
|
||||
if (equal(tok, "include")) {
|
||||
if (EQUAL(tok, "include")) {
|
||||
bool is_dquote;
|
||||
char *filename = read_include_filename(&tok, tok->next, &is_dquote);
|
||||
|
||||
if (filename[0] != '/' && is_dquote) {
|
||||
char *path =
|
||||
format("%s/%s", dirname(strdup(start->file->name)), filename);
|
||||
if (file_exists(path)) {
|
||||
xasprintf("%s/%s", dirname(strdup(start->file->name)), filename);
|
||||
if (fileexists(path)) {
|
||||
tok = include_file(tok, path);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
char *path = search_include_paths(filename);
|
||||
tok = include_file(tok, path ? path : filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "include_next")) {
|
||||
if (EQUAL(tok, "include_next")) {
|
||||
bool ignore;
|
||||
char *filename = read_include_filename(&tok, tok->next, &ignore);
|
||||
char *path = search_include_next(filename);
|
||||
tok = include_file(tok, path ? path : filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "define")) {
|
||||
if (EQUAL(tok, "define")) {
|
||||
read_macro_definition(&tok, tok->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "undef")) {
|
||||
if (EQUAL(tok, "undef")) {
|
||||
tok = tok->next;
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "macro name must be an identifier");
|
||||
@ -805,90 +785,74 @@ static Token *preprocess2(Token *tok) {
|
||||
tok = skip_line(tok->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "if")) {
|
||||
if (EQUAL(tok, "if")) {
|
||||
long val = eval_const_expr(&tok, tok);
|
||||
push_cond_incl(start, val);
|
||||
if (!val) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "ifdef")) {
|
||||
if (EQUAL(tok, "ifdef")) {
|
||||
bool defined = find_macro(tok->next);
|
||||
push_cond_incl(tok, defined);
|
||||
tok = skip_line(tok->next->next);
|
||||
if (!defined) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "ifndef")) {
|
||||
if (EQUAL(tok, "ifndef")) {
|
||||
bool defined = find_macro(tok->next);
|
||||
push_cond_incl(tok, !defined);
|
||||
tok = skip_line(tok->next->next);
|
||||
if (defined) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "elif")) {
|
||||
if (EQUAL(tok, "elif")) {
|
||||
if (!cond_incl || cond_incl->ctx == IN_ELSE)
|
||||
error_tok(start, "stray #elif");
|
||||
cond_incl->ctx = IN_ELIF;
|
||||
|
||||
if (!cond_incl->included && eval_const_expr(&tok, tok))
|
||||
cond_incl->included = true;
|
||||
else
|
||||
tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "else")) {
|
||||
if (EQUAL(tok, "else")) {
|
||||
if (!cond_incl || cond_incl->ctx == IN_ELSE)
|
||||
error_tok(start, "stray #else");
|
||||
cond_incl->ctx = IN_ELSE;
|
||||
tok = skip_line(tok->next);
|
||||
|
||||
if (cond_incl->included) tok = skip_cond_incl(tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "endif")) {
|
||||
if (EQUAL(tok, "endif")) {
|
||||
if (!cond_incl) error_tok(start, "stray #endif");
|
||||
cond_incl = cond_incl->next;
|
||||
tok = skip_line(tok->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "line")) {
|
||||
if (EQUAL(tok, "line")) {
|
||||
read_line_marker(&tok, tok->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok->kind == TK_PP_NUM) {
|
||||
read_line_marker(&tok, tok);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "pragma") && equal(tok->next, "once")) {
|
||||
if (EQUAL(tok, "pragma") && EQUAL(tok->next, "once")) {
|
||||
hashmap_put(&pragma_once, tok->file->name, (void *)1);
|
||||
tok = skip_line(tok->next->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "pragma")) {
|
||||
if (EQUAL(tok, "pragma")) {
|
||||
do {
|
||||
tok = tok->next;
|
||||
} while (!tok->at_bol);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "error")) error_tok(tok, "error");
|
||||
|
||||
if (EQUAL(tok, "error")) error_tok(tok, "error");
|
||||
// `#`-only line is legal. It's called a null directive.
|
||||
if (tok->at_bol) continue;
|
||||
|
||||
error_tok(tok, "invalid preprocessor directive");
|
||||
}
|
||||
|
||||
cur->next = tok;
|
||||
return head.next;
|
||||
}
|
||||
@ -944,7 +908,7 @@ static Token *base_file_macro(Token *tmpl) {
|
||||
|
||||
// __DATE__ is expanded to the current date, e.g. "May 17 2020".
|
||||
static char *format_date(struct tm *tm) {
|
||||
static char mon[][4] = {
|
||||
_Alignas(char) static char mon[][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
};
|
||||
@ -962,48 +926,320 @@ static char *format_time(struct tm *tm) {
|
||||
}
|
||||
|
||||
void init_macros(void) {
|
||||
// Define predefined macros
|
||||
define_macro("_LP64", "1");
|
||||
define_macro("__STRICT_ANSI__", "1");
|
||||
define_macro("__C99_MACRO_WITH_VA_ARGS", "1");
|
||||
define_macro("__ELF__", "1");
|
||||
define_macro("__LP64__", "1");
|
||||
define_macro("__SIZEOF_DOUBLE__", "8");
|
||||
define_macro("__SIZEOF_FLOAT__", "4");
|
||||
define_macro("__SIZEOF_INT__", "4");
|
||||
define_macro("__SIZEOF_LONG_DOUBLE__", "8");
|
||||
define_macro("__SIZEOF_LONG_LONG__", "8");
|
||||
define_macro("__SIZEOF_LONG__", "8");
|
||||
define_macro("__SIZEOF_POINTER__", "8");
|
||||
define_macro("__SIZEOF_PTRDIFF_T__", "8");
|
||||
define_macro("__SIZEOF_SHORT__", "2");
|
||||
define_macro("__SIZEOF_SIZE_T__", "8");
|
||||
define_macro("__SIZE_TYPE__", "unsigned long");
|
||||
define_macro("__STDC_HOSTED__", "1");
|
||||
define_macro("__STDC_NO_COMPLEX__", "1");
|
||||
define_macro("__STDC_UTF_16__", "1");
|
||||
define_macro("__STDC_UTF_32__", "1");
|
||||
define_macro("__STDC_VERSION__", "201112L");
|
||||
define_macro("__STDC__", "1");
|
||||
define_macro("__USER_LABEL_PREFIX__", "");
|
||||
define_macro("__alignof__", "_Alignof");
|
||||
define_macro("__amd64", "1");
|
||||
define_macro("__amd64__", "1");
|
||||
define_macro("__chibicc__", "1");
|
||||
define_macro("__const__", "const");
|
||||
define_macro("__gnu_linux__", "1");
|
||||
define_macro("__inline__", "inline");
|
||||
define_macro("__linux", "1");
|
||||
define_macro("__linux__", "1");
|
||||
define_macro("__signed__", "signed");
|
||||
define_macro("__typeof__", "typeof");
|
||||
define_macro("__unix", "1");
|
||||
define_macro("__unix__", "1");
|
||||
define_macro("__volatile__", "volatile");
|
||||
define_macro("__x86_64", "1");
|
||||
define_macro("__x86_64__", "1");
|
||||
define_macro("linux", "1");
|
||||
define_macro("unix", "1");
|
||||
char *val, *name = "\
|
||||
__chibicc__\000\
|
||||
1\000\
|
||||
__cosmopolitan__\000\
|
||||
1\000\
|
||||
__GNUC__\000\
|
||||
6\000\
|
||||
__GNUC_MINOR__\000\
|
||||
6\000\
|
||||
__GNUC_PATCHLEVEL__\000\
|
||||
6\000\
|
||||
__NO_INLINE__\000\
|
||||
16\000\
|
||||
__BIGGEST_ALIGNMENT__\000\
|
||||
16\000\
|
||||
__C99_MACRO_WITH_VA_ARGS\000\
|
||||
1\000\
|
||||
__GCC_ASM_FLAG_OUTPUTS__\000\
|
||||
1\000\
|
||||
__ELF__\000\
|
||||
1\000\
|
||||
__LP64__\000\
|
||||
1\000\
|
||||
_LP64\000\
|
||||
1\000\
|
||||
__STDC__\000\
|
||||
1\000\
|
||||
__STDC_HOSTED__\000\
|
||||
1\000\
|
||||
__STDC_NO_COMPLEX__\000\
|
||||
1\000\
|
||||
__STDC_UTF_16__\000\
|
||||
1\000\
|
||||
__STDC_UTF_32__\000\
|
||||
1\000\
|
||||
__STDC_VERSION__\000\
|
||||
201112L\000\
|
||||
__USER_LABEL_PREFIX__\000\
|
||||
\000\
|
||||
__alignof__\000\
|
||||
_Alignof\000\
|
||||
__const__\000\
|
||||
const\000\
|
||||
__inline__\000\
|
||||
inline\000\
|
||||
__signed__\000\
|
||||
signed\000\
|
||||
__typeof__\000\
|
||||
typeof\000\
|
||||
__volatile__\000\
|
||||
volatile\000\
|
||||
__unix\000\
|
||||
1\000\
|
||||
__unix__\000\
|
||||
1\000\
|
||||
__linux\000\
|
||||
1\000\
|
||||
__linux__\000\
|
||||
1\000\
|
||||
__gnu_linux__\000\
|
||||
1\000\
|
||||
__BYTE_ORDER__\000\
|
||||
1234\000\
|
||||
__FLOAT_WORD_ORDER__\000\
|
||||
1234\000\
|
||||
__ORDER_BIG_ENDIAN__\000\
|
||||
4321\000\
|
||||
__ORDER_LITTLE_ENDIAN__\000\
|
||||
1234\000\
|
||||
__INT8_MAX__\000\
|
||||
0x7f\000\
|
||||
__UINT8_MAX__\000\
|
||||
0xff\000\
|
||||
__INT16_MAX__\000\
|
||||
0x7fff\000\
|
||||
__UINT16_MAX__\000\
|
||||
0xffff\000\
|
||||
__SHRT_MAX__\000\
|
||||
0x7fff\000\
|
||||
__INT_MAX__\000\
|
||||
0x7fffffff\000\
|
||||
__INT32_MAX__\000\
|
||||
0x7fffffff\000\
|
||||
__UINT32_MAX__\000\
|
||||
0xffffffffu\000\
|
||||
__INT64_MAX__\000\
|
||||
0x7fffffffffffffffl\000\
|
||||
__UINT64_MAX__\000\
|
||||
0xfffffffffffffffful\000\
|
||||
__SIZE_MAX__\000\
|
||||
0xfffffffffffffffful\000\
|
||||
__INTPTR_MAX__\000\
|
||||
0x7fffffffffffffffl\000\
|
||||
__UINTPTR_MAX__\000\
|
||||
0xfffffffffffffffful\000\
|
||||
__WINT_MAX__\000\
|
||||
0xffffffffu\000\
|
||||
__CHAR_BIT__\000\
|
||||
8\000\
|
||||
__SIZEOF_SHORT__\000\
|
||||
2\000\
|
||||
__SIZEOF_INT__\000\
|
||||
4\000\
|
||||
__SIZEOF_LONG__\000\
|
||||
8\000\
|
||||
__SIZEOF_LONG_LONG__\000\
|
||||
8\000\
|
||||
__SIZEOF_POINTER__\000\
|
||||
8\000\
|
||||
__SIZEOF_PTRDIFF_T__\000\
|
||||
8\000\
|
||||
__SIZEOF_SIZE_T__\000\
|
||||
8\000\
|
||||
__SIZEOF_WCHAR_T__\000\
|
||||
4\000\
|
||||
__SIZEOF_WINT_T__\000\
|
||||
4\000\
|
||||
__SIZEOF_FLOAT__\000\
|
||||
4\000\
|
||||
__SIZEOF_FLOAT128__\000\
|
||||
16\000\
|
||||
__SIZEOF_DOUBLE__\000\
|
||||
8\000\
|
||||
__SIZEOF_FLOAT80__\000\
|
||||
16\000\
|
||||
__SIZEOF_LONG_DOUBLE__\000\
|
||||
16\000\
|
||||
__INT8_TYPE__\000\
|
||||
signed char\000\
|
||||
__UINT8_TYPE__\000\
|
||||
unsigned char\000\
|
||||
__INT16_TYPE__\000\
|
||||
short int\000\
|
||||
__UINT16_TYPE__\000\
|
||||
short unsigned int\000\
|
||||
__INT32_TYPE__\000\
|
||||
int\000\
|
||||
__UINT32_TYPE__\000\
|
||||
unsigned int\000\
|
||||
__INT64_TYPE__\000\
|
||||
long int\000\
|
||||
__UINT64_TYPE__\000\
|
||||
long unsigned int\000\
|
||||
__INTPTR_TYPE__\000\
|
||||
long int\000\
|
||||
__UINTPTR_TYPE__\000\
|
||||
long unsigned int\000\
|
||||
__PTRDIFF_TYPE__\000\
|
||||
long int\000\
|
||||
__SIZE_TYPE__\000\
|
||||
long unsigned int\000\
|
||||
__WCHAR_TYPE__\000\
|
||||
int\000\
|
||||
__CHAR16_TYPE__\000\
|
||||
short unsigned int\000\
|
||||
__CHAR32_TYPE__\000\
|
||||
unsigned int\000\
|
||||
__WINT_TYPE__\000\
|
||||
unsigned int\000\
|
||||
__CHAR16_TYPE__\000\
|
||||
short unsigned int\000\
|
||||
__WCHAR_TYPE__\000\
|
||||
int\000\
|
||||
__CHAR32_TYPE__\000\
|
||||
unsigned int\000\
|
||||
__INT_LEAST8_TYPE__\000\
|
||||
signed char\000\
|
||||
__UINT_LEAST8_TYPE__\000\
|
||||
unsigned char\000\
|
||||
__INT_LEAST16_TYPE__\000\
|
||||
int\000\
|
||||
__UINT_LEAST16_TYPE__\000\
|
||||
unsigned short\000\
|
||||
__INT_LEAST32_TYPE__\000\
|
||||
short\000\
|
||||
__UINT_LEAST32_TYPE__\000\
|
||||
unsigned int\000\
|
||||
__INT_LEAST64_TYPE__\000\
|
||||
long\000\
|
||||
__UINT_LEAST64_TYPE__\000\
|
||||
unsigned long\000\
|
||||
__INT_FAST8_TYPE__\000\
|
||||
signed char\000\
|
||||
__UINT_FAST8_TYPE__\000\
|
||||
unsigned char\000\
|
||||
__INT_FAST16_TYPE__\000\
|
||||
int\000\
|
||||
__UINT_FAST16_TYPE__\000\
|
||||
unsigned\000\
|
||||
__INT_FAST32_TYPE__\000\
|
||||
int\000\
|
||||
__UINT_FAST32_TYPE__\000\
|
||||
unsigned\000\
|
||||
__INT_FAST64_TYPE__\000\
|
||||
long\000\
|
||||
__UINT_FAST64_TYPE__\000\
|
||||
unsigned long\000\
|
||||
__DBL_DECIMAL_DIG__\000\
|
||||
17\000\
|
||||
__DBL_DENORM_MIN__\000\
|
||||
((double)4.94065645841246544176568792868221372e-324L)\000\
|
||||
__DBL_DIG__\000\
|
||||
15\000\
|
||||
__DBL_EPSILON__\000\
|
||||
((double)2.22044604925031308084726333618164062e-16L)\000\
|
||||
__DBL_HAS_DENORM__\000\
|
||||
1\000\
|
||||
__DBL_HAS_INFINITY__\000\
|
||||
1\000\
|
||||
__DBL_HAS_QUIET_NAN__\000\
|
||||
1\000\
|
||||
__DBL_MANT_DIG__\000\
|
||||
53\000\
|
||||
__DBL_MAX_10_EXP__\000\
|
||||
308\000\
|
||||
__DBL_MAX_EXP__\000\
|
||||
1024\000\
|
||||
__DBL_MAX__\000\
|
||||
((double)1.79769313486231570814527423731704357e+308L)\000\
|
||||
__DBL_MIN_10_EXP__\000\
|
||||
(-307)\000\
|
||||
__DBL_MIN_EXP__\000\
|
||||
(-1021)\000\
|
||||
__DBL_MIN__\000\
|
||||
((double)2.22507385850720138309023271733240406e-308L)\000\
|
||||
__FLT_DECIMAL_DIG__\000\
|
||||
9\000\
|
||||
__FLT_DENORM_MIN__\000\
|
||||
1.40129846432481707092372958328991613e-45F\000\
|
||||
__FLT_DIG__\000\
|
||||
6\000\
|
||||
__FLT_EPSILON__\000\
|
||||
1.19209289550781250000000000000000000e-7F\000\
|
||||
__FLT_EVAL_METHOD_TS_18661_3__\000\
|
||||
0\000\
|
||||
__FLT_EVAL_METHOD__\000\
|
||||
0\000\
|
||||
__FLT_HAS_DENORM__\000\
|
||||
1\000\
|
||||
__FLT_HAS_INFINITY__\000\
|
||||
1\000\
|
||||
__FLT_HAS_QUIET_NAN__\000\
|
||||
1\000\
|
||||
__FLT_MANT_DIG__\000\
|
||||
24\000\
|
||||
__FLT_MAX_10_EXP__\000\
|
||||
38\000\
|
||||
__FLT_MAX_EXP__\000\
|
||||
128\000\
|
||||
__FLT_MAX__\000\
|
||||
3.40282346638528859811704183484516925e+38F\000\
|
||||
__FLT_MIN_10_EXP__\000\
|
||||
(-37)\000\
|
||||
__FLT_MIN_EXP__\000\
|
||||
(-125)\000\
|
||||
__FLT_MIN__\000\
|
||||
1.17549435082228750796873653722224568e-38F\000\
|
||||
__FLT_RADIX__\000\
|
||||
2\000\
|
||||
__LDBL_DECIMAL_DIG__\000\
|
||||
21\000\
|
||||
__LDBL_DENORM_MIN__\000\
|
||||
3.64519953188247460252840593361941982e-4951L\000\
|
||||
__LDBL_DIG__\000\
|
||||
18\000\
|
||||
__LDBL_EPSILON__\000\
|
||||
1.08420217248550443400745280086994171e-19L\000\
|
||||
__LDBL_HAS_DENORM__\000\
|
||||
1\000\
|
||||
__LDBL_HAS_INFINITY__\000\
|
||||
1\000\
|
||||
__LDBL_HAS_QUIET_NAN__\000\
|
||||
1\000\
|
||||
__LDBL_MANT_DIG__\000\
|
||||
64\000\
|
||||
__LDBL_MAX_10_EXP__\000\
|
||||
4932\000\
|
||||
__LDBL_MAX_EXP__\000\
|
||||
16384\000\
|
||||
__LDBL_MAX__\000\
|
||||
1.18973149535723176502126385303097021e+4932L\000\
|
||||
__LDBL_MIN_10_EXP__\000\
|
||||
(-4931)\000\
|
||||
__LDBL_MIN_EXP__\000\
|
||||
(-16381)\000\
|
||||
__LDBL_MIN__\000\
|
||||
3.36210314311209350626267781732175260e-4932L\000\
|
||||
__x86_64\000\
|
||||
1\000\
|
||||
__x86_64__\000\
|
||||
1\000\
|
||||
__amd64\000\
|
||||
1\000\
|
||||
__amd64__\000\
|
||||
1\000\
|
||||
__MMX__\000\
|
||||
1\000\
|
||||
__SSE__\000\
|
||||
1\000\
|
||||
__SSE_MATH__\000\
|
||||
1\000\
|
||||
__SSE2__\000\
|
||||
1\000\
|
||||
__SSE2_MATH__\000\
|
||||
1\000\
|
||||
\000";
|
||||
do {
|
||||
val = name + strlen(name) + 1;
|
||||
define_macro(name, val);
|
||||
name = val + strlen(val) + 1;
|
||||
} while (*name);
|
||||
#ifdef __SSE3__
|
||||
define_macro("__SSE3__", "1");
|
||||
#endif
|
||||
add_builtin("__FILE__", file_macro);
|
||||
add_builtin("__LINE__", line_macro);
|
||||
add_builtin("__COUNTER__", counter_macro);
|
||||
@ -1015,14 +1251,6 @@ void init_macros(void) {
|
||||
define_macro("__TIME__", format_time(tm));
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
STR_NONE,
|
||||
STR_UTF8,
|
||||
STR_UTF16,
|
||||
STR_UTF32,
|
||||
STR_WIDE,
|
||||
} StringKind;
|
||||
|
||||
static StringKind getStringKind(Token *tok) {
|
||||
if (!strcmp(tok->loc, "u8")) return STR_UTF8;
|
||||
switch (tok->loc[0]) {
|
||||
@ -1090,10 +1318,13 @@ static void join_adjacent_string_literals(Token *tok) {
|
||||
// Entry point function of the preprocessor.
|
||||
Token *preprocess(Token *tok) {
|
||||
tok = preprocess2(tok);
|
||||
if (cond_incl)
|
||||
if (cond_incl) {
|
||||
error_tok(cond_incl->tok, "unterminated conditional directive");
|
||||
}
|
||||
convert_pp_tokens(tok);
|
||||
join_adjacent_string_literals(tok);
|
||||
for (Token *t = tok; t; t = t->next) t->line_no += t->line_delta;
|
||||
for (Token *t = tok; t; t = t->next) {
|
||||
t->line_no += t->line_delta;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
2
third_party/chibicc/strarray.c
vendored
2
third_party/chibicc/strarray.c
vendored
@ -5,12 +5,10 @@ void strarray_push(StringArray *arr, char *s) {
|
||||
arr->data = calloc(8, sizeof(char *));
|
||||
arr->capacity = 8;
|
||||
}
|
||||
|
||||
if (arr->capacity == arr->len) {
|
||||
arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
|
||||
arr->capacity *= 2;
|
||||
for (int i = arr->len; i < arr->capacity; i++) arr->data[i] = NULL;
|
||||
}
|
||||
|
||||
arr->data[arr->len++] = s;
|
||||
}
|
||||
|
||||
103
third_party/chibicc/test/alignof_test.c
vendored
Normal file
103
third_party/chibicc/test/alignof_test.c
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int _Alignas(512) g1;
|
||||
int _Alignas(512) g2;
|
||||
char g3;
|
||||
int g4;
|
||||
long g5;
|
||||
char g6;
|
||||
|
||||
int main() {
|
||||
ASSERT(1, _Alignof(char));
|
||||
ASSERT(2, _Alignof(short));
|
||||
ASSERT(4, _Alignof(int));
|
||||
ASSERT(8, _Alignof(long));
|
||||
ASSERT(8, _Alignof(long long));
|
||||
ASSERT(1, _Alignof(char[3]));
|
||||
ASSERT(4, _Alignof(int[3]));
|
||||
ASSERT(1, _Alignof(struct {
|
||||
char a;
|
||||
char b;
|
||||
}[2]));
|
||||
ASSERT(8, _Alignof(struct {
|
||||
char a;
|
||||
long b;
|
||||
}[2]));
|
||||
|
||||
ASSERT(1, ({
|
||||
_Alignas(char) char x, y;
|
||||
&y - &x;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
_Alignas(long) char x, y;
|
||||
&y - &x;
|
||||
}));
|
||||
ASSERT(32, ({
|
||||
_Alignas(32) char x, y;
|
||||
&y - &x;
|
||||
}));
|
||||
ASSERT(32, ({
|
||||
_Alignas(32) int *x, *y;
|
||||
((char *)&y) - ((char *)&x);
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
struct {
|
||||
_Alignas(16) char x, y;
|
||||
} a;
|
||||
&a.y - &a.x;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct T {
|
||||
_Alignas(8) char a;
|
||||
};
|
||||
_Alignof(struct T);
|
||||
}));
|
||||
|
||||
ASSERT(0, (long)(char *)&g1 % 512);
|
||||
ASSERT(0, (long)(char *)&g2 % 512);
|
||||
ASSERT(0, (long)(char *)&g4 % 4);
|
||||
ASSERT(0, (long)(char *)&g5 % 8);
|
||||
|
||||
ASSERT(1, ({
|
||||
char x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x;
|
||||
_Alignof x;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
_Alignof x;
|
||||
}));
|
||||
|
||||
ASSERT(1, _Alignof(char) << 31 >> 31);
|
||||
ASSERT(1, _Alignof(char) << 63 >> 63);
|
||||
ASSERT(1, ({
|
||||
char x;
|
||||
_Alignof(x) << 63 >> 63;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
char x[16];
|
||||
(unsigned long)&x % 16;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[17];
|
||||
(unsigned long)&x % 16;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[100];
|
||||
(unsigned long)&x % 16;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[101];
|
||||
(unsigned long)&x % 16;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
third_party/chibicc/test/alloca_test.c
vendored
Normal file
29
third_party/chibicc/test/alloca_test.c
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
void *fn(int x, void *p, int y) {
|
||||
return p;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int i = 0;
|
||||
|
||||
char *p1 = alloca(16);
|
||||
char *p2 = alloca(16);
|
||||
char *p3 = 1 + (char *)alloca(3) + 1;
|
||||
p3 -= 2;
|
||||
char *p4 = fn(1, alloca(16), 3);
|
||||
|
||||
ASSERT(16, p1 - p2);
|
||||
ASSERT(16, p2 - p3);
|
||||
ASSERT(16, p3 - p4);
|
||||
|
||||
memcpy(p1, "0123456789abcdef", 16);
|
||||
memcpy(p2, "ghijklmnopqrstuv", 16);
|
||||
memcpy(p3, "wxy", 3);
|
||||
|
||||
ASSERT(0, memcmp(p1, "0123456789abcdef", 16));
|
||||
ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16));
|
||||
ASSERT(0, memcmp(p3, "wxy", 3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
341
third_party/chibicc/test/arith_test.c
vendored
Normal file
341
third_party/chibicc/test/arith_test.c
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(0, 0);
|
||||
ASSERT(42, 42);
|
||||
ASSERT(21, 5 + 20 - 4);
|
||||
ASSERT(41, 12 + 34 - 5);
|
||||
ASSERT(47, 5 + 6 * 7);
|
||||
ASSERT(15, 5 * (9 - 6));
|
||||
ASSERT(4, (3 + 5) / 2);
|
||||
ASSERT(10, -10 + 20);
|
||||
|
||||
ASSERT(0, 0 == 1);
|
||||
ASSERT(1, 42 == 42);
|
||||
ASSERT(1, 0 != 1);
|
||||
ASSERT(0, 42 != 42);
|
||||
|
||||
ASSERT(1, 0 < 1);
|
||||
ASSERT(0, 1 < 1);
|
||||
ASSERT(0, 2 < 1);
|
||||
ASSERT(1, 0 <= 1);
|
||||
ASSERT(1, 1 <= 1);
|
||||
ASSERT(0, 2 <= 1);
|
||||
|
||||
ASSERT(1, 1 > 0);
|
||||
ASSERT(0, 1 > 1);
|
||||
ASSERT(0, 1 > 2);
|
||||
ASSERT(1, 1 >= 0);
|
||||
ASSERT(1, 1 >= 1);
|
||||
ASSERT(0, 1 >= 2);
|
||||
|
||||
ASSERT(0, 1073741824 * 100 / 100);
|
||||
|
||||
ASSERT(7, ({
|
||||
int i = 2;
|
||||
i += 5;
|
||||
i;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int i = 2;
|
||||
i += 5;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 5;
|
||||
i -= 2;
|
||||
i;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 5;
|
||||
i -= 2;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int i = 3;
|
||||
i *= 2;
|
||||
i;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int i = 3;
|
||||
i *= 2;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 6;
|
||||
i /= 2;
|
||||
i;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 6;
|
||||
i /= 2;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int i = 2;
|
||||
++i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
++*p;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
--*p;
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int i = 2;
|
||||
i++;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int i = 2;
|
||||
i--;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 2;
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int i = 2;
|
||||
i--;
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
*p++;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
*p--;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p++)--;
|
||||
a[0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*(p--))--;
|
||||
a[1];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p)--;
|
||||
a[2];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p)--;
|
||||
p++;
|
||||
*p;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p++)--;
|
||||
a[0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p++)--;
|
||||
a[1];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p++)--;
|
||||
a[2];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int a[3];
|
||||
a[0] = 0;
|
||||
a[1] = 1;
|
||||
a[2] = 2;
|
||||
int *p = a + 1;
|
||||
(*p++)--;
|
||||
*p;
|
||||
}));
|
||||
|
||||
ASSERT(0, !1);
|
||||
ASSERT(0, !2);
|
||||
ASSERT(1, !0);
|
||||
ASSERT(1, !(char)0);
|
||||
ASSERT(0, !(long)3);
|
||||
ASSERT(4, sizeof(!(char)0));
|
||||
ASSERT(4, sizeof(!(long)0));
|
||||
|
||||
ASSERT(-1, ~0);
|
||||
ASSERT(0, ~-1);
|
||||
|
||||
ASSERT(5, 17 % 6);
|
||||
ASSERT(5, ((long)17) % 6);
|
||||
ASSERT(2, ({
|
||||
int i = 10;
|
||||
i %= 4;
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
long i = 10;
|
||||
i %= 4;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(0, 0 & 1);
|
||||
ASSERT(1, 3 & 1);
|
||||
ASSERT(3, 7 & 3);
|
||||
ASSERT(10, -1 & 10);
|
||||
|
||||
ASSERT(1, 0 | 1);
|
||||
ASSERT(0b10011, 0b10000 | 0b00011);
|
||||
|
||||
ASSERT(0, 0 ^ 0);
|
||||
ASSERT(0, 0b1111 ^ 0b1111);
|
||||
ASSERT(0b110100, 0b111000 ^ 0b001100);
|
||||
|
||||
ASSERT(2, ({
|
||||
int i = 6;
|
||||
i &= 3;
|
||||
i;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int i = 6;
|
||||
i |= 3;
|
||||
i;
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
int i = 15;
|
||||
i ^= 5;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(1, 1 << 0);
|
||||
ASSERT(8, 1 << 3);
|
||||
ASSERT(10, 5 << 1);
|
||||
ASSERT(2, 5 >> 1);
|
||||
ASSERT(-1, -1 >> 1);
|
||||
ASSERT(1, ({
|
||||
int i = 1;
|
||||
i <<= 0;
|
||||
i;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int i = 1;
|
||||
i <<= 3;
|
||||
i;
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
int i = 5;
|
||||
i <<= 1;
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int i = 5;
|
||||
i >>= 1;
|
||||
i;
|
||||
}));
|
||||
ASSERT(-1, -1);
|
||||
ASSERT(-1, ({
|
||||
int i = -1;
|
||||
i;
|
||||
}));
|
||||
ASSERT(-1, ({
|
||||
int i = -1;
|
||||
i >>= 1;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(2, 0 ? 1 : 2);
|
||||
ASSERT(1, 1 ? 1 : 2);
|
||||
ASSERT(-1, 0 ? -2 : -1);
|
||||
ASSERT(-2, 1 ? -2 : -1);
|
||||
ASSERT(4, sizeof(0 ? 1 : 2));
|
||||
ASSERT(8, sizeof(0 ? (long)1 : (long)2));
|
||||
ASSERT(-1, 0 ? (long)-2 : -1);
|
||||
ASSERT(-1, 0 ? -2 : (long)-1);
|
||||
ASSERT(-2, 1 ? (long)-2 : -1);
|
||||
ASSERT(-2, 1 ? -2 : (long)-1);
|
||||
|
||||
1 ? -2 : (void)-1;
|
||||
|
||||
ASSERT(20, ({
|
||||
int x;
|
||||
int *p = &x;
|
||||
p + 20 - p;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x;
|
||||
int *p = &x;
|
||||
p + 20 - p > 0;
|
||||
}));
|
||||
ASSERT(-20, ({
|
||||
int x;
|
||||
int *p = &x;
|
||||
p - 20 - p;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x;
|
||||
int *p = &x;
|
||||
p - 20 - p < 0;
|
||||
}));
|
||||
|
||||
ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0);
|
||||
ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff);
|
||||
ASSERT(1, (void *)0xffffffffffffffff > (void *)0);
|
||||
|
||||
ASSERT(3, 3 ?: 5);
|
||||
ASSERT(5, 0 ?: 5);
|
||||
ASSERT(4, ({
|
||||
int i = 3;
|
||||
++i ?: 10;
|
||||
}));
|
||||
|
||||
ASSERT(3, (long double)3);
|
||||
ASSERT(5, (long double)3 + 2);
|
||||
ASSERT(6, (long double)3 * 2);
|
||||
ASSERT(5, (long double)3 + 2.0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
132
third_party/chibicc/test/asm_test.c
vendored
Normal file
132
third_party/chibicc/test/asm_test.c
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
char *asm_fn1(void) {
|
||||
asm("mov\t$50,%rax\n\t"
|
||||
"mov\t%rbp,%rsp\n\t"
|
||||
"leave\n\t"
|
||||
"ret");
|
||||
}
|
||||
|
||||
char *asm_fn2(void) {
|
||||
asm inline volatile("mov\t$55,%rax\n\t"
|
||||
"mov\t%rbp,%rsp\n\t"
|
||||
"leave\n\t"
|
||||
"ret");
|
||||
}
|
||||
|
||||
void *repmovsb(void *dst, void *src, unsigned long n) {
|
||||
asm("rep movsb"
|
||||
: "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "0"(dst), "1"(src), "2"(n), "m"(*(const char(*)[n])src));
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *repmovsbeax(void *dst, void *src, unsigned long n) {
|
||||
void *res;
|
||||
asm("rep movsb\n\t"
|
||||
"xchg\t%0,%1"
|
||||
: "=a"(res), "=D"(dst), "=S"(src), "=c"(n), "=m"(*(char(*)[n])dst)
|
||||
: "1"(dst), "2"(src), "3"(n), "m"(*(const char(*)[n])src)
|
||||
: "rbx", "rbp", "r12", "r13", "r14", "r15", "cc");
|
||||
return res;
|
||||
}
|
||||
|
||||
void testSmashStackFrame_clobberIsRestored(void) {
|
||||
asm volatile("xor\t%%ebp,%%ebp"
|
||||
: /* no outputs */
|
||||
: /* no inputs */
|
||||
: "rbp", "cc");
|
||||
}
|
||||
|
||||
void testFlagOutputs(void) {
|
||||
bool zf, cf, sf;
|
||||
asm("xor\t%%eax,%%eax\n\t"
|
||||
"inc\t%%eax"
|
||||
: "=@ccz"(zf), "=@ccs"(cf)
|
||||
: /* no inputs */
|
||||
: "rax");
|
||||
ASSERT(false, zf);
|
||||
ASSERT(false, sf);
|
||||
asm("xor\t%%eax,%%eax\n\t"
|
||||
"dec\t%%eax"
|
||||
: "=@ccz"(zf), "=@ccs"(cf)
|
||||
: /* no inputs */
|
||||
: "rax");
|
||||
ASSERT(false, zf);
|
||||
ASSERT(true, sf);
|
||||
asm("xor\t%%eax,%%eax\n\t"
|
||||
"cmc"
|
||||
: "=@ccz"(zf), "=@ccc"(cf), "=@ccs"(sf)
|
||||
: /* no inputs */
|
||||
: "rax");
|
||||
ASSERT(true, zf);
|
||||
ASSERT(true, cf);
|
||||
ASSERT(false, sf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(50, asm_fn1());
|
||||
ASSERT(55, asm_fn2());
|
||||
|
||||
{
|
||||
char buf[] = "HELLO";
|
||||
char *s = "hello";
|
||||
char *p = repmovsb(buf, s, 4);
|
||||
ASSERT(4, p - buf);
|
||||
ASSERT('h', buf[0]);
|
||||
ASSERT('e', buf[1]);
|
||||
ASSERT('l', buf[2]);
|
||||
ASSERT('l', buf[3]);
|
||||
ASSERT('O', buf[4]);
|
||||
}
|
||||
|
||||
{
|
||||
char buf[] = "HELLO";
|
||||
char *s = "hello";
|
||||
char *p = repmovsbeax(buf, s, 4);
|
||||
ASSERT(4, p - buf);
|
||||
ASSERT('h', buf[0]);
|
||||
ASSERT('e', buf[1]);
|
||||
ASSERT('l', buf[2]);
|
||||
ASSERT('l', buf[3]);
|
||||
ASSERT('O', buf[4]);
|
||||
}
|
||||
|
||||
testSmashStackFrame_clobberIsRestored();
|
||||
|
||||
short v1[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
short v2[8] = {1, 1, 1, 1, 1, 1, 1, 1};
|
||||
short v3[8] = {2, 2, 2, 2, 2, 2, 2, 2};
|
||||
asm("paddsw\t%1,%0\n\t"
|
||||
"paddsw\t%2,%0"
|
||||
: "+x"(v1)
|
||||
: "xm"(v2), "xm"(v3));
|
||||
ASSERT(3, v1[0]);
|
||||
ASSERT(4, v1[1]);
|
||||
ASSERT(5, v1[2]);
|
||||
ASSERT(6, v1[3]);
|
||||
ASSERT(7, v1[4]);
|
||||
ASSERT(8, v1[5]);
|
||||
ASSERT(9, v1[6]);
|
||||
ASSERT(10, v1[7]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
160
third_party/chibicc/test/attribute_test.c
vendored
Normal file
160
third_party/chibicc/test/attribute_test.c
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(5, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((packed)) x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0, offsetof(
|
||||
struct __attribute__((packed)) {
|
||||
char a;
|
||||
int b;
|
||||
},
|
||||
a));
|
||||
ASSERT(1, offsetof(
|
||||
struct __attribute__((packed)) {
|
||||
char a;
|
||||
int b;
|
||||
},
|
||||
b));
|
||||
|
||||
ASSERT(5, ({
|
||||
struct __attribute__((packed)) {
|
||||
char a;
|
||||
int b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0, offsetof(
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((packed)),
|
||||
a));
|
||||
ASSERT(1, offsetof(
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((packed)),
|
||||
b));
|
||||
|
||||
ASSERT(9, ({
|
||||
typedef struct {
|
||||
char a;
|
||||
int b[2];
|
||||
} __attribute__((packed)) T;
|
||||
sizeof(T);
|
||||
}));
|
||||
ASSERT(9, ({
|
||||
typedef struct __attribute__((packed)) {
|
||||
char a;
|
||||
int b[2];
|
||||
} T;
|
||||
sizeof(T);
|
||||
}));
|
||||
|
||||
ASSERT(1, offsetof(
|
||||
struct __attribute__((packed)) T {
|
||||
char a;
|
||||
int b[2];
|
||||
},
|
||||
b));
|
||||
ASSERT(1, _Alignof(struct __attribute__((packed)) {
|
||||
char a;
|
||||
int b[2];
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct __attribute__((aligned(8))) {
|
||||
int a;
|
||||
} x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
int a;
|
||||
} __attribute__((aligned(8))) x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct __attribute__((aligned(8), packed)) {
|
||||
char a;
|
||||
int b;
|
||||
} x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((aligned(8), packed)) x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(1, offsetof(
|
||||
struct __attribute__((aligned(8), packed)) {
|
||||
char a;
|
||||
int b;
|
||||
},
|
||||
b));
|
||||
ASSERT(1, offsetof(
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((aligned(8), packed)),
|
||||
b));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct __attribute__((aligned(8))) __attribute__((packed)) {
|
||||
char a;
|
||||
int b;
|
||||
} x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((aligned(8))) __attribute__((packed)) x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(1, offsetof(
|
||||
struct __attribute__((aligned(8))) __attribute__((packed)) {
|
||||
char a;
|
||||
int b;
|
||||
},
|
||||
b));
|
||||
ASSERT(1, offsetof(
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((aligned(8))) __attribute__((packed)),
|
||||
b));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct __attribute__((aligned(8))) {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((packed)) x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
ASSERT(1, offsetof(
|
||||
struct __attribute__((aligned(8))) {
|
||||
char a;
|
||||
int b;
|
||||
} __attribute__((packed)),
|
||||
b));
|
||||
|
||||
ASSERT(16, ({
|
||||
struct __attribute__((aligned(8 + 8))) {
|
||||
char a;
|
||||
int b;
|
||||
} x;
|
||||
_Alignof(x);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
128
third_party/chibicc/test/bitfield_test.c
vendored
Normal file
128
third_party/chibicc/test/bitfield_test.c
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
struct {
|
||||
char a;
|
||||
int b : 5;
|
||||
int c : 10;
|
||||
} g45 = {1, 2, 3}, g46 = {};
|
||||
|
||||
int main() {
|
||||
ASSERT(4, sizeof(struct { int x : 1; }));
|
||||
ASSERT(8, sizeof(struct { long x : 1; }));
|
||||
|
||||
struct bit1 {
|
||||
short a;
|
||||
char b;
|
||||
int c : 2;
|
||||
int d : 3;
|
||||
int e : 3;
|
||||
};
|
||||
|
||||
ASSERT(4, sizeof(struct bit1));
|
||||
ASSERT(1, ({
|
||||
struct bit1 x;
|
||||
x.a = 1;
|
||||
x.b = 2;
|
||||
x.c = 3;
|
||||
x.d = 4;
|
||||
x.e = 5;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct bit1 x = {1, 2, 3, 4, 5};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct bit1 x = {1, 2, 3, 4, 5};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(-1, ({
|
||||
struct bit1 x = {1, 2, 3, 4, 5};
|
||||
x.c;
|
||||
}));
|
||||
ASSERT(-4, ({
|
||||
struct bit1 x = {1, 2, 3, 4, 5};
|
||||
x.d;
|
||||
}));
|
||||
ASSERT(-3, ({
|
||||
struct bit1 x = {1, 2, 3, 4, 5};
|
||||
x.e;
|
||||
}));
|
||||
|
||||
ASSERT(1, g45.a);
|
||||
ASSERT(2, g45.b);
|
||||
ASSERT(3, g45.c);
|
||||
|
||||
ASSERT(0, g46.a);
|
||||
ASSERT(0, g46.b);
|
||||
ASSERT(0, g46.c);
|
||||
|
||||
typedef struct {
|
||||
int a : 10;
|
||||
int b : 10;
|
||||
int c : 10;
|
||||
} T3;
|
||||
|
||||
ASSERT(1, ({
|
||||
T3 x = {1, 2, 3};
|
||||
x.a++;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
T3 x = {1, 2, 3};
|
||||
x.b++;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
T3 x = {1, 2, 3};
|
||||
x.c++;
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
T3 x = {1, 2, 3};
|
||||
++x.a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
T3 x = {1, 2, 3};
|
||||
++x.b;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
T3 x = {1, 2, 3};
|
||||
++x.c;
|
||||
}));
|
||||
|
||||
ASSERT(4, sizeof(struct {
|
||||
int a : 3;
|
||||
int c : 1;
|
||||
int c : 5;
|
||||
}));
|
||||
ASSERT(8, sizeof(struct {
|
||||
int a : 3;
|
||||
int : 0;
|
||||
int c : 5;
|
||||
}));
|
||||
ASSERT(4, sizeof(struct {
|
||||
int a : 3;
|
||||
int : 0;
|
||||
}));
|
||||
|
||||
typedef struct {
|
||||
long p : 1;
|
||||
long a : 40;
|
||||
long b : 20;
|
||||
} T4;
|
||||
|
||||
ASSERT(0xfffffffffffaaaaa, ({
|
||||
T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa};
|
||||
x.b++;
|
||||
}));
|
||||
ASSERT(0x7313371337, ({
|
||||
T4 x = {1, 0x31337313371337, 0xaaaaaaaaaaaaaaaa};
|
||||
x.a++;
|
||||
}));
|
||||
ASSERT(0xffffffffffffffd4, ({
|
||||
T4 x;
|
||||
x.b = -44;
|
||||
x.b++;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
242
third_party/chibicc/test/builtin_test.c
vendored
Normal file
242
third_party/chibicc/test/builtin_test.c
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
#define FPNAN 0
|
||||
#define FPINFINITE 1
|
||||
#define FPZERO 2
|
||||
#define FPSUBNORMAL 3
|
||||
#define FPNORMAL 4
|
||||
#define FPCLASSIFY(x) \
|
||||
__builtin_fpclassify(FPNAN, FPINFINITE, FPNORMAL, FPSUBNORMAL, FPZERO, x)
|
||||
|
||||
void test_constant(void) {
|
||||
ASSERT(1, __builtin_constant_p(1));
|
||||
ASSERT(0, __builtin_constant_p(stdin));
|
||||
ASSERT(1, __builtin_constant_p(__builtin_popcount(0b10111011)));
|
||||
}
|
||||
|
||||
void test_fpclassify(void) {
|
||||
float minf = __FLT_MIN__;
|
||||
double min = __DBL_MIN__;
|
||||
long double minl = __LDBL_MIN__;
|
||||
ASSERT(FPZERO, FPCLASSIFY(.0f));
|
||||
ASSERT(FPZERO, FPCLASSIFY(.0));
|
||||
ASSERT(FPZERO, FPCLASSIFY(.0L));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.f));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.L));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.f));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(1.L));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(minf));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(min));
|
||||
ASSERT(FPNORMAL, FPCLASSIFY(minl));
|
||||
ASSERT(FPSUBNORMAL, FPCLASSIFY(minf / 2));
|
||||
ASSERT(FPSUBNORMAL, FPCLASSIFY(min / 2));
|
||||
ASSERT(FPSUBNORMAL, FPCLASSIFY(minl / 2));
|
||||
ASSERT(FPNAN, FPCLASSIFY(__builtin_nanf("")));
|
||||
ASSERT(FPNAN, FPCLASSIFY(__builtin_nan("")));
|
||||
ASSERT(FPNAN, FPCLASSIFY(__builtin_nanl("")));
|
||||
}
|
||||
|
||||
void __attribute__((__aligned__(16))) test_clz(void) {
|
||||
ASSERT(31, __builtin_clz(1));
|
||||
ASSERT(63, __builtin_clzl(1));
|
||||
ASSERT(63, __builtin_clzll(1));
|
||||
ASSERT(25, __builtin_clz(77));
|
||||
ASSERT(4, __builtin_clz(0x08000000));
|
||||
ASSERT(4, __builtin_clz(0xfff08000000));
|
||||
}
|
||||
|
||||
__attribute__((__weak__)) void test_ctz(void) {
|
||||
ASSERT(0, __builtin_ctz(1));
|
||||
ASSERT(0, __builtin_ctz(77));
|
||||
ASSERT(27, __builtin_ctz(0x08000000));
|
||||
ASSERT(27, __builtin_ctz(0xffff08000000));
|
||||
ASSERT(63, __builtin_ctzl(0x8000000000000000));
|
||||
ASSERT(63, __builtin_ctzll(0x8000000000000000));
|
||||
}
|
||||
|
||||
void test_ffs(void) {
|
||||
ASSERT(0, __builtin_ffs(0));
|
||||
ASSERT(1, __builtin_ffs(1));
|
||||
ASSERT(1, __builtin_ffs(77));
|
||||
ASSERT(28, __builtin_ffs(0x08000000));
|
||||
ASSERT(28, __builtin_ffs(0xffff08000000));
|
||||
}
|
||||
|
||||
void test_popcnt(void) {
|
||||
ASSERT(0, __builtin_popcount(0));
|
||||
ASSERT(1, __builtin_popcount(1));
|
||||
ASSERT(6, __builtin_popcount(0b10111011));
|
||||
ASSERT(6, __builtin_popcountl(0b10111011));
|
||||
ASSERT(6, __builtin_popcountll(0xbb00000000000000));
|
||||
}
|
||||
|
||||
void test_bswap(void) {
|
||||
ASSERT(0x3412, __builtin_bswap16(0x1234));
|
||||
ASSERT(0x78563412, __builtin_bswap32(0x12345678));
|
||||
ASSERT(0xefcdab8967452301, __builtin_bswap64(0x0123456789abcdef));
|
||||
ASSERT(0xefcdab89, __builtin_bswap32(0x0123456789abcdef));
|
||||
}
|
||||
|
||||
void test_memcpy(void) {
|
||||
{
|
||||
char x[5] = {4, 3, 2, 1, 0};
|
||||
char y[5] = {0, 1, 2, 3, 4};
|
||||
char z[5] = {2, 3, 4, 1, 0};
|
||||
ASSERT(1, x == __builtin_memcpy(x, y + 2, 3));
|
||||
ASSERT(0, memcmp(x, z, 5));
|
||||
}
|
||||
{
|
||||
int n = 3;
|
||||
char x[5] = {4, 3, 2, 1, 0};
|
||||
char y[5] = {0, 1, 2, 3, 4};
|
||||
char z[5] = {2, 3, 4, 1, 0};
|
||||
ASSERT(1, x == __builtin_memcpy(x, y + 2, n));
|
||||
ASSERT(0, memcmp(x, z, 5));
|
||||
}
|
||||
}
|
||||
|
||||
void test_inf(void) {
|
||||
ASSERT(0, __builtin_isinf(0));
|
||||
ASSERT(0, __builtin_isinf(1));
|
||||
ASSERT(1, __builtin_isinf(__builtin_inff()));
|
||||
ASSERT(1, __builtin_isinf(-__builtin_inff()));
|
||||
ASSERT(1, __builtin_isinf(__builtin_inf()));
|
||||
ASSERT(1, __builtin_isinf(-__builtin_inf()));
|
||||
ASSERT(1, __builtin_isinf(__builtin_infl()));
|
||||
ASSERT(1, __builtin_isinf(-__builtin_infl()));
|
||||
ASSERT(1, __builtin_isfinite(0));
|
||||
ASSERT(1, __builtin_isfinite(1));
|
||||
ASSERT(0, __builtin_isfinite(__builtin_inff()));
|
||||
ASSERT(0, __builtin_isfinite(-__builtin_inff()));
|
||||
ASSERT(0, __builtin_isfinite(__builtin_inf()));
|
||||
ASSERT(0, __builtin_isfinite(-__builtin_inf()));
|
||||
ASSERT(0, __builtin_isfinite(__builtin_infl()));
|
||||
ASSERT(0, __builtin_isfinite(-__builtin_infl()));
|
||||
}
|
||||
|
||||
void test_signbit(void) {
|
||||
ASSERT(0, !!__builtin_signbitf(0));
|
||||
ASSERT(0, !!__builtin_signbitf(0.f));
|
||||
ASSERT(0, !!__builtin_signbit(0.));
|
||||
ASSERT(0, !!__builtin_signbitl(0.L));
|
||||
ASSERT(1, !!__builtin_signbitf(-0.f));
|
||||
ASSERT(1, !!__builtin_signbit(-0.));
|
||||
ASSERT(1, !!__builtin_signbitl(-0.L));
|
||||
ASSERT(0, !!__builtin_signbitf(__builtin_nanf("")));
|
||||
ASSERT(1, !!__builtin_signbitf(-__builtin_nanf("")));
|
||||
ASSERT(0, !!__builtin_signbit(__builtin_nan("")));
|
||||
ASSERT(1, !!__builtin_signbit(-__builtin_nan("")));
|
||||
ASSERT(0, !!__builtin_signbitl(__builtin_nanl("")));
|
||||
ASSERT(1, !!__builtin_signbitl(-__builtin_nanl("")));
|
||||
ASSERT(0, !!__builtin_signbitf(__builtin_inff()));
|
||||
ASSERT(1, !!__builtin_signbitf(-__builtin_inff()));
|
||||
ASSERT(0, !!__builtin_signbit(__builtin_inf()));
|
||||
ASSERT(1, !!__builtin_signbit(-__builtin_inf()));
|
||||
ASSERT(0, !!__builtin_signbitl(__builtin_infl()));
|
||||
ASSERT(1, !!__builtin_signbitl(-__builtin_infl()));
|
||||
}
|
||||
|
||||
void test_nan(void) {
|
||||
ASSERT(0, __builtin_isnan(0));
|
||||
ASSERT(0, __builtin_isnan(1));
|
||||
ASSERT(1, __builtin_isnan(__builtin_nanf("")));
|
||||
ASSERT(1, __builtin_isnan(-__builtin_nanf("")));
|
||||
ASSERT(1, __builtin_isnan(__builtin_nan("")));
|
||||
ASSERT(1, __builtin_isnan(-__builtin_nan("")));
|
||||
ASSERT(1, __builtin_isnan(__builtin_nanl("")));
|
||||
ASSERT(1, __builtin_isnan(-__builtin_nanl("")));
|
||||
ASSERT(0, __builtin_isunordered(0, 0));
|
||||
ASSERT(0, __builtin_isunordered(-1, 1));
|
||||
ASSERT(1, __builtin_isunordered(0, __builtin_nanf("")));
|
||||
ASSERT(1, __builtin_isunordered(__builtin_nanf(""), 0));
|
||||
ASSERT(1, __builtin_isunordered(__builtin_nanf(""), __builtin_nanf("")));
|
||||
}
|
||||
|
||||
void test_double(void) { /* TODO */
|
||||
/* ASSERT(1, __DBL_MIN__ < 0.0L); */
|
||||
/* ASSERT(1, __DBL_MAX__ > 0.0L); */
|
||||
}
|
||||
|
||||
void test_types_compatible_p(void) {
|
||||
ASSERT(1, __builtin_types_compatible_p(int, int));
|
||||
ASSERT(1, __builtin_types_compatible_p(double, double));
|
||||
ASSERT(0, __builtin_types_compatible_p(int, long));
|
||||
ASSERT(0, __builtin_types_compatible_p(long, float));
|
||||
ASSERT(1, __builtin_types_compatible_p(int *, int *));
|
||||
ASSERT(0, __builtin_types_compatible_p(short *, int *));
|
||||
ASSERT(0, __builtin_types_compatible_p(int **, int *));
|
||||
ASSERT(1, __builtin_types_compatible_p(const int, int));
|
||||
ASSERT(0, __builtin_types_compatible_p(unsigned, int));
|
||||
ASSERT(1, __builtin_types_compatible_p(signed, int));
|
||||
ASSERT(0, __builtin_types_compatible_p(
|
||||
struct { int a; }, struct { int a; }));
|
||||
ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void)));
|
||||
ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int)));
|
||||
ASSERT(1, __builtin_types_compatible_p(void (*)(int, double),
|
||||
void (*)(int, double)));
|
||||
ASSERT(1, __builtin_types_compatible_p(int (*)(float, double),
|
||||
int (*)(float, double)));
|
||||
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int));
|
||||
ASSERT(0,
|
||||
__builtin_types_compatible_p(int (*)(float, double), int (*)(float)));
|
||||
ASSERT(0, __builtin_types_compatible_p(int (*)(float, double),
|
||||
int (*)(float, double, int)));
|
||||
ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...)));
|
||||
ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void)));
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a;
|
||||
} T;
|
||||
__builtin_types_compatible_p(T, T);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a;
|
||||
} T;
|
||||
__builtin_types_compatible_p(T, const T);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
__builtin_types_compatible_p(typeof(x.a), typeof(x.b));
|
||||
}));
|
||||
}
|
||||
|
||||
void test_offsetof(void) {
|
||||
ASSERT(0, ({
|
||||
struct T {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
__builtin_offsetof(struct T, a);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct T {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
__builtin_offsetof(struct T, b);
|
||||
}));
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_constant();
|
||||
test_types_compatible_p();
|
||||
test_clz();
|
||||
test_ctz();
|
||||
test_ffs();
|
||||
test_bswap();
|
||||
test_popcnt();
|
||||
test_inf();
|
||||
test_nan();
|
||||
test_double();
|
||||
test_fpclassify();
|
||||
test_signbit();
|
||||
test_memcpy();
|
||||
test_offsetof();
|
||||
return 0;
|
||||
}
|
||||
80
third_party/chibicc/test/cast_test.c
vendored
Normal file
80
third_party/chibicc/test/cast_test.c
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(131585, (int)8590066177);
|
||||
ASSERT(513, (short)8590066177);
|
||||
ASSERT(1, (char)8590066177);
|
||||
ASSERT(1, (long)1);
|
||||
ASSERT(0, (long)&*(int *)0);
|
||||
ASSERT(513, ({
|
||||
int x = 512;
|
||||
*(char *)&x = 1;
|
||||
x;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 5;
|
||||
long y = (long)&x;
|
||||
*(int *)y;
|
||||
}));
|
||||
|
||||
(void)1;
|
||||
|
||||
ASSERT(-1, (char)255);
|
||||
ASSERT(-1, (signed char)255);
|
||||
ASSERT(255, (unsigned char)255);
|
||||
ASSERT(-1, (short)65535);
|
||||
ASSERT(65535, (unsigned short)65535);
|
||||
ASSERT(-1, (int)0xffffffff);
|
||||
ASSERT(0xffffffff, (unsigned)0xffffffff);
|
||||
|
||||
ASSERT(1, -1 < 1);
|
||||
ASSERT(0, -1 < (unsigned)1);
|
||||
ASSERT(254, (char)127 + (char)127);
|
||||
ASSERT(65534, (short)32767 + (short)32767);
|
||||
ASSERT(-1, -1 >> 1);
|
||||
ASSERT(-1, (unsigned long)-1);
|
||||
ASSERT(2147483647, ((unsigned)-1) >> 1);
|
||||
ASSERT(-50, (-100) / 2);
|
||||
ASSERT(2147483598, ((unsigned)-100) / 2);
|
||||
ASSERT(9223372036854775758, ((unsigned long)-100) / 2);
|
||||
ASSERT(0, ((long)-1) / (unsigned)100);
|
||||
ASSERT(-2, (-100) % 7);
|
||||
ASSERT(2, ((unsigned)-100) % 7);
|
||||
ASSERT(6, ((unsigned long)-100) % 9);
|
||||
|
||||
ASSERT(65535, (int)(unsigned short)65535);
|
||||
ASSERT(65535, ({
|
||||
unsigned short x = 65535;
|
||||
x;
|
||||
}));
|
||||
ASSERT(65535, ({
|
||||
unsigned short x = 65535;
|
||||
(int)x;
|
||||
}));
|
||||
|
||||
ASSERT(-1, ({
|
||||
typedef short T;
|
||||
T x = 65535;
|
||||
(int)x;
|
||||
}));
|
||||
ASSERT(65535, ({
|
||||
typedef unsigned short T;
|
||||
T x = 65535;
|
||||
(int)x;
|
||||
}));
|
||||
|
||||
ASSERT(0, (_Bool)0.0);
|
||||
ASSERT(1, (_Bool)0.1);
|
||||
ASSERT(3, (char)3.0);
|
||||
ASSERT(1000, (short)1000.3);
|
||||
ASSERT(3, (int)3.99);
|
||||
ASSERT(2000000000000000, (long)2e15);
|
||||
ASSERT(3, (float)3.5);
|
||||
ASSERT(5, (double)(float)5.5);
|
||||
ASSERT(3, (float)3);
|
||||
ASSERT(3, (double)3);
|
||||
ASSERT(3, (float)3L);
|
||||
ASSERT(3, (double)3L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
195
third_party/chibicc/test/common.c
vendored
Normal file
195
third_party/chibicc/test/common.c
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
void Assert(long expected, long actual, char *code) {
|
||||
if (expected != actual) {
|
||||
fprintf(stderr, "%s => %ld expected but got %ld\n", code, expected, actual);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Assert2(long expected, long actual, char *code, char *func, int line) {
|
||||
if (expected != actual) {
|
||||
fprintf(stderr, "%s:%d: %s => expected %ld but got %ld\n", func, line, code,
|
||||
expected, actual);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Assert128(__int128 k, __int128 x, char *code, char *func, int line) {
|
||||
if (k != x) {
|
||||
fprintf(stderr, "%s:%d: %s => want %jd but got %jd\n", func, line, code, k,
|
||||
x);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int static_fn() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
int ext1 = 5;
|
||||
int *ext2 = &ext1;
|
||||
int ext3 = 7;
|
||||
|
||||
int ext_fn1(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int ext_fn2(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int common_ext2 = 3;
|
||||
static int common_local;
|
||||
|
||||
int false_fn() {
|
||||
return 512;
|
||||
}
|
||||
|
||||
int true_fn() {
|
||||
return 513;
|
||||
}
|
||||
|
||||
int char_fn() {
|
||||
return (2 << 8) + 3;
|
||||
}
|
||||
|
||||
int short_fn() {
|
||||
return (2 << 16) + 5;
|
||||
}
|
||||
|
||||
int uchar_fn() {
|
||||
return (2 << 10) - 1 - 4;
|
||||
}
|
||||
|
||||
int ushort_fn() {
|
||||
return (2 << 20) - 1 - 7;
|
||||
}
|
||||
|
||||
int schar_fn() {
|
||||
return (2 << 10) - 1 - 4;
|
||||
}
|
||||
|
||||
int sshort_fn() {
|
||||
return (2 << 20) - 1 - 7;
|
||||
}
|
||||
|
||||
int add_all(int n, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
int sum = 0;
|
||||
for (int i = 0; i < n; i++) sum += va_arg(ap, int);
|
||||
va_end(ap);
|
||||
return sum;
|
||||
}
|
||||
|
||||
float add_float(float x, float y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
double add_double(double x, double y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8,
|
||||
int x9, int x10) {
|
||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
|
||||
}
|
||||
|
||||
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6,
|
||||
float x7, float x8, float x9, float x10) {
|
||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
|
||||
}
|
||||
|
||||
double add10_double(double x1, double x2, double x3, double x4, double x5,
|
||||
double x6, double x7, double x8, double x9, double x10) {
|
||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a, b;
|
||||
short c;
|
||||
char d;
|
||||
} Ty4;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
float b;
|
||||
double c;
|
||||
} Ty5;
|
||||
|
||||
typedef struct {
|
||||
unsigned char a[3];
|
||||
} Ty6;
|
||||
|
||||
typedef struct {
|
||||
long a, b, c;
|
||||
} Ty7;
|
||||
|
||||
int struct_test4(Ty4 x, int n) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return x.a;
|
||||
case 1:
|
||||
return x.b;
|
||||
case 2:
|
||||
return x.c;
|
||||
default:
|
||||
return x.d;
|
||||
}
|
||||
}
|
||||
|
||||
int struct_test5(Ty5 x, int n) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return x.a;
|
||||
case 1:
|
||||
return x.b;
|
||||
default:
|
||||
return x.c;
|
||||
}
|
||||
}
|
||||
|
||||
int struct_test6(Ty6 x, int n) {
|
||||
return x.a[n];
|
||||
}
|
||||
|
||||
int struct_test7(Ty7 x, int n) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return x.a;
|
||||
case 1:
|
||||
return x.b;
|
||||
default:
|
||||
return x.c;
|
||||
}
|
||||
}
|
||||
|
||||
Ty4 struct_test24(void) {
|
||||
return (Ty4){10, 20, 30, 40};
|
||||
}
|
||||
|
||||
Ty5 struct_test25(void) {
|
||||
return (Ty5){10, 20, 30};
|
||||
}
|
||||
|
||||
Ty6 struct_test26(void) {
|
||||
return (Ty6){{10, 20, 30}};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned char a[10];
|
||||
} Ty20;
|
||||
|
||||
typedef struct {
|
||||
unsigned char a[20];
|
||||
} Ty21;
|
||||
|
||||
Ty20 struct_test27(void) {
|
||||
return (Ty20){{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}};
|
||||
}
|
||||
|
||||
Ty21 struct_test28(void) {
|
||||
return (Ty21){
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}};
|
||||
}
|
||||
18
third_party/chibicc/test/compat_test.c
vendored
Normal file
18
third_party/chibicc/test/compat_test.c
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
_Noreturn noreturn_fn(int restrict x) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void funcy_type(int arg[restrict static 3]) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
{ volatile x; }
|
||||
{ int volatile x; }
|
||||
{ volatile int x; }
|
||||
{ volatile int volatile volatile x; }
|
||||
{ int volatile *volatile volatile x; }
|
||||
{ auto **restrict __restrict __restrict__ const volatile *x; }
|
||||
return 0;
|
||||
}
|
||||
31
third_party/chibicc/test/complit_test.c
vendored
Normal file
31
third_party/chibicc/test/complit_test.c
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
typedef struct Tree {
|
||||
int val;
|
||||
struct Tree *lhs;
|
||||
struct Tree *rhs;
|
||||
} Tree;
|
||||
|
||||
Tree *tree = &(Tree){1, &(Tree){2, &(Tree){3, 0, 0}, &(Tree){4, 0, 0}}, 0};
|
||||
|
||||
int main() {
|
||||
ASSERT(1, (int){1});
|
||||
ASSERT(2, ((int[]){0, 1, 2})[2]);
|
||||
ASSERT('a', ((struct {
|
||||
char a;
|
||||
int b;
|
||||
}){'a', 3})
|
||||
.a);
|
||||
ASSERT(3, ({
|
||||
int x = 3;
|
||||
(int){x};
|
||||
}));
|
||||
(int){3} = 5;
|
||||
|
||||
ASSERT(1, tree->val);
|
||||
ASSERT(2, tree->lhs->val);
|
||||
ASSERT(3, tree->lhs->lhs->val);
|
||||
ASSERT(4, tree->lhs->rhs->val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
third_party/chibicc/test/const_test.c
vendored
Normal file
23
third_party/chibicc/test/const_test.c
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
{ const x; }
|
||||
{ int const x; }
|
||||
{ const int x; }
|
||||
{ const int const const x; }
|
||||
ASSERT(5, ({
|
||||
const x = 5;
|
||||
x;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
const x = 8;
|
||||
int *const y = &x;
|
||||
*y;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
const x = 6;
|
||||
*(const *const) & x;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
181
third_party/chibicc/test/constexpr_test.c
vendored
Normal file
181
third_party/chibicc/test/constexpr_test.c
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
float g40 = 1.5;
|
||||
double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0);
|
||||
|
||||
int main() {
|
||||
ASSERT(10, ({
|
||||
enum { ten = 1 + 2 + 3 + 4 };
|
||||
ten;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int i = 0;
|
||||
switch (3) {
|
||||
case 5 - 2 + 0 * 3:
|
||||
i++;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x[1 + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
char x[8 - 2];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
char x[2 * 3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char x[12 / 4];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[12 % 10];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0b100, ({
|
||||
char x[0b110 & 0b101];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0b111, ({
|
||||
char x[0b110 | 0b101];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0b110, ({
|
||||
char x[0b111 ^ 0b001];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[1 << 2];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[4 >> 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[(1 == 1) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(1 != 1) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(1 < 1) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[(1 <= 1) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[1 ? 2 : 3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char x[0 ? 2 : 3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char x[(1, 3)];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[!0 + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[!1 + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[~-3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[(5 || 6) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(0 || 0) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x[(1 && 1) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(1 && 0) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char x[(int)3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(15, ({
|
||||
char x[(char)0xffffff0f];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0x10f, ({
|
||||
char x[(short)0xffff010f];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[(int)0xfffffffffff + 5];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
char x[(int*)0 + 2];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
char x[(int*)16 - 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char x[(int*)16 - (int*)4];
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
char x[(-1 >> 31) + 5];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(255, ({
|
||||
char x[(unsigned char)0xffffffff];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0x800f, ({
|
||||
char x[(unsigned short)0xffff800f];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(unsigned int)0xfffffffffff >> 31];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(long)-1 / ((long)1 << 62) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[(unsigned long)-1 / ((long)1 << 62) + 1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(unsigned)1 < -1];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x[(unsigned)1 <= -1];
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(1, g40 == 1.5);
|
||||
ASSERT(1, g41 == 11);
|
||||
|
||||
return 0;
|
||||
}
|
||||
542
third_party/chibicc/test/control_test.c
vendored
Normal file
542
third_party/chibicc/test/control_test.c
vendored
Normal file
@ -0,0 +1,542 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
/*
|
||||
* This is a block comment.
|
||||
*/
|
||||
|
||||
int main() {
|
||||
ASSERT(3, ({
|
||||
int x;
|
||||
if (0)
|
||||
x = 2;
|
||||
else
|
||||
x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x;
|
||||
if (1 - 1)
|
||||
x = 2;
|
||||
else
|
||||
x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x;
|
||||
if (1)
|
||||
x = 2;
|
||||
else
|
||||
x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x;
|
||||
if (2 - 1)
|
||||
x = 2;
|
||||
else
|
||||
x = 3;
|
||||
x;
|
||||
}));
|
||||
|
||||
ASSERT(55, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (i = 0; i <= 10; i = i + 1) j = i + j;
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
int i = 0;
|
||||
while (i < 10) i = i + 1;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
1;
|
||||
{ 2; }
|
||||
3;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
;
|
||||
;
|
||||
;
|
||||
5;
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
int i = 0;
|
||||
while (i < 10) i = i + 1;
|
||||
i;
|
||||
}));
|
||||
ASSERT(55, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i <= 10) {
|
||||
j = i + j;
|
||||
i = i + 1;
|
||||
}
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(3, (1, 2, 3));
|
||||
ASSERT(5, ({
|
||||
int i = 2, j = 3;
|
||||
(i = 5, j) = 6;
|
||||
i;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int i = 2, j = 3;
|
||||
(i = 5, j) = 6;
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(55, ({
|
||||
int j = 0;
|
||||
for (int i = 0; i <= 10; i = i + 1) j = j + i;
|
||||
j;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 3;
|
||||
int j = 0;
|
||||
for (int i = 0; i <= 10; i = i + 1) j = j + i;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(1, 0 || 1);
|
||||
ASSERT(1, 0 || (2 - 2) || 5);
|
||||
ASSERT(0, 0 || 0);
|
||||
ASSERT(0, 0 || (2 - 2));
|
||||
|
||||
ASSERT(0, 0 && 1);
|
||||
ASSERT(0, (2 - 2) && 5);
|
||||
ASSERT(1, 1 && 5);
|
||||
|
||||
ASSERT(3, ({
|
||||
int i = 0;
|
||||
goto a;
|
||||
a:
|
||||
i++;
|
||||
b:
|
||||
i++;
|
||||
c:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int i = 0;
|
||||
goto e;
|
||||
d:
|
||||
i++;
|
||||
e:
|
||||
i++;
|
||||
f:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int i = 0;
|
||||
goto i;
|
||||
g:
|
||||
i++;
|
||||
h:
|
||||
i++;
|
||||
i:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
typedef int foo;
|
||||
goto foo;
|
||||
foo:;
|
||||
1;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int i = 0;
|
||||
for (; i < 10; i++) {
|
||||
if (i == 3) break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int i = 0;
|
||||
while (1) {
|
||||
if (i++ == 3) break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int i = 0;
|
||||
for (; i < 10; i++) {
|
||||
for (;;) break;
|
||||
if (i == 3) break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int i = 0;
|
||||
while (1) {
|
||||
while (1) break;
|
||||
if (i++ == 3) break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (; i < 10; i++) {
|
||||
if (i > 5) continue;
|
||||
j++;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (; i < 10; i++) {
|
||||
if (i > 5) continue;
|
||||
j++;
|
||||
}
|
||||
j;
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (; !i;) {
|
||||
for (; j != 10; j++) continue;
|
||||
break;
|
||||
}
|
||||
j;
|
||||
}));
|
||||
ASSERT(11, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i++ < 10) {
|
||||
if (i > 5) continue;
|
||||
j++;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i++ < 10) {
|
||||
if (i > 5) continue;
|
||||
j++;
|
||||
}
|
||||
j;
|
||||
}));
|
||||
ASSERT(11, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (!i) {
|
||||
while (j++ != 10) continue;
|
||||
break;
|
||||
}
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(5, ({
|
||||
int i = 0;
|
||||
switch (0) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
case 1:
|
||||
i = 6;
|
||||
break;
|
||||
case 2:
|
||||
i = 7;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int i = 0;
|
||||
switch (1) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
case 1:
|
||||
i = 6;
|
||||
break;
|
||||
case 2:
|
||||
i = 7;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int i = 0;
|
||||
switch (2) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
case 1:
|
||||
i = 6;
|
||||
break;
|
||||
case 2:
|
||||
i = 7;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int i = 0;
|
||||
switch (3) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
case 1:
|
||||
i = 6;
|
||||
break;
|
||||
case 2:
|
||||
i = 7;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int i = 0;
|
||||
switch (0) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
default:
|
||||
i = 7;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int i = 0;
|
||||
switch (1) {
|
||||
case 0:
|
||||
i = 5;
|
||||
break;
|
||||
default:
|
||||
i = 7;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int i = 0;
|
||||
switch (1) {
|
||||
case 0:
|
||||
0;
|
||||
case 1:
|
||||
0;
|
||||
case 2:
|
||||
0;
|
||||
i = 2;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int i = 0;
|
||||
switch (3) {
|
||||
case 0:
|
||||
0;
|
||||
case 1:
|
||||
0;
|
||||
case 2:
|
||||
0;
|
||||
i = 2;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int i = 0;
|
||||
switch (-1) {
|
||||
case 0xffffffff:
|
||||
i = 3;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(7, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
do {
|
||||
j++;
|
||||
} while (i++ < 6);
|
||||
j;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
do {
|
||||
if (++j > 3) break;
|
||||
continue;
|
||||
k++;
|
||||
} while (1);
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(0, 0.0 && 0.0);
|
||||
ASSERT(0, 0.0 && 0.1);
|
||||
ASSERT(0, 0.3 && 0.0);
|
||||
ASSERT(1, 0.3 && 0.5);
|
||||
ASSERT(0, 0.0 || 0.0);
|
||||
ASSERT(1, 0.0 || 0.1);
|
||||
ASSERT(1, 0.3 || 0.0);
|
||||
ASSERT(1, 0.3 || 0.5);
|
||||
ASSERT(5, ({
|
||||
int x;
|
||||
if (0.0)
|
||||
x = 3;
|
||||
else
|
||||
x = 5;
|
||||
x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x;
|
||||
if (0.1)
|
||||
x = 3;
|
||||
else
|
||||
x = 5;
|
||||
x;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 5;
|
||||
if (0.0) x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x = 5;
|
||||
if (0.1) x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
double i = 10.0;
|
||||
int j = 0;
|
||||
for (; i; i--, j++)
|
||||
;
|
||||
j;
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
double i = 10.0;
|
||||
int j = 0;
|
||||
do
|
||||
j++;
|
||||
while (--i);
|
||||
j;
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int i = 0;
|
||||
switch (7) {
|
||||
case 0 ... 5:
|
||||
i = 1;
|
||||
break;
|
||||
case 6 ... 20:
|
||||
i = 2;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int i = 0;
|
||||
switch (7) {
|
||||
case 0 ... 7:
|
||||
i = 1;
|
||||
break;
|
||||
case 8 ... 10:
|
||||
i = 2;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int i = 0;
|
||||
switch (7) {
|
||||
case 0:
|
||||
i = 1;
|
||||
break;
|
||||
case 7 ... 7:
|
||||
i = 1;
|
||||
break;
|
||||
}
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
void *p = &&v11;
|
||||
int i = 0;
|
||||
goto *p;
|
||||
v11:
|
||||
i++;
|
||||
v12:
|
||||
i++;
|
||||
v13:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
void *p = &&v22;
|
||||
int i = 0;
|
||||
goto *p;
|
||||
v21:
|
||||
i++;
|
||||
v22:
|
||||
i++;
|
||||
v23:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
void *p = &&v33;
|
||||
int i = 0;
|
||||
goto *p;
|
||||
v31:
|
||||
i++;
|
||||
v32:
|
||||
i++;
|
||||
v33:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
static void *p[] = {&&v41, &&v42, &&v43};
|
||||
int i = 0;
|
||||
goto *p[0];
|
||||
v41:
|
||||
i++;
|
||||
v42:
|
||||
i++;
|
||||
v43:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
static void *p[] = {&&v52, &&v52, &&v53};
|
||||
int i = 0;
|
||||
goto *p[1];
|
||||
v51:
|
||||
i++;
|
||||
v52:
|
||||
i++;
|
||||
v53:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
static void *p[] = {&&v62, &&v62, &&v63};
|
||||
int i = 0;
|
||||
goto *p[2];
|
||||
v61:
|
||||
i++;
|
||||
v62:
|
||||
i++;
|
||||
v63:
|
||||
i++;
|
||||
i;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
third_party/chibicc/test/decl_test.c
vendored
Normal file
51
third_party/chibicc/test/decl_test.c
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({
|
||||
char x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
short int x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int short x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
long int x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int long x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
long long x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
_Bool x = 0;
|
||||
x;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
_Bool x = 1;
|
||||
x;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
_Bool x = 2;
|
||||
x;
|
||||
}));
|
||||
ASSERT(1, (_Bool)1);
|
||||
ASSERT(1, (_Bool)2);
|
||||
ASSERT(0, (_Bool)(char)256);
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
third_party/chibicc/test/enum_test.c
vendored
Normal file
50
third_party/chibicc/test/enum_test.c
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(0, ({
|
||||
enum { zero, one, two };
|
||||
zero;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
enum { zero, one, two };
|
||||
one;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
enum { zero, one, two };
|
||||
two;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
enum { five = 5, six, seven };
|
||||
five;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
enum { five = 5, six, seven };
|
||||
six;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
enum { zero, five = 5, three = 3, four };
|
||||
zero;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
enum { zero, five = 5, three = 3, four };
|
||||
five;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
enum { zero, five = 5, three = 3, four };
|
||||
three;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
enum { zero, five = 5, three = 3, four };
|
||||
four;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
enum { zero, one, two } x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
enum t { zero, one, two };
|
||||
enum t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
return 0;
|
||||
}
|
||||
24
third_party/chibicc/test/extern_test.c
vendored
Normal file
24
third_party/chibicc/test/extern_test.c
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
extern int ext1;
|
||||
extern int *ext2;
|
||||
|
||||
inline int inline_fn(void) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(5, ext1);
|
||||
ASSERT(5, *ext2);
|
||||
|
||||
extern int ext3;
|
||||
ASSERT(7, ext3);
|
||||
|
||||
int ext_fn1(int x);
|
||||
ASSERT(5, ext_fn1(5));
|
||||
|
||||
extern int ext_fn2(int x);
|
||||
ASSERT(8, ext_fn2(8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
92
third_party/chibicc/test/float_test.c
vendored
Normal file
92
third_party/chibicc/test/float_test.c
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(35, (float)(char)35);
|
||||
ASSERT(35, (float)(short)35);
|
||||
ASSERT(35, (float)(int)35);
|
||||
ASSERT(35, (float)(long)35);
|
||||
ASSERT(35, (float)(unsigned char)35);
|
||||
ASSERT(35, (float)(unsigned short)35);
|
||||
ASSERT(35, (float)(unsigned int)35);
|
||||
ASSERT(35, (float)(unsigned long)35);
|
||||
|
||||
ASSERT(35, (double)(char)35);
|
||||
ASSERT(35, (double)(short)35);
|
||||
ASSERT(35, (double)(int)35);
|
||||
ASSERT(35, (double)(long)35);
|
||||
ASSERT(35, (double)(unsigned char)35);
|
||||
ASSERT(35, (double)(unsigned short)35);
|
||||
ASSERT(35, (double)(unsigned int)35);
|
||||
ASSERT(35, (double)(unsigned long)35);
|
||||
|
||||
ASSERT(35, (char)(float)35);
|
||||
ASSERT(35, (short)(float)35);
|
||||
ASSERT(35, (int)(float)35);
|
||||
ASSERT(35, (long)(float)35);
|
||||
ASSERT(35, (unsigned char)(float)35);
|
||||
ASSERT(35, (unsigned short)(float)35);
|
||||
ASSERT(35, (unsigned int)(float)35);
|
||||
ASSERT(35, (unsigned long)(float)35);
|
||||
|
||||
ASSERT(35, (char)(double)35);
|
||||
ASSERT(35, (short)(double)35);
|
||||
ASSERT(35, (int)(double)35);
|
||||
ASSERT(35, (long)(double)35);
|
||||
ASSERT(35, (unsigned char)(double)35);
|
||||
ASSERT(35, (unsigned short)(double)35);
|
||||
ASSERT(35, (unsigned int)(double)35);
|
||||
ASSERT(35, (unsigned long)(double)35);
|
||||
|
||||
ASSERT(0x8000000000000000, (double)(unsigned long)(long)-1);
|
||||
|
||||
ASSERT(1, 2e3 == 2e3);
|
||||
ASSERT(0, 2e3 == 2e5);
|
||||
ASSERT(1, 2.0 == 2);
|
||||
ASSERT(0, 5.1 < 5);
|
||||
ASSERT(0, 5.0 < 5);
|
||||
ASSERT(1, 4.9 < 5);
|
||||
ASSERT(0, 5.1 <= 5);
|
||||
ASSERT(1, 5.0 <= 5);
|
||||
ASSERT(1, 4.9 <= 5);
|
||||
|
||||
ASSERT(1, 2e3f == 2e3);
|
||||
ASSERT(0, 2e3f == 2e5);
|
||||
ASSERT(1, 2.0f == 2);
|
||||
ASSERT(0, 5.1f < 5);
|
||||
ASSERT(0, 5.0f < 5);
|
||||
ASSERT(1, 4.9f < 5);
|
||||
ASSERT(0, 5.1f <= 5);
|
||||
ASSERT(1, 5.0f <= 5);
|
||||
ASSERT(1, 4.9f <= 5);
|
||||
|
||||
ASSERT(6, 2.3 + 3.8);
|
||||
ASSERT(-1, 2.3 - 3.8);
|
||||
ASSERT(-3, -3.8);
|
||||
ASSERT(13, 3.3 * 4);
|
||||
ASSERT(2, 5.0 / 2);
|
||||
|
||||
ASSERT(6, 2.3f + 3.8f);
|
||||
ASSERT(6, 2.3f + 3.8);
|
||||
ASSERT(-1, 2.3f - 3.8);
|
||||
ASSERT(-3, -3.8f);
|
||||
ASSERT(13, 3.3f * 4);
|
||||
ASSERT(2, 5.0f / 2);
|
||||
|
||||
ASSERT(0, 0.0 / 0.0 == 0.0 / 0.0);
|
||||
ASSERT(1, 0.0 / 0.0 != 0.0 / 0.0);
|
||||
|
||||
ASSERT(0, 0.0 / 0.0 < 0);
|
||||
ASSERT(0, 0.0 / 0.0 <= 0);
|
||||
ASSERT(0, 0.0 / 0.0 > 0);
|
||||
ASSERT(0, 0.0 / 0.0 >= 0);
|
||||
|
||||
ASSERT(0, !3.);
|
||||
ASSERT(1, !0.);
|
||||
ASSERT(0, !3.f);
|
||||
ASSERT(1, !0.f);
|
||||
|
||||
ASSERT(5, 0.0 ? 3 : 5);
|
||||
ASSERT(3, 1.2 ? 3 : 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
534
third_party/chibicc/test/function_test.c
vendored
Normal file
534
third_party/chibicc/test/function_test.c
vendored
Normal file
@ -0,0 +1,534 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int ret3(void) {
|
||||
return 3;
|
||||
return 5;
|
||||
}
|
||||
|
||||
int add2(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
int sub2(int x, int y) {
|
||||
return x - y;
|
||||
}
|
||||
|
||||
int add6(int a, int b, int c, int d, int e, int f) {
|
||||
return a + b + c + d + e + f;
|
||||
}
|
||||
|
||||
int addx(int *x, int y) {
|
||||
return *x + y;
|
||||
}
|
||||
|
||||
int sub_char(char a, char b, char c) {
|
||||
return a - b - c;
|
||||
}
|
||||
|
||||
int fib(int x) {
|
||||
if (x <= 1) return 1;
|
||||
return fib(x - 1) + fib(x - 2);
|
||||
}
|
||||
|
||||
int sub_long(long a, long b, long c) {
|
||||
return a - b - c;
|
||||
}
|
||||
|
||||
int sub_short(short a, short b, short c) {
|
||||
return a - b - c;
|
||||
}
|
||||
|
||||
int g1;
|
||||
|
||||
int *g1_ptr(void) {
|
||||
return &g1;
|
||||
}
|
||||
char int_to_char(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int div_long(long a, long b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
_Bool bool_fn_add(_Bool x) {
|
||||
return x + 1;
|
||||
}
|
||||
_Bool bool_fn_sub(_Bool x) {
|
||||
return x - 1;
|
||||
}
|
||||
|
||||
static int static_fn(void) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
int param_decay(int x[]) {
|
||||
return x[0];
|
||||
}
|
||||
|
||||
int counter() {
|
||||
static int i;
|
||||
static int j = 1 + 1;
|
||||
return i++ + j++;
|
||||
}
|
||||
|
||||
void ret_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
_Bool true_fn();
|
||||
_Bool false_fn();
|
||||
char char_fn();
|
||||
short short_fn();
|
||||
|
||||
unsigned char uchar_fn();
|
||||
unsigned short ushort_fn();
|
||||
|
||||
char schar_fn();
|
||||
short sshort_fn();
|
||||
|
||||
int add_all(int n, ...);
|
||||
|
||||
typedef struct {
|
||||
int gp_offset;
|
||||
int fp_offset;
|
||||
void *overflow_arg_area;
|
||||
void *reg_save_area;
|
||||
} __va_elem;
|
||||
|
||||
typedef __va_elem va_list[1];
|
||||
|
||||
int add_all(int n, ...);
|
||||
int sprintf(char *buf, char *fmt, ...);
|
||||
int vsprintf(char *buf, char *fmt, va_list ap);
|
||||
|
||||
char *fmt(char *buf, char *fmt, ...) {
|
||||
va_list ap;
|
||||
*ap = *(__va_elem *)__va_area__;
|
||||
vsprintf(buf, fmt, ap);
|
||||
}
|
||||
|
||||
double add_double(double x, double y);
|
||||
float add_float(float x, float y);
|
||||
|
||||
float add_float3(float x, float y, float z) {
|
||||
return x + y + z;
|
||||
}
|
||||
|
||||
double add_double3(double x, double y, double z) {
|
||||
return x + y + z;
|
||||
}
|
||||
|
||||
int (*fnptr(int (*fn)(int n, ...)))(int, ...) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
int param_decay2(int x()) {
|
||||
return x();
|
||||
}
|
||||
|
||||
char *func_fn(void) {
|
||||
return __func__;
|
||||
}
|
||||
|
||||
char *function_fn(void) {
|
||||
return __FUNCTION__;
|
||||
}
|
||||
|
||||
int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8,
|
||||
int x9, int x10);
|
||||
float add10_float(float x1, float x2, float x3, float x4, float x5, float x6,
|
||||
float x7, float x8, float x9, float x10);
|
||||
double add10_double(double x1, double x2, double x3, double x4, double x5,
|
||||
double x6, double x7, double x8, double x9, double x10);
|
||||
|
||||
int many_args1(int a, int b, int c, int d, int e, int f, int g, int h) {
|
||||
return g / h;
|
||||
}
|
||||
|
||||
double many_args2(double a, double b, double c, double d, double e, double f,
|
||||
double g, double h, double i, double j) {
|
||||
return i / j;
|
||||
}
|
||||
|
||||
int many_args3(int a, double b, int c, int d, double e, int f, double g, int h,
|
||||
double i, double j, double k, double l, double m, int n, int o,
|
||||
double p) {
|
||||
return o / p;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int a, b;
|
||||
short c;
|
||||
char d;
|
||||
} Ty4;
|
||||
typedef struct {
|
||||
int a;
|
||||
float b;
|
||||
double c;
|
||||
} Ty5;
|
||||
typedef struct {
|
||||
unsigned char a[3];
|
||||
} Ty6;
|
||||
typedef struct {
|
||||
long a, b, c;
|
||||
} Ty7;
|
||||
|
||||
int struct_test5(Ty5 x, int n);
|
||||
int struct_test4(Ty4 x, int n);
|
||||
int struct_test6(Ty6 x, int n);
|
||||
int struct_test7(Ty7 x, int n);
|
||||
|
||||
int struct_test14(Ty4 x, int n) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return x.a;
|
||||
case 1:
|
||||
return x.b;
|
||||
case 2:
|
||||
return x.c;
|
||||
default:
|
||||
return x.d;
|
||||
}
|
||||
}
|
||||
|
||||
int struct_test15(Ty5 x, int n) {
|
||||
switch (n) {
|
||||
case 0:
|
||||
return x.a;
|
||||
case 1:
|
||||
return x.b;
|
||||
default:
|
||||
return x.c;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned char a[10];
|
||||
} Ty20;
|
||||
typedef struct {
|
||||
unsigned char a[20];
|
||||
} Ty21;
|
||||
|
||||
Ty4 struct_test24(void);
|
||||
Ty5 struct_test25(void);
|
||||
Ty6 struct_test26(void);
|
||||
Ty20 struct_test27(void);
|
||||
Ty21 struct_test28(void);
|
||||
|
||||
Ty4 struct_test34(void) {
|
||||
return (Ty4){10, 20, 30, 40};
|
||||
}
|
||||
|
||||
Ty5 struct_test35(void) {
|
||||
return (Ty5){10, 20, 30};
|
||||
}
|
||||
|
||||
Ty6 struct_test36(void) {
|
||||
return (Ty6){10, 20, 30};
|
||||
}
|
||||
|
||||
Ty20 struct_test37(void) {
|
||||
return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
|
||||
}
|
||||
|
||||
Ty21 struct_test38(void) {
|
||||
return (Ty21){1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
}
|
||||
|
||||
inline int inline_fn(void) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
double to_double(long double x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
long double to_ldouble(int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
int main() {
|
||||
FILE *f = fopen("/dev/null", "w");
|
||||
|
||||
ASSERT(3, ret3());
|
||||
ASSERT(8, add2(3, 5));
|
||||
ASSERT(2, sub2(5, 3));
|
||||
ASSERT(21, add6(1, 2, 3, 4, 5, 6));
|
||||
ASSERT(66, add6(1, 2, add6(3, 4, 5, 6, 7, 8), 9, 10, 11));
|
||||
ASSERT(136, add6(1, 2, add6(3, add6(4, 5, 6, 7, 8, 9), 10, 11, 12, 13), 14,
|
||||
15, 16));
|
||||
|
||||
ASSERT(7, add2(3, 4));
|
||||
ASSERT(1, sub2(4, 3));
|
||||
ASSERT(55, fib(9));
|
||||
|
||||
ASSERT(1, ({ sub_char(7, 3, 3); }));
|
||||
|
||||
ASSERT(1, sub_long(7, 3, 3));
|
||||
ASSERT(1, sub_short(7, 3, 3));
|
||||
|
||||
g1 = 3;
|
||||
|
||||
ASSERT(3, *g1_ptr());
|
||||
ASSERT(5, int_to_char(261));
|
||||
ASSERT(5, int_to_char(261));
|
||||
ASSERT(-5, div_long(-10, 2));
|
||||
|
||||
ASSERT(1, bool_fn_add(3));
|
||||
ASSERT(0, bool_fn_sub(3));
|
||||
ASSERT(1, bool_fn_add(-3));
|
||||
ASSERT(0, bool_fn_sub(-3));
|
||||
ASSERT(1, bool_fn_add(0));
|
||||
ASSERT(1, bool_fn_sub(0));
|
||||
|
||||
ASSERT(3, static_fn());
|
||||
|
||||
ASSERT(3, ({
|
||||
int x[2];
|
||||
x[0] = 3;
|
||||
param_decay(x);
|
||||
}));
|
||||
|
||||
ASSERT(2, counter());
|
||||
ASSERT(4, counter());
|
||||
ASSERT(6, counter());
|
||||
|
||||
ret_none();
|
||||
|
||||
ASSERT(1, true_fn());
|
||||
ASSERT(0, false_fn());
|
||||
ASSERT(3, char_fn());
|
||||
ASSERT(5, short_fn());
|
||||
|
||||
ASSERT(6, add_all(3, 1, 2, 3));
|
||||
ASSERT(5, add_all(4, 1, 2, 3, -1));
|
||||
|
||||
{
|
||||
char buf[100];
|
||||
fmt(buf, "%d %d %s", 1, 2, "foo");
|
||||
fprintf(f, "%s\n", buf);
|
||||
}
|
||||
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
sprintf(buf, "%d %d %s", 1, 2, "foo");
|
||||
strcmp("1 2 foo", buf);
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
fmt(buf, "%d %d %s", 1, 2, "foo");
|
||||
strcmp("1 2 foo", buf);
|
||||
}));
|
||||
|
||||
ASSERT(251, uchar_fn());
|
||||
ASSERT(65528, ushort_fn());
|
||||
ASSERT(-5, schar_fn());
|
||||
ASSERT(-8, sshort_fn());
|
||||
|
||||
ASSERT(6, add_float(2.3, 3.8));
|
||||
ASSERT(6, add_double(2.3, 3.8));
|
||||
|
||||
ASSERT(7, add_float3(2.5, 2.5, 2.5));
|
||||
ASSERT(7, add_double3(2.5, 2.5, 2.5));
|
||||
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
sprintf(buf, "%.1f", (float)3.5);
|
||||
strcmp(buf, "3.5");
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
fmt(buf, "%.1f", (float)3.5);
|
||||
strcmp(buf, "3.5");
|
||||
}));
|
||||
|
||||
ASSERT(5, (add2)(2, 3));
|
||||
ASSERT(5, (&add2)(2, 3));
|
||||
ASSERT(7, ({
|
||||
int (*fn)(int, int) = add2;
|
||||
fn(2, 5);
|
||||
}));
|
||||
ASSERT(6, fnptr(add_all)(3, 1, 2, 3));
|
||||
|
||||
ASSERT(3, param_decay2(ret3));
|
||||
|
||||
ASSERT(5, sizeof(__func__));
|
||||
ASSERT(0, strcmp("main", __func__));
|
||||
ASSERT(0, strcmp("func_fn", func_fn()));
|
||||
ASSERT(0, strcmp("main", __FUNCTION__));
|
||||
ASSERT(0, strcmp("function_fn", function_fn()));
|
||||
|
||||
ASSERT(55, add10_int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
ASSERT(55, add10_float(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
ASSERT(55, add10_double(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
|
||||
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);
|
||||
}));
|
||||
|
||||
ASSERT(4, many_args1(1, 2, 3, 4, 5, 6, 40, 10));
|
||||
ASSERT(4, many_args2(1, 2, 3, 4, 5, 6, 7, 8, 40, 10));
|
||||
ASSERT(8, many_args3(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 80, 10));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test4(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test4(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test4(x, 2);
|
||||
}));
|
||||
ASSERT(40, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test4(x, 3);
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test5(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test5(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test5(x, 2);
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty6 x = {10, 20, 30};
|
||||
struct_test6(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty6 x = {10, 20, 30};
|
||||
struct_test6(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty6 x = {10, 20, 30};
|
||||
struct_test6(x, 2);
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty7 x = {10, 20, 30};
|
||||
struct_test7(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty7 x = {10, 20, 30};
|
||||
struct_test7(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty7 x = {10, 20, 30};
|
||||
struct_test7(x, 2);
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test14(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test14(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test14(x, 2);
|
||||
}));
|
||||
ASSERT(40, ({
|
||||
Ty4 x = {10, 20, 30, 40};
|
||||
struct_test14(x, 3);
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test15(x, 0);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test15(x, 1);
|
||||
}));
|
||||
ASSERT(30, ({
|
||||
Ty5 x = {10, 20, 30};
|
||||
struct_test15(x, 2);
|
||||
}));
|
||||
|
||||
ASSERT(10, struct_test24().a);
|
||||
ASSERT(20, struct_test24().b);
|
||||
ASSERT(30, struct_test24().c);
|
||||
ASSERT(40, struct_test24().d);
|
||||
|
||||
ASSERT(10, struct_test25().a);
|
||||
ASSERT(20, struct_test25().b);
|
||||
ASSERT(30, struct_test25().c);
|
||||
|
||||
ASSERT(10, struct_test26().a[0]);
|
||||
ASSERT(20, struct_test26().a[1]);
|
||||
ASSERT(30, struct_test26().a[2]);
|
||||
|
||||
ASSERT(10, struct_test27().a[0]);
|
||||
ASSERT(60, struct_test27().a[5]);
|
||||
ASSERT(100, struct_test27().a[9]);
|
||||
|
||||
ASSERT(1, struct_test28().a[0]);
|
||||
ASSERT(5, struct_test28().a[4]);
|
||||
ASSERT(10, struct_test28().a[9]);
|
||||
ASSERT(15, struct_test28().a[14]);
|
||||
ASSERT(20, struct_test28().a[19]);
|
||||
|
||||
ASSERT(10, struct_test34().a);
|
||||
ASSERT(20, struct_test34().b);
|
||||
ASSERT(30, struct_test34().c);
|
||||
ASSERT(40, struct_test34().d);
|
||||
|
||||
ASSERT(10, struct_test35().a);
|
||||
ASSERT(20, struct_test35().b);
|
||||
ASSERT(30, struct_test35().c);
|
||||
|
||||
ASSERT(10, struct_test36().a[0]);
|
||||
ASSERT(20, struct_test36().a[1]);
|
||||
ASSERT(30, struct_test36().a[2]);
|
||||
|
||||
ASSERT(10, struct_test37().a[0]);
|
||||
ASSERT(60, struct_test37().a[5]);
|
||||
ASSERT(100, struct_test37().a[9]);
|
||||
|
||||
ASSERT(1, struct_test38().a[0]);
|
||||
ASSERT(5, struct_test38().a[4]);
|
||||
ASSERT(10, struct_test38().a[9]);
|
||||
ASSERT(15, struct_test38().a[14]);
|
||||
ASSERT(20, struct_test38().a[19]);
|
||||
|
||||
ASSERT(5, (***add2)(2, 3));
|
||||
|
||||
ASSERT(3, inline_fn());
|
||||
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
sprintf(buf, "%Lf", (long double)12.3);
|
||||
strncmp(buf, "12.3", 4);
|
||||
}));
|
||||
|
||||
ASSERT(1, to_double(3.5) == 3.5);
|
||||
ASSERT(0, to_double(3.5) == 3);
|
||||
|
||||
ASSERT(1, (long double)5.0 == (long double)5.0);
|
||||
ASSERT(0, (long double)5.0 == (long double)5.2);
|
||||
|
||||
ASSERT(1, to_ldouble(5.0) == 5.0);
|
||||
ASSERT(0, to_ldouble(5.0) == 5.2);
|
||||
}
|
||||
10
third_party/chibicc/test/generic_test.c
vendored
Normal file
10
third_party/chibicc/test/generic_test.c
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(1, _Generic(100.0, double : 1, int * : 2, int : 3, float : 4));
|
||||
ASSERT(2, _Generic((int *)0, double : 1, int * : 2, int : 3, float : 4));
|
||||
ASSERT(2, _Generic((int[3]){}, double : 1, int * : 2, int : 3, float : 4));
|
||||
ASSERT(3, _Generic(100, double : 1, int * : 2, int : 3, float : 4));
|
||||
ASSERT(4, _Generic(100f, double : 1, int * : 2, int : 3, float : 4));
|
||||
return 0;
|
||||
}
|
||||
5
third_party/chibicc/test/include1.h
vendored
Normal file
5
third_party/chibicc/test/include1.h
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#include "third_party/chibicc/test/include2.h"
|
||||
|
||||
char *include1_filename = __FILE__;
|
||||
int include1_line = __LINE__;
|
||||
int include1 = 5;
|
||||
1
third_party/chibicc/test/include2.h
vendored
Normal file
1
third_party/chibicc/test/include2.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
int include2 = 7;
|
||||
1
third_party/chibicc/test/include3.h
vendored
Normal file
1
third_party/chibicc/test/include3.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
#define foo 3
|
||||
1
third_party/chibicc/test/include4.h
vendored
Normal file
1
third_party/chibicc/test/include4.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
#define foo 4
|
||||
793
third_party/chibicc/test/initializer_test.c
vendored
Normal file
793
third_party/chibicc/test/initializer_test.c
vendored
Normal file
@ -0,0 +1,793 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
char g3 = 3;
|
||||
short g4 = 4;
|
||||
int g5 = 5;
|
||||
long g6 = 6;
|
||||
int g9[3] = {0, 1, 2};
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} g11[2] = {{1, 2}, {3, 4}};
|
||||
struct {
|
||||
int a[2];
|
||||
} g12[2] = {{{1, 2}}};
|
||||
union {
|
||||
int a;
|
||||
char b[8];
|
||||
} g13[2] = {0x01020304, 0x05060708};
|
||||
char g17[] = "foobar";
|
||||
char g18[10] = "foobar";
|
||||
char g19[3] = "foobar";
|
||||
char *g20 = g17 + 0;
|
||||
char *g21 = g17 + 3;
|
||||
char *g22 = &g17 - 3;
|
||||
char *g23[] = {g17 + 0, g17 + 3, g17 - 3};
|
||||
int g24 = 3;
|
||||
int *g25 = &g24;
|
||||
int g26[3] = {1, 2, 3};
|
||||
int *g27 = g26 + 1;
|
||||
int *g28 = &g11[1].a;
|
||||
long g29 = (long)(long)g26;
|
||||
struct {
|
||||
struct {
|
||||
int a[3];
|
||||
} a;
|
||||
} g30 = {{{1, 2, 3}}};
|
||||
int *g31 = g30.a.a;
|
||||
struct {
|
||||
int a[2];
|
||||
} g40[2] = {{1, 2}, 3, 4};
|
||||
struct {
|
||||
int a[2];
|
||||
} g41[2] = {1, 2, 3, 4};
|
||||
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
|
||||
char *g44 = {"foo"};
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} g50 = {.b[2] = 0x12};
|
||||
union {
|
||||
int a;
|
||||
} g51[2] = {};
|
||||
|
||||
typedef char T60[];
|
||||
T60 g60 = {1, 2, 3};
|
||||
T60 g61 = {1, 2, 3, 4, 5, 6};
|
||||
|
||||
typedef struct {
|
||||
char a, b[];
|
||||
} T65;
|
||||
T65 g65 = {'f', 'o', 'o', 0};
|
||||
T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0};
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[2];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int x[2][3] = {{1, 2, 3}, {4, 5, 6}};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[3] = {};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {{1, 2}};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT('a', ({
|
||||
char x[4] = "abc";
|
||||
x[0];
|
||||
}));
|
||||
ASSERT('c', ({
|
||||
char x[4] = "abc";
|
||||
x[2];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[4] = "abc";
|
||||
x[3];
|
||||
}));
|
||||
ASSERT('a', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[0][3];
|
||||
}));
|
||||
ASSERT('d', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT('f', ({
|
||||
char x[2][4] = {"abc", "def"};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
int x[] = {1, 2, 3, 4};
|
||||
x[3];
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
int x[] = {1, 2, 3, 4};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[] = "foo";
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
typedef char T[];
|
||||
T x = "foo";
|
||||
T y = "x";
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef char T[];
|
||||
T x = "foo";
|
||||
T y = "x";
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef char T[];
|
||||
T x = "x";
|
||||
T y = "foo";
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
typedef char T[];
|
||||
T x = "x";
|
||||
T y = "foo";
|
||||
sizeof(y);
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1, 2, 3};
|
||||
x.c;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} x = {1};
|
||||
x.c;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[0].b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[1].a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}, {3, 4}};
|
||||
x[1].b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {{1, 2}};
|
||||
x[1].b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x = {};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x = {};
|
||||
x.b;
|
||||
}));
|
||||
|
||||
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;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y, z;
|
||||
z = y = x;
|
||||
z.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y = x;
|
||||
y.a;
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x = {0x01020304};
|
||||
x.b[0];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x = {0x01020304};
|
||||
x.b[1];
|
||||
}));
|
||||
|
||||
ASSERT(0x01020304, ({
|
||||
union {
|
||||
struct {
|
||||
char a, b, c, d;
|
||||
} e;
|
||||
int f;
|
||||
} x = {{4, 3, 2, 1}};
|
||||
x.f;
|
||||
}));
|
||||
|
||||
ASSERT(3, g3);
|
||||
ASSERT(4, g4);
|
||||
ASSERT(5, g5);
|
||||
ASSERT(6, g6);
|
||||
|
||||
ASSERT(0, g9[0]);
|
||||
ASSERT(1, g9[1]);
|
||||
ASSERT(2, g9[2]);
|
||||
|
||||
ASSERT(1, g11[0].a);
|
||||
ASSERT(2, g11[0].b);
|
||||
ASSERT(3, g11[1].a);
|
||||
ASSERT(4, g11[1].b);
|
||||
|
||||
ASSERT(1, g12[0].a[0]);
|
||||
ASSERT(2, g12[0].a[1]);
|
||||
ASSERT(0, g12[1].a[0]);
|
||||
ASSERT(0, g12[1].a[1]);
|
||||
|
||||
ASSERT(4, g13[0].b[0]);
|
||||
ASSERT(3, g13[0].b[1]);
|
||||
ASSERT(8, g13[1].b[0]);
|
||||
ASSERT(7, g13[1].b[1]);
|
||||
|
||||
ASSERT(7, sizeof(g17));
|
||||
ASSERT(10, sizeof(g18));
|
||||
ASSERT(3, sizeof(g19));
|
||||
|
||||
ASSERT(0, memcmp(g17, "foobar", 7));
|
||||
ASSERT(0, memcmp(g18, "foobar\0\0\0", 10));
|
||||
ASSERT(0, memcmp(g19, "foo", 3));
|
||||
|
||||
ASSERT(0, strcmp(g20, "foobar"));
|
||||
ASSERT(0, strcmp(g21, "bar"));
|
||||
ASSERT(0, strcmp(g22 + 3, "foobar"));
|
||||
|
||||
ASSERT(0, strcmp(g23[0], "foobar"));
|
||||
ASSERT(0, strcmp(g23[1], "bar"));
|
||||
ASSERT(0, strcmp(g23[2] + 3, "foobar"));
|
||||
|
||||
ASSERT(3, g24);
|
||||
ASSERT(3, *g25);
|
||||
ASSERT(2, *g27);
|
||||
ASSERT(3, *g28);
|
||||
ASSERT(1, *(int *)g29);
|
||||
|
||||
ASSERT(1, g31[0]);
|
||||
ASSERT(2, g31[1]);
|
||||
ASSERT(3, g31[2]);
|
||||
|
||||
ASSERT(1, g40[0].a[0]);
|
||||
ASSERT(2, g40[0].a[1]);
|
||||
ASSERT(3, g40[1].a[0]);
|
||||
ASSERT(4, g40[1].a[1]);
|
||||
|
||||
ASSERT(1, g41[0].a[0]);
|
||||
ASSERT(2, g41[0].a[1]);
|
||||
ASSERT(3, g41[1].a[0]);
|
||||
ASSERT(4, g41[1].a[1]);
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[2][3] = {0, 1, 2, 3, 4, 5};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3] = {0, 1, 2, 3, 4, 5};
|
||||
x[1][0];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {0, 1, 2, 3};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x[2] = {0, 1, 2, 3};
|
||||
x[1].a;
|
||||
}));
|
||||
|
||||
ASSERT(0, strcmp(g43[0], "foo"));
|
||||
ASSERT(0, strcmp(g43[1], "bar"));
|
||||
ASSERT(0, strcmp(g44, "foo"));
|
||||
|
||||
ASSERT(3, ({
|
||||
int a[] = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
a[2];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a, b, c;
|
||||
} x = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
enum {
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
};
|
||||
z;
|
||||
}));
|
||||
|
||||
ASSERT(3, sizeof(g60));
|
||||
ASSERT(6, sizeof(g61));
|
||||
|
||||
ASSERT(4, sizeof(g65));
|
||||
ASSERT(7, sizeof(g66));
|
||||
ASSERT(0, strcmp(g65.b, "oo"));
|
||||
ASSERT(0, strcmp(g66.b, "oobar"));
|
||||
|
||||
ASSERT(4, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[3] = {1, 2, 3, [0] = 4, 5};
|
||||
x[2];
|
||||
}));
|
||||
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
|
||||
ASSERT(7, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[0][2];
|
||||
}));
|
||||
ASSERT(9, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][1];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10};
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
ASSERT(7, ((int[10]){[3] = 7})[3]);
|
||||
ASSERT(0, ((int[10]){[3] = 7})[4]);
|
||||
|
||||
ASSERT(10, ({
|
||||
char x[] = {[10 - 3] = 1, 2, 3};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
char x[][2] = {[8][1] = 1, 2};
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(3, sizeof(g60));
|
||||
ASSERT(6, sizeof(g61));
|
||||
|
||||
ASSERT(4, sizeof(g65));
|
||||
ASSERT(7, sizeof(g66));
|
||||
ASSERT(0, strcmp(g65.b, "oo"));
|
||||
ASSERT(0, strcmp(g66.b, "oobar"));
|
||||
|
||||
ASSERT(7, ((int[10]){[3] 7})[3]);
|
||||
ASSERT(0, ((int[10]){[3] 7})[4]);
|
||||
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x = {1, 2, .b = 3, .a = 4};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x = {1, 2, .b = 3, .a = 4};
|
||||
x.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c = 1, 2};
|
||||
x.c.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c = 1, 2};
|
||||
x.c.b;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c.b = 1};
|
||||
x.c.a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x = {.c.b = 1};
|
||||
x.c.b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a = 1, 2};
|
||||
x.a[0];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a = 1, 2};
|
||||
x.a[1];
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a[1] = 1};
|
||||
x.a[0];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a[2];
|
||||
} x = {.a[1] = 1};
|
||||
x.a[1];
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[0].b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[1].a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[1].b;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[2].a;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x[] = {
|
||||
[1].b = 1,
|
||||
2,
|
||||
[0] = 3,
|
||||
4,
|
||||
};
|
||||
x[2].b;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x};
|
||||
y[0].a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x};
|
||||
y[0].b;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x, [0].b = 3};
|
||||
y[0].a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
typedef struct {
|
||||
int a, b;
|
||||
} T;
|
||||
T x = {1, 2};
|
||||
T y[] = {x, [0].b = 3};
|
||||
y[0].b;
|
||||
}));
|
||||
|
||||
ASSERT(5, ((struct { int a, b, c; }){.c = 5}).c);
|
||||
ASSERT(0, ((struct { int a, b, c; }){.c = 5}).a);
|
||||
|
||||
ASSERT(0x00ff, ({
|
||||
union {
|
||||
unsigned short a;
|
||||
char b[2];
|
||||
} x = {.b[0] = 0xff};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0xff00, ({
|
||||
union {
|
||||
unsigned short a;
|
||||
char b[2];
|
||||
} x = {.b[1] = 0xff};
|
||||
x.a;
|
||||
}));
|
||||
|
||||
ASSERT(0x00120000, g50.a);
|
||||
ASSERT(0, g51[0].a);
|
||||
ASSERT(0, g51[1].a);
|
||||
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
};
|
||||
int c;
|
||||
} x = {1, 2, 3, .b = 4, 5};
|
||||
x.c;
|
||||
}));
|
||||
|
||||
ASSERT(16, ({
|
||||
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'};
|
||||
memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
8183
third_party/chibicc/test/int128_test.c
vendored
Normal file
8183
third_party/chibicc/test/int128_test.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
third_party/chibicc/test/line_test.c
vendored
Normal file
20
third_party/chibicc/test/line_test.c
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
#line 500 "foo"
|
||||
ASSERT(501, __LINE__);
|
||||
ASSERT(0, strcmp(__FILE__, "foo"));
|
||||
|
||||
#line 800 "bar"
|
||||
ASSERT(801, __LINE__);
|
||||
ASSERT(0, strcmp(__FILE__, "bar"));
|
||||
|
||||
#line 1
|
||||
ASSERT(2, __LINE__);
|
||||
|
||||
# 200 "xyz" 2 3
|
||||
ASSERT(201, __LINE__);
|
||||
ASSERT(0, strcmp(__FILE__, "xyz"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
108
third_party/chibicc/test/literal_test.c
vendored
Normal file
108
third_party/chibicc/test/literal_test.c
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(97, 'a');
|
||||
ASSERT(10, '\n');
|
||||
ASSERT(-128, '\x80');
|
||||
|
||||
ASSERT(511, 0777);
|
||||
ASSERT(0, 0x0);
|
||||
ASSERT(10, 0xa);
|
||||
ASSERT(10, 0XA);
|
||||
ASSERT(48879, 0xbeef);
|
||||
ASSERT(48879, 0xBEEF);
|
||||
ASSERT(48879, 0XBEEF);
|
||||
ASSERT(0, 0b0);
|
||||
ASSERT(1, 0b1);
|
||||
ASSERT(47, 0b101111);
|
||||
ASSERT(47, 0B101111);
|
||||
|
||||
ASSERT(4, sizeof(0));
|
||||
ASSERT(8, sizeof(0L));
|
||||
ASSERT(8, sizeof(0LU));
|
||||
ASSERT(8, sizeof(0UL));
|
||||
ASSERT(8, sizeof(0LL));
|
||||
ASSERT(8, sizeof(0LLU));
|
||||
ASSERT(8, sizeof(0Ull));
|
||||
ASSERT(8, sizeof(0l));
|
||||
ASSERT(8, sizeof(0ll));
|
||||
ASSERT(8, sizeof(0x0L));
|
||||
ASSERT(8, sizeof(0b0L));
|
||||
ASSERT(4, sizeof(2147483647));
|
||||
ASSERT(8, sizeof(2147483648));
|
||||
ASSERT(-1, 0xffffffffffffffff);
|
||||
ASSERT(8, sizeof(0xffffffffffffffff));
|
||||
ASSERT(4, sizeof(4294967295U));
|
||||
ASSERT(8, sizeof(4294967296U));
|
||||
|
||||
ASSERT(3, -1U >> 30);
|
||||
ASSERT(3, -1Ul >> 62);
|
||||
ASSERT(3, -1ull >> 62);
|
||||
|
||||
ASSERT(1, 0xffffffffffffffffl >> 63);
|
||||
ASSERT(1, 0xffffffffffffffffll >> 63);
|
||||
|
||||
ASSERT(-1, 18446744073709551615);
|
||||
ASSERT(8, sizeof(18446744073709551615));
|
||||
ASSERT(-1, 18446744073709551615 >> 63);
|
||||
|
||||
ASSERT(-1, 0xffffffffffffffff);
|
||||
ASSERT(8, sizeof(0xffffffffffffffff));
|
||||
ASSERT(1, 0xffffffffffffffff >> 63);
|
||||
|
||||
ASSERT(-1, 01777777777777777777777);
|
||||
ASSERT(8, sizeof(01777777777777777777777));
|
||||
ASSERT(1, 01777777777777777777777 >> 63);
|
||||
|
||||
ASSERT(-1,
|
||||
0b1111111111111111111111111111111111111111111111111111111111111111);
|
||||
ASSERT(
|
||||
8,
|
||||
sizeof(
|
||||
0b1111111111111111111111111111111111111111111111111111111111111111));
|
||||
ASSERT(
|
||||
1,
|
||||
0b1111111111111111111111111111111111111111111111111111111111111111 >> 63);
|
||||
|
||||
ASSERT(8, sizeof(2147483648));
|
||||
ASSERT(4, sizeof(2147483647));
|
||||
|
||||
ASSERT(8, sizeof(0x1ffffffff));
|
||||
ASSERT(4, sizeof(0xffffffff));
|
||||
ASSERT(1, 0xffffffff >> 31);
|
||||
|
||||
ASSERT(8, sizeof(040000000000));
|
||||
ASSERT(4, sizeof(037777777777));
|
||||
ASSERT(1, 037777777777 >> 31);
|
||||
|
||||
ASSERT(8, sizeof(0b111111111111111111111111111111111));
|
||||
ASSERT(4, sizeof(0b11111111111111111111111111111111));
|
||||
ASSERT(1, 0b11111111111111111111111111111111 >> 31);
|
||||
|
||||
ASSERT(-1, 1 << 31 >> 31);
|
||||
ASSERT(-1, 01 << 31 >> 31);
|
||||
ASSERT(-1, 0x1 << 31 >> 31);
|
||||
ASSERT(-1, 0b1 << 31 >> 31);
|
||||
|
||||
0.0;
|
||||
1.0;
|
||||
3e+8;
|
||||
0x10.1p0;
|
||||
.1E4f;
|
||||
|
||||
ASSERT(4, sizeof(8f));
|
||||
ASSERT(4, sizeof(0.3F));
|
||||
ASSERT(8, sizeof(0.));
|
||||
ASSERT(8, sizeof(.0));
|
||||
ASSERT(16, sizeof(5.l));
|
||||
ASSERT(16, sizeof(2.0L));
|
||||
|
||||
Assert(1, size\
|
||||
of(char),
|
||||
"sizeof(char)");
|
||||
|
||||
ASSERT(4, sizeof(L'\0'));
|
||||
ASSERT(97, L'a');
|
||||
|
||||
return 0;
|
||||
}
|
||||
413
third_party/chibicc/test/macro_test.c
vendored
Normal file
413
third_party/chibicc/test/macro_test.c
vendored
Normal file
@ -0,0 +1,413 @@
|
||||
#include "third_party/chibicc/test/include1.h"
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
/* clang-format off */
|
||||
char *main_filename1 = __FILE__;
|
||||
int main_line1 = __LINE__;
|
||||
#define LINE() __LINE__
|
||||
int main_line2 = LINE();
|
||||
|
||||
#
|
||||
|
||||
/* */ #
|
||||
|
||||
int ret3(void) { return 3; }
|
||||
int dbl(int x) { return x*x; }
|
||||
|
||||
int add2(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
int add6(int a, int b, int c, int d, int e, int f) {
|
||||
return a + b + c + d + e + f;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(5, include1);
|
||||
ASSERT(7, include2);
|
||||
|
||||
#if 0
|
||||
#include "/no/such/file"
|
||||
ASSERT(0, 1);
|
||||
#if nested
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int m = 0;
|
||||
|
||||
#if 1
|
||||
m = 5;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
#if 1
|
||||
# if 0
|
||||
# if 1
|
||||
foo bar
|
||||
# endif
|
||||
# endif
|
||||
m = 3;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#if 1-1
|
||||
# if 1
|
||||
# endif
|
||||
# if 1
|
||||
# else
|
||||
# endif
|
||||
# if 0
|
||||
# else
|
||||
# endif
|
||||
m = 2;
|
||||
#else
|
||||
# if 1
|
||||
m = 3;
|
||||
# endif
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#if 1
|
||||
m = 2;
|
||||
#else
|
||||
m = 3;
|
||||
#endif
|
||||
ASSERT(2, m);
|
||||
|
||||
#if 1
|
||||
m = 2;
|
||||
#else
|
||||
m = 3;
|
||||
#endif
|
||||
ASSERT(2, m);
|
||||
|
||||
#if 0
|
||||
m = 1;
|
||||
#elif 0
|
||||
m = 2;
|
||||
#elif 3+5
|
||||
m = 3;
|
||||
#elif 1*5
|
||||
m = 4;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#if 1+5
|
||||
m = 1;
|
||||
#elif 1
|
||||
m = 2;
|
||||
#elif 3
|
||||
m = 2;
|
||||
#endif
|
||||
ASSERT(1, m);
|
||||
|
||||
#if 0
|
||||
m = 1;
|
||||
#elif 1
|
||||
# if 1
|
||||
m = 2;
|
||||
# else
|
||||
m = 3;
|
||||
# endif
|
||||
#else
|
||||
m = 5;
|
||||
#endif
|
||||
ASSERT(2, m);
|
||||
|
||||
int M1 = 5;
|
||||
|
||||
#define M1 3
|
||||
ASSERT(3, M1);
|
||||
#define M1 4
|
||||
ASSERT(4, M1);
|
||||
|
||||
#define M1 3+4+
|
||||
ASSERT(12, M1 5);
|
||||
|
||||
#define M1 3+4
|
||||
ASSERT(23, M1*5);
|
||||
|
||||
#define ASSERT_ Assert(
|
||||
#define if 5
|
||||
#define five "5"
|
||||
#define END )
|
||||
ASSERT_ 5, if, five END;
|
||||
|
||||
#undef ASSERT_
|
||||
#undef if
|
||||
#undef five
|
||||
#undef END
|
||||
|
||||
if (0);
|
||||
|
||||
#define M 5
|
||||
#if M
|
||||
m = 5;
|
||||
#else
|
||||
m = 6;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
#define M 5
|
||||
#if M-5
|
||||
m = 6;
|
||||
#elif M
|
||||
m = 5;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
int M2 = 6;
|
||||
#define M2 M2 + 3
|
||||
ASSERT(9, M2);
|
||||
|
||||
#define M3 M2 + 3
|
||||
ASSERT(12, M3);
|
||||
|
||||
int M4 = 3;
|
||||
#define M4 M5 * 5
|
||||
#define M5 M4 + 2
|
||||
ASSERT(13, M4);
|
||||
|
||||
#ifdef M6
|
||||
m = 5;
|
||||
#else
|
||||
m = 3;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#define M6
|
||||
#ifdef M6
|
||||
m = 5;
|
||||
#else
|
||||
m = 3;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
#ifndef M7
|
||||
m = 3;
|
||||
#else
|
||||
m = 5;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#define M7
|
||||
#ifndef M7
|
||||
m = 3;
|
||||
#else
|
||||
m = 5;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
#if 0
|
||||
#ifdef NO_SUCH_MACRO
|
||||
#endif
|
||||
#ifndef NO_SUCH_MACRO
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
#define M7() 1
|
||||
int M7 = 5;
|
||||
ASSERT(1, M7());
|
||||
ASSERT(5, M7);
|
||||
|
||||
#define M7 ()
|
||||
ASSERT(3, ret3 M7);
|
||||
|
||||
#define M8(x,y) x+y
|
||||
ASSERT(7, M8(3, 4));
|
||||
|
||||
#define M8(x,y) x*y
|
||||
ASSERT(24, M8(3+4, 4+5));
|
||||
|
||||
#define M8(x,y) (x)*(y)
|
||||
ASSERT(63, M8(3+4, 4+5));
|
||||
|
||||
#define M8(x,y) x y
|
||||
ASSERT(9, M8(, 4+5));
|
||||
|
||||
#define M8(x,y) x*y
|
||||
ASSERT(20, M8((2+3), 4));
|
||||
|
||||
#define M8(x,y) x*y
|
||||
ASSERT(12, M8((2,3), 4));
|
||||
|
||||
#define dbl(x) M10(x) * x
|
||||
#define M10(x) dbl(x) + 3
|
||||
ASSERT(10, dbl(2));
|
||||
|
||||
#define M11(x) #x
|
||||
ASSERT('a', M11( a!b `""c)[0]);
|
||||
ASSERT('!', M11( a!b `""c)[1]);
|
||||
ASSERT('b', M11( a!b `""c)[2]);
|
||||
ASSERT(' ', M11( a!b `""c)[3]);
|
||||
ASSERT('`', M11( a!b `""c)[4]);
|
||||
ASSERT('"', M11( a!b `""c)[5]);
|
||||
ASSERT('"', M11( a!b `""c)[6]);
|
||||
ASSERT('c', M11( a!b `""c)[7]);
|
||||
ASSERT(0, M11( a!b `""c)[8]);
|
||||
|
||||
#define paste(x,y) x##y
|
||||
ASSERT(15, paste(1,5));
|
||||
ASSERT(255, paste(0,xff));
|
||||
ASSERT(3, ({ int foobar=3; paste(foo,bar); }));
|
||||
ASSERT(5, paste(5,));
|
||||
ASSERT(5, paste(,5));
|
||||
|
||||
#define i 5
|
||||
ASSERT(101, ({ int i3=100; paste(1+i,3); }));
|
||||
#undef i
|
||||
|
||||
#define paste2(x) x##5
|
||||
ASSERT(26, paste2(1+2));
|
||||
|
||||
#define paste3(x) 2##x
|
||||
ASSERT(23, paste3(1+2));
|
||||
|
||||
#define paste4(x, y, z) x##y##z
|
||||
ASSERT(123, paste4(1,2,3));
|
||||
|
||||
#define M12
|
||||
#if defined(M12)
|
||||
m = 3;
|
||||
#else
|
||||
m = 4;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#define M12
|
||||
#if defined M12
|
||||
m = 3;
|
||||
#else
|
||||
m = 4;
|
||||
#endif
|
||||
ASSERT(3, m);
|
||||
|
||||
#if defined(M12) - 1
|
||||
m = 3;
|
||||
#else
|
||||
m = 4;
|
||||
#endif
|
||||
ASSERT(4, m);
|
||||
|
||||
#if defined(NO_SUCH_MACRO)
|
||||
m = 3;
|
||||
#else
|
||||
m = 4;
|
||||
#endif
|
||||
ASSERT(4, m);
|
||||
|
||||
#if no_such_symbol == 0
|
||||
m = 5;
|
||||
#else
|
||||
m = 6;
|
||||
#endif
|
||||
ASSERT(5, m);
|
||||
|
||||
#define STR(x) #x
|
||||
#define M12(x) STR(x)
|
||||
#define M13(x) M12(foo.x)
|
||||
ASSERT(0, strcmp(M13(bar), "foo.bar"));
|
||||
|
||||
#define M13(x) M12(foo. x)
|
||||
ASSERT(0, strcmp(M13(bar), "foo. bar"));
|
||||
|
||||
#define M12 foo
|
||||
#define M13(x) STR(x)
|
||||
#define M14(x) M13(x.M12)
|
||||
ASSERT(0, strcmp(M14(bar), "bar.foo"));
|
||||
|
||||
#define M14(x) M13(x. M12)
|
||||
ASSERT(0, strcmp(M14(bar), "bar. foo"));
|
||||
|
||||
#include "third_party/chibicc/test/include3.h"
|
||||
ASSERT(3, foo);
|
||||
|
||||
#include "third_party/chibicc/test/include4.h"
|
||||
ASSERT(4, foo);
|
||||
|
||||
#define M13 "third_party/chibicc/test/include3.h"
|
||||
#include M13
|
||||
ASSERT(3, foo);
|
||||
|
||||
#define M13 < third_party/chibicc/test/include4.h
|
||||
#include M13 >
|
||||
ASSERT(4, foo);
|
||||
|
||||
#undef foo
|
||||
|
||||
ASSERT(1, __STDC__);
|
||||
|
||||
ASSERT(0, strcmp(main_filename1, "third_party/chibicc/test/macro_test.c"));
|
||||
ASSERT(5, main_line1);
|
||||
ASSERT(7, main_line2);
|
||||
ASSERT(0, strcmp(include1_filename, "third_party/chibicc/test/include1.h"));
|
||||
ASSERT(4, include1_line);
|
||||
|
||||
#define M14(...) 3
|
||||
ASSERT(3, M14());
|
||||
|
||||
#define M14(...) __VA_ARGS__
|
||||
ASSERT(2, M14() 2);
|
||||
ASSERT(5, M14(5));
|
||||
|
||||
#define M14(...) add2(__VA_ARGS__)
|
||||
ASSERT(8, M14(2, 6));
|
||||
|
||||
#define M14(...) add6(1,2,__VA_ARGS__,6)
|
||||
ASSERT(21, M14(3,4,5));
|
||||
|
||||
#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)
|
||||
ASSERT(21, M14(3,4,5));
|
||||
|
||||
#define M14(args...) 3
|
||||
ASSERT(3, M14());
|
||||
|
||||
#define M14(x, ...) x
|
||||
ASSERT(5, M14(5));
|
||||
|
||||
#define M14(args...) args
|
||||
ASSERT(2, M14() 2);
|
||||
ASSERT(5, M14(5));
|
||||
|
||||
#define M14(args...) add2(args)
|
||||
ASSERT(8, M14(2, 6));
|
||||
|
||||
#define M14(args...) add6(1,2,args,6)
|
||||
ASSERT(21, M14(3,4,5));
|
||||
|
||||
#define M14(x, args...) add6(1,2,x,args,6)
|
||||
ASSERT(21, M14(3,4,5));
|
||||
|
||||
#define M14(x, args...) x
|
||||
ASSERT(5, M14(5));
|
||||
|
||||
#define CONCAT(x,y) x##y
|
||||
ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); }));
|
||||
ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));
|
||||
|
||||
ASSERT(11, strlen(__DATE__));
|
||||
ASSERT(8, strlen(__TIME__));
|
||||
|
||||
ASSERT(0, __COUNTER__);
|
||||
ASSERT(1, __COUNTER__);
|
||||
ASSERT(2, __COUNTER__);
|
||||
|
||||
ASSERT(24, strlen(__TIMESTAMP__));
|
||||
|
||||
ASSERT(0, strcmp(__BASE_FILE__, "third_party/chibicc/test/macro_test.c"));
|
||||
|
||||
#define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||
ASSERT(0, ({ char buf[100]; M30(buf, "foo"); strcmp(buf, "foo"); }));
|
||||
ASSERT(0, ({ char buf[100]; M30(buf, "foo%d", 3); strcmp(buf, "foo3"); }));
|
||||
ASSERT(0, ({ char buf[100]; M30(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); }));
|
||||
|
||||
#define M31(buf, fmt, ...) sprintf(buf, fmt, ## __VA_ARGS__)
|
||||
ASSERT(0, ({ char buf[100]; M31(buf, "foo"); strcmp(buf, "foo"); }));
|
||||
ASSERT(0, ({ char buf[100]; M31(buf, "foo%d", 3); strcmp(buf, "foo3"); }));
|
||||
ASSERT(0, ({ char buf[100]; M31(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); }));
|
||||
|
||||
#define M31(x, y) (1, ##x y)
|
||||
ASSERT(3, M31(, 3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
third_party/chibicc/test/offsetof_test.c
vendored
Normal file
17
third_party/chibicc/test/offsetof_test.c
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
char b;
|
||||
int c;
|
||||
double d;
|
||||
} T;
|
||||
|
||||
int main() {
|
||||
ASSERT(0, offsetof(T, a));
|
||||
ASSERT(4, offsetof(T, b));
|
||||
ASSERT(8, offsetof(T, c));
|
||||
ASSERT(16, offsetof(T, d));
|
||||
|
||||
return 0;
|
||||
}
|
||||
202
third_party/chibicc/test/pointer_test.c
vendored
Normal file
202
third_party/chibicc/test/pointer_test.c
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(3, ({
|
||||
int x = 3;
|
||||
*&x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x = 3;
|
||||
int *y = &x;
|
||||
int **z = &y;
|
||||
**z;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 3;
|
||||
int y = 5;
|
||||
*(&x + 1);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x = 3;
|
||||
int y = 5;
|
||||
*(&y - 1);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 3;
|
||||
int y = 5;
|
||||
*(&x - (-1));
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 3;
|
||||
int *y = &x;
|
||||
*y = 5;
|
||||
x;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int x = 3;
|
||||
int y = 5;
|
||||
*(&x + 1) = 7;
|
||||
y;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
int x = 3;
|
||||
int y = 5;
|
||||
*(&y - 2 + 1) = 7;
|
||||
x;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x = 3;
|
||||
(&x + 2) - &x + 3;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x, y;
|
||||
x = 3;
|
||||
y = 5;
|
||||
x + y;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x = 3, y = 5;
|
||||
x + y;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int x[2];
|
||||
int *y = &x;
|
||||
*y = 3;
|
||||
*x;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
*(x + 1) = 4;
|
||||
*(x + 2) = 5;
|
||||
*x;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
*(x + 1) = 4;
|
||||
*(x + 2) = 5;
|
||||
*(x + 1);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
*(x + 1) = 4;
|
||||
*(x + 2) = 5;
|
||||
*(x + 2);
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*y = 0;
|
||||
**x;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*(y + 1) = 1;
|
||||
*(*x + 1);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*(y + 2) = 2;
|
||||
*(*x + 2);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*(y + 3) = 3;
|
||||
**(x + 1);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*(y + 4) = 4;
|
||||
*(*(x + 1) + 1);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
*(y + 5) = 5;
|
||||
*(*(x + 1) + 2);
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
x[1] = 4;
|
||||
x[2] = 5;
|
||||
*x;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
x[1] = 4;
|
||||
x[2] = 5;
|
||||
*(x + 1);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
x[1] = 4;
|
||||
x[2] = 5;
|
||||
*(x + 2);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
x[1] = 4;
|
||||
x[2] = 5;
|
||||
*(x + 2);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3];
|
||||
*x = 3;
|
||||
x[1] = 4;
|
||||
2 [x] = 5;
|
||||
*(x + 2);
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[0] = 0;
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[1] = 1;
|
||||
x[0][1];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[2] = 2;
|
||||
x[0][2];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[3] = 3;
|
||||
x[1][0];
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[4] = 4;
|
||||
x[1][1];
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[2][3];
|
||||
int *y = x;
|
||||
y[5] = 5;
|
||||
x[1][2];
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
third_party/chibicc/test/pragma-once_test.c
vendored
Normal file
9
third_party/chibicc/test/pragma-once_test.c
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "third_party/chibicc/test/pragma-once_test.c"
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
113
third_party/chibicc/test/sizeof_test.c
vendored
Normal file
113
third_party/chibicc/test/sizeof_test.c
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(1, sizeof(char));
|
||||
ASSERT(2, sizeof(short));
|
||||
ASSERT(2, sizeof(short int));
|
||||
ASSERT(2, sizeof(int short));
|
||||
ASSERT(4, sizeof(int));
|
||||
ASSERT(8, sizeof(long));
|
||||
ASSERT(8, sizeof(long int));
|
||||
ASSERT(8, sizeof(long int));
|
||||
ASSERT(8, sizeof(char *));
|
||||
ASSERT(8, sizeof(int *));
|
||||
ASSERT(8, sizeof(long *));
|
||||
ASSERT(8, sizeof(int **));
|
||||
ASSERT(8, sizeof(int(*)[4]));
|
||||
ASSERT(32, sizeof(int *[4]));
|
||||
ASSERT(16, sizeof(int[4]));
|
||||
ASSERT(48, sizeof(int[3][4]));
|
||||
ASSERT(8, sizeof(struct {
|
||||
int a;
|
||||
int b;
|
||||
}));
|
||||
|
||||
ASSERT(8, sizeof(-10 + (long)5));
|
||||
ASSERT(8, sizeof(-10 - (long)5));
|
||||
ASSERT(8, sizeof(-10 * (long)5));
|
||||
ASSERT(8, sizeof(-10 / (long)5));
|
||||
ASSERT(8, sizeof((long)-10 + 5));
|
||||
ASSERT(8, sizeof((long)-10 - 5));
|
||||
ASSERT(8, sizeof((long)-10 * 5));
|
||||
ASSERT(8, sizeof((long)-10 / 5));
|
||||
|
||||
ASSERT(1, ({
|
||||
char i;
|
||||
sizeof(++i);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char i;
|
||||
sizeof(i++);
|
||||
}));
|
||||
|
||||
ASSERT(8, sizeof(int(*)[10]));
|
||||
ASSERT(8, sizeof(int(*)[][10]));
|
||||
|
||||
ASSERT(4, sizeof(struct { int x, y[]; }));
|
||||
|
||||
ASSERT(1, sizeof(char));
|
||||
ASSERT(1, sizeof(signed char));
|
||||
ASSERT(1, sizeof(signed char signed));
|
||||
ASSERT(1, sizeof(unsigned char));
|
||||
ASSERT(1, sizeof(unsigned char unsigned));
|
||||
|
||||
ASSERT(2, sizeof(short));
|
||||
ASSERT(2, sizeof(int short));
|
||||
ASSERT(2, sizeof(short int));
|
||||
ASSERT(2, sizeof(signed short));
|
||||
ASSERT(2, sizeof(int short signed));
|
||||
ASSERT(2, sizeof(unsigned short));
|
||||
ASSERT(2, sizeof(int short unsigned));
|
||||
|
||||
ASSERT(4, sizeof(int));
|
||||
ASSERT(4, sizeof(signed int));
|
||||
ASSERT(4, sizeof(signed));
|
||||
ASSERT(4, sizeof(signed signed));
|
||||
ASSERT(4, sizeof(unsigned int));
|
||||
ASSERT(4, sizeof(unsigned));
|
||||
ASSERT(4, sizeof(unsigned unsigned));
|
||||
|
||||
ASSERT(8, sizeof(long));
|
||||
ASSERT(8, sizeof(signed long));
|
||||
ASSERT(8, sizeof(signed long int));
|
||||
ASSERT(8, sizeof(unsigned long));
|
||||
ASSERT(8, sizeof(unsigned long int));
|
||||
|
||||
ASSERT(8, sizeof(long long));
|
||||
ASSERT(8, sizeof(signed long long));
|
||||
ASSERT(8, sizeof(signed long long int));
|
||||
ASSERT(8, sizeof(unsigned long long));
|
||||
ASSERT(8, sizeof(unsigned long long int));
|
||||
|
||||
ASSERT(1, sizeof((char)1));
|
||||
ASSERT(2, sizeof((short)1));
|
||||
ASSERT(4, sizeof((int)1));
|
||||
ASSERT(8, sizeof((long)1));
|
||||
|
||||
ASSERT(4, sizeof((char)1 + (char)1));
|
||||
ASSERT(4, sizeof((short)1 + (short)1));
|
||||
ASSERT(4, sizeof(1 ? 2 : 3));
|
||||
ASSERT(4, sizeof(1 ? (short)2 : (char)3));
|
||||
ASSERT(8, sizeof(1 ? (long)2 : (char)3));
|
||||
|
||||
ASSERT(1, sizeof(char) << 31 >> 31);
|
||||
ASSERT(1, sizeof(char) << 63 >> 63);
|
||||
|
||||
ASSERT(4, sizeof(float));
|
||||
ASSERT(8, sizeof(double));
|
||||
|
||||
ASSERT(4, sizeof(1f + 2));
|
||||
ASSERT(8, sizeof(1.0 + 2));
|
||||
ASSERT(4, sizeof(1f - 2));
|
||||
ASSERT(8, sizeof(1.0 - 2));
|
||||
ASSERT(4, sizeof(1f * 2));
|
||||
ASSERT(8, sizeof(1.0 * 2));
|
||||
ASSERT(4, sizeof(1f / 2));
|
||||
ASSERT(8, sizeof(1.0 / 2));
|
||||
|
||||
ASSERT(16, sizeof(long double));
|
||||
|
||||
ASSERT(1, sizeof(main));
|
||||
|
||||
return 0;
|
||||
}
|
||||
105
third_party/chibicc/test/string_test.c
vendored
Normal file
105
third_party/chibicc/test/string_test.c
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(0, ""[0]);
|
||||
ASSERT(1, sizeof(""));
|
||||
|
||||
ASSERT(97, "abc"[0]);
|
||||
ASSERT(98, "abc"[1]);
|
||||
ASSERT(99, "abc"[2]);
|
||||
ASSERT(0, "abc"[3]);
|
||||
ASSERT(4, sizeof("abc"));
|
||||
|
||||
ASSERT(7, "\a"[0]);
|
||||
ASSERT(8, "\b"[0]);
|
||||
ASSERT(9, "\t"[0]);
|
||||
ASSERT(10, "\n"[0]);
|
||||
ASSERT(11, "\v"[0]);
|
||||
ASSERT(12, "\f"[0]);
|
||||
ASSERT(13, "\r"[0]);
|
||||
ASSERT(27, "\e"[0]);
|
||||
|
||||
ASSERT(106, "\j"[0]);
|
||||
ASSERT(107, "\k"[0]);
|
||||
ASSERT(108, "\l"[0]);
|
||||
|
||||
ASSERT(7, "\ax\ny"[0]);
|
||||
ASSERT(120, "\ax\ny"[1]);
|
||||
ASSERT(10, "\ax\ny"[2]);
|
||||
ASSERT(121, "\ax\ny"[3]);
|
||||
|
||||
ASSERT(0, "\0"[0]);
|
||||
ASSERT(16, "\20"[0]);
|
||||
ASSERT(65, "\101"[0]);
|
||||
ASSERT(104, "\1500"[0]);
|
||||
ASSERT(0, "\x00"[0]);
|
||||
ASSERT(119, "\x77"[0]);
|
||||
|
||||
ASSERT(7, sizeof("abc"
|
||||
"def"));
|
||||
ASSERT(9, sizeof("abc"
|
||||
"d"
|
||||
"efgh"));
|
||||
ASSERT(0, strcmp("abc"
|
||||
"d"
|
||||
"\nefgh",
|
||||
"abcd\nefgh"));
|
||||
ASSERT(0, !strcmp("abc"
|
||||
"d",
|
||||
"abcd\nefgh"));
|
||||
ASSERT(0, strcmp("\x9"
|
||||
"0",
|
||||
"\t0"));
|
||||
|
||||
ASSERT(16, sizeof(L"abc"
|
||||
""));
|
||||
|
||||
ASSERT(28, sizeof(L"abc"
|
||||
"def"));
|
||||
ASSERT(28, sizeof(L"abc"
|
||||
L"def"));
|
||||
ASSERT(14, sizeof(u"abc"
|
||||
"def"));
|
||||
ASSERT(14, sizeof(u"abc"
|
||||
u"def"));
|
||||
|
||||
ASSERT(L'a', (L"abc"
|
||||
"def")[0]);
|
||||
ASSERT(L'd', (L"abc"
|
||||
"def")[3]);
|
||||
ASSERT(L'\0', (L"abc"
|
||||
"def")[6]);
|
||||
|
||||
ASSERT(u'a', (u"abc"
|
||||
"def")[0]);
|
||||
ASSERT(u'd', (u"abc"
|
||||
"def")[3]);
|
||||
ASSERT(u'\0', (u"abc"
|
||||
"def")[6]);
|
||||
|
||||
ASSERT(L'あ', ("あ"
|
||||
L"")[0]);
|
||||
ASSERT(0343, ("\343\201\202"
|
||||
L"")[0]);
|
||||
ASSERT(0201, ("\343\201\202"
|
||||
L"")[1]);
|
||||
ASSERT(0202, ("\343\201\202"
|
||||
L"")[2]);
|
||||
ASSERT(0, ("\343\201\202"
|
||||
L"")[3]);
|
||||
|
||||
ASSERT(L'a', ("a"
|
||||
"b"
|
||||
L"c")[0]);
|
||||
ASSERT(L'b', ("a"
|
||||
"b"
|
||||
L"c")[1]);
|
||||
ASSERT(L'c', ("a"
|
||||
"b"
|
||||
L"c")[2]);
|
||||
ASSERT(0, ("a"
|
||||
"b"
|
||||
L"c")[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
379
third_party/chibicc/test/struct_test.c
vendored
Normal file
379
third_party/chibicc/test/struct_test.c
vendored
Normal file
@ -0,0 +1,379 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
x.a = 1;
|
||||
x.b = 2;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
x.a = 1;
|
||||
x.b = 2;
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
char c;
|
||||
} x;
|
||||
x.a = 1;
|
||||
x.b = 2;
|
||||
x.c = 3;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
char c;
|
||||
} x;
|
||||
x.b = 1;
|
||||
x.b = 2;
|
||||
x.c = 3;
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
char c;
|
||||
} x;
|
||||
x.a = 1;
|
||||
x.b = 2;
|
||||
x.c = 3;
|
||||
x.c;
|
||||
}));
|
||||
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
char a;
|
||||
char b;
|
||||
} x[3];
|
||||
char *p = x;
|
||||
p[0] = 0;
|
||||
x[0].a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct {
|
||||
char a;
|
||||
char b;
|
||||
} x[3];
|
||||
char *p = x;
|
||||
p[1] = 1;
|
||||
x[0].b;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
char a;
|
||||
char b;
|
||||
} x[3];
|
||||
char *p = x;
|
||||
p[2] = 2;
|
||||
x[1].a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
char a;
|
||||
char b;
|
||||
} x[3];
|
||||
char *p = x;
|
||||
p[3] = 3;
|
||||
x[1].b;
|
||||
}));
|
||||
|
||||
ASSERT(6, ({
|
||||
struct {
|
||||
char a[3];
|
||||
char b[5];
|
||||
} x;
|
||||
char *p = &x;
|
||||
x.a[0] = 6;
|
||||
p[0];
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
struct {
|
||||
char a[3];
|
||||
char b[5];
|
||||
} x;
|
||||
char *p = &x;
|
||||
x.b[0] = 7;
|
||||
p[3];
|
||||
}));
|
||||
|
||||
ASSERT(6, ({
|
||||
struct {
|
||||
struct {
|
||||
char b;
|
||||
} a;
|
||||
} x;
|
||||
x.a.b = 6;
|
||||
x.a.b;
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
int a;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
struct {
|
||||
int a[3];
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
struct {
|
||||
int a;
|
||||
} x[4];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(24, ({
|
||||
struct {
|
||||
int a[3];
|
||||
} x[2];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct {
|
||||
char a;
|
||||
char b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
struct {
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
char a;
|
||||
int b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct {
|
||||
int a;
|
||||
char b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct t {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
struct t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct t {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
struct t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
struct t {
|
||||
char a[2];
|
||||
};
|
||||
{
|
||||
struct t {
|
||||
char a[4];
|
||||
};
|
||||
}
|
||||
struct t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct t {
|
||||
int x;
|
||||
};
|
||||
int t = 1;
|
||||
struct t y;
|
||||
y.x = 2;
|
||||
t + y.x;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct t {
|
||||
char a;
|
||||
} x;
|
||||
struct t *y = &x;
|
||||
x.a = 3;
|
||||
y->a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
struct t {
|
||||
char a;
|
||||
} x;
|
||||
struct t *y = &x;
|
||||
y->a = 3;
|
||||
x.a;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x, y;
|
||||
x.a = 3;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
struct t {
|
||||
int a, b;
|
||||
};
|
||||
struct t x;
|
||||
x.a = 7;
|
||||
struct t y;
|
||||
struct t *z = &y;
|
||||
*z = x;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
struct t {
|
||||
int a, b;
|
||||
};
|
||||
struct t x;
|
||||
x.a = 7;
|
||||
struct t y, *p = &x, *q = &y;
|
||||
*q = *p;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct t {
|
||||
char a, b;
|
||||
} x, y;
|
||||
x.a = 5;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
int a, b;
|
||||
} x, y;
|
||||
x.a = 3;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
struct t {
|
||||
int a, b;
|
||||
};
|
||||
struct t x;
|
||||
x.a = 7;
|
||||
struct t y;
|
||||
struct t *z = &y;
|
||||
*z = x;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(7, ({
|
||||
struct t {
|
||||
int a, b;
|
||||
};
|
||||
struct t x;
|
||||
x.a = 7;
|
||||
struct t y, *p = &x, *q = &y;
|
||||
*q = *p;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct t {
|
||||
char a, b;
|
||||
} x, y;
|
||||
x.a = 5;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct t {
|
||||
int a;
|
||||
int b;
|
||||
} x;
|
||||
struct t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
struct t {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
struct t y;
|
||||
sizeof(y);
|
||||
}));
|
||||
|
||||
ASSERT(16, ({
|
||||
struct {
|
||||
char a;
|
||||
long b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct {
|
||||
char a;
|
||||
short b;
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
struct foo *bar;
|
||||
sizeof(bar);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
struct T *foo;
|
||||
struct T {
|
||||
int x;
|
||||
};
|
||||
sizeof(struct T);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
struct T {
|
||||
struct T *next;
|
||||
int x;
|
||||
} a;
|
||||
struct T b;
|
||||
b.x = 1;
|
||||
a.next = &b;
|
||||
a.next->x;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
typedef struct T T;
|
||||
struct T {
|
||||
int x;
|
||||
};
|
||||
sizeof(T);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
third_party/chibicc/test/test.h
vendored
Normal file
11
third_party/chibicc/test/test.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define ASSERT(x, y) Assert2(x, y, #y, __FILE__, __LINE__)
|
||||
#define ASSERT128(x, y) Assert128(x, y, #y, __FILE__, __LINE__)
|
||||
|
||||
void Assert(long, long, char *);
|
||||
void Assert2(long, long, char *, char *, int);
|
||||
void Assert128(__int128, __int128, char *, char *, int);
|
||||
100
third_party/chibicc/test/test.mk
vendored
Normal file
100
third_party/chibicc/test/test.mk
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# C Compiler Unit Tests
|
||||
#
|
||||
# OVERVIEW
|
||||
#
|
||||
# This makefile compiles and runs each test twice. The first with
|
||||
# GCC-built chibicc, and a second time with chibicc-built chibicc
|
||||
|
||||
PKGS += THIRD_PARTY_CHIBICC_TEST
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_A = o/$(MODE)/third_party/chibicc/test/test.a
|
||||
THIRD_PARTY_CHIBICC_TEST2_A = o/$(MODE)/third_party/chibicc/test/test2.a
|
||||
THIRD_PARTY_CHIBICC_TEST_FILES := $(wildcard third_party/chibicc/test/*)
|
||||
THIRD_PARTY_CHIBICC_TEST_SRCS = $(filter %.c,$(THIRD_PARTY_CHIBICC_TEST_FILES))
|
||||
THIRD_PARTY_CHIBICC_TEST_SRCS_TEST = $(filter %_test.c,$(THIRD_PARTY_CHIBICC_TEST_SRCS))
|
||||
THIRD_PARTY_CHIBICC_TEST_HDRS = $(filter %.h,$(THIRD_PARTY_CHIBICC_TEST_FILES))
|
||||
THIRD_PARTY_CHIBICC_TEST_TESTS = $(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.ok)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_COMS = \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%.com) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS_TEST:%.c=o/$(MODE)/%2.com)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_OBJS = \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.o)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST2_OBJS = \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.o)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_BINS = \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_COMS) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.dbg)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_CHECKS = \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_COMS:%=%.runs) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_FMT \
|
||||
LIBC_STR \
|
||||
LIBC_STDIO \
|
||||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_UNICODE \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
||||
THIRD_PARTY_CHIBICC_TEST_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A): \
|
||||
third_party/chibicc/test/ \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_OBJS)
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A): \
|
||||
third_party/chibicc/test/ \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_OBJS)
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A).pkg: \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg: \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/test/%.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A) \
|
||||
o/$(MODE)/third_party/chibicc/test/%.chibicc.o \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A) \
|
||||
o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/chibicc/test
|
||||
o/$(MODE)/third_party/chibicc/test: \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_BINS) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_CHECKS) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc.s) \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_SRCS:%.c=o/$(MODE)/%.chibicc2.s)
|
||||
18
third_party/chibicc/test/tls_test.c.todo
vendored
Normal file
18
third_party/chibicc/test/tls_test.c.todo
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
_Thread_local int x;
|
||||
|
||||
void add(void) {
|
||||
x += 3;
|
||||
}
|
||||
|
||||
_Noreturn int test(void) {
|
||||
x = 7;
|
||||
add();
|
||||
ASSERT(10, x);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test();
|
||||
}
|
||||
49
third_party/chibicc/test/typedef_test.c
vendored
Normal file
49
third_party/chibicc/test/typedef_test.c
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
typedef int MyInt, MyInt2[4];
|
||||
typedef int;
|
||||
|
||||
int main() {
|
||||
ASSERT(1, ({
|
||||
typedef int t;
|
||||
t x = 1;
|
||||
x;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
typedef struct {
|
||||
int a;
|
||||
} t;
|
||||
t x;
|
||||
x.a = 1;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
typedef int t;
|
||||
t t = 1;
|
||||
t;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
typedef struct {
|
||||
int a;
|
||||
} t;
|
||||
{ typedef int t; }
|
||||
t x;
|
||||
x.a = 2;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
typedef t;
|
||||
t x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
MyInt x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
MyInt2 x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
third_party/chibicc/test/typeof_test.c
vendored
Normal file
29
third_party/chibicc/test/typeof_test.c
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(3, ({
|
||||
typeof(int) x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
typeof(1) x = 3;
|
||||
x;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
typeof(x) y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int x;
|
||||
typeof(&x) y;
|
||||
sizeof(y);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
typeof("foo") x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(12, sizeof(typeof(struct { int a, b, c; })));
|
||||
|
||||
return 0;
|
||||
}
|
||||
138
third_party/chibicc/test/unicode_test.c
vendored
Normal file
138
third_party/chibicc/test/unicode_test.c
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
/* TODO(jart): shl overflow in read_escaped_char */
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
typedef unsigned short char16_t;
|
||||
typedef unsigned int char32_t;
|
||||
typedef int wchar_t;
|
||||
|
||||
int π = 3;
|
||||
|
||||
int main() {
|
||||
ASSERT(4, sizeof(L'\0'));
|
||||
ASSERT(97, L'a');
|
||||
|
||||
ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3"));
|
||||
ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E"));
|
||||
ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E"));
|
||||
ASSERT(0, strcmp("🌮", "\U0001F32E"));
|
||||
|
||||
ASSERT(-1, L'\xffffffff' >> 31);
|
||||
ASSERT(946, L'β');
|
||||
ASSERT(12354, L'あ');
|
||||
ASSERT(127843, L'🍣');
|
||||
|
||||
ASSERT(2, sizeof(u'\0'));
|
||||
ASSERT(1, u'\xffff' >> 15);
|
||||
ASSERT(97, u'a');
|
||||
ASSERT(946, u'β');
|
||||
ASSERT(12354, u'あ');
|
||||
ASSERT(62307, u'🍣');
|
||||
|
||||
ASSERT(0, strcmp(STR(u'a'), "u'a'"));
|
||||
|
||||
ASSERT(4, sizeof(U'\0'));
|
||||
ASSERT(1, U'\xffffffff' >> 31);
|
||||
ASSERT(97, U'a');
|
||||
ASSERT(946, U'β');
|
||||
ASSERT(12354, U'あ');
|
||||
ASSERT(127843, U'🍣');
|
||||
|
||||
ASSERT(0, strcmp(STR(U'a'), "U'a'"));
|
||||
|
||||
ASSERT(4, sizeof(u8"abc"));
|
||||
ASSERT(0, strcmp(u8"abc", "abc"));
|
||||
|
||||
ASSERT(0, strcmp(STR(u8"a"), "u8\"a\""));
|
||||
|
||||
ASSERT(2, sizeof(u""));
|
||||
ASSERT(10, sizeof(u"\xffzzz"));
|
||||
ASSERT(0, memcmp(u"", "\0\0", 2));
|
||||
ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8));
|
||||
ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8));
|
||||
ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6));
|
||||
ASSERT(u'β', u"βb"[0]);
|
||||
ASSERT(u'b', u"βb"[1]);
|
||||
ASSERT(0, u"βb"[2]);
|
||||
|
||||
ASSERT(0, strcmp(STR(u"a"), "u\"a\""));
|
||||
|
||||
ASSERT(4, sizeof(U""));
|
||||
ASSERT(20, sizeof(U"\xffzzz"));
|
||||
ASSERT(0, memcmp(U"", "\0\0\0\0", 4));
|
||||
ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
|
||||
ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
|
||||
ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8));
|
||||
ASSERT(u'β', U"βb"[0]);
|
||||
ASSERT(u'b', U"βb"[1]);
|
||||
ASSERT(0, U"βb"[2]);
|
||||
ASSERT(1, U"\xffffffff"[0] >> 31);
|
||||
|
||||
ASSERT(0, strcmp(STR(U"a"), "U\"a\""));
|
||||
|
||||
ASSERT(4, sizeof(L""));
|
||||
ASSERT(20, sizeof(L"\xffzzz"));
|
||||
ASSERT(0, memcmp(L"", "\0\0\0\0", 4));
|
||||
ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16));
|
||||
ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16));
|
||||
ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8));
|
||||
ASSERT(u'β', L"βb"[0]);
|
||||
ASSERT(u'b', L"βb"[1]);
|
||||
ASSERT(0, L"βb"[2]);
|
||||
ASSERT(-1, L"\xffffffff"[0] >> 31);
|
||||
|
||||
ASSERT(0, strcmp(STR(L"a"), "L\"a\""));
|
||||
|
||||
ASSERT(u'α', ({
|
||||
char16_t x[] = u"αβ";
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(u'β', ({
|
||||
char16_t x[] = u"αβ";
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
char16_t x[] = u"αβ";
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(U'🤔', ({
|
||||
char32_t x[] = U"🤔x";
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(U'x', ({
|
||||
char32_t x[] = U"🤔x";
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
char32_t x[] = U"🤔x";
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(L'🤔', ({
|
||||
wchar_t x[] = L"🤔x";
|
||||
x[0];
|
||||
}));
|
||||
ASSERT(L'x', ({
|
||||
wchar_t x[] = L"🤔x";
|
||||
x[1];
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
wchar_t x[] = L"🤔x";
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(3, π);
|
||||
ASSERT(3, ({
|
||||
int あβ0¾ = 3;
|
||||
あβ0¾;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int $$$ = 5;
|
||||
$$$;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
132
third_party/chibicc/test/union_test.c
vendored
Normal file
132
third_party/chibicc/test/union_test.c
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(8, ({
|
||||
union {
|
||||
int a;
|
||||
char b[6];
|
||||
} x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x;
|
||||
x.a = 515;
|
||||
x.b[0];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x;
|
||||
x.a = 515;
|
||||
x.b[1];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x;
|
||||
x.a = 515;
|
||||
x.b[2];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
union {
|
||||
int a;
|
||||
char b[4];
|
||||
} x;
|
||||
x.a = 515;
|
||||
x.b[3];
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
union {
|
||||
int a, b;
|
||||
} x, y;
|
||||
x.a = 3;
|
||||
y.a = 5;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
union {
|
||||
struct {
|
||||
int a, b;
|
||||
} c;
|
||||
} x, y;
|
||||
x.c.b = 3;
|
||||
y.c.b = 5;
|
||||
y = x;
|
||||
y.c.b;
|
||||
}));
|
||||
|
||||
ASSERT(0xef, ({
|
||||
union {
|
||||
struct {
|
||||
unsigned char a, b, c, d;
|
||||
};
|
||||
long e;
|
||||
} x;
|
||||
x.e = 0xdeadbeef;
|
||||
x.a;
|
||||
}));
|
||||
ASSERT(0xbe, ({
|
||||
union {
|
||||
struct {
|
||||
unsigned char a, b, c, d;
|
||||
};
|
||||
long e;
|
||||
} x;
|
||||
x.e = 0xdeadbeef;
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(0xad, ({
|
||||
union {
|
||||
struct {
|
||||
unsigned char a, b, c, d;
|
||||
};
|
||||
long e;
|
||||
} x;
|
||||
x.e = 0xdeadbeef;
|
||||
x.c;
|
||||
}));
|
||||
ASSERT(0xde, ({
|
||||
union {
|
||||
struct {
|
||||
unsigned char a, b, c, d;
|
||||
};
|
||||
long e;
|
||||
} x;
|
||||
x.e = 0xdeadbeef;
|
||||
x.d;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
struct {
|
||||
union {
|
||||
int a, b;
|
||||
};
|
||||
union {
|
||||
int c, d;
|
||||
};
|
||||
} x;
|
||||
x.a = 3;
|
||||
x.b;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct {
|
||||
union {
|
||||
int a, b;
|
||||
};
|
||||
union {
|
||||
int c, d;
|
||||
};
|
||||
} x;
|
||||
x.d = 5;
|
||||
x.c;
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
58
third_party/chibicc/test/usualconv_test.c
vendored
Normal file
58
third_party/chibicc/test/usualconv_test.c
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
static int ret10(void) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT((long)-5, -10 + (long)5);
|
||||
ASSERT((long)-15, -10 - (long)5);
|
||||
ASSERT((long)-50, -10 * (long)5);
|
||||
ASSERT((long)-2, -10 / (long)5);
|
||||
|
||||
ASSERT(1, -2 < (long)-1);
|
||||
ASSERT(1, -2 <= (long)-1);
|
||||
ASSERT(0, -2 > (long)-1);
|
||||
ASSERT(0, -2 >= (long)-1);
|
||||
|
||||
ASSERT(1, (long)-2 < -1);
|
||||
ASSERT(1, (long)-2 <= -1);
|
||||
ASSERT(0, (long)-2 > -1);
|
||||
ASSERT(0, (long)-2 >= -1);
|
||||
|
||||
ASSERT(0, 2147483647 + 2147483647 + 2);
|
||||
ASSERT((long)-1, ({
|
||||
long x;
|
||||
x = -1;
|
||||
x;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
char x[3];
|
||||
x[0] = 0;
|
||||
x[1] = 1;
|
||||
x[2] = 2;
|
||||
char *y = x + 1;
|
||||
y[0];
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
char x[3];
|
||||
x[0] = 0;
|
||||
x[1] = 1;
|
||||
x[2] = 2;
|
||||
char *y = x + 1;
|
||||
y[-1];
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
struct t {
|
||||
char a;
|
||||
} x, y;
|
||||
x.a = 5;
|
||||
y = x;
|
||||
y.a;
|
||||
}));
|
||||
|
||||
ASSERT(10, (1 ? ret10 : (void *)0)());
|
||||
|
||||
return 0;
|
||||
}
|
||||
52
third_party/chibicc/test/varargs_test.c
vendored
Normal file
52
third_party/chibicc/test/varargs_test.c
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int sum1(int x, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, x);
|
||||
|
||||
for (;;) {
|
||||
int y = va_arg(ap, int);
|
||||
if (y == 0) return x;
|
||||
x += y;
|
||||
}
|
||||
}
|
||||
|
||||
int sum2(int x, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, x);
|
||||
|
||||
for (;;) {
|
||||
double y = va_arg(ap, double);
|
||||
x += y;
|
||||
|
||||
int z = va_arg(ap, int);
|
||||
if (z == 0) return x;
|
||||
x += z;
|
||||
}
|
||||
}
|
||||
|
||||
void fmt(char *buf, char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
va_list ap2;
|
||||
va_copy(ap2, ap);
|
||||
vsprintf(buf, fmt, ap2);
|
||||
va_end(buf);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ASSERT(6, sum1(1, 2, 3, 0));
|
||||
ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0));
|
||||
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
|
||||
ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0));
|
||||
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));
|
||||
ASSERT(0, ({
|
||||
char buf[100];
|
||||
fmt(buf, "%d %d", 2, 3);
|
||||
strcmp(buf, "2 3");
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
244
third_party/chibicc/test/variable_test.c
vendored
Normal file
244
third_party/chibicc/test/variable_test.c
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int g1, g2[4];
|
||||
static int g3 = 3;
|
||||
|
||||
int main() {
|
||||
ASSERT(3, ({
|
||||
int a;
|
||||
a = 3;
|
||||
a;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int a = 3;
|
||||
a;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int a = 3;
|
||||
int z = 5;
|
||||
a + z;
|
||||
}));
|
||||
|
||||
ASSERT(3, ({
|
||||
int a = 3;
|
||||
a;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int a = 3;
|
||||
int z = 5;
|
||||
a + z;
|
||||
}));
|
||||
ASSERT(6, ({
|
||||
int a;
|
||||
int b;
|
||||
a = b = 3;
|
||||
a + b;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int foo = 3;
|
||||
foo;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int foo123 = 3;
|
||||
int bar = 5;
|
||||
foo123 + bar;
|
||||
}));
|
||||
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x;
|
||||
sizeof x;
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
int *x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
int x[4];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(48, ({
|
||||
int x[3][4];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(16, ({
|
||||
int x[3][4];
|
||||
sizeof(*x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[3][4];
|
||||
sizeof(**x);
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3][4];
|
||||
sizeof(**x) + 1;
|
||||
}));
|
||||
ASSERT(5, ({
|
||||
int x[3][4];
|
||||
sizeof **x + 1;
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x[3][4];
|
||||
sizeof(**x + 1);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
int x = 1;
|
||||
sizeof(x = 2);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x = 1;
|
||||
sizeof(x = 2);
|
||||
x;
|
||||
}));
|
||||
|
||||
ASSERT(0, g1);
|
||||
ASSERT(3, ({
|
||||
g1 = 3;
|
||||
g1;
|
||||
}));
|
||||
ASSERT(0, ({
|
||||
g2[0] = 0;
|
||||
g2[1] = 1;
|
||||
g2[2] = 2;
|
||||
g2[3] = 3;
|
||||
g2[0];
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
g2[0] = 0;
|
||||
g2[1] = 1;
|
||||
g2[2] = 2;
|
||||
g2[3] = 3;
|
||||
g2[1];
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
g2[0] = 0;
|
||||
g2[1] = 1;
|
||||
g2[2] = 2;
|
||||
g2[3] = 3;
|
||||
g2[2];
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
g2[0] = 0;
|
||||
g2[1] = 1;
|
||||
g2[2] = 2;
|
||||
g2[3] = 3;
|
||||
g2[3];
|
||||
}));
|
||||
|
||||
ASSERT(4, sizeof(g1));
|
||||
ASSERT(16, sizeof(g2));
|
||||
|
||||
ASSERT(1, ({
|
||||
char x = 1;
|
||||
x;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char x = 1;
|
||||
char y = 2;
|
||||
x;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
char x = 1;
|
||||
char y = 2;
|
||||
y;
|
||||
}));
|
||||
|
||||
ASSERT(1, ({
|
||||
char x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(10, ({
|
||||
char x[10];
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(2, ({
|
||||
int x = 2;
|
||||
{ int x = 3; }
|
||||
x;
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
int x = 2;
|
||||
{ int x = 3; }
|
||||
int y = 4;
|
||||
x;
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
int x = 2;
|
||||
{ x = 3; }
|
||||
x;
|
||||
}));
|
||||
|
||||
ASSERT(7, ({
|
||||
int x;
|
||||
int y;
|
||||
char z;
|
||||
char *a = &y;
|
||||
char *b = &z;
|
||||
b - a;
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
int x;
|
||||
char y;
|
||||
int z;
|
||||
char *a = &y;
|
||||
char *b = &z;
|
||||
b - a;
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
long x;
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(2, ({
|
||||
short x;
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(24, ({
|
||||
char *x[3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(8, ({
|
||||
char(*x)[3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(1, ({
|
||||
char(x);
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char(x)[3];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
char(x[3])[4];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char(x[3])[4];
|
||||
sizeof(x[0]);
|
||||
}));
|
||||
ASSERT(3, ({
|
||||
char *x[3];
|
||||
char y;
|
||||
x[0] = &y;
|
||||
y = 3;
|
||||
x[0][0];
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char x[3];
|
||||
char(*y)[3] = x;
|
||||
y[0][0] = 4;
|
||||
y[0][0];
|
||||
}));
|
||||
|
||||
{ void *x; }
|
||||
|
||||
ASSERT(3, g3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
56
third_party/chibicc/test/vector_test.c
vendored
Normal file
56
third_party/chibicc/test/vector_test.c
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
typedef float float4 __attribute__((__vector_size__(16)));
|
||||
typedef float float4a1 __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef float float4a16 __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
typedef double double2 __attribute__((__vector_size__(16)));
|
||||
typedef double double2a1 __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
typedef double double2a16 __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
|
||||
int main(void) {
|
||||
ASSERT(16, sizeof(float4));
|
||||
ASSERT(16, sizeof(float4a1));
|
||||
ASSERT(16, sizeof(float4a16));
|
||||
ASSERT(16, sizeof(double2));
|
||||
ASSERT(16, sizeof(double2a1));
|
||||
ASSERT(16, sizeof(double2a16));
|
||||
ASSERT(16, _Alignof(float4));
|
||||
ASSERT(1, _Alignof(float4a1));
|
||||
ASSERT(16, _Alignof(float4a16));
|
||||
ASSERT(16, _Alignof(double2));
|
||||
ASSERT(1, _Alignof(double2a1));
|
||||
ASSERT(16, _Alignof(double2a16));
|
||||
|
||||
float4 v1;
|
||||
float4 v2;
|
||||
float x[4] = {1, 2, 3, 4};
|
||||
float y[4] = {1, 1, 1, 1};
|
||||
memcpy(&v1, x, 16);
|
||||
memcpy(&v2, y, 16);
|
||||
v1 = v1 + v2;
|
||||
memcpy(x, &v1, 16);
|
||||
ASSERT(2, x[0]);
|
||||
/* ASSERT(3, x[1]); */
|
||||
/* ASSERT(4, x[2]); */
|
||||
/* ASSERT(5, x[3]); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
86
third_party/chibicc/test/vla_test.c
vendored
Normal file
86
third_party/chibicc/test/vla_test.c
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(20, ({
|
||||
int n = 5;
|
||||
int x[n];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT((5 + 1) * (8 * 2) * 4, ({
|
||||
int m = 5, n = 8;
|
||||
int x[m + 1][n * 2];
|
||||
sizeof(x);
|
||||
}));
|
||||
|
||||
ASSERT(8, ({
|
||||
char n = 10;
|
||||
int(*x)[n][n + 2];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(480, ({
|
||||
char n = 10;
|
||||
int(*x)[n][n + 2];
|
||||
sizeof(*x);
|
||||
}));
|
||||
ASSERT(48, ({
|
||||
char n = 10;
|
||||
int(*x)[n][n + 2];
|
||||
sizeof(**x);
|
||||
}));
|
||||
ASSERT(4, ({
|
||||
char n = 10;
|
||||
int(*x)[n][n + 2];
|
||||
sizeof(***x);
|
||||
}));
|
||||
|
||||
ASSERT(60, ({
|
||||
char n = 3;
|
||||
int x[5][n];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(12, ({
|
||||
char n = 3;
|
||||
int x[5][n];
|
||||
sizeof(*x);
|
||||
}));
|
||||
|
||||
ASSERT(60, ({
|
||||
char n = 3;
|
||||
int x[n][5];
|
||||
sizeof(x);
|
||||
}));
|
||||
ASSERT(20, ({
|
||||
char n = 3;
|
||||
int x[n][5];
|
||||
sizeof(*x);
|
||||
}));
|
||||
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
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];
|
||||
}));
|
||||
|
||||
ASSERT(10, ({
|
||||
int n = 5;
|
||||
sizeof(char[2][n]);
|
||||
}));
|
||||
|
||||
return 0;
|
||||
}
|
||||
196
third_party/chibicc/tokenize.c
vendored
196
third_party/chibicc/tokenize.c
vendored
@ -1,5 +1,7 @@
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
#define LOOKINGAT(TOK, OP) lookingat(TOK, OP, strlen(OP))
|
||||
|
||||
// Input file
|
||||
static File *current_file;
|
||||
|
||||
@ -30,17 +32,13 @@ static void verror_at(char *filename, char *input, int line_no, char *loc,
|
||||
// Find a line containing `loc`.
|
||||
char *line = loc;
|
||||
while (input < line && line[-1] != '\n') line--;
|
||||
|
||||
char *end = loc;
|
||||
while (*end && *end != '\n') end++;
|
||||
|
||||
// Print out the line.
|
||||
int indent = fprintf(stderr, "%s:%d: ", filename, line_no);
|
||||
fprintf(stderr, "%.*s\n", (int)(end - line), line);
|
||||
|
||||
// Show the error message.
|
||||
int pos = str_width(line, loc - line) + indent;
|
||||
|
||||
fprintf(stderr, "%*s", pos, ""); // print pos spaces.
|
||||
fprintf(stderr, "^ ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
@ -49,9 +47,9 @@ static void verror_at(char *filename, char *input, int line_no, char *loc,
|
||||
|
||||
void error_at(char *loc, char *fmt, ...) {
|
||||
int line_no = 1;
|
||||
for (char *p = current_file->contents; p < loc; p++)
|
||||
for (char *p = current_file->contents; p < loc; p++) {
|
||||
if (*p == '\n') line_no++;
|
||||
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap);
|
||||
@ -59,10 +57,14 @@ void error_at(char *loc, char *fmt, ...) {
|
||||
}
|
||||
|
||||
void error_tok(Token *tok, char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt,
|
||||
ap);
|
||||
va_list ap, va;
|
||||
va_start(va, fmt);
|
||||
for (Token *t = tok; t; t = t->origin) {
|
||||
va_copy(ap, va);
|
||||
verror_at(t->file->name, t->file->contents, t->line_no, t->loc, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_end(va);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -73,19 +75,29 @@ void warn_tok(Token *tok, char *fmt, ...) {
|
||||
ap);
|
||||
}
|
||||
|
||||
forceinline int compare_strings(const char *a, const char *b, size_t n) {
|
||||
size_t i = 0;
|
||||
if (!n-- || a == b) return 0;
|
||||
while (a[i] == b[i] && b[i] && i < n) ++i;
|
||||
return (a[i] & 0xff) - (b[i] & 0xff);
|
||||
}
|
||||
|
||||
static int is_space(int c) {
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
|
||||
c == '\v';
|
||||
}
|
||||
|
||||
static bool lookingat(const char *a, const char *b, size_t n) {
|
||||
return !compare_strings(a, b, n);
|
||||
}
|
||||
|
||||
// Consumes the current token if it matches `op`.
|
||||
bool equal(Token *tok, char *op) {
|
||||
return strlen(op) == tok->len && !strncmp(tok->loc, op, tok->len);
|
||||
bool equal(Token *tok, char *op, size_t n) {
|
||||
return n == tok->len && !compare_strings(tok->loc, op, tok->len);
|
||||
}
|
||||
|
||||
// Ensure that the current token is `op`.
|
||||
Token *skip(Token *tok, char *op) {
|
||||
if (!equal(tok, op)) error_tok(tok, "expected '%s'", op);
|
||||
return tok->next;
|
||||
}
|
||||
|
||||
bool consume(Token **rest, Token *tok, char *str) {
|
||||
if (equal(tok, str)) {
|
||||
bool consume(Token **rest, Token *tok, char *str, size_t n) {
|
||||
if (n == tok->len && !compare_strings(tok->loc, str, n)) {
|
||||
*rest = tok->next;
|
||||
return true;
|
||||
}
|
||||
@ -93,6 +105,12 @@ bool consume(Token **rest, Token *tok, char *str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure that the current token is `op`.
|
||||
Token *skip(Token *tok, char *op) {
|
||||
if (!EQUAL(tok, op)) error_tok(tok, "expected '%s'", op);
|
||||
return tok->next;
|
||||
}
|
||||
|
||||
// Create a new token and add it as the next token of `cur`.
|
||||
static Token *new_token(TokenKind kind, char *start, char *end) {
|
||||
Token *tok = calloc(1, sizeof(Token));
|
||||
@ -103,15 +121,10 @@ static Token *new_token(TokenKind kind, char *start, char *end) {
|
||||
tok->filename = current_file->display_name;
|
||||
tok->at_bol = at_bol;
|
||||
tok->has_space = has_space;
|
||||
|
||||
at_bol = has_space = false;
|
||||
return tok;
|
||||
}
|
||||
|
||||
static bool starts_with(char *p, char *q) {
|
||||
return strncmp(p, q, strlen(q)) == 0;
|
||||
}
|
||||
|
||||
// Read an identifier and returns a pointer pointing to the end
|
||||
// of an identifier.
|
||||
//
|
||||
@ -119,11 +132,12 @@ static bool starts_with(char *p, char *q) {
|
||||
static char *read_ident(char *p) {
|
||||
uint32_t c = decode_utf8(&p, p);
|
||||
if (!is_ident1(c)) return NULL;
|
||||
|
||||
for (;;) {
|
||||
char *q;
|
||||
c = decode_utf8(&q, p);
|
||||
if (!is_ident2(c)) return p;
|
||||
if (!('a' <= c && c <= 'f') && !is_ident2(c)) {
|
||||
return p;
|
||||
}
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
@ -136,7 +150,6 @@ static int from_hex(char c) {
|
||||
|
||||
static bool is_keyword(Token *tok) {
|
||||
static HashMap map;
|
||||
|
||||
if (map.capacity == 0) {
|
||||
static char *kw[] = {
|
||||
"return", "if", "else",
|
||||
@ -155,18 +168,17 @@ static bool is_keyword(Token *tok) {
|
||||
"typeof", "asm", "_Thread_local",
|
||||
"__thread", "_Atomic", "__attribute__",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) {
|
||||
hashmap_put(&map, kw[i], (void *)1);
|
||||
}
|
||||
}
|
||||
|
||||
return hashmap_get2(&map, tok->loc, tok->len);
|
||||
}
|
||||
|
||||
static int read_escaped_char(char **new_pos, char *p) {
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
// Read an octal number.
|
||||
int c = *p++ - '0';
|
||||
unsigned c = *p++ - '0';
|
||||
if ('0' <= *p && *p <= '7') {
|
||||
c = (c << 3) + (*p++ - '0');
|
||||
if ('0' <= *p && *p <= '7') c = (c << 3) + (*p++ - '0');
|
||||
@ -174,20 +186,18 @@ static int read_escaped_char(char **new_pos, char *p) {
|
||||
*new_pos = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
if (*p == 'x') {
|
||||
// Read a hexadecimal number.
|
||||
p++;
|
||||
if (!isxdigit(*p)) error_at(p, "invalid hex escape sequence");
|
||||
|
||||
int c = 0;
|
||||
for (; isxdigit(*p); p++) c = (c << 4) + from_hex(*p);
|
||||
unsigned c = 0;
|
||||
for (; isxdigit(*p); p++) {
|
||||
c = (c << 4) + from_hex(*p); /* TODO(jart): overflow here unicode_test */
|
||||
}
|
||||
*new_pos = p;
|
||||
return c;
|
||||
}
|
||||
|
||||
*new_pos = p + 1;
|
||||
|
||||
switch (*p) {
|
||||
case 'a':
|
||||
return '\a';
|
||||
@ -225,14 +235,12 @@ static Token *read_string_literal(char *start, char *quote) {
|
||||
char *end = string_literal_end(quote + 1);
|
||||
char *buf = calloc(1, end - quote);
|
||||
int len = 0;
|
||||
|
||||
for (char *p = quote + 1; p < end;) {
|
||||
if (*p == '\\')
|
||||
buf[len++] = read_escaped_char(&p, p + 1);
|
||||
else
|
||||
buf[len++] = *p++;
|
||||
}
|
||||
|
||||
Token *tok = new_token(TK_STR, start, end + 1);
|
||||
tok->ty = array_of(ty_char, len + 1);
|
||||
tok->str = buf;
|
||||
@ -250,13 +258,11 @@ static Token *read_utf16_string_literal(char *start, char *quote) {
|
||||
char *end = string_literal_end(quote + 1);
|
||||
uint16_t *buf = calloc(2, end - start - 1);
|
||||
int len = 0;
|
||||
|
||||
for (char *p = quote + 1; p < end;) {
|
||||
if (*p == '\\') {
|
||||
buf[len++] = read_escaped_char(&p, p + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t c = decode_utf8(&p, p);
|
||||
if (c < 0x10000) {
|
||||
// Encode a code point in 2 bytes.
|
||||
@ -268,7 +274,6 @@ static Token *read_utf16_string_literal(char *start, char *quote) {
|
||||
buf[len++] = 0xdc00 + (c & 0x3ff);
|
||||
}
|
||||
}
|
||||
|
||||
Token *tok = new_token(TK_STR, start, end + 1);
|
||||
tok->ty = array_of(ty_ushort, len + 1);
|
||||
tok->str = (char *)buf;
|
||||
@ -283,14 +288,12 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
|
||||
char *end = string_literal_end(quote + 1);
|
||||
uint32_t *buf = calloc(4, end - quote);
|
||||
int len = 0;
|
||||
|
||||
for (char *p = quote + 1; p < end;) {
|
||||
if (*p == '\\')
|
||||
buf[len++] = read_escaped_char(&p, p + 1);
|
||||
else
|
||||
buf[len++] = decode_utf8(&p, p);
|
||||
}
|
||||
|
||||
Token *tok = new_token(TK_STR, start, end + 1);
|
||||
tok->ty = array_of(ty, len + 1);
|
||||
tok->str = (char *)buf;
|
||||
@ -300,16 +303,13 @@ static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
|
||||
static Token *read_char_literal(char *start, char *quote, Type *ty) {
|
||||
char *p = quote + 1;
|
||||
if (*p == '\0') error_at(start, "unclosed char literal");
|
||||
|
||||
int c;
|
||||
if (*p == '\\')
|
||||
c = read_escaped_char(&p, p + 1);
|
||||
else
|
||||
c = decode_utf8(&p, p);
|
||||
|
||||
char *end = strchr(p, '\'');
|
||||
if (!end) error_at(p, "unclosed char literal");
|
||||
|
||||
Token *tok = new_token(TK_NUM, start, end + 1);
|
||||
tok->val = c;
|
||||
tok->ty = ty;
|
||||
@ -318,7 +318,6 @@ static Token *read_char_literal(char *start, char *quote, Type *ty) {
|
||||
|
||||
static bool convert_pp_int(Token *tok) {
|
||||
char *p = tok->loc;
|
||||
|
||||
// Read a binary, octal, decimal or hexadecimal number.
|
||||
int base = 10;
|
||||
if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) {
|
||||
@ -330,22 +329,19 @@ static bool convert_pp_int(Token *tok) {
|
||||
} else if (*p == '0') {
|
||||
base = 8;
|
||||
}
|
||||
|
||||
int64_t val = strtoul(p, &p, base);
|
||||
|
||||
// Read U, L or LL suffixes.
|
||||
bool l = false;
|
||||
bool u = false;
|
||||
|
||||
if (starts_with(p, "LLU") || starts_with(p, "LLu") || starts_with(p, "llU") ||
|
||||
starts_with(p, "llu") || starts_with(p, "ULL") || starts_with(p, "Ull") ||
|
||||
starts_with(p, "uLL") || starts_with(p, "ull")) {
|
||||
if (LOOKINGAT(p, "LLU") || LOOKINGAT(p, "LLu") || LOOKINGAT(p, "llU") ||
|
||||
LOOKINGAT(p, "llu") || LOOKINGAT(p, "ULL") || LOOKINGAT(p, "Ull") ||
|
||||
LOOKINGAT(p, "uLL") || LOOKINGAT(p, "ull")) {
|
||||
p += 3;
|
||||
l = u = true;
|
||||
} else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) {
|
||||
p += 2;
|
||||
l = u = true;
|
||||
} else if (starts_with(p, "LL") || starts_with(p, "ll")) {
|
||||
} else if (LOOKINGAT(p, "LL") || LOOKINGAT(p, "ll")) {
|
||||
p += 2;
|
||||
l = true;
|
||||
} else if (*p == 'L' || *p == 'l') {
|
||||
@ -355,9 +351,7 @@ static bool convert_pp_int(Token *tok) {
|
||||
p++;
|
||||
u = true;
|
||||
}
|
||||
|
||||
if (p != tok->loc + tok->len) return false;
|
||||
|
||||
// Infer a type.
|
||||
Type *ty;
|
||||
if (base == 10) {
|
||||
@ -385,7 +379,6 @@ static bool convert_pp_int(Token *tok) {
|
||||
else
|
||||
ty = ty_int;
|
||||
}
|
||||
|
||||
tok->kind = TK_NUM;
|
||||
tok->val = val;
|
||||
tok->ty = ty;
|
||||
@ -402,11 +395,9 @@ static bool convert_pp_int(Token *tok) {
|
||||
static void convert_pp_number(Token *tok) {
|
||||
// Try to parse as an integer constant.
|
||||
if (convert_pp_int(tok)) return;
|
||||
|
||||
// If it's not an integer, it must be a floating point constant.
|
||||
char *end;
|
||||
long double val = strtold(tok->loc, &end);
|
||||
|
||||
Type *ty;
|
||||
if (*end == 'f' || *end == 'F') {
|
||||
ty = ty_float;
|
||||
@ -417,9 +408,7 @@ static void convert_pp_number(Token *tok) {
|
||||
} else {
|
||||
ty = ty_double;
|
||||
}
|
||||
|
||||
if (tok->loc + tok->len != end) error_tok(tok, "invalid numeric constant");
|
||||
|
||||
tok->kind = TK_NUM;
|
||||
tok->fval = val;
|
||||
tok->ty = ty;
|
||||
@ -438,7 +427,6 @@ void convert_pp_tokens(Token *tok) {
|
||||
static void add_line_numbers(Token *tok) {
|
||||
char *p = current_file->contents;
|
||||
int n = 1;
|
||||
|
||||
do {
|
||||
if (p == tok->loc) {
|
||||
tok->line_no = n;
|
||||
@ -461,32 +449,27 @@ Token *tokenize_string_literal(Token *tok, Type *basety) {
|
||||
// Tokenize a given string and returns new tokens.
|
||||
Token *tokenize(File *file) {
|
||||
current_file = file;
|
||||
|
||||
char *p = file->contents;
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
|
||||
at_bol = true;
|
||||
has_space = false;
|
||||
|
||||
while (*p) {
|
||||
// Skip line comments.
|
||||
if (starts_with(p, "//")) {
|
||||
if (LOOKINGAT(p, "//")) {
|
||||
p += 2;
|
||||
while (*p != '\n') p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip block comments.
|
||||
if (starts_with(p, "/*")) {
|
||||
if (LOOKINGAT(p, "/*")) {
|
||||
char *q = strstr(p + 2, "*/");
|
||||
if (!q) error_at(p, "unclosed block comment");
|
||||
p = q + 2;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip newline.
|
||||
if (*p == '\n') {
|
||||
p++;
|
||||
@ -494,14 +477,12 @@ Token *tokenize(File *file) {
|
||||
has_space = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip whitespace characters.
|
||||
if (isspace(*p)) {
|
||||
if (is_space(*p)) {
|
||||
p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Numeric literal
|
||||
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
|
||||
char *q = p++;
|
||||
@ -516,42 +497,36 @@ Token *tokenize(File *file) {
|
||||
cur = cur->next = new_token(TK_PP_NUM, q, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
// String literal
|
||||
if (*p == '"') {
|
||||
cur = cur->next = read_string_literal(p, p);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// UTF-8 string literal
|
||||
if (starts_with(p, "u8\"")) {
|
||||
if (LOOKINGAT(p, "u8\"")) {
|
||||
cur = cur->next = read_string_literal(p, p + 2);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// UTF-16 string literal
|
||||
if (starts_with(p, "u\"")) {
|
||||
if (LOOKINGAT(p, "u\"")) {
|
||||
cur = cur->next = read_utf16_string_literal(p, p + 1);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wide string literal
|
||||
if (starts_with(p, "L\"")) {
|
||||
if (LOOKINGAT(p, "L\"")) {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// UTF-32 string literal
|
||||
if (starts_with(p, "U\"")) {
|
||||
if (LOOKINGAT(p, "U\"")) {
|
||||
cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Character literal
|
||||
if (*p == '\'') {
|
||||
cur = cur->next = read_char_literal(p, p, ty_int);
|
||||
@ -559,29 +534,25 @@ Token *tokenize(File *file) {
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// UTF-16 character literal
|
||||
if (starts_with(p, "u'")) {
|
||||
if (LOOKINGAT(p, "u'")) {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_ushort);
|
||||
cur->val &= 0xffff;
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wide character literal
|
||||
if (starts_with(p, "L'")) {
|
||||
if (LOOKINGAT(p, "L'")) {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_int);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// UTF-32 character literal
|
||||
if (starts_with(p, "U'")) {
|
||||
if (LOOKINGAT(p, "U'")) {
|
||||
cur = cur->next = read_char_literal(p, p + 1, ty_uint);
|
||||
p += cur->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Identifier or keyword
|
||||
char *q;
|
||||
if ((q = read_ident(p)) != NULL) {
|
||||
@ -589,38 +560,32 @@ Token *tokenize(File *file) {
|
||||
p = q;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Three-letter punctuators
|
||||
if (starts_with(p, "<<=") || starts_with(p, ">>=") ||
|
||||
starts_with(p, "...")) {
|
||||
if (LOOKINGAT(p, "<<=") || LOOKINGAT(p, ">>=") || LOOKINGAT(p, "...")) {
|
||||
cur = cur->next = new_token(TK_RESERVED, p, p + 3);
|
||||
p += 3;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Two-letter punctuators
|
||||
if (starts_with(p, "==") || starts_with(p, "!=") || starts_with(p, "<=") ||
|
||||
starts_with(p, ">=") || starts_with(p, "->") || starts_with(p, "+=") ||
|
||||
starts_with(p, "-=") || starts_with(p, "*=") || starts_with(p, "/=") ||
|
||||
starts_with(p, "++") || starts_with(p, "--") || starts_with(p, "%=") ||
|
||||
starts_with(p, "&=") || starts_with(p, "|=") || starts_with(p, "^=") ||
|
||||
starts_with(p, "&&") || starts_with(p, "||") || starts_with(p, "<<") ||
|
||||
starts_with(p, ">>") || starts_with(p, "##")) {
|
||||
if (LOOKINGAT(p, "==") || LOOKINGAT(p, "!=") || LOOKINGAT(p, "<=") ||
|
||||
LOOKINGAT(p, ">=") || LOOKINGAT(p, "->") || LOOKINGAT(p, "+=") ||
|
||||
LOOKINGAT(p, "-=") || LOOKINGAT(p, "*=") || LOOKINGAT(p, "/=") ||
|
||||
LOOKINGAT(p, "++") || LOOKINGAT(p, "--") || LOOKINGAT(p, "%=") ||
|
||||
LOOKINGAT(p, "&=") || LOOKINGAT(p, "|=") || LOOKINGAT(p, "^=") ||
|
||||
LOOKINGAT(p, "&&") || LOOKINGAT(p, "||") || LOOKINGAT(p, "<<") ||
|
||||
LOOKINGAT(p, ">>") || LOOKINGAT(p, "##")) {
|
||||
cur = cur->next = new_token(TK_RESERVED, p, p + 2);
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single-letter punctuators
|
||||
if (ispunct(*p)) {
|
||||
cur = cur->next = new_token(TK_RESERVED, p, p + 1);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
error_at(p, "invalid token");
|
||||
}
|
||||
|
||||
cur = cur->next = new_token(TK_EOF, p, p);
|
||||
add_line_numbers(head.next);
|
||||
return head.next;
|
||||
@ -629,7 +594,6 @@ Token *tokenize(File *file) {
|
||||
// Returns the contents of a given file.
|
||||
static char *read_file(char *path) {
|
||||
FILE *fp;
|
||||
|
||||
if (strcmp(path, "-") == 0) {
|
||||
// By convention, read from stdin if a given filename is "-".
|
||||
fp = stdin;
|
||||
@ -637,11 +601,9 @@ static char *read_file(char *path) {
|
||||
fp = fopen(path, "r");
|
||||
if (!fp) return NULL;
|
||||
}
|
||||
|
||||
int buflen = 4096;
|
||||
int nread = 0;
|
||||
char *buf = calloc(1, buflen);
|
||||
|
||||
// Read the entire file.
|
||||
for (;;) {
|
||||
int end = buflen - 2; // extra 2 bytes for the trailing "\n\0"
|
||||
@ -653,15 +615,12 @@ static char *read_file(char *path) {
|
||||
buf = realloc(buf, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
if (fp != stdin) fclose(fp);
|
||||
|
||||
// Make sure that the last logical line is properly terminated with '\n'.
|
||||
if (nread > 0 && buf[nread - 1] == '\\')
|
||||
buf[nread - 1] = '\n';
|
||||
else if (nread == 0 || buf[nread - 1] != '\n')
|
||||
buf[nread++] = '\n';
|
||||
|
||||
buf[nread] = '\0';
|
||||
return buf;
|
||||
}
|
||||
@ -682,7 +641,6 @@ File *new_file(char *name, int file_no, char *contents) {
|
||||
// Replaces \r or \r\n with \n.
|
||||
static void canonicalize_newline(char *p) {
|
||||
int i = 0, j = 0;
|
||||
|
||||
while (p[i]) {
|
||||
if (p[i] == '\r' && p[i + 1] == '\n') {
|
||||
i += 2;
|
||||
@ -694,19 +652,16 @@ static void canonicalize_newline(char *p) {
|
||||
p[j++] = p[i++];
|
||||
}
|
||||
}
|
||||
|
||||
p[j] = '\0';
|
||||
}
|
||||
|
||||
// Removes backslashes followed by a newline.
|
||||
static void remove_backslash_newline(char *p) {
|
||||
int i = 0, j = 0;
|
||||
|
||||
// We want to keep the number of newline characters so that
|
||||
// the logical line number matches the physical one.
|
||||
// This counter maintain the number of newlines we have removed.
|
||||
int n = 0;
|
||||
|
||||
while (p[i]) {
|
||||
if (p[i] == '\\' && p[i + 1] == '\n') {
|
||||
i += 2;
|
||||
@ -718,7 +673,6 @@ static void remove_backslash_newline(char *p) {
|
||||
p[j++] = p[i++];
|
||||
}
|
||||
}
|
||||
|
||||
p[j] = '\0';
|
||||
}
|
||||
|
||||
@ -734,9 +688,8 @@ static uint32_t read_universal_char(char *p, int len) {
|
||||
// Replace \u or \U escape sequences with corresponding UTF-8 bytes.
|
||||
static void convert_universal_chars(char *p) {
|
||||
char *q = p;
|
||||
|
||||
while (*p) {
|
||||
if (starts_with(p, "\\u")) {
|
||||
if (LOOKINGAT(p, "\\u")) {
|
||||
uint32_t c = read_universal_char(p + 2, 4);
|
||||
if (c) {
|
||||
p += 6;
|
||||
@ -744,7 +697,7 @@ static void convert_universal_chars(char *p) {
|
||||
} else {
|
||||
*q++ = *p++;
|
||||
}
|
||||
} else if (starts_with(p, "\\U")) {
|
||||
} else if (LOOKINGAT(p, "\\U")) {
|
||||
uint32_t c = read_universal_char(p + 2, 8);
|
||||
if (c) {
|
||||
p += 10;
|
||||
@ -759,27 +712,22 @@ static void convert_universal_chars(char *p) {
|
||||
*q++ = *p++;
|
||||
}
|
||||
}
|
||||
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
Token *tokenize_file(char *path) {
|
||||
char *p = read_file(path);
|
||||
if (!p) return NULL;
|
||||
|
||||
canonicalize_newline(p);
|
||||
remove_backslash_newline(p);
|
||||
convert_universal_chars(p);
|
||||
|
||||
// Save the filename for assembler .file directive.
|
||||
static int file_no;
|
||||
File *file = new_file(path, file_no + 1, p);
|
||||
|
||||
// Save the filename for assembler .file directive.
|
||||
input_files = realloc(input_files, sizeof(char *) * (file_no + 2));
|
||||
input_files[file_no] = file;
|
||||
input_files[file_no + 1] = NULL;
|
||||
file_no++;
|
||||
|
||||
return tokenize(file);
|
||||
}
|
||||
|
||||
64
third_party/chibicc/type.c
vendored
64
third_party/chibicc/type.c
vendored
@ -1,21 +1,21 @@
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
Type *ty_void = &(Type){TY_VOID, 1, 1};
|
||||
Type *ty_bool = &(Type){TY_BOOL, 1, 1};
|
||||
|
||||
Type *ty_char = &(Type){TY_CHAR, 1, 1};
|
||||
Type *ty_short = &(Type){TY_SHORT, 2, 2};
|
||||
Type *ty_int = &(Type){TY_INT, 4, 4};
|
||||
Type *ty_long = &(Type){TY_LONG, 8, 8};
|
||||
|
||||
Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
|
||||
Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
|
||||
Type *ty_uint = &(Type){TY_INT, 4, 4, true};
|
||||
Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
|
||||
|
||||
Type *ty_float = &(Type){TY_FLOAT, 4, 4};
|
||||
Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
|
||||
Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
|
||||
/* TODO(jart): Why can't these be const? */
|
||||
Type ty_void[1] = {{TY_VOID, 1, 1}};
|
||||
Type ty_bool[1] = {{TY_BOOL, 1, 1}};
|
||||
Type ty_char[1] = {{TY_CHAR, 1, 1}};
|
||||
Type ty_short[1] = {{TY_SHORT, 2, 2}};
|
||||
Type ty_int[1] = {{TY_INT, 4, 4}};
|
||||
Type ty_long[1] = {{TY_LONG, 8, 8}};
|
||||
Type ty_int128[1] = {{TY_INT128, 16, 16}};
|
||||
Type ty_uchar[1] = {{TY_CHAR, 1, 1, true}};
|
||||
Type ty_ushort[1] = {{TY_SHORT, 2, 2, true}};
|
||||
Type ty_uint[1] = {{TY_INT, 4, 4, true}};
|
||||
Type ty_ulong[1] = {{TY_LONG, 8, 8, true}};
|
||||
Type ty_uint128[1] = {{TY_INT128, 16, 16, true}};
|
||||
Type ty_float[1] = {{TY_FLOAT, 4, 4}};
|
||||
Type ty_double[1] = {{TY_DOUBLE, 8, 8}};
|
||||
Type ty_ldouble[1] = {{TY_LDOUBLE, 16, 16}};
|
||||
|
||||
static Type *new_type(TypeKind kind, int size, int align) {
|
||||
Type *ty = calloc(1, sizeof(Type));
|
||||
@ -28,7 +28,7 @@ static Type *new_type(TypeKind kind, int size, int align) {
|
||||
bool is_integer(Type *ty) {
|
||||
TypeKind k = ty->kind;
|
||||
return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT || k == TY_INT ||
|
||||
k == TY_LONG || k == TY_ENUM;
|
||||
k == TY_LONG || k == TY_INT128 || k == TY_ENUM;
|
||||
}
|
||||
|
||||
bool is_flonum(Type *ty) {
|
||||
@ -42,18 +42,15 @@ bool is_numeric(Type *ty) {
|
||||
|
||||
bool is_compatible(Type *t1, Type *t2) {
|
||||
if (t1 == t2) return true;
|
||||
|
||||
if (t1->origin) return is_compatible(t1->origin, t2);
|
||||
|
||||
if (t2->origin) return is_compatible(t1, t2->origin);
|
||||
|
||||
if (t1->kind != t2->kind) return false;
|
||||
|
||||
switch (t1->kind) {
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
case TY_INT:
|
||||
case TY_LONG:
|
||||
case TY_INT128:
|
||||
return t1->is_unsigned == t2->is_unsigned;
|
||||
case TY_FLOAT:
|
||||
case TY_DOUBLE:
|
||||
@ -64,11 +61,11 @@ bool is_compatible(Type *t1, Type *t2) {
|
||||
case TY_FUNC: {
|
||||
if (!is_compatible(t1->return_ty, t2->return_ty)) return false;
|
||||
if (t1->is_variadic != t2->is_variadic) return false;
|
||||
|
||||
Type *p1 = t1->params;
|
||||
Type *p2 = t2->params;
|
||||
for (; p1 && p2; p1 = p1->next, p2 = p2->next)
|
||||
for (; p1 && p2; p1 = p1->next, p2 = p2->next) {
|
||||
if (!is_compatible(p1, p2)) return false;
|
||||
}
|
||||
return p1 == NULL && p2 == NULL;
|
||||
}
|
||||
case TY_ARRAY:
|
||||
@ -125,19 +122,14 @@ Type *struct_type(void) {
|
||||
|
||||
static Type *get_common_type(Type *ty1, Type *ty2) {
|
||||
if (ty1->base) return pointer_to(ty1->base);
|
||||
|
||||
if (ty1->kind == TY_FUNC) return pointer_to(ty1);
|
||||
if (ty2->kind == TY_FUNC) return pointer_to(ty2);
|
||||
|
||||
if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE) return ty_ldouble;
|
||||
if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) return ty_double;
|
||||
if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) return ty_float;
|
||||
|
||||
if (ty1->size < 4) ty1 = ty_int;
|
||||
if (ty2->size < 4) ty2 = ty_int;
|
||||
|
||||
if (ty1->size != ty2->size) return (ty1->size < ty2->size) ? ty2 : ty1;
|
||||
|
||||
if (ty2->is_unsigned) return ty2;
|
||||
return ty1;
|
||||
}
|
||||
@ -157,7 +149,6 @@ static void usual_arith_conv(Node **lhs, Node **rhs) {
|
||||
|
||||
void add_type(Node *node) {
|
||||
if (!node || node->ty) return;
|
||||
|
||||
add_type(node->lhs);
|
||||
add_type(node->rhs);
|
||||
add_type(node->cond);
|
||||
@ -165,10 +156,8 @@ void add_type(Node *node) {
|
||||
add_type(node->els);
|
||||
add_type(node->init);
|
||||
add_type(node->inc);
|
||||
|
||||
for (Node *n = node->body; n; n = n->next) add_type(n);
|
||||
for (Node *n = node->args; n; n = n->next) add_type(n);
|
||||
|
||||
switch (node->kind) {
|
||||
case ND_NUM:
|
||||
node->ty = ty_int;
|
||||
@ -192,7 +181,7 @@ void add_type(Node *node) {
|
||||
}
|
||||
case ND_ASSIGN:
|
||||
if (node->lhs->ty->kind == TY_ARRAY)
|
||||
error_tok(node->lhs->tok, "not an lvalue");
|
||||
error_tok(node->lhs->tok, "not an lvalue!");
|
||||
if (node->lhs->ty->kind != TY_STRUCT)
|
||||
node->rhs = new_cast(node->rhs, node->lhs->ty);
|
||||
node->ty = node->lhs->ty;
|
||||
@ -244,12 +233,20 @@ void add_type(Node *node) {
|
||||
return;
|
||||
}
|
||||
case ND_DEREF:
|
||||
#if 0
|
||||
if (node->lhs->ty->size == 16 && (node->lhs->ty->kind == TY_FLOAT ||
|
||||
node->lhs->ty->kind == TY_DOUBLE)) {
|
||||
node->ty = node->lhs->ty;
|
||||
} else {
|
||||
#endif
|
||||
if (!node->lhs->ty->base)
|
||||
error_tok(node->tok, "invalid pointer dereference");
|
||||
if (node->lhs->ty->base->kind == TY_VOID)
|
||||
error_tok(node->tok, "dereferencing a void pointer");
|
||||
|
||||
node->ty = node->lhs->ty->base;
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
case ND_STMT_EXPR:
|
||||
if (node->body) {
|
||||
@ -271,7 +268,6 @@ void add_type(Node *node) {
|
||||
add_type(node->cas_old);
|
||||
add_type(node->cas_new);
|
||||
node->ty = ty_bool;
|
||||
|
||||
if (node->cas_addr->ty->kind != TY_PTR)
|
||||
error_tok(node->cas_addr->tok, "pointer expected");
|
||||
if (node->cas_old->ty->kind != TY_PTR)
|
||||
|
||||
71
third_party/chibicc/unicode.c
vendored
71
third_party/chibicc/unicode.c
vendored
@ -6,20 +6,17 @@ int encode_utf8(char *buf, uint32_t c) {
|
||||
buf[0] = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c <= 0x7FF) {
|
||||
buf[0] = 0b11000000 | (c >> 6);
|
||||
buf[1] = 0b10000000 | (c & 0b00111111);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (c <= 0xFFFF) {
|
||||
buf[0] = 0b11100000 | (c >> 12);
|
||||
buf[1] = 0b10000000 | ((c >> 6) & 0b00111111);
|
||||
buf[2] = 0b10000000 | (c & 0b00111111);
|
||||
return 3;
|
||||
}
|
||||
|
||||
buf[0] = 0b11110000 | (c >> 18);
|
||||
buf[1] = 0b10000000 | ((c >> 12) & 0b00111111);
|
||||
buf[2] = 0b10000000 | ((c >> 6) & 0b00111111);
|
||||
@ -39,11 +36,9 @@ uint32_t decode_utf8(char **new_pos, char *p) {
|
||||
*new_pos = p + 1;
|
||||
return *p;
|
||||
}
|
||||
|
||||
char *start = p;
|
||||
int len;
|
||||
uint32_t c;
|
||||
|
||||
if ((unsigned char)*p >= 0b11110000) {
|
||||
len = 4;
|
||||
c = *p & 0b111;
|
||||
@ -56,13 +51,11 @@ uint32_t decode_utf8(char **new_pos, char *p) {
|
||||
} else {
|
||||
error_at(start, "invalid UTF-8 sequence");
|
||||
}
|
||||
|
||||
for (int i = 1; i < len; i++) {
|
||||
if ((unsigned char)p[i] >> 6 != 0b10)
|
||||
error_at(start, "invalid UTF-8 sequence");
|
||||
c = (c << 6) | (p[i] & 0b111111);
|
||||
}
|
||||
|
||||
*new_pos = p + len;
|
||||
return c;
|
||||
}
|
||||
@ -85,7 +78,7 @@ static bool in_range(uint32_t *range, uint32_t c) {
|
||||
// (U+3000, full-width space) are allowed because they are out of range.
|
||||
bool is_ident1(uint32_t c) {
|
||||
static uint32_t range[] = {
|
||||
'_', '_', 'a', 'z', 'A', 'Z', '$', '$',
|
||||
'a', 'z', 'A', 'Z', '_', '_', '$', '$',
|
||||
0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
|
||||
0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
|
||||
0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
|
||||
@ -100,7 +93,6 @@ bool is_ident1(uint32_t c) {
|
||||
0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD,
|
||||
0xE0000, 0xEFFFD, -1,
|
||||
};
|
||||
|
||||
return in_range(range, c);
|
||||
}
|
||||
|
||||
@ -111,68 +103,9 @@ bool is_ident2(uint32_t c) {
|
||||
'0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0,
|
||||
0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1,
|
||||
};
|
||||
|
||||
return is_ident1(c) || in_range(range, c);
|
||||
}
|
||||
|
||||
// Returns the number of columns needed to display a given
|
||||
// character in a fixed-width font.
|
||||
//
|
||||
// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
static int char_width(uint32_t c) {
|
||||
static uint32_t range1[] = {
|
||||
0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,
|
||||
0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,
|
||||
0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,
|
||||
0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,
|
||||
0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,
|
||||
0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,
|
||||
0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,
|
||||
0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,
|
||||
0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,
|
||||
0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,
|
||||
0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,
|
||||
0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,
|
||||
0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,
|
||||
0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,
|
||||
0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,
|
||||
0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,
|
||||
0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,
|
||||
0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,
|
||||
0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,
|
||||
0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,
|
||||
0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,
|
||||
0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,
|
||||
0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,
|
||||
0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,
|
||||
0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,
|
||||
0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,
|
||||
0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,
|
||||
0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,
|
||||
0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,
|
||||
0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,
|
||||
0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,
|
||||
0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,
|
||||
0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,
|
||||
0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,
|
||||
0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
|
||||
0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
|
||||
-1,
|
||||
};
|
||||
|
||||
if (in_range(range1, c)) return 0;
|
||||
|
||||
static uint32_t range2[] = {
|
||||
0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
|
||||
0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,
|
||||
0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
|
||||
0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1,
|
||||
};
|
||||
|
||||
if (in_range(range2, c)) return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns the number of columns needed to display a given
|
||||
// string in a fixed-width font.
|
||||
int str_width(char *p, int len) {
|
||||
@ -180,7 +113,7 @@ int str_width(char *p, int len) {
|
||||
int w = 0;
|
||||
while (p - start < len) {
|
||||
uint32_t c = decode_utf8(&p, p);
|
||||
w += char_width(c);
|
||||
w += wcwidth(c);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
2
third_party/compiler_rt/int_util.h
vendored
2
third_party/compiler_rt/int_util.h
vendored
@ -26,7 +26,7 @@
|
||||
|
||||
/* #define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__) */
|
||||
|
||||
noreturn void __compilerrt_abort_impl(const char *file, int line,
|
||||
wontreturn void __compilerrt_abort_impl(const char *file, int line,
|
||||
const char *function);
|
||||
|
||||
#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
|
||||
|
||||
2
third_party/dlmalloc/dlmalloc.c
vendored
2
third_party/dlmalloc/dlmalloc.c
vendored
@ -34,7 +34,7 @@ struct MallocParams g_mparams;
|
||||
* Note that contiguous allocations are what Doug Lea recommends.
|
||||
*/
|
||||
static void *dlmalloc_requires_more_vespene_gas(size_t size) {
|
||||
if (0 && !IsTrustworthy()) {
|
||||
if (0) {
|
||||
size_t need = mallinfo().arena + size;
|
||||
if (need > 8 * 1024 * 1024) {
|
||||
struct sysinfo info;
|
||||
|
||||
33
third_party/dtoa/divmax.S
vendored
33
third_party/dtoa/divmax.S
vendored
@ -1,33 +0,0 @@
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ Avoid dtoa needing .data section.
|
||||
.bss
|
||||
.align 4
|
||||
dtoa_divmax:
|
||||
.zero 4
|
||||
.endobj dtoa_divmax,globl
|
||||
.previous
|
||||
|
||||
.init.start 202,_init_dtoa_divmax
|
||||
movb $2,dtoa_divmax(%rip)
|
||||
.init.end 202,_init_dtoa_divmax
|
||||
5848
third_party/dtoa/dtoa.c
vendored
5848
third_party/dtoa/dtoa.c
vendored
File diff suppressed because it is too large
Load Diff
18
third_party/dtoa/dtoa.h
vendored
18
third_party/dtoa/dtoa.h
vendored
@ -1,18 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_
|
||||
#define COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
char *g_fmt(char *buf /*[32]*/, double x);
|
||||
char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign,
|
||||
char **rve) nodiscard;
|
||||
void freedtoa(char *s);
|
||||
char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign,
|
||||
char **rve, char *buf, size_t blen);
|
||||
|
||||
double strtod(const char *, char **);
|
||||
double plan9_strtod(const char *, char **);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_DTOA_DTOA_H_ */
|
||||
62
third_party/dtoa/dtoa.mk
vendored
62
third_party/dtoa/dtoa.mk
vendored
@ -1,62 +0,0 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += THIRD_PARTY_DTOA
|
||||
|
||||
THIRD_PARTY_DTOA_ARTIFACTS += THIRD_PARTY_DTOA_A
|
||||
THIRD_PARTY_DTOA = $(THIRD_PARTY_DTOA_A_DEPS) $(THIRD_PARTY_DTOA_A)
|
||||
THIRD_PARTY_DTOA_A = o/$(MODE)/third_party/dtoa/dtoa.a
|
||||
THIRD_PARTY_DTOA_A_FILES := $(wildcard third_party/dtoa/*)
|
||||
THIRD_PARTY_DTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_DTOA_A_FILES))
|
||||
THIRD_PARTY_DTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_DTOA_A_FILES))
|
||||
THIRD_PARTY_DTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_DTOA_A_FILES))
|
||||
|
||||
THIRD_PARTY_DTOA_A_SRCS = \
|
||||
$(THIRD_PARTY_DTOA_A_SRCS_S) \
|
||||
$(THIRD_PARTY_DTOA_A_SRCS_C)
|
||||
|
||||
THIRD_PARTY_DTOA_A_OBJS = \
|
||||
$(THIRD_PARTY_DTOA_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(THIRD_PARTY_DTOA_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(THIRD_PARTY_DTOA_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
THIRD_PARTY_DTOA_A_CHECKS = \
|
||||
$(THIRD_PARTY_DTOA_A).pkg \
|
||||
$(THIRD_PARTY_DTOA_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
THIRD_PARTY_DTOA_A_DIRECTDEPS = \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_SYSV
|
||||
|
||||
THIRD_PARTY_DTOA_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(THIRD_PARTY_DTOA_A): \
|
||||
third_party/dtoa/ \
|
||||
$(THIRD_PARTY_DTOA_A).pkg \
|
||||
$(THIRD_PARTY_DTOA_A_OBJS)
|
||||
|
||||
$(THIRD_PARTY_DTOA_A).pkg: \
|
||||
$(THIRD_PARTY_DTOA_A_OBJS) \
|
||||
$(foreach x,$(THIRD_PARTY_DTOA_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
$(THIRD_PARTY_DTOA_A_OBJS): \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(OLD_CODE) \
|
||||
$(IEEE_MATH) \
|
||||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
||||
THIRD_PARTY_DTOA_LIBS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)))
|
||||
THIRD_PARTY_DTOA_SRCS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_SRCS))
|
||||
THIRD_PARTY_DTOA_HDRS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_HDRS))
|
||||
THIRD_PARTY_DTOA_CHECKS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_CHECKS))
|
||||
THIRD_PARTY_DTOA_OBJS = $(foreach x,$(THIRD_PARTY_DTOA_ARTIFACTS),$($(x)_OBJS))
|
||||
$(THIRD_PARTY_DTOA_OBJS): $(BUILD_FILES) third_party/dtoa/dtoa.mk
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/dtoa
|
||||
o/$(MODE)/third_party/dtoa: $(THIRD_PARTY_DTOA_CHECKS)
|
||||
114
third_party/dtoa/g_fmt.c
vendored
114
third_party/dtoa/g_fmt.c
vendored
@ -1,114 +0,0 @@
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#pragma GCC diagnostic ignored "-Wunused-label"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
dtoa (MIT License)\\n\
|
||||
The author of this software is David M. Gay.\\n\
|
||||
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
*
|
||||
* The author of this software is David M. Gay.
|
||||
*
|
||||
* Copyright (c) 1991, 1996 by Lucent Technologies.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*
|
||||
***************************************************************/
|
||||
|
||||
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
|
||||
* it suffices to declare buf
|
||||
* char buf[32];
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern char *dtoa(double, int, int, int *, int *, char **);
|
||||
extern char *g_fmt(char *, double);
|
||||
extern void freedtoa(char*);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
g_fmt(register char *b, double x)
|
||||
{
|
||||
register int i, k;
|
||||
register char *s;
|
||||
int decpt, j, sign;
|
||||
char *b0, *s0, *se;
|
||||
|
||||
b0 = b;
|
||||
#ifdef IGNORE_ZERO_SIGN
|
||||
if (!x) {
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
|
||||
if (sign)
|
||||
*b++ = '-';
|
||||
if (decpt == 9999) /* Infinity or Nan */ {
|
||||
while(*b++ = *s++);
|
||||
goto done0;
|
||||
}
|
||||
if (decpt <= -4 || decpt > se - s + 5) {
|
||||
*b++ = *s++;
|
||||
if (*s) {
|
||||
*b++ = '.';
|
||||
while(*b = *s++)
|
||||
b++;
|
||||
}
|
||||
*b++ = 'e';
|
||||
/* sprintf(b, "%+.2d", decpt - 1); */
|
||||
if (--decpt < 0) {
|
||||
*b++ = '-';
|
||||
decpt = -decpt;
|
||||
}
|
||||
else
|
||||
*b++ = '+';
|
||||
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
|
||||
for(;;) {
|
||||
i = decpt / k;
|
||||
*b++ = i + '0';
|
||||
if (--j <= 0)
|
||||
break;
|
||||
decpt -= i*k;
|
||||
decpt *= 10;
|
||||
}
|
||||
*b = 0;
|
||||
}
|
||||
else if (decpt <= 0) {
|
||||
*b++ = '.';
|
||||
for(; decpt < 0; decpt++)
|
||||
*b++ = '0';
|
||||
while(*b++ = *s++);
|
||||
}
|
||||
else {
|
||||
while(*b = *s++) {
|
||||
b++;
|
||||
if (--decpt == 0 && *s)
|
||||
*b++ = '.';
|
||||
}
|
||||
for(; decpt > 0; decpt--)
|
||||
*b++ = '0';
|
||||
*b = 0;
|
||||
}
|
||||
done0:
|
||||
freedtoa(s0);
|
||||
done:
|
||||
return b0;
|
||||
}
|
||||
531
third_party/dtoa/strtod.c
vendored
531
third_party/dtoa/strtod.c
vendored
@ -1,531 +0,0 @@
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Plan 9 strtod().
|
||||
* It's like dtoa but smaller.
|
||||
*/
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Plan 9 » strtod (MIT)\\n\
|
||||
The authors of this software are Rob Pike and Ken Thompson.\\n\
|
||||
Copyright (c) 2002 by Lucent Technologies.\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define nelem(a) ARRAYLEN(a)
|
||||
#define ulong unsigned long
|
||||
#define nil NULL
|
||||
#define __NaN() __builtin_nanf("")
|
||||
|
||||
/* clang-format off */
|
||||
/* The authors of this software are Rob Pike and Ken Thompson.
|
||||
* Copyright (c) 2002 by Lucent Technologies.
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose without fee is hereby granted, provided that this entire notice
|
||||
* is included in all copies of any software which is or includes a copy
|
||||
* or modification of this software and in all copies of the supporting
|
||||
* documentation for such software.
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
|
||||
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static ulong
|
||||
umuldiv(ulong a, ulong b, ulong c)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = ((double)a * (double)b) / (double)c;
|
||||
if(d >= 4294967295.)
|
||||
d = 4294967295.;
|
||||
return (ulong)d;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will convert to arbitrary precision
|
||||
* floating point entirely in multi-precision fixed.
|
||||
* The answer is the closest floating point number to
|
||||
* the given decimal number. Exactly half way are
|
||||
* rounded ala ieee rules.
|
||||
* Method is to scale input decimal between .500 and .999...
|
||||
* with external power of 2, then binary search for the
|
||||
* closest mantissa to this decimal number.
|
||||
* Nmant is is the required precision. (53 for ieee dp)
|
||||
* Nbits is the max number of bits/word. (must be <= 28)
|
||||
* Prec is calculated - the number of words of fixed mantissa.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
Nbits = 28, /* bits safely represented in a ulong */
|
||||
Nmant = 53, /* bits of precision required */
|
||||
Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
|
||||
Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
|
||||
Ndig = 1500,
|
||||
One = (ulong)(1<<Nbits),
|
||||
Half = (ulong)(One>>1),
|
||||
Maxe = 310,
|
||||
|
||||
Fsign = 1<<0, /* found - */
|
||||
Fesign = 1<<1, /* found e- */
|
||||
Fdpoint = 1<<2, /* found . */
|
||||
|
||||
S0 = 0, /* _ _S0 +S1 #S2 .S3 */
|
||||
S1, /* _+ #S2 .S3 */
|
||||
S2, /* _+# #S2 .S4 eS5 */
|
||||
S3, /* _+. #S4 */
|
||||
S4, /* _+#.# #S4 eS5 */
|
||||
S5, /* _+#.#e +S6 #S7 */
|
||||
S6, /* _+#.#e+ #S7 */
|
||||
S7 /* _+#.#e+# #S7 */
|
||||
};
|
||||
|
||||
static int fpcmp(char*, ulong*);
|
||||
static void frnorm(ulong*);
|
||||
static void divascii(char*, int*, int*, int*);
|
||||
static void mulascii(char*, int*, int*, int*);
|
||||
|
||||
typedef struct Tab Tab;
|
||||
struct Tab
|
||||
{
|
||||
int bp;
|
||||
int siz;
|
||||
char* cmp;
|
||||
};
|
||||
|
||||
double
|
||||
plan9_strtod(const char *as, char **aas)
|
||||
{
|
||||
int na, ex, dp, bp, c, i, flag, state;
|
||||
ulong low[Prec], hig[Prec], mid[Prec];
|
||||
double d;
|
||||
char *s, a[Ndig];
|
||||
|
||||
flag = 0; /* Fsign, Fesign, Fdpoint */
|
||||
na = 0; /* number of digits of a[] */
|
||||
dp = 0; /* na of decimal point */
|
||||
ex = 0; /* exonent */
|
||||
|
||||
state = S0;
|
||||
for(s=(char*)as;; s++) {
|
||||
c = *s;
|
||||
if(c >= '0' && c <= '9') {
|
||||
switch(state) {
|
||||
case S0:
|
||||
case S1:
|
||||
case S2:
|
||||
state = S2;
|
||||
break;
|
||||
case S3:
|
||||
case S4:
|
||||
state = S4;
|
||||
break;
|
||||
|
||||
case S5:
|
||||
case S6:
|
||||
case S7:
|
||||
state = S7;
|
||||
ex = ex*10 + (c-'0');
|
||||
continue;
|
||||
}
|
||||
if(na == 0 && c == '0') {
|
||||
dp--;
|
||||
continue;
|
||||
}
|
||||
if(na < Ndig-50)
|
||||
a[na++] = c;
|
||||
continue;
|
||||
}
|
||||
switch(c) {
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\v':
|
||||
case '\f':
|
||||
case '\r':
|
||||
case ' ':
|
||||
if(state == S0)
|
||||
continue;
|
||||
break;
|
||||
case '-':
|
||||
if(state == S0)
|
||||
flag |= Fsign;
|
||||
else
|
||||
flag |= Fesign;
|
||||
case '+':
|
||||
if(state == S0)
|
||||
state = S1;
|
||||
else
|
||||
if(state == S5)
|
||||
state = S6;
|
||||
else
|
||||
break; /* syntax */
|
||||
continue;
|
||||
case '.':
|
||||
flag |= Fdpoint;
|
||||
dp = na;
|
||||
if(state == S0 || state == S1) {
|
||||
state = S3;
|
||||
continue;
|
||||
}
|
||||
if(state == S2) {
|
||||
state = S4;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
if(state == S2 || state == S4) {
|
||||
state = S5;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean up return char-pointer
|
||||
*/
|
||||
switch(state) {
|
||||
case S0:
|
||||
if(strcasecmp(s, "nan") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+3;
|
||||
goto retnan;
|
||||
}
|
||||
case S1:
|
||||
if(strcasecmp(s, "infinity") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+8;
|
||||
goto retinf;
|
||||
}
|
||||
if(strcasecmp(s, "inf") == 0) {
|
||||
if(aas != nil)
|
||||
*aas = s+3;
|
||||
goto retinf;
|
||||
}
|
||||
case S3:
|
||||
if(aas != nil)
|
||||
*aas = (char*)as;
|
||||
goto ret0; /* no digits found */
|
||||
case S6:
|
||||
s--; /* back over +- */
|
||||
case S5:
|
||||
s--; /* back over e */
|
||||
break;
|
||||
}
|
||||
if(aas != nil)
|
||||
*aas = s;
|
||||
|
||||
if(flag & Fdpoint)
|
||||
while(na > 0 && a[na-1] == '0')
|
||||
na--;
|
||||
if(na == 0)
|
||||
goto ret0; /* zero */
|
||||
a[na] = 0;
|
||||
if(!(flag & Fdpoint))
|
||||
dp = na;
|
||||
if(flag & Fesign)
|
||||
ex = -ex;
|
||||
dp += ex;
|
||||
if(dp < -Maxe){
|
||||
erange();
|
||||
goto ret0; /* underflow by exp */
|
||||
} else
|
||||
if(dp > +Maxe)
|
||||
goto retinf; /* overflow by exp */
|
||||
|
||||
/*
|
||||
* normalize the decimal ascii number
|
||||
* to range .[5-9][0-9]* e0
|
||||
*/
|
||||
bp = 0; /* binary exponent */
|
||||
while(dp > 0)
|
||||
divascii(a, &na, &dp, &bp);
|
||||
while(dp < 0 || a[0] < '5')
|
||||
mulascii(a, &na, &dp, &bp);
|
||||
|
||||
/* close approx by naïve conversion */
|
||||
mid[0] = 0;
|
||||
mid[1] = 1;
|
||||
for(i=0; (c=a[i]) != '\0'; i++) {
|
||||
mid[0] = mid[0]*10 + (c-'0');
|
||||
mid[1] = mid[1]*10;
|
||||
if(i >= 8)
|
||||
break;
|
||||
}
|
||||
low[0] = umuldiv(mid[0], One, mid[1]);
|
||||
hig[0] = umuldiv(mid[0]+1, One, mid[1]);
|
||||
for(i=1; i<Prec; i++) {
|
||||
low[i] = 0;
|
||||
hig[i] = One-1;
|
||||
}
|
||||
|
||||
/* binary search for closest mantissa */
|
||||
for(;;) {
|
||||
/* mid = (hig + low) / 2 */
|
||||
c = 0;
|
||||
for(i=0; i<Prec; i++) {
|
||||
mid[i] = hig[i] + low[i];
|
||||
if(c)
|
||||
mid[i] += One;
|
||||
c = mid[i] & 1;
|
||||
mid[i] >>= 1;
|
||||
}
|
||||
frnorm(mid);
|
||||
|
||||
/* compare */
|
||||
c = fpcmp(a, mid);
|
||||
if(c > 0) {
|
||||
c = 1;
|
||||
for(i=0; i<Prec; i++)
|
||||
if(low[i] != mid[i]) {
|
||||
c = 0;
|
||||
low[i] = mid[i];
|
||||
}
|
||||
if(c)
|
||||
break; /* between mid and hig */
|
||||
continue;
|
||||
}
|
||||
if(c < 0) {
|
||||
for(i=0; i<Prec; i++)
|
||||
hig[i] = mid[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only hard part is if even/odd roundings wants to go up */
|
||||
c = mid[Prec-1] & (Sigbit-1);
|
||||
if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
|
||||
mid[Prec-1] -= c;
|
||||
break; /* exactly mid */
|
||||
}
|
||||
|
||||
/* normal rounding applies */
|
||||
c = mid[Prec-1] & (Sigbit-1);
|
||||
mid[Prec-1] -= c;
|
||||
if(c >= Sigbit/2) {
|
||||
mid[Prec-1] += Sigbit;
|
||||
frnorm(mid);
|
||||
}
|
||||
goto out;
|
||||
|
||||
ret0:
|
||||
return 0;
|
||||
|
||||
retnan:
|
||||
return __NaN();
|
||||
|
||||
retinf:
|
||||
/*
|
||||
* Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
|
||||
erange();
|
||||
if(flag & Fsign)
|
||||
return -HUGE_VAL;
|
||||
return HUGE_VAL;
|
||||
|
||||
out:
|
||||
d = 0;
|
||||
for(i=0; i<Prec; i++)
|
||||
d = d*One + mid[i];
|
||||
if(flag & Fsign)
|
||||
d = -d;
|
||||
d = ldexp(d, bp - Prec*Nbits);
|
||||
if(d == 0){ /* underflow */
|
||||
erange();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
frnorm(ulong *f)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
c = 0;
|
||||
for(i=Prec-1; i>0; i--) {
|
||||
f[i] += c;
|
||||
c = f[i] >> Nbits;
|
||||
f[i] &= One-1;
|
||||
}
|
||||
f[0] += c;
|
||||
}
|
||||
|
||||
static int
|
||||
fpcmp(char *a, ulong* f)
|
||||
{
|
||||
ulong tf[Prec];
|
||||
int i, d, c;
|
||||
|
||||
for(i=0; i<Prec; i++)
|
||||
tf[i] = f[i];
|
||||
|
||||
for(;;) {
|
||||
/* tf *= 10 */
|
||||
for(i=0; i<Prec; i++)
|
||||
tf[i] = tf[i]*10;
|
||||
frnorm(tf);
|
||||
d = (tf[0] >> Nbits) + '0';
|
||||
tf[0] &= One-1;
|
||||
|
||||
/* compare next digit */
|
||||
c = *a;
|
||||
if(c == 0) {
|
||||
if('0' < d)
|
||||
return -1;
|
||||
if(tf[0] != 0)
|
||||
goto cont;
|
||||
for(i=1; i<Prec; i++)
|
||||
if(tf[i] != 0)
|
||||
goto cont;
|
||||
return 0;
|
||||
}
|
||||
if(c > d)
|
||||
return +1;
|
||||
if(c < d)
|
||||
return -1;
|
||||
a++;
|
||||
cont:;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
divby(char *a, int *na, int b)
|
||||
{
|
||||
int n, c;
|
||||
char *p;
|
||||
|
||||
p = a;
|
||||
n = 0;
|
||||
while(n>>b == 0) {
|
||||
c = *a++;
|
||||
if(c == 0) {
|
||||
while(n) {
|
||||
c = n*10;
|
||||
if(c>>b)
|
||||
break;
|
||||
n = c;
|
||||
}
|
||||
goto xx;
|
||||
}
|
||||
n = n*10 + c-'0';
|
||||
(*na)--;
|
||||
}
|
||||
for(;;) {
|
||||
c = n>>b;
|
||||
n -= c<<b;
|
||||
*p++ = c + '0';
|
||||
c = *a++;
|
||||
if(c == 0)
|
||||
break;
|
||||
n = n*10 + c-'0';
|
||||
}
|
||||
(*na)++;
|
||||
xx:
|
||||
while(n) {
|
||||
n = n*10;
|
||||
c = n>>b;
|
||||
n -= c<<b;
|
||||
*p++ = c + '0';
|
||||
(*na)++;
|
||||
}
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
static Tab tab1[] =
|
||||
{
|
||||
{ 1, 0, ""},
|
||||
{ 3, 1, "7"},
|
||||
{ 6, 2, "63"},
|
||||
{ 9, 3, "511"},
|
||||
{13, 4, "8191"},
|
||||
{16, 5, "65535"},
|
||||
{19, 6, "524287"},
|
||||
{23, 7, "8388607"},
|
||||
{26, 8, "67108863"},
|
||||
{27, 9, "134217727"},
|
||||
};
|
||||
|
||||
static void
|
||||
divascii(char *a, int *na, int *dp, int *bp)
|
||||
{
|
||||
int b, d;
|
||||
Tab *t;
|
||||
|
||||
d = *dp;
|
||||
if(d >= (int)(nelem(tab1)))
|
||||
d = (int)(nelem(tab1))-1;
|
||||
t = tab1 + d;
|
||||
b = t->bp;
|
||||
if(memcmp(a, t->cmp, t->siz) > 0)
|
||||
d--;
|
||||
*dp -= d;
|
||||
*bp += b;
|
||||
divby(a, na, b);
|
||||
}
|
||||
|
||||
static void
|
||||
mulby(char *a, char *p, char *q, int b)
|
||||
{
|
||||
int n, c;
|
||||
|
||||
n = 0;
|
||||
*p = 0;
|
||||
for(;;) {
|
||||
q--;
|
||||
if(q < a)
|
||||
break;
|
||||
c = *q - '0';
|
||||
c = (c<<b) + n;
|
||||
n = c/10;
|
||||
c -= n*10;
|
||||
p--;
|
||||
*p = c + '0';
|
||||
}
|
||||
while(n) {
|
||||
c = n;
|
||||
n = c/10;
|
||||
c -= n*10;
|
||||
p--;
|
||||
*p = c + '0';
|
||||
}
|
||||
}
|
||||
|
||||
static Tab tab2[] =
|
||||
{
|
||||
{ 1, 1, ""}, /* dp = 0-0 */
|
||||
{ 3, 3, "125"},
|
||||
{ 6, 5, "15625"},
|
||||
{ 9, 7, "1953125"},
|
||||
{13, 10, "1220703125"},
|
||||
{16, 12, "152587890625"},
|
||||
{19, 14, "19073486328125"},
|
||||
{23, 17, "11920928955078125"},
|
||||
{26, 19, "1490116119384765625"},
|
||||
{27, 19, "7450580596923828125"}, /* dp 8-9 */
|
||||
};
|
||||
|
||||
static void
|
||||
mulascii(char *a, int *na, int *dp, int *bp)
|
||||
{
|
||||
char *p;
|
||||
int d, b;
|
||||
Tab *t;
|
||||
|
||||
d = -*dp;
|
||||
if(d >= (int)(nelem(tab2)))
|
||||
d = (int)(nelem(tab2))-1;
|
||||
t = tab2 + d;
|
||||
b = t->bp;
|
||||
if(memcmp(a, t->cmp, t->siz) < 0)
|
||||
d--;
|
||||
p = a + *na;
|
||||
*bp -= b;
|
||||
*dp += d;
|
||||
*na += d;
|
||||
mulby(a, p+d, p, b);
|
||||
}
|
||||
2
third_party/duktape/duk_config.h
vendored
2
third_party/duktape/duk_config.h
vendored
@ -786,7 +786,7 @@
|
||||
* Disabled temporarily in GCC 5+ because of an unresolved noreturn-related
|
||||
* issue: https://github.com/svaarala/duktape/issues/2155.
|
||||
*/
|
||||
#define DUK_NORETURN(decl) decl noreturn
|
||||
#define DUK_NORETURN(decl) decl wontreturn
|
||||
#endif
|
||||
|
||||
#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L)
|
||||
|
||||
2
third_party/gdtoa/dmisc.c
vendored
2
third_party/gdtoa/dmisc.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/dtoa.c
vendored
2
third_party/gdtoa/dtoa.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_Qfmt.c
vendored
2
third_party/gdtoa/g_Qfmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_Qfmt_p.c
vendored
2
third_party/gdtoa/g_Qfmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g__fmt.c
vendored
2
third_party/gdtoa/g__fmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_ddfmt.c
vendored
2
third_party/gdtoa/g_ddfmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_ddfmt_p.c
vendored
2
third_party/gdtoa/g_ddfmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_dfmt.c
vendored
2
third_party/gdtoa/g_dfmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_dfmt_p.c
vendored
2
third_party/gdtoa/g_dfmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_ffmt.c
vendored
2
third_party/gdtoa/g_ffmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_ffmt_p.c
vendored
2
third_party/gdtoa/g_ffmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_xLfmt.c
vendored
2
third_party/gdtoa/g_xLfmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_xLfmt_p.c
vendored
2
third_party/gdtoa/g_xLfmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_xfmt.c
vendored
2
third_party/gdtoa/g_xfmt.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/g_xfmt_p.c
vendored
2
third_party/gdtoa/g_xfmt_p.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/gdtoa.c
vendored
2
third_party/gdtoa/gdtoa.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
@ -5,8 +5,9 @@
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
gdtoa (MIT License)\\n\
|
||||
The author of this software is David M. Gay.\\n\
|
||||
Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\"");
|
||||
The author of this software is David M. Gay\\n\
|
||||
Kudos go to Guy L. Steele, Jr. and Jon L. White\\n\
|
||||
Copyright (C) 1997, 1998, 2000 by Lucent Technologies\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
#define IEEE_8087 1
|
||||
2
third_party/gdtoa/gethex.c
vendored
2
third_party/gdtoa/gethex.c
vendored
@ -1,5 +1,5 @@
|
||||
#include "libc/errno.h"
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/gmisc.c
vendored
2
third_party/gdtoa/gmisc.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/hd_init.c
vendored
2
third_party/gdtoa/hd_init.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/hexnan.c
vendored
2
third_party/gdtoa/hexnan.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/misc.c
vendored
2
third_party/gdtoa/misc.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/smisc.c
vendored
2
third_party/gdtoa/smisc.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/strtoIQ.c
vendored
2
third_party/gdtoa/strtoIQ.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/strtoId.c
vendored
2
third_party/gdtoa/strtoId.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/strtoIdd.c
vendored
2
third_party/gdtoa/strtoIdd.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
2
third_party/gdtoa/strtoIf.c
vendored
2
third_party/gdtoa/strtoIf.c
vendored
@ -1,4 +1,4 @@
|
||||
#include "third_party/gdtoa/gdtoaimp.h"
|
||||
#include "third_party/gdtoa/gdtoa.internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
/****************************************************************
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user