static uint32_t readutf(char c, char **buf, size_t *buflen, size_t *sz) { size_t i, len; uint32_t val; if ((c & 0x80) == 0) len = 1; else if ((c & 0xe0) == 0xc0) len = 2; else if ((c & 0xf0) == 0xe0) len = 3; else if ((c & 0xf8) == 0xf0) len = 4; else lfatal(curloc, "Invalid utf8 encoded character constant"); val = c & ((1 << (8 - len)) - 1); append(buf, buflen, sz, c); for (i = 1; i < len; i++) { c = next(); if ((c & 0xc0) != 0x80) lfatal(curloc, "Invalid utf8 codepoint in character literal"); val = (val << 6) | (c & 0x3f); append(buf, buflen, sz, c); } return val; }
static Tok *charlit(void) { Tok *t; int c; uint32_t val; size_t len, sz; char *buf; assert(next() == '\''); buf = NULL; len = 0; sz = 0; val = 0; c = next(); if (c == End) lfatal(curloc, "Unexpected EOF within char lit"); else if (c == '\n') lfatal(curloc, "Newlines not allowed in char lit"); else if (c == '\\') val = decode(&buf, &len, &sz); else val = readutf(c, &buf, &len, &sz); append(&buf, &len, &sz, '\0'); if (next() != '\'') lfatal(curloc, "Character constant with multiple characters"); t = mktok(Tchrlit); t->chrval = val; t->id = buf; return t; }
/* * decodes an escape code. These are * shared between strings and characters. * Unknown escape codes are ignored. */ static int decode(char **buf, size_t *len, size_t *sz) { char c, c1, c2; int32_t v; c = next(); /* we've already seen the '\' */ switch (c) { case 'u': v = unichar(); appendc(buf, len, sz, v); return v; case 'x': /* arbitrary hex */ c1 = next(); if (!isxdigit(c1)) lfatal(curloc, "expected hex digit, got %c", c1); c2 = next(); if (!isxdigit(c2)) lfatal(curloc, "expected hex digit, got %c", c1); v = 16*hexval(c1) + hexval(c2); break; case 'n': v = '\n'; break; case 'r': v = '\r'; break; case 't': v = '\t'; break; case 'b': v = '\b'; break; case '"': v = '\"'; break; case '\'': v = '\''; break; case 'v': v = '\v'; break; case '\\': v = '\\'; break; case '0': v = '\0'; break; default: lfatal(curloc, "unknown escape code \\%c", c); } append(buf, len, sz, v); return v; }
static Tok *strlit(void) { Tok *t; int c; size_t len, sz; char *buf; assert(next() == '"'); buf = NULL; len = 0; sz = 0; while (1) { c = next(); /* we don't unescape here, but on output */ if (c == '"') break; else if (c == End) lfatal(curloc, "Unexpected EOF within string"); else if (c == '\n') lfatal(curloc, "Newlines not allowed in strings"); else if (c == '\\') decode(&buf, &len, &sz); else append(&buf, &len, &sz, c); }; t = mktok(Tstrlit); t->strval.len = len; /* null terminator should not count towards length */ append(&buf, &len, &sz, '\0'); t->strval.buf = buf; t->id = buf; return t; }
// ###################################################################### void env_stdio_write_gray(const struct env_image* iimage, const char* outstem, const char* name, int c) { if (!env_img_initialized(iimage)) return; // if outstem is the empty string, then the user wanted us to // suppress output: if (outstem[0] == '\0') return; char fname[256]; snprintf(fname, sizeof(fname), "%s-%s%06d.pnm", outstem, name, c); FILE* const f = fopen(fname, "wb"); if (f == 0) lfatal("%s: couldn't open PNM file for writing (errno=%d, %s)", fname, errno, strerror(errno)); //REV: so they are P5 (binary, greyscale), dim * dim images, with max value 255. if (fprintf(f, "P5\n%d %d\n255\n", (int) iimage->dims.w, (int) iimage->dims.h) < 0) lfatal("%s: fprintf() failed (errno=%d, %s)", fname, errno, strerror(errno)); const intg32* const src = env_img_pixels(iimage); const env_size_t sz = env_img_size(iimage); byte* bimage = (byte*) env_allocate(sz * sizeof(byte)); for (env_size_t i = 0; i < sz; ++i) { // the caller is supposed to have already ensured that // the intg32 image has been downsampled to a [0,255] // range, so let's verify that: ENV_ASSERT(src[i] >= 0 && src[i] <= 255); bimage[i] = (byte) src[i]; } //REV: they aren't using any newlines! if (fwrite(bimage, 1, sz, f) != sz) { env_deallocate(bimage); lfatal("%s: fwrite() failed (errno=%d, %s)", fname, errno, strerror(errno)); } env_deallocate(bimage); if (fclose(f) != 0) lfatal("%s: fclose() failed (errno=%d, %s)", fname, errno, strerror(errno)); }
static void eatcomment(void) { int depth; int startln; int c; depth = 0; startln = curloc.line; while (1) { c = next(); switch (c) { /* enter level of nesting */ case '/': if (match('*')) depth++; break; /* leave level of nesting */ case '*': if (match('/')) depth--; break; /* have to keep line numbers synced */ case '\n': curloc.line++; break; case End: lfatal(curloc, "File ended within comment starting at line %d", startln); break; } if (depth == 0) break; } }
static Tok *toknext() { Tok *t; int c; eatspace(); c = peek(); if (c == End) { t = mktok(0); } else if (c == '\n') { curloc.line++; next(); t = mktok(Tendln); } else if (isalpha(c) || c == '_' || c == '$') { t = kwident(); } else if (c == '"') { t = strlit(); } else if (c == '\'') { t = charlit(); } else if (isdigit(c)) { t = numlit(); } else if (c == '@') { t = typaram(); } else { t = oper(); } if (!t || t->type == Terror) lfatal(curloc, "Unable to parse token starting with %c", c); return t; }
/* \u{abc} */ static int32_t unichar(void) { uint32_t v; int c; /* we've already seen the \u */ if (next() != '{') lfatal(curloc, "\\u escape sequence without initial '{'"); v = 0; while (ishexval(peek())) { c = next(); v = 16*v + hexval(c); if (v > 0x10FFFF) lfatal(curloc, "invalid codepoint for \\u escape sequence"); } if (next() != '}') lfatal(curloc, "\\u escape sequence without ending '}'"); return v; }
/* * Converts a character to its hex value. */ static int hexval(char c) { if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= '0' && c <= '9') return c - '0'; lfatal(curloc, "passed non-hex value '%c' to where hex was expected", c); return -1; }
static void fixtypemappings(Stab *st) { size_t i; Type *t, *old; /* * merge duplicate definitions. * This allows us to compare named types by id, instead * of doing a deep walk through the type. This ability is * depended on when we do type inference. */ for (i = 0; i < ntypefixdest; i++) { t = htget(tidmap, itop(typefixid[i])); if (!t) die("Unable to find type for id %zd\n", typefixid[i]); *typefixdest[i] = t; } for (i = 0; i < ntypefixdest; i++) { old = *typefixdest[i]; if (old->type == Tyname || old->type == Tygeneric) { t = htget(tydedup, old); if (!t) { t = old; htput(tydedup, old, old); } *typefixdest[i] = t; } } /* check for duplicate type definitions */ for (i = 0; i < ntypefixdest; i++) { t = htget(tidmap, itop(typefixid[i])); if ((t->type != Tyname && t->type != Tygeneric) || t->issynth) continue; old = htget(tydedup, t); if (old && !tyeq(t, old) && !isspecialization(t, old)) lfatal(t->loc, "Duplicate definition of type %s on %s:%d", tystr(old), file->file.files[old->loc.file], old->loc.line); } for (i = 0; i < ntypefixdest; i++) lfree(&typefixdest, &ntypefixdest); lfree(&typefixid, &ntypefixid); }
/* * Appends a unicode codepoint 'c' to a growable buffer 'buf', * resizing if needed. */ static void appendc(char **buf, size_t *len, size_t *sz, uint32_t c) { size_t i, charlen; char charbuf[5] = {0}; if (c < 0x80) charlen = 1; else if (c < 0x800) charlen = 2; else if (c < 0x10000) charlen = 3; else if (c < 0x200000) charlen = 4; else lfatal(curloc, "invalid utf character '\\u{%x}'", c); encode(charbuf, charlen, c); for (i = 0; i < charlen; i++) append(buf, len, sz, charbuf[i]); }
static Tok *number(int base) { Tok *t; int start; int c; int isfloat; int unsignedval; /* because we allow '_' in numbers, and strtod/stroull don't, we * need a buffer that holds the number without '_'. */ char buf[2048]; size_t nbuf; t = NULL; isfloat = 0; start = fidx; nbuf = 0; for (c = peek(); isxdigit(c) || c == '.' || c == '_'; c = peek()) { next(); if (c == '_') continue; if (c == '.') isfloat = 1; else if (hexval(c) < 0 || hexval(c) > base) lfatal(curloc, "Integer digit '%c' outside of base %d", c, base); if (nbuf >= sizeof buf - 1) { buf[nbuf-1] = '\0'; lfatal(curloc, "number %s... too long to represent", buf); } buf[nbuf++] = c; } buf[nbuf] = '\0'; /* we only support base 10 floats */ if (isfloat && base == 10) { t = mktok(Tfloatlit); t->id = strdupn(&fbuf[start], fidx - start); t->fltval = strtod(buf, NULL); } else { t = mktok(Tintlit); t->id = strdupn(&fbuf[start], fidx - start); t->intval = strtoull(buf, NULL, base); /* check suffixes: * u -> unsigned * l -> 64 bit * i -> 32 bit * w -> 16 bit * b -> 8 bit */ unsignedval = 0; nextsuffix: switch (peek()) { case 'u': if (unsignedval == 1) lfatal(curloc, "Duplicate 'u' integer specifier"); next(); unsignedval = 1; goto nextsuffix; case 'l': next(); if (unsignedval) t->inttype = Tyuint64; else t->inttype = Tyint64; break; case 'i': next(); if (unsignedval) t->inttype = Tyuint32; else t->inttype = Tyint32; break; case 's': next(); if (unsignedval) t->inttype = Tyuint16; else t->inttype = Tyint16; break; case 'b': next(); if (unsignedval) t->inttype = Tyuint8; else t->inttype = Tyint8; break; default: if (unsignedval) lfatal(curloc, "Unrecognized character int type specifier after 'u'"); break; } } return t; }
static Tok *oper(void) { int tt; char c; c = next(); switch (c) { case '{': tt = Tobrace; break; case '}': tt = Tcbrace; break; case '(': tt = Toparen; break; case ')': tt = Tcparen; break; case '[': tt = Tosqbrac; break; case ']': tt = Tcsqbrac; break; case ',': tt = Tcomma; break; case '`': tt = Ttick; break; case '#': tt = Tderef; break; case ':': if (match(':')) tt = Twith; else tt = Tcolon; break; case '~': tt = Tbnot; break; case ';': if (match(';')) tt = Tendblk; else tt = Tendln; break; case '.': if (match('.')) { if (match('.')) { tt = Tellipsis; } else { unget(); tt = Tdot; } } else { tt = Tdot; } break; case '+': if (match('=')) tt = Taddeq; else if (match('+')) tt = Tinc; else tt = Tplus; break; case '-': if (match('=')) tt = Tsubeq; else if (match('-')) tt = Tdec; else if (match('>')) tt = Tret; else tt = Tminus; break; case '*': if (match('=')) tt = Tmuleq; else tt = Tmul; break; case '/': if (match('=')) tt = Tdiveq; else tt = Tdiv; break; case '%': if (match('=')) tt = Tmodeq; else tt = Tmod; break; case '=': if (match('=')) tt = Teq; else tt = Tasn; break; case '|': if (match('=')) tt = Tboreq; else if (match('|')) tt = Tlor; else tt = Tbor; break; case '&': if (match('=')) tt = Tbandeq; else if (match('&')) tt = Tland; else tt = Tband; break; case '^': if (match('=')) tt = Tbxoreq; else tt = Tbxor; break; case '<': if (match('=')) { tt = Tle; } else if (match('<')) { if (match('=')) tt = Tbsleq; else tt = Tbsl; } else { tt = Tlt; } break; case '>': if (match('=')) { tt = Tge; } else if (match('>')) { if (match('=')) tt = Tbsreq; else tt = Tbsr; } else { tt = Tgt; } break; case '!': if (match('=')) tt = Tne; else tt = Tlnot; break; default: tt = Terror; lfatal(curloc, "Junk character %c", c); break; } return mktok(tt); }
// ###################################################################### struct env_rgb_pixel* env_stdio_parse_rgb(const char* fname, struct env_dims* outdims) { FILE* f = fopen(fname, "rb"); if (f == 0) lfatal("Couldn't open file '%s' for reading.", fname); int c = getc(f); if (c != 'P') lfatal("Missing magic number in pnm file '%s'" "(got '%c' [%d], expected '%c' [%d]).", fname, c, c, 'P', 'P'); int mode = -1; int ret = fscanf(f, "%d", &mode); if (ret > 0 && mode != 6) lfatal("Wrong pnm mode (got 'P%d', expected 'P6')", //REV: so they expect P6, i.e. binary rgb! mode); while (1) { const int c = getc(f); //REV: they're getting one char at a time...removing all spaces... if (!isspace(c)) { ungetc(c, f); break; } } // copy and concatenate optional comment line(s) starting with '#' // into comments string //REV: they're removing comments and such...we won't need to worry about this... while (1) { const int c = getc(f); if (c != '#') { ungetc(c, f); break; } else { while (getc(f) != '\n') { /* empty loop */ } } } int w = -1; int h = -1; int maxGrey = -1; ret = fscanf(f, "%d %d %d", &w, &h, &maxGrey); //REV: they get the dimensions... and the max grey value (wth?) ENV_ASSERT(ret > 0); ENV_ASSERT(w > 0); ENV_ASSERT(h > 0); ENV_ASSERT(maxGrey > 0); // read one more character of whitespace from the stream after maxGrey c = getc(f); if ( !isspace(c) ) lfatal("Missing whitespace after maxGrey in pbm file '%s'.", fname); struct env_rgb_pixel* result = (struct env_rgb_pixel*) //REV: note RGB pixel is byte[3]. env_allocate(w * h * sizeof(struct env_rgb_pixel)); if (fread((char*) result, 3, w*h, f) != ((env_size_t)(w*h))) lfatal("%s: fread() failed", fname); outdims->w = w; outdims->h = h; return result; }