/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * pre.c * * preprocessor for the compiler * * Handles all preprocessor (#) commands and * looks up keywords * * Interface: * getnode() returns next "token node" */ #include #include "param.h" #include "tok.h" #include "nodes.h" #if CC68 FILE *fopenb(); #define fopen fopenb #endif NODE *deflist[NHASH]; extern struct tok curtok; extern char curstr[]; #define TK_SEENL 1 /* want to see NL token */ #define TK_SEEWS 2 /* want to see WS token */ #define TK_ONLY1 4 /* only want 1st token on line */ #define TK_LTSTR 8 /* '<' starts a string */ #define TK_NOESC 16 /* dont do '\' escapes in string */ extern int tk_flags, sawnl; NODE *holdtok; extern lineno; extern char *inname; extern FILE *input; int iflevel, iftruth, ifnest; NODE *hlook(), *llook(); NODEP tok_to_node(); NODE *copylist(); #ifdef DEBUG extern int oflags[]; #define debugd oflags['d'-'a'] #define debugt oflags['t'-'a'] #endif NODEP hi_node() { register NODEP rv; /* node from hold queue ? */ if (holdtok) { #ifdef DEBUG if (debugd > 2) { printf("Holdqueue"); printnode(holdtok); } #endif rv = holdtok; holdtok = rv->n_next; rv->n_next = NULL; return rv; } /* node from input */ again: while (iflevel && !iftruth) skiplines(); if (nxttok()==0) return NULL; if (curtok.tnum == '#') { dopound(0); goto again; } rv = tok_to_node(); return rv; } NODEP getnode() { register NODEP rv; NODEP dp; again: rv = hi_node(); if (rv == NULL) { rv = allocnode(); rv->e_token = EOFTOK; strcpy(rv->n_name, "*EOF*"); } else if (rv->e_token == ID) { if ((dp = hlook(deflist, rv)) != NULL) { expand(dp); freenode(rv); goto again; } else kw_tok(rv); } #ifdef DEBUG if (debugt) { putchar('['); put_nnm(rv); printf("] "); } #endif return rv; } skiplines() { for (;;) { if (nxttok()== 0) return; if (curtok.tnum == '#') { dopound(1); return; } tk_flags |= TK_ONLY1; } } static defnargs; p_def() { NODE *args; NODE *val; NODE *def; NODE *def_rgs(), *def_val(); defnargs = -1; args = NULL; val = NULL; nxttok(); if (curtok.tnum != ID) { error("bad #define"); goto flush; } def = tok_to_node(); tk_flags |= TK_SEEWS; nxttok(); switch (curtok.tnum) { case '(': defnargs = 0; args = def_rgs(); case WS: goto getval; case NL: goto dodef; default: error("bad #define"); goto flush; } getval: val = def_val(); dodef: def->e_ival = defnargs; define(def, val, args); flush: ; } optdef(s) char *s; { NODEP val; NODEP def; NODEP id_tok(), def_val(); char *as, *strchr(); as = strchr(s, '='); if (as) *as++ = 0; else as = "1"; defnargs = -1; val = NULL; def = id_tok(s); chr_push(as); tk_flags |= TK_SEENL; val = def_val(); tk_flags = 0; def->e_ival = defnargs; define(def, val, NULL); } optundef(s) char *s; { NODEP np, tp, id_tok(); np = id_tok(s); tp = hlook(deflist, np); if (tp != NULL) tp->n_name[0] = '#'; freenode(np); } samedef(p1, p2) NODEP p1, p2; { if (p1->e_ival != p2->e_ival) return 0; return same_list(p1->n_right, p2->n_right); } same_list(p1, p2) NODEP p1, p2; { if (p1 == NULL) return p2 == NULL; if (p2 == NULL) return 0; if (l_cmp(p1, p2, sizeof(*p1)/sizeof(long)) != 0) return 0; return same_list(p1->n_left, p2->n_left); } l_cmp(p1, p2, n) NODE *p1, *p2; { if (xstrcmp(p1,p2) != 0) return 1; if (p1->e_token != p2->e_token || p1->e_ival != p2->e_ival) return 1; return 0; } define(def, val, args) NODEP def, val, args; { NODEP oldp; if (args != NULL) { argsmod(val, args); freenode(args); } def->n_right = val; if ((oldp = hlook(deflist, def)) != NULL) { if (!samedef(oldp, def)) warnn("redefined", def); } #ifdef DEBUG if (debugd) { printf("define (%d args)", (int)def->e_ival); printnode(def); } #endif puthlist(deflist, def); } argsmod(toks, args) NODEP toks, args; { register NODE *np, *vp; for (np=toks; np != NULL; np = np->n_next) if (np->e_token == ID) { vp = llook(args,np); if (vp != NULL) { np->e_token = DPARAM; np->e_ival = vp->e_ival; sprintf(np->n_name, "\\%d", (int)np->e_ival); } } } NODE * def_rgs() { NODE *rv; NODE *tail; NODE *np; rv = NULL; tail = NULL; nxttok(); if (curtok.tnum == ')') { goto out; } more: if (curtok.tnum != ID) { error("expect ID"); goto bad; } np = tok_to_node(); np->e_ival = defnargs; /* hold sequence number */ defnargs++; if (tail == NULL) { /* first one */ rv = np; tail = np; } else { /* more */ tail->n_next = np; tail = np; } nxttok(); if (curtok.tnum == ',') { nxttok(); goto more; } if (curtok.tnum == ')') goto out; error("define arg syntax"); bad: freenode(rv); rv = NULL; defnargs = 0; out: return rv; } NODE * def_val() { NODE *rv; NODE *tail; NODE *np; rv = NULL; tail = NULL; more: nxttok(); if (curtok.tnum == NL) { goto out; /* } else if (curtok.tnum == '\\') { nxttok(); if (curtok.tnum != NL) goto bad; goto more; */ } np = tok_to_node(); if (tail == NULL) { /* first one */ rv = np; tail = np; } else { /* more */ tail->n_next = np; tail = np; } goto more; bad: freenode(rv); rv = NULL; out: return rv; } NODE * gath1(sep) int *sep; { NODE *np, *rv, *tail; int inparen; inparen = 0; rv = NULL; tail = NULL; more: np = hi_node(); if (np == NULL) { goto bad; } switch (np->e_token) { case ')': case ',': if (inparen) { /* dont end, part of subexpr */ if (np->e_token == ')') inparen--; break; } *sep = np->e_token; freenode(np); goto out; case '(': inparen++; break; } if (tail == NULL) { /* first one */ rv = np; tail = np; } else { /* more */ tail->n_next = np; tail = np; } goto more; bad: freenode(rv); rv = NULL; *sep = 0; out: return rv; } NODE * gath_args(n) { NODE *rv; NODE *tail; NODE *np; int sep; int getn; getn = 0; rv = NULL; tail = NULL; np = hi_node(); if (np->e_token != '(') { error("expect ("); goto bad; } freenode(np); if (n == 0) { np = hi_node(); if (np->e_token != ')') { error("expect )"); goto bad; } freenode(np); return NULL; } more: np = gath1(&sep); if (np == NULL) { error("expect arg"); goto bad; } getn++; if (tail == NULL) { /* first one */ rv = np; tail = np; } else { /* more */ tail->n_right = np; tail = np; } if (sep) switch (sep) { case ',': goto more; case ')': if (getn != n) { error("arg num mismatch"); goto bad; } goto out; } error("expand arg syntax"); bad: freenode(rv); rv = NULL; out: return rv; } NODE * argfix(val, args, rt) NODE *val, *args; NODE **rt; { register NODE *scan, *sub; NODE *head; NODE *tail, *back; NODE *rthnode(); NODE *copylist(); head = val; back = NULL; for (scan = val; scan != NULL; back=scan, scan=scan->n_next) if (scan->e_token == DPARAM) { sub = rthnode(args, (int)scan->e_ival); sub = copylist(sub,&tail); if (back) { back->n_next = sub; tail->n_next = scan->n_next; } else { head = sub; tail->n_next = scan->n_next; } scan->n_next = NULL; freenode(scan); scan = tail; } *rt = back; return head; } expand(dp) NODEP dp; { int nargs; NODEP args; register NODEP val; NODEP tail; val = dp->n_right; if (val) val = copylist(val, &tail); nargs = dp->e_ival; if (nargs >= 0) { args = gath_args(nargs); if (args) { if (val) val = argfix(val,args,&tail); freenode(args); } } if (val == NULL) return; #ifdef DEBUG if (debugd > 1) { printf("Expand"); printnode(val); } #endif tail->n_next = holdtok; holdtok = val; } p_undef() { NODEP np, tp; nxttok(); if (curtok.tnum != ID) { error("bad #undef"); goto out; } tp = tok_to_node(); if ((np = hlook(deflist, tp)) != NULL) /* quick and dirty */ np->n_name[0] = '#'; freenode(tp); out: ; } p_inc() { int chkhere; FILE *newf, *srch_open(); char *scopy(), *newnm; tk_flags |= TK_NOESC|TK_LTSTR; nxttok(); switch (curtok.tnum) { case SCON: chkhere = 1; break; case SCON2: chkhere = 0; break; case NL: case EOF: error("bad #include"); return; } newf = srch_open(curstr, chkhere); if (newf == NULL) { fatals("Cant open ", curstr); return; } newnm = scopy(curstr); do nxttok(); while (curtok.tnum != NL); newfile(newf,newnm); } int inclvl; struct svinc { int lineno; FILE *fd; char *filenm; } svincs[MAXINCL]; #if NEEDBUF char p_buf[MAXINCL][BUFSIZ]; #endif static char obuf[MAXSTR]; newfile(fd,s) FILE *fd; char *s; { register struct svinc *p; inclvl++; if (inclvl > MAXINCL) { inclvl--; fclose(fd); error("too many includes"); return; } p = &svincs[inclvl-1]; p->lineno = lineno; p->fd = input; p->filenm = inname; input = fd; lineno = 1; inname = s; #if NEEDBUF setbuf(input, p_buf[inclvl-1]); #endif } endfile() { register struct svinc *p; if (inclvl == 0) return 0; fclose(input); inclvl--; p = &svincs[inclvl]; sfree(inname); input = p->fd; lineno = p->lineno; inname = p->filenm; return 1; } #define MAXIDIR 10 char *srchlist[MAXIDIR] = { "", "\\include\\", "\\sozobon\\include\\", "", 0 }; static int idir_n = 4; /* number of entries in above table */ static int idir_put = 1; /* where to put -I dirs */ optincl(s) char *s; { register char **pp; if (idir_n >= MAXIDIR-1) { warn("too many -I dirs"); return; } for (pp = &srchlist[idir_n]; pp > &srchlist[idir_put]; ) { pp--; pp[1] = pp[0]; } *pp = s; idir_put++; idir_n++; } FILE * srch_open(s, chkhere) char *s; { char **dir; FILE *fd; dir = srchlist; if (chkhere == 0) dir++; while (*dir) { strcpy(obuf, *dir); strcat(obuf, s); fd = fopen(obuf, ROPEN); if (fd != NULL) { return fd; } dir++; } return NULL; } p_if(kind,skipping) { int truth; NODEP tp; if (skipping) { ifnest++; return; } switch (kind) { case 0: truth = if_expr(); break; case 1: case 2: nxttok(); if (curtok.tnum != ID) { error("bad #if(n)def"); goto flush; } tp = tok_to_node(); truth = (hlook(deflist, tp) != NULL); freenode(tp); if (kind == 2) truth = !truth; } iflevel++; iftruth = truth; flush: ; } extern NODE *cur; if_expr() { NODE *tp, *questx(); int rv; advnode(); tp = questx(); if (tp) { rv = conxval(tp); } else rv = 0; if (cur->e_token != NL) { error("bad #if"); } else freenode(cur); return rv; } p_swit(kind,skipping) { if (skipping && ifnest) { if (kind == 1) ifnest--; return; } if (iflevel == 0) { error("not in #if"); goto out; } switch (kind) { case 0: /* else */ iftruth = !iftruth; break; case 1: /* endif */ iflevel--; iftruth = 1; break; } out: ; } p_line() { char *scopy(); nxttok(); if (curtok.tnum != ICON) { error("bad #line"); goto flush; } tk_flags |= TK_NOESC; nxttok(); if (curtok.tnum == SCON) { sfree(inname); inname = scopy(curtok.name); } lineno = curtok.ival; flush: ; } struct cmds { char *name; int (*fun)(); int arg; int skip; } pcmds[] = { {"define", p_def, 0, 1}, {"undef", p_undef, 0, 1}, {"include", p_inc, 0, 1}, {"if", p_if, 0, 0}, {"ifdef", p_if, 1, 0}, {"ifndef", p_if, 2, 0}, {"else", p_swit, 0, 0}, {"endif", p_swit, 1, 0}, {"line", p_line, 0, 1}, {0} }; dopound(skipping) { register struct cmds *p; register char *cname; tk_flags |= TK_SEENL; sawnl = 0; nxttok(); if (curtok.tnum != ID) { error("expect name"); return; } cname = curtok.name; for (p=pcmds; p->name; p++) if (strcmp(p->name, cname) == 0) { if (!skipping || !p->skip) (*p->fun)(p->arg, skipping); tk_flags = 0; if (sawnl == 0) tk_flags |= TK_ONLY1; return; } error("bad # command"); } NODEP tok_to_node() { register struct tok *tp; register NODEP np; tp = &curtok; np = allocnode(); np->e_token = tp->tnum; np->e_flags = tp->flags; if (tp->prec) /* binary op */ np->e_prec = tp->prec; else switch (np->e_token) { case ICON: np->e_ival = tp->ival; break; case FCON: np->e_fval = tp->fval; break; } nscpy(np, tp->name); return np; } NODEP id_tok(s) char *s; { NODEP np; np = allocnode(); np->e_token = ID; nscpy(np, s); return np; }