/* * @(#) define.c - Pre-processor for C (handles only define and undef macros). * (c) 1995 Ivan Maidanski http://ivmai.chat.ru * Freeware program source. All rights reserved. ** * Language: ANSI C * Tested with: BSD GNU CC * Last modified: 1995-11-25 12:00:00 GMT+03:00 */ #include #include /* #include */ #include #include /* limits */ #define MAXLEXEM 31 #define HASHSIZE 64 typedef char tlexem[MAXLEXEM+1]; typedef struct macrorec { char *name; char *body; struct macrorec *next; } tmacrorec; static tmacrorec *macros[HASHSIZE]; int islexsymbol(int ch); /* returns 1 if ch is lex symbol */ int stricmp(char *s1, char *s2); /* compares s1 with s2 ignoring case; returns 0 if s1==s2 */ void *allocate(void *ptr,size_t size); /* (re)allocates buffer with specified size; returns new value of ptr */ char *strconcat(char *base,char *add); /* adds add to the end of *base (may be NULL); returns new value of base */ int hashfunc(char *str); /* generates and returns hash value of string */ void put_to_hash(char *name,char *body); /* adds record with specified name and body */ char *get_from_hash(char *name); /* gets body from record with specified name */ void del_from_hash(char *name); /* deletes record with specified name */ char get_symbol(char symbol); /* gets next symbol from stdin (symbol='\0'); puts back symbol if symbol>'\0'; returns '/1' if EOF found */ void skip_space(); /* skips spaces */ void get_lexem(char *lexem); /* gets a lexem from stdin; if EOF found, result string is NULL */ char *get_line(); /* gets a line from stdin */ void define_macro(char *name,char *macroext); /* defines macro name as macroext */ void undefine_macro(char *name); /* undefine macro name */ char *get_macroext(char *name); /* extends macro name into macroext; returns NULL if macro name not defined */ char *extend_line(char *line); /* extends all macros in line */ /* implementation */ int main() { tlexem lexem; while (get_lexem(lexem),lexem[0]) { if (!strcmp(lexem,"#")) { skip_space(); get_lexem(lexem); if (!stricmp(lexem,"undef")) { skip_space(); get_lexem(lexem); if (lexem[0]!='\n') { undefine_macro(lexem); free((void *)get_line()); } printf("\n"); } else if (!stricmp(lexem,"define")) { char *macro; skip_space(); get_lexem(lexem); if (lexem[0]!='\n') { skip_space(); macro=extend_line(get_line()); if (*macro) { macro[strlen(macro)-1]='\0'; define_macro(lexem,macro); } free((void *)macro); } printf("\n"); } else printf("#%s",lexem); } else { char *macro=extend_line(strconcat(NULL,lexem)); printf("%s",macro); free((void *)macro); } } return 0; } int islexsymbol(int ch) { return (ch=='_') || isalnum(ch); } int stricmp(char *s1, char *s2) { if (!s1 || !s2) return !s2-!s1; for (;*s1 && (isupper(*s1) ? tolower(*s1) : *s1)== (isupper(*s2) ? tolower(*s2) : *s2); s1++,s2++); return (isupper(*s1) ? tolower(*s1) : *s1)- (isupper(*s2) ? tolower(*s2) : *s2); } void *allocate(void *ptr,size_t size) { void *p=(void *)realloc(ptr,size); if (!p) { fprintf(stderr,"Error: Not Enough Memory!\n"); exit(1); } return p; } char *strconcat(char *base,char *add) { return base ? strcat((char *)allocate((void *)base, strlen(base)+strlen(add)+1),add): strcpy((char *)allocate(NULL,strlen(add)+1),add); } char get_symbol(char symbol) { static char save='\0'; if (symbol) return save=symbol; if (!save) { int ch=getchar(); save= ch!=EOF ? (char)ch : '\1'; } symbol=save; save='\0'; return symbol; } void skip_space() { char ch; while (ch=get_symbol('\0'),ch==' ' || ch=='\t'); get_symbol(ch); } void get_lexem(char *lexem) { if ((*lexem=get_symbol('\0'))=='\1') get_symbol(*lexem); else if (islexsymbol(*(lexem++))) { while (islexsymbol(*lexem=get_symbol('\0'))) lexem++; get_symbol(*lexem); } *lexem='\0'; } char *get_line() { tlexem lexem; char *line=strconcat(NULL,""); do { get_lexem(lexem); line=strconcat(line,lexem); } while (lexem[0]!='\0' && lexem[0]!='\n'); return line; } int hashfunc(char *str) { long val=0; while (*str) { val+=(*str)*(*str); str++; } return val % HASHSIZE; } void put_to_hash(char *name,char *body) { int n=hashfunc(name); tmacrorec *ptr=macros[n]; while (ptr && strcmp(ptr->name,name)) ptr=ptr->next; if (!ptr) { ptr=(tmacrorec *)allocate(NULL,sizeof(tmacrorec)); ptr->name=strconcat(NULL,name); ptr->next=macros[n]; macros[n]=ptr; } else free((void *)ptr->body); ptr->body=strconcat(NULL,body); } void del_from_hash(char *name) { int n=hashfunc(name); tmacrorec *last,*ptr=macros[n]; if (ptr) if (!strcmp(ptr->name,name)) macros[n]=ptr->next; else { do { last=ptr; ptr=ptr->next; } while (ptr && strcmp(ptr->name,name)); if (ptr) last->next=ptr->next; } if (ptr) { free((void *)ptr->name); free((void *)ptr->body); free((void *)ptr); } } char *get_from_hash(char *name) { tmacrorec *ptr=macros[hashfunc(name)]; while (ptr && strcmp(ptr->name,name)) ptr=ptr->next; return ptr ? strconcat(NULL,ptr->body) : NULL; } void define_macro(char *name,char *macroext) { put_to_hash(name,macroext); } void undefine_macro(char *name) { del_from_hash(name); } char *get_macroext(char *name) { return get_from_hash(name); } char *extend_line(char *line) { int beg=0; char ch; char *cur,*macro,*newline; do { for (;line[beg] && !islexsymbol(line[beg]);beg++); for (cur=line+beg;islexsymbol(*cur);cur++); ch=*cur; *cur='\0'; macro=get_macroext(line+beg); *cur=ch; if (macro) { line[beg]='\0'; newline=strconcat(strconcat(strconcat(NULL,line),macro),cur); free((void *)macro); free((void *)line); line=newline; } else beg=cur-line; } while (ch); return line; }