Browse Source

Further refine documentation

main
Justine Tunney 10 months ago
parent
commit
548dcb9f08
  1. 8
      Makefile
  2. 1
      examples/examples.mk
  3. 120
      examples/fld.c
  4. 50
      libc/bits/xmmintrin.internal.h
  5. 8
      libc/integral/lp64arg.inc
  6. 6
      libc/log/vflogf.c
  7. 22
      libc/math.h
  8. 18
      libc/nexgen32e/bsrmax.S
  9. 2
      libc/nt/winsock.h
  10. 4
      libc/runtime/valist.c
  11. 4
      libc/runtime/valist.h
  12. 145
      third_party/chibicc/as.c
  13. 4
      third_party/chibicc/chibicc.h
  14. 7
      third_party/chibicc/dox1.c
  15. 108
      third_party/chibicc/dox2.c
  16. 106
      third_party/chibicc/file.c
  17. 13
      third_party/chibicc/file.h
  18. 50
      third_party/chibicc/parse.c
  19. 1
      third_party/chibicc/test/asm_test.c
  20. 23
      third_party/chibicc/test/vla_test.c
  21. 103
      third_party/chibicc/tokenize.c
  22. 50
      third_party/getopt/getopt.c
  23. 444
      third_party/getopt/getopt_long.3
  24. 553
      third_party/getopt/getopt_long.c
  25. 3
      third_party/getopt/initgetopt.S
  26. 10
      tool/build/calculator.inc
  27. 10
      tool/viz/printvideo.c

8
Makefile

@ -312,8 +312,12 @@ o/cosmopolitan.h: \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
@ACTION=ROLLUP TARGET=$@ build/do $^ >$@
o/cosmopolitan.html: o/$(MODE)/third_party/chibicc/chibicc.com.dbg
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J -fno-common -include libc/integral/normalize.inc -o $@ $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
-fno-common -include libc/integral/normalize.inc -o $@ \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))
# UNSPECIFIED PREREQUISITES TUTORIAL
#

1
examples/examples.mk

@ -54,6 +54,7 @@ EXAMPLES_DIRECTDEPS = \
LIBC_NT_KERNELBASE \
LIBC_NT_NTDLL \
LIBC_NT_USER32 \
LIBC_NT_WS2_32 \
LIBC_OHMYPLUS \
LIBC_RAND \
LIBC_RUNTIME \

120
examples/fld.c

@ -1,120 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/
http://creativecommons.org/publicdomain/zero/1.0/
*/
#endif
#include "libc/bits/bits.h"
#include "libc/inttypes.h"
#include "libc/literal.h"
#include "libc/math.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
static const char kHeaderBin[] = "\
/\tsign\n\
/\t exponent\n\
/\t intpart\n\
/\t fraction\n\
/\t \n\
/\t\n";
static const char kHeaderHex[] = "\
/\t sign/exponent\n\
/\t intpart/fraction\n\
/\t \n\
/\t\n";
void dobin(const char *op, long double x, FILE *f) {
uint16_t hi;
uint64_t lo;
uint8_t buf[16];
memcpy(buf, &x, sizeof(x));
memcpy(&lo, &buf[0], sizeof(lo));
memcpy(&hi, &buf[8], sizeof(hi));
fprintf(f, "/\t%016" PRIb16 "%064" PRIb64 " %-8s % 17.14Lf\n", hi, lo, op, x);
}
void dohex(const char *op, long double x, FILE *f) {
uint16_t hi;
uint64_t lo;
uint8_t buf[16];
memcpy(buf, &x, sizeof(x));
memcpy(&lo, &buf[0], sizeof(lo));
memcpy(&hi, &buf[8], sizeof(hi));
fprintf(f, "/\t%04" PRIx16 "%016" PRIx64 " %-8s % 17.14Lf\n", hi, lo, op, x);
}
#define DOBIN(OP) \
dobin(" " #OP, OP(), stdout); \
dobin("-" #OP, -OP(), stdout)
#define DOHEX(OP) \
dohex(" " #OP, OP(), stdout); \
dohex("-" #OP, -OP(), stdout)
int main(int argc, char *argv[]) {
fputs(kHeaderBin, stdout);
DOBIN(fldz);
DOBIN(fld1);
DOBIN(fldpi);
DOBIN(fldl2t);
DOBIN(fldlg2);
DOBIN(fldln2);
DOBIN(fldl2e);
fputc('\n', stdout);
fputs(kHeaderHex, stdout);
DOHEX(fldz);
DOHEX(fld1);
DOHEX(fldpi);
DOHEX(fldl2t);
DOHEX(fldlg2);
DOHEX(fldln2);
DOHEX(fldl2e);
return 0;
}
// clang-format off
//
// sign
// exponent
// intpart
// fraction
//
//
// 00000000000000000000000000000000000000000000000000000000000000000000000000000000 fldz 0.0000000000000000000
// 10000000000000000000000000000000000000000000000000000000000000000000000000000000 -fldz -0.0000000000000000000
// 00111111111111111000000000000000000000000000000000000000000000000000000000000000 fld1 1.0000000000000000000
// 10111111111111111000000000000000000000000000000000000000000000000000000000000000 -fld1 -1.0000000000000000000
// 01000000000000001100100100001111110110101010001000100001011010001100001000110101 fldpi 3.1415926540000000000
// 11000000000000001100100100001111110110101010001000100001011010001100001000110101 -fldpi -3.1415926540000000000
// 01000000000000001101010010011010011110000100101111001101000110111000101011111110 fldl2t 3.3219280950000000000
// 11000000000000001101010010011010011110000100101111001101000110111000101011111110 -fldl2t -3.3219280950000000000
// 00111111111111011001101000100000100110101000010011111011110011111111011110011001 fldlg2 0.3010299960000000000
// 10111111111111011001101000100000100110101000010011111011110011111111011110011001 -fldlg2 -0.3010299960000000000
// 00111111111111101011000101110010000101111111011111010001110011110111100110101100 fldln2 0.6931471810000000000
// 10111111111111101011000101110010000101111111011111010001110011110111100110101100 -fldln2 -0.6931471810000000000
// 00111111111111111011100010101010001110110010100101011100000101111111000010111100 fldl2e 1.4426950410000000000
// 10111111111111111011100010101010001110110010100101011100000101111111000010111100 -fldl2e -1.4426950410000000000
//
// sign/exponent
// intpart/fraction
//
//
// 00000000000000000000 fldz 0.0000000000000000000
// 80000000000000000000 -fldz -0.0000000000000000000
// 3fff8000000000000000 fld1 1.0000000000000000000
// bfff8000000000000000 -fld1 -1.0000000000000000000
// 4000c90fdaa22168c235 fldpi 3.1415926540000000000
// c000c90fdaa22168c235 -fldpi -3.1415926540000000000
// 4000d49a784bcd1b8afe fldl2t 3.3219280950000000000
// c000d49a784bcd1b8afe -fldl2t -3.3219280950000000000
// 3ffd9a209a84fbcff799 fldlg2 0.3010299960000000000
// bffd9a209a84fbcff799 -fldlg2 -0.3010299960000000000
// 3ffeb17217f7d1cf79ac fldln2 0.6931471810000000000
// bffeb17217f7d1cf79ac -fldln2 -0.6931471810000000000
// 3fffb8aa3b295c17f0bc fldl2e 1.4426950410000000000
// bfffb8aa3b295c17f0bc -fldl2e -1.4426950410000000000

50
libc/bits/xmmintrin.internal.h

@ -98,25 +98,37 @@ typedef float __m128_u _Vector_size(16) forcealign(1) mayalias;
cosmopolitan § it's a trap! » sse » scalar ops
*/
forceinline __m128 _mm_add_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] += m128_1[0];
return m128_0;
}
forceinline __m128 _mm_sub_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] -= m128_1[0];
return m128_0;
}
forceinline __m128 _mm_mul_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] *= m128_1[0];
return m128_0;
}
forceinline __m128 _mm_div_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] /= m128_1[0];
return m128_0;
}
#define _mm_add_ss(m128_0, m128_1) \
({ \
__m128 a = m128_0; \
__m128 b = m128_0; \
a[0] += b[0]; \
a; \
})
#define _mm_sub_ss(m128_0, m128_1) \
({ \
__m128 a = m128_0; \
__m128 b = m128_0; \
a[0] -= b[0]; \
a; \
})
#define _mm_mul_ss(m128_0, m128_1) \
({ \
__m128 a = m128_0; \
__m128 b = m128_0; \
a[0] *= b[0]; \
a; \
})
#define _mm_div_ss(m128_0, m128_1) \
({ \
__m128 a = m128_0; \
__m128 b = m128_0; \
a[0] /= b[0]; \
a; \
})
#define _mm_rcp_ss(M128) __builtin_ia32_rcpss((__v4sf)(M128)) /*~1/x*/
#define _mm_sqrt_ss(M128) __builtin_ia32_sqrtss((__v4sf)(M128)) /*sqrt𝑥*/

8
libc/integral/lp64arg.inc

@ -5,13 +5,13 @@
#define va_end(AP)
#define va_copy(DST, SRC) ((DST)[0] = (SRC)[0])
#define va_start(AP, LAST) \
do { \
*(AP) = *(struct __va *)__va_area__; \
#define va_start(AP, LAST) \
do { \
*(AP) = *(struct __va_list *)__va_area__; \
} while (0)
#define va_arg(AP, TYPE) \
(*(TYPE *)__va_arg(AP, sizeof(TYPE), _Alignof(TYPE), \
__builtin_reg_class(TYPE)))
typedef struct __va va_list[1];
typedef struct __va_list va_list[1];

6
libc/log/vflogf.c

@ -73,7 +73,7 @@ void vflogf_onfail(FILE *f) {
fseek(f, SEEK_SET, 0);
f->beg = f->end = 0;
clearerr(f);
(fprintf)(f, "performed emergency log truncation: %s\r\n", strerror(err));
(fprintf)(f, "performed emergency log truncation: %s\n", strerror(err));
}
}
@ -112,10 +112,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
}
(vfprintf)(f, fmt, va);
va_end(va);
fputs("\r\n", f);
fputs("\n", f);
if (level == kLogFatal) {
__start_fatal(file, line);
(dprintf)(STDERR_FILENO, "fatal error see logfile\r\n");
(dprintf)(STDERR_FILENO, "fatal error see logfile\n");
__die();
unreachable;
}

22
libc/math.h

@ -285,28 +285,6 @@ void sincos(double, double *, double *);
void sincosf(float, float *, float *);
void sincosl(long double, long double *, long double *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § mathematics » x87
*/
#define fldz() __X87_CONST(fldz, 0x0p+0)
#define fld1() __X87_CONST(fld1, 0x8p-3)
#define fldpi() __X87_CONST(fldpi, M_PI)
#define fldl2t() __X87_CONST(fldl2t, M_LOG2_10)
#define fldlg2() __X87_CONST(fldlg2, M_LOG10_2)
#define fldln2() __X87_CONST(fldln2, M_LN2)
#define fldl2e() __X87_CONST(fldl2e, M_LOG2E)
#ifdef __x86__
#define __X87_CONST(OP, VALUE) \
({ \
long double St0##OP; \
asm(#OP : "=t"(St0##OP)); \
St0##OP; \
})
#else
#define __X87_CONST(OP, VALUE) VALUE
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MATH_H_ */

18
libc/nexgen32e/bsrmax.S

@ -21,15 +21,15 @@
/ Returns binary logarithm of integer 𝑥.
/
/ uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
/ 0x00000000 wut 32 0 wut 32
/ 0x00000001 0 0 1 0 31
/ 0x80000001 0 0 1 31 0
/ 0x80000000 31 31 32 31 0
/ 0x00000010 4 4 5 4 27
/ 0x08000010 4 4 5 27 4
/ 0x08000000 27 27 28 27 4
/ 0xffffffff 0 0 1 31 0
/ uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
/ 0x00000000 wut 32 0 wut 32
/ 0x00000001 0 0 1 0 31
/ 0x80000001 0 0 1 31 0
/ 0x80000000 31 31 32 31 0
/ 0x00000010 4 4 5 4 27
/ 0x08000010 4 4 5 27 4
/ 0x08000000 27 27 28 27 4
/ 0xffffffff 0 0 1 31 0
/
/ @param rsi:rdi is 128-bit unsigned 𝑥 value
/ @return eax number in range [0,128) or undef if 𝑥 is 0

2
libc/nt/winsock.h

@ -409,7 +409,7 @@ int WSARecvFrom(uint64_t s, const struct NtIovec *out_lpBuffers,
uint32_t *inout_fromsockaddrlen,
struct NtOverlapped *opt_inout_lpOverlapped,
const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine)
paramsnonnull((2, 5, 6, 7));
paramsnonnull((2, 5));
int WSARecvDisconnect(uint64_t s,
const struct NtIovec *opt_lpInboundDisconnectData);

4
libc/runtime/valist.c

@ -20,13 +20,13 @@
#include "libc/macros.h"
#include "libc/runtime/valist.h"
static void *__va_arg_mem(struct __va *ap, size_t sz, size_t align) {
static void *__va_arg_mem(struct __va_list *ap, size_t sz, size_t align) {
void *r = (void *)ROUNDUP((intptr_t)ap->overflow_arg_area, align);
ap->overflow_arg_area = (void *)ROUNDUP((intptr_t)r + sz, 8);
return r;
}
void *__va_arg(struct __va *ap, size_t sz, unsigned align, unsigned k) {
void *__va_arg(struct __va_list *ap, size_t sz, unsigned align, unsigned k) {
void *r;
switch (k) {
case 0:

4
libc/runtime/valist.h

@ -3,14 +3,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct __va {
struct __va_list {
uint32_t gp_offset;
uint32_t fp_offset;
void *overflow_arg_area;
void *reg_save_area;
};
void *__va_arg(struct __va *, size_t, unsigned, unsigned);
void *__va_arg(struct __va_list *, size_t, unsigned, unsigned);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

145
third_party/chibicc/as.c

@ -27,6 +27,8 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/x/x.h"
#include "third_party/chibicc/file.h"
#include "third_party/gdtoa/gdtoa.h"
#include "tool/build/lib/elfwriter.h"
@ -443,49 +445,6 @@ static unsigned Hash(const void *p, unsigned long n) {
return MAX(1, h);
}
static bool StartsWith(const char *s, const char *prefix) {
for (;;) {
if (!*prefix) return true;
if (!*s) return false;
if (*s++ != *prefix++) return false;
}
}
static bool EndsWith(const char *s, const char *suffix) {
size_t n, m;
n = strlen(s);
m = strlen(suffix);
if (m > n) return false;
return !memcmp(s + n - m, suffix, m);
}
static char *Format(const char *fmt, ...) {
char *res;
va_list va;
va_start(va, fmt);
vasprintf(&res, fmt, va);
va_end(va);
return res;
}
static char *DirName(const char *path) {
return dirname(strdup(path));
}
static char *JoinPaths(const char *path, const char *other) {
if (!*other) {
return strdup(path);
} else if (!*path) {
return strdup(other);
} else if (StartsWith(other, "/") || !strcmp(path, ".")) {
return strdup(other);
} else if (EndsWith(path, "/")) {
return Format("%s%s", path, other);
} else {
return Format("%s/%s", path, other);
}
}
static bool IsPunctMergeable(int c) {
switch (c) {
case ';':
@ -613,11 +572,11 @@ static void ReadFlags(struct As *a, int argc, char *argv[]) {
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-o")) {
a->outpath = StrDup(a, argv[++i]);
} else if (StartsWith(argv[i], "-o")) {
} else if (startswith(argv[i], "-o")) {
a->outpath = StrDup(a, argv[i] + 2);
} else if (!strcmp(argv[i], "-I")) {
SaveString(&a->incpaths, strdup(argv[++i]));
} else if (StartsWith(argv[i], "-I")) {
} else if (startswith(argv[i], "-I")) {
SaveString(&a->incpaths, strdup(argv[i] + 2));
} else if (!strcmp(argv[i], "-Z")) {
a->inhibiterr = true;
@ -677,72 +636,6 @@ static int ReadCharLiteral(struct Slice *buf, int c, char *p, int *i) {
}
}
static void CanonicalizeNewline(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '\r' && p[i + 1] == '\n') {
i += 2;
p[j++] = '\n';
} else if (p[i] == '\r') {
i++;
p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
static void RemoveBackslashNewline(char *p) {
int i, j, n;
for (i = j = n = 0; p[i];) {
if (p[i] == '\\' && p[i + 1] == '\n') {
i += 2;
n++;
} else if (p[i] == '\n') {
p[j++] = p[i++];
for (; n > 0; n--) p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
for (; n > 0; n--) p[j++] = '\n';
p[j] = '\0';
}
static char *ReadFile(const char *path) {
char *p;
FILE *fp;
int buflen, nread, end, n;
if (!strcmp(path, "-")) {
fp = stdin;
} else {
fp = fopen(path, "r");
if (!fp) return NULL;
}
buflen = 4096;
nread = 0;
p = calloc(1, buflen);
for (;;) {
end = buflen - 2;
n = fread(p + nread, 1, end - nread, fp);
if (n == 0) break;
nread += n;
if (nread == end) {
buflen *= 2;
p = realloc(p, buflen);
}
}
if (fp != stdin) fclose(fp);
if (nread > 0 && p[nread - 1] == '\\') {
p[nread - 1] = '\n';
} else if (nread == 0 || p[nread - 1] != '\n') {
p[nread++] = '\n';
}
p[nread] = '\0';
return p;
}
static void PrintLocation(struct As *a) {
fprintf(stderr,
"%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[a->i].s].path],
@ -768,7 +661,7 @@ static char *FindInclude(struct As *a, const char *file) {
char *path;
struct stat st;
for (i = 0; i < a->incpaths.n; ++i) {
path = JoinPaths(a->incpaths.p[i], file);
path = xjoinpaths(a->incpaths.p[i], file);
if (stat(path, &st) != -1 && S_ISREG(st.st_mode)) return path;
free(path);
}
@ -780,10 +673,10 @@ static void Tokenize(struct As *a, int path) {
char *p, *path2;
struct Slice buf;
bool bol, isfloat, isfpu;
p = SaveString(&a->strings, ReadFile(a->strings.p[path]));
if (!memcmp(p, "\357\273\277", 3)) p += 3;
CanonicalizeNewline(p);
RemoveBackslashNewline(p);
p = SaveString(&a->strings, read_file(a->strings.p[path]));
p = skip_bom(p);
canonicalize_newline(p);
remove_backslash_newline(p);
line = 1;
bol = true;
while ((c = *p)) {
@ -1031,7 +924,7 @@ static void OnSymbol(struct As *a, int name) {
static void OnLocalLabel(struct As *a, int id) {
int i;
char *name;
name = Format(".Label.%d", a->counter++);
name = xasprintf(".Label.%d", a->counter++);
SaveString(&a->strings, name);
AppendSlice(a);
a->slices.p[a->slices.n - 1].p = name;
@ -1796,13 +1689,13 @@ static int GrabSection(struct As *a, int name, int flags, int type) {
static void OnSection(struct As *a, struct Slice s) {
int name, flags, type;
name = SliceDup(a, GetSlice(a));
if (StartsWith(a->strings.p[name], ".text")) {
if (startswith(a->strings.p[name], ".text")) {
flags = SHF_ALLOC | SHF_EXECINSTR;
type = SHT_PROGBITS;
} else if (StartsWith(a->strings.p[name], ".data")) {
} else if (startswith(a->strings.p[name], ".data")) {
flags = SHF_ALLOC | SHF_WRITE;
type = SHT_PROGBITS;
} else if (StartsWith(a->strings.p[name], ".bss")) {
} else if (startswith(a->strings.p[name], ".bss")) {
flags = SHF_ALLOC | SHF_WRITE;
type = SHT_NOBITS;
} else {
@ -2372,7 +2265,7 @@ static noinline void OpBsu(struct As *a, struct Slice opname, int op) {
OpBsuImpl(a, opname, op);
}
static int OpF6(struct As *a, struct Slice s, int reg) {
static noinline int OpF6Impl(struct As *a, struct Slice s, int reg) {
int modrm, imm, disp;
modrm = ParseModrm(a, &disp);
reg |= GetOpSize(a, s, modrm, 1) << 3;
@ -2380,6 +2273,10 @@ static int OpF6(struct As *a, struct Slice s, int reg) {
return reg;
}
static noinline int OpF6(struct As *a, struct Slice s, int reg) {
return OpF6Impl(a, s, reg);
}
static void OnTest(struct As *a, struct Slice s) {
int reg, modrm, imm, disp;
if (IsPunct(a, a->i, '$')) {
@ -2571,8 +2468,8 @@ static bool HasXmmOnLine(struct As *a) {
int i;
for (i = 0; !IsPunct(a, a->i + i, ';'); ++i) {
if (IsSlice(a, a->i + i) && a->slices.p[a->things.p[a->i + i].i].n >= 4 &&
(StartsWith(a->slices.p[a->things.p[a->i + i].i].p, "xmm") ||
StartsWith(a->slices.p[a->things.p[a->i + i].i].p, "%xmm"))) {
(startswith(a->slices.p[a->things.p[a->i + i].i].p, "xmm") ||
startswith(a->slices.p[a->things.p[a->i + i].i].p, "%xmm"))) {
return true;
}
}
@ -4002,7 +3899,7 @@ void Assembler(int argc, char *argv[]) {
a = NewAssembler();
ReadFlags(a, argc, argv);
SaveString(&a->incpaths, strdup("."));
SaveString(&a->incpaths, DirName(a->strings.p[a->inpath]));
SaveString(&a->incpaths, xdirname(a->strings.p[a->inpath]));
Tokenize(a, a->inpath);
/* PrintThings(a); */
Assemble(a);

4
third_party/chibicc/chibicc.h

@ -130,9 +130,6 @@ Token *tokenize_string_literal(Token *, Type *);
bool consume(Token **, Token *, char *, size_t);
bool equal(Token *, char *, size_t);
void convert_pp_tokens(Token *);
void remove_backslash_newline(char *);
void canonicalize_newline(char *);
char *read_file(char *);
int read_escaped_char(char **, char *);
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
@ -450,6 +447,7 @@ struct Type {
int align; // alignment
bool is_unsigned; // unsigned or signed
bool is_atomic; // true if _Atomic
bool is_const; // const
bool is_ms_abi; // microsoft abi
Type *origin; // for type compatibility check
// Pointer-to or array-of type. We intentionally use the same member

7
third_party/chibicc/dox1.c

@ -79,7 +79,8 @@ static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) {
}
static char *DescribeScalar(struct Type *ty, char *name) {
return xasprintf("%s%s%s", ty->is_atomic ? "_Atomic " : "",
return xasprintf("%s%s%s%s", ty->is_atomic ? "_Atomic " : "",
ty->is_const ? "const " : "",
ty->is_unsigned ? "unsigned " : "", name);
}
@ -134,7 +135,7 @@ static char *DescribeType(struct Type *ty) {
return strdup("ANONYMOUS-UNION");
}
default:
return "UNKNOWN";
return strdup("UNKNOWN");
}
}
@ -178,6 +179,7 @@ static void SerializeDox(struct DoxWriter *dox, Obj *prog) {
SerializeStr(&dox->buf, GetFileName(dox->objects.p[i]));
SerializeInt(&dox->buf, GetLine(dox->objects.p[i]));
SerializeInt(&dox->buf, dox->objects.p[i]->is_function);
SerializeInt(&dox->buf, dox->objects.p[i]->ty->is_variadic);
SerializeInt(&dox->buf, dox->objects.p[i]->is_weak);
SerializeInt(&dox->buf, dox->objects.p[i]->is_inline);
SerializeInt(&dox->buf, dox->objects.p[i]->is_noreturn);
@ -248,6 +250,7 @@ static void SerializeAsmdown(struct DoxWriter *dox, struct Asmdown *ad,
SerializeStr(&dox->buf, filename);
SerializeInt(&dox->buf, ad->symbols.p[i].line);
SerializeInt(&dox->buf, true); // TODO: is_function
SerializeInt(&dox->buf, false); // is_variadic
SerializeInt(&dox->buf, false); // TODO: is_weak
SerializeInt(&dox->buf, false); // is_inline
SerializeInt(&dox->buf, false); // is_noreturn

108
third_party/chibicc/dox2.c

@ -47,6 +47,7 @@ struct Dox {
char *path;
int line;
bool is_function;
bool is_variadic;
bool is_weak;
bool is_inline;
bool is_noreturn;
@ -177,6 +178,7 @@ static void DeserializeObject(struct Dox *dox, struct DoxObject *o) {
o->path = DeserializeStr(dox);
o->line = DeserializeInt(dox);
o->is_function = DeserializeInt(dox);
o->is_variadic = DeserializeInt(dox);
o->is_weak = DeserializeInt(dox);
o->is_inline = DeserializeInt(dox);
o->is_noreturn = DeserializeInt(dox);
@ -210,7 +212,7 @@ static void DeserializeMacro(struct Dox *dox, struct DoxMacro *m) {
}
}
static void DeserializeDox(struct Dox *dox) {
static void DeserializeDox(struct Dox *dox, const char *path) {
int i, j, n;
i = dox->objects.n;
n = DeserializeInt(dox);
@ -242,7 +244,7 @@ static void ReadDox(struct Dox *dox, const StringArray *files) {
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)));
dox->p = map;
DeserializeDox(dox);
DeserializeDox(dox, files->data[i]);
munmap(map, st.st_size);
}
close(fd);
@ -317,15 +319,19 @@ static void IndexDox(struct Dox *dox) {
CompareDoxIndexEntry, dox);
}
/**
* Escapes HTML entities and interprets basic Markdown syntax.
*/
static void PrintText(FILE *f, const char *s) {
int c;
bool bol, pre, ul0, ul2, bt1, bt2;
for (bt1 = bt2 = ul2 = ul0 = pre = false, bol = true;;) {
bool bol, pre, ul0, ul2, ol0, ol2, bt1, bt2;
for (bt1 = bt2 = ul2 = ul0 = ol2 = ol0 = pre = false, bol = true;;) {
switch ((c = *s++)) {
case '\0':
if (bt1 || bt2) fprintf(f, "</code>");
if (pre) fprintf(f, "</pre>");
if (ul0 || ul2) fprintf(f, "</ul>");
if (ol0 || ol2) fprintf(f, "</ol>");
return;
case '&':
fprintf(f, "&amp;");
@ -368,14 +374,19 @@ static void PrintText(FILE *f, const char *s) {
bol = false;
break;
case '\n':
if (!pre && !ul0 && !ul2 && *s == '\n') {
if (!pre && !ul0 && !ul2 && !ol0 && !ol2 && *s == '\n') {
fprintf(f, "\n<p>");
bol = true;
} else if (pre && s[0] != '\n' &&
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) {
fprintf(f, "</pre>\n");
pre = false;
bol = true;
} else if (pre && s[0] != '\n') {
if (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ') {
fprintf(f, "</pre>\n");
pre = false;
bol = true;
} else {
fprintf(f, "\n");
bol = false;
s += 4;
}
} else if (ul0 && s[0] == '-' && s[1] == ' ') {
fprintf(f, "\n<li>");
s += 2;
@ -394,29 +405,65 @@ static void PrintText(FILE *f, const char *s) {
fprintf(f, "\n</ul>\n");
bol = true;
ul2 = false;
} else if (ol0 && ('0' <= s[0] && s[0] <= '9') && s[1] == '.' &&
s[2] == ' ') {
fprintf(f, "\n<li>");
s += 3;
bol = false;
} else if (ol2 && s[0] == ' ' && s[1] == ' ' &&
('0' <= s[2] && s[2] <= '9') && s[3] == '.' && s[3] == ' ') {
fprintf(f, "\n<li>");
s += 5;
bol = false;
} else if (ol0 && s[0] != '\n' && (s[0] != ' ' || s[1] != ' ')) {
fprintf(f, "\n</ol>\n");
bol = true;
ol0 = false;
} else if (ol2 && s[0] != '\n' &&
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) {
fprintf(f, "\n</ol>\n");
bol = true;
ol2 = false;
} else {
fprintf(f, "\n");
bol = true;
}
break;
case '-':
if (bol && !ul0 && !ul2 && s[0] == ' ') {
if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ') {
ul0 = true;
fprintf(f, "<ul><li>");
++s;
} else {
fprintf(f, "-");
}
bol = false;
break;
case '1':
if (bol && !ol0 && !ol2 && !ul0 && !ul2 && s[0] == '.' && s[1] == ' ') {
ol0 = true;
fprintf(f, "<ol><li>");
s += 2;
} else {
fprintf(f, "1");
}
bol = false;
break;
case ' ':
if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') {
pre = true;
fprintf(f, "<pre> ");
} else if (bol && !ul0 && !ul2 && s[0] == ' ' && s[1] == '-' &&
s[2] == ' ') {
fprintf(f, "<pre>");
s += 3;
} else if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ' &&
s[1] == '-' && s[2] == ' ') {
ul2 = true;
fprintf(f, "<ul><li>");
s += 3;
} else if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ' &&
('0' <= s[1] && s[1] <= '9') && s[2] == '.' && s[3] == ' ') {
ol2 = true;
fprintf(f, "<ol><li>");
s += 4;
} else {
fprintf(f, " ");
}
@ -469,6 +516,9 @@ static void PrintDox(struct Dox *dox, FILE *f) {
.nav {\n\
margin-bottom: 0;\n\
}\n\
.toc {\n\
overflow-x: auto;\n\
}\n\
.toc a {\n\
text-decoration: none;\n\
}\n\
@ -514,7 +564,10 @@ static void PrintDox(struct Dox *dox, FILE *f) {
</style>\n\
\n\
<header>\n\
<img width=\"196\" height=\"105\" src=\"//storage.googleapis.com/justine/cosmopolitan/cosmopolitan.png\" alt=\"honeybadger\">\n\
<img width=\"196\" height=\"105\"\n\
src=\"//storage.googleapis.com/justine/cosmopolitan/cosmopolitan.png\"\n\
title=\"cosmopolitan honeybadger\"\n\
alt=\"honeybadger\">\n\
<h1>cosmopolitan libc</h1>\n\
<span>build-once run-anywhere c without devops</span>\n\
</header>\n\
@ -533,7 +586,7 @@ static void PrintDox(struct Dox *dox, FILE *f) {
\n\
<table class=\"dox\" width=\"960\">\n\
<tr>\n\
<td width=\"320\" valign=\"top\" class=\"toc\">\n\
<td width=\"283\" valign=\"top\" class=\"toc\">\n\
");
/* // lefthand index: objects */
@ -581,7 +634,7 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
// righthand contents
fprintf(f, "<td width=\"640\" valign=\"top\">\n");
fprintf(f, "<td width=\"667\" valign=\"top\">\n");
for (i = 0; i < dox->index.n; ++i) {
if (dox->index.p[i].t == kObject) {
o = dox->objects.p + dox->index.p[i].i;
@ -606,7 +659,8 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
// parameters
if (o->is_function && (o->params.n || HasTag(o->javadown, "param"))) {
if (o->is_function &&
(o->is_variadic || o->params.n || HasTag(o->javadown, "param"))) {
fprintf(f, "<div class=\"tag\">\n");
fprintf(f, "<span class=\"tagname\">@param</span>\n");
fprintf(f, "<dl>\n");
@ -641,6 +695,9 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
}
}
if (o->is_variadic) {
fprintf(f, "<dt>...\n");
}
fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag
}
@ -676,6 +733,17 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
}
// type
if (!o->is_function) {
fprintf(f, "<div class=\"tag\">\n");
fprintf(f, "<span class=\"tagname\">@type</span>\n");
fprintf(f, "<dl>\n");
fprintf(f, "<dt>");
PrintText(f, o->type);
fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag
}
// tags
if (o->javadown) {
for (k = 0; k < o->javadown->tags.n; ++k) {
@ -714,21 +782,18 @@ static void PrintDox(struct Dox *dox, FILE *f) {
if (i) fprintf(f, "<hr>");
fprintf(f, "<div id=\"%s\" class=\"api\">\n", m->name);
fprintf(f, "<h3><a href=\"#%s\">%s</a></h3>", m->name, m->name);
// title
if (m->javadown && *m->javadown->title) {
fprintf(f, "<p>");
PrintText(f, m->javadown->title);
fprintf(f, "\n");
}
// text
if (m->javadown && *m->javadown->text) {
fprintf(f, "<p>");
PrintText(f, m->javadown->text);
fprintf(f, "\n");
}
// parameters
if (!m->is_objlike && (m->params.n || HasTag(m->javadown, "param"))) {
fprintf(f, "<div class=\"tag\">\n");
@ -767,7 +832,6 @@ static void PrintDox(struct Dox *dox, FILE *f) {
fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag
}
fprintf(f, "</div>\n"); /* class=".api" */
}
}

106
third_party/chibicc/file.c

@ -0,0 +1,106 @@
#include "third_party/chibicc/chibicc.h"
// Slurps contents of file.
char *read_file(const char *path) {
char *p;
FILE *fp;
int buflen, nread, end, n;
if (!strcmp(path, "-")) {
fp = stdin;
} else {
fp = fopen(path, "r");
if (!fp) return NULL;
}
buflen = 4096;
nread = 0;
p = calloc(1, buflen);
for (;;) {
end = buflen - 2;
n = fread(p + nread, 1, end - nread, fp);
if (n == 0) break;
nread += n;
if (nread == end) {
buflen *= 2;
p = realloc(p, buflen);
}
}
if (fp != stdin) fclose(fp);
if (nread > 0 && p[nread - 1] == '\\') {
p[nread - 1] = '\n';
} else if (nread == 0 || p[nread - 1] != '\n') {
p[nread++] = '\n';
}
p[nread] = '\0';
return p;
}
char *skip_bom(char *p) {
// UTF-8 texts may start with a 3-byte "BOM" marker sequence.
// If exists, just skip them because they are useless bytes.
// (It is actually not recommended to add BOM markers to UTF-8
// texts, but it's not uncommon particularly on Windows.)
if (!memcmp(p, "\357\273\277", 3)) p += 3;
return p;
}
// Replaces \r or \r\n with \n.
void canonicalize_newline(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '\r' && p[i + 1] == '\n') {
i += 2;
p[j++] = '\n';
} else if (p[i] == '\r') {
i++;
p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
// Removes backslashes followed by a newline.
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;
bool instring = false;
while (p[i]) {
if (instring) {
if (p[i] == '"' && p[i - 1] != '\\') {
instring = false;
}
} else {
if (p[i] == '"') {
instring = true;
} else if (p[i] == '/' && p[i + 1] == '*') {
p[j++] = p[i++];
p[j++] = p[i++];
while (p[i]) {
if (p[i] == '*' && p[i + 1] == '/') {
p[j++] = p[i++];
p[j++] = p[i++];
break;
} else {
p[j++] = p[i++];
}
}
continue;
}
}
if (p[i] == '\\' && p[i + 1] == '\n') {
i += 2;
n++;
} else if (p[i] == '\n') {
p[j++] = p[i++];
for (; n > 0; n--) p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
for (; n > 0; n--) p[j++] = '\n';
p[j] = '\0';
}

13
third_party/chibicc/file.h

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_
#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *skip_bom(char *);
char *read_file(const char *);
void remove_backslash_newline(char *);
void canonicalize_newline(char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_ */

50
third_party/chibicc/parse.c

@ -48,7 +48,6 @@ typedef struct {
bool is_static;
bool is_extern;
bool is_inline;
bool is_const;
bool is_tls;
bool is_weak;
bool is_ms_abi;
@ -233,6 +232,8 @@ static Node *new_ulong(long val, Token *tok) {
}
static Node *new_var_node(Obj *var, Token *tok) {
if (!var) DebugBreak();
CHECK_NOTNULL(var);
Node *node = new_node(ND_VAR, tok);
node->var = var;
return node;
@ -647,6 +648,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
};
Type *ty = copy_type(ty_int);
int counter = 0;
bool is_const = false;
bool is_atomic = false;
while (is_typename(tok)) {
// Handle storage class specifiers.
@ -682,7 +684,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
goto Continue;
}
if (CONSUME(&tok, tok, "const")) {
if (attr) attr->is_const = true;
is_const = true;
goto Continue;
}
// These keywords are recognized but ignored.
@ -841,6 +843,10 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
ty = copy_type(ty);
ty->is_atomic = true;
}
/* if (attr && is_const) { */
/* ty = copy_type(ty); */
/* ty->is_const = true; */
/* } */
*rest = tok;
return ty;
}
@ -873,6 +879,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type head = {};
Type *cur = &head;
bool is_variadic = false;
enter_scope();
while (!EQUAL(tok, ")")) {
if (cur != &head) tok = skip(tok, ',');
if (EQUAL(tok, "...")) {
@ -884,6 +891,9 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type *ty2 = declspec(&tok, tok, NULL);
ty2 = declarator(&tok, tok, ty2);
Token *name = ty2->name;
if (name) {
new_lvar(strndup(name->loc, name->len), ty2);
}
if (ty2->kind == TY_ARRAY) {
// "array of T" is converted to "pointer to T" only in the parameter
// context. For example, *argv[] is converted to **argv by this.
@ -897,6 +907,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
}
cur = cur->next = copy_type(ty2);
}
leave_scope();
if (cur == &head) is_variadic = true;
ty = func_type(ty);
ty->params = head.next;
@ -2471,6 +2482,16 @@ static Node *shift(Token **rest, Token *tok) {
}
}
static Node *get_vla_size(Type *ty, Token *tok) {
if (ty->vla_size) {
return new_var_node(ty->vla_size, tok);
} else {
Node *lhs = compute_vla_size(ty, tok);
Node *rhs = new_var_node(ty->vla_size, tok);
return new_binary(ND_COMMA, lhs, rhs, tok);
}
}
// In C, `+` operator is overloaded to perform the pointer arithmetic.
// If p is a pointer, p+n adds not n but sizeof(*p)*n to the value of p,
// so that p+n points to the location n elements (not bytes) ahead of p.
@ -2491,8 +2512,7 @@ static Node *new_add(Node *lhs, Node *rhs, Token *tok) {
}
// VLA + num
if (lhs->ty->base->kind == TY_VLA) {
rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok),
tok);
rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
return new_binary(ND_ADD, lhs, rhs, tok);
}
// ptr + num
@ -2509,8 +2529,7 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) {
return new_binary(ND_SUB, lhs, rhs, tok);
// VLA + num
if (lhs->ty->base->kind == TY_VLA) {
rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok),
tok);
rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
add_type(rhs);
Node *node = new_binary(ND_SUB, lhs, rhs, tok);
node->ty = lhs->ty;
@ -3044,7 +3063,9 @@ static Node *primary(Token **rest, Token *tok) {
if (EQUAL(tok, "sizeof")) {
Node *node = unary(rest, tok->next);
add_type(node);
if (node->ty->kind == TY_VLA) return new_var_node(node->ty->vla_size, tok);
if (node->ty->kind == TY_VLA) {
return get_vla_size(node->ty, tok);
}
return new_ulong(node->ty->size, tok);
}
if ((EQUAL(tok, "_Alignof") || EQUAL(tok, "__alignof__")) &&
@ -3416,8 +3437,9 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
fn->is_no_instrument_function |= attr->is_no_instrument_function;
fn->is_force_align_arg_pointer |= attr->is_force_align_arg_pointer;
fn->is_no_caller_saved_registers |= attr->is_no_caller_saved_registers;
fn->javadown = fn->javadown ?: current_javadown;
fn->is_root = !(fn->is_static && fn->is_inline);
fn->javadown = fn->javadown ?: current_javadown;
current_javadown = NULL;
if (consume_attribute(&tok, tok, "asm")) {
tok = skip(tok, '(');
fn->asmname = ConsumeStringLiteral(&tok, tok);
@ -3526,16 +3548,20 @@ static void scan_globals(void) {
globals = head.next;
}
static char *prefix_builtin(const char *name) {
return xstrcat("__builtin_", name);
}
static Obj *declare0(char *name, Type *ret) {
if (!opt_no_builtin) new_gvar(name, func_type(ret));
return new_gvar(xstrcat("__builtin_", name), func_type(ret));
return new_gvar(prefix_builtin(name), func_type(ret));
}
static Obj *declare1(char *name, Type *ret, Type *p1) {
Type *ty = func_type(ret);
ty->params = copy_type(p1);
if (!opt_no_builtin) new_gvar(name, ty);
return new_gvar(xstrcat("__builtin_", name), ty);
return new_gvar(prefix_builtin(name), ty);
}
static Obj *declare2(char *name, Type *ret, Type *p1, Type *p2) {
@ -3543,7 +3569,7 @@ static Obj *declare2(char *name, Type *ret, Type *p1, Type *p2) {
ty->params = copy_type(p1);
ty->params->next = copy_type(p2);
if (!opt_no_builtin) new_gvar(name, ty);
return new_gvar(xstrcat("__builtin_", name), ty);
return new_gvar(prefix_builtin(name), ty);
}
static Obj *declare3(char *s, Type *r, Type *a, Type *b, Type *c) {
@ -3552,7 +3578,7 @@ static Obj *declare3(char *s, Type *r, Type *a, Type *b, Type *c) {
ty->params->next = copy_type(b);
ty->params->next->next = copy_type(c);
if (!opt_no_builtin) new_gvar(s, ty);
return new_gvar(xstrcat("__builtin_", s), ty);
return new_gvar(prefix_builtin(s), ty);
}
static void math0(char *name) {

1
third_party/chibicc/test/asm_test.c

@ -1,3 +1,4 @@
asm(".ident\t\"hello\"");
/*-*- 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

23
third_party/chibicc/test/vla_test.c

@ -1,7 +1,30 @@
#include "libc/macros.h"
#include "third_party/chibicc/test/test.h"
int index1d(int xn, int p[xn], int x) {
return p[x];
}
int index2d(int yn, int xn, int (*p)[yn][xn], int y, int x) {
return (*p)[y][x];
}