Research V7 development
authorAlfred V. Aho <aho@research.uucp>
Sun, 6 May 1979 08:30:01 +0000 (03:30 -0500)
committerAlfred V. Aho <aho@research.uucp>
Sun, 6 May 1979 08:30:01 +0000 (03:30 -0500)
Work on file usr/src/cmd/awk/awk.def
Work on file usr/src/cmd/awk/lib.c
Work on file usr/src/cmd/awk/proc.c
Work on file usr/src/cmd/awk/tran.c

Co-Authored-By: Peter J. Weinberger <pjw@research.uucp>
Co-Authored-By: Brian W. Kernighan <bwk@research.uucp>
Synthesized-from: v7

usr/src/cmd/awk/awk.def [new file with mode: 0644]
usr/src/cmd/awk/lib.c [new file with mode: 0644]
usr/src/cmd/awk/proc.c [new file with mode: 0644]
usr/src/cmd/awk/tran.c [new file with mode: 0644]

diff --git a/usr/src/cmd/awk/awk.def b/usr/src/cmd/awk/awk.def
new file mode 100644 (file)
index 0000000..e1d7d5a
--- /dev/null
@@ -0,0 +1,127 @@
+#define        xfree(a)        { if(a!=NULL) yfree(a); a=NULL;}
+#define yfree free
+#ifdef DEBUG
+#      define  dprintf if(dbg)printf
+#else
+#      define  dprintf(x1, x2, x3, x4)
+#endif
+typedef        double  awkfloat;
+
+extern char    **FS;
+extern char    **RS;
+extern char    **ORS;
+extern char    **OFS;
+extern char    **OFMT;
+extern awkfloat *NR;
+extern awkfloat *NF;
+extern char    **FILENAME;
+
+extern char    record[];
+extern int     dbg;
+extern int     lineno;
+extern int     errorflag;
+extern int     donefld;        /* 1 if record broken into fields */
+extern int     donerec;        /* 1 if record is valid (no fld has changed */
+
+typedef struct val {   /* general value during processing */
+       char    *nval;  /* name, for variables only */
+       char    *sval;  /* string value */
+       awkfloat        fval;   /* value as number */
+       unsigned        tval;   /* type info */
+       struct val      *nextval;       /* ptr to next if chained */
+} cell;
+extern cell *symtab[];
+cell   *setsymtab(), *lookup(), **makesymtab();
+
+extern cell    *recloc;        /* location of input record */
+extern cell    *nrloc;         /* NR */
+extern cell    *nfloc;         /* NF */
+
+#define        STR     01      /* string value is valid */
+#define        NUM     02      /* number value is valid */
+#define FLD    04      /* FLD means don't free string space */
+#define        CON     010     /* this is a constant */
+#define        ARR     020     /* this is an array */
+
+awkfloat setfval(), getfval();
+char   *setsval(), *getsval();
+char   *tostring(), *tokname(), *malloc();
+double log(), sqrt(), exp(), atof();
+
+/* function types */
+#define        FLENGTH 1
+#define        FSQRT   2
+#define        FEXP    3
+#define        FLOG    4
+#define        FINT    5
+
+typedef struct {
+       char otype;
+       char osub;
+       cell *optr;
+} obj;
+
+#define BOTCH  1
+struct nd {
+       char ntype;
+       char subtype;
+       struct nd *nnext;
+       int nobj;
+       struct nd *narg[BOTCH]; /* C won't take a zero length array */
+};
+typedef struct nd node;
+extern node    *winner;
+extern node    *nullstat;
+
+/* otypes */
+#define OCELL  0
+#define OEXPR  1
+#define OBOOL  2
+#define OJUMP  3
+
+/* cell subtypes */
+#define CTEMP  4
+#define CNAME  3 
+#define CVAR   2
+#define CFLD   1
+#define CCON   0
+
+/* bool subtypes */
+#define BTRUE  1
+#define BFALSE 2
+
+/* jump subtypes */
+#define JEXIT  1
+#define JNEXT  2
+#define        JBREAK  3
+#define        JCONT   4
+
+/* node types */
+#define NVALUE 1
+#define NSTAT  2
+#define NEXPR  3
+#define NPA2   4
+
+extern obj     (*proctab[])();
+extern obj     true, false;
+extern int     pairstack[], paircnt;
+
+#define cantexec(n)    (n->ntype == NVALUE)
+#define notlegal(n)    (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN]== nullproc)
+#define isexpr(n)      (n->ntype == NEXPR)
+#define isjump(n)      (n.otype == OJUMP)
+#define isexit(n)      (n.otype == OJUMP && n.osub == JEXIT)
+#define        isbreak(n)      (n.otype == OJUMP && n.osub == JBREAK)
+#define        iscont(n)       (n.otype == OJUMP && n.osub == JCONT)
+#define        isnext(n)       (n.otype == OJUMP && n.osub == JNEXT)
+#define isstr(n)       (n.optr->tval & STR)
+#define istrue(n)      (n.otype == OBOOL && n.osub == BTRUE)
+#define istemp(n)      (n.otype == OCELL && n.osub == CTEMP)
+#define isfld(n)       (!donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval==0)
+#define isrec(n)       (donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval!=0)
+obj    nullproc();
+obj    relop();
+
+#define MAXSYM 16
+#define        HAT     0177    /* matches ^ in regular expr */
+                       /* watch out for mach dep */
diff --git a/usr/src/cmd/awk/lib.c b/usr/src/cmd/awk/lib.c
new file mode 100644 (file)
index 0000000..bdc9abb
--- /dev/null
@@ -0,0 +1,274 @@
+#include "stdio.h"
+#include "awk.def"
+#include "awk.h"
+#include "ctype.h"
+
+FILE   *infile = NULL;
+char   *file;
+#define        RECSIZE 512
+char   record[RECSIZE];
+char   fields[RECSIZE];
+
+#define        MAXFLD  50
+int    donefld;        /* 1 = implies rec broken into fields */
+int    donerec;        /* 1 = record is valid (no flds have changed) */
+int    mustfld;        /* 1 = NF seen, so always break*/
+
+#define        FINIT   {0, NULL, 0.0, FLD|STR}
+cell fldtab[MAXFLD] = {        /*room for fields */
+       { "$record", record, 0.0, STR|FLD},
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
+       FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT
+};
+int    maxfld  = 0;    /* last used field */
+
+
+getrec()
+{
+       register char *rr;
+       extern int svargc;
+       extern char **svargv;
+       register c, sep;
+
+       dprintf("**RS=%o, **FS=%o\n", **RS, **FS, NULL);
+       donefld = 0;
+       donerec = 1;
+       record[0] = 0;
+       while (svargc > 0) {
+               dprintf("svargc=%d, *svargv=%s\n", svargc, *svargv, NULL);
+               if (infile == NULL) {   /* have to open a new file */
+                       if (member('=', *svargv)) {     /* it's a var=value argument */
+                               setclvar(*svargv);
+                               svargv++;
+                               svargc--;
+                               continue;
+                       }
+                       *FILENAME = file = *svargv;
+                       dprintf("opening file %s\n", file, NULL, NULL);
+                       if (*file == '-')
+                               infile = stdin;
+                       else if ((infile = fopen(file, "r")) == NULL)
+                               error(FATAL, "can't open %s", file);
+               }
+               if ((sep = **RS) == 0)
+                       sep = '\n';
+               for (rr = record; ; ) {
+                       for (; (c=getc(infile)) != sep && c != EOF; *rr++ = c)
+                               ;
+                       if (**RS == sep || c == EOF)
+                               break;
+                       if ((c = getc(infile)) == '\n' || c == EOF)     /* 2 in a row */
+                               break;
+                       *rr++ = '\n';
+                       *rr++ = c;
+               }
+               if (rr > record+RECSIZE)
+                       error(FATAL, "record `%.20s...' too long", record);
+               *rr = 0;
+               if (mustfld)
+                       fldbld();
+               if (c != EOF)   /* normal record */
+                       return(1);
+               /* EOF arrived on this file; set up next */
+               if (infile != stdin)
+                       fclose(infile);
+               infile = NULL;
+               svargc--;
+               svargv++;
+       }
+       return(0);      /* true end of file */
+}
+
+setclvar(s)    /* set var=value from s */
+char *s;
+{
+       char *p;
+       cell *q;
+
+       for (p=s; *p != '='; p++)
+               ;
+       *p++ = 0;
+       q = setsymtab(s, tostring(p), 0.0, STR, symtab);
+       setsval(q, p);
+       dprintf("command line set %s to |%s|\n", s, p, NULL);
+}
+
+fldbld()
+{
+       register char *r, *fr, sep;
+       int i, j;
+
+       r = record;
+       fr = fields;
+       if ((sep = **FS) == ' ')
+               for (i = 0; ; ) {
+                       while (*r == ' ' || *r == '\t' || *r == '\n')
+                               r++;
+                       if (*r == 0)
+                               break;
+                       i++;
+                       if (i >= MAXFLD)
+                               error(FATAL, "record `%.20s...' has too many fields", record);
+                       if (!(fldtab[i].tval&FLD))
+                               xfree(fldtab[i].sval);
+                       fldtab[i].sval = fr;
+                       fldtab[i].tval = FLD | STR;
+                       do
+                               *fr++ = *r++;
+                       while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
+                       *fr++ = 0;
+               }
+       else
+               for (i = 0; ; ) {
+                       i++;
+                       if (i >= MAXFLD)
+                               error(FATAL, "record `%.20s...' has too many fields", record);
+                       if (!(fldtab[i].tval&FLD))
+                               xfree(fldtab[i].sval);
+                       fldtab[i].sval = fr;
+                       fldtab[i].tval = FLD | STR;
+                       while (*r != sep && *r != '\n' && *r != '\0')   /* \n always a separator */
+                               *fr++ = *r++;
+                       *fr++ = '\0';
+                       if (*r == 0) break;
+                       r++;
+               }
+       *fr = 0;
+       for (j=maxfld; j>i; j--) {      /* clean out junk from previous record */
+               if (!(fldtab[j].tval&FLD))
+                       xfree(fldtab[j].sval);
+               fldtab[j].tval = STR | FLD;
+               fldtab[j].sval = NULL;
+       }
+       maxfld = i;
+       donefld = 1;
+       for(i=1; i<=maxfld; i++)
+               if(isnumber(fldtab[i].sval))
+               {       fldtab[i].fval = atof(fldtab[i].sval);
+                       fldtab[i].tval |= NUM;
+               }
+       setfval(lookup("NF", symtab), (awkfloat) maxfld);
+       if (dbg)
+               for (i = 0; i <= maxfld; i++)
+                       printf("field %d: |%s|\n", i, fldtab[i].sval);
+}
+
+recbld()
+{
+       int i;
+       register char *r, *p;
+
+       if (donefld == 0 || donerec == 1)
+               return;
+       r = record;
+       for (i = 1; i <= *NF; i++) {
+               p = getsval(&fldtab[i]);
+               while (*r++ = *p++)
+                       ;
+               *(r-1) = **OFS;
+       }
+       *(r-1) = '\0';
+       dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
+       recloc->tval = STR | FLD;
+       dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
+       if (r > record+RECSIZE)
+               error(FATAL, "built giant record `%.20s...'", record);
+       dprintf("recbld = |%s|\n", record, NULL, NULL);
+}
+
+cell *fieldadr(n)
+{
+       if (n >= MAXFLD)
+               error(FATAL, "trying to access field %d", n);
+       return(&fldtab[n]);
+}
+
+int    errorflag       = 0;
+
+yyerror(s) char *s; {
+       fprintf(stderr, "awk: %s near line %d\n", s, lineno);
+       errorflag = 2;
+}
+
+error(f, s, a1, a2, a3, a4, a5, a6, a7) {
+       fprintf(stderr, "awk: ");
+       fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
+       fprintf(stderr, "\n");
+       if (*NR > 0)
+               fprintf(stderr, " record number %g\n", *NR);
+       if (f)
+               exit(2);
+}
+
+PUTS(s) char *s; {
+       dprintf("%s\n", s, NULL, NULL);
+}
+
+#define        MAXEXPON        38      /* maximum exponenet for fp number */
+
+isnumber(s)
+register char *s;
+{
+       register d1, d2;
+       int point;
+       char *es;
+
+       d1 = d2 = point = 0;
+       while (*s == ' ' || *s == '\t' || *s == '\n')
+               s++;
+       if (*s == '\0')
+               return(0);      /* empty stuff isn't number */
+       if (*s == '+' || *s == '-')
+               s++;
+       if (!isdigit(*s) && *s != '.')
+               return(0);
+       if (isdigit(*s)) {
+               d1++;
+               do {
+                       s++;
+               } while (isdigit(*s));
+       }
+       if (*s == '.') {
+               point++;
+               s++;
+       }
+       if (d1 == 0 && point == 0)
+               return(0);
+       if (isdigit(*s)) {
+               d2++;
+               do {
+                       s++;
+               } while (isdigit(*s));
+       }
+       if (!(d1 || point && d2))
+               return(0);
+       if (*s == 'e' || *s == 'E') {
+               s++;
+               if (*s == '+' || *s == '-')
+                       s++;
+               if (!isdigit(*s))
+                       return(0);
+               es = s;
+               do {
+                       s++;
+               } while (isdigit(*s));
+               if (s - es > 2)
+                       return(0);
+               else if (s - es == 2 && 10 * (*es-'0') + *(es+1)-'0' >= MAXEXPON)
+                       return(0);
+       }
+       while (*s == ' ' || *s == '\t' || *s == '\n')
+               s++;
+       if (*s == '\0')
+               return(1);
+       else
+               return(0);
+}
+/*
+isnumber(s) char *s; {return(0);}
+*/
diff --git a/usr/src/cmd/awk/proc.c b/usr/src/cmd/awk/proc.c
new file mode 100644 (file)
index 0000000..869e9e9
--- /dev/null
@@ -0,0 +1,82 @@
+#include "awk.h"
+#define NULL 0
+struct xx
+{      int token;
+       char *name;
+       char *pname;
+} proc[] {
+       { PROGRAM, "program", NULL},
+       { BOR, "boolop", " || "},
+       { AND, "boolop", " && "},
+       { NOT, "boolop", " !"},
+       { NE, "relop", " != "},
+       { EQ, "relop", " == "},
+       { LE, "relop", " <= "},
+       { LT, "relop", " < "},
+       { GE, "relop", " >= "},
+       { GT, "relop", " > "},
+       { ARRAY, "array", NULL},
+       { INDIRECT, "indirect", "$("},
+       { SUBSTR, "substr", "substr"},
+       { INDEX, "sindex", "sindex"},
+       { SPRINTF, "asprintf", "sprintf "},
+       { ADD, "arith", " + "},
+       { MINUS, "arith", " - "},
+       { MULT, "arith", " * "},
+       { DIVIDE, "arith", " / "},
+       { MOD, "arith", " % "},
+       { UMINUS, "arith", " -"},
+       { PREINCR, "incrdecr", "++"},
+       { POSTINCR, "incrdecr", "++"},
+       { PREDECR, "incrdecr", "--"},
+       { POSTDECR, "incrdecr", "--"},
+       { CAT, "cat", " "},
+       { PASTAT, "pastat", NULL},
+       { PASTAT2, "dopa2", NULL},
+       { MATCH, "matchop", " ~ "},
+       { NOTMATCH, "matchop", " !~ "},
+       { PRINTF, "aprintf", "printf"},
+       { PRINT, "print", "print"},
+       { SPLIT, "split", "split"},
+       { ASSIGN, "assign", " = "},
+       { ADDEQ, "assign", " += "},
+       { SUBEQ, "assign", " -= "},
+       { MULTEQ, "assign", " *= "},
+       { DIVEQ, "assign", " /= "},
+       { MODEQ, "assign", " %= "},
+       { IF, "ifstat", "if("},
+       { WHILE, "whilestat", "while("},
+       { FOR, "forstat", "for("},
+       { IN, "instat", "instat"},
+       { NEXT, "jump", "next"},
+       { EXIT, "jump", "exit"},
+       { BREAK, "jump", "break"},
+       { CONTINUE, "jump", "continue"},
+       { FNCN, "fncn", "fncn"},
+       { 0, ""},
+};
+#define SIZE   LASTTOKEN - FIRSTTOKEN
+char *table[SIZE];
+char *names[SIZE];
+main()
+{      struct xx *p;
+       int i;
+       printf("#include \"awk.def\"\n");
+       printf("obj nullproc();\n");
+       for(p=proc;p->token!=0;p++)
+               if(p==proc || strcmp(p->name, (p-1)->name))
+                       printf("extern obj %s();\n",p->name);
+       for(p=proc;p->token!=0;p++)
+               table[p->token-FIRSTTOKEN]=p->name;
+       printf("obj (*proctab[%d])() {\n", SIZE);
+       for(i=0;i<SIZE;i++)
+               if(table[i]==0) printf("/*%s*/\tnullproc,\n",tokname(i+FIRSTTOKEN));
+               else printf("/*%s*/\t%s,\n",tokname(i+FIRSTTOKEN),table[i]);
+       printf("};\n");
+       printf("char *printname[%d] {\n", SIZE);
+       for(p=proc; p->token!=0; p++)
+               names[p->token-FIRSTTOKEN] = p->pname;
+       for(i=0; i<SIZE; i++)
+               printf("/*%s*/\t\"%s\",\n",tokname(i+FIRSTTOKEN),names[i]);
+       printf("};\n");
+}
diff --git a/usr/src/cmd/awk/tran.c b/usr/src/cmd/awk/tran.c
new file mode 100644 (file)
index 0000000..b5f7f06
--- /dev/null
@@ -0,0 +1,241 @@
+#include "stdio.h"
+#include "awk.def"
+#include "awk.h"
+
+cell *symtab[MAXSYM];  /* symbol table pointers */
+
+char   **FS;   /* initial field sep */
+char   **RS;   /* initial record sep */
+char   **OFS;  /* output field sep */
+char   **ORS;  /* output record sep */
+char   **OFMT; /*output format for numbers*/
+awkfloat *NF;  /* number of fields in current record */
+awkfloat *NR;  /* number of current record */
+char   **FILENAME;     /* current filename argument */
+
+cell   *recloc;        /* location of record */
+cell   *nrloc;         /* NR */
+cell   *nfloc;         /* NF */
+
+syminit()
+{
+       setsymtab("0", tostring("0"), 0.0, NUM|STR|CON|FLD, symtab);
+       recloc = setsymtab("$record", record, 0.0, STR|FLD, symtab);
+       dprintf("recloc %o lookup %o\n", recloc, lookup("$record", symtab), NULL);
+       FS = &setsymtab("FS", tostring(" "), 0.0, STR|FLD, symtab)->sval;
+       RS = &setsymtab("RS", tostring("\n"), 0.0, STR|FLD, symtab)->sval;
+       OFS = &setsymtab("OFS", tostring(" "), 0.0, STR|FLD, symtab)->sval;
+       ORS = &setsymtab("ORS", tostring("\n"), 0.0, STR|FLD, symtab)->sval;
+       OFMT = &setsymtab("OFMT", tostring("%.6g"), 0.0, STR|FLD, symtab)->sval;
+       FILENAME = &setsymtab("FILENAME", NULL, 0.0, STR|FLD, symtab)->sval;
+       nfloc = setsymtab("NF", NULL, 0.0, NUM, symtab);
+       NF = &nfloc->fval;
+       nrloc = setsymtab("NR", NULL, 0.0, NUM, symtab);
+       NR = &nrloc->fval;
+}
+
+cell **makesymtab()
+{
+       int i;
+       cell **cp;
+
+       cp = (char *) malloc(MAXSYM * sizeof(cell *));
+       if (cp == NULL)
+               error(FATAL, "out of space in makesymtab");
+       for (i = 0; i < MAXSYM; i++)
+               *((cell **) cp + i) = 0;
+       return(cp);
+}
+
+freesymtab(ap) /* free symbol table */
+cell *ap;
+{
+       cell *cp, **tp;
+       int i;
+
+       if (!(ap->tval & ARR))
+               return;
+       tp = (cell **) ap->sval;
+       for (i = 0; i < MAXSYM; i++) {
+               for (cp = tp[i]; cp != NULL; cp = cp->nextval) {
+                       xfree(cp->nval);
+                       xfree(cp->sval);
+                       free(cp);
+               }
+       }
+       xfree(tp);
+}
+
+cell *setsymtab(n, s, f, t, tab)
+char *n, *s;
+awkfloat f;
+unsigned t;
+cell **tab;
+{
+       register h;
+       register cell *p;
+       cell *lookup();
+
+       if (n != NULL && (p = lookup(n, tab)) != NULL) {
+               xfree(s);
+               dprintf("setsymtab found %o: %s", p, p->nval, NULL);
+               dprintf(" %s %g %o\n", p->sval, p->fval, p->tval);
+               return(p);
+       }
+       p = (cell *) malloc(sizeof(cell));
+       if (p == NULL)
+               error(FATAL, "symbol table overflow at %s", n);
+       p->nval = tostring(n);
+       p->sval = s;
+       p->fval = f;
+       p->tval = t;
+       h = hash(n);
+       p->nextval = tab[h];
+       tab[h] = p;
+       dprintf("setsymtab set %o: %s", p, p->nval, NULL);
+       dprintf(" %s %g %o\n", p->sval, p->fval, p->tval);
+       return(p);
+}
+
+hash(s)        /* form hash value for string s */
+register char *s;
+{
+       register int hashval;
+
+       for (hashval = 0; *s != '\0'; )
+               hashval += *s++;
+       return(hashval % MAXSYM);
+}
+
+cell *lookup(s, tab)   /* look for s in tab */
+register char *s;
+cell **tab;
+{
+       register cell *p;
+
+       for (p = tab[hash(s)]; p != NULL; p = p->nextval)
+               if (strcmp(s, p->nval) == 0)
+                       return(p);      /* found it */
+       return(NULL);   /* not found */
+}
+
+awkfloat setfval(vp, f)
+register cell *vp;
+awkfloat f;
+{
+       dprintf("setfval: %o %g\n", vp, f, NULL);
+       checkval(vp);
+       if (vp == recloc)
+               error(FATAL, "can't set $0");
+       vp->tval &= ~STR;       /* mark string invalid */
+       vp->tval |= NUM;        /* mark number ok */
+       if ((vp->tval & FLD) && vp->nval == 0)
+               donerec = 0;
+       return(vp->fval = f);
+}
+
+char *setsval(vp, s)
+register cell *vp;
+char *s;
+{
+       dprintf("setsval: %o %s\n", vp, s, NULL);
+       checkval(vp);
+       if (vp == recloc)
+               error(FATAL, "can't set $0");
+       vp->tval &= ~NUM;
+       vp->tval |= STR;
+       if ((vp->tval & FLD) && vp->nval == 0)
+               donerec = 0;
+       if (!(vp->tval&FLD))
+               xfree(vp->sval);
+       vp->tval &= ~FLD;
+       return(vp->sval = tostring(s));
+}
+
+awkfloat getfval(vp)
+register cell *vp;
+{
+       awkfloat atof();
+
+       if (vp->sval == record && donerec == 0)
+               recbld();
+       dprintf("getfval: %o", vp, NULL, NULL);
+       checkval(vp);
+       if ((vp->tval & NUM) == 0) {
+               /* the problem is to make non-numeric things */
+               /* have unlikely numeric variables, so that */
+               /* $1 == $2 comparisons sort of make sense when */
+               /* one or the other is numeric */
+               if (isnumber(vp->sval)) {
+                       vp->fval = atof(vp->sval);
+                       if (!(vp->tval & CON))  /* don't change type of a constant */
+                               vp->tval |= NUM;
+               }
+               else
+                       vp->fval = 0.0; /* not a very good idea */
+       }
+       dprintf("  %g\n", vp->fval, NULL, NULL);
+       return(vp->fval);
+}
+
+char *getsval(vp)
+register cell *vp;
+{
+       char s[100];
+
+       if (vp->sval == record && donerec == 0)
+               recbld();
+       dprintf("getsval: %o", vp, NULL, NULL);
+       checkval(vp);
+       if ((vp->tval & STR) == 0) {
+               if (!(vp->tval&FLD))
+                       xfree(vp->sval);
+               if ((long)vp->fval==vp->fval)
+                       sprintf(s, "%.20g", vp->fval);
+               else
+                       sprintf(s, *OFMT, vp->fval);
+               vp->sval = tostring(s);
+               vp->tval &= ~FLD;
+               vp->tval |= STR;
+       }
+       dprintf("  %s\n", vp->sval, NULL, NULL);
+       return(vp->sval);
+}
+
+checkval(vp)
+register cell *vp;
+{
+       if (vp->tval & ARR)
+               error(FATAL, "illegal reference to array %s", vp->nval);
+       if ((vp->tval & (NUM | STR)) == 0)
+               error(FATAL, "funny variable %o: %s %s %g %o", vp, vp->nval,
+                       vp->sval, vp->fval, vp->tval);
+}
+
+char *tostring(s)
+register char *s;
+{
+       register char *p;
+
+       p = malloc(strlen(s)+1);
+       if (p == NULL)
+               error(FATAL, "out of space in tostring on %s", s);
+       strcpy(p, s);
+       return(p);
+}
+#ifndef yfree
+yfree(a) char *a;
+{
+       printf("%o\n", a);
+       free(a);
+}
+#endif
+#ifdef malloc
+#undef malloc
+char *ymalloc(u) unsigned u;
+{      char *p;
+       p = malloc(u);
+       printf("%o %o\n", u, p);
+       return(p);
+}
+#endif