/* * 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" /* * Print error message on standard output */ printerr(msg) char *msg; { extern int lineno[]; /* Line number stack */ extern int inclvl; /* #include depth */ extern int err_cnt; /* Error count */ register int i; printf("%d", lineno[0]); for (i = 1; i <= inclvl; i++) printf(".%d", lineno[i]); printf(":\t%s\n", msg); err_cnt++; 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) char *ptr; { while (*ptr == ' ' || *ptr == '\t') ptr++; return(ptr); } /* * String copy routine -- copies 'src' to 'dst' until EOS */ strcopy(src, dst) char *src, *dst; { while ((*dst++ = *src++) != EOS) ; return; } /* * String comparison */ lexeq(cp1, cp2) char *cp1, *cp2; { while (*cp1 != EOS && *cp2 != EOS) if (*cp1++ != *cp2++) return(FALSE); return(*cp1 == *cp2); } /* * 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; { char *p; if ((p = alloc(nbytes)) == ERROR) { printerr("No dynamic memory available"); exit(1); } else return(p); } /* * Concatenate two strings, return pointer to result in local static buffer */ char *concat(str1, str2) char *str1, *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; 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) 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); } /* * 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; int in_com FALSE; char *skipq(src, dst, dstmax) char *src, **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) ? ERROR : src); case '/': if (*(src+1) == '*') { in_com = TRUE; return(skipcom(src+2)); } else break; } unmagic = FALSE; return(src); } /* * 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) char *src; { while (!(*src == '*' && *(src+1) == '/')) if (*src == EOS) return(src); else 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) char ch, **where, *limit; { #ifdef stdio extern FILE *outfil; #else extern struct buf *outfil; #endif if (where == NIL) { putc(ch, outfil); return; } 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) int last; { register int i; extern char *call_ala[]; for(i = 0; i <= last; i++) free(call_ala[i]); return; } /* * 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) 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) char string[]; 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, "_", "$") */ { if (c >= 'A') return (c == '_' || (c | 040) <= 'z'); return (c == '$'); } c_alnum(c) register int c; /* * Return TRUE if c is a C-language alpha (A-Z, a-z, "_", "$") * or a digit. */ { if (c >= 'A') return (c == '_' || (c | 040) <= 'z'); return (c == '$' || (c >= '0' && c <= '9')); } $exit() { msg("In $exit"); abort(); }