tran.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 2.13 */
#define DEBUG
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "awk.h"
#include "y.tab.h"
#define FULLTAB 2 /* rehash when table gets this x full */
#define GROWTAB 4 /* grow table by this factor */
Array *symtab; /* main symbol table */
uchar **FS; /* initial field sep */
uchar **RS; /* initial record sep */
uchar **OFS; /* output field sep */
uchar **ORS; /* output record sep */
uchar **OFMT; /* output format for numbers*/
Awkfloat *NF; /* number of fields in current record */
Awkfloat *NR; /* number of current record */
Awkfloat *FNR; /* number of current record in current file */
uchar **FILENAME; /* current filename argument */
Awkfloat *ARGC; /* number of arguments from command line */
uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
Awkfloat *RLENGTH; /* length of same */
Cell *recloc; /* location of record */
Cell *nrloc; /* NR */
Cell *nfloc; /* NF */
Cell *fnrloc; /* FNR */
Array *ARGVtab; /* symbol table containing ARGV[...] */
Array *ENVtab; /* symbol table containing ENVIRON[...] */
Cell *rstartloc; /* RSTART */
Cell *rlengthloc; /* RLENGTH */
Cell *symtabloc; /* SYMTAB */
Cell *nullloc;
Node *nullnode; /* zero&null, converted into a node for comparisons */
extern Node *valtonode();
extern Cell fldtab[];
extern uchar recdata[];
syminit()
{
int i;
fldtab[0].ctype = OCELL;
fldtab[0].csub = CFLD;
fldtab[0].nval = (uchar*) "$0";
fldtab[0].sval = recdata;
fldtab[0].fval = 0.0;
fldtab[0].tval = REC|STR|DONTFREE;
for (i = 1; i < MAXFLD; i++) {
fldtab[i].ctype = OCELL;
fldtab[i].csub = CFLD;
fldtab[i].nval = NULL;
fldtab[i].sval = (uchar*) "";
fldtab[i].fval = 0.0;
fldtab[i].tval = FLD|STR|DONTFREE;
}
symtab = makesymtab(NSYMTAB);
setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
/* this is used for if(x)... tests: */
nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
nullnode = valtonode(nullloc, CCON);
/* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
recloc = &fldtab[0];
FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
FILENAME = &setsymtab("FILENAME", "-", 0.0, STR|DONTFREE, symtab)->sval;
nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
NF = &nfloc->fval;
nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
NR = &nrloc->fval;
fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
FNR = &fnrloc->fval;
SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
RSTART = &rstartloc->fval;
rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
RLENGTH = &rlengthloc->fval;
symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
symtabloc->sval = (uchar *) symtab;
}
arginit(ac, av)
int ac;
uchar *av[];
{
Cell *cp;
Array *makesymtab();
int i;
uchar temp[5];
for (i = 1; i < ac; i++) /* first make FILENAME first real argument */
if (!isclvar(av[i])) {
setsval(lookup("FILENAME", symtab), av[i]);
break;
}
ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
cp->sval = (uchar *) ARGVtab;
for (i = 0; i < ac; i++) {
sprintf((char *)temp, "%d", i);
if (isnumber(*av))
setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
else
setsymtab(temp, *av, 0.0, STR, ARGVtab);
av++;
}
}
envinit(envp)
uchar *envp[];
{
Cell *cp;
Array *makesymtab();
uchar *p;
cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
ENVtab = makesymtab(NSYMTAB);
cp->sval = (uchar *) ENVtab;
for ( ; *envp; envp++) {
if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL) /* index() on bsd */
continue;
*p++ = 0; /* split into two strings at = */
if (isnumber(p))
setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
else
setsymtab(*envp, p, 0.0, STR, ENVtab);
p[-1] = '='; /* restore in case env is passed down to a shell */
}
}
Array *makesymtab(n)
int n;
{
Array *ap;
Cell **tp;
ap = (Array *) malloc(sizeof(Array));
tp = (Cell **) calloc(n, sizeof(Cell *));
if (ap == NULL || tp == NULL)
ERROR "out of space in makesymtab" FATAL;
ap->nelem = 0;
ap->size = n;
ap->tab = tp;
return(ap);
}
freesymtab(ap) /* free symbol table */
Cell *ap;
{
Cell *cp, *next;
Array *tp;
int i;
if (!isarr(ap))
return;
tp = (Array *) ap->sval;
if (tp == NULL)
return;
for (i = 0; i < tp->size; i++) {
for (cp = tp->tab[i]; cp != NULL; cp = next) {
next = cp->cnext;
xfree(cp->nval);
if (freeable(cp))
xfree(cp->sval);
free(cp);
}
}
free(tp->tab);
free(tp);
}
freeelem(ap, s) /* free elem s from ap (i.e., ap["s"] */
Cell *ap;
uchar *s;
{
Array *tp;
Cell *p, *prev = NULL;
int h;
tp = (Array *) ap->sval;
h = hash(s, tp->size);
for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
if (strcmp((char *) s, (char *) p->nval) == 0) {
if (prev == NULL) /* 1st one */
tp->tab[h] = p->cnext;
else /* middle somewhere */
prev->cnext = p->cnext;
if (freeable(p))
xfree(p->sval);
free(p->nval);
free(p);
tp->nelem--;
return;
}
}
Cell *setsymtab(n, s, f, t, tp)
uchar *n, *s;
Awkfloat f;
unsigned t;
Array *tp;
{
register int h;
register Cell *p;
Cell *lookup();
if (n != NULL && (p = lookup(n, tp)) != NULL) {
dprintf( ("setsymtab found %o: n=%s", p, p->nval) );
dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
return(p);
}
p = (Cell *) malloc(sizeof(Cell));
if (p == NULL)
ERROR "symbol table overflow at %s", n FATAL;
p->nval = tostring(n);
p->sval = s ? tostring(s) : tostring("");
p->fval = f;
p->tval = t;
p->csub = 0;
tp->nelem++;
if (tp->nelem > FULLTAB * tp->size)
rehash(tp);
h = hash(n, tp->size);
p->cnext = tp->tab[h];
tp->tab[h] = p;
dprintf( ("setsymtab set %o: n=%s", p, p->nval) );
dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
return(p);
}
hash(s, n) /* form hash value for string s */
register uchar *s;
int n;
{
register unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = (*s + 31 * hashval);
return hashval % n;
}
rehash(tp) /* rehash items in small table into big one */
Array *tp;
{
int i, nh, nsz;
Cell *cp, *op, **np;
nsz = GROWTAB * tp->size;
np = (Cell **) calloc(nsz, sizeof(Cell *));
if (np == NULL)
ERROR "out of space in rehash" FATAL;
for (i = 0; i < tp->size; i++) {
for (cp = tp->tab[i]; cp; cp = op) {
op = cp->cnext;
nh = hash(cp->nval, nsz);
cp->cnext = np[nh];
np[nh] = cp;
}
}
free(tp->tab);
tp->tab = np;
tp->size = nsz;
}
Cell *lookup(s, tp) /* look for s in tp */
register uchar *s;
Array *tp;
{
register Cell *p, *prev = NULL;
int h;
h = hash(s, tp->size);
for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
if (strcmp((char *) s, (char *) p->nval) == 0)
return(p); /* found it */
return(NULL); /* not found */
}
Awkfloat setfval(vp, f)
register Cell *vp;
Awkfloat f;
{
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "assign to");
if (vp->tval & FLD) {
donerec = 0; /* mark $0 invalid */
if (vp-fldtab > *NF)
newfld(vp-fldtab);
dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
} else if (vp->tval & REC) {
donefld = 0; /* mark $1... invalid */
donerec = 1;
}
vp->tval &= ~STR; /* mark string invalid */
vp->tval |= NUM; /* mark number ok */
dprintf( ("setfval %p: %s = %g, t=%o\n", vp,
vp->nval ? vp->nval : (unsigned char *)"NULL",
f, vp->tval) );
return vp->fval = f;
}
funnyvar(vp, rw)
Cell *vp;
char *rw;
{
if (vp->tval & ARR)
ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
if (vp->tval & FCN)
ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
vp, vp->nval, vp->sval, vp->fval, vp->tval);
}
uchar *setsval(vp, s)
register Cell *vp;
uchar *s;
{
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "assign to");
if (vp->tval & FLD) {
donerec = 0; /* mark $0 invalid */
if (vp-fldtab > *NF)
newfld(vp-fldtab);
dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
} else if (vp->tval & REC) {
donefld = 0; /* mark $1... invalid */
donerec = 1;
}
vp->tval &= ~NUM;
vp->tval |= STR;
if (freeable(vp))
xfree(vp->sval);
vp->tval &= ~DONTFREE;
dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
return(vp->sval = tostring(s));
}
Awkfloat r_getfval(vp)
register Cell *vp;
{
/* if (vp->tval & ARR)
ERROR "illegal reference to array %s", vp->nval FATAL;
return 0.0; */
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "read value of");
if ((vp->tval & FLD) && donefld == 0)
fldbld();
else if ((vp->tval & REC) && donerec == 0)
recbld();
if (!isnum(vp)) { /* not a number */
vp->fval = atof(vp->sval); /* best guess */
if (isnumber(vp->sval) && !(vp->tval&CON))
vp->tval |= NUM; /* make NUM only sparingly */
}
dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
return(vp->fval);
}
uchar *r_getsval(vp)
register Cell *vp;
{
uchar s[100];
/* if (vp->tval & ARR)
ERROR "illegal reference to array %s", vp->nval FATAL;
return ""; */
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "read value of");
if ((vp->tval & FLD) && donefld == 0)
fldbld();
else if ((vp->tval & REC) && donerec == 0)
recbld();
if ((vp->tval & STR) == 0) {
if (!(vp->tval&DONTFREE))
xfree(vp->sval);
if ((long long)vp->fval == vp->fval)
sprintf((char *)s, "%.20g", vp->fval);
else
sprintf((char *)s, (char *)*OFMT, vp->fval);
vp->sval = tostring(s);
vp->tval &= ~DONTFREE;
vp->tval |= STR;
}
dprintf( ("getsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
return(vp->sval);
}
uchar *tostring(s)
register uchar *s;
{
register uchar *p;
p = (uchar *) malloc(strlen((char *) s)+1);
if (p == NULL)
ERROR "out of space in tostring on %s", s FATAL;
strcpy((char *) p, (char *) s);
return(p);
}
uchar *qstring(s, delim) /* collect string up to delim */
uchar *s;
int delim;
{
uchar *q;
int c, n;
for (q = cbuf; (c = *s) != delim; s++) {
if (q >= cbuf + RECSIZE - 1)
ERROR "string %.10s... too long", cbuf SYNTAX;
else if (c == '\n')
ERROR "newline in string %.10s...", cbuf SYNTAX;
else if (c != '\\')
*q++ = c;
else /* \something */
switch (c = *++s) {
case '\\': *q++ = '\\'; break;
case 'n': *q++ = '\n'; break;
case 't': *q++ = '\t'; break;
case 'b': *q++ = '\b'; break;
case 'f': *q++ = '\f'; break;
case 'r': *q++ = '\r'; break;
default:
if (!isdigit(c)) {
*q++ = c;
break;
}
n = c - '0';
if (isdigit(s[1])) {
n = 8 * n + *++s - '0';
if (isdigit(s[1]))
n = 8 * n + *++s - '0';
}
*q++ = n;
break;
}
}
*q = '\0';
return cbuf;
}