Introduction
Introduction Statistics Contact Development Disclaimer Help
added olegfink's patches for adding cal and hoc - 9base - revived minimalist po…
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
commit f61f650899ccc18561eb21fce96e4770508adb71
parent a34055fb4b74b06c01e0e0f9623eba002bda6ef1
Author: Anselm R Garbe <[email protected]>
Date: Mon, 10 Aug 2009 15:04:03 +0100
added olegfink's patches for adding cal and hoc
Diffstat:
M Makefile | 8 ++++----
A cal/Makefile | 6 ++++++
A cal/cal.1 | 46 +++++++++++++++++++++++++++++…
A cal/cal.c | 313 +++++++++++++++++++++++++++++…
A hoc/Makefile | 9 +++++++++
A hoc/code.c | 666 +++++++++++++++++++++++++++++…
A hoc/hoc.1 | 144 +++++++++++++++++++++++++++++…
A hoc/hoc.h | 83 +++++++++++++++++++++++++++++…
A hoc/hoc.y | 398 +++++++++++++++++++++++++++++…
A hoc/init.c | 69 ++++++++++++++++++++++++++++++
A hoc/math.c | 75 +++++++++++++++++++++++++++++…
A hoc/symbol.c | 55 +++++++++++++++++++++++++++++…
12 files changed, 1868 insertions(+), 4 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -1,10 +1,10 @@
-# 9base - awk basename cat cleanname echo grep rc sed seq sleep sort tee
-# test touch tr uniq from Plan 9
+# 9base - awk basename cal cat cleanname echo grep rc sed seq sleep
+# hoc sort tee test touch tr uniq from Plan 9
include config.mk
-SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \
- rc read sed seq sleep sort tee test touch tr uniq
+SUBDIRS = lib9 yacc awk basename bc dc cal cat cleanname date echo grep ls \
+ hoc rc read sed seq sleep sort tee test touch tr uniq
all:
@echo 9base build options:
diff --git a/cal/Makefile b/cal/Makefile
@@ -0,0 +1,6 @@
+# cal - cal unix port from plan9
+# Depends on ../lib9
+
+TARG = cal
+
+include ../std.mk
diff --git a/cal/cal.1 b/cal/cal.1
@@ -0,0 +1,46 @@
+.TH CAL 1
+.SH NAME
+cal \- print calendar
+.SH SYNOPSIS
+.B cal
+[
+.I month
+]
+[
+.I year
+]
+.SH DESCRIPTION
+.I Cal
+prints a calendar.
+.I Month
+is either a number from 1 to 12,
+a lower case month name,
+or a lower case three-letter prefix of a month name.
+.I Year
+can be between 1
+and 9999.
+If either
+.I month
+or
+.I year
+is omitted, the current month or year is used.
+If only one argument is given, and it is a number larger than 12,
+a calendar for all twelve months of the given year is produced;
+otherwise a calendar for just one month is printed.
+The calendar
+produced is that for England and her colonies.
+.PP
+Try
+.EX
+ cal sep 1752
+.EE
+.SH SOURCE
+.B \*9/src/cmd/cal.c
+.SH BUGS
+The year is always considered to start in January even though this
+is historically naive.
+.PP
+Beware that
+.L "cal 90"
+refers to the early Christian era,
+not the 20th century.
diff --git a/cal/cal.c b/cal/cal.c
@@ -0,0 +1,313 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+char dayw[] =
+{
+ " S M Tu W Th F S"
+};
+char *smon[] =
+{
+ "January", "February", "March", "April",
+ "May", "June", "July", "August",
+ "September", "October", "November", "December",
+};
+char mon[] =
+{
+ 0,
+ 31, 29, 31, 30,
+ 31, 30, 31, 31,
+ 30, 31, 30, 31,
+};
+char string[432];
+Biobuf bout;
+
+void main(int argc, char *argv[]);
+int number(char *str);
+void pstr(char *str, int n);
+void cal(int m, int y, char *p, int w);
+int jan1(int yr);
+int curmo(void);
+int curyr(void);
+
+void
+main(int argc, char *argv[])
+{
+ int y, i, j, m;
+
+ if(argc > 3) {
+ fprint(2, "usage: cal [month] [year]\n");
+ exits("usage");
+ }
+ Binit(&bout, 1, OWRITE);
+
+/*
+ * no arg, print current month
+ */
+ if(argc == 1) {
+ m = curmo();
+ y = curyr();
+ goto xshort;
+ }
+
+/*
+ * one arg
+ * if looks like a month, print month
+ * else print year
+ */
+ if(argc == 2) {
+ y = number(argv[1]);
+ if(y < 0)
+ y = -y;
+ if(y >= 1 && y <= 12) {
+ m = y;
+ y = curyr();
+ goto xshort;
+ }
+ goto xlong;
+ }
+
+/*
+ * two arg, month and year
+ */
+ m = number(argv[1]);
+ if(m < 0)
+ m = -m;
+ y = number(argv[2]);
+ goto xshort;
+
+/*
+ * print out just month
+ */
+xshort:
+ if(m < 1 || m > 12)
+ goto badarg;
+ if(y < 1 || y > 9999)
+ goto badarg;
+ Bprint(&bout, " %s %u\n", smon[m-1], y);
+ Bprint(&bout, "%s\n", dayw);
+ cal(m, y, string, 24);
+ for(i=0; i<6*24; i+=24)
+ pstr(string+i, 24);
+ exits(0);
+
+/*
+ * print out complete year
+ */
+xlong:
+ y = number(argv[1]);
+ if(y<1 || y>9999)
+ goto badarg;
+ Bprint(&bout, "\n\n\n");
+ Bprint(&bout, " %u\n", y);
+ Bprint(&bout, "\n");
+ for(i=0; i<12; i+=3) {
+ for(j=0; j<6*72; j++)
+ string[j] = '\0';
+ Bprint(&bout, " %.3s", smon[i]);
+ Bprint(&bout, " %.3s", smon[i+1]);
+ Bprint(&bout, " %.3s\n", smon[i+2]);
+ Bprint(&bout, "%s %s %s\n", dayw, dayw, dayw);
+ cal(i+1, y, string, 72);
+ cal(i+2, y, string+23, 72);
+ cal(i+3, y, string+46, 72);
+ for(j=0; j<6*72; j+=72)
+ pstr(string+j, 72);
+ }
+ Bprint(&bout, "\n\n\n");
+ exits(0);
+
+badarg:
+ Bprint(&bout, "cal: bad argument\n");
+}
+
+struct
+{
+ char* word;
+ int val;
+} dict[] =
+{
+ "jan", 1,
+ "january", 1,
+ "feb", 2,
+ "february", 2,
+ "mar", 3,
+ "march", 3,
+ "apr", 4,
+ "april", 4,
+ "may", 5,
+ "jun", 6,
+ "june", 6,
+ "jul", 7,
+ "july", 7,
+ "aug", 8,
+ "august", 8,
+ "sep", 9,
+ "sept", 9,
+ "september", 9,
+ "oct", 10,
+ "october", 10,
+ "nov", 11,
+ "november", 11,
+ "dec", 12,
+ "december", 12,
+ 0
+};
+
+/*
+ * convert to a number.
+ * if its a dictionary word,
+ * return negative number
+ */
+int
+number(char *str)
+{
+ int n, c;
+ char *s;
+
+ for(n=0; s=dict[n].word; n++)
+ if(strcmp(s, str) == 0)
+ return -dict[n].val;
+ n = 0;
+ s = str;
+ while(c = *s++) {
+ if(c<'0' || c>'9')
+ return 0;
+ n = n*10 + c-'0';
+ }
+ return n;
+}
+
+void
+pstr(char *str, int n)
+{
+ int i;
+ char *s;
+
+ s = str;
+ i = n;
+ while(i--)
+ if(*s++ == '\0')
+ s[-1] = ' ';
+ i = n+1;
+ while(i--)
+ if(*--s != ' ')
+ break;
+ s[1] = '\0';
+ Bprint(&bout, "%s\n", str);
+}
+
+void
+cal(int m, int y, char *p, int w)
+{
+ int d, i;
+ char *s;
+
+ s = p;
+ d = jan1(y);
+ mon[2] = 29;
+ mon[9] = 30;
+
+ switch((jan1(y+1)+7-d)%7) {
+
+ /*
+ * non-leap year
+ */
+ case 1:
+ mon[2] = 28;
+ break;
+
+ /*
+ * 1752
+ */
+ default:
+ mon[9] = 19;
+ break;
+
+ /*
+ * leap year
+ */
+ case 2:
+ ;
+ }
+ for(i=1; i<m; i++)
+ d += mon[i];
+ d %= 7;
+ s += 3*d;
+ for(i=1; i<=mon[m]; i++) {
+ if(i==3 && mon[m]==19) {
+ i += 11;
+ mon[m] += 11;
+ }
+ if(i > 9)
+ *s = i/10+'0';
+ s++;
+ *s++ = i%10+'0';
+ s++;
+ if(++d == 7) {
+ d = 0;
+ s = p+w;
+ p = s;
+ }
+ }
+}
+
+/*
+ * return day of the week
+ * of jan 1 of given year
+ */
+int
+jan1(int yr)
+{
+ int y, d;
+
+/*
+ * normal gregorian calendar
+ * one extra day per four years
+ */
+
+ y = yr;
+ d = 4+y+(y+3)/4;
+
+/*
+ * julian calendar
+ * regular gregorian
+ * less three days per 400
+ */
+
+ if(y > 1800) {
+ d -= (y-1701)/100;
+ d += (y-1601)/400;
+ }
+
+/*
+ * great calendar changeover instant
+ */
+
+ if(y > 1752)
+ d += 3;
+
+ return d%7;
+}
+
+/*
+ * system dependent
+ * get current month and year
+ */
+int
+curmo(void)
+{
+ Tm *tm;
+
+ tm = localtime(time(0));
+ return tm->mon+1;
+}
+
+int
+curyr(void)
+{
+ Tm *tm;
+
+ tm = localtime(time(0));
+ return tm->year+1900;
+}
diff --git a/hoc/Makefile b/hoc/Makefile
@@ -0,0 +1,9 @@
+# hoc - hoc unix port from plan9
+# Depends on ../lib9
+
+TARG = hoc
+OFILES = y.tab.o init.o code.o math.o symbol.o
+YFILES = hoc.y
+MANFILES = hoc.1
+
+include ../yacc.mk
diff --git a/hoc/code.c b/hoc/code.c
@@ -0,0 +1,666 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "hoc.h"
+#include "y.tab.h"
+
+#define NSTACK 256
+
+static Datum stack[NSTACK]; /* the stack */
+static Datum *stackp; /* next free spot on stack */
+
+#define NPROG 2000
+Inst prog[NPROG]; /* the machine */
+Inst *progp; /* next free spot for code generation */
+Inst *pc; /* program counter during execution */
+Inst *progbase = prog; /* start of current subprogram */
+int returning; /* 1 if return stmt seen */
+int indef; /* 1 if parsing a func or proc */
+
+typedef struct Frame { /* proc/func call stack frame */
+ Symbol *sp; /* symbol table entry */
+ Inst *retpc; /* where to resume after return */
+ Datum *argn; /* n-th argument on stack */
+ int nargs; /* number of arguments */
+} Frame;
+#define NFRAME 100
+Frame frame[NFRAME];
+Frame *fp; /* frame pointer */
+
+void
+initcode(void)
+{
+ progp = progbase;
+ stackp = stack;
+ fp = frame;
+ returning = 0;
+ indef = 0;
+}
+
+void
+nop(void)
+{
+}
+
+void
+push(Datum d)
+{
+ if (stackp >= &stack[NSTACK])
+ execerror("stack too deep", 0);
+ *stackp++ = d;
+}
+
+Datum
+pop(void)
+{
+ if (stackp == stack)
+ execerror("stack underflow", 0);
+ return *--stackp;
+}
+
+void
+xpop(void) /* for when no value is wanted */
+{
+ if (stackp == stack)
+ execerror("stack underflow", (char *)0);
+ --stackp;
+}
+
+void
+constpush(void)
+{
+ Datum d;
+ d.val = ((Symbol *)*pc++)->u.val;
+ push(d);
+}
+
+void
+varpush(void)
+{
+ Datum d;
+ d.sym = (Symbol *)(*pc++);
+ push(d);
+}
+
+void
+whilecode(void)
+{
+ Datum d;
+ Inst *savepc = pc;
+
+ execute(savepc+2); /* condition */
+ d = pop();
+ while (d.val) {
+ execute(*((Inst **)(savepc))); /* body */
+ if (returning)
+ break;
+ execute(savepc+2); /* condition */
+ d = pop();
+ }
+ if (!returning)
+ pc = *((Inst **)(savepc+1)); /* next stmt */
+}
+
+void
+forcode(void)
+{
+ Datum d;
+ Inst *savepc = pc;
+
+ execute(savepc+4); /* precharge */
+ pop();
+ execute(*((Inst **)(savepc))); /* condition */
+ d = pop();
+ while (d.val) {
+ execute(*((Inst **)(savepc+2))); /* body */
+ if (returning)
+ break;
+ execute(*((Inst **)(savepc+1))); /* post loop */
+ pop();
+ execute(*((Inst **)(savepc))); /* condition */
+ d = pop();
+ }
+ if (!returning)
+ pc = *((Inst **)(savepc+3)); /* next stmt */
+}
+
+void
+ifcode(void)
+{
+ Datum d;
+ Inst *savepc = pc; /* then part */
+
+ execute(savepc+3); /* condition */
+ d = pop();
+ if (d.val)
+ execute(*((Inst **)(savepc)));
+ else if (*((Inst **)(savepc+1))) /* else part? */
+ execute(*((Inst **)(savepc+1)));
+ if (!returning)
+ pc = *((Inst **)(savepc+2)); /* next stmt */
+}
+
+void
+define(Symbol* sp, Formal *f) /* put func/proc in symbol table */
+{
+ Fndefn *fd;
+ int n;
+
+ fd = emalloc(sizeof(Fndefn));
+ fd->code = progbase; /* start of code */
+ progbase = progp; /* next code starts here */
+ fd->formals = f;
+ for(n=0; f; f=f->next)
+ n++;
+ fd->nargs = n;
+ sp->u.defn = fd;
+}
+
+void
+call(void) /* call a function */
+{
+ Formal *f;
+ Datum *arg;
+ Saveval *s;
+ int i;
+
+ Symbol *sp = (Symbol *)pc[0]; /* symbol table entry */
+ /* for function */
+ if (fp >= &frame[NFRAME])
+ execerror(sp->name, "call nested too deeply");
+ fp++;
+ fp->sp = sp;
+ fp->nargs = (int)(uintptr)pc[1];
+ fp->retpc = pc + 2;
+ fp->argn = stackp - 1; /* last argument */
+ if(fp->nargs != sp->u.defn->nargs)
+ execerror(sp->name, "called with wrong number of arguments");
+ /* bind formals */
+ f = sp->u.defn->formals;
+ arg = stackp - fp->nargs;
+ while(f){
+ s = emalloc(sizeof(Saveval));
+ s->val = f->sym->u;
+ s->type = f->sym->type;
+ s->next = f->save;
+ f->save = s;
+ f->sym->u.val = arg->val;
+ f->sym->type = VAR;
+ f = f->next;
+ arg++;
+ }
+ for (i = 0; i < fp->nargs; i++)
+ pop(); /* pop arguments; no longer needed */
+ execute(sp->u.defn->code);
+ returning = 0;
+}
+
+void
+restore(Symbol *sp) /* restore formals associated with symbol */
+{
+ Formal *f;
+ Saveval *s;
+
+ f = sp->u.defn->formals;
+ while(f){
+ s = f->save;
+ if(s == 0) /* more actuals than formals */
+ break;
+ f->sym->u = s->val;
+ f->sym->type = s->type;
+ f->save = s->next;
+ free(s);
+ f = f->next;
+ }
+}
+
+void
+restoreall(void) /* restore all variables in case of error */
+{
+ while(fp>=frame && fp->sp){
+ restore(fp->sp);
+ --fp;
+ }
+ fp = frame;
+}
+
+static void
+ret(void) /* common return from func or proc */
+{
+ /* restore formals */
+ restore(fp->sp);
+ pc = (Inst *)fp->retpc;
+ --fp;
+ returning = 1;
+}
+
+void
+funcret(void) /* return from a function */
+{
+ Datum d;
+ if (fp->sp->type == PROCEDURE)
+ execerror(fp->sp->name, "(proc) returns value");
+ d = pop(); /* preserve function return value */
+ ret();
+ push(d);
+}
+
+void
+procret(void) /* return from a procedure */
+{
+ if (fp->sp->type == FUNCTION)
+ execerror(fp->sp->name,
+ "(func) returns no value");
+ ret();
+}
+
+void
+bltin(void)
+{
+
+ Datum d;
+ d = pop();
+ d.val = (*(double (*)(double))*pc++)(d.val);
+ push(d);
+}
+
+void
+add(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val += d2.val;
+ push(d1);
+}
+
+void
+sub(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val -= d2.val;
+ push(d1);
+}
+
+void
+mul(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val *= d2.val;
+ push(d1);
+}
+
+void
+div(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ if (d2.val == 0.0)
+ execerror("division by zero", (char *)0);
+ d1 = pop();
+ d1.val /= d2.val;
+ push(d1);
+}
+
+void
+mod(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ if (d2.val == 0.0)
+ execerror("division by zero", (char *)0);
+ d1 = pop();
+ /* d1.val %= d2.val; */
+ d1.val = fmod(d1.val, d2.val);
+ push(d1);
+}
+
+void
+negate(void)
+{
+ Datum d;
+ d = pop();
+ d.val = -d.val;
+ push(d);
+}
+
+void
+verify(Symbol* s)
+{
+ if (s->type != VAR && s->type != UNDEF)
+ execerror("attempt to evaluate non-variable", s->name);
+ if (s->type == UNDEF)
+ execerror("undefined variable", s->name);
+}
+
+void
+eval(void) /* evaluate variable on stack */
+{
+ Datum d;
+ d = pop();
+ verify(d.sym);
+ d.val = d.sym->u.val;
+ push(d);
+}
+
+void
+preinc(void)
+{
+ Datum d;
+ d.sym = (Symbol *)(*pc++);
+ verify(d.sym);
+ d.val = d.sym->u.val += 1.0;
+ push(d);
+}
+
+void
+predec(void)
+{
+ Datum d;
+ d.sym = (Symbol *)(*pc++);
+ verify(d.sym);
+ d.val = d.sym->u.val -= 1.0;
+ push(d);
+}
+
+void
+postinc(void)
+{
+ Datum d;
+ double v;
+ d.sym = (Symbol *)(*pc++);
+ verify(d.sym);
+ v = d.sym->u.val;
+ d.sym->u.val += 1.0;
+ d.val = v;
+ push(d);
+}
+
+void
+postdec(void)
+{
+ Datum d;
+ double v;
+ d.sym = (Symbol *)(*pc++);
+ verify(d.sym);
+ v = d.sym->u.val;
+ d.sym->u.val -= 1.0;
+ d.val = v;
+ push(d);
+}
+
+void
+gt(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val > d2.val);
+ push(d1);
+}
+
+void
+lt(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val < d2.val);
+ push(d1);
+}
+
+void
+ge(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val >= d2.val);
+ push(d1);
+}
+
+void
+le(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val <= d2.val);
+ push(d1);
+}
+
+void
+eq(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val == d2.val);
+ push(d1);
+}
+
+void
+ne(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val != d2.val);
+ push(d1);
+}
+
+void
+and(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val != 0.0 && d2.val != 0.0);
+ push(d1);
+}
+
+void
+or(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = (double)(d1.val != 0.0 || d2.val != 0.0);
+ push(d1);
+}
+
+void
+not(void)
+{
+ Datum d;
+ d = pop();
+ d.val = (double)(d.val == 0.0);
+ push(d);
+}
+
+void
+power(void)
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val = Pow(d1.val, d2.val);
+ push(d1);
+}
+
+void
+assign(void)
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ d1.sym->u.val = d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+}
+
+void
+addeq(void)
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ d2.val = d1.sym->u.val += d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+}
+
+void
+subeq(void)
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ d2.val = d1.sym->u.val -= d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+}
+
+void
+muleq(void)
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ d2.val = d1.sym->u.val *= d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+}
+
+void
+diveq(void)
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ d2.val = d1.sym->u.val /= d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+}
+
+void
+ppush(Datum *d)
+{
+ push(*d);
+}
+
+void
+modeq(void)
+{
+ Datum d1, d2;
+ long x;
+
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable",
+ d1.sym->name);
+ /* d2.val = d1.sym->u.val %= d2.val; */
+ x = d1.sym->u.val;
+ x %= (long) d2.val;
+ d2.val = x;
+ d1.sym->u.val = x;
+ d1.sym->type = VAR;
+
+ /* push(d2) generates a compiler error on Linux w. gcc 2.95.4 */
+ ppush(&d2);
+}
+
+void
+printtop(void) /* pop top value from stack, print it */
+{
+ Datum d;
+ static Symbol *s; /* last value computed */
+ if (s == 0)
+ s = install("_", VAR, 0.0);
+ d = pop();
+ print("%.17g\n", d.val);
+ s->u.val = d.val;
+}
+
+void
+prexpr(void) /* print numeric value */
+{
+ Datum d;
+ d = pop();
+ print("%.17g ", d.val);
+}
+
+void
+prstr(void) /* print string value */
+{
+ print("%s", (char *) *pc++);
+}
+
+void
+varread(void) /* read into variable */
+{
+ Datum d;
+ extern Biobuf *bin;
+ Symbol *var = (Symbol *) *pc++;
+ int c;
+
+ Again:
+ do
+ c = Bgetc(bin);
+ while(c==' ' || c=='\t');
+ if(c == Beof){
+ Iseof:
+ if(moreinput())
+ goto Again;
+ d.val = var->u.val = 0.0;
+ goto Return;
+ }
+
+ if(strchr("+-.0123456789", c) == 0)
+ execerror("non-number read into", var->name);
+ Bungetc(bin);
+ if(Bgetd(bin, &var->u.val) == Beof)
+ goto Iseof;
+ else
+ d.val = 1.0;
+ Return:
+ var->type = VAR;
+ push(d);
+}
+
+Inst*
+code(Inst f) /* install one instruction or operand */
+{
+ Inst *oprogp = progp;
+ if (progp >= &prog[NPROG])
+ execerror("program too big", (char *)0);
+ *progp++ = f;
+ return oprogp;
+}
+
+void
+execute(Inst* p)
+{
+ for (pc = p; *pc != STOP && !returning; )
+ (*((++pc)[-1]))();
+}
diff --git a/hoc/hoc.1 b/hoc/hoc.1
@@ -0,0 +1,144 @@
+.TH HOC 1
+.SH NAME
+hoc \- interactive floating point language
+.SH SYNOPSIS
+.B hoc
+[
+.I file ...
+]
+[
+.B -e
+.I expression
+]
+.SH DESCRIPTION
+.I Hoc
+interprets a simple language for floating point arithmetic,
+at about the level of BASIC, with C-like syntax and
+functions.
+.PP
+The named
+.I files
+are read and interpreted in order.
+If no
+.I file
+is given or if
+.I file
+is
+.L -
+.I hoc
+interprets the standard input.
+The
+.B -e
+option allows input to
+.I hoc
+to be specified on the command line, to be treated as if it appeared in a file.
+.PP
+.I Hoc
+input consists of
+.I expressions
+and
+.IR statements .
+Expressions are evaluated and their results printed.
+Statements, typically assignments and function or procedure
+definitions, produce no output unless they explicitly call
+.IR print .
+.PP
+Variable names have the usual syntax, including
+.LR _ ;
+the name
+.L _
+by itself contains the value of the last expression evaluated.
+The variables
+.BR E ,
+.BR PI ,
+.BR PHI ,
+.BR GAMMA
+and
+.B DEG
+are predefined; the last is 59.25..., degrees per radian.
+.PP
+Expressions are formed with these C-like operators, listed by
+decreasing precedence.
+.TP
+.B ^
+exponentiation
+.TP
+.B ! - ++ --
+.TP
+.B * / %
+.TP
+.B + -
+.TP
+.B > >= < <= == !=
+.TP
+.B &&
+.TP
+.B ||
+.TP
+.B = += -= *= /= %=
+.PP
+Built in functions are
+.BR abs ,
+.BR acos ,
+.BR asin ,
+.B atan
+(one argument),
+.BR cos ,
+.BR cosh ,
+.BR exp ,
+.BR int ,
+.BR log ,
+.BR log10 ,
+.BR sin ,
+.BR sinh ,
+.BR sqrt ,
+.BR tan ,
+and
+.BR tanh .
+The function
+.B read(x)
+reads a value into the variable
+.B x
+and returns 0 at EOF;
+the statement
+.B print
+prints a list of expressions that may include
+string constants such as
+\fL"hello\en"\f1.\fP
+.PP
+Control flow statements are
+.BR if - else ,
+.BR while ,
+and
+.BR for ,
+with braces for grouping.
+Newline ends a statement.
+Backslash-newline is equivalent to a space.
+.PP
+Functions and procedures are introduced by the words
+.B func
+and
+.BR proc ;
+.B return
+is used to return with a value from a function.
+.SH EXAMPLES
+.EX
+func gcd(a, b) {
+ temp = abs(a) % abs(b)
+ if(temp == 0) return abs(b)
+ return gcd(b, temp)
+}
+for(i=1; i<12; i++) print gcd(i,12)
+.EE
+.SH SOURCE
+.B \*9/src/cmd/hoc
+.SH "SEE ALSO"
+.IR bc (1),
+.IR dc (1)
+.br
+B. W. Kernighan and R. Pike,
+.I
+The Unix Programming Environment,
+Prentice-Hall, 1984
+.SH BUGS
+Error recovery is imperfect within function and procedure definitions.
diff --git a/hoc/hoc.h b/hoc/hoc.h
@@ -0,0 +1,83 @@
+typedef void (*Inst)(void);
+#define STOP (Inst) 0
+
+typedef struct Symbol Symbol;
+typedef union Datum Datum;
+typedef struct Formal Formal;
+typedef struct Saveval Saveval;
+typedef struct Fndefn Fndefn;
+typedef union Symval Symval;
+
+union Symval { /* value of a symbol */
+ double val; /* VAR */
+ double (*ptr)(double); /* BLTIN */
+ Fndefn *defn; /* FUNCTION, PROCEDURE */
+ char *str; /* STRING */
+};
+
+struct Symbol { /* symbol table entry */
+ char *name;
+ long type;
+ Symval u;
+ struct Symbol *next; /* to link to another */
+};
+Symbol *install(char*, int, double), *lookup(char*);
+
+union Datum { /* interpreter stack type */
+ double val;
+ Symbol *sym;
+};
+
+struct Saveval { /* saved value of variable */
+ Symval val;
+ long type;
+ Saveval *next;
+};
+
+struct Formal { /* formal parameter */
+ Symbol *sym;
+ Saveval *save;
+ Formal *next;
+};
+
+struct Fndefn { /* formal parameter */
+ Inst *code;
+ Formal *formals;
+ int nargs;
+};
+
+extern Formal *formallist(Symbol*, Formal*);
+extern double Fgetd(int);
+extern int moreinput(void);
+extern void restore(Symbol*);
+extern void restoreall(void);
+extern void execerror(char*, char*);
+extern void define(Symbol*, Formal*), verify(Symbol*);
+extern Datum pop(void);
+extern void initcode(void), push(Datum), xpop(void), constpush(void);
+extern void varpush(void);
+#define div hocdiv
+extern void eval(void), add(void), sub(void), mul(void), div(void), mod…
+extern void negate(void), power(void);
+extern void addeq(void), subeq(void), muleq(void), diveq(void), modeq(v…
+
+extern Inst *progp, *progbase, prog[], *code(Inst);
+extern void assign(void), bltin(void), varread(void);
+extern void prexpr(void), prstr(void);
+extern void gt(void), lt(void), eq(void), ge(void), le(void), ne(void);
+extern void and(void), or(void), not(void);
+extern void ifcode(void), whilecode(void), forcode(void);
+extern void call(void), arg(void), argassign(void);
+extern void funcret(void), procret(void);
+extern void preinc(void), predec(void), postinc(void), postdec(void);
+extern void execute(Inst*);
+extern void printtop(void);
+
+extern double Log(double), Log10(double), Gamma(double), Sqrt(double), …
+extern double Asin(double), Acos(double), Sinh(double), Cosh(double), i…
+extern double Pow(double, double);
+
+extern void init(void);
+extern int yyparse(void);
+extern void execerror(char*, char*);
+extern void *emalloc(unsigned);
diff --git a/hoc/hoc.y b/hoc/hoc.y
@@ -0,0 +1,398 @@
+%{
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "hoc.h"
+#define code2(c1,c2) code(c1); code(c2)
+#define code3(c1,c2,c3) code(c1); code(c2); code(c3)
+%}
+%union {
+ Symbol *sym; /* symbol table pointer */
+ Inst *inst; /* machine instruction */
+ int narg; /* number of arguments */
+ Formal *formals; /* list of formal parameters */
+}
+%token <sym> NUMBER STRING PRINT VAR BLTIN UNDEF WHILE FOR IF EL…
+%token <sym> FUNCTION PROCEDURE RETURN FUNC PROC READ
+%type <formals> formals
+%type <inst> expr stmt asgn prlist stmtlist
+%type <inst> cond while for if begin end
+%type <sym> procname
+%type <narg> arglist
+%right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ
+%left OR
+%left AND
+%left GT GE LT LE EQ NE
+%left '+' '-'
+%left '*' '/' '%'
+%left UNARYMINUS NOT INC DEC
+%right '^'
+%%
+list: /* nothing */
+ | list '\n'
+ | list defn '\n'
+ | list asgn '\n' { code2(xpop, STOP); return 1; }
+ | list stmt '\n' { code(STOP); return 1; }
+ | list expr '\n' { code2(printtop, STOP); return 1; }
+ | list error '\n' { yyerrok; }
+ ;
+asgn: VAR '=' expr { code3(varpush,(Inst)$1,assign); $$=$3; }
+ | VAR ADDEQ expr { code3(varpush,(Inst)$1,addeq); $$=$3; }
+ | VAR SUBEQ expr { code3(varpush,(Inst)$1,subeq); $$=$3; }
+ | VAR MULEQ expr { code3(varpush,(Inst)$1,muleq); $$=$3; }
+ | VAR DIVEQ expr { code3(varpush,(Inst)$1,diveq); $$=$3; }
+ | VAR MODEQ expr { code3(varpush,(Inst)$1,modeq); $$=$3; }
+ ;
+stmt: expr { code(xpop); }
+ | RETURN { defnonly("return"); code(procret); }
+ | RETURN expr
+ { defnonly("return"); $$=$2; code(funcret); }
+ | PROCEDURE begin '(' arglist ')'
+ { $$ = $2; code3(call, (Inst)$1, (Inst)(uintptr)$4); }
+ | PRINT prlist { $$ = $2; }
+ | while '(' cond ')' stmt end {
+ ($1)[1] = (Inst)$5; /* body of loop */
+ ($1)[2] = (Inst)$6; } /* end, if cond fails */
+ | for '(' cond ';' cond ';' cond ')' stmt end {
+ ($1)[1] = (Inst)$5; /* condition */
+ ($1)[2] = (Inst)$7; /* post loop */
+ ($1)[3] = (Inst)$9; /* body of loop */
+ ($1)[4] = (Inst)$10; } /* end, if cond fails */
+ | if '(' cond ')' stmt end { /* else-less if */
+ ($1)[1] = (Inst)$5; /* thenpart */
+ ($1)[3] = (Inst)$6; } /* end, if cond fails */
+ | if '(' cond ')' stmt end ELSE stmt end { /* if with else */
+ ($1)[1] = (Inst)$5; /* thenpart */
+ ($1)[2] = (Inst)$8; /* elsepart */
+ ($1)[3] = (Inst)$9; } /* end, if cond fails */
+ | '{' stmtlist '}' { $$ = $2; }
+ ;
+cond: expr { code(STOP); }
+ ;
+while: WHILE { $$ = code3(whilecode,STOP,STOP); }
+ ;
+for: FOR { $$ = code(forcode); code3(STOP,STOP,STOP); code(STO…
+ ;
+if: IF { $$ = code(ifcode); code3(STOP,STOP,STOP); }
+ ;
+begin: /* nothing */ { $$ = progp; }
+ ;
+end: /* nothing */ { code(STOP); $$ = progp; }
+ ;
+stmtlist: /* nothing */ { $$ = progp; }
+ | stmtlist '\n'
+ | stmtlist stmt
+ ;
+expr: NUMBER { $$ = code2(constpush, (Inst)$1); }
+ | VAR { $$ = code3(varpush, (Inst)$1, eval); }
+ | asgn
+ | FUNCTION begin '(' arglist ')'
+ { $$ = $2; code3(call,(Inst)$1,(Inst)(uintptr)$4); }
+ | READ '(' VAR ')' { $$ = code2(varread, (Inst)$3); }
+ | BLTIN '(' expr ')' { $$=$3; code2(bltin, (Inst)$1->u.ptr); }
+ | '(' expr ')' { $$ = $2; }
+ | expr '+' expr { code(add); }
+ | expr '-' expr { code(sub); }
+ | expr '*' expr { code(mul); }
+ | expr '/' expr { code(div); }
+ | expr '%' expr { code(mod); }
+ | expr '^' expr { code (power); }
+ | '-' expr %prec UNARYMINUS { $$=$2; code(negate); }
+ | expr GT expr { code(gt); }
+ | expr GE expr { code(ge); }
+ | expr LT expr { code(lt); }
+ | expr LE expr { code(le); }
+ | expr EQ expr { code(eq); }
+ | expr NE expr { code(ne); }
+ | expr AND expr { code(and); }
+ | expr OR expr { code(or); }
+ | NOT expr { $$ = $2; code(not); }
+ | INC VAR { $$ = code2(preinc,(Inst)$2); }
+ | DEC VAR { $$ = code2(predec,(Inst)$2); }
+ | VAR INC { $$ = code2(postinc,(Inst)$1); }
+ | VAR DEC { $$ = code2(postdec,(Inst)$1); }
+ ;
+prlist: expr { code(prexpr); }
+ | STRING { $$ = code2(prstr, (Inst)$1); }
+ | prlist ',' expr { code(prexpr); }
+ | prlist ',' STRING { code2(prstr, (Inst)$3); }
+ ;
+defn: FUNC procname { $2->type=FUNCTION; indef=1; }
+ '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
+ | PROC procname { $2->type=PROCEDURE; indef=1; }
+ '(' formals ')' stmt { code(procret); define($2, $5); indef=0; }
+ ;
+formals: { $$ = 0; }
+ | VAR { $$ = formallist($1, 0); }
+ | VAR ',' formals { $$ = formallist($1, $3); }
+ ;
+procname: VAR
+ | FUNCTION
+ | PROCEDURE
+ ;
+arglist: /* nothing */ { $$ = 0; }
+ | expr { $$ = 1; }
+ | arglist ',' expr { $$ = $1 + 1; }
+ ;
+%%
+ /* end of grammar */
+char *progname;
+int lineno = 1;
+jmp_buf begin;
+int indef;
+char *infile; /* input file name */
+Biobuf *bin; /* input file descriptor */
+Biobuf binbuf;
+char **gargv; /* global argument list */
+int gargc;
+
+int c = '\n'; /* global for use by warning() */
+
+int backslash(int), follow(int, int, int);
+void defnonly(char*), run(void);
+void warning(char*, char*);
+
+int
+yylex(void) /* hoc6 */
+{
+ while ((c=Bgetc(bin)) == ' ' || c == '\t')
+ ;
+ if (c < 0)
+ return 0;
+ if (c == '\\') {
+ c = Bgetc(bin);
+ if (c == '\n') {
+ lineno++;
+ return yylex();
+ }
+ }
+ if (c == '#') { /* comment */
+ while ((c=Bgetc(bin)) != '\n' && c >= 0)
+ ;
+ if (c == '\n')
+ lineno++;
+ return c;
+ }
+ if (c == '.' || isdigit(c)) { /* number */
+ double d;
+ Bungetc(bin);
+ Bgetd(bin, &d);
+ yylval.sym = install("", NUMBER, d);
+ return NUMBER;
+ }
+ if (isalpha(c) || c == '_') {
+ Symbol *s;
+ char sbuf[100], *p = sbuf;
+ do {
+ if (p >= sbuf + sizeof(sbuf) - 1) {
+ *p = '\0';
+ execerror("name too long", sbuf);
+ }
+ *p++ = c;
+ } while ((c=Bgetc(bin)) >= 0 && (isalnum(c) || c == '_'));
+ Bungetc(bin);
+ *p = '\0';
+ if ((s=lookup(sbuf)) == 0)
+ s = install(sbuf, UNDEF, 0.0);
+ yylval.sym = s;
+ return s->type == UNDEF ? VAR : s->type;
+ }
+ if (c == '"') { /* quoted string */
+ char sbuf[100], *p;
+ for (p = sbuf; (c=Bgetc(bin)) != '"'; p++) {
+ if (c == '\n' || c == Beof)
+ execerror("missing quote", "");
+ if (p >= sbuf + sizeof(sbuf) - 1) {
+ *p = '\0';
+ execerror("string too long", sbuf);
+ }
+ *p = backslash(c);
+ }
+ *p = 0;
+ yylval.sym = (Symbol *)emalloc(strlen(sbuf)+1);
+ strcpy((char*)yylval.sym, sbuf);
+ return STRING;
+ }
+ switch (c) {
+ case '+': return follow('+', INC, follow('=', ADDEQ, '+'));
+ case '-': return follow('-', DEC, follow('=', SUBEQ, '-'));
+ case '*': return follow('=', MULEQ, '*');
+ case '/': return follow('=', DIVEQ, '/');
+ case '%': return follow('=', MODEQ, '%');
+ case '>': return follow('=', GE, GT);
+ case '<': return follow('=', LE, LT);
+ case '=': return follow('=', EQ, '=');
+ case '!': return follow('=', NE, NOT);
+ case '|': return follow('|', OR, '|');
+ case '&': return follow('&', AND, '&');
+ case '\n': lineno++; return '\n';
+ default: return c;
+ }
+}
+
+int
+backslash(int c) /* get next char with \'s interpreted */
+{
+ static char transtab[] = "b\bf\fn\nr\rt\t";
+ if (c != '\\')
+ return c;
+ c = Bgetc(bin);
+ if (islower(c) && strchr(transtab, c))
+ return strchr(transtab, c)[1];
+ return c;
+}
+
+int
+follow(int expect, int ifyes, int ifno) /* look ahead for >=, etc. */
+{
+ int c = Bgetc(bin);
+
+ if (c == expect)
+ return ifyes;
+ Bungetc(bin);
+ return ifno;
+}
+
+void
+yyerror(char* s) /* report compile-time error */
+{
+/*rob
+ warning(s, (char *)0);
+ longjmp(begin, 0);
+rob*/
+ execerror(s, (char *)0);
+}
+
+void
+execerror(char* s, char* t) /* recover from run-time error */
+{
+ warning(s, t);
+ Bseek(bin, 0L, 2); /* flush rest of file */
+ restoreall();
+ longjmp(begin, 0);
+}
+
+void
+fpecatch(void) /* catch floating point exceptions */
+{
+ execerror("floating point exception", (char *) 0);
+}
+
+void
+intcatch(void) /* catch interrupts */
+{
+ execerror("interrupt", 0);
+}
+
+void
+run(void) /* execute until EOF */
+{
+ setjmp(begin);
+ for (initcode(); yyparse(); initcode())
+ execute(progbase);
+}
+
+void
+main(int argc, char* argv[]) /* hoc6 */
+{
+ static int first = 1;
+#ifdef YYDEBUG
+ extern int yydebug;
+ yydebug=3;
+#endif
+ progname = argv[0];
+ init();
+ if (argc == 1) { /* fake an argument list */
+ static char *stdinonly[] = { "-" };
+
+ gargv = stdinonly;
+ gargc = 1;
+ } else if (first) { /* for interrupts */
+ first = 0;
+ gargv = argv+1;
+ gargc = argc-1;
+ }
+ Binit(&binbuf, 0, OREAD);
+ bin = &binbuf;
+ while (moreinput())
+ run();
+ exits(0);
+}
+
+int
+moreinput(void)
+{
+ char *expr;
+ static char buf[64];
+ int fd;
+ static Biobuf b;
+
+ if (gargc-- <= 0)
+ return 0;
+ if (bin && bin != &binbuf)
+ Bterm(bin);
+ infile = *gargv++;
+ lineno = 1;
+ if (strcmp(infile, "-") == 0) {
+ bin = &binbuf;
+ infile = 0;
+ return 1;
+ }
+ if(strncmp(infile, "-e", 2) == 0) {
+ if(infile[2]==0){
+ if(gargc == 0){
+ fprint(2, "%s: no argument for -e\n", progname…
+ return 0;
+ }
+ gargc--;
+ expr = *gargv++;
+ }else
+ expr = infile+2;
+ sprint(buf, "/tmp/hocXXXXXXX");
+ fd = mkstemp(buf);
+ remove(buf);
+/*
+ infile = mktemp(buf);
+ fd = create(infile, ORDWR|ORCLOSE, 0600);
+ if(fd < 0){
+ fprint(2, "%s: can't create temp. file: %r\n", prognam…
+ return 0;
+ }
+*/
+ fprint(fd, "%s\n", expr);
+ /* leave fd around; file will be removed on exit */
+ /* the following looks weird but is required for unix version …
+ bin = &b;
+ seek(fd, 0, 0);
+ Binit(bin, fd, OREAD);
+ } else {
+ bin=Bopen(infile, OREAD);
+ if (bin == 0) {
+ fprint(2, "%s: can't open %s\n", progname, infile);
+ return moreinput();
+ }
+ }
+ return 1;
+}
+
+void
+warning(char* s, char* t) /* print warning message */
+{
+ fprint(2, "%s: %s", progname, s);
+ if (t)
+ fprint(2, " %s", t);
+ if (infile)
+ fprint(2, " in %s", infile);
+ fprint(2, " near line %d\n", lineno);
+ while (c != '\n' && c != Beof)
+ if((c = Bgetc(bin)) == '\n') /* flush rest of input lin…
+ lineno++;
+}
+
+void
+defnonly(char *s) /* warn if illegal definition */
+{
+ if (!indef)
+ execerror(s, "used outside definition");
+}
diff --git a/hoc/init.c b/hoc/init.c
@@ -0,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include "hoc.h"
+#include "y.tab.h"
+
+static struct { /* Keywords */
+ char *name;
+ int kval;
+} keywords[] = {
+ "proc", PROC,
+ "func", FUNC,
+ "return", RETURN,
+ "if", IF,
+ "else", ELSE,
+ "while", WHILE,
+ "for", FOR,
+ "print", PRINT,
+ "read", READ,
+ 0, 0
+};
+
+static struct { /* Constants */
+ char *name;
+ double cval;
+} consts[] = {
+ "PI", 3.14159265358979323846,
+ "E", 2.71828182845904523536,
+ "GAMMA", 0.57721566490153286060, /* Euler */
+ "DEG", 57.29577951308232087680, /* deg/radian */
+ "PHI", 1.61803398874989484820, /* golden ratio */
+ 0, 0
+};
+
+static struct { /* Built-ins */
+ char *name;
+ double (*func)(double);
+} builtins[] = {
+ "sin", sin,
+ "cos", cos,
+ "tan", tan,
+ "atan", atan,
+ "asin", Asin, /* checks range */
+ "acos", Acos, /* checks range */
+ "sinh", Sinh, /* checks range */
+ "cosh", Cosh, /* checks range */
+ "tanh", tanh,
+ "log", Log, /* checks range */
+ "log10", Log10, /* checks range */
+ "exp", Exp, /* checks range */
+ "sqrt", Sqrt, /* checks range */
+ "int", integer,
+ "abs", fabs,
+ 0, 0
+};
+
+void
+init(void) /* install constants and built-ins in table */
+{
+ int i;
+ Symbol *s;
+ for (i = 0; keywords[i].name; i++)
+ install(keywords[i].name, keywords[i].kval, 0.0);
+ for (i = 0; consts[i].name; i++)
+ install(consts[i].name, VAR, consts[i].cval);
+ for (i = 0; builtins[i].name; i++) {
+ s = install(builtins[i].name, BLTIN, 0.0);
+ s->u.ptr = builtins[i].func;
+ }
+}
diff --git a/hoc/math.c b/hoc/math.c
@@ -0,0 +1,75 @@
+#include <u.h>
+#include <libc.h>
+
+#include "hoc.h"
+
+double errcheck(double, char*);
+
+double
+Log(double x)
+{
+ return errcheck(log(x), "log");
+}
+double
+Log10(double x)
+{
+ return errcheck(log10(x), "log10");
+}
+
+double
+Sqrt(double x)
+{
+ return errcheck(sqrt(x), "sqrt");
+}
+
+double
+Exp(double x)
+{
+ return errcheck(exp(x), "exp");
+}
+
+double
+Asin(double x)
+{
+ return errcheck(asin(x), "asin");
+}
+
+double
+Acos(double x)
+{
+ return errcheck(acos(x), "acos");
+}
+
+double
+Sinh(double x)
+{
+ return errcheck(sinh(x), "sinh");
+}
+double
+Cosh(double x)
+{
+ return errcheck(cosh(x), "cosh");
+}
+double
+Pow(double x, double y)
+{
+ return errcheck(pow(x,y), "exponentiation");
+}
+
+double
+integer(double x)
+{
+ if(x<-2147483648.0 || x>2147483647.0)
+ execerror("argument out of domain", 0);
+ return (double)(long)x;
+}
+
+double
+errcheck(double d, char* s) /* check result of library call */
+{
+ if(isNaN(d))
+ execerror(s, "argument out of domain");
+ if(isInf(d, 0))
+ execerror(s, "result out of range");
+ return d;
+}
diff --git a/hoc/symbol.c b/hoc/symbol.c
@@ -0,0 +1,55 @@
+#include <u.h>
+#include <libc.h>
+#include "hoc.h"
+#include "y.tab.h"
+
+static Symbol *symlist = 0; /* symbol table: linked list */
+
+Symbol*
+lookup(char* s) /* find s in symbol table */
+{
+ Symbol *sp;
+
+ for (sp = symlist; sp != (Symbol *) 0; sp = sp->next)
+ if (strcmp(sp->name, s) == 0)
+ return sp;
+ return 0; /* 0 ==> not found */
+}
+
+Symbol*
+install(char* s, int t, double d) /* install s in symbol table */
+{
+ Symbol *sp;
+
+ sp = emalloc(sizeof(Symbol));
+ sp->name = emalloc(strlen(s)+1); /* +1 for '\0' */
+ strcpy(sp->name, s);
+ sp->type = t;
+ sp->u.val = d;
+ sp->next = symlist; /* put at front of list */
+ symlist = sp;
+ return sp;
+}
+
+void*
+emalloc(unsigned n) /* check return from malloc */
+{
+ char *p;
+
+ p = malloc(n);
+ if (p == 0)
+ execerror("out of memory", (char *) 0);
+ return p;
+}
+
+Formal*
+formallist(Symbol *formal, Formal *list) /* add formal to list */
+{
+ Formal *f;
+
+ f = emalloc(sizeof(Formal));
+ f->sym = formal;
+ f->save = 0;
+ f->next = list;
+ return f;
+}
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.