/* * Utility routines for 'mp', the C macro preprocessor. */ /* * Include compile-time constants, and external and structure defintions. */ #ifdef decus #define stdio #define Digital #endif #ifdef vms #define stdio #define Digital #endif #ifdef stdio #include #else #define NULL (0) #endif #include "mpdefs.h" /* * These are defined here for error messages. */ extern int lineno[]; /* Line number stack */ extern int pageno[]; /* Page number stack */ extern char fname[][40]; /* File name stack */ extern int inclvl; /* #include depth */ extern int nocomp; /* Flag: don't do auto #LINE's */ extern int linefeeds; /* Running count of LF's in output */ extern int in_com; /* If TRUE, currently inside a comment */ /* * Print error message on standard output */ printerr(msg) char *msg; { extern int err_cnt; /* Error count */ register int i, j; for (i = 0; i <= inclvl; i++) { for (j = 0; j < i; j++) putchar('\t'); printf("Page %d, line %d %s\n", pageno[i], lineno[i], fname[i]); } printf("\t%s\n", msg); err_cnt++; return; } /* * Print diagnostic message on standard output */ diagnostic(msg) char *msg; { extern int err_cnt; /* Error count */ printerr(msg); err_cnt--; /* Undo printerr's count */ return; } /* * Internal bug catcher */ screech(msg) char *msg; { printerr("ANTI-BUG CHECK FAILURE:"); printerr(msg); abort(); } /* * Skip a string of blanks and tabs */ char *skipblnk(ptr) register char *ptr; { while (*ptr == ' ' || *ptr == '\t') ptr++; return(ptr); } /* * String comparison -- replace with "streq()" */ lexeq(cp1, cp2) register char *cp1, *cp2; { while (*cp1 != EOS && *cp2 != EOS) { if (*cp1++ != *cp2++) return(FALSE); } return(*cp1 == *cp2); } /* * get_mem - Allocate 'nbytes' of dynamic memory. If none is available, report * an error and exit with nonzero status; otherwise return pointer to * the node. */ char *get_mem(nbytes) int nbytes; { register char *p; if ((p = malloc(nbytes)) == NULL) { printerr("No dynamic memory available"); exits(4); } else return(p); } /* * Concatenate two strings, return pointer to result in local static buffer * replace with strcat(). */ char *concat(str1, str2) register char *str1; char *str2; { register int limit; register char *t; static char buffer[CATMAX]; limit = buffer+CATMAX-1; /* Buffer limit */ for (t = buffer; t <= limit && (*t = *str1) != EOS; t++, str1++) ; while (t <= limit && (*t = *str2) != EOS) { t++; str2++; } if (t > limit) screech("Insufficient space in concat()"); else return(buffer); } /* * Push an item on the stack specified */ int push(item, stkaddr) int item; register struct stack *stkaddr; { if (stkaddr->spcnt == 0) return(ERROR); stkaddr->spcnt-- , stkaddr->usecnt++; *stkaddr->stackptr++ = item; return(OK); } /* * Pop an item off of the stack */ int pop(stkaddr) register struct stack *stkaddr; { if (empty(stkaddr)) screech("Stack underflow!"); stkaddr->spcnt++, stkaddr->usecnt--; return(*--stkaddr->stackptr); } /* * Test whether a stack is empty */ int empty(stkaddr) struct stack *stkaddr; { return(stkaddr->usecnt == 0); } /* * skipq - Routine to return pointer to next unquoted character starting from * "src". All quoted text is flushed to either a text buffer or the * output file, as determined by "dst". If "dst" == NIL, quoted text * is written to "outfil"; if "dst" is non-NIL, then any bypassed * characters are moved to the buffer specified. The parameter "dstmax" * specified the last address into which a character may be deposited. * All comments are also flushed here. For multi-line comments, a * pointer to the end of line is returned. When end of comment is * encountered, scanning is resumed immediately afterward. */ int unmagic = FALSE; char *skipq(src, dst, dstmax) register char *src; char **dst, *dstmax; { register char quote; register int full; extern char *skipcom(); if (in_com) src = skipcom(src); switch(*src) { case '\\': unmagic = !unmagic; return(src); case '\'': case '"': if (unmagic) break; putch(quote = *src++, dst, dstmax); for(;;) { if (*src == EOS) { printerr("Unterminated quoted string"); break; } if (*src == '\\') { putch(*src++, dst, dstmax); unmagic = !unmagic; continue; } full = putch(*src, dst, dstmax); if (*src++ == quote && !unmagic) break; unmagic = FALSE; } return((full == ERROR) ? (char *) ERROR : src); case '/': if (*(src+1) == '*') { in_com = TRUE; return(skipcom(src+2)); } else break; } unmagic = FALSE; return(src); } /* * skipcom - Routine to skip past any comment characters, until either end of * comment or end of line. If end of comment is encountered, in_com is set to * FALSE. */ char *skipcom(src) register char *src; { while ((*src != '*' || *(src+1) != '/')) { if (*src == EOS) return(src); if ((*src == '/' && *(src+1) == '*')) diagnostic("Warning: nested comments"); src++; } src += 2; in_com = FALSE; return(src); } /* * Routine to emit a flushed character to either the current output * file or to the buffer whose address is specified. Returns ERROR if * the buffer is overrun. */ int putch(ch, where, limit) register char ch; char **where, *limit; { #ifdef stdio extern FILE *outfil; #else extern struct buf *outfil; #endif if (where == NIL) { if ((ch == '\n') & !nocomp) { if (linefeeds++ == 0) putc(ch, outfil); } else { if (linefeeds > 1) { if (linefeeds == 2) putc('\n', outfil); else { #ifdef UNIMATION #ifdef PREPRE fprintf(outfil, "#define pg #%d p.%d %s\npg\n", #else fprintf(outfil,"#%d p.%d %s\n", #endif lineno[inclvl], pageno[inclvl], fname[inclvl]); #else fprintf(outfil, "#%d %s\n", lineno[inclvl], fname[inclvl]); #endif } } linefeeds = 0; putc(ch, outfil); } return; } else { if (*where > limit) return(ERROR); else *(*where)++ = ch; return(OK); } } /* * Routine to release entries in the call_ala. The last entry to free * is specified by 'last'. */ rlse_ala(last) register int last; { register int i; extern char *call_ala[]; for(i = 0; i <= last; i++) free(call_ala[i]); return; } /* * get_id - Get an identifier (1-MAXIDLEN alphanumerics + '_', must start with * an alpha). Note that alpha's include '_' and (in Dec-land) '$'. */ char *get_id(src, dst) register char *src, *dst; { register int i; for(i = 0; i < MAXIDLEN && c_alnum(*src); i++) { *dst++ = *src++; } while (c_alnum(*src)) src++; *dst = EOS; return(src); } /* * Increment the character string representation of a number. First * argument specifies the address of the string, second argument * specifies the index in the string of the character to be incremented. * Calls itself recursively if we carry to the next digit. Wraps around * to 0 if the largest unsigned number is incremented. */ charincr(string, index) register char string[]; register int index; { if (index <= 0) return; /* Allow wrap-around */ switch (string[index]) { case ' ': string[index] = '1'; /* ' ' == '0' */ break; case '9': string[index] = '0'; charincr(string, index-1); break; default: string[index] += 1; break; } return; } c_alpha(c) register int c; /* * return(TRUE if c is a C-language alpha (A-Z,a-z, "_", "$") */ { return (isalpha(c) || c == '_' || c == '$'); } c_alnum(c) register int c; /* * Return TRUE if c is a C-language alpha (A-Z, a-z, "_", "$") * or a digit. */ { return (isalnum(c) || c == '_' || c == '$'); }