#include "c.h" #include #include #define MAXTOKEN 32 enum { BLANK=01, NEWLINE=02, LETTER=04, DIGIT=010, HEX=020, OTHER=040 }; static unsigned char map[256] = { /* 000 nul */ 0, /* 001 soh */ 0, /* 002 stx */ 0, /* 003 etx */ 0, /* 004 eot */ 0, /* 005 enq */ 0, /* 006 ack */ 0, /* 007 bel */ 0, /* 010 bs */ 0, /* 011 ht */ BLANK, /* 012 nl */ NEWLINE, /* 013 vt */ BLANK, /* 014 ff */ BLANK, /* 015 cr */ 0, /* 016 so */ 0, /* 017 si */ 0, /* 020 dle */ 0, /* 021 dc1 */ 0, /* 022 dc2 */ 0, /* 023 dc3 */ 0, /* 024 dc4 */ 0, /* 025 nak */ 0, /* 026 syn */ 0, /* 027 etb */ 0, /* 030 can */ 0, /* 031 em */ 0, /* 032 sub */ 0, /* 033 esc */ 0, /* 034 fs */ 0, /* 035 gs */ 0, /* 036 rs */ 0, /* 037 us */ 0, /* 040 sp */ BLANK, /* 041 ! */ OTHER, /* 042 " */ OTHER, /* 043 # */ OTHER, /* 044 $ */ 0, /* 045 % */ OTHER, /* 046 & */ OTHER, /* 047 ' */ OTHER, /* 050 ( */ OTHER, /* 051 ) */ OTHER, /* 052 * */ OTHER, /* 053 + */ OTHER, /* 054 , */ OTHER, /* 055 - */ OTHER, /* 056 . */ OTHER, /* 057 / */ OTHER, /* 060 0 */ DIGIT, /* 061 1 */ DIGIT, /* 062 2 */ DIGIT, /* 063 3 */ DIGIT, /* 064 4 */ DIGIT, /* 065 5 */ DIGIT, /* 066 6 */ DIGIT, /* 067 7 */ DIGIT, /* 070 8 */ DIGIT, /* 071 9 */ DIGIT, /* 072 : */ OTHER, /* 073 ; */ OTHER, /* 074 < */ OTHER, /* 075 = */ OTHER, /* 076 > */ OTHER, /* 077 ? */ OTHER, /* 100 @ */ 0, /* 101 A */ LETTER|HEX, /* 102 B */ LETTER|HEX, /* 103 C */ LETTER|HEX, /* 104 D */ LETTER|HEX, /* 105 E */ LETTER|HEX, /* 106 F */ LETTER|HEX, /* 107 G */ LETTER, /* 110 H */ LETTER, /* 111 I */ LETTER, /* 112 J */ LETTER, /* 113 K */ LETTER, /* 114 L */ LETTER, /* 115 M */ LETTER, /* 116 N */ LETTER, /* 117 O */ LETTER, /* 120 P */ LETTER, /* 121 Q */ LETTER, /* 122 R */ LETTER, /* 123 S */ LETTER, /* 124 T */ LETTER, /* 125 U */ LETTER, /* 126 V */ LETTER, /* 127 W */ LETTER, /* 130 X */ LETTER, /* 131 Y */ LETTER, /* 132 Z */ LETTER, /* 133 [ */ OTHER, /* 134 \ */ OTHER, /* 135 ] */ OTHER, /* 136 ^ */ OTHER, /* 137 _ */ LETTER, /* 140 ` */ 0, /* 141 a */ LETTER|HEX, /* 142 b */ LETTER|HEX, /* 143 c */ LETTER|HEX, /* 144 d */ LETTER|HEX, /* 145 e */ LETTER|HEX, /* 146 f */ LETTER|HEX, /* 147 g */ LETTER, /* 150 h */ LETTER, /* 151 i */ LETTER, /* 152 j */ LETTER, /* 153 k */ LETTER, /* 154 l */ LETTER, /* 155 m */ LETTER, /* 156 n */ LETTER, /* 157 o */ LETTER, /* 160 p */ LETTER, /* 161 q */ LETTER, /* 162 r */ LETTER, /* 163 s */ LETTER, /* 164 t */ LETTER, /* 165 u */ LETTER, /* 166 v */ LETTER, /* 167 w */ LETTER, /* 170 x */ LETTER, /* 171 y */ LETTER, /* 172 z */ LETTER, /* 173 { */ OTHER, /* 174 | */ OTHER, /* 175 } */ OTHER, /* 176 ~ */ OTHER, }; static struct symbol tval; static char cbuf[BUFSIZE+1]; static unsigned int wcbuf[BUFSIZE+1]; Coordinate src; /* current source coordinate */ int t; char *token; /* current token */ Symbol tsym; /* symbol table entry for current token */ static void *cput(int c, void *cl); static void *wcput(int c, void *cl); static void *scon(int q, void *put(int c, void *cl), void *cl); static int backslash(int q); static Symbol fcon(void); static Symbol icon(unsigned long, int, int); static void ppnumber(char *); int gettok(void) { for (;;) { register unsigned char *rcp = cp; while (map[*rcp]&BLANK) rcp++; if (limit - rcp < MAXTOKEN) { cp = rcp; fillbuf(); rcp = cp; } src.file = file; src.x = (char *)rcp - line; src.y = lineno; cp = rcp + 1; switch (*rcp++) { case '/': if (*rcp == '*') { int c = 0; for (rcp++; *rcp != '/' || c != '*'; ) if (map[*rcp]&NEWLINE) { if (rcp < limit) c = *rcp; cp = rcp + 1; nextline(); rcp = cp; if (rcp == limit) break; } else c = *rcp++; if (rcp < limit) rcp++; else error("unclosed comment\n"); cp = rcp; continue; } return '/'; case '<': if (*rcp == '=') return cp++, LEQ; if (*rcp == '<') return cp++, LSHIFT; return '<'; case '>': if (*rcp == '=') return cp++, GEQ; if (*rcp == '>') return cp++, RSHIFT; return '>'; case '-': if (*rcp == '>') return cp++, DEREF; if (*rcp == '-') return cp++, DECR; return '-'; case '=': return *rcp == '=' ? cp++, EQL : '='; case '!': return *rcp == '=' ? cp++, NEQ : '!'; case '|': return *rcp == '|' ? cp++, OROR : '|'; case '&': return *rcp == '&' ? cp++, ANDAND : '&'; case '+': return *rcp == '+' ? cp++, INCR : '+'; case ';': case ',': case ':': case '*': case '~': case '%': case '^': case '?': case '[': case ']': case '{': case '}': case '(': case ')': return rcp[-1]; case '\n': case '\v': case '\r': case '\f': nextline(); if (cp == limit) { tsym = NULL; return EOI; } continue; case 'i': if (rcp[0] == 'f' && !(map[rcp[1]]&(DIGIT|LETTER))) { cp = rcp + 1; return IF; } if (rcp[0] == 'n' && rcp[1] == 't' && !(map[rcp[2]]&(DIGIT|LETTER))) { cp = rcp + 2; tsym = inttype->u.sym; return INT; } goto id; case 'h': case 'j': case 'k': case 'm': case 'n': case 'o': case 'p': case 'q': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': id: if (limit - rcp < MAXLINE) { cp = rcp - 1; fillbuf(); rcp = ++cp; } assert(cp == rcp); token = (char *)rcp - 1; while (map[*rcp]&(DIGIT|LETTER)) rcp++; token = stringn(token, (char *)rcp - token); tsym = lookup(token, identifiers); cp = rcp; return ID; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { unsigned long n = 0; if (limit - rcp < MAXLINE) { cp = rcp - 1; fillbuf(); rcp = ++cp; } assert(cp == rcp); token = (char *)rcp - 1; if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) { int d, overflow = 0; while (*++rcp) { if (map[*rcp]&DIGIT) d = *rcp - '0'; else if (*rcp >= 'a' && *rcp <= 'f') d = *rcp - 'a' + 10; else if (*rcp >= 'A' && *rcp <= 'F') d = *rcp - 'A' + 10; else break; if (n&~(~0UL >> 4)) overflow = 1; else n = (n<<4) + d; } if ((char *)rcp - token <= 2) error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token); cp = rcp; tsym = icon(n, overflow, 16); } else if (*token == '0') { int err = 0, overflow = 0; for ( ; map[*rcp]&DIGIT; rcp++) { if (*rcp == '8' || *rcp == '9') err = 1; if (n&~(~0UL >> 3)) overflow = 1; else n = (n<<3) + (*rcp - '0'); } if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { cp = rcp; tsym = fcon(); return FCON; } cp = rcp; tsym = icon(n, overflow, 8); if (err) error("invalid octal constant `%S'\n", token, (char*)cp-token); } else { int overflow = 0; for (n = *token - '0'; map[*rcp]&DIGIT; ) { int d = *rcp++ - '0'; if (n > (ULONG_MAX - d)/10) overflow = 1; else n = 10*n + d; } if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { cp = rcp; tsym = fcon(); return FCON; } cp = rcp; tsym = icon(n, overflow, 10); } return ICON; } case '.': if (rcp[0] == '.' && rcp[1] == '.') { cp += 2; return ELLIPSIS; } if ((map[*rcp]&DIGIT) == 0) return '.'; if (limit - rcp < MAXLINE) { cp = rcp - 1; fillbuf(); rcp = ++cp; } assert(cp == rcp); cp = rcp - 1; token = (char *)cp; tsym = fcon(); return FCON; case 'L': if (*rcp == '\'') { unsigned int *s = scon(*cp, wcput, wcbuf); if (s - wcbuf > 2) warning("excess characters in wide-character literal ignored\n"); tval.type = widechar; tval.u.c.v.u = wcbuf[0]; tsym = &tval; return ICON; } else if (*rcp == '"') { unsigned int *s = scon(*cp, wcput, wcbuf); tval.type = array(widechar, s - wcbuf, 0); tval.u.c.v.p = wcbuf; tsym = &tval; return SCON; } else goto id; case '\'': { char *s = scon(*--cp, cput, cbuf); if (s - cbuf > 2) warning("excess characters in multibyte character literal ignored\n"); tval.type = inttype; if (chartype->op == INT) tval.u.c.v.i = extend(cbuf[0], chartype); else tval.u.c.v.i = cbuf[0]&0xFF; tsym = &tval; return ICON; } case '"': { char *s = scon(*--cp, cput, cbuf); tval.type = array(chartype, s - cbuf, 0); tval.u.c.v.p = cbuf; tsym = &tval; return SCON; } case 'a': if (rcp[0] == 'u' && rcp[1] == 't' && rcp[2] == 'o' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return AUTO; } goto id; case 'b': if (rcp[0] == 'r' && rcp[1] == 'e' && rcp[2] == 'a' && rcp[3] == 'k' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; return BREAK; } goto id; case 'c': if (rcp[0] == 'a' && rcp[1] == 's' && rcp[2] == 'e' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return CASE; } if (rcp[0] == 'h' && rcp[1] == 'a' && rcp[2] == 'r' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; tsym = chartype->u.sym; return CHAR; } if (rcp[0] == 'o' && rcp[1] == 'n' && rcp[2] == 's' && rcp[3] == 't' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; return CONST; } if (rcp[0] == 'o' && rcp[1] == 'n' && rcp[2] == 't' && rcp[3] == 'i' && rcp[4] == 'n' && rcp[5] == 'u' && rcp[6] == 'e' && !(map[rcp[7]]&(DIGIT|LETTER))) { cp = rcp + 7; return CONTINUE; } goto id; case 'd': if (rcp[0] == 'e' && rcp[1] == 'f' && rcp[2] == 'a' && rcp[3] == 'u' && rcp[4] == 'l' && rcp[5] == 't' && !(map[rcp[6]]&(DIGIT|LETTER))) { cp = rcp + 6; return DEFAULT; } if (rcp[0] == 'o' && rcp[1] == 'u' && rcp[2] == 'b' && rcp[3] == 'l' && rcp[4] == 'e' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; tsym = doubletype->u.sym; return DOUBLE; } if (rcp[0] == 'o' && !(map[rcp[1]]&(DIGIT|LETTER))) { cp = rcp + 1; return DO; } goto id; case 'e': if (rcp[0] == 'l' && rcp[1] == 's' && rcp[2] == 'e' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return ELSE; } if (rcp[0] == 'n' && rcp[1] == 'u' && rcp[2] == 'm' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return ENUM; } if (rcp[0] == 'x' && rcp[1] == 't' && rcp[2] == 'e' && rcp[3] == 'r' && rcp[4] == 'n' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return EXTERN; } goto id; case 'f': if (rcp[0] == 'l' && rcp[1] == 'o' && rcp[2] == 'a' && rcp[3] == 't' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; tsym = floattype->u.sym; return FLOAT; } if (rcp[0] == 'o' && rcp[1] == 'r' && !(map[rcp[2]]&(DIGIT|LETTER))) { cp = rcp + 2; return FOR; } goto id; case 'g': if (rcp[0] == 'o' && rcp[1] == 't' && rcp[2] == 'o' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return GOTO; } goto id; case 'l': if (rcp[0] == 'o' && rcp[1] == 'n' && rcp[2] == 'g' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; return LONG; } goto id; case 'r': if (rcp[0] == 'e' && rcp[1] == 'g' && rcp[2] == 'i' && rcp[3] == 's' && rcp[4] == 't' && rcp[5] == 'e' && rcp[6] == 'r' && !(map[rcp[7]]&(DIGIT|LETTER))) { cp = rcp + 7; return REGISTER; } if (rcp[0] == 'e' && rcp[1] == 't' && rcp[2] == 'u' && rcp[3] == 'r' && rcp[4] == 'n' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return RETURN; } goto id; case 's': if (rcp[0] == 'h' && rcp[1] == 'o' && rcp[2] == 'r' && rcp[3] == 't' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; return SHORT; } if (rcp[0] == 'i' && rcp[1] == 'g' && rcp[2] == 'n' && rcp[3] == 'e' && rcp[4] == 'd' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return SIGNED; } if (rcp[0] == 'i' && rcp[1] == 'z' && rcp[2] == 'e' && rcp[3] == 'o' && rcp[4] == 'f' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return SIZEOF; } if (rcp[0] == 't' && rcp[1] == 'a' && rcp[2] == 't' && rcp[3] == 'i' && rcp[4] == 'c' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return STATIC; } if (rcp[0] == 't' && rcp[1] == 'r' && rcp[2] == 'u' && rcp[3] == 'c' && rcp[4] == 't' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return STRUCT; } if (rcp[0] == 'w' && rcp[1] == 'i' && rcp[2] == 't' && rcp[3] == 'c' && rcp[4] == 'h' && !(map[rcp[5]]&(DIGIT|LETTER))) { cp = rcp + 5; return SWITCH; } goto id; case 't': if (rcp[0] == 'y' && rcp[1] == 'p' && rcp[2] == 'e' && rcp[3] == 'd' && rcp[4] == 'e' && rcp[5] == 'f' && !(map[rcp[6]]&(DIGIT|LETTER))) { cp = rcp + 6; return TYPEDEF; } goto id; case 'u': if (rcp[0] == 'n' && rcp[1] == 'i' && rcp[2] == 'o' && rcp[3] == 'n' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; return UNION; } if (rcp[0] == 'n' && rcp[1] == 's' && rcp[2] == 'i' && rcp[3] == 'g' && rcp[4] == 'n' && rcp[5] == 'e' && rcp[6] == 'd' && !(map[rcp[7]]&(DIGIT|LETTER))) { cp = rcp + 7; return UNSIGNED; } goto id; case 'v': if (rcp[0] == 'o' && rcp[1] == 'i' && rcp[2] == 'd' && !(map[rcp[3]]&(DIGIT|LETTER))) { cp = rcp + 3; tsym = voidtype->u.sym; return VOID; } if (rcp[0] == 'o' && rcp[1] == 'l' && rcp[2] == 'a' && rcp[3] == 't' && rcp[4] == 'i' && rcp[5] == 'l' && rcp[6] == 'e' && !(map[rcp[7]]&(DIGIT|LETTER))) { cp = rcp + 7; return VOLATILE; } goto id; case 'w': if (rcp[0] == 'h' && rcp[1] == 'i' && rcp[2] == 'l' && rcp[3] == 'e' && !(map[rcp[4]]&(DIGIT|LETTER))) { cp = rcp + 4; return WHILE; } goto id; case '_': if (rcp[0] == '_' && rcp[1] == 't' && rcp[2] == 'y' && rcp[3] == 'p' && rcp[4] == 'e' && rcp[5] == 'c' && rcp[6] == 'o' && rcp[7] == 'd' && rcp[8] == 'e' && !(map[rcp[9]]&(DIGIT|LETTER))) { cp = rcp + 9; return TYPECODE; } if (rcp[0] == '_' && rcp[1] == 'f' && rcp[2] == 'i' && rcp[3] == 'r' && rcp[4] == 's' && rcp[5] == 't' && rcp[6] == 'a' && rcp[7] == 'r' && rcp[8] == 'g' && !(map[rcp[9]]&(DIGIT|LETTER))) { cp = rcp + 9; return FIRSTARG; } goto id; default: if ((map[cp[-1]]&BLANK) == 0) if (cp[-1] < ' ' || cp[-1] >= 0177) error("illegal character `\\0%o'\n", cp[-1]); else error("illegal character `%c'\n", cp[-1]); } } } static Symbol icon(unsigned long n, int overflow, int base) { if ((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L') || (*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U')) { tval.type = unsignedlong; cp += 2; } else if (*cp == 'u' || *cp == 'U') { if (overflow || n > unsignedtype->u.sym->u.limits.max.i) tval.type = unsignedlong; else tval.type = unsignedtype; cp += 1; } else if (*cp == 'l' || *cp == 'L') { if (overflow || n > longtype->u.sym->u.limits.max.i) tval.type = unsignedlong; else tval.type = longtype; cp += 1; } else if (overflow || n > longtype->u.sym->u.limits.max.i) tval.type = unsignedlong; else if (n > inttype->u.sym->u.limits.max.i) tval.type = longtype; else if (base != 10 && n > inttype->u.sym->u.limits.max.i) tval.type = unsignedtype; else tval.type = inttype; switch (tval.type->op) { case INT: if (overflow || n > tval.type->u.sym->u.limits.max.i) { warning("overflow in constant `%S'\n", token, (char*)cp - token); tval.u.c.v.i = tval.type->u.sym->u.limits.max.i; } else tval.u.c.v.i = n; break; case UNSIGNED: if (overflow || n > tval.type->u.sym->u.limits.max.u) { warning("overflow in constant `%S'\n", token, (char*)cp - token); tval.u.c.v.u = tval.type->u.sym->u.limits.max.u; } else tval.u.c.v.u = n; break; default: assert(0); } ppnumber("integer"); return &tval; } static void ppnumber(char *which) { unsigned char *rcp = cp--; for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++) if ((cp[0] == 'E' || cp[0] == 'e') && (cp[1] == '-' || cp[1] == '+')) cp++; if (cp > rcp) error("`%S' is a preprocessing number but an invalid %s constant\n", token, (char*)cp-token, which); } static Symbol fcon(void) { if (*cp == '.') do cp++; while (map[*cp]&DIGIT); if (*cp == 'e' || *cp == 'E') { if (*++cp == '-' || *cp == '+') cp++; if (map[*cp]&DIGIT) do cp++; while (map[*cp]&DIGIT); else error("invalid floating constant `%S'\n", token, (char*)cp - token); } errno = 0; tval.u.c.v.d = strtod(token, NULL); if (errno == ERANGE) warning("overflow in floating constant `%S'\n", token, (char*)cp - token); if (*cp == 'f' || *cp == 'F') { ++cp; if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d) warning("overflow in floating constant `%S'\n", token, (char*)cp - token); tval.type = floattype; } else if (*cp == 'l' || *cp == 'L') { cp++; tval.type = longdouble; } else { if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d) warning("overflow in floating constant `%S'\n", token, (char*)cp - token); tval.type = doubletype; } ppnumber("floating"); return &tval; } static void *cput(int c, void *cl) { char *s = cl; if (c < 0 || c > 255) warning("overflow in escape sequence with resulting value `%d'\n", c); *s++ = c; return s; } static void *wcput(int c, void *cl) { unsigned int *s = cl; *s++ = c; return s; } static void *scon(int q, void *put(int c, void *cl), void *cl) { int n = 0, nbad = 0; do { cp++; while (*cp != q) { int c; if (map[*cp]&NEWLINE) { if (cp < limit) break; cp++; nextline(); if (cp == limit) break; continue; } c = *cp++; if (c == '\\') { if (map[*cp]&NEWLINE) { if (cp < limit) break; cp++; nextline(); } if (limit - cp < MAXTOKEN) fillbuf(); c = backslash(q); } else if (c < 0 || c > 255 || map[c] == 0) nbad++; if (n++ < BUFSIZE) cl = put(c, cl); } if (*cp == q) cp++; else error("missing %c\n", q); } while (q == '"' && getchr() == '"'); cl = put(0, cl); if (n >= BUFSIZE) error("%s literal too long\n", q == '"' ? "string" : "character"); if (Aflag >= 2 && q == '"' && n > 509) warning("more than 509 characters in a string literal\n"); if (Aflag >= 2 && nbad > 0) warning("%s literal contains non-portable characters\n", q == '"' ? "string" : "character"); return cl; } int getchr(void) { for (;;) { while (map[*cp]&BLANK) cp++; if (!(map[*cp]&NEWLINE)) return *cp; cp++; nextline(); if (cp == limit) return EOI; } } static int backslash(int q) { unsigned int c; switch (*cp++) { case 'a': return 7; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; case '\'': case '"': case '\\': case '\?': break; case 'x': { int overflow = 0; if ((map[*cp]&(DIGIT|HEX)) == 0) { if (*cp < ' ' || *cp == 0177) error("ill-formed hexadecimal escape sequence\n"); else error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp); if (*cp != q) cp++; return 0; } for (c = 0; map[*cp]&(DIGIT|HEX); cp++) { if (c >> (8*widechar->size - 4)) overflow = 1; if (map[*cp]&DIGIT) c = (c<<4) + *cp - '0'; else c = (c<<4) + (*cp&~040) - 'A' + 10; } if (overflow) warning("overflow in hexadecimal escape sequence\n"); return c&ones(8*widechar->size); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = *(cp-1) - '0'; if (*cp >= '0' && *cp <= '7') { c = (c<<3) + *cp++ - '0'; if (*cp >= '0' && *cp <= '7') c = (c<<3) + *cp++ - '0'; } return c; default: if (cp[-1] < ' ' || cp[-1] >= 0177) warning("unrecognized character escape sequence\n"); else warning("unrecognized character escape sequence `\\%c'\n", cp[-1]); } return cp[-1]; }