/* ** Small-C Compiler -- Part 2 -- Front End and Miscellaneous. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix ** Copyright 1998 H T Walheim ** All rights reserved. */ #include #include "cc.h" extern char *symtab, *macn, *macq, *pline, *mline, optimize, alarm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3, *locptr, msname[NAMESIZE], pause, quote[2]; extern int *wq, ccode, ch, csp, eof, errflag, iflevel, input, input2, listfp, macptr, nch, nxtlab, op[16], opindex, opsize, output, pptr, skiplevel, *wqptr; /********************** input functions **********************/ preprocess() { int k; char c; if(ccode) { line = mline; ifline(); if(eof) return; } else { inline(); return; } pptr = -1; while(ch != NEWLINE && ch) { if(white()) { keepch(' '); while(white()) gch(); } else if(ch == '"') { keepch(ch); gch(); while(ch != '"' || (*(lptr-1) == 92 && *(lptr-2) != 92)) { if(ch == NULL) { error("no quote"); break; } keepch(gch()); } gch(); keepch('"'); } else if(ch == 39) { keepch(39); gch(); while(ch != 39 || (*(lptr-1) == 92 && *(lptr-2) != 92)) { if(ch == NULL) { error("no apostrophe"); break; } keepch(gch()); } gch(); keepch(39); } else if(ch == '/' && nch == '*') { bump(2); while((ch == '*' && nch == '/') == 0) { if(ch) bump(1); else { ifline(); if(eof) break; } } bump(2); } else if(ch == '/' && nch == '/') { bump(2); while(ch != NEWLINE) { if(ch) bump(1); else { if(eof) break; } } bump(1); } else if(an(ch)) { k = 0; while(an(ch) && k < NAMEMAX) { msname[k++] = ch; gch(); } msname[k] = NULL; if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) { k = getint(cptr+NAMESIZE, 2/*INTSIZE*/); while(c = macq[k++]) keepch(c); while(an(ch)) gch(); } else { k = 0; while(c = msname[k++]) keepch(c); } } else keepch(gch()); } if(pptr >= LINEMAX) error("line too long"); keepch(NULL); line = pline; bump(0); } keepch(c) char c; { if(pptr < LINEMAX) pline[++pptr] = c; } ifline() { while(1) { inline(); if(eof) return; if(match("#ifdef")) { ++iflevel; if(skiplevel) continue; symname(msname); if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) skiplevel = iflevel; continue; } if(match("#ifndef")) { ++iflevel; if(skiplevel) continue; symname(msname); if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) skiplevel = iflevel; continue; } if(match("#else")) { if(iflevel) { if(skiplevel == iflevel) skiplevel = 0; else if(skiplevel == 0) skiplevel = iflevel; } else noiferr(); continue; } if(match("#endif")) { if(iflevel) { if(skiplevel == iflevel) skiplevel = 0; --iflevel; } else noiferr(); continue; } if(skiplevel) continue; if(ch == 0) continue; break; } } inline() { /* numerous revisions */ int k, unit; if(input == EOF) openfile(); if(eof) return; if((unit = input2) == EOF) unit = input; if(fgets(line, LINEMAX, unit) == NULL) { fclose(unit); if(input2 != EOF) input2 = EOF; else input = EOF; *line = NULL; } else if(listfp) { if(listfp == output) fputc(';', output); fputs(line, listfp); } #ifdef _MSC_VER else { fputc(';', output); fputs(line, output); } #endif bump(0); } inbyte() { while(ch == 0) { if(eof) return 0; preprocess(); } return gch(); } /********************* scanning functions ********************/ /* ** test if next input string is legal symbol name */ symname(sname) char *sname; { int k;char c; blanks(); if(alpha(ch) == 0) return (*sname = 0); k = 0; while(an(ch)) { sname[k] = gch(); if(k < NAMEMAX) ++k; } sname[k] = 0; return 1; } need(str) char *str; { if(match(str) == 0) error("missing token"); } ns() { if(match(";") == 0) error("no semicolon"); else errflag = 0; } match(lit) char *lit; { int k; blanks(); if(k = streq(lptr, lit)) { bump(k); return 1; } return 0; } streq(str1, str2) char str1[], str2[]; { int k; k = 0; while (str2[k]) { if(str1[k] != str2[k]) return 0; ++k; } return k; } amatch(lit, len) char *lit; int len; { int k; blanks(); if(k = astreq(lptr, lit, len)) { bump(k); return 1; } return 0; } astreq(str1, str2, len) char str1[], str2[]; int len; { int k; k = 0; while (k < len) { if(str1[k] != str2[k]) break; /* ** must detect end of symbol table names terminated by ** symbol length in binary */ if(str2[k] < ' ') break; if(str1[k] < ' ') break; ++k; } if(an(str1[k]) || an(str2[k])) return 0; return k; } nextop(list) char *list; { char op[4]; opindex = 0; blanks(); while(1) { opsize = 0; while(*list > ' ') op[opsize++] = *list++; op[opsize] = 0; if(opsize = streq(lptr, op)) if(*(lptr+opsize) != '=' && *(lptr+opsize) != *(lptr+opsize-1)) return 1; if(*list) { ++list; ++opindex; } else return 0; } } blanks() { while(1) { while(ch) { if(white()) gch(); else return; } if(line == mline) return; preprocess(); if(eof) break; } } white() { return (*lptr <= ' ' && *lptr); } gch() { int c; if(c = ch) bump(1); return c; } bump(n) int n; { if(n) lptr += n; else lptr = line; if(ch = nch = *lptr) nch = *(lptr+1); } kill() { *line = 0; bump(0); } skip() { if(an(inbyte())) while(an(ch)) gch(); else while(an(ch) == 0) { if(ch == 0) break; gch(); } blanks(); } endst() { blanks(); return (streq(lptr, ";") || ch == 0); } /*********** symbol table management functions ***********/ addsym(sname, id, type, size, value, lgpp, class) char *sname, id, type; int size, value, *lgpp, class; { if(lgpp == &glbptr) { if(cptr2 = findglb(sname)) return cptr2; if(cptr == 0) { error("global symbol table overflow"); return 0; } } else { if(locptr > (ENDLOC-SYMMAX)) { error("local symbol table overflow"); exit(ERRCODE); } cptr = *lgpp; } cptr[IDENT] = id; cptr[TYPE] = type; cptr[CLASS] = class; putint(size, cptr + SIZE, INTSIZE); putint(value, cptr + OFFSET, INTSIZE); cptr3 = cptr2 = cptr + NAME; while(an(*sname)) *cptr2++ = *sname++; if(lgpp == &locptr) { *cptr2 = cptr2 - cptr3; /* set length */ *lgpp = ++cptr2; } return cptr; } /* ** search for symbol match ** on return cptr points to slot found or empty slot */ search(sname, buf, len, end, max, off) char *sname, *buf, *end; int len, max, off; { cptr = cptr2 = buf+((hash(sname)%(max-1))*len); while(*cptr != NULL) { if(astreq(sname, cptr+off, NAMEMAX)) return 1; if((cptr = cptr+len) >= end) cptr = buf; if(cptr == cptr2) return (cptr = 0); } return 0; } hash(sname) char *sname; { int i, c; i = 0; while(c = *sname++) i = (i << 1) + c; return i; } findglb(sname) char *sname; { if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1; } return 0; } nextsym(entry) char *entry; { entry = entry + NAME; while(*entry++ >= ' '); /* find length byte */ return entry; } /******** while queue management functions *********/ addwhile(ptr) int ptr[]; { int k; ptr[WQSP] = csp; /* and stk ptr */ ptr[WQLOOP] = getlabel(); /* and looping label */ ptr[WQEXIT] = getlabel(); /* and exit label */ if(wqptr == WQMAX) { error("control statement nesting limit"); exit(ERRCODE); } k = 0; while (k < WQSIZ) *wqptr++ = ptr[k++]; } readwhile(ptr) int *ptr; { if(ptr <= wq) { error("out of context"); return 0; } else return (ptr - WQSIZ); } delwhile() { if(wqptr > wq) wqptr -= WQSIZ; } /****************** utility functions ********************/ /* ** test if c is alphabetic */ alpha(c) char c; { return (isalpha(c) || c == '_'); } /* ** test if given character is alphanumeric */ an(c) char c; { return (alpha(c) || isdigit(c)); } /* ** return next avail internal label number */ getlabel() { return(++nxtlab); } /* ** get integer of length len from address addr ** (byte sequence set by "putint") */ getint(addr, len) char *addr; int len; { int i; i = *(addr + --len); /* high order byte sign extended */ while(len--) i = (i << 8) | *(addr + len) & 255; return i; } /* ** put integer i of length len into address addr ** (low byte first) */ putint(i, addr, len) char *addr; int i, len; { while(len--) { *addr++ = i; i = i >> 8; } } lout(line, fd) char *line; int fd; { fputs(line, fd); fputc(NEWLINE, fd); } /******************* error functions *********************/ illname() { error("illegal symbol"); skip(); } multidef(sname) char *sname; { error("already defined"); } needlval() { error("must be lvalue"); } noiferr() { error("no matching #if..."); errflag = 0; } error(msg) char msg[]; { if(errflag) return; else errflag = 1; lout(line, stderr); errout(msg, stderr); if(alarm) fputc(7, stderr); if(pause) while(fgetc(stderr) != NEWLINE); if(listfp > 0) errout(msg, listfp); } errout(msg, fp) char msg[]; int fp; { int k; k = line+2; while(k++ <= lptr) fputc(' ', fp); lout("/\\", fp); fputs("**** ", fp); lout(msg, fp); }