#include <stdio.h> #include <string.h> #include <assert.h> /* Bug: appears to get %c wrong if followed by a trailing space */ /* Also Imp80 allows ... %c <newline> <newline> code ... */ #define huge 1000000 char outbuf[huge] = { 255 }; char *outp = outbuf+1; #define maxline 4096 char buffer[maxline+2]; char *line, *s; int mode = '\n', savemode = '\n', c, pendch = -1, peek, bracedepth = 0;; int lastch(void) { int c; outp -= 1; c = *outp; /* I don't trust *outp[-1] */ outp += 1; return(c); } void outch(char c) { int x; if (c == '\0') { /* Explicit flush */ /* for now we assume outout buffer bigger than source file */ fwrite(outbuf+1, outp-outbuf-1, 1, stdout); outp = outbuf+1; return; } if ((c > '\0' && c < '\n') || (c > '\n' && c < ' ') || (c >= 127)) { return; // bad character in data. } if ((c != '\n') || (mode == '!')) { *outp++ = c; return;} if (lastch() == 'c') { outp -= 1; fwrite(outbuf+1, outp-outbuf-1, 1, stdout); outp = outbuf+1; /* empty the buffer */ return; } *outp++ = c; } int main(int argc, char **argv) { buffer[0] = '\n'; for (;;) { line = fgets(buffer+1, maxline, stdin); if (line == NULL) break; /* zap all DOS-style CR's, just in case */ while ((s = strchr(line, '\r')) != NULL) { memmove(s, s+1, strlen(s) /* incl NUL */); } s = line+strlen(line); /* points to NUL */ if (s == line) break; if (*--s != '\n') { /* Line does not terminate in \n??? */ exit(1); } while (*--s == ' ' || *s == '\t') /* strip trailing spaces */; *++s = '\n'; /* Reinsert newline - we can now guarantee %c\n */ for (;;) { c = *line++; if (c == '\0') break; retry: switch (mode) { case '\n': /* pre-statement space */ bracedepth = 0; if (isspace(c)) continue; if (c == ';') continue; assert(c != '\n'); if ((c == '\'') ||(c == '%') ||(c == '!')) { if ((c == '\'') || (c == '!')) outch(c); /* why did I invent 'pendch'??? - use it here? ^ */ bracedepth = 0; savemode = mode; mode = c; continue; } mode = '.'; pendch = c; continue; case '+': /* post %c space */ if ((c == ' ') || (c == '\t')) continue; mode = '.'; goto retry; case '!': /* in ! comment */ /* ERROR: %c at end of comment matters! */ /* %COMMENT not handled by this code */ if (c == '%') { c = *line++; if (isalpha(c) && (toupper(c) == 'C') && (*line == '\n')) { line++; break; /* Join next line */ } else { outch('%'); outch(c); } } else outch(c); if (c == '\n') mode = c; continue; case '%': /* in keyword */ /* THIS DOES NOT HANDLE %comment CORRECTLY! */ if (isalpha(c)) { c = tolower(c); peek = *line; if ((c == 'c') && (peek == '\n')) { mode = '+'; line += 1; break; } outch(c); if (c == 't') { if ( ( *(outp-1) == 't') && ( *(outp-2) == 'n') && ( *(outp-3) == 'e') && ( *(outp-4) == 'm') && ( *(outp-5) == 'm') && ( *(outp-6) == 'o') && ( *(outp-7) == 'c')) { // copy over rest of comment up to newline mode = '!'; continue; } } continue; } else { mode = '.'; goto retry; } case '\'': /* in 'const' */ if ((c == mode) && (*line == mode)) { outch(c); outch(c); line += 1; /* past 2nd ' */ continue; } if (c == mode) { /* end of string */ outch(c); mode = '.'; continue; /* reclassify on next ch */ } outch(c); continue; case '.': /* everything else */; if (pendch >= 0) { if (isalpha(pendch) && islower(pendch)) pendch = toupper(pendch); outch(pendch); pendch = -1; }; if (isalpha(c) && islower(c)) c = toupper(c); if (c == ' ' || c == '\t') continue; if ( (c == '\'') && ( (isalpha(lastch()) && isupper(lastch())) || isdigit(lastch()) || (lastch() == '\'') // a X' or X'' variable... )) { outch(c); continue; } if (c == '(') { bracedepth += 1; } else if (c == ')') { bracedepth -= 1; } #ifdef NEVER else if ((c == ':') && (bracedepth == 0)) { /* emit label on line of its own - makes for easier parsing */ outch(c); outch('\n'); mode = '\n'; continue; } #endif if (c == ';') c = '\n'; if (strchr("\n%'", c) != NULL) { if (strchr("\n'", c) != NULL) outch(c); savemode = mode; mode = c; continue; }; outch(c); } } } outch(0); /* Flush buffer */ }