Further refine documentation

This commit is contained in:
Justine Tunney 2020-12-27 17:05:03 -08:00
parent 1bc3a25505
commit 548dcb9f08
27 changed files with 389 additions and 1478 deletions

View file

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

View file

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

View file

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

View file

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

106
third_party/chibicc/file.c vendored Normal file
View file

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

13
third_party/chibicc/file.h vendored Normal file
View file

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

View file

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

View file

@ -1,3 +1,4 @@
asm(".ident\t\"hello\"");
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi

View file

@ -1,7 +1,30 @@
#include "libc/macros.h"
#include "third_party/chibicc/test/test.h"
int index1d(int xn, int p[xn], int x) {
return p[x];
}
int index2d(int yn, int xn, int (*p)[yn][xn], int y, int x) {
return (*p)[y][x];
}
int main() {
ASSERT(30, ({
int a[5] = {00, 10, 20, 30, 40, 50};
index1d(5, a, 3);
}));
/* ASSERT(210, ({ */
/* int a[3][3] = { */
/* {000, 010, 020}, */
/* {100, 110, 120}, */
/* {200, 210, 220}, */
/* }; */
/* index2d(3, 3, a, 2, 1); */
/* })); */
ASSERT(20, ({
int n = 5;
int x[n];

View file

@ -1,4 +1,5 @@
#include "third_party/chibicc/chibicc.h"
#include "third_party/chibicc/file.h"
#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, sizeof(OP) - 1))
@ -610,40 +611,6 @@ Token *tokenize(File *file) {
return head.next;
}
// Returns the contents of a given file.
char *read_file(char *path) {
FILE *fp;
if (strcmp(path, "-") == 0) {
// By convention, read from stdin if a given filename is "-".
fp = stdin;
} else {
fp = fopen(path, "r");
if (!fp) return NULL;
}
int buflen = 4096;
int nread = 0;
char *buf = calloc(1, buflen);
// Read the entire file.
for (;;) {
int end = buflen - 2; // extra 2 bytes for the trailing "\n\0"
int n = fread(buf + nread, 1, end - nread, fp);
if (n == 0) break;
nread += n;
if (nread == end) {
buflen *= 2;
buf = realloc(buf, buflen);
}
}
if (fp != stdin) fclose(fp);
// Make sure that the last logical line is properly terminated with '\n'.
if (nread > 0 && buf[nread - 1] == '\\')
buf[nread - 1] = '\n';
else if (nread == 0 || buf[nread - 1] != '\n')
buf[nread++] = '\n';
buf[nread] = '\0';
return buf;
}
File **get_input_files(void) {
return input_files;
}
@ -657,68 +624,6 @@ File *new_file(char *name, int file_no, char *contents) {
return file;
}
// Replaces \r or \r\n with \n.
void canonicalize_newline(char *p) {
int i = 0, j = 0;
while (p[i]) {
if (p[i] == '\r' && p[i + 1] == '\n') {
i += 2;
p[j++] = '\n';
} else if (p[i] == '\r') {
i++;
p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
p[j] = '\0';
}
// Removes backslashes followed by a newline.
void remove_backslash_newline(char *p) {
int i = 0, j = 0;
// We want to keep the number of newline characters so that
// the logical line number matches the physical one.
// This counter maintain the number of newlines we have removed.
int n = 0;
bool instring = false;
while (p[i]) {
if (instring) {
if (p[i] == '"' && p[i - 1] != '\\') {
instring = false;
}
} else {
if (p[i] == '"') {
instring = true;
} else if (p[i] == '/' && p[i + 1] == '*') {
p[j++] = p[i++];
p[j++] = p[i++];
while (p[i]) {
if (p[i] == '*' && p[i + 1] == '/') {
p[j++] = p[i++];
p[j++] = p[i++];
break;
} else {
p[j++] = p[i++];
}
}
continue;
}
}
if (p[i] == '\\' && p[i + 1] == '\n') {
i += 2;
n++;
} else if (p[i] == '\n') {
p[j++] = p[i++];
for (; n > 0; n--) p[j++] = '\n';
} else {
p[j++] = p[i++];
}
}
for (; n > 0; n--) p[j++] = '\n';
p[j] = '\0';
}
static uint32_t read_universal_char(char *p, int len) {
uint32_t c = 0;
for (int i = 0; i < len; i++) {
@ -761,11 +666,7 @@ static void convert_universal_chars(char *p) {
Token *tokenize_file(char *path) {
char *p = read_file(path);
if (!p) return NULL;
// UTF-8 texts may start with a 3-byte "BOM" marker sequence.
// If exists, just skip them because they are useless bytes.
// (It is actually not recommended to add BOM markers to UTF-8
// texts, but it's not uncommon particularly on Windows.)
if (!memcmp(p, "\xef\xbb\xbf", 3)) p += 3;
p = skip_bom(p);
canonicalize_newline(p);
remove_backslash_newline(p);
convert_universal_chars(p);