mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-29 05:50:27 +00:00
Improve documentation
The Cosmo API documentation page is pretty good now https://justine.lol/cosmopolitan/documentation.html
This commit is contained in:
parent
13437dd19b
commit
1bc3a25505
367 changed files with 2542 additions and 26178 deletions
56
third_party/chibicc/as.c
vendored
56
third_party/chibicc/as.c
vendored
|
@ -2707,15 +2707,6 @@ static noinline void OpFpu1(struct As *a, int op, int reg) {
|
|||
OpFpu1Impl(a, op, reg);
|
||||
}
|
||||
|
||||
static void OnFucomi(struct As *a, struct Slice s) {
|
||||
int reg, rm;
|
||||
rm = !IsPunct(a, a->i, ';') ? GetRegisterRm(a) : 1;
|
||||
reg = !IsPunct(a, a->i, ';') ? GetRegisterReg(a) : 0;
|
||||
if (reg & 7) Fail(a, "bad register");
|
||||
EmitByte(a, 0xDB);
|
||||
EmitByte(a, 0350 | rm & 7);
|
||||
}
|
||||
|
||||
static void OnFxch(struct As *a, struct Slice s) {
|
||||
int rm;
|
||||
rm = !IsPunct(a, a->i, ';') ? GetRegisterRm(a) : 1;
|
||||
|
@ -2731,6 +2722,18 @@ static void OnBswap(struct As *a, struct Slice s) {
|
|||
EmitByte(a, 0310 | srm & 7);
|
||||
}
|
||||
|
||||
static noinline void OpFcomImpl(struct As *a, int op) {
|
||||
int reg, rm;
|
||||
rm = !IsPunct(a, a->i, ';') ? GetRegisterRm(a) : 1;
|
||||
reg = !IsPunct(a, a->i, ';') ? GetRegisterReg(a) : 0;
|
||||
if (reg & 7) Fail(a, "bad register");
|
||||
EmitVarword(a, op | rm & 7);
|
||||
}
|
||||
|
||||
static noinline void OpFcom(struct As *a, int op) {
|
||||
OpFcomImpl(a, op);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static void OnAdc(struct As *a, struct Slice s) { OpAlu(a, s, 2); }
|
||||
static void OnAdd(struct As *a, struct Slice s) { OpAlu(a, s, 0); }
|
||||
|
@ -2803,13 +2806,22 @@ static void OnDivps(struct As *a, struct Slice s) { OpSse(a, 0x0F5E); }
|
|||
static void OnDivsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5E); }
|
||||
static void OnDivss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5E); }
|
||||
static void OnDppd(struct As *a, struct Slice s) { OpSse(a, 0x660F3A41); }
|
||||
static void OnFabs(struct As *a, struct Slice s) { EmitVarword(a, 0xd9e1); }
|
||||
static void OnFabs(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E1); }
|
||||
static void OnFaddl(struct As *a, struct Slice s) { OpFpu1(a, 0xDC, 0); }
|
||||
static void OnFaddp(struct As *a, struct Slice s) { EmitVarword(a, 0xdec1); }
|
||||
static void OnFaddp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEC1); }
|
||||
static void OnFadds(struct As *a, struct Slice s) { OpFpu1(a, 0xD8, 0); }
|
||||
static void OnFchs(struct As *a, struct Slice s) { EmitVarword(a, 0xd9e0); }
|
||||
static void OnFcomip(struct As *a, struct Slice s) { EmitVarword(a, 0xdff1); }
|
||||
static void OnFdivrp(struct As *a, struct Slice s) { EmitVarword(a, 0xdef9); }
|
||||
static void OnFchs(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E0); }
|
||||
static void OnFcmovb(struct As *a, struct Slice s) { OpFcom(a, 0xDAC0); }
|
||||
static void OnFcmovbe(struct As *a, struct Slice s) { OpFcom(a, 0xDAD0); }
|
||||
static void OnFcmove(struct As *a, struct Slice s) { OpFcom(a, 0xDAC8); }
|
||||
static void OnFcmovnb(struct As *a, struct Slice s) { OpFcom(a, 0xDBC0); }
|
||||
static void OnFcmovnbe(struct As *a, struct Slice s) { OpFcom(a, 0xDBD0); }
|
||||
static void OnFcmovne(struct As *a, struct Slice s) { OpFcom(a, 0xDBC8); }
|
||||
static void OnFcmovnu(struct As *a, struct Slice s) { OpFcom(a, 0xDBD8); }
|
||||
static void OnFcmovu(struct As *a, struct Slice s) { OpFcom(a, 0xDAD8); }
|
||||
static void OnFcomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBF0); }
|
||||
static void OnFcomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFF0); }
|
||||
static void OnFdivrp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEF9); }
|
||||
static void OnFildl(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 0); }
|
||||
static void OnFildll(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 5); }
|
||||
static void OnFildq(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 5); }
|
||||
|
@ -2837,9 +2849,11 @@ static void OnFstps(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 3); }
|
|||
static void OnFstpt(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 7); }
|
||||
static void OnFsubrp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEE9); }
|
||||
static void OnFtst(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E4); }
|
||||
static void OnFucomip(struct As *a, struct Slice s) { EmitVarword(a, 0xDFE9); }
|
||||
static void OnFucomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBE8); }
|
||||
static void OnFucomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFE8); }
|
||||
static void OnFwait(struct As *a, struct Slice s) { EmitByte(a, 0x9B); }
|
||||
static void OnFxam(struct As *a, struct Slice s) { EmitVarword(a, 0xd9e5); }
|
||||
static void OnFxam(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E5); }
|
||||
static void OnFxtract(struct As *a, struct Slice s) { EmitVarword(a, 0xD9F4); }
|
||||
static void OnHaddpd(struct As *a, struct Slice s) { OpSse(a, 0x660F7C); }
|
||||
static void OnHaddps(struct As *a, struct Slice s) { OpSse(a, 0xF20F7C); }
|
||||
static void OnHlt(struct As *a, struct Slice s) { EmitByte(a, 0xF4); }
|
||||
|
@ -3211,6 +3225,15 @@ static const struct Directive8 {
|
|||
{"faddp", OnFaddp}, //
|
||||
{"fadds", OnFadds}, //
|
||||
{"fchs", OnFchs}, //
|
||||
{"fcmovb", OnFcmovb}, //
|
||||
{"fcmovbe", OnFcmovbe}, //
|
||||
{"fcmove", OnFcmove}, //
|
||||
{"fcmovnb", OnFcmovnb}, //
|
||||
{"fcmovnbe", OnFcmovnbe}, //
|
||||
{"fcmovne", OnFcmovne}, //
|
||||
{"fcmovnu", OnFcmovnu}, //
|
||||
{"fcmovu", OnFcmovu}, //
|
||||
{"fcomi", OnFcomi}, //
|
||||
{"fcomip", OnFcomip}, //
|
||||
{"fdivrp", OnFdivrp}, //
|
||||
{"fildl", OnFildl}, //
|
||||
|
@ -3246,6 +3269,7 @@ static const struct Directive8 {
|
|||
{"fwait", OnFwait}, //
|
||||
{"fxam", OnFxam}, //
|
||||
{"fxch", OnFxch}, //
|
||||
{"fxtract", OnFxtract}, //
|
||||
{"haddpd", OnHaddpd}, //
|
||||
{"haddps", OnHaddps}, //
|
||||
{"hlt", OnHlt}, //
|
||||
|
|
45
third_party/chibicc/chibicc.c
vendored
45
third_party/chibicc/chibicc.c
vendored
|
@ -1,3 +1,5 @@
|
|||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
|
@ -381,10 +383,9 @@ static bool run_subprocess(char **argv) {
|
|||
for (int i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if (fork() == 0) {
|
||||
if (!vfork()) {
|
||||
// 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.
|
||||
|
@ -503,7 +504,7 @@ static Token *append_tokens(Token *tok1, Token *tok2) {
|
|||
return tok1;
|
||||
}
|
||||
|
||||
static FileType get_file_type(char *filename) {
|
||||
static FileType get_file_type(const char *filename) {
|
||||
if (opt_x != FILE_NONE) return opt_x;
|
||||
if (endswith(filename, ".a")) return FILE_AR;
|
||||
if (endswith(filename, ".o")) return FILE_OBJ;
|
||||
|
@ -514,7 +515,13 @@ static FileType get_file_type(char *filename) {
|
|||
}
|
||||
|
||||
static void cc1(void) {
|
||||
FileType ft;
|
||||
Token *tok = NULL;
|
||||
ft = get_file_type(base_file);
|
||||
if (opt_J && (ft == FILE_ASM || ft == FILE_ASM_CPP)) {
|
||||
output_javadown_asm(output_file, base_file);
|
||||
return;
|
||||
}
|
||||
// Process -include option
|
||||
for (int i = 0; i < opt_include.len; i++) {
|
||||
char *incl = opt_include.data[i];
|
||||
|
@ -538,7 +545,7 @@ static void cc1(void) {
|
|||
if (opt_M) return;
|
||||
}
|
||||
// If -E is given, print out preprocessed C code as a result.
|
||||
if (opt_E || get_file_type(base_file) == FILE_ASM_CPP) {
|
||||
if (opt_E || ft == FILE_ASM_CPP) {
|
||||
print_tokens(tok);
|
||||
return;
|
||||
}
|
||||
|
@ -605,8 +612,13 @@ static void run_linker(StringArray *inputs, char *output) {
|
|||
handle_exit(run_subprocess(arr.data));
|
||||
}
|
||||
|
||||
static void OnCtrlC(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int chibicc(int argc, char **argv) {
|
||||
showcrashreports();
|
||||
sigaction(SIGINT, &(struct sigaction){.sa_sigaction = OnCtrlC}, NULL);
|
||||
atexit(cleanup);
|
||||
init_macros();
|
||||
parse_args(argc, argv);
|
||||
|
@ -649,6 +661,18 @@ int chibicc(int argc, char **argv) {
|
|||
strarray_push(&ld_args, input);
|
||||
continue;
|
||||
}
|
||||
// Dox
|
||||
if (opt_J) {
|
||||
if (opt_c) {
|
||||
handle_exit(run_cc1(argc, argv, input, output));
|
||||
} else {
|
||||
char *tmp = create_tmpfile();
|
||||
if (run_cc1(argc, argv, input, tmp)) {
|
||||
strarray_push(&dox_args, tmp);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Handle .s
|
||||
if (type == FILE_ASM) {
|
||||
if (!opt_S) {
|
||||
|
@ -657,6 +681,11 @@ int chibicc(int argc, char **argv) {
|
|||
continue;
|
||||
}
|
||||
assert(type == FILE_C || type == FILE_ASM_CPP);
|
||||
// Just print ast.
|
||||
if (opt_A) {
|
||||
handle_exit(run_cc1(argc, argv, input, NULL));
|
||||
continue;
|
||||
}
|
||||
// Just preprocess
|
||||
if (opt_E || opt_M) {
|
||||
handle_exit(run_cc1(argc, argv, input, NULL));
|
||||
|
@ -674,14 +703,6 @@ int chibicc(int argc, char **argv) {
|
|||
assemble(tmp, output);
|
||||
continue;
|
||||
}
|
||||
// Dox
|
||||
if (opt_J) {
|
||||
char *tmp = create_tmpfile();
|
||||
if (run_cc1(argc, argv, input, tmp)) {
|
||||
strarray_push(&dox_args, tmp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Compile, assemble and link
|
||||
char *tmp1 = create_tmpfile();
|
||||
char *tmp2 = create_tmpfile();
|
||||
|
|
9
third_party/chibicc/chibicc.h
vendored
9
third_party/chibicc/chibicc.h
vendored
|
@ -272,6 +272,7 @@ struct Obj {
|
|||
bool is_destructor;
|
||||
bool is_constructor;
|
||||
bool is_ms_abi; /* TODO */
|
||||
bool is_no_instrument_function;
|
||||
bool is_force_align_arg_pointer;
|
||||
bool is_no_caller_saved_registers;
|
||||
int stack_size;
|
||||
|
@ -616,10 +617,16 @@ Obj *alloc_obj(void);
|
|||
Type *alloc_type(void);
|
||||
|
||||
//
|
||||
// javadown.c
|
||||
// dox1.c
|
||||
//
|
||||
|
||||
void output_javadown(const char *, Obj *);
|
||||
void output_javadown_asm(const char *, const char *);
|
||||
|
||||
//
|
||||
// dox2.c
|
||||
//
|
||||
|
||||
void drop_dox(const StringArray *, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
9
third_party/chibicc/chibicc.mk
vendored
9
third_party/chibicc/chibicc.mk
vendored
|
@ -116,15 +116,6 @@ o/$(MODE)/third_party/chibicc/as.com.dbg: \
|
|||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/hello.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
$(APE) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/hello.chibicc.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/chibicc.o: \
|
||||
CPPFLAGS += $(THIRD_PARTY_CHIBICC_DEFINES)
|
||||
|
||||
|
|
78
third_party/chibicc/codegen.c
vendored
78
third_party/chibicc/codegen.c
vendored
|
@ -973,6 +973,12 @@ static bool gen_builtin_funcall(Node *node, const char *name) {
|
|||
pop("%rax");
|
||||
return true;
|
||||
}
|
||||
} else if (!strcmp(name, "logbl")) {
|
||||
gen_expr(node->args);
|
||||
emitlin("\
|
||||
\tfxtract\n\
|
||||
\tfstp\t%st");
|
||||
return true;
|
||||
} else if (!strcmp(name, "isgreater")) {
|
||||
gen_comis(node, "comisd", 1, 0, "a");
|
||||
return true;
|
||||
|
@ -1010,17 +1016,17 @@ static bool gen_builtin_funcall(Node *node, const char *name) {
|
|||
\tflds\t(%rsp)\n\
|
||||
\tpop\t%rax");
|
||||
return true;
|
||||
} else if (!strcmp(name, "inff")) {
|
||||
} else if (!strcmp(name, "inff") || !strcmp(name, "huge_valf")) {
|
||||
emitlin("\
|
||||
\tmov\t$0x7f800000,%eax\n\
|
||||
\tmovd\t%eax,%xmm0");
|
||||
return true;
|
||||
} else if (!strcmp(name, "inf")) {
|
||||
} else if (!strcmp(name, "inf") || !strcmp(name, "huge_val")) {
|
||||
emitlin("\
|
||||
\tmov\t$0x7ff0000000000000,%rax\n\
|
||||
\tmovq\t%rax,%xmm0");
|
||||
return true;
|
||||
} else if (!strcmp(name, "infl")) {
|
||||
} else if (!strcmp(name, "infl") || !strcmp(name, "huge_vall")) {
|
||||
emitlin("\
|
||||
\tpush\t$0x7f800000\n\
|
||||
\tflds\t(%rsp)\n\
|
||||
|
@ -2304,6 +2310,42 @@ static void store_gp(int r, int offset, int sz) {
|
|||
}
|
||||
}
|
||||
|
||||
static void emit_function_hook(void) {
|
||||
if (opt_nop_mcount) {
|
||||
print_profiling_nop();
|
||||
} else if (opt_fentry) {
|
||||
emitlin("\tcall\t__fentry__@gotpcrel(%rip)");
|
||||
} else if (opt_pg) {
|
||||
emitlin("\tcall\tmcount@gotpcrel(%rip)");
|
||||
} else {
|
||||
print_profiling_nop();
|
||||
}
|
||||
}
|
||||
|
||||
static void save_caller_saved_registers(void) {
|
||||
emitlin("\
|
||||
\tpush\t%rdi\n\
|
||||
\tpush\t%rsi\n\
|
||||
\tpush\t%rdx\n\
|
||||
\tpush\t%rcx\n\
|
||||
\tpush\t%r8\n\
|
||||
\tpush\t%r9\n\
|
||||
\tpush\t%r10\n\
|
||||
\tpush\t%r11");
|
||||
}
|
||||
|
||||
static void restore_caller_saved_registers(void) {
|
||||
emitlin("\
|
||||
\tpop\t%r11\n\
|
||||
\tpop\t%r10\n\
|
||||
\tpop\t%r9\n\
|
||||
\tpop\t%r8\n\
|
||||
\tpop\t%rcx\n\
|
||||
\tpop\t%rdx\n\
|
||||
\tpop\t%rsi\n\
|
||||
\tpop\t%rdi");
|
||||
}
|
||||
|
||||
static void emit_text(Obj *prog) {
|
||||
for (Obj *fn = prog; fn; fn = fn->next) {
|
||||
if (!fn->is_function || !fn->is_definition) continue;
|
||||
|
@ -2327,14 +2369,8 @@ static void emit_text(Obj *prog) {
|
|||
// Prologue
|
||||
emitlin("\tpush\t%rbp");
|
||||
emitlin("\tmov\t%rsp,%rbp");
|
||||
if (opt_nop_mcount) {
|
||||
print_profiling_nop();
|
||||
} else if (opt_fentry) {
|
||||
emitlin("\tcall\t__fentry__@gotpcrel(%rip)");
|
||||
} else if (opt_pg) {
|
||||
emitlin("\tcall\tmcount@gotpcrel(%rip)");
|
||||
} else {
|
||||
print_profiling_nop();
|
||||
if (!fn->is_no_instrument_function) {
|
||||
emit_function_hook();
|
||||
}
|
||||
println("\tsub\t$%d,%%rsp", fn->stack_size);
|
||||
println("\tmov\t%%rsp,%d(%%rbp)", fn->alloca_bottom->offset);
|
||||
|
@ -2410,15 +2446,7 @@ static void emit_text(Obj *prog) {
|
|||
emitlin("\tand\t$-16,%rsp");
|
||||
}
|
||||
if (fn->is_no_caller_saved_registers) {
|
||||
emitlin("\
|
||||
\tpush\t%rdi\n\
|
||||
\tpush\t%rsi\n\
|
||||
\tpush\t%rdx\n\
|
||||
\tpush\t%rcx\n\
|
||||
\tpush\t%r8\n\
|
||||
\tpush\t%r9\n\
|
||||
\tpush\t%r10\n\
|
||||
\tpush\t%r11");
|
||||
save_caller_saved_registers();
|
||||
}
|
||||
// Emit code
|
||||
gen_stmt(fn->body);
|
||||
|
@ -2436,15 +2464,7 @@ static void emit_text(Obj *prog) {
|
|||
emitlin("\tud2");
|
||||
} else {
|
||||
if (fn->is_no_caller_saved_registers) {
|
||||
emitlin("\
|
||||
\tpop\t%r11\n\
|
||||
\tpop\t%r10\n\
|
||||
\tpop\t%r9\n\
|
||||
\tpop\t%r8\n\
|
||||
\tpop\t%rcx\n\
|
||||
\tpop\t%rdx\n\
|
||||
\tpop\t%rsi\n\
|
||||
\tpop\t%rdi");
|
||||
restore_caller_saved_registers();
|
||||
}
|
||||
emitlin("\tleave");
|
||||
emitlin("\tret");
|
||||
|
|
155
third_party/chibicc/dox1.c
vendored
155
third_party/chibicc/dox1.c
vendored
|
@ -17,7 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/chibicc/chibicc.h"
|
||||
#include "tool/build/lib/asmdown.h"
|
||||
|
||||
#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p))
|
||||
|
||||
|
@ -101,30 +105,34 @@ static char *DescribeType(struct Type *ty) {
|
|||
return DescribeScalar(ty, "double");
|
||||
case TY_LDOUBLE:
|
||||
return DescribeScalar(ty, "long double");
|
||||
case TY_FUNC:
|
||||
return xasprintf("%s(*)()", gc(DescribeType(ty->return_ty)));
|
||||
case TY_PTR:
|
||||
return xasprintf("%s*", gc(DescribeType(ty->base)));
|
||||
if (ty->base->kind == TY_FUNC) {
|
||||
return DescribeType(ty->base);
|
||||
} else {
|
||||
return xasprintf("%s*", gc(DescribeType(ty->base)));
|
||||
}
|
||||
case TY_ARRAY:
|
||||
return xasprintf("%s[%d]", gc(DescribeType(ty->base)), ty->array_len);
|
||||
case TY_ENUM:
|
||||
if (ty->name_pos) {
|
||||
return xasprintf("enum %.*s", ty->name_pos->len, ty->name_pos->loc);
|
||||
if (ty->name) {
|
||||
return xasprintf("enum %.*s", ty->name->len, ty->name->loc);
|
||||
} else {
|
||||
return strdup("ANONYMOUS-ENUM");
|
||||
}
|
||||
case TY_STRUCT:
|
||||
if (ty->name_pos) {
|
||||
return xasprintf("struct %.*s", ty->name_pos->len, ty->name_pos->loc);
|
||||
if (ty->name) {
|
||||
return xasprintf("struct %.*s", ty->name->len, ty->name->loc);
|
||||
} else {
|
||||
return strdup("ANONYMOUS-STRUCT");
|
||||
}
|
||||
case TY_UNION:
|
||||
if (ty->name_pos) {
|
||||
return xasprintf("union %.*s", ty->name_pos->len, ty->name_pos->loc);
|
||||
if (ty->name) {
|
||||
return xasprintf("union %.*s", ty->name->len, ty->name->loc);
|
||||
} else {
|
||||
return strdup("ANONYMOUS-UNION");
|
||||
}
|
||||
case TY_FUNC:
|
||||
return xasprintf("%s(*)()", gc(DescribeType(ty->return_ty)));
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -136,6 +144,12 @@ static int CountParams(Obj *params) {
|
|||
return n;
|
||||
}
|
||||
|
||||
static int CountMacroParams(struct MacroParam *params) {
|
||||
int n;
|
||||
for (n = 0; params; params = params->next) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static const char *GetFileName(Obj *obj) {
|
||||
if (obj->javadown && obj->javadown->file) return obj->javadown->file->name;
|
||||
if (obj->tok && obj->tok->file) return obj->tok->file->name;
|
||||
|
@ -155,7 +169,9 @@ static void SerializeDox(struct DoxWriter *dox, Obj *prog) {
|
|||
MacroParam *mparam;
|
||||
SerializeInt(&dox->buf, dox->objects.n);
|
||||
for (i = 0; i < dox->objects.n; ++i) {
|
||||
s = DescribeType(dox->objects.p[i]->ty);
|
||||
s = DescribeType(dox->objects.p[i]->is_function
|
||||
? dox->objects.p[i]->ty->return_ty
|
||||
: dox->objects.p[i]->ty);
|
||||
SerializeStr(&dox->buf, s);
|
||||
free(s);
|
||||
SerializeStr(&dox->buf, dox->objects.p[i]->name);
|
||||
|
@ -170,7 +186,10 @@ static void SerializeDox(struct DoxWriter *dox, Obj *prog) {
|
|||
SerializeInt(&dox->buf, dox->objects.p[i]->is_force_align_arg_pointer);
|
||||
SerializeInt(&dox->buf, dox->objects.p[i]->is_no_caller_saved_registers);
|
||||
SerializeStr(&dox->buf, dox->objects.p[i]->visibility);
|
||||
SerializeJavadown(&dox->buf, dox->objects.p[i]->javadown->javadown);
|
||||
SerializeInt(&dox->buf, !!dox->objects.p[i]->javadown);
|
||||
if (dox->objects.p[i]->javadown) {
|
||||
SerializeJavadown(&dox->buf, dox->objects.p[i]->javadown->javadown);
|
||||
}
|
||||
SerializeInt(&dox->buf, CountParams(dox->objects.p[i]->params));
|
||||
for (param = dox->objects.p[i]->params; param; param = param->next) {
|
||||
s = DescribeType(param->ty);
|
||||
|
@ -184,22 +203,93 @@ static void SerializeDox(struct DoxWriter *dox, Obj *prog) {
|
|||
SerializeStr(&dox->buf, dox->macros.p[i]->name);
|
||||
SerializeStr(&dox->buf, dox->macros.p[i]->javadown->file->name);
|
||||
SerializeInt(&dox->buf, dox->macros.p[i]->javadown->line_no);
|
||||
SerializeJavadown(&dox->buf, dox->macros.p[i]->javadown->javadown);
|
||||
SerializeInt(&dox->buf, dox->macros.p[i]->is_objlike);
|
||||
SerializeStr(&dox->buf, dox->macros.p[i]->va_args_name);
|
||||
SerializeInt(&dox->buf, !!dox->macros.p[i]->javadown);
|
||||
if (dox->macros.p[i]->javadown) {
|
||||
SerializeJavadown(&dox->buf, dox->macros.p[i]->javadown->javadown);
|
||||
}
|
||||
SerializeInt(&dox->buf, CountMacroParams(dox->macros.p[i]->params));
|
||||
for (mparam = dox->macros.p[i]->params; mparam; mparam = mparam->next) {
|
||||
SerializeStr(&dox->buf, mparam->name);
|
||||
}
|
||||
}
|
||||
SerializeInt(&dox->buf, 31337);
|
||||
}
|
||||
|
||||
static int IsJavadownParam(struct JavadownTag *jt) {
|
||||
return !strcmp(jt->tag, "param") && strchr(jt->text, ' ');
|
||||
}
|
||||
|
||||
static char *ExtractJavadownParamName(const char *text) {
|
||||
char *space;
|
||||
space = strchr(text, ' ');
|
||||
return strndup(text, space - text);
|
||||
}
|
||||
|
||||
static int CountJavadownParams(struct Javadown *jd) {
|
||||
int i, n;
|
||||
for (n = i = 0; i < jd->tags.n; ++i) {
|
||||
if (IsJavadownParam(jd->tags.p + i)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void SerializeAsmdown(struct DoxWriter *dox, struct Asmdown *ad,
|
||||
const char *filename) {
|
||||
char *s;
|
||||
int i, j;
|
||||
SerializeInt(&dox->buf, ad->symbols.n);
|
||||
for (i = 0; i < ad->symbols.n; ++i) {
|
||||
SerializeStr(&dox->buf, ""); // type
|
||||
SerializeStr(&dox->buf, ad->symbols.p[i].name);
|
||||
SerializeStr(&dox->buf, filename);
|
||||
SerializeInt(&dox->buf, ad->symbols.p[i].line);
|
||||
SerializeInt(&dox->buf, true); // TODO: is_function
|
||||
SerializeInt(&dox->buf, false); // TODO: is_weak
|
||||
SerializeInt(&dox->buf, false); // is_inline
|
||||
SerializeInt(&dox->buf, false); // is_noreturn
|
||||
SerializeInt(&dox->buf, false); // is_destructor
|
||||
SerializeInt(&dox->buf, false); // is_constructor
|
||||
SerializeInt(&dox->buf, false); // is_force_align_arg_pointer
|
||||
SerializeInt(&dox->buf, false); // is_no_caller_saved_registers
|
||||
SerializeStr(&dox->buf, ""); // TODO: visibility
|
||||
SerializeInt(&dox->buf, true); // has_javadown
|
||||
SerializeJavadown(&dox->buf, ad->symbols.p[i].javadown);
|
||||
SerializeInt(&dox->buf, CountJavadownParams(ad->symbols.p[i].javadown));
|
||||
for (j = 0; j < ad->symbols.p[i].javadown->tags.n; ++j) {
|
||||
if (IsJavadownParam(ad->symbols.p[i].javadown->tags.p + j)) {
|
||||
SerializeStr(&dox->buf, ""); // type
|
||||
s = ExtractJavadownParamName(ad->symbols.p[i].javadown->tags.p[j].text);
|
||||
SerializeStr(&dox->buf, s); // name
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
SerializeInt(&dox->buf, 0); // macros
|
||||
SerializeInt(&dox->buf, 31337);
|
||||
}
|
||||
|
||||
static void LoadPublicDefinitions(struct DoxWriter *dox, Obj *prog) {
|
||||
int i;
|
||||
Obj *obj;
|
||||
Macro *macro;
|
||||
for (obj = prog; obj; obj = obj->next) {
|
||||
if (!obj->javadown) {
|
||||
if (*obj->name == '_') continue;
|
||||
if (strchr(obj->name, '$')) continue;
|
||||
if (startswith(obj->name, "__gdtoa_")) continue;
|
||||
if (obj->visibility && !strcmp(obj->visibility, "hidden")) continue;
|
||||
if (!obj->is_definition && (!obj->is_function || !obj->params ||
|
||||
!obj->params->name || !*obj->params->name)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (obj->is_static) continue;
|
||||
if (*obj->name == '_') continue;
|
||||
if (!obj->javadown) continue;
|
||||
if (obj->is_string_literal) continue;
|
||||
if (obj->visibility && !strcmp(obj->visibility, "hidden")) continue;
|
||||
if (strchr(obj->name, '$')) continue;
|
||||
if (obj->section && startswith(obj->section, ".init_array")) continue;
|
||||
APPEND(dox->objects);
|
||||
dox->objects.p[dox->objects.n - 1] = obj;
|
||||
}
|
||||
|
@ -209,8 +299,8 @@ static void LoadPublicDefinitions(struct DoxWriter *dox, Obj *prog) {
|
|||
macro = macros.buckets[i].val;
|
||||
if (!macro->javadown) continue;
|
||||
if (!macro->javadown->javadown) continue;
|
||||
if (*macro->name == '_') continue;
|
||||
if (strchr(macro->name, '$')) continue;
|
||||
/* if (*macro->name == '_') continue; */
|
||||
/* if (strchr(macro->name, '$')) continue; */
|
||||
APPEND(dox->macros);
|
||||
dox->macros.p[dox->macros.n - 1] = macro;
|
||||
}
|
||||
|
@ -237,7 +327,7 @@ static void WriteDox(struct DoxWriter *dox, const char *path) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Emits documentation datum for compilation unit just parsed.
|
||||
* Emits documentation data for compilation unit just parsed.
|
||||
*/
|
||||
void output_javadown(const char *path, Obj *prog) {
|
||||
struct DoxWriter *dox = NewDoxWriter();
|
||||
|
@ -246,3 +336,30 @@ void output_javadown(const char *path, Obj *prog) {
|
|||
WriteDox(dox, path);
|
||||
FreeDoxWriter(dox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits documentation data for assembly source file.
|
||||
*/
|
||||
void output_javadown_asm(const char *path, const char *source) {
|
||||
int fd;
|
||||
void *map;
|
||||
struct stat st;
|
||||
struct Asmdown *ad;
|
||||
struct DoxWriter *dox;
|
||||
CHECK_NE(-1, (fd = open(source, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
if (st.st_size) {
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
ad = ParseAsmdown(map, st.st_size);
|
||||
munmap(map, st.st_size);
|
||||
} else {
|
||||
ad = ParseAsmdown("", 0);
|
||||
}
|
||||
close(fd);
|
||||
dox = NewDoxWriter();
|
||||
SerializeAsmdown(dox, ad, source);
|
||||
WriteDox(dox, path);
|
||||
FreeDoxWriter(dox);
|
||||
FreeAsmdown(ad);
|
||||
}
|
||||
|
|
604
third_party/chibicc/dox2.c
vendored
604
third_party/chibicc/dox2.c
vendored
|
@ -65,10 +65,34 @@ struct Dox {
|
|||
} params;
|
||||
} * p;
|
||||
} objects;
|
||||
struct {
|
||||
struct DoxMacros {
|
||||
size_t n;
|
||||
int *p;
|
||||
} objectindex;
|
||||
struct DoxMacro {
|
||||
bool ignore;
|
||||
char *name;
|
||||
char *path;
|
||||
int line;
|
||||
bool is_objlike;
|
||||
char *va_args_name;
|
||||
struct Javadown *javadown;
|
||||
struct DoxMacroParams {
|
||||
size_t n;
|
||||
struct DoxMacroParam {
|
||||
char *name;
|
||||
} * p;
|
||||
} params;
|
||||
} * p;
|
||||
} macros;
|
||||
struct DoxIndex {
|
||||
size_t n;
|
||||
struct DoxIndexEntry {
|
||||
enum DoxIndexType {
|
||||
kObject,
|
||||
kMacro,
|
||||
} t;
|
||||
int i;
|
||||
} * p;
|
||||
} index;
|
||||
};
|
||||
|
||||
static unsigned Hash(const void *p, unsigned long n) {
|
||||
|
@ -93,6 +117,8 @@ static void FreeDox(struct Dox *dox) {
|
|||
free(dox->names.p);
|
||||
free(dox->freelist.p);
|
||||
free(dox->objects.p);
|
||||
free(dox->macros.p);
|
||||
free(dox->index.p);
|
||||
free(dox);
|
||||
}
|
||||
}
|
||||
|
@ -124,18 +150,23 @@ static char *DeserializeStr(struct Dox *dox) {
|
|||
|
||||
static struct Javadown *DeserializeJavadown(struct Dox *dox) {
|
||||
int i;
|
||||
bool present;
|
||||
struct Javadown *jd;
|
||||
jd = FreeLater(dox, calloc(1, sizeof(struct Javadown)));
|
||||
jd->isfileoverview = DeserializeInt(dox);
|
||||
jd->title = DeserializeStr(dox);
|
||||
jd->text = DeserializeStr(dox);
|
||||
jd->tags.n = DeserializeInt(dox);
|
||||
jd->tags.p = FreeLater(dox, malloc(jd->tags.n * sizeof(*jd->tags.p)));
|
||||
for (i = 0; i < jd->tags.n; ++i) {
|
||||
jd->tags.p[i].tag = DeserializeStr(dox);
|
||||
jd->tags.p[i].text = DeserializeStr(dox);
|
||||
if (DeserializeInt(dox)) {
|
||||
jd = FreeLater(dox, calloc(1, sizeof(struct Javadown)));
|
||||
jd->isfileoverview = DeserializeInt(dox);
|
||||
jd->title = DeserializeStr(dox);
|
||||
jd->text = DeserializeStr(dox);
|
||||
jd->tags.n = DeserializeInt(dox);
|
||||
jd->tags.p = FreeLater(dox, malloc(jd->tags.n * sizeof(*jd->tags.p)));
|
||||
for (i = 0; i < jd->tags.n; ++i) {
|
||||
jd->tags.p[i].tag = DeserializeStr(dox);
|
||||
jd->tags.p[i].text = DeserializeStr(dox);
|
||||
}
|
||||
return jd;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return jd;
|
||||
}
|
||||
|
||||
static void DeserializeObject(struct Dox *dox, struct DoxObject *o) {
|
||||
|
@ -163,6 +194,22 @@ static void DeserializeObject(struct Dox *dox, struct DoxObject *o) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DeserializeMacro(struct Dox *dox, struct DoxMacro *m) {
|
||||
int i;
|
||||
m->ignore = false;
|
||||
m->name = DeserializeStr(dox);
|
||||
m->path = DeserializeStr(dox);
|
||||
m->line = DeserializeInt(dox);
|
||||
m->is_objlike = DeserializeInt(dox);
|
||||
m->va_args_name = DeserializeStr(dox);
|
||||
m->javadown = DeserializeJavadown(dox);
|
||||
m->params.n = DeserializeInt(dox);
|
||||
m->params.p = FreeLater(dox, malloc(m->params.n * sizeof(*m->params.p)));
|
||||
for (i = 0; i < m->params.n; ++i) {
|
||||
m->params.p[i].name = DeserializeStr(dox);
|
||||
}
|
||||
}
|
||||
|
||||
static void DeserializeDox(struct Dox *dox) {
|
||||
int i, j, n;
|
||||
i = dox->objects.n;
|
||||
|
@ -172,7 +219,16 @@ static void DeserializeDox(struct Dox *dox) {
|
|||
for (j = 0; j < n; ++j) {
|
||||
DeserializeObject(dox, dox->objects.p + i + j);
|
||||
}
|
||||
i = dox->macros.n;
|
||||
dox->objects.n += n;
|
||||
n = DeserializeInt(dox);
|
||||
dox->macros.p =
|
||||
realloc(dox->macros.p, (dox->macros.n + n) * sizeof(*dox->macros.p));
|
||||
for (j = 0; j < n; ++j) {
|
||||
DeserializeMacro(dox, dox->macros.p + i + j);
|
||||
}
|
||||
dox->macros.n += n;
|
||||
CHECK_EQ(31337, DeserializeInt(dox));
|
||||
}
|
||||
|
||||
static void ReadDox(struct Dox *dox, const StringArray *files) {
|
||||
|
@ -210,43 +266,66 @@ static bool AddSet(struct Set *set, char *s) {
|
|||
}
|
||||
}
|
||||
|
||||
static int CompareObjectNames(const void *a, const void *b, void *arg) {
|
||||
int *i1, *i2;
|
||||
static int CompareDoxIndexEntry(const void *p1, const void *p2, void *arg) {
|
||||
struct Dox *dox;
|
||||
i1 = a, i2 = b, dox = arg;
|
||||
return strcmp(dox->objects.p[*i1].name, dox->objects.p[*i2].name);
|
||||
const char *s1, *s2;
|
||||
struct DoxIndexEntry *a, *b;
|
||||
dox = arg, a = p1, b = p2;
|
||||
s1 = a->t == kObject ? dox->objects.p[a->i].name : dox->macros.p[a->i].name;
|
||||
s2 = b->t == kObject ? dox->objects.p[b->i].name : dox->macros.p[b->i].name;
|
||||
while (*s1 == '_') ++s1;
|
||||
while (*s2 == '_') ++s2;
|
||||
return strcasecmp(s1, s2);
|
||||
}
|
||||
|
||||
static void IndexDox(struct Dox *dox) {
|
||||
size_t i, j, n;
|
||||
dox->names.n = roundup2pow(dox->objects.n) << 1;
|
||||
dox->names.n = roundup2pow(dox->objects.n + dox->macros.n) << 1;
|
||||
dox->names.p = calloc(dox->names.n, sizeof(*dox->names.p));
|
||||
for (n = i = 0; i < dox->objects.n; ++i) {
|
||||
n = 0;
|
||||
for (i = 0; i < dox->objects.n; ++i) {
|
||||
if (AddSet(&dox->names, dox->objects.p[i].name)) {
|
||||
++n;
|
||||
} else {
|
||||
dox->objects.p[i].ignore = true;
|
||||
}
|
||||
}
|
||||
dox->objectindex.n = n;
|
||||
dox->objectindex.p = malloc(n * sizeof(*dox->objectindex.p));
|
||||
for (j = i = 0; i < dox->objects.n; ++i) {
|
||||
if (dox->objects.p[i].ignore) continue;
|
||||
dox->objectindex.p[j++] = i;
|
||||
for (i = 0; i < dox->macros.n; ++i) {
|
||||
if (AddSet(&dox->names, dox->macros.p[i].name)) {
|
||||
++n;
|
||||
} else {
|
||||
dox->macros.p[i].ignore = true;
|
||||
}
|
||||
}
|
||||
qsort_r(dox->objectindex.p, dox->objectindex.n, sizeof(*dox->objectindex.p),
|
||||
CompareObjectNames, dox);
|
||||
dox->index.n = n;
|
||||
dox->index.p = malloc(n * sizeof(*dox->index.p));
|
||||
j = 0;
|
||||
for (i = 0; i < dox->objects.n; ++i) {
|
||||
if (dox->objects.p[i].ignore) continue;
|
||||
dox->index.p[j].t = kObject;
|
||||
dox->index.p[j].i = i;
|
||||
++j;
|
||||
}
|
||||
for (i = 0; i < dox->macros.n; ++i) {
|
||||
if (dox->macros.p[i].ignore) continue;
|
||||
dox->index.p[j].t = kMacro;
|
||||
dox->index.p[j].i = i;
|
||||
++j;
|
||||
}
|
||||
CHECK_EQ(n, j);
|
||||
qsort_r(dox->index.p, dox->index.n, sizeof(*dox->index.p),
|
||||
CompareDoxIndexEntry, dox);
|
||||
}
|
||||
|
||||
static void PrintText(FILE *f, const char *s) {
|
||||
int c;
|
||||
bool bol, pre;
|
||||
for (pre = false, bol = true;;) {
|
||||
bool bol, pre, ul0, ul2, bt1, bt2;
|
||||
for (bt1 = bt2 = ul2 = ul0 = pre = false, bol = true;;) {
|
||||
switch ((c = *s++)) {
|
||||
case '\0':
|
||||
if (pre) {
|
||||
fprintf(f, "</pre>");
|
||||
}
|
||||
if (bt1 || bt2) fprintf(f, "</code>");
|
||||
if (pre) fprintf(f, "</pre>");
|
||||
if (ul0 || ul2) fprintf(f, "</ul>");
|
||||
return;
|
||||
case '&':
|
||||
fprintf(f, "&");
|
||||
|
@ -268,25 +347,79 @@ static void PrintText(FILE *f, const char *s) {
|
|||
fprintf(f, "'");
|
||||
bol = false;
|
||||
break;
|
||||
case '\n':
|
||||
if (!pre && *s == '\n') {
|
||||
case '`':
|
||||
if (!pre && !bt1 && !bt2 && *s != '`') {
|
||||
fprintf(f, "<code>");
|
||||
bt1 = true;
|
||||
} else if (!pre && !bt1 && !bt2 && *s == '`') {
|
||||
fprintf(f, "<code>");
|
||||
bt2 = true;
|
||||
++s;
|
||||
} else if (bt1) {
|
||||
fprintf(f, "</code>");
|
||||
bt1 = false;
|
||||
} else if (bt2 && *s == '`') {
|
||||
fprintf(f, "</code>");
|
||||
bt2 = false;
|
||||
++s;
|
||||
} else {
|
||||
fprintf(f, "`");
|
||||
}
|
||||
bol = false;
|
||||
break;
|
||||
case '\n':
|
||||
if (!pre && !ul0 && !ul2 && *s == '\n') {
|
||||
fprintf(f, "\n<p>");
|
||||
} else if (pre &&
|
||||
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 (ul0 && s[0] == '-' && s[1] == ' ') {
|
||||
fprintf(f, "\n<li>");
|
||||
s += 2;
|
||||
bol = false;
|
||||
} else if (ul2 && s[0] == ' ' && s[1] == ' ' && s[2] == '-' &&
|
||||
s[3] == ' ') {
|
||||
fprintf(f, "\n<li>");
|
||||
s += 4;
|
||||
bol = false;
|
||||
} else if (ul0 && s[0] != '\n' && (s[0] != ' ' || s[1] != ' ')) {
|
||||
fprintf(f, "\n</ul>\n");
|
||||
bol = true;
|
||||
ul0 = false;
|
||||
} else if (ul2 && s[0] != '\n' &&
|
||||
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) {
|
||||
fprintf(f, "\n</ul>\n");
|
||||
bol = true;
|
||||
ul2 = false;
|
||||
} else {
|
||||
fprintf(f, "\n");
|
||||
bol = true;
|
||||
}
|
||||
bol = true;
|
||||
break;
|
||||
case '-':
|
||||
if (bol && !ul0 && !ul2 && s[0] == ' ') {
|
||||
ul0 = true;
|
||||
fprintf(f, "<ul><li>");
|
||||
} else {
|
||||
fprintf(f, "-");
|
||||
}
|
||||
bol = false;
|
||||
break;
|
||||
case ' ':
|
||||
if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') {
|
||||
pre = true;
|
||||
fprintf(f, "<pre>");
|
||||
fprintf(f, "<pre> ");
|
||||
} else if (bol && !ul0 && !ul2 && s[0] == ' ' && s[1] == '-' &&
|
||||
s[2] == ' ') {
|
||||
ul2 = true;
|
||||
fprintf(f, "<ul><li>");
|
||||
s += 3;
|
||||
} else {
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, " ");
|
||||
bol = false;
|
||||
break;
|
||||
default:
|
||||
|
@ -297,83 +430,364 @@ static void PrintText(FILE *f, const char *s) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool HasTag(struct Javadown *jd, const char *tag) {
|
||||
int k;
|
||||
if (jd) {
|
||||
for (k = 0; k < jd->tags.n; ++k) {
|
||||
if (!strcmp(jd->tags.p[k].tag, tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsNoReturn(struct DoxObject *o) {
|
||||
return o->is_noreturn || HasTag(o->javadown, "noreturn");
|
||||
}
|
||||
|
||||
static void PrintDox(struct Dox *dox, FILE *f) {
|
||||
int i, j, k;
|
||||
char *prefix;
|
||||
bool was_outputted;
|
||||
struct DoxMacro *m;
|
||||
struct DoxObject *o;
|
||||
|
||||
// header
|
||||
fprintf(f, "\
|
||||
<!doctype html>\n\
|
||||
<html lang=\"en\">\n\
|
||||
<meta charset=\"utf-8\">\n\
|
||||
<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-43182592-5\"></script>\n\
|
||||
<script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-43182592-5');</script>\n\
|
||||
<title>Cosmopolitan C Library</title>\n\
|
||||
<meta name=\"viewport\" content=\"width=1024\">\n\
|
||||
<link rel=\"canonical\" href=\"https://justine.lol/cosmopolitan/documentation.html\">\n\
|
||||
<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\">\n\
|
||||
<link rel=\"stylesheet\" href=\"style.css\">\n\
|
||||
<style>\n\
|
||||
.indent {\n\
|
||||
padding-left: 1em;\n\
|
||||
}\n\
|
||||
.nav {\n\
|
||||
margin-bottom: 0;\n\
|
||||
}\n\
|
||||
.toc a {\n\
|
||||
text-decoration: none;\n\
|
||||
}\n\
|
||||
h3 a {\n\
|
||||
color: inherit;\n\
|
||||
text-decoration: none;\n\
|
||||
}\n\
|
||||
pre {\n\
|
||||
margin-left: 0;\n\
|
||||
padding: 12px;\n\
|
||||
background: #f6f6f6;\n\
|
||||
width: 100%;\n\
|
||||
overflow-x: auto;\n\
|
||||
border-radius: 5px;\n\
|
||||
}\n\
|
||||
code {\n\
|
||||
padding: 2px 4px;\n\
|
||||
background: #e4e6e8;\n\
|
||||
border-radius: 3px;\n\
|
||||
}\n\
|
||||
hr {\n\
|
||||
height: 1px;\n\
|
||||
margin-bottom: 16px;\n\
|
||||
color: #d6d9dc;\n\
|
||||
background: #d6d9dc;\n\
|
||||
border: 0;\n\
|
||||
}\n\
|
||||
.category {\n\
|
||||
font-weight: bold;\n\
|
||||
}\n\
|
||||
.tagname {\n\
|
||||
font-size: 12pt;\n\
|
||||
font-weight: bold;\n\
|
||||
}\n\
|
||||
.tag {\n\
|
||||
margin-top: .5em;\n\
|
||||
}\n\
|
||||
.tag dl {\n\
|
||||
margin-top: .5em;\n\
|
||||
margin-bottom: .5em;\n\
|
||||
margin-left: 1em;\n\
|
||||
}\n\
|
||||
</style>\n\
|
||||
\n\
|
||||
<table width=\"100%%\"><tr><td width=\"33%%\" valign=\"top\">\n\
|
||||
<p class=\"toc\">\n\
|
||||
<header>\n\
|
||||
<img width=\"196\" height=\"105\" src=\"//storage.googleapis.com/justine/cosmopolitan/cosmopolitan.png\" alt=\"honeybadger\">\n\
|
||||
<h1>cosmopolitan libc</h1>\n\
|
||||
<span>build-once run-anywhere c without devops</span>\n\
|
||||
</header>\n\
|
||||
\n\
|
||||
<nav class=\"nav\">\n\
|
||||
<ul>\n\
|
||||
<li><a href=\"index.html\">Intro</a>\n\
|
||||
<li><a href=\"download.html\">Download</a>\n\
|
||||
<li><a class=\"active\" href=\"documentation.html\">Documentation</a>\n\
|
||||
<li><a href=\"sources.html\">Sources</a>\n\
|
||||
<li><a href=\"https://github.com/jart/cosmopolitan\">GitHub</a>\n\
|
||||
<li><a href=\"license.html\">License</a>\n\
|
||||
<li class=\"right\"><a href=\"../index.html\">» jart's web page</a>\n\
|
||||
</ul>\n\
|
||||
</nav>\n\
|
||||
\n\
|
||||
<table class=\"dox\" width=\"960\">\n\
|
||||
<tr>\n\
|
||||
<td width=\"320\" valign=\"top\" class=\"toc\">\n\
|
||||
");
|
||||
for (i = 0; i < dox->objectindex.n; ++i) {
|
||||
o = dox->objects.p + dox->objectindex.p[i];
|
||||
if (o->ignore || !o->is_function) continue;
|
||||
|
||||
/* // lefthand index: objects */
|
||||
/* fprintf(f, "<p><span class=\"category\">macro objects</span>\n"); */
|
||||
/* fprintf(f, "<p>\n"); */
|
||||
/* for (i = 0; i < dox->index.n; ++i) { */
|
||||
/* if (dox->index.p[i].t != kMacro) continue; */
|
||||
/* m = dox->macros.p + dox->index.p[i].i; */
|
||||
/* if (m->ignore) continue; */
|
||||
/* if (!m->is_objlike) continue; */
|
||||
/* fprintf(f, "<a href=\"#%s\">%s</a><br>\n", m->name, m->name); */
|
||||
/* } */
|
||||
|
||||
/* // lefthand index: functions */
|
||||
/* fprintf(f, "<p><span class=\"category\">macro functions</span>\n"); */
|
||||
/* fprintf(f, "<p>\n"); */
|
||||
/* for (i = 0; i < dox->index.n; ++i) { */
|
||||
/* if (dox->index.p[i].t != kMacro) continue; */
|
||||
/* m = dox->macros.p + dox->index.p[i].i; */
|
||||
/* if (m->ignore) continue; */
|
||||
/* if (m->is_objlike) continue; */
|
||||
/* fprintf(f, "<a href=\"#%s\">%s</a><br>\n", m->name, m->name); */
|
||||
/* } */
|
||||
|
||||
// lefthand index: objects
|
||||
fprintf(f, "<p><span class=\"category\">objects</span>\n");
|
||||
fprintf(f, "<p>\n");
|
||||
for (i = 0; i < dox->index.n; ++i) {
|
||||
if (dox->index.p[i].t != kObject) continue;
|
||||
o = dox->objects.p + dox->index.p[i].i;
|
||||
if (o->ignore) continue;
|
||||
if (o->is_function) continue;
|
||||
fprintf(f, "<a href=\"#%s\">%s</a><br>\n", o->name, o->name);
|
||||
fprintf(f, "<br>\n");
|
||||
}
|
||||
fprintf(f, "<td width=\"67%%\" valign=\"top\">\n");
|
||||
for (i = 0; i < dox->objectindex.n; ++i) {
|
||||
o = dox->objects.p + dox->objectindex.p[i];
|
||||
if (o->ignore || !o->is_function) continue;
|
||||
fprintf(f, "\n<div id=\"%s\" class=\"func\">\n", o->name, o->name);
|
||||
fprintf(f, "<h3><a href=\"#%s\">", o->name);
|
||||
fprintf(f, "<strong class=\"name\">%s</strong></a></h3>", o->name);
|
||||
fprintf(f, "<p>");
|
||||
PrintText(f, o->javadown->title);
|
||||
fprintf(f, "\n");
|
||||
if (*o->javadown->text) {
|
||||
fprintf(f, "<p>");
|
||||
PrintText(f, o->javadown->text);
|
||||
|
||||
// lefthand index: functions
|
||||
fprintf(f, "<p><span class=\"category\">functions</span>\n");
|
||||
fprintf(f, "<p>\n");
|
||||
for (i = 0; i < dox->index.n; ++i) {
|
||||
if (dox->index.p[i].t != kObject) continue;
|
||||
o = dox->objects.p + dox->index.p[i].i;
|
||||
if (o->ignore) continue;
|
||||
if (!o->is_function) continue;
|
||||
fprintf(f, "<a href=\"#%s\">%s</a><br>\n", o->name, o->name);
|
||||
}
|
||||
|
||||
// righthand contents
|
||||
fprintf(f, "<td width=\"640\" 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;
|
||||
if (o->ignore) continue;
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "<p><strong>@param</strong>\n");
|
||||
fprintf(f, "<div class=\"params indent\">\n");
|
||||
if (o->params.n) {
|
||||
fprintf(f, "<dl>\n");
|
||||
for (j = 0; j < o->params.n; ++j) {
|
||||
fprintf(f, "<dt>");
|
||||
PrintText(f, o->params.p[j].type);
|
||||
fprintf(f, " <em>");
|
||||
PrintText(f, o->params.p[j].name);
|
||||
fprintf(f, "</em>\n");
|
||||
prefix = xasprintf("%s ", o->params.p[j].name);
|
||||
for (k = 0; k < o->javadown->tags.n; ++k) {
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "param") &&
|
||||
startswith(o->javadown->tags.p[k].text, prefix)) {
|
||||
fprintf(f, "<dd>");
|
||||
PrintText(f, o->javadown->tags.p[k].text + strlen(prefix));
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(prefix);
|
||||
}
|
||||
fprintf(f, "</dl>\n");
|
||||
} else {
|
||||
fprintf(f, "<p>None.\n");
|
||||
}
|
||||
fprintf(f, "</div>\n");
|
||||
for (k = 0; k < o->javadown->tags.n; ++k) {
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "param")) continue;
|
||||
fprintf(f, "<p><strong>@");
|
||||
PrintText(f, o->javadown->tags.p[k].tag);
|
||||
fprintf(f, "</strong>\n");
|
||||
if (*o->javadown->tags.p[k].text) {
|
||||
PrintText(f, o->javadown->tags.p[k].text);
|
||||
if (i) fprintf(f, "<hr>");
|
||||
fprintf(f, "<div id=\"%s\" class=\"api\">\n", o->name);
|
||||
fprintf(f, "<h3><a href=\"#%s\">%s</a></h3>", o->name, o->name);
|
||||
|
||||
// title
|
||||
if (o->javadown && *o->javadown->title) {
|
||||
fprintf(f, "<p>");
|
||||
PrintText(f, o->javadown->title);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
// text
|
||||
if (o->javadown && *o->javadown->text) {
|
||||
fprintf(f, "<p>");
|
||||
PrintText(f, o->javadown->text);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
// parameters
|
||||
if (o->is_function && (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");
|
||||
if (o->params.n) {
|
||||
for (j = 0; j < o->params.n; ++j) {
|
||||
fprintf(f, "<dt>");
|
||||
PrintText(f, o->params.p[j].type);
|
||||
fprintf(f, " <em>");
|
||||
PrintText(f, o->params.p[j].name);
|
||||
fprintf(f, "</em>\n");
|
||||
if (o->javadown) {
|
||||
prefix = xasprintf("%s ", o->params.p[j].name);
|
||||
for (k = 0; k < o->javadown->tags.n; ++k) {
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "param") &&
|
||||
startswith(o->javadown->tags.p[k].text, prefix)) {
|
||||
fprintf(f, "<dd>");
|
||||
PrintText(f, o->javadown->tags.p[k].text + strlen(prefix));
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(prefix);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (k = 0; k < o->javadown->tags.n; ++k) {
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "param")) {
|
||||
fprintf(f, "<dd>");
|
||||
PrintText(f, o->javadown->tags.p[k].text);
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "</dl>\n");
|
||||
fprintf(f, "</div>\n"); // .tag
|
||||
}
|
||||
|
||||
// return
|
||||
if (o->is_function) {
|
||||
fprintf(f, "<div class=\"tag\">\n");
|
||||
if (IsNoReturn(o)) {
|
||||
fprintf(f, "<span class=\"tagname\">@noreturn</span>\n");
|
||||
} else {
|
||||
fprintf(f, "<span class=\"tagname\">@return</span>\n");
|
||||
was_outputted = false;
|
||||
fprintf(f, "<dl>\n");
|
||||
if (o->javadown) {
|
||||
for (k = 0; k < o->javadown->tags.n; ++k) {
|
||||
if (strcmp(o->javadown->tags.p[k].tag, "return")) continue;
|
||||
if (!was_outputted) {
|
||||
fprintf(f, "<dt>");
|
||||
PrintText(f, o->type);
|
||||
was_outputted = true;
|
||||
}
|
||||
fprintf(f, "\n<dd>");
|
||||
PrintText(f, o->javadown->tags.p[k].text);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
if (!was_outputted) {
|
||||
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) {
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "param")) continue;
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "return")) continue;
|
||||
if (!strcmp(o->javadown->tags.p[k].tag, "noreturn")) continue;
|
||||
fprintf(f, "<div class=\"tag\">\n");
|
||||
fprintf(f, "<span class=\"tagname\">@");
|
||||
PrintText(f, o->javadown->tags.p[k].tag);
|
||||
fprintf(f, "</span>\n");
|
||||
if (*o->javadown->tags.p[k].text) {
|
||||
PrintText(f, o->javadown->tags.p[k].text);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "</div>\n"); // .tag
|
||||
}
|
||||
}
|
||||
|
||||
// sauce
|
||||
if (strcmp(o->path, "missingno.c")) {
|
||||
fprintf(f, "<div class=\"tag\">\n");
|
||||
fprintf(f,
|
||||
"<span class=\"tagname\">@see</span> <a "
|
||||
"href=\"https://github.com/jart/cosmopolitan/blob/master/"
|
||||
"%s#L%d\">%s</a>",
|
||||
o->path, o->line, o->path);
|
||||
fprintf(f, "</div>\n"); // .tag
|
||||
}
|
||||
|
||||
fprintf(f, "</div>\n"); /* class=".api" */
|
||||
} else {
|
||||
continue;
|
||||
m = dox->macros.p + dox->index.p[i].i;
|
||||
if (m->ignore) continue;
|
||||
fprintf(f, "\n");
|
||||
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");
|
||||
fprintf(f, "<span class=\"tagname\">@param</span>\n");
|
||||
fprintf(f, "<dl>\n");
|
||||
if (m->params.n) {
|
||||
for (j = 0; j < m->params.n; ++j) {
|
||||
fprintf(f, "<dt>");
|
||||
fprintf(f, "<em>");
|
||||
PrintText(f, m->params.p[j].name);
|
||||
fprintf(f, "</em>\n");
|
||||
if (m->javadown) {
|
||||
prefix = xasprintf("%s ", m->params.p[j].name);
|
||||
for (k = 0; k < m->javadown->tags.n; ++k) {
|
||||
if (!strcmp(m->javadown->tags.p[k].tag, "param") &&
|
||||
startswith(m->javadown->tags.p[k].text, prefix)) {
|
||||
fprintf(f, "<dd>");
|
||||
PrintText(f, m->javadown->tags.p[k].text + strlen(prefix));
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(prefix);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (k = 0; k < m->javadown->tags.n; ++k) {
|
||||
if (!strcmp(m->javadown->tags.p[k].tag, "param")) {
|
||||
fprintf(f, "<dd>");
|
||||
PrintText(f, m->javadown->tags.p[k].text);
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "</dl>\n");
|
||||
fprintf(f, "</div>\n"); // .tag
|
||||
}
|
||||
|
||||
fprintf(f, "</div>\n"); /* class=".api" */
|
||||
}
|
||||
fprintf(f, "</div>\n");
|
||||
}
|
||||
fprintf(f, "</table>\n");
|
||||
|
||||
// footer
|
||||
fprintf(f, "\
|
||||
\n\
|
||||
<footer>\n\
|
||||
<p>\n\
|
||||
<div style=\"float:right;text-align:right\">\n\
|
||||
Free Libre & Open Source<br>\n\
|
||||
<a href=\"https://github.com/jart\">github.com/jart/cosmopolitan</a>\n\
|
||||
</div>\n\
|
||||
Feedback<br>\n\
|
||||
jtunney@gmail.com\n\
|
||||
</p>\n\
|
||||
<div style=\"clear:both\"></div>\n\
|
||||
</footer>\n\
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
83
third_party/chibicc/parse.c
vendored
83
third_party/chibicc/parse.c
vendored
|
@ -57,6 +57,7 @@ typedef struct {
|
|||
bool is_destructor;
|
||||
bool is_constructor;
|
||||
bool is_externally_visible;
|
||||
bool is_no_instrument_function;
|
||||
bool is_force_align_arg_pointer;
|
||||
bool is_no_caller_saved_registers;
|
||||
int align;
|
||||
|
@ -476,6 +477,10 @@ static Token *thing_attributes(Token *tok, void *arg) {
|
|||
attr->is_externally_visible = true;
|
||||
return tok;
|
||||
}
|
||||
if (consume_attribute(&tok, tok, "no_instrument_function")) {
|
||||
attr->is_no_instrument_function = true;
|
||||
return tok;
|
||||
}
|
||||
if (consume_attribute(&tok, tok, "force_align_arg_pointer")) {
|
||||
attr->is_force_align_arg_pointer = true;
|
||||
return tok;
|
||||
|
@ -555,7 +560,6 @@ static Token *thing_attributes(Token *tok, void *arg) {
|
|||
consume_attribute(&tok, tok, "no_split_stack") ||
|
||||
consume_attribute(&tok, tok, "no_stack_limit") ||
|
||||
consume_attribute(&tok, tok, "no_sanitize_undefined") ||
|
||||
consume_attribute(&tok, tok, "no_instrument_function") ||
|
||||
consume_attribute(&tok, tok, "no_profile_instrument_function")) {
|
||||
return tok;
|
||||
}
|
||||
|
@ -1018,6 +1022,7 @@ static Type *enum_specifier(Token **rest, Token *tok) {
|
|||
*rest = tok;
|
||||
return ty;
|
||||
}
|
||||
ty->name = tag;
|
||||
tok = skip(tok, '{');
|
||||
// Read an enum-list.
|
||||
int i = 0;
|
||||
|
@ -2066,8 +2071,9 @@ int64_t eval2(Node *node, char ***label) {
|
|||
}
|
||||
error_tok(node->tok, "not a compile-time constant");
|
||||
}
|
||||
if (node->var->ty->kind != TY_ARRAY && node->var->ty->kind != TY_FUNC)
|
||||
if (node->var->ty->kind != TY_ARRAY && node->var->ty->kind != TY_FUNC) {
|
||||
error_tok(node->tok, "invalid initializer");
|
||||
}
|
||||
*label = &node->var->name;
|
||||
return 0;
|
||||
case ND_NUM:
|
||||
|
@ -2727,6 +2733,7 @@ static Type *struct_union_decl(Token **rest, Token *tok) {
|
|||
push_tag_scope(tag, ty);
|
||||
return ty;
|
||||
}
|
||||
ty->name = tag;
|
||||
tok = skip(tok, '{');
|
||||
// Construct a struct object.
|
||||
struct_members(&tok, tok, ty);
|
||||
|
@ -3361,10 +3368,12 @@ static Obj *find_func(char *name) {
|
|||
}
|
||||
|
||||
static void mark_live(Obj *var) {
|
||||
int i;
|
||||
Obj *fn;
|
||||
if (!var->is_function || var->is_live) return;
|
||||
var->is_live = true;
|
||||
for (int i = 0; i < var->refs.len; i++) {
|
||||
Obj *fn = find_func(var->refs.data[i]);
|
||||
for (i = 0; i < var->refs.len; i++) {
|
||||
fn = find_func(var->refs.data[i]);
|
||||
if (fn) mark_live(fn);
|
||||
}
|
||||
}
|
||||
|
@ -3385,25 +3394,28 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
|
|||
fn->is_definition = fn->is_definition || EQUAL(tok, "{");
|
||||
fn->is_weak |= attr->is_weak;
|
||||
fn->is_noreturn |= attr->is_noreturn;
|
||||
fn->tok = ty->name;
|
||||
} else {
|
||||
fn = new_gvar(name_str, ty);
|
||||
fn->tok = ty->name;
|
||||
fn->is_function = true;
|
||||
fn->is_definition = EQUAL(tok, "{");
|
||||
fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern);
|
||||
fn->is_inline = attr->is_inline;
|
||||
fn->is_weak = attr->is_weak;
|
||||
fn->is_ms_abi = attr->is_ms_abi;
|
||||
fn->is_aligned = attr->is_aligned;
|
||||
fn->is_noreturn = attr->is_noreturn;
|
||||
fn->is_destructor = attr->is_destructor;
|
||||
fn->is_constructor = attr->is_constructor;
|
||||
fn->is_externally_visible = attr->is_externally_visible;
|
||||
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->align = attr->align;
|
||||
fn->section = attr->section;
|
||||
fn->visibility = attr->visibility;
|
||||
}
|
||||
fn->align = MAX(fn->align, attr->align);
|
||||
fn->is_weak |= attr->is_weak;
|
||||
fn->section = fn->section ?: attr->section;
|
||||
fn->is_ms_abi |= attr->is_ms_abi;
|
||||
fn->visibility = fn->visibility ?: attr->visibility;
|
||||
fn->is_aligned |= attr->is_aligned;
|
||||
fn->is_noreturn |= attr->is_noreturn;
|
||||
fn->is_destructor |= attr->is_destructor;
|
||||
fn->is_constructor |= attr->is_constructor;
|
||||
fn->is_externally_visible |= attr->is_externally_visible;
|
||||
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);
|
||||
if (consume_attribute(&tok, tok, "asm")) {
|
||||
|
@ -3452,6 +3464,7 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {
|
|||
Type *ty = declarator(&tok, tok, basety);
|
||||
if (!ty->name) error_tok(ty->name_pos, "variable name omitted");
|
||||
Obj *var = new_gvar(get_ident(ty->name), ty);
|
||||
if (!var->tok) var->tok = ty->name;
|
||||
var->javadown = current_javadown;
|
||||
if (consume_attribute(&tok, tok, "asm")) {
|
||||
tok = skip(tok, '(');
|
||||
|
@ -3459,9 +3472,16 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {
|
|||
tok = skip(tok, ')');
|
||||
}
|
||||
tok = attribute_list(tok, attr, thing_attributes);
|
||||
var->align = MAX(var->align, attr->align);
|
||||
var->is_weak = attr->is_weak;
|
||||
var->section = attr->section;
|
||||
var->visibility = attr->visibility;
|
||||
var->is_aligned = var->is_aligned | attr->is_aligned;
|
||||
var->is_externally_visible = attr->is_externally_visible;
|
||||
var->is_definition = !attr->is_extern;
|
||||
var->is_static = attr->is_static;
|
||||
var->is_tls = attr->is_tls;
|
||||
var->section = attr->section;
|
||||
if (attr->align) var->align = attr->align;
|
||||
if (EQUAL(tok, "=")) {
|
||||
gvar_initializer(&tok, tok->next, var);
|
||||
|
@ -3535,15 +3555,30 @@ static Obj *declare3(char *s, Type *r, Type *a, Type *b, Type *c) {
|
|||
return new_gvar(xstrcat("__builtin_", s), ty);
|
||||
}
|
||||
|
||||
static void math0(char *name) {
|
||||
declare0(name, ty_double);
|
||||
declare0(xstrcat(name, 'f'), ty_float);
|
||||
declare0(xstrcat(name, 'l'), ty_ldouble);
|
||||
}
|
||||
|
||||
static void math1(char *name) {
|
||||
declare1(name, ty_double, ty_double);
|
||||
declare1(xstrcat(name, 'f'), ty_float, ty_float);
|
||||
declare1(xstrcat(name, 'l'), ty_ldouble, ty_ldouble);
|
||||
}
|
||||
|
||||
static void math2(char *name) {
|
||||
declare2(name, ty_double, ty_double, ty_double);
|
||||
declare2(xstrcat(name, 'f'), ty_float, ty_float, ty_float);
|
||||
declare2(xstrcat(name, 'l'), ty_ldouble, ty_ldouble, ty_ldouble);
|
||||
}
|
||||
|
||||
void declare_builtin_functions(void) {
|
||||
Type *pvoid = pointer_to(ty_void);
|
||||
Type *pchar = pointer_to(ty_char);
|
||||
builtin_alloca = declare1("alloca", pointer_to(ty_void), ty_int);
|
||||
declare0("trap", ty_int);
|
||||
declare0("unreachable", ty_int);
|
||||
declare0("inff", ty_float);
|
||||
declare0("inf", ty_double);
|
||||
declare0("infl", ty_ldouble);
|
||||
declare1("ctz", ty_int, ty_int);
|
||||
declare1("ctzl", ty_long, ty_long);
|
||||
declare1("ctzll", ty_long, ty_long);
|
||||
|
@ -3581,6 +3616,16 @@ void declare_builtin_functions(void) {
|
|||
declare2("strchr", pchar, pchar, ty_int);
|
||||
declare2("strstr", pchar, pchar, pchar);
|
||||
declare1("frame_address", pvoid, ty_int);
|
||||
declare2("scalbnf", ty_float, ty_float, ty_int);
|
||||
declare2("scalbn", ty_double, ty_double, ty_int);
|
||||
declare2("scalbnl", ty_ldouble, ty_ldouble, ty_int);
|
||||
math0("inf");
|
||||
math0("huge_val");
|
||||
math1("fabs");
|
||||
math1("logb");
|
||||
math2("fmax");
|
||||
math2("fmin");
|
||||
math2("copysign");
|
||||
}
|
||||
|
||||
// program = (typedef | function-definition | global-variable)*
|
||||
|
|
8
third_party/chibicc/printast.c
vendored
8
third_party/chibicc/printast.c
vendored
|
@ -119,7 +119,6 @@ static void PrintType(FILE *f, int l, const char *s, Type *t) {
|
|||
PrintInt(f, l + 2, "align: ", t->align);
|
||||
PrintBool(f, l + 2, "is_unsigned: ", t->is_unsigned);
|
||||
PrintBool(f, l + 2, "is_atomic: ", t->is_atomic);
|
||||
PrintType(f, l + 2, "origin: ", t->origin);
|
||||
PrintType(f, l + 2, "base: ", t->base);
|
||||
PrintTokStr(f, l + 2, "name: ", t->name);
|
||||
PrintTokStr(f, l + 2, "name_pos: ", t->name_pos);
|
||||
|
@ -231,6 +230,13 @@ static void PrintObj(FILE *f, int l, const char *s, Obj *o) {
|
|||
PrintBool(f, l + 2, "is_noreturn: ", o->is_noreturn);
|
||||
PrintBool(f, l + 2, "is_destructor: ", o->is_destructor);
|
||||
PrintBool(f, l + 2, "is_constructor: ", o->is_constructor);
|
||||
PrintBool(f, l + 2, "is_externally_visible: ", o->is_externally_visible);
|
||||
PrintBool(f, l + 2,
|
||||
"is_no_instrument_function: ", o->is_no_instrument_function);
|
||||
PrintBool(f, l + 2,
|
||||
"is_force_align_arg_pointer: ", o->is_force_align_arg_pointer);
|
||||
PrintBool(f, l + 2,
|
||||
"is_no_caller_saved_registers: ", o->is_no_caller_saved_registers);
|
||||
PrintInt(f, l + 2, "stack_size: ", o->stack_size);
|
||||
PrintObj(f, l + 2, "params: ", o->params);
|
||||
PrintNode(f, l + 2, "body: ", o->body);
|
||||
|
|
28
third_party/chibicc/test/builtin_test.c
vendored
28
third_party/chibicc/test/builtin_test.c
vendored
|
@ -1,3 +1,4 @@
|
|||
#include "libc/math.h"
|
||||
#include "third_party/chibicc/test/test.h"
|
||||
|
||||
#define FPNAN 0
|
||||
|
@ -115,6 +116,31 @@ void test_fpclassify(void) {
|
|||
ASSERT(FPNAN, FPCLASSIFY(__builtin_nanl("")));
|
||||
}
|
||||
|
||||
void test_logb(void) {
|
||||
ASSERT(6, __builtin_logbl(123.456));
|
||||
ASSERT(logbl(123.456L), __builtin_logbl(123.456L));
|
||||
ASSERT(logbl(__LDBL_MIN__), __builtin_logbl(__LDBL_MIN__));
|
||||
ASSERT(logbl(__LDBL_MAX__), __builtin_logbl(__LDBL_MAX__));
|
||||
}
|
||||
|
||||
void test_fmax(void) {
|
||||
ASSERT(fmaxl(1, 2), __builtin_fmaxl(1, 2));
|
||||
ASSERT(2, __builtin_fmaxl(__builtin_nanl(""), 2));
|
||||
ASSERT(1, __builtin_fmaxl(1, __builtin_nanl("")));
|
||||
ASSERT(2, fmaxl(nanl(""), 2));
|
||||
ASSERT(1, fmaxl(1, nanl("")));
|
||||
ASSERT(fmaxf(1, 2), __builtin_fmaxf(1, 2));
|
||||
ASSERT(2, __builtin_fmaxf(__builtin_nanl(""), 2));
|
||||
ASSERT(1, __builtin_fmaxf(1, __builtin_nanl("")));
|
||||
ASSERT(2, fmaxf(nanl(""), 2));
|
||||
ASSERT(1, fmaxf(1, nanl("")));
|
||||
ASSERT(fmax(1, 2), __builtin_fmax(1, 2));
|
||||
ASSERT(2, __builtin_fmax(__builtin_nanl(""), 2));
|
||||
ASSERT(1, __builtin_fmax(1, __builtin_nanl("")));
|
||||
ASSERT(2, fmax(nanl(""), 2));
|
||||
ASSERT(1, fmax(1, nanl("")));
|
||||
}
|
||||
|
||||
void test_strlen(void) {
|
||||
ASSERT(5, strlen("hello"));
|
||||
ASSERT(5, __builtin_strlen("hello"));
|
||||
|
@ -414,5 +440,7 @@ int main() {
|
|||
test_strchr();
|
||||
test_strpbrk();
|
||||
test_strstr();
|
||||
test_logb();
|
||||
test_fmax();
|
||||
return 0;
|
||||
}
|
||||
|
|
1
third_party/chibicc/test/test.mk
vendored
1
third_party/chibicc/test/test.mk
vendored
|
@ -49,6 +49,7 @@ THIRD_PARTY_CHIBICC_TEST_DIRECTDEPS = \
|
|||
LIBC_NEXGEN32E \
|
||||
LIBC_UNICODE \
|
||||
LIBC_MEM \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_CHIBICC \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue