Auto-generate some documentation

This commit is contained in:
Justine Tunney 2020-12-26 02:09:07 -08:00
parent 117d0111ab
commit 13437dd19b
97 changed files with 2033 additions and 661 deletions

View file

@ -16,18 +16,22 @@ local enhancements
- support __builtin_constant_p, __builtin_likely, etc.
- support __builtin_isunordered, __builtin_islessgreater, etc.
- support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc.
- support __force_align_arg_pointer__, __no_caller_saved_registers__, etc.
- support __constructor__, __section__, __cold__, -ffunction-sections, etc.
- support building -x assembler-with-cpp a.k.a. .S files
- support profiling w/ -mcount / -mfentry / -mnop-mcount
- improve error messages to trace macro expansions
- reduce #lines of generated assembly by a third
- reduce #bytes of generated binary by a third
- report divide errors in constexprs
local bug fixes
- allow casted values to be lvalues
- permit remainder operator in constexprs
- permit parentheses around string-initializer
- fix 64-bit bug in generated code for struct bitfields
- fix struct_designator() so it won't crash on anonymous union members
- fix bug where last statement in statement expression couldn't have label
- print_tokens (chibicc -E) now works in the case of adjacent string literals
- make enums unsigned (like gcc) so we don't suffer the msvc enum bitfield bug
@ -35,6 +39,8 @@ local bug fixes
local changes
- use tabs in generated output
- parse javadoc-style markdown comments
- don't fold backslash newline in comments
- generated code no longer assumes red zone
- emit .size directives for function definitions
- use fisttp long double conversions if built w/ -msse3

View file

@ -177,8 +177,8 @@ struct As {
struct Sauces {
unsigned long n;
struct Sauce {
int path; // strings
int line; // 1-indexed
unsigned path; // strings
unsigned line; // 1-indexed
} * p;
} sauces;
struct Things {
@ -192,14 +192,14 @@ struct As {
TT_FORWARD,
TT_BACKWARD,
} t : 4;
int s : 28; // sauces
int i; // identity,ints,floats,slices
unsigned s : 28; // sauces
unsigned i; // identity,ints,floats,slices
} * p;
} things;
struct Sections {
unsigned long n;
struct Section {
int name; // strings
unsigned name; // strings
int flags;
int type;
int align;
@ -210,11 +210,11 @@ struct As {
unsigned long n;
struct Symbol {
bool isused;
int name; // slices
int section; // sections
int stb; // STB_*
int stv; // STV_*
int type; // STT_*
unsigned char stb; // STB_*
unsigned char stv; // STV_*
unsigned char type; // STT_*
unsigned name; // slices
unsigned section; // sections
long offset;
long size;
struct ElfWriterSymRef ref;
@ -223,25 +223,25 @@ struct As {
struct HashTable {
unsigned i, n;
struct HashEntry {
int h;
int i;
unsigned h;
unsigned i;
} * p;
} symbolindex;
struct Labels {
unsigned long n;
struct Label {
int id;
int tok; // things
int symbol; // symbols
unsigned id;
unsigned tok; // things
unsigned symbol; // symbols
} * p;
} labels;
struct Relas {
unsigned long n;
struct Rela {
bool isdead;
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
int expr; // exprs
int section; // sections
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
unsigned expr; // exprs
unsigned section; // sections
long offset;
long addend;
} * p;
@ -251,7 +251,7 @@ struct As {
struct Expr {
enum ExprKind {
EX_INT, // integer
EX_SYM, // slice, forward, backward, then symbol
EX_SYM, // things (then symbols after eval)
EX_NEG, // unary -
EX_NOT, // unary !
EX_BITNOT, // unary ~
@ -276,7 +276,7 @@ struct As {
EM_DTPOFF,
EM_TPOFF,
} em;
int tok;
unsigned tok;
int lhs;
int rhs;
long x;
@ -456,7 +456,7 @@ static bool EndsWith(const char *s, const char *suffix) {
n = strlen(s);
m = strlen(suffix);
if (m > n) return false;
return memcmp(s + n - m, suffix, m) == 0;
return !memcmp(s + n - m, suffix, m);
}
static char *Format(const char *fmt, ...) {
@ -1192,21 +1192,21 @@ static int ParseMul(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '*')) {
y = ParseUnary(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x *= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_MUL, x, y);
}
} else if (IsPunct(a, i, '/')) {
y = ParseUnary(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x /= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_DIV, x, y);
}
} else if (IsPunct(a, i, '%')) {
y = ParseUnary(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x %= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_REM, x, y);
@ -1225,14 +1225,14 @@ static int ParseAdd(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '+')) {
y = ParseMul(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x += a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_ADD, x, y);
}
} else if (IsPunct(a, i, '-')) {
y = ParseMul(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x -= a->exprs.p[y].x;
} else if (a->exprs.p[y].kind == EX_INT) {
a->exprs.p[y].x = -a->exprs.p[y].x;
@ -1254,14 +1254,14 @@ static int ParseShift(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '<' << 8 | '<')) {
y = ParseAdd(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x <<= a->exprs.p[y].x & 63;
} else {
x = NewBinary(a, EX_SHL, x, y);
}
} else if (IsPunct(a, i, '>' << 8 | '>')) {
y = ParseAdd(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x >>= a->exprs.p[y].x & 63;
} else {
x = NewBinary(a, EX_SHR, x, y);
@ -1280,28 +1280,28 @@ static int ParseRelational(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '<')) {
y = ParseShift(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[x].x < a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_LT, x, y);
}
} else if (IsPunct(a, i, '>')) {
y = ParseShift(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[y].x < a->exprs.p[x].x;
} else {
x = NewBinary(a, EX_LT, y, x);
}
} else if (IsPunct(a, i, '<' << 8 | '=')) {
y = ParseShift(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[x].x <= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_LE, x, y);
}
} else if (IsPunct(a, i, '>' << 8 | '=')) {
y = ParseShift(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[y].x <= a->exprs.p[x].x;
} else {
x = NewBinary(a, EX_LE, y, x);
@ -1320,14 +1320,14 @@ static int ParseEquality(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '=' << 8 | '=')) {
y = ParseRelational(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_EQ, x, y);
}
} else if (IsPunct(a, i, '!' << 8 | '=')) {
y = ParseRelational(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_NE, x, y);
@ -1346,7 +1346,7 @@ static int ParseAnd(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '&')) {
y = ParseEquality(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x &= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_AND, x, y);
@ -1365,7 +1365,7 @@ static int ParseXor(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '^')) {
y = ParseAnd(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x ^= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_XOR, x, y);
@ -1384,7 +1384,7 @@ static int ParseOr(struct As *a, int *rest, int i) {
for (;;) {
if (IsPunct(a, i, '|')) {
y = ParseXor(a, &i, i + 1);
if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) {
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
a->exprs.p[x].x |= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_OR, x, y);
@ -3745,8 +3745,7 @@ static int ResolveSymbol(struct As *a, int i) {
case TT_FORWARD:
return FindLabelForward(a, a->ints.p[a->things.p[i].i]);
default:
DebugBreak();
Fail(a, "this corruption");
Fail(a, "this corruption %d", a->things.p[i].t);
}
}
@ -3777,15 +3776,6 @@ static void Write32(char b[4], int x) {
b[3] = x >> 030;
}
static void MarkUndefinedSymbolsGlobal(struct As *a) {
int i;
for (i = 0; i < a->symbols.n; ++i) {
if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) {
a->symbols.p[i].stb = STB_GLOBAL;
}
}
}
static void MarkUsedSymbols(struct As *a, int i) {
if (i == -1) return;
MarkUsedSymbols(a, a->exprs.p[i].lhs);
@ -3818,6 +3808,16 @@ static void Evaluate(struct As *a) {
}
}
static void MarkUndefinedSymbolsGlobal(struct As *a) {
int i;
for (i = 0; i < a->symbols.n; ++i) {
if (a->symbols.p[i].isused && !a->symbols.p[i].section &&
a->symbols.p[i].stb == STB_LOCAL) {
a->symbols.p[i].stb = STB_GLOBAL;
}
}
}
static bool IsLocal(struct As *a, int name) {
if (name < 0) return true;
return a->slices.p[name].n >= 2 && !memcmp(a->slices.p[name].p, ".L", 2);
@ -3829,17 +3829,18 @@ static bool IsLiveSymbol(struct As *a, int i) {
}
static void Objectify(struct As *a, int path) {
int i, j, s;
char *p;
int i, j, s, e;
struct ElfWriter *elf;
elf = elfwriter_open(a->strings.p[path], 0644);
for (i = 0; i < a->symbols.n; ++i) {
if (!IsLiveSymbol(a, i)) continue;
p = strndup(a->slices.p[a->symbols.p[i].name].p,
a->slices.p[a->symbols.p[i].name].n);
a->symbols.p[i].ref = elfwriter_appendsym(
elf,
strndup(a->slices.p[a->symbols.p[i].name].p,
a->slices.p[a->symbols.p[i].name].n),
ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type),
elf, p, ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type),
a->symbols.p[i].stv, a->symbols.p[i].offset, a->symbols.p[i].size);
free(p);
}
for (i = 0; i < a->sections.n; ++i) {
elfwriter_align(elf, a->sections.p[i].align, 0);
@ -3853,24 +3854,24 @@ static void Objectify(struct As *a, int path) {
for (j = 0; j < a->relas.n; ++j) {
if (a->relas.p[j].isdead) continue;
if (a->relas.p[j].section != i) continue;
a->i = a->exprs.p[a->relas.p[j].expr].tok;
switch (a->exprs.p[a->relas.p[j].expr].kind) {
e = a->relas.p[j].expr;
a->i = a->exprs.p[e].tok;
switch (a->exprs.p[e].kind) {
case EX_INT:
break;
case EX_SYM:
elfwriter_appendrela(
elf, a->relas.p[j].offset,
a->symbols.p[a->exprs.p[a->relas.p[j].expr].x].ref,
a->relas.p[j].kind, a->relas.p[j].addend);
elfwriter_appendrela(elf, a->relas.p[j].offset,
a->symbols.p[a->exprs.p[e].x].ref,
a->relas.p[j].kind, a->relas.p[j].addend);
break;
case EX_ADD:
if (a->exprs.p[a->exprs.p[j].lhs].kind == EX_SYM &&
a->exprs.p[a->exprs.p[j].rhs].kind == EX_INT) {
if (a->exprs.p[a->exprs.p[e].lhs].kind == EX_SYM &&
a->exprs.p[a->exprs.p[e].rhs].kind == EX_INT) {
elfwriter_appendrela(
elf, a->relas.p[j].offset,
a->symbols.p[a->exprs.p[a->exprs.p[j].lhs].x].ref,
a->symbols.p[a->exprs.p[a->exprs.p[e].lhs].x].ref,
a->relas.p[j].kind,
a->relas.p[j].addend + a->exprs.p[a->exprs.p[j].rhs].x);
a->relas.p[j].addend + a->exprs.p[a->exprs.p[e].rhs].x);
} else {
Fail(a, "bad addend");
}
@ -3887,6 +3888,58 @@ static void Objectify(struct As *a, int path) {
elfwriter_close(elf);
}
static void CheckIntegrity(struct As *a) {
int i;
for (i = 0; i < a->things.n; ++i) {
CHECK_LT((int)a->things.p[i].s, a->sauces.n);
switch (a->things.p[i].t) {
case TT_INT:
case TT_FORWARD:
case TT_BACKWARD:
CHECK_LT(a->things.p[i].i, a->ints.n);
break;
case TT_FLOAT:
CHECK_LT(a->things.p[i].i, a->floats.n);
break;
case TT_SLICE:
CHECK_LT(a->things.p[i].i, a->slices.n);
break;
default:
break;
}
}
for (i = 0; i < a->sections.n; ++i) {
CHECK_LT(a->sections.p[i].name, a->strings.n);
}
for (i = 0; i < a->symbols.n; ++i) {
CHECK_LT(a->symbols.p[i].name, a->slices.n);
CHECK_LT(a->symbols.p[i].section, a->sections.n);
}
for (i = 0; i < a->labels.n; ++i) {
CHECK_LT(a->labels.p[i].tok, a->things.n);
CHECK_LT(a->labels.p[i].symbol, a->symbols.n);
}
for (i = 0; i < a->relas.n; ++i) {
CHECK_LT(a->relas.p[i].expr, a->exprs.n);
CHECK_LT(a->relas.p[i].section, a->sections.n);
}
for (i = 0; i < a->exprs.n; ++i) {
CHECK_LT(a->exprs.p[i].tok, a->things.n);
if (a->exprs.p[i].lhs != -1) CHECK_LT(a->exprs.p[i].lhs, a->exprs.n);
if (a->exprs.p[i].rhs != -1) CHECK_LT(a->exprs.p[i].rhs, a->exprs.n);
switch (a->exprs.p[i].kind) {
case EX_SYM:
CHECK_LT(a->exprs.p[i].x, a->things.n);
CHECK(a->things.p[a->exprs.p[i].x].t == TT_SLICE ||
a->things.p[a->exprs.p[i].x].t == TT_FORWARD ||
a->things.p[a->exprs.p[i].x].t == TT_BACKWARD);
break;
default:
break;
}
}
}
static void PrintThings(struct As *a) {
int i;
char pbuf[4], fbuf[32];
@ -3929,17 +3982,18 @@ void Assembler(int argc, char *argv[]) {
Tokenize(a, a->inpath);
/* PrintThings(a); */
Assemble(a);
/* CheckIntegrity(a); */
Evaluate(a);
MarkUndefinedSymbolsGlobal(a);
Objectify(a, a->outpath);
malloc_stats();
/* malloc_stats(); */
FreeAssembler(a);
}
int main(int argc, char *argv[]) {
showcrashreports();
if (argc == 1) {
system("o//third_party/chibicc/as.com -o /tmp/o third_party/chibicc/hog.s");
system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s");
system("objdump -xwd /tmp/o");
exit(0);
}

View file

@ -32,6 +32,7 @@ bool opt_verbose;
static bool opt_A;
static bool opt_E;
static bool opt_J;
static bool opt_M;
static bool opt_MD;
static bool opt_MMD;
@ -202,6 +203,8 @@ static void parse_args(int argc, char **argv) {
opt_c = true;
} else if (!strcmp(argv[i], "-E")) {
opt_E = true;
} else if (!strcmp(argv[i], "-J")) {
opt_J = true;
} else if (!strcmp(argv[i], "-A")) {
opt_A = true;
} else if (!strcmp(argv[i], "-I")) {
@ -364,7 +367,14 @@ static char *create_tmpfile(void) {
return path;
}
static void run_subprocess(char **argv) {
static void handle_exit(bool ok) {
if (!ok) {
opt_save_temps = true;
exit(1);
}
}
static bool run_subprocess(char **argv) {
// If -### is given, dump the subprocess's command line.
if (opt_hash_hash_hash) {
fprintf(stderr, "%s", argv[0]);
@ -384,13 +394,10 @@ static void run_subprocess(char **argv) {
break;
}
}
if (status != 0) {
opt_save_temps = true;
exit(1);
}
return !status;
}
static void run_cc1(int argc, char **argv, char *input, char *output) {
static bool run_cc1(int argc, char **argv, char *input, char *output) {
char **args = calloc(argc + 10, sizeof(char *));
memcpy(args, argv, argc * sizeof(char *));
args[argc++] = "-cc1";
@ -402,7 +409,7 @@ static void run_cc1(int argc, char **argv, char *input, char *output) {
args[argc++] = "-cc1-output";
args[argc++] = output;
}
run_subprocess(args);
return run_subprocess(args);
}
static void print_token(FILE *out, Token *tok) {
@ -540,6 +547,10 @@ static void cc1(void) {
print_ast(stdout, prog);
return;
}
if (opt_J) {
output_javadown(output_file, prog);
return;
}
FILE *out = open_file(output_file);
codegen(prog, out);
fclose(out);
@ -561,7 +572,7 @@ static void assemble(char *input, char *output) {
strarray_push(&arr, "-o");
strarray_push(&arr, output);
strarray_push(&arr, NULL);
run_subprocess(arr.data);
handle_exit(run_subprocess(arr.data));
}
static void run_linker(StringArray *inputs, char *output) {
@ -591,7 +602,7 @@ static void run_linker(StringArray *inputs, char *output) {
strarray_push(&arr, inputs->data[i]);
}
strarray_push(&arr, NULL);
run_subprocess(arr.data);
handle_exit(run_subprocess(arr.data));
}
int chibicc(int argc, char **argv) {
@ -608,6 +619,7 @@ int chibicc(int argc, char **argv) {
error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
}
StringArray ld_args = {};
StringArray dox_args = {};
for (int i = 0; i < input_paths.len; i++) {
char *input = input_paths.data[i];
if (!strncmp(input, "-l", 2)) {
@ -647,25 +659,33 @@ int chibicc(int argc, char **argv) {
assert(type == FILE_C || type == FILE_ASM_CPP);
// Just preprocess
if (opt_E || opt_M) {
run_cc1(argc, argv, input, NULL);
handle_exit(run_cc1(argc, argv, input, NULL));
continue;
}
// Compile
if (opt_S) {
run_cc1(argc, argv, input, output);
handle_exit(run_cc1(argc, argv, input, output));
continue;
}
// Compile and assemble
if (opt_c) {
char *tmp = create_tmpfile();
run_cc1(argc, argv, input, tmp);
handle_exit(run_cc1(argc, argv, input, tmp));
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();
run_cc1(argc, argv, input, tmp1);
handle_exit(run_cc1(argc, argv, input, tmp1));
assemble(tmp1, tmp2);
strarray_push(&ld_args, tmp2);
continue;
@ -673,5 +693,8 @@ int chibicc(int argc, char **argv) {
if (ld_args.len > 0) {
run_linker(&ld_args, opt_o ? opt_o : "a.out");
}
if (dox_args.len > 0) {
drop_dox(&dox_args, opt_o ? opt_o : "/dev/stdout");
}
return 0;
}

View file

@ -26,6 +26,7 @@
#include "libc/unicode/unicode.h"
#include "libc/x/x.h"
#include "third_party/gdtoa/gdtoa.h"
#include "tool/build/lib/javadown.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -35,7 +36,10 @@ typedef struct Asm Asm;
typedef struct AsmOperand AsmOperand;
typedef struct File File;
typedef struct FpClassify FpClassify;
typedef struct HashMap HashMap;
typedef struct Hideset Hideset;
typedef struct Macro Macro;
typedef struct MacroParam MacroParam;
typedef struct Member Member;
typedef struct Node Node;
typedef struct Obj Obj;
@ -47,6 +51,8 @@ typedef struct Token Token;
typedef struct TokenStack TokenStack;
typedef struct Type Type;
typedef Token *macro_handler_fn(Token *);
//
// strarray.c
//
@ -64,13 +70,14 @@ void strarray_push(StringArray *, char *);
//
typedef enum {
TK_IDENT, // Identifiers
TK_PUNCT, // Punctuators
TK_KEYWORD, // Keywords
TK_STR, // String literals
TK_NUM, // Numeric literals
TK_PP_NUM, // Preprocessing numbers
TK_EOF, // End-of-file markers
TK_IDENT, // Identifiers
TK_PUNCT, // Punctuators
TK_KEYWORD, // Keywords
TK_STR, // String literals
TK_NUM, // Numeric literals
TK_PP_NUM, // Preprocessing numbers
TK_JAVADOWN, // /** ... */ comments
TK_EOF, // End-of-file markers
} TokenKind;
struct File {
@ -80,6 +87,7 @@ struct File {
// For #line directive
char *display_name;
int line_delta;
struct Javadown *javadown;
};
struct thatispacked Token {
@ -96,6 +104,7 @@ struct thatispacked Token {
char *filename; // Filename
Hideset *hideset; // For macro expansion
Token *origin; // If this is expanded from a macro, the original token
struct Javadown *javadown;
union {
int64_t val; // If kind is TK_NUM, its value
long double fval; // If kind is TK_NUM, its value
@ -134,6 +143,23 @@ int read_escaped_char(char **, char *);
// preprocess.c
//
struct MacroParam {
MacroParam *next;
char *name;
};
struct Macro {
char *name;
bool is_objlike; // Object-like or function-like
MacroParam *params;
char *va_args_name;
Token *body;
macro_handler_fn *handler;
Token *javadown;
};
extern HashMap macros;
char *search_include_paths(char *);
void init_macros(void);
void define_macro(char *, char *);
@ -232,6 +258,7 @@ struct Obj {
char *asmname;
char *section;
char *visibility;
Token *javadown;
// Global variable
bool is_tentative;
bool is_string_literal;
@ -244,6 +271,9 @@ struct Obj {
bool is_noreturn;
bool is_destructor;
bool is_constructor;
bool is_ms_abi; /* TODO */
bool is_force_align_arg_pointer;
bool is_no_caller_saved_registers;
int stack_size;
Obj *params;
Node *body;
@ -419,6 +449,7 @@ struct Type {
int align; // alignment
bool is_unsigned; // unsigned or signed
bool is_atomic; // true if _Atomic
bool is_ms_abi; // microsoft abi
Type *origin; // for type compatibility check
// Pointer-to or array-of type. We intentionally use the same member
// to represent pointer/array duality in C.
@ -534,11 +565,11 @@ typedef struct {
void *val;
} HashEntry;
typedef struct {
struct HashMap {
HashEntry *buckets;
int capacity;
int used;
} HashMap;
};
void *hashmap_get(HashMap *, char *);
void *hashmap_get2(HashMap *, char *, int);
@ -584,6 +615,13 @@ Token *alloc_token(void);
Obj *alloc_obj(void);
Type *alloc_type(void);
//
// javadown.c
//
void output_javadown(const char *, Obj *);
void drop_dox(const StringArray *, const char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */

View file

@ -49,6 +49,7 @@ THIRD_PARTY_CHIBICC_A_CHECKS = \
$(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_BITS \
LIBC_CALLS \
LIBC_CALLS_HEFTY \

View file

@ -2265,7 +2265,7 @@ static void emit_data(Obj *prog) {
}
}
static void store_fp(int r, int offset, int sz) {
static void store_fp(Obj *fn, int r, int offset, int sz) {
switch (sz) {
case 4:
println("\tmovss\t%%xmm%d,%d(%%rbp)", r, offset);
@ -2274,7 +2274,8 @@ static void store_fp(int r, int offset, int sz) {
println("\tmovsd\t%%xmm%d,%d(%%rbp)", r, offset);
return;
case 16:
println("\tmovaps\t%%xmm%d,%d(%%rbp)", r, offset);
println("\t%s\t%%xmm%d,%d(%%rbp)",
fn->is_force_align_arg_pointer ? "movups" : "movaps", r, offset);
return;
}
UNREACHABLE();
@ -2381,13 +2382,13 @@ static void emit_text(Obj *prog) {
case TY_UNION:
assert(ty->size <= 16);
if (has_flonum(ty, 0, 8, 0)) {
store_fp(fp++, var->offset, MIN(8, ty->size));
store_fp(fn, fp++, var->offset, MIN(8, ty->size));
} else {
store_gp(gp++, var->offset, MIN(8, ty->size));
}
if (ty->size > 8) {
if (has_flonum(ty, 8, 16, 0)) {
store_fp(fp++, var->offset + 8, ty->size - 8);
store_fp(fn, fp++, var->offset + 8, ty->size - 8);
} else {
store_gp(gp++, var->offset + 8, ty->size - 8);
}
@ -2395,7 +2396,7 @@ static void emit_text(Obj *prog) {
break;
case TY_FLOAT:
case TY_DOUBLE:
store_fp(fp++, var->offset, ty->size);
store_fp(fn, fp++, var->offset, ty->size);
break;
case TY_INT128:
store_gp(gp++, var->offset + 0, 8);
@ -2405,6 +2406,20 @@ static void emit_text(Obj *prog) {
store_gp(gp++, var->offset, ty->size);
}
}
if (fn->is_force_align_arg_pointer) {
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");
}
// Emit code
gen_stmt(fn->body);
assert(!depth);
@ -2420,6 +2435,17 @@ static void emit_text(Obj *prog) {
if (fn->is_noreturn) {
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");
}
emitlin("\tleave");
emitlin("\tret");
}

248
third_party/chibicc/dox1.c vendored Normal file
View file

@ -0,0 +1,248 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/gc.h"
#include "third_party/chibicc/chibicc.h"
#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p))
struct DoxWriter {
struct Buffer {
size_t n;
char *p;
} buf;
struct Macros {
size_t n;
Macro **p;
} macros;
struct Objects {
size_t n;
Obj **p;
} objects;
};
static void SerializeData(struct Buffer *buf, const void *p, unsigned long n) {
struct Slice *s;
buf->p = realloc(buf->p, buf->n + n);
memcpy(buf->p + buf->n, p, n);
buf->n += n;
}
static int SerializeInt(struct Buffer *buf, int x) {
unsigned char b[4];
b[0] = x >> 000;
b[1] = x >> 010;
b[2] = x >> 020;
b[3] = x >> 030;
SerializeData(buf, b, 4);
return x;
}
static void SerializeStr(struct Buffer *buf, const char *s) {
size_t n;
if (!s) s = "";
n = strlen(s);
n = MIN(INT_MAX, n);
SerializeInt(buf, n);
SerializeData(buf, s, n);
}
static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) {
int i;
SerializeInt(buf, jd->isfileoverview);
SerializeStr(buf, jd->title);
SerializeStr(buf, jd->text);
SerializeInt(buf, jd->tags.n);
for (i = 0; i < jd->tags.n; ++i) {
SerializeStr(buf, jd->tags.p[i].tag);
SerializeStr(buf, jd->tags.p[i].text);
}
}
static char *DescribeScalar(struct Type *ty, char *name) {
return xasprintf("%s%s%s", ty->is_atomic ? "_Atomic " : "",
ty->is_unsigned ? "unsigned " : "", name);
}
static char *DescribeType(struct Type *ty) {
switch (ty->kind) {
case TY_VOID:
return strdup("void");
case TY_BOOL:
return strdup("_Bool");
case TY_CHAR:
return DescribeScalar(ty, "char");
case TY_SHORT:
return DescribeScalar(ty, "short");
case TY_INT:
return DescribeScalar(ty, "int");
case TY_LONG:
return DescribeScalar(ty, "long");
case TY_INT128:
return DescribeScalar(ty, "__int128");
case TY_FLOAT:
return DescribeScalar(ty, "float");
case TY_DOUBLE:
return DescribeScalar(ty, "double");
case TY_LDOUBLE:
return DescribeScalar(ty, "long double");
case TY_PTR:
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);
} else {
return strdup("ANONYMOUS-ENUM");
}
case TY_STRUCT:
if (ty->name_pos) {
return xasprintf("struct %.*s", ty->name_pos->len, ty->name_pos->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);
} else {
return strdup("ANONYMOUS-UNION");
}
case TY_FUNC:
return xasprintf("%s(*)()", gc(DescribeType(ty->return_ty)));
default:
return "UNKNOWN";
}
}
static int CountParams(Obj *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;
return "missingno.c";
}
static int GetLine(Obj *obj) {
if (obj->javadown && obj->javadown->file) return obj->javadown->line_no;
if (obj->tok && obj->tok->file) return obj->tok->line_no;
return 0;
}
static void SerializeDox(struct DoxWriter *dox, Obj *prog) {
int i;
char *s;
Obj *param;
MacroParam *mparam;
SerializeInt(&dox->buf, dox->objects.n);
for (i = 0; i < dox->objects.n; ++i) {
s = DescribeType(dox->objects.p[i]->ty);
SerializeStr(&dox->buf, s);
free(s);
SerializeStr(&dox->buf, dox->objects.p[i]->name);
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]->is_weak);
SerializeInt(&dox->buf, dox->objects.p[i]->is_inline);
SerializeInt(&dox->buf, dox->objects.p[i]->is_noreturn);
SerializeInt(&dox->buf, dox->objects.p[i]->is_destructor);
SerializeInt(&dox->buf, dox->objects.p[i]->is_constructor);
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, CountParams(dox->objects.p[i]->params));
for (param = dox->objects.p[i]->params; param; param = param->next) {
s = DescribeType(param->ty);
SerializeStr(&dox->buf, s);
free(s);
SerializeStr(&dox->buf, param->name);
}
}
SerializeInt(&dox->buf, dox->macros.n);
for (i = 0; i < dox->macros.n; ++i) {
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, 31337);
}
static void LoadPublicDefinitions(struct DoxWriter *dox, Obj *prog) {
int i;
Obj *obj;
Macro *macro;
for (obj = prog; obj; obj = obj->next) {
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;
APPEND(dox->objects);
dox->objects.p[dox->objects.n - 1] = obj;
}
for (i = 0; i < macros.capacity; ++i) {
if (!macros.buckets[i].key) continue;
if (macros.buckets[i].key == (char *)-1) continue;
macro = macros.buckets[i].val;
if (!macro->javadown) continue;
if (!macro->javadown->javadown) continue;
if (*macro->name == '_') continue;
if (strchr(macro->name, '$')) continue;
APPEND(dox->macros);
dox->macros.p[dox->macros.n - 1] = macro;
}
}
static struct DoxWriter *NewDoxWriter(void) {
return calloc(1, sizeof(struct DoxWriter));
}
static void FreeDoxWriter(struct DoxWriter *dox) {
if (dox) {
free(dox->buf.p);
free(dox->macros.p);
free(dox->objects.p);
free(dox);
}
}
static void WriteDox(struct DoxWriter *dox, const char *path) {
int fd;
CHECK_NE(-1, (fd = creat(path, 0644)));
CHECK_EQ(dox->buf.n, write(fd, dox->buf.p, dox->buf.n));
close(fd);
}
/**
* Emits documentation datum for compilation unit just parsed.
*/
void output_javadown(const char *path, Obj *prog) {
struct DoxWriter *dox = NewDoxWriter();
LoadPublicDefinitions(dox, prog);
SerializeDox(dox, prog);
WriteDox(dox, path);
FreeDoxWriter(dox);
}

392
third_party/chibicc/dox2.c vendored Normal file
View file

@ -0,0 +1,392 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/alg.h"
#include "libc/bits/bits.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"
#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p))
struct Dox {
unsigned char *p;
struct Freelist {
size_t n;
void **p;
} freelist;
struct Set {
size_t n;
struct SetEntry {
unsigned h;
char *s;
} * p;
} names;
struct DoxObjects {
size_t n;
struct DoxObject {
bool ignore;
char *type;
char *name;
char *path;
int line;
bool is_function;
bool is_weak;
bool is_inline;
bool is_noreturn;
bool is_destructor;
bool is_constructor;
bool is_force_align_arg_pointer;
bool is_no_caller_saved_registers;
char *visibility;
struct Javadown *javadown;
struct DoxObjectParams {
size_t n;
struct DoxObjectParam {
char *type;
char *name;
} * p;
} params;
} * p;
} objects;
struct {
size_t n;
int *p;
} objectindex;
};
static unsigned Hash(const void *p, unsigned long n) {
unsigned h, i;
for (h = i = 0; i < n; i++) {
h += ((unsigned char *)p)[i];
h *= 0x9e3779b1;
}
return MAX(1, h);
}
static struct Dox *NewDox(void) {
return calloc(1, sizeof(struct Dox));
}
static void FreeDox(struct Dox *dox) {
int i;
if (dox) {
for (i = 0; i < dox->freelist.n; ++i) {
free(dox->freelist.p[i]);
}
free(dox->names.p);
free(dox->freelist.p);
free(dox->objects.p);
free(dox);
}
}
static void *FreeLater(struct Dox *dox, void *p) {
APPEND(dox->freelist);
dox->freelist.p[dox->freelist.n - 1] = p;
return p;
}
static int DeserializeInt(struct Dox *dox) {
int x;
x = (unsigned)dox->p[0] << 000 | (unsigned)dox->p[1] << 010 |
(unsigned)dox->p[2] << 020 | (unsigned)dox->p[3] << 030;
dox->p += 4;
return x;
}
static char *DeserializeStr(struct Dox *dox) {
char *s;
size_t n;
n = DeserializeInt(dox);
s = malloc(n + 1);
memcpy(s, dox->p, n);
s[n] = '\0';
dox->p += n;
return FreeLater(dox, s);
}
static struct Javadown *DeserializeJavadown(struct Dox *dox) {
int i;
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);
}
return jd;
}
static void DeserializeObject(struct Dox *dox, struct DoxObject *o) {
int i;
o->ignore = false;
o->type = DeserializeStr(dox);
o->name = DeserializeStr(dox);
o->path = DeserializeStr(dox);
o->line = DeserializeInt(dox);
o->is_function = DeserializeInt(dox);
o->is_weak = DeserializeInt(dox);
o->is_inline = DeserializeInt(dox);
o->is_noreturn = DeserializeInt(dox);
o->is_destructor = DeserializeInt(dox);
o->is_constructor = DeserializeInt(dox);
o->is_force_align_arg_pointer = DeserializeInt(dox);
o->is_no_caller_saved_registers = DeserializeInt(dox);
o->visibility = DeserializeStr(dox);
o->javadown = DeserializeJavadown(dox);
o->params.n = DeserializeInt(dox);
o->params.p = FreeLater(dox, malloc(o->params.n * sizeof(*o->params.p)));
for (i = 0; i < o->params.n; ++i) {
o->params.p[i].type = DeserializeStr(dox);
o->params.p[i].name = DeserializeStr(dox);
}
}
static void DeserializeDox(struct Dox *dox) {
int i, j, n;
i = dox->objects.n;
n = DeserializeInt(dox);
dox->objects.p =
realloc(dox->objects.p, (dox->objects.n + n) * sizeof(*dox->objects.p));
for (j = 0; j < n; ++j) {
DeserializeObject(dox, dox->objects.p + i + j);
}
dox->objects.n += n;
}
static void ReadDox(struct Dox *dox, const StringArray *files) {
int i, fd;
void *map;
struct stat st;
for (i = 0; i < files->len; ++i) {
CHECK_NE(-1, (fd = open(files->data[i], 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)));
dox->p = map;
DeserializeDox(dox);
munmap(map, st.st_size);
}
close(fd);
}
}
static bool AddSet(struct Set *set, char *s) {
unsigned i, h, k;
h = Hash(s, strlen(s));
k = 0;
for (k = 0;; ++k) {
i = (h + k + ((k + 1) >> 1)) & (set->n - 1);
if (!set->p[i].h) {
set->p[i].h = h;
set->p[i].s = s;
return true;
}
if (h == set->p[i].h && !strcmp(s, set->p[i].s)) {
return false;
}
}
}
static int CompareObjectNames(const void *a, const void *b, void *arg) {
int *i1, *i2;
struct Dox *dox;
i1 = a, i2 = b, dox = arg;
return strcmp(dox->objects.p[*i1].name, dox->objects.p[*i2].name);
}
static void IndexDox(struct Dox *dox) {
size_t i, j, n;
dox->names.n = roundup2pow(dox->objects.n) << 1;
dox->names.p = calloc(dox->names.n, sizeof(*dox->names.p));
for (n = 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;
}
qsort_r(dox->objectindex.p, dox->objectindex.n, sizeof(*dox->objectindex.p),
CompareObjectNames, dox);
}
static void PrintText(FILE *f, const char *s) {
int c;
bool bol, pre;
for (pre = false, bol = true;;) {
switch ((c = *s++)) {
case '\0':
if (pre) {
fprintf(f, "</pre>");
}
return;
case '&':
fprintf(f, "&amp;");
bol = false;
break;
case '<':
fprintf(f, "&lt;");
bol = false;
break;
case '>':
fprintf(f, "&gt;");
bol = false;
break;
case '"':
fprintf(f, "&quot;");
bol = false;
break;
case '\'':
fprintf(f, "&apos;");
bol = false;
break;
case '\n':
if (!pre && *s == '\n') {
++s;
fprintf(f, "\n<p>");
} else if (pre &&
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) {
fprintf(f, "</pre>\n");
pre = false;
} else {
fprintf(f, "\n");
}
bol = true;
break;
case ' ':
if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') {
pre = true;
fprintf(f, "<pre>");
}
fprintf(f, " ");
bol = false;
break;
default:
fprintf(f, "%c", c);
bol = false;
break;
}
}
}
static void PrintDox(struct Dox *dox, FILE *f) {
int i, j, k;
char *prefix;
struct DoxObject *o;
fprintf(f, "\
<!doctype html>\n\
<meta charset=\"utf-8\">\n\
<style>\n\
.indent {\n\
padding-left: 1em;\n\
}\n\
</style>\n\
\n\
<table width=\"100%%\"><tr><td width=\"33%%\" valign=\"top\">\n\
<p 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;
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);
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);
fprintf(f, "\n");
}
}
fprintf(f, "</div>\n");
}
fprintf(f, "</table>\n");
}
/**
* Merges documentation data and outputs HTML.
*/
void drop_dox(const StringArray *files, const char *path) {
FILE *f;
struct Dox *dox;
dox = NewDox();
ReadDox(dox, files);
IndexDox(dox);
f = fopen(path, "w");
PrintDox(dox, f);
fclose(f);
FreeDox(dox);
}

View file

@ -16,6 +16,7 @@
// So it is very easy to lookahead arbitrary number of tokens in this
// parser.
#include "libc/nexgen32e/ffs.h"
#include "libc/testlib/testlib.h"
#include "third_party/chibicc/chibicc.h"
@ -50,11 +51,14 @@ typedef struct {
bool is_const;
bool is_tls;
bool is_weak;
bool is_ms_abi;
bool is_aligned;
bool is_noreturn;
bool is_destructor;
bool is_constructor;
bool is_externally_visible;
bool is_force_align_arg_pointer;
bool is_no_caller_saved_registers;
int align;
char *section;
char *visibility;
@ -113,6 +117,8 @@ static Node *current_switch;
static Obj *builtin_alloca;
static Token *current_javadown;
static Initializer *initializer(Token **, Token *, Type *, Type **);
static Member *get_struct_member(Type *, Token *);
static Node *binor(Token **, Token *);
@ -382,6 +388,10 @@ static Token *type_attributes(Token *tok, void *arg) {
ty->is_packed = true;
return tok;
}
if (consume_attribute(&tok, tok, "ms_abi")) {
ty->is_ms_abi = true;
return tok;
}
if (consume_attribute(&tok, tok, "aligned")) {
ty->is_aligned = true;
if (CONSUME(&tok, tok, "(")) {
@ -466,6 +476,18 @@ static Token *thing_attributes(Token *tok, void *arg) {
attr->is_externally_visible = true;
return tok;
}
if (consume_attribute(&tok, tok, "force_align_arg_pointer")) {
attr->is_force_align_arg_pointer = true;
return tok;
}
if (consume_attribute(&tok, tok, "no_caller_saved_registers")) {
attr->is_no_caller_saved_registers = true;
return tok;
}
if (consume_attribute(&tok, tok, "ms_abi")) {
attr->is_ms_abi = true;
return tok;
}
if (consume_attribute(&tok, tok, "constructor")) {
attr->is_constructor = true;
if (CONSUME(&tok, tok, "(")) {
@ -1080,6 +1102,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety,
// even if ty is not VLA because ty may be a pointer to VLA
// (e.g. int (*foo)[n][m] where n and m are variables.)
cur = cur->next = new_unary(ND_EXPR_STMT, compute_vla_size(ty, tok), tok);
tok = attribute_list(tok, attr, thing_attributes);
if (ty->kind == TY_VLA) {
if (EQUAL(tok, "="))
error_tok(tok, "variable-sized object may not be initialized");
@ -1198,7 +1221,8 @@ static Member *struct_designator(Token **rest, Token *tok, Type *ty) {
if (tok->kind != TK_IDENT) error_tok(tok, "expected a field designator");
for (Member *mem = ty->members; mem; mem = mem->next) {
// Anonymous struct member
if (mem->ty->kind == TY_STRUCT && !mem->name) {
if ((mem->ty->kind == TY_STRUCT || mem->ty->kind == TY_UNION) &&
!mem->name) {
if (get_struct_member(mem->ty, tok)) {
*rest = start;
return mem;
@ -1920,6 +1944,7 @@ int64_t eval(Node *node) {
// number. The latter form is accepted only as an initialization
// expression for a global variable.
int64_t eval2(Node *node, char ***label) {
int64_t x, y;
add_type(node);
if (is_flonum(node->ty)) return eval_double(node);
switch (node->kind) {
@ -1930,15 +1955,25 @@ int64_t eval2(Node *node, char ***label) {
case ND_MUL:
return eval(node->lhs) * eval(node->rhs);
case ND_DIV:
if (node->ty->is_unsigned)
return (uint64_t)eval(node->lhs) / eval(node->rhs);
return eval(node->lhs) / eval(node->rhs);
y = eval(node->rhs);
if (!y) error_tok(node->rhs->tok, "constexpr div by zero");
if (node->ty->is_unsigned) {
return (uint64_t)eval(node->lhs) / y;
}
x = eval(node->lhs);
if (x == 0x8000000000000000 && y == -1) {
error_tok(node->rhs->tok, "constexpr divide error");
}
return x / y;
case ND_NEG:
return -eval(node->lhs);
case ND_REM:
if (node->ty->is_unsigned)
return (uint64_t)eval(node->lhs) % eval(node->rhs);
return eval(node->lhs) % eval(node->rhs);
y = eval(node->rhs);
if (!y) error_tok(node->rhs->tok, "constexpr rem by zero");
if (node->ty->is_unsigned) {
return (uint64_t)eval(node->lhs) % y;
}
return eval(node->lhs) % y;
case ND_BINAND:
return eval(node->lhs) & eval(node->rhs);
case ND_BINOR:
@ -2044,8 +2079,9 @@ int64_t eval2(Node *node, char ***label) {
static int64_t eval_rval(Node *node, char ***label) {
switch (node->kind) {
case ND_VAR:
if (node->var->is_local)
if (node->var->is_local) {
error_tok(node->tok, "not a compile-time constant");
}
*label = &node->var->name;
return 0;
case ND_DEREF:
@ -2063,6 +2099,7 @@ bool is_const_expr(Node *node) {
case ND_SUB:
case ND_MUL:
case ND_DIV:
case ND_REM:
case ND_BINAND:
case ND_BINOR:
case ND_BINXOR:
@ -2884,8 +2921,9 @@ static Node *postfix(Token **rest, Token *tok) {
static Node *funcall(Token **rest, Token *tok, Node *fn) {
add_type(fn);
if (fn->ty->kind != TY_FUNC &&
(fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC))
(fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC)) {
error_tok(fn->tok, "not a function");
}
Type *ty = (fn->ty->kind == TY_FUNC) ? fn->ty : fn->ty->base;
Type *param_ty = ty->params;
Node head = {};
@ -2896,8 +2934,9 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
add_type(arg);
if (!param_ty && !ty->is_variadic) error_tok(tok, "too many arguments");
if (param_ty) {
if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION)
if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION) {
arg = new_cast(arg, param_ty);
}
param_ty = param_ty->next;
} else if (arg->ty->kind == TY_FLOAT) {
// If parameter type is omitted (e.g. in "..."), float
@ -2914,8 +2953,9 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) {
node->args = head.next;
// If a function returns a struct, it is caller's responsibility
// to allocate a space for the return value.
if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION)
if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) {
node->ret_buffer = new_lvar("", node->ty);
}
return node;
}
@ -3138,13 +3178,37 @@ static Node *primary(Token **rest, Token *tok) {
*rest = skip(tok, ')');
return node;
}
if (EQUAL(tok, "__builtin_popcount") || EQUAL(tok, "__builtin_popcountl") ||
if (EQUAL(tok, "__builtin_popcount")) {
Token *t = skip(tok->next, '(');
Node *node = assign(&t, t);
if (is_const_expr(node)) {
*rest = skip(t, ')');
return new_num(__builtin_popcount(eval(node)), t);
}
}
if (EQUAL(tok, "__builtin_popcountl") ||
EQUAL(tok, "__builtin_popcountll")) {
Token *t = skip(tok->next, '(');
Node *node = assign(&t, t);
if (is_const_expr(node)) {
*rest = skip(t, ')');
return new_num(popcnt(eval(node)), t);
return new_num(__builtin_popcountl(eval(node)), t);
}
}
if (EQUAL(tok, "__builtin_ffs")) {
Token *t = skip(tok->next, '(');
Node *node = assign(&t, t);
if (is_const_expr(node)) {
*rest = skip(t, ')');
return new_num(__builtin_ffs(eval(node)), t);
}
}
if (EQUAL(tok, "__builtin_ffsl") || EQUAL(tok, "__builtin_ffsll")) {
Token *t = skip(tok->next, '(');
Node *node = assign(&t, t);
if (is_const_expr(node)) {
*rest = skip(t, ')');
return new_num(__builtin_ffsl(eval(node)), t);
}
}
}
@ -3328,15 +3392,19 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
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->javadown = fn->javadown ?: current_javadown;
fn->is_root = !(fn->is_static && fn->is_inline);
if (consume_attribute(&tok, tok, "asm")) {
tok = skip(tok, '(');
@ -3352,11 +3420,13 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
// A buffer for a struct/union return value is passed
// as the hidden first parameter.
Type *rty = ty->return_ty;
if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16)
if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16) {
new_lvar("", pointer_to(rty));
}
fn->params = locals;
if (ty->is_variadic)
if (ty->is_variadic) {
fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136));
}
fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char));
tok = skip(tok, '{');
// [https://www.sigbus.info/n1570#6.4.2.2p1] "__func__" is
@ -3382,6 +3452,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);
var->javadown = current_javadown;
if (consume_attribute(&tok, tok, "asm")) {
tok = skip(tok, '(');
var->asmname = ConsumeStringLiteral(&tok, tok);
@ -3528,6 +3599,12 @@ Obj *parse(Token *tok) {
tok = static_assertion(tok);
continue;
}
if (tok->kind == TK_JAVADOWN) {
current_javadown = tok;
tok = tok->next;
} else {
current_javadown = NULL;
}
VarAttr attr = {};
tok = attribute_list(tok, &attr, thing_attributes);
Type *basety = declspec(&tok, tok, &attr);

View file

@ -26,11 +26,7 @@
typedef struct CondIncl CondIncl;
typedef struct Hideset Hideset;
typedef struct Macro Macro;
typedef struct MacroArg MacroArg;
typedef struct MacroParam MacroParam;
typedef Token *macro_handler_fn(Token *);
typedef enum {
STR_NONE,
@ -40,11 +36,6 @@ typedef enum {
STR_WIDE,
} StringKind;
struct MacroParam {
MacroParam *next;
char *name;
};
struct MacroArg {
MacroArg *next;
char *name;
@ -52,15 +43,6 @@ struct MacroArg {
Token *tok;
};
struct Macro {
char *name;
bool is_objlike; // Object-like or function-like
MacroParam *params;
char *va_args_name;
Token *body;
macro_handler_fn *handler;
};
// `#if` can be nested, so we use a stack to manage nested `#if`s.
struct CondIncl {
CondIncl *next;
@ -74,7 +56,8 @@ struct Hideset {
char *name;
};
static HashMap macros;
HashMap macros;
static CondIncl *cond_incl;
static HashMap pragma_once;
static int include_next_idx;
@ -338,21 +321,24 @@ static MacroParam *read_macro_params(Token **rest, Token *tok,
return head.next;
}
static void read_macro_definition(Token **rest, Token *tok) {
static Macro *read_macro_definition(Token **rest, Token *tok) {
Macro *m;
char *name;
if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier");
char *name = strndup(tok->loc, tok->len);
name = strndup(tok->loc, tok->len);
tok = tok->next;
if (!tok->has_space && EQUAL(tok, "(")) {
// Function-like macro
char *va_args_name = NULL;
MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
Macro *m = add_macro(name, false, copy_line(rest, tok));
m = add_macro(name, false, copy_line(rest, tok));
m->params = params;
m->va_args_name = va_args_name;
} else {
// Object-like macro
add_macro(name, true, copy_line(rest, tok));
m = add_macro(name, true, copy_line(rest, tok));
}
return m;
}
static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
@ -742,6 +728,12 @@ static Token *preprocess2(Token *tok) {
while (tok->kind != TK_EOF) {
// If it is a macro, expand it.
if (expand_macro(&tok, tok)) continue;
// make sure javadown is removed if it's for a macro definition
if (tok->kind == TK_JAVADOWN && is_hash(tok->next) &&
EQUAL(tok->next->next, "define")) {
read_macro_definition(&tok, tok->next->next->next)->javadown = tok;
continue;
}
// Pass through if it is not a "#".
if (!is_hash(tok)) {
tok->line_delta = tok->file->line_delta;
@ -936,6 +928,8 @@ __GNUC_PATCHLEVEL__\000\
0\000\
__NO_INLINE__\000\
16\000\
__GNUC_STDC_INLINE__\000\
1\000\
__BIGGEST_ALIGNMENT__\000\
16\000\
__C99_MACRO_WITH_VA_ARGS\000\
@ -1010,6 +1004,10 @@ __UINT32_MAX__\000\
0xffffffffu\000\
__INT64_MAX__\000\
0x7fffffffffffffffl\000\
__LONG_MAX__\000\
0x7fffffffffffffffl\000\
__LONG_LONG_MAX__\000\
0x7fffffffffffffffl\000\
__UINT64_MAX__\000\
0xfffffffffffffffful\000\
__SIZE_MAX__\000\

View file

@ -12,7 +12,8 @@ __attribute__((__nonnull__(1))) void cate2(char *);
__attribute__((__section__(".data.var"))) int var2;
__attribute__((__section__(".data.var"))) int ar2[4];
int main() {
__attribute__((__force_align_arg_pointer__, __no_caller_saved_registers__)) int
main() {
int2 a;
ASSERT(64, _Alignof(int2));
ASSERT(64, _Alignof(a));

View file

@ -1,3 +1,4 @@
#include "libc/macros.h"
#include "third_party/chibicc/test/test.h"
int main() {
@ -6,6 +7,11 @@ int main() {
int x[n];
sizeof(x);
}));
ASSERT(5, ({
int n = 5;
int x[n];
ARRAYLEN(x);
}));
ASSERT((5 + 1) * (8 * 2) * 4, ({
int m = 5, n = 8;
int x[m + 1][n * 2];

View file

@ -470,6 +470,7 @@ Token *tokenize(File *file) {
char *p = file->contents;
Token head = {};
Token *cur = &head;
struct Javadown *javadown;
at_bol = true;
has_space = false;
while (*p) {
@ -480,6 +481,22 @@ Token *tokenize(File *file) {
has_space = true;
continue;
}
// Javadoc-style markdown comments.
if (LOOKINGAT(p, "/**") && p[3] != '/' && p[3] != '*') {
char *q = strstr(p + 3, "*/");
if (!q) error_at(p, "unclosed javadown");
javadown = ParseJavadown(p + 3, q - p - 3 - 2);
if (javadown->isfileoverview) {
FreeJavadown(file->javadown);
file->javadown = javadown;
} else {
cur = cur->next = new_token(TK_JAVADOWN, p, q + 2);
cur->javadown = javadown;
}
p = q + 2;
has_space = true;
continue;
}
// Skip block comments.
if (LOOKINGAT(p, "/*")) {
char *q = strstr(p + 2, "*/");
@ -505,12 +522,13 @@ Token *tokenize(File *file) {
if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
char *q = p++;
for (;;) {
if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1]))
if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) {
p += 2;
else if (isalnum(*p) || *p == '.')
} else if (isalnum(*p) || *p == '.') {
p++;
else
} else {
break;
}
}
cur = cur->next = new_token(TK_PP_NUM, q, p);
continue;
@ -663,7 +681,30 @@ void remove_backslash_newline(char *p) {
// 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++;

View file

@ -4,19 +4,28 @@
/**
* Returns (by copy) a struct containing various summary statistics:
*
* arena: current total non-mmapped bytes allocated from system
* ordblks: the number of free chunks
* smblks: always zero.
* hblks: current number of mmapped regions
* hblkhd: total bytes held in mmapped regions
* usmblks: the maximum total allocated space. This will be greater
* than current total if trimming has occurred.
* fsmblks: always zero
* uordblks: current total allocated space (normal or mmapped)
* fordblks: total free space
* keepcost: the maximum number of bytes that could ideally be released
* back to system via malloc_trim. ("ideally" means that
* it ignores page restrictions etc.)
* - arena: current total non-mmapped bytes allocated from system
*
* - ordblks: the number of free chunks
*
* - smblks: always zero.
*
* - hblks: current number of mmapped regions
*
* - hblkhd: total bytes held in mmapped regions
*
* - usmblks: the maximum total allocated space. This will be greater
* than current total if trimming has occurred.
*
* - fsmblks: always zero
*
* - uordblks: current total allocated space (normal or mmapped)
*
* - fordblks: total free space
*
* - keepcost: the maximum number of bytes that could ideally be
* released back to system via malloc_trim. ("ideally" means that it
* ignores page restrictions etc.)
*
* Because these fields are ints, but internal bookkeeping may
* be kept as longs, the reported values may wrap around zero and

View file

@ -227,13 +227,13 @@ static int GlobPredicate(const void *a, const void *b) {
*
* For example:
*
* glob_t g = {.gl_offs = 2};
* glob("*.*", GLOB_DOOFFS, NULL, &g);
* glob("../.*", GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
* g.gl_pathv[0] = "ls";
* g.gl_pathv[1] = "-l";
* execvp("ls", &g.gl_pathv[0]);
* globfree(g);
* glob_t g = {.gl_offs = 2};
* glob("*.*", GLOB_DOOFFS, NULL, &g);
* glob("../.*", GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
* g.gl_pathv[0] = "ls";
* g.gl_pathv[1] = "-l";
* execvp("ls", &g.gl_pathv[0]);
* globfree(g);
*
* @param pat can have star wildcard see fnmatch()
* @param g will receive matching entries and needs globfree()

View file

@ -2387,10 +2387,10 @@ static reg_errcode_t tre_ast_to_tnfa(tre_ast_node_t *node,
/**
* Compiles regular expression, e.g.
*
* regex_t rx;
* EXPECT_EQ(REG_OK, regcomp(&rx, "^[A-Za-z\x7f-\uFFFF]{2}$", REG_EXTENDED));
* EXPECT_EQ(REG_OK, regexec(&rx, "→A", 0, NULL, 0));
* regfree(&rx);
* regex_t rx;
* EXPECT_EQ(REG_OK, regcomp(&rx, "^[A-Za-z]{2}$", REG_EXTENDED));
* EXPECT_EQ(REG_OK, regexec(&rx, "→A", 0, NULL, 0));
* regfree(&rx);
*
* @param preg points to state, and needs regfree() afterwards
* @param regex is utf-8 regular expression string

View file

@ -38,11 +38,11 @@
* even in the case of corrupted input.
*/
#define ZLIB_VERSION "1.2.11"
#define ZLIB_VERNUM 0x12b0
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 11
#define ZLIB_VERSION "1.2.11"
#define ZLIB_VERNUM 0x12b0
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 11
#define ZLIB_VER_SUBREVISION 0
/**
@ -81,25 +81,25 @@
* (particularly if the decompressor wants to decompress everything in a
* single step).
*/
#define Z_NO_FLUSH 0
#define Z_NO_FLUSH 0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH 2
#define Z_FULL_FLUSH 3
#define Z_FINISH 4
#define Z_BLOCK 5
#define Z_TREES 6
#define Z_SYNC_FLUSH 2
#define Z_FULL_FLUSH 3
#define Z_FINISH 4
#define Z_BLOCK 5
#define Z_TREES 6
/**
* Allowed flush values; see deflate() and inflate() below for details.
*/
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_NEED_DICT 2
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_NEED_DICT 2
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
#define Z_VERSION_ERROR (-6)
/**
@ -107,26 +107,26 @@
* values are errors, positive values are used for special but normal
* events.
*/
#define Z_NO_COMPRESSION 0
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_NO_COMPRESSION 0
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_DEFAULT_COMPRESSION (-1)
/**
* Compression levels.
*/
#define Z_FILTERED 1
#define Z_HUFFMAN_ONLY 2
#define Z_RLE 3
#define Z_FIXED 4
#define Z_FILTERED 1
#define Z_HUFFMAN_ONLY 2
#define Z_RLE 3
#define Z_FIXED 4
#define Z_DEFAULT_STRATEGY 0
/**
* Compression strategy; see deflateInit2() below for details
*/
#define Z_BINARY 0
#define Z_TEXT 1
#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
#define Z_BINARY 0
#define Z_TEXT 1
#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN 2
/**
@ -1139,7 +1139,7 @@ int inflateBack(z_streamp strm, in_func in, void *in_desc, out_func out,
*/
int inflateBackEnd(z_streamp strm);
/**
/*
* Return flags indicating compile-time options.
*
* Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
@ -1160,10 +1160,13 @@ int inflateBackEnd(z_streamp strm);
* 14,15: 0 (reserved)
*
* Library content (indicates missing functionality):
*
* 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
* deflate code when not needed)
* 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
* and decode gzip streams (to avoid linking crc code)
* deflate code when not needed)
*
* 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't
* detect and decode gzip streams (to avoid linking crc code)
*
* 18-19: 0 (reserved)
*
* Operation variations (changes in library functionality):
@ -1685,12 +1688,11 @@ uLong adler32_combine(uLong adler1, uLong adler2, int64_t len2);
*
* Usage example:
*
* uLong crc = crc32(0L, Z_NULL, 0);
*
* while (read_buffer(buffer, length) != EOF) {
* crc = crc32(crc, buffer, length);
* }
* if (crc != original_crc) error();
* uLong crc = crc32(0L, Z_NULL, 0);
* while (read_buffer(buffer, length) != EOF) {
* crc = crc32(crc, buffer, length);
* }
* if (crc != original_crc) error();
*/
uLong crc32(uLong crc, const Bytef *buf, uInt len);