[BACK]Return to tran.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / awk

Annotation of src/usr.bin/awk/tran.c, Revision 1.1

1.1     ! tholo       1: /****************************************************************
        !             2: Copyright (C) AT&T and Lucent Technologies 1996
        !             3: All Rights Reserved
        !             4:
        !             5: Permission to use, copy, modify, and distribute this software and
        !             6: its documentation for any purpose and without fee is hereby
        !             7: granted, provided that the above copyright notice appear in all
        !             8: copies and that both that the copyright notice and this
        !             9: permission notice and warranty disclaimer appear in supporting
        !            10: documentation, and that the names of AT&T or Lucent Technologies
        !            11: or any of their entities not be used in advertising or publicity
        !            12: pertaining to distribution of the software without specific,
        !            13: written prior permission.
        !            14:
        !            15: AT&T AND LUCENT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
        !            16: SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
        !            17: FITNESS. IN NO EVENT SHALL AT&T OR LUCENT OR ANY OF THEIR
        !            18: ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
        !            19: DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
        !            20: DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
        !            21: OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
        !            22: USE OR PERFORMANCE OF THIS SOFTWARE.
        !            23: ****************************************************************/
        !            24:
        !            25: #define        DEBUG
        !            26: #include <stdio.h>
        !            27: #include <math.h>
        !            28: #include <ctype.h>
        !            29: #include <string.h>
        !            30: #include <stdlib.h>
        !            31: #include "awk.h"
        !            32: #include "awkgram.h"
        !            33:
        !            34: #define        FULLTAB 2       /* rehash when table gets this x full */
        !            35: #define        GROWTAB 4       /* grow table by this factor */
        !            36:
        !            37: Array  *symtab;        /* main symbol table */
        !            38:
        !            39: char   **FS;           /* initial field sep */
        !            40: char   **RS;           /* initial record sep */
        !            41: char   **OFS;          /* output field sep */
        !            42: char   **ORS;          /* output record sep */
        !            43: char   **OFMT;         /* output format for numbers */
        !            44: char   **CONVFMT;      /* format for conversions in getsval */
        !            45: Awkfloat *NF;          /* number of fields in current record */
        !            46: Awkfloat *NR;          /* number of current record */
        !            47: Awkfloat *FNR;         /* number of current record in current file */
        !            48: char   **FILENAME;     /* current filename argument */
        !            49: Awkfloat *ARGC;                /* number of arguments from command line */
        !            50: char   **SUBSEP;       /* subscript separator for a[i,j,k]; default \034 */
        !            51: Awkfloat *RSTART;      /* start of re matched with ~; origin 1 (!) */
        !            52: Awkfloat *RLENGTH;     /* length of same */
        !            53:
        !            54: Cell   *recloc;        /* location of record */
        !            55: Cell   *nrloc;         /* NR */
        !            56: Cell   *nfloc;         /* NF */
        !            57: Cell   *fnrloc;        /* FNR */
        !            58: Array  *ARGVtab;       /* symbol table containing ARGV[...] */
        !            59: Array  *ENVtab;        /* symbol table containing ENVIRON[...] */
        !            60: Cell   *rstartloc;     /* RSTART */
        !            61: Cell   *rlengthloc;    /* RLENGTH */
        !            62: Cell   *symtabloc;     /* SYMTAB */
        !            63:
        !            64: Cell   *nullloc;       /* a guaranteed empty cell */
        !            65: Node   *nullnode;      /* zero&null, converted into a node for comparisons */
        !            66:
        !            67: extern Cell *fldtab;
        !            68:
        !            69: void syminit(void)     /* initialize symbol table with builtin vars */
        !            70: {
        !            71:        setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
        !            72:        /* this is used for if(x)... tests: */
        !            73:        nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
        !            74:        nullnode = valtonode(nullloc, CCON);
        !            75:
        !            76:        /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
        !            77:        /* has been done elsewhere */
        !            78:        recloc = &fldtab[0];
        !            79:        FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
        !            80:        RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
        !            81:        OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
        !            82:        ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
        !            83:        OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
        !            84:        CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
        !            85:        FILENAME = &setsymtab("FILENAME", "-", 0.0, STR|DONTFREE, symtab)->sval;
        !            86:        nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
        !            87:        NF = &nfloc->fval;
        !            88:        nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
        !            89:        NR = &nrloc->fval;
        !            90:        fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
        !            91:        FNR = &fnrloc->fval;
        !            92:        SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
        !            93:        rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
        !            94:        RSTART = &rstartloc->fval;
        !            95:        rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
        !            96:        RLENGTH = &rlengthloc->fval;
        !            97:        symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
        !            98:        symtabloc->sval = (char *) symtab;
        !            99: }
        !           100:
        !           101: void arginit(int ac, char *av[])       /* set up ARGV and ARGC */
        !           102: {
        !           103:        Cell *cp;
        !           104:        int i;
        !           105:        char temp[5];
        !           106:
        !           107:        ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
        !           108:        cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
        !           109:        ARGVtab = makesymtab(NSYMTAB);  /* could be (int) ARGC as well */
        !           110:        cp->sval = (char *) ARGVtab;
        !           111:        for (i = 0; i < ac; i++) {
        !           112:                sprintf((char *)temp, "%d", i);
        !           113:                if (isnumber(*av))
        !           114:                        setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
        !           115:                else
        !           116:                        setsymtab(temp, *av, 0.0, STR, ARGVtab);
        !           117:                av++;
        !           118:        }
        !           119: }
        !           120:
        !           121: void envinit(char **envp)      /* set up ENVIRON variable */
        !           122: {
        !           123:        Cell *cp;
        !           124:        char *p;
        !           125:
        !           126:        cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
        !           127:        ENVtab = makesymtab(NSYMTAB);
        !           128:        cp->sval = (char *) ENVtab;
        !           129:        for ( ; *envp; envp++) {
        !           130:                if ((p = (char *) strchr((char *) *envp, '=')) == NULL)
        !           131:                        continue;
        !           132:                *p++ = 0;       /* split into two strings at = */
        !           133:                if (isnumber(p))
        !           134:                        setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
        !           135:                else
        !           136:                        setsymtab(*envp, p, 0.0, STR, ENVtab);
        !           137:                p[-1] = '=';    /* restore in case env is passed down to a shell */
        !           138:        }
        !           139: }
        !           140:
        !           141: Array *makesymtab(int n)       /* make a new symbol table */
        !           142: {
        !           143:        Array *ap;
        !           144:        Cell **tp;
        !           145:
        !           146:        ap = (Array *) malloc(sizeof(Array));
        !           147:        tp = (Cell **) calloc(n, sizeof(Cell *));
        !           148:        if (ap == NULL || tp == NULL)
        !           149:                ERROR "out of space in makesymtab" FATAL;
        !           150:        ap->nelem = 0;
        !           151:        ap->size = n;
        !           152:        ap->tab = tp;
        !           153:        return(ap);
        !           154: }
        !           155:
        !           156: void freesymtab(Cell *ap)      /* free a symbol table */
        !           157: {
        !           158:        Cell *cp, *temp;
        !           159:        Array *tp;
        !           160:        int i;
        !           161:
        !           162:        if (!isarr(ap))
        !           163:                return;
        !           164:        tp = (Array *) ap->sval;
        !           165:        if (tp == NULL)
        !           166:                return;
        !           167:        for (i = 0; i < tp->size; i++) {
        !           168:                for (cp = tp->tab[i]; cp != NULL; cp = temp) {
        !           169:                        xfree(cp->nval);
        !           170:                        if (freeable(cp))
        !           171:                                xfree(cp->sval);
        !           172:                        temp = cp->cnext;       /* avoids freeing then using */
        !           173:                        free((char *) cp);
        !           174:                }
        !           175:                tp->tab[i] = 0;
        !           176:        }
        !           177:        free((char *) (tp->tab));
        !           178:        free((char *) tp);
        !           179: }
        !           180:
        !           181: void freeelem(Cell *ap, char *s)       /* free elem s from ap (i.e., ap["s"] */
        !           182: {
        !           183:        Array *tp;
        !           184:        Cell *p, *prev = NULL;
        !           185:        int h;
        !           186:
        !           187:        tp = (Array *) ap->sval;
        !           188:        h = hash(s, tp->size);
        !           189:        for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
        !           190:                if (strcmp((char *) s, (char *) p->nval) == 0) {
        !           191:                        if (prev == NULL)       /* 1st one */
        !           192:                                tp->tab[h] = p->cnext;
        !           193:                        else                    /* middle somewhere */
        !           194:                                prev->cnext = p->cnext;
        !           195:                        if (freeable(p))
        !           196:                                xfree(p->sval);
        !           197:                        free(p->nval);
        !           198:                        free((char *) p);
        !           199:                        tp->nelem--;
        !           200:                        return;
        !           201:                }
        !           202: }
        !           203:
        !           204: Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
        !           205: {
        !           206:        int h;
        !           207:        Cell *p;
        !           208:
        !           209:        if (n != NULL && (p = lookup(n, tp)) != NULL) {
        !           210:                dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
        !           211:                        p, p->nval, p->sval, p->fval, p->tval) );
        !           212:                return(p);
        !           213:        }
        !           214:        p = (Cell *) malloc(sizeof(Cell));
        !           215:        if (p == NULL)
        !           216:                ERROR "out of space for symbol table at %s", n FATAL;
        !           217:        p->nval = tostring(n);
        !           218:        p->sval = s ? tostring(s) : tostring("");
        !           219:        p->fval = f;
        !           220:        p->tval = t;
        !           221:        p->csub = CUNK;
        !           222:        p->ctype = OCELL;
        !           223:        tp->nelem++;
        !           224:        if (tp->nelem > FULLTAB * tp->size)
        !           225:                rehash(tp);
        !           226:        h = hash(n, tp->size);
        !           227:        p->cnext = tp->tab[h];
        !           228:        tp->tab[h] = p;
        !           229:        dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
        !           230:                p, p->nval, p->sval, p->fval, p->tval) );
        !           231:        return(p);
        !           232: }
        !           233:
        !           234: int hash(char *s, int n)       /* form hash value for string s */
        !           235: {
        !           236:        unsigned hashval;
        !           237:
        !           238:        for (hashval = 0; *s != '\0'; s++)
        !           239:                hashval = (*s + 31 * hashval);
        !           240:        return hashval % n;
        !           241: }
        !           242:
        !           243: void rehash(Array *tp) /* rehash items in small table into big one */
        !           244: {
        !           245:        int i, nh, nsz;
        !           246:        Cell *cp, *op, **np;
        !           247:
        !           248:        nsz = GROWTAB * tp->size;
        !           249:        np = (Cell **) calloc(nsz, sizeof(Cell *));
        !           250:        if (np == NULL)         /* can't do it, but can keep running. */
        !           251:                return;         /* someone else will run out later. */
        !           252:        for (i = 0; i < tp->size; i++) {
        !           253:                for (cp = tp->tab[i]; cp; cp = op) {
        !           254:                        op = cp->cnext;
        !           255:                        nh = hash(cp->nval, nsz);
        !           256:                        cp->cnext = np[nh];
        !           257:                        np[nh] = cp;
        !           258:                }
        !           259:        }
        !           260:        free((char *) (tp->tab));
        !           261:        tp->tab = np;
        !           262:        tp->size = nsz;
        !           263: }
        !           264:
        !           265: Cell *lookup(char *s, Array *tp)       /* look for s in tp */
        !           266: {
        !           267:        Cell *p, *prev = NULL;
        !           268:        int h;
        !           269:
        !           270:        h = hash(s, tp->size);
        !           271:        for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
        !           272:                if (strcmp((char *) s, (char *) p->nval) == 0)
        !           273:                        return(p);      /* found it */
        !           274:        return(NULL);                   /* not found */
        !           275: }
        !           276:
        !           277: Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
        !           278: {
        !           279:        if ((vp->tval & (NUM | STR)) == 0)
        !           280:                funnyvar(vp, "assign to");
        !           281:        if (vp->tval & FLD) {
        !           282:                donerec = 0;    /* mark $0 invalid */
        !           283:                if (vp-fldtab > *NF)
        !           284:                        newfld(vp-fldtab);
        !           285:                dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
        !           286:        } else if (vp->tval & REC) {
        !           287:                donefld = 0;    /* mark $1... invalid */
        !           288:                donerec = 1;
        !           289:        }
        !           290:        vp->tval &= ~STR;       /* mark string invalid */
        !           291:        vp->tval |= NUM;        /* mark number ok */
        !           292:        dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
        !           293:        return vp->fval = f;
        !           294: }
        !           295:
        !           296: void funnyvar(Cell *vp, char *rw)
        !           297: {
        !           298:        if (vp->tval & ARR)
        !           299:                ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
        !           300:        if (vp->tval & FCN)
        !           301:                ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
        !           302:        ERROR "funny variable %p: n=%s s=\"%s\" f=%g t=%o",
        !           303:                vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
        !           304: }
        !           305:
        !           306: char *setsval(Cell *vp, char *s)       /* set string val of a Cell */
        !           307: {
        !           308:        char *t;
        !           309:
        !           310:        if ((vp->tval & (NUM | STR)) == 0)
        !           311:                funnyvar(vp, "assign to");
        !           312:        if (vp->tval & FLD) {
        !           313:                donerec = 0;    /* mark $0 invalid */
        !           314:                if (vp-fldtab > *NF)
        !           315:                        newfld(vp-fldtab);
        !           316:                dprintf( ("setting field %d to %s (%p)\n", vp-fldtab, s, s) );
        !           317:        } else if (vp->tval & REC) {
        !           318:                donefld = 0;    /* mark $1... invalid */
        !           319:                donerec = 1;
        !           320:        }
        !           321:        t = tostring(s);        /* in case it's self-assign */
        !           322:        vp->tval &= ~NUM;
        !           323:        vp->tval |= STR;
        !           324:        if (freeable(vp))
        !           325:                xfree(vp->sval);
        !           326:        vp->tval &= ~DONTFREE;
        !           327:        dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
        !           328:        return(vp->sval = t);
        !           329: }
        !           330:
        !           331: Awkfloat getfval(Cell *vp)     /* get float val of a Cell */
        !           332: {
        !           333:        if ((vp->tval & (NUM | STR)) == 0)
        !           334:                funnyvar(vp, "read value of");
        !           335:        if ((vp->tval & FLD) && donefld == 0)
        !           336:                fldbld();
        !           337:        else if ((vp->tval & REC) && donerec == 0)
        !           338:                recbld();
        !           339:        if (!isnum(vp)) {       /* not a number */
        !           340:                vp->fval = atof(vp->sval);      /* best guess */
        !           341:                if (isnumber(vp->sval) && !(vp->tval&CON))
        !           342:                        vp->tval |= NUM;        /* make NUM only sparingly */
        !           343:        }
        !           344:        dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
        !           345:        return(vp->fval);
        !           346: }
        !           347:
        !           348: char *getsval(Cell *vp)        /* get string val of a Cell */
        !           349: {
        !           350:        char s[100];
        !           351:        double dtemp;
        !           352:
        !           353:        if ((vp->tval & (NUM | STR)) == 0)
        !           354:                funnyvar(vp, "read value of");
        !           355:        if ((vp->tval & FLD) && donefld == 0)
        !           356:                fldbld();
        !           357:        else if ((vp->tval & REC) && donerec == 0)
        !           358:                recbld();
        !           359:        if ((vp->tval & STR) == 0) {
        !           360:                if (!(vp->tval&DONTFREE))
        !           361:                        xfree(vp->sval);
        !           362:                if (modf(vp->fval, &dtemp) == 0)        /* it's integral */
        !           363:                        sprintf((char *)s, "%.20g", vp->fval);
        !           364:                else
        !           365:                        sprintf((char *)s, (char *)*CONVFMT, vp->fval);
        !           366:                vp->sval = tostring(s);
        !           367:                vp->tval &= ~DONTFREE;
        !           368:                vp->tval |= STR;
        !           369:        }
        !           370:        dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
        !           371:        return(vp->sval);
        !           372: }
        !           373:
        !           374: char *tostring(char *s)        /* make a copy of string s */
        !           375: {
        !           376:        char *p;
        !           377:
        !           378:        p = (char *) malloc(strlen((char *) s)+1);
        !           379:        if (p == NULL)
        !           380:                ERROR "out of space in tostring on %s", s FATAL;
        !           381:        strcpy((char *) p, (char *) s);
        !           382:        return(p);
        !           383: }
        !           384:
        !           385: char *qstring(char *s, int delim)      /* collect string up to next delim */
        !           386: {
        !           387:        int c, n;
        !           388:
        !           389:        for (caddreset(gs); (c = *s) != delim; s++) {
        !           390:                if (c == '\n')
        !           391:                        ERROR "newline in string %.10s...", gs->cbuf SYNTAX;
        !           392:                else if (c != '\\')
        !           393:                        cadd(gs, c);
        !           394:                else    /* \something */
        !           395:                        switch (c = *++s) {
        !           396:                        case '\\':      cadd(gs, '\\'); break;
        !           397:                        case 'n':       cadd(gs, '\n'); break;
        !           398:                        case 't':       cadd(gs, '\t'); break;
        !           399:                        case 'b':       cadd(gs, '\b'); break;
        !           400:                        case 'f':       cadd(gs, '\f'); break;
        !           401:                        case 'r':       cadd(gs, '\r'); break;
        !           402:                        default:
        !           403:                                if (!isdigit(c)) {
        !           404:                                        cadd(gs, c);
        !           405:                                        break;
        !           406:                                }
        !           407:                                n = c - '0';
        !           408:                                if (isdigit(s[1])) {
        !           409:                                        n = 8 * n + *++s - '0';
        !           410:                                        if (isdigit(s[1]))
        !           411:                                                n = 8 * n + *++s - '0';
        !           412:                                }
        !           413:                                cadd(gs, n);
        !           414:                                break;
        !           415:                        }
        !           416:        }
        !           417:        cadd(gs, 0);
        !           418:        return gs->cbuf;
        !           419: }