/* * deal with comments in the fast scanner. */ static void fastcmnt2(int ch) { int lastline = ifiles->lineno; incmnt = 1; if (ch == '/') { /* C++ comment */ while ((ch = qcchar()) != '\n') ; unch(ch); } else if (ch == '*') { for (;;) { if ((ch = qcchar()) == 0) break; if (ch == '*') { if ((ch = qcchar()) == '/') { break; } else unch(ch); } else if (ch == '\n') { putch('\n'); ifiles->lineno++; } } } else error("fastcmnt2"); if (ch == 0) error("comment at line %d never ends", lastline); incmnt = 0; }
/* * Check for (and convert) trigraphs. */ int chktg() { int c; if ((c = inpch()) != '?') { unch(c); return 0; } switch (c = inpch()) { case '=': c = '#'; break; case '(': c = '['; break; case ')': c = ']'; break; case '<': c = '{'; break; case '>': c = '}'; break; case '/': c = '\\'; break; case '\'': c = '^'; break; case '!': c = '|'; break; case '-': c = '~'; break; default: unch(c); unch('?'); c = 0; } return c; }
/* * Check for (and convert) trigraphs. */ static int chktg(void) { int ch; if ((ch = inpch()) != '?') { unch(ch); return 0; } switch (ch = inpch()) { case '=': return '#'; case '(': return '['; case ')': return ']'; case '<': return '{'; case '>': return '}'; case '/': return '\\'; case '\'': return '^'; case '!': return '|'; case '-': return '~'; } unch(ch); unch('?'); return 0; }
/* * deal with comments when -C is active. * Save comments in expanded macros??? */ void Ccmnt2(struct iobuf *ob, int ch) { if (skpows) cntline(); if (ch == '/') { /* C++ comment */ putob(ob, ch); do { putob(ob, ch); } while ((ch = qcchar()) && ch != '\n'); unch(ch); } else if (ch == '*') { strtobuf((usch *)"/*", ob); for (;;) { ch = qcchar(); putob(ob, ch); if (ch == '*') { if ((ch = qcchar()) == '/') { putob(ob, ch); break; } else unch(ch); } else if (ch == '\n') { ifiles->lineno++; } } } }
/* * Handle a preprocessor directive. */ void ppdir(void) { char bp[20]; int ch, i; redo: while ((ch = inch()) == ' ' || ch == '\t') ; if (ch == '/') { if ((ch = inch()) == '/') { skpln(); return; } if (ch == '*') { while ((ch = inch()) != -1) { if (ch == '*') { if ((ch = inch()) == '/') goto redo; unch(ch); } else if (ch == '\n') { putch('\n'); ifiles->lineno++; } } } } if (ch == '\n') { /* empty directive */ unch(ch); return; } if (ch < 'a' || ch > 'z') goto out; /* something else, ignore */ i = 0; do { bp[i++] = (usch)ch; if (i == sizeof(bp)-1) goto out; /* too long */ ch = inch(); } while ((ch >= 'a' && ch <= 'z') || (ch == '_')); unch(ch); bp[i++] = 0; /* got keyword */ for (i = 0; i < NPPD; i++) { if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0) { (*ppd[i].fun)(); return; } } out: if (flslvl == 0 && Aflag == 0) error("invalid preprocessor directive"); unch(ch); skpln(); }
/* * Handle a preprocessor directive. * # is already found. */ void ppdir(void) { int ch, i, oldC; usch *bp; oldC = Cflag; redo: Cflag = 0; if ((ch = fastspc()) == '\n') { /* empty directive */ unch(ch); Cflag = oldC; return; } Cflag = oldC; if ((spechr[ch] & C_ID0) == 0) goto out; bp = readid(ch); /* got some keyword */ for (i = 0; i < NPPD; i++) { if (bp[0] == ppd[i].name[0] && strcmp((char *)bp, ppd[i].name) == 0) { if (flslvl == 0) { (*ppd[i].fun)(); if (flslvl == 0) return; } else { if (ppd[i].flags & DIR_FLSLVL) { (*ppd[i].fun)(); if (flslvl == 0) return; } else if (ppd[i].flags & DIR_FLSINC) flslvl++; } flscan(); goto redo; } } if (flslvl == 0) { if (Aflag) skpln(); return; } flscan(); goto redo; out: if (flslvl == 0 && Aflag == 0) error("invalid preprocessor directive"); unch(ch); skpln(); }
static int eatcmnt(void) { int ch; if (Cflag) { PUTCH('/'); PUTCH('*'); } for (;;) { ch = inch(); if (ch == '\n') { ifiles->lineno++; PUTCH('\n'); } if (ch == -1) return -1; if (ch == '*') { ch = inch(); if (ch == '/') { if (Cflag) { PUTCH('*'); PUTCH('/'); } else PUTCH(' '); break; } unch(ch); ch = '*'; } if (Cflag) PUTCH(ch); } return 0; }
/* * get a preprocessing number and save it as given by ob. * returns first non-pp-number char. * We know that this is a valid number already. * * pp-number: digit * . digit * pp-number digit * pp-number identifier-nondigit * pp-number e sign * pp-number E sign * pp-number p sign * pp-number P sign * pp-number . */ int fastnum(int ch, struct iobuf *ob) { int c2; if ((spechr[ch] & C_DIGIT) == 0) { /* not digit, dot */ putob(ob, ch); ch = qcchar(); } for (;;) { putob(ob, ch); if ((ch = qcchar()) == 0) return 0; if ((c2 = (ch & 0337)) == 'E' || c2 == 'P') { if ((c2 = qcchar()) != '-' && c2 != '+') { if (c2 > 0) unch(c2); break; } putob(ob, ch); ch = c2; } else if (ch == '.' || (spechr[ch] & C_ID)) { continue; } else break; } return ch; }
static void cppwarning(void) { usch *cp; int c; if (flslvl) return; c = sloscan(); if (c != WSPACE && c != '\n') error("bad warning"); /* svinp() add an unwanted \n */ cp = stringbuf; while ((c = inch()) && c != '\n') savch(c); savch(0); if (flslvl) stringbuf = cp; else warning("#warning %s", cp); unch('\n'); }
static void eatcmnt(void) { int ch; if (Cflag) { PUTCH('/'); PUTCH('*'); } for (;;) { ch = inch(); if (ch == '\n') { ifiles->lineno++; putch('\n'); continue; } if (ch == -1) break; if (ch == '*') { ch = inch(); if (ch == '/') { if (Cflag) { PUTCH('*'); PUTCH('/'); } else PUTCH(' '); break; } unch(ch); ch = '*'; } if (Cflag) PUTCH(ch); } }
void cunput(int c) { #ifdef PCC_DEBUG // if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c); #endif unch(c); }
/* * check for universal-character-name on input, and * unput to the pushback buffer encoded as UTF-8. */ static int chkucn(void) { unsigned long cp, m; int ch, n; if ((ch = inch()) == -1) return 0; if (ch == 'u') n = 4; else if (ch == 'U') n = 8; else { unch(ch); return 0; } cp = 0; while (n-- > 0) { if ((ch = inch()) == -1 || (spechr[ch] & C_HEX) == 0) { warning("invalid universal character name"); // XXX should actually unput the chars and return 0 unch(ch); // XXX eof break; } cp = cp * 16 + dig2num(ch); } if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60) || (cp >= 0xd800 && cp <= 0xdfff)) /* 6.4.3.2 */ error("universal character name cannot be used"); if (cp > 0x7fffffff) error("universal character name out of range"); n = 0; m = 0x7f; while (cp > m) { unch(0x80 | (cp & 0x3f)); cp >>= 6; m >>= (n++ ? 1 : 2); } unch(((m << 1) ^ 0xfe) | cp); return 1; }
static void skpln(void) { /* just ignore the rest of the line */ while (inch() != '\n') ; unch('\n'); flslvl++; }
/* * do an even faster scan than fastscan while at flslvl. * just search for a new directive. */ static void flscan(void) { int ch; for (;;) { ch = qcchar(); again: switch (ch) { case 0: return; case '\n': putch('\n'); ifiles->lineno++; while ((ch = qcchar()) == ' ' || ch == '\t') ; if (ch == '#') return; if (ch == '%' && (ch = qcchar()) == ':') return; goto again; case '\'': while ((ch = qcchar()) != '\'') { if (ch == '\\') qcchar(); if (ch == '\n') return; } break; case '\"': instr = 1; while ((ch = qcchar()) != '\"') { switch (ch) { case '\\': incmnt = 1; qcchar(); incmnt = 0; break; case '\n': unch(ch); /* FALLTHROUGH */ case 0: instr = 0; return; } } instr = 0; break; case '/': ch = qcchar(); if (ch == '/' || ch == '*') fastcmnt2(ch); goto again; } } }
static void pragmastmt(void) { int ch; putstr((const usch *)"\n#pragma"); while ((ch = qcchar()) != '\n' && ch > 0) putch(ch); unch(ch); prtline(1); }
/* * check for (and eat) end-of-line */ static int chkeol(void) { int ch; ch = inpch(); if (ch == '\r') { ch = inpch(); if (ch == '\n') return '\n'; unch(ch); unch('\r'); return 0; } if (ch == '\n') return '\n'; unch(ch); return 0; }
/* * check for universal-character-name on input, and * unput to the pushback buffer encoded as UTF-8. */ static void ucn(int n) { unsigned long cp, m; int ch; if (incmnt) { struct iobuf *ib = ifiles->ib; ib->cptr--; /* [uU] */ ib->buf[--ib->cptr] = '\\'; return; } cp = 0; while (n-- > 0) { if ((ch = qcchar()) == 0 || (spechr[ch] & C_HEX) == 0) { warning("invalid universal character name"); // XXX should actually unput the chars and return 0 unch(ch); // XXX eof break; } cp = cp * 16 + dig2num(ch); } if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60) || (cp >= 0xd800 && cp <= 0xdfff)) /* 6.4.3.2 */ error("universal character name cannot be used"); if (cp > 0x7fffffff) error("universal character name out of range"); n = 0; m = 0x7f; while (cp > m) { unch(0x80 | (cp & 0x3f)); cp >>= 6; m >>= (n++ ? 1 : 2); } unch(((m << 1) ^ 0xfe) | cp); }
/* * Handle a preprocessor directive. */ void ppdir(void) { char bp[20]; int ch, i; while ((ch = inch()) == ' ' || ch == '\t') ; if (ch == '\n') { /* empty directive */ unch(ch); return; } if (ch < 'a' || ch > 'z') goto out; /* something else, ignore */ i = 0; do { bp[i++] = (usch)ch; if (i == sizeof(bp)-1) goto out; /* too long */ ch = inch(); } while ((ch >= 'a' && ch <= 'z') || (ch == '_')); unch(ch); bp[i++] = 0; /* got keyword */ #define SZ (int)(sizeof(ppd)/sizeof(ppd[0])) for (i = 0; i < SZ; i++) if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0) break; if (i == SZ) goto out; /* Found matching keyword */ (*ppd[i].fun)(); return; out: while ((ch = inch()) != '\n' && ch != -1) ; unch('\n'); }
static void skpln(void) { int ch; /* just ignore the rest of the line */ while ((ch = inch()) != -1) { if (ch == '\n') { unch('\n'); break; } } }
void cunput(int c) { #ifdef CPP_DEBUG extern int dflag; if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c); #endif #if 0 if (c == 10) { printf("c == 10!!!\n"); } #endif unch(c); }
static int inch(void) { int c; again: switch (c = inpch()) { case '\\': /* continued lines */ msdos: if ((c = inpch()) == '\n') { ifiles->lineno++; goto again; } else if (c == '\r') goto msdos; unch(c); return '\\'; case '?': /* trigraphs */ if ((c = chktg())) { unch(c); goto again; } return '?'; default: return c; } }
/* * readin chars and store in buf. Warn about too long names. */ usch * readid(int ch) { int p = 0; do { if (p == MAXIDSZ) warning("identifier exceeds C99 5.2.4.1, truncating"); if (p < MAXIDSZ) idbuf[p] = ch; p++; } while (spechr[ch = qcchar()] & C_ID); idbuf[p] = 0; unch(ch); return idbuf; }
/* * readin chars and store in buf. Warn about too long names. */ usch * bufid(int ch, struct iobuf *ob) { int n = ob->cptr; do { if (ob->cptr - n == MAXIDSZ) warning("identifier exceeds C99 5.2.4.1"); if (ob->cptr < ob->bsz) ob->buf[ob->cptr++] = ch; else putob(ob, ch); } while (spechr[ch = qcchar()] & C_ID); ob->buf[ob->cptr] = 0; /* legal */ unch(ch); return ob->buf+n; }
/* save line into stringbuf */ static usch * savln(void) { int c; usch *cp = stringbuf; while ((c = inch()) != -1) { if (c == '\n') { unch(c); break; } savch(c); } savch(0); return cp; }
static void pragmastmt(void) { int c; if (sloscan() != WSPACE) error("bad pragma"); if (!flslvl) putstr((const usch *)"#pragma "); do { c = inch(); if (!flslvl) putch(c); /* Do arg expansion instead? */ } while (c && c != '\n'); if (c == '\n') unch(c); prtline(); }
static void chknl(int ignore) { void (*f)(const char *, ...); int t; f = ignore ? warning : error; if ((t = fastspc()) != '\n') { if (t) { f("newline expected"); /* ignore rest of line */ while ((t = qcchar()) > 0 && t != '\n') ; } else f("no newline at end of file"); } unch(t); }
/* save line into iobuf */ struct iobuf * savln(void) { struct iobuf *ob = getobuf(BNORMAL); int c; while ((c = qcchar()) != 0) { if (c == '\n') { unch(c); break; } if (c == '\'' || c == '\"') faststr(c, ob); else putob(ob, c); } ob->buf[ob->cptr] = 0; return ob; }
/* * get a string or character constant and save it as given by d. */ struct iobuf * faststr(int bc, struct iobuf *ob) { struct iobuf *ib = ifiles->ib; int ch; if (ob == NULL) ob = getobuf(BNORMAL); instr = 1; putob(ob, bc); for (;;) { if (ib->bsz == ib->cptr) ch = qcchar(); else if (ISCQ(ch = ib->buf[ib->cptr])) ch = qcchar(); else ib->cptr++; switch (ch) { case '\\': putob(ob, ch); if (ib->cptr == ib->bsz) inpbuf(0); incmnt = 1; putob(ob, qcchar()); incmnt = 0; continue; case '\n': warning("unterminated literal"); instr = 0; unch(ch); return ob; } putob(ob, ch); if (ch == bc) break; } putob(ob, 0); ob->cptr--; instr = 0; return ob; }
int yylex(void) { static int ifdef, noex; struct symtab *nl; int ch, c2; while ((ch = sloscan()) == WSPACE) ; if (ch < 128 && (spechr[ch] & C_2)) c2 = inch(); else c2 = 0; switch (ch) { case '=': if (c2 == '=') return EQ; break; case '!': if (c2 == '=') return NE; break; case '|': if (c2 == '|') return OROR; break; case '&': if (c2 == '&') return ANDAND; break; case '<': if (c2 == '<') return LS; if (c2 == '=') return LE; break; case '>': if (c2 == '>') return RS; if (c2 == '=') return GE; break; case '+': case '-': if (ch == c2) error("invalid preprocessor operator %c%c", ch, c2); break; case '/': if (Cflag == 0 || c2 != '*') break; /* Found comment that need to be skipped */ for (;;) { ch = inch(); c1: if (ch != '*') continue; if ((ch = inch()) == '/') break; goto c1; } return yylex(); case NUMBER: if (yytext[0] == '\'') { yylval.node.op = NUMBER; yylval.node.nd_val = charcon(yytext); } else cvtdig(yytext[0] != '0' ? 10 : yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8); return NUMBER; case IDENT: if (strcmp((char *)yytext, "defined") == 0) { ifdef = 1; return DEFINED; } nl = lookup(yytext, FIND); if (ifdef) { yylval.node.nd_val = nl != NULL; ifdef = 0; } else if (nl && noex == 0) { usch *och = stringbuf; int i; i = kfind(nl); unch(WARN); if (i) unpstr(stringbuf); else unpstr(nl->namep); stringbuf = och; noex = 1; return yylex(); } else { yylval.node.nd_val = 0; } yylval.node.op = NUMBER; return NUMBER; case WARN: noex = 0; /* FALLTHROUGH */ case PHOLD: return yylex(); default: return ch; } unch(c2); return ch; }
int sloscan(void) { int ch; int yyp; zagain: yyp = 0; ch = inch(); yytext[yyp++] = (usch)ch; switch (ch) { case -1: return 0; case '\n': /* sloscan() never passes \n, that's up to fastscan() */ unch(ch); yytext[yyp] = 0; return ch; case '\r': /* Ignore CR's */ yyp = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* readin a "pp-number" */ ppnum: for (;;) { ch = inch(); if (ch == -1) break; if (spechr[ch] & C_EP) { yytext[yyp++] = (usch)ch; ch = inch(); if (ch == '-' || ch == '+') { yytext[yyp++] = (usch)ch; } else unch(ch); continue; } if ((spechr[ch] & C_ID) || ch == '.') { yytext[yyp++] = (usch)ch; continue; } break; } unch(ch); yytext[yyp] = 0; return NUMBER; case '\'': chlit: for (;;) { if ((ch = inch()) == '\\') { yytext[yyp++] = (usch)ch; yytext[yyp++] = (usch)inch(); continue; } else if (ch == -1 || ch == '\n') { /* not a constant */ while (yyp > 1) unch(yytext[--yyp]); ch = '\''; goto any; } else yytext[yyp++] = (usch)ch; if (ch == '\'') break; } yytext[yyp] = 0; return NUMBER; case ' ': case '\t': while ((ch = inch()) == ' ' || ch == '\t') yytext[yyp++] = (usch)ch; unch(ch); yytext[yyp] = 0; return WSPACE; case '/': if ((ch = inch()) == '/') { do { yytext[yyp++] = (usch)ch; ch = inch(); } while (ch != -1 && ch != '\n'); yytext[yyp] = 0; unch(ch); goto zagain; } else if (ch == '*') { int c, wrn; extern int readmac; if (Cflag && !flslvl && readmac) { unch(ch); yytext[yyp] = 0; return CMNT; } wrn = 0; more: while ((c = inch()) != '*') { if (c == -1) return 0; if (c == '\n') putch(c), ifiles->lineno++; else if (c == EBLOCK) { (void)inch(); (void)inch(); } else if (c == WARN) wrn = 1; } if ((c = inch()) == -1) return 0; if (c != '/') { unch(c); goto more; } if (!tflag && !Cflag && !flslvl) unch(' '); if (wrn) unch(WARN); goto zagain; } unch(ch); ch = '/'; goto any; case '.': if ((ch = inch()) == -1) return 0; if ((spechr[ch] & C_DIGIT)) { yytext[yyp++] = (usch)ch; goto ppnum; } else { unch(ch); ch = '.'; } goto any; case '\"': if (tflag && defining) goto any; strng: for (;;) { if ((ch = inch()) == '\\') { yytext[yyp++] = (usch)ch; yytext[yyp++] = (usch)inch(); continue; } else if (ch == -1) { break; } else yytext[yyp++] = (usch)ch; if (ch == '\"') break; } yytext[yyp] = 0; return STRING; case 'L': if ((ch = inch()) == '\"' && !tflag) { yytext[yyp++] = (usch)ch; goto strng; } else if (ch == '\'' && !tflag) { yytext[yyp++] = (usch)ch; goto chlit; } unch(ch); /* FALLTHROUGH */ /* Yetch, all identifiers */ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 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': 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': case '_': /* {L}({L}|{D})* */ /* Special hacks */ for (;;) { /* get chars */ if ((ch = inch()) == -1) break; if ((spechr[ch] & C_ID)) { yytext[yyp++] = (usch)ch; } else { unch(ch); break; } } yytext[yyp] = 0; /* need already string */ /* end special hacks */ return IDENT; default: any: yytext[yyp] = 0; return yytext[0]; } /* endcase */ goto zagain; }