Commits

Anonymous committed dfa3748

Initial import of Maentwrog version 1.0 revision 2007.0930 sources.

  • Participants
  • Tags rel_1_0_2007_0930

Comments (0)

Files changed (4)

+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+ * caparse.c
+ *
+ * cellular automata parser handles 1-character values and operators :
+ *
+ * not          !
+ * or           |
+ * and          &
+ * xor          ^
+ * values       a, b, c, ... z
+ * parenthesis  (, )
+ */
+
+#define OP_OR   0
+#define OP_AND  1
+#define OP_XOR  2
+
+int caparse(char *string, int values[]);
+int doper(int state, int oper, int modder);
+
+main()
+{
+  int values[26] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                     0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  char in[255];
+
+  while (!feof(stdin))
+  {
+    gets(in);
+    if (isalpha(in[0])&&in[1]=='=')
+      values[in[0]-'a']=(in[2]-'0');
+      else
+      printf("%d\n", caparse(in, values));
+  }
+
+}
+
+int caparse(char *string, int values[])
+{
+
+#define sp string[pos]
+
+  int negate = 0;
+  int state  = 0;
+  int oper   = OP_OR;
+  int pos    = 0;
+
+  for (;((sp) && (sp != ')'));pos++)
+  {
+    if (isalpha(sp))
+    {
+      state = doper(state, oper, negate ? !values[sp-'a'] : values[sp-'a']);
+      negate = 0;
+    } else
+    switch (sp)
+    {
+      case '|' : oper = OP_OR; break;
+      case '&' : oper = OP_AND; break;
+      case '^' : oper = OP_XOR; break;
+      case '!' : negate = 1; break;
+      case '(' : pos++;
+                 state = doper(state, oper,
+                         negate ? !caparse(&sp, values) :
+                                   caparse(&sp, values));
+                 {
+                   int bra = 1;
+                   while (bra)
+                   {
+                     if (sp=='(') bra++;
+                     if (sp==')') bra--;
+                     printf("%d\n", bra);
+                     if (bra) pos++;
+                   }
+                 }
+                 break;
+      default  : break;
+    }
+  }
+  return state;
+}
+
+int doper(int state, int oper, int modder)
+{
+  switch (oper)
+  {
+    case OP_OR  : return(state | modder); break;
+    case OP_AND : return(state & modder); break;
+    case OP_XOR : return(state ^ modder); break;
+  }
+}
+
+/*
+ * maentw.c
+ *
+ * Maentwrog (RPN calculator & simple interpreted language)
+ * - derived from rpn, Aug 1993 Chris Pressey
+ * - updated Jul 1997 Chris Pressey, fixed minor bugs
+ * - updated Jul 1998 Chris Pressey, fixed more minor bugs
+ * -         and ANSI C-ized: now case sensitive
+ * Usage : maentw maentw-expressions   executes and exits
+ *         maentw		       goes into interactive mode
+ *         maentw <maentwrog-file      runs file through maentw
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <alloc.h>
+#include <string.h>
+#include <ctype.h>
+
+#define DEFSIZE 1024
+
+struct stack			/* stack structure, for values on stack */
+{
+  signed long val;
+  struct stack *next;
+} *head;			/* head of stack */
+
+struct word			/* word structure, for words (pre- and user- */
+{				/* defined) */
+  char name[80];		/* name of word */
+  char *macro;  		/* macro (user-defined; only executed if
+				 * fcn==0) */
+  int fcn;			/* built-in fcn or 0 for user-defined fcn */
+  struct word *next;
+} *whead;			/* head of words */
+
+struct vari			/* variable structure, for variables */
+{
+  char name[80];		/* name of variable */
+  signed long value;			/* values of variable (signed longs only) */
+  struct vari *next;
+} *vhead;			/* head of variables */
+
+int debug=0;
+
+/* prototypes */
+
+/* word-handling */
+struct word *addword(char *name, char *macro, int fcn);
+struct word *lookup(char *name);
+void initwords(void);
+void makeword(void);
+
+/* variable-handling */
+struct vari *addvari(char *name);
+struct vari *getvari(char *name);
+void setvari(char *name, signed long value);
+
+/* stack-handling */
+void push(signed long val);
+signed long pop(void);
+
+/* functions */
+void dofunc(struct word * w);
+void words(void);
+void vars(void);
+signed long sizestack(void);
+
+/* parsing and interpreting */
+void process(char *s);
+void procstr(char *s);
+
+char * strdup(char * s)
+{
+  char * t;
+  t = (char *)malloc(strlen(s) * sizeof(char));
+  strcpy(t, s);
+  return t;
+}
+
+int main(argc, argv)
+  int argc;
+  char **argv;
+{
+  char s[80];
+  int i;
+
+  head = NULL;			/* init */
+  whead = NULL;
+  vhead = NULL;
+  initwords();
+  if (argc != 1)
+  {
+    for(i=2;i<=argc;i++) procstr(argv[i-1]);
+    exit(0);
+  }
+  scanf("%s", s);		/* process commands/values from stdin */
+  while (!feof(stdin))
+  {
+    process(s);
+    scanf("%s", s);
+  }
+  return 0;
+}
+
+/*
+ * processes the word in s according to parsing rules.
+ *
+ * if word starts with a digit or a -digit, it is converted to a float and put
+ * on the stack.
+ *
+ * if word starts with a = then the variable following equals is assigned the
+ * last value popped off the stack.
+ *
+ * if word starts with a * a variable is defined using that word.
+ *
+ * if word starts with a @, the stack is popped, is checked for the boolean
+ * value, and if true, executes it. (if.)
+ *
+ * if word starts with a $, the stack is popped, and command is repeated
+ * that number of times.
+ *
+ * if word starts with a [, the stack is popped, is checked for the boolean
+ * value, and if true, executes it.  Then goes back and pops the stack
+ * again (while.)
+ *
+ * if word is in words list, that function is executed.
+ *
+ * if word is in variables list, the value of it is pushed onto the stack.
+ *
+ * otherwise generates an error.
+ */
+void process(char *s)
+{
+  struct word *w;
+  struct vari *v;
+  int i;
+
+  if(debug) printf("%s ", s);
+
+  if (isdigit(s[0]) || ((s[0] == '-') && (isdigit(s[1]))))
+    push(atoi(s));
+  else if (s[0] == '=')
+    setvari(s + 1, pop());
+  else if ((s[0] == '*') && (isalpha(s[1])))
+    addvari(s + 1);
+  else if (s[0] == '@')
+  {
+    if (pop())
+      if (w = lookup(s + 1))
+	dofunc(w);
+  }
+  else if (s[0] == '$')
+  {
+    for(i=pop();i;i--)
+      if (w = lookup(s + 1))
+	dofunc(w);
+  }
+  else if (s[0] == '[')
+  {
+    for(;;)
+    {
+      if (pop())
+      {
+	if (w = lookup(s + 1))
+	  dofunc(w);
+      } else break;
+    }
+  }
+  else if (w = lookup(s))
+    dofunc(w);
+  else if (v = getvari(s))
+    push(v->value);
+  else
+    printf("unknown command '%s'\n", s);
+}
+
+/*
+ * processes each word in the string s.
+ * strtok doesn't work with recursion :-(
+ */
+void procstr(char *s)
+{
+  char *h=strdup(s);
+  char *g, *gg;
+  g = h;
+
+  for (;;)
+  {
+    gg = g;
+    while (!isspace(gg[0])&&gg[0])
+      gg++;
+    if (!gg[0])
+      break;
+    gg[0] = 0;
+
+    process(g);
+
+    gg[0] = ' ';
+    g = gg;
+    while (isspace(g[0])&&g[0])
+      g++;
+  }
+
+  free(h);			/* called with strdup(), so we must free */
+}
+
+/*
+ * adds a unique word to the list of words.
+ */
+struct word *addword(char *name, char *macro, int fcn)
+{
+  struct word *new;
+  for (new = whead; new; new = new->next)
+    if (!strcmp(new->name, name))
+    {
+      printf("already exists\n");
+      return NULL;
+    }
+  new = (struct word *) malloc(sizeof(struct word));
+  strcpy(new->name, name);
+  new->macro = strdup(macro);
+  new->fcn = fcn;
+
+  new->next = whead;
+  whead = new;
+  return new;
+}
+
+/*
+ * attempts to find the word 'name' in the words list.  returns NULL if it
+ * could not be found.
+ */
+struct word *lookup(char *name)
+{
+  struct word *l = whead;
+  struct word *k = NULL;
+
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      k = l;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+  return (k);
+}
+
+/*
+ * initialize the words list with all the built-in words.
+ */
+void initwords()
+{
+  addword("bye", "", 200);
+  addword("rem", "", 199);
+  addword("debug", "", 198);
+  addword("vars", "", 101);
+  addword("words", "", 100);
+
+  addword("free", "", 91);
+  addword("alloc", "", 90);
+
+  addword(";", "", 81);
+  addword(":", "", 80);
+
+  addword("size", "", 50);
+  addword("dup", "", 51);
+  addword("swap", "", 52);
+  addword("pop", "", 53);
+
+  addword("get", "", 45);
+  addword("put", "", 44);
+
+  addword("rnd", "", 40);
+
+  addword(">", "", 22);
+  addword("<", "", 21);
+  addword("==", "", 20);
+
+  addword(".", "", 1);
+  addword("..", "", 6);
+
+  addword("mod", "", 30);
+
+  addword("/", "", 5);
+  addword("*", "", 4);
+  addword("-", "", 3);
+  addword("+", "", 2);
+}
+
+/*
+ * makes a word, reading between the : and ;, defining the new word's macro,
+ * and adds it.
+ */
+void makeword()
+{
+  char s[80];
+  char t[80];
+  char *y;
+  int size = DEFSIZE;
+
+  y = (char *)malloc(size);
+  scanf("%s", s);
+  strcpy(y, "");
+  scanf("%s", t);
+  while (strcmp(t, ";"))
+  {
+    if ((strlen(y)+strlen(t))>size)
+    {
+      printf("out of memory\n");
+      exit(0);
+    }
+    strcat(y, t);
+    strcat(y, " ");
+    scanf("%s", t);
+  }
+  {
+    char *n = (char *)malloc(strlen(y)+1);
+/*  printf("(usage : %d bytes)\n", strlen(y)+1); */
+    strcpy(n, y);
+    free(y);
+    y = n;
+  }
+  addword(s, y, 0);
+}
+
+/*
+ * pushes a value onto the stack.
+ */
+void push(signed long val)
+{
+  struct stack *s;
+  s = (struct stack *) malloc(sizeof(struct stack));
+  s->val = val;
+  s->next = head;
+  head = s;
+}
+
+/*
+ * pops a value off the stack. generates error and returns 0.0 in case of
+ * underflow.
+ */
+signed long pop()
+{
+  signed long v;
+  struct stack *s = head;
+  if (s)
+  {
+    v = head->val;
+    head = head->next;
+    free(s);
+    return v;
+  } else
+  {
+    printf("stack underflow\n");
+    return 0;
+  }
+}
+
+/*
+ * adds a unique variable to the vari list.
+ */
+struct vari *addvari(char *name)
+{
+  struct vari *v;
+  for (v = vhead; v; v = v->next)
+    if (!strcmp(v->name, name))
+    {
+      printf("already exists\n");
+      return NULL;
+    }
+  v = (struct vari *) malloc(sizeof(struct vari));
+  strcpy(v->name, name);
+  v->next = vhead;
+  vhead = v;
+  return v;
+}
+
+/*
+ * gets the value of a variable off the variable list.
+ */
+struct vari *getvari(char *name)
+{
+  struct vari *l = vhead;
+  struct vari *k = NULL;
+
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      k = l;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+  return (k);
+}
+
+/*
+ * sets the value of a variable
+ */
+void setvari(char *name, signed long value)
+{
+  struct vari *l = vhead;
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      l->value = value;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+}
+
+/*
+ * lists all words in mw's words list
+ */
+void words()
+{
+  struct word *w;
+  for (w = whead; w; w = w->next)
+    printf("%s ", w->name);
+  printf("\n");
+}
+
+signed long sizestack()
+{
+  signed long total = 0;
+  struct stack *s = head;
+
+  while(s)
+  {
+    total++;
+    s=s->next;
+  }
+  return total;
+}
+
+/*
+ * list all variables in mw's vari list
+ */
+void vars()
+{
+  struct vari *v;
+  for (v = vhead; v; v = v->next)
+    printf("%-16s %ld\n", v->name, v->value);
+}
+
+/*
+ * execute function of a word.  if w->fcn is 0, it will run processtr on the
+ * word.  otherwise, a built-in function will be called. see the rpn
+ * documentation on built-in functions.
+ */
+void dofunc(struct word * w)
+{
+  signed long a, b;
+  signed long *ax;
+  switch (w->fcn)
+  {
+    case 1:			/* output (.) */
+      printf("%ld\n", pop());
+      break;
+    case 2:			/* add (+) */
+      push(pop() + pop());
+      break;
+    case 3:			/* subtract (-) */
+      a = pop();
+      b = pop();
+      push(b - a);
+      break;
+    case 4:			/* multiply (*) */
+      push(pop() * pop());
+      break;
+    case 5:			/* divide (/) */
+      a = pop();
+      b = pop();
+      push(b / a);
+      break;
+    case 6:			/* output ASCII (..) */
+      printf("%c", (char)pop());
+      break;
+    case 20:
+      push(!pop() == !pop());
+      break;
+    case 21:
+      push(pop()>pop());
+      break;
+    case 22:
+      push(pop()<pop());
+      break;
+    case 30:
+      a = pop();
+      b = pop();
+      push(b % a);
+      break;
+    case 40:
+      push(a);                  /* something random */
+      break;
+    case 44:                    /* put */
+      a = pop();
+      b = pop();
+      if (b % 4)
+	printf("must be longword boundary\n"); else
+	{
+	  ax = (signed long *)b;
+	  *ax = a;
+	}
+      break;
+    case 45:
+      a = pop();
+      if (a % 4)
+	printf("must be longword boundary\n"); else
+	{
+	  ax = (signed long *)a;
+	  push(*ax);
+	}
+      break;
+    case 50:
+      push(sizestack());        /* size of stack (size) */
+      break;
+    case 51:                    /* duplicate top element (dup) */
+      a = pop();
+      push(a); push (a); break;
+    case 52:                    /* swap top elements (swap) */
+      a = pop();
+      b = pop();
+      push(a); push (b);
+      break;
+    case 53:                    /* pop element (pop) */
+      pop();
+      break;
+    case 80:			/* define word (: ... ;) */
+      makeword();
+      break;
+    case 81:			/* null (;) */
+      break;
+    case 90:
+      a = pop();
+      push((signed long)malloc(a*sizeof(signed long)));
+      break;
+    case 91:
+      free((void *)pop());
+      break;
+    case 100:			/* list known words (words) */
+      words();
+      break;
+    case 101:			/* list variables (vars) */
+      vars();
+      break;
+    case 198:
+      debug = 1;
+      break;
+    case 199:                   /* rem */
+    {
+      char t[80];
+      scanf("%s", t);
+      while (strcmp(t, ";"))
+	scanf("%s", t);
+    }
+      break;
+    case 200:			/* exit mw (bye) */
+      exit(0);
+      break;
+    default:			/* user-defined word */
+      procstr(w->macro);
+  }
+}
+/*
+
+   rdp.c
+
+   a recursive decent parser (origins now lost, sorry)
+
+   Chris Pressey, March, like, 7th, 1994
+
+   This program is by no means complete, but it's as far as I'll
+   go in the general case.  It should be no problem adapting it
+   to do all sorts of really demented things.
+
+ */
+
+#define THIS_PROGRAM_IS_NOT_REALLY_AS_CRAPPY_AS_YOU_THINK
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define T_DELIMITER     0	/* delimeter token */
+#define T_VARIABLE      1
+#define T_CONSTANT      2
+
+#define T_LENGTH        80
+
+int toktype;			/* type of last token */
+char token[T_LENGTH];		/* what gettoken returns - a token */
+char prog[T_LENGTH];		/* the string to parse */
+
+int t;				/* a 'pointer' to the pos in prog[] */
+int result;			/* result of calculations */
+int vars[26];			/* variables */
+
+int level2 (int result);	/* recursion levels.  level 1 is no */
+int level3 (int result);	/* longer needed (it assigned vars) */
+int level4 (int result);
+int level5 (int result);
+int level6 (int result);
+int primitive (int result);
+
+/*-------------------------------------------------------------------------*/
+
+int 
+isdelimeter (char ch)
+{
+  switch (ch)
+    {
+    case ' ':
+    case '+':
+    case '-':
+    case '/':
+    case '*':
+    case '%':
+    case '=':
+    case '>':
+    case '<':
+    case '(':
+    case ')':
+    case '$':
+    case '!':
+    case '&':
+    case '|':
+    case '^':
+      return 1;
+      break;
+
+    default:
+      return 0;
+    }
+}
+
+void 
+gettoken ()
+{
+  char temp[T_LENGTH];
+
+  strcpy (token, "");
+  token[1] = (char) 0;
+
+  while (isspace (prog[t]))
+    t++;
+  if (prog[t] == '$')
+    strcpy (token, "$");
+  if (isdelimeter (prog[t]))
+    {
+      toktype = T_DELIMITER;
+      token[0] = prog[t++];
+    }
+  else
+    {
+      if (isalpha (prog[t]))
+	{
+	  toktype = T_VARIABLE;
+	  while (!(isdelimeter (prog[t])))
+	    {
+	      token[strlen (token) + 1] = (char) 0;
+	      token[strlen (token)] = prog[t++];
+	    }
+	}
+      else if (isdigit (prog[t]))
+	{
+	  toktype = T_CONSTANT;
+	  while (!(isdelimeter (prog[t])))
+	    {
+	      token[strlen (token) + 1] = (char) 0;
+	      token[strlen (token)] = prog[t++];
+	    }
+	}
+    }
+}
+
+void 
+putback ()
+{
+  t -= strlen (token);
+}
+
+void 
+serror (int s)
+{
+  switch (s)
+    {
+    case 1:
+      printf ("syntax error\n");
+      break;
+    case 2:
+      printf ("mismatched parentheses\n");
+      break;
+    case 3:
+      printf ("expression absent\n");
+      break;
+    }
+}
+
+/*
+   if you define a new operator, use
+
+   return (argument op operand)
+
+   if you define a function (eg. sin(x)), use
+
+   return (func(operand))
+
+   if you define a backwards function (eg. x!) use
+
+   return (func(argument))
+
+   unary operators (such as -5 and !(a=b)) are not handled here, but are
+   handled in level5()
+
+ */
+int 
+arith (char op, int argument, int operand)
+{
+  switch (op)
+    {
+    case '+':
+      return (argument + operand);	/* addition */
+    case '-':
+      return (argument - operand);	/* subtraction */
+    case '*':
+      return (argument * operand);	/* multiplication */
+    case '/':
+      return (argument / operand);	/* division */
+    case '%':
+      return (argument % operand);	/* modulus */
+    case '=':
+      return (argument == operand);	/* equality */
+    case '>':
+      return (argument > operand);	/* superiority */
+    case '<':
+      return (argument < operand);	/* inferiority */
+    case '&':
+      return (argument & operand);	/* binary AND */
+    case '|':
+      return (argument | operand);	/* binary OR */
+    case '^':
+      return (argument ^ operand);	/* binary XOR */
+    }
+}
+
+int 
+findvar (char *s)
+{
+  return vars[(int) toupper (s[0]) - (int) 'A'];
+}
+
+int 
+getexp (int result)
+{
+  gettoken ();
+  if (strlen (token))
+    result = level2 (result);
+  else
+    serror (3);
+  return result;
+}
+
+int 
+level2 (int result)
+{
+  char op;
+  int hold = 0;
+
+  result = level3 (result);
+  op = token[0];
+  while ((op == '+') || (op == '-'))
+    {
+      gettoken ();
+      hold = level3 (hold);
+      result = arith (op, result, hold);
+      op = token[0];
+    }
+  return result;
+}
+
+int 
+level3 (int result)
+{
+  char op;
+  int hold = 0;
+
+  result = level4 (result);
+  op = token[0];
+  while ((op == '*') || (op == '/'))
+    {
+      gettoken ();
+      hold = level4 (hold);
+      result = arith (op, result, hold);
+      op = token[0];
+    }
+  return result;
+}
+
+int 
+level4 (int result)
+{
+  int hold = 0;
+  char ch;
+
+  result = level5 (result);
+  ch = token[0];
+  switch (ch)
+    {
+    case '=':
+    case '>':
+    case '<':
+    case '&':
+    case '|':
+    case '^':
+      gettoken ();
+      hold = level4 (hold);
+      result = arith (ch, result, hold);
+      break;
+    }
+  return result;
+}
+
+int 
+level5 (int result)
+{
+  char op;
+  int hold = 0;
+
+  op = ' ';
+  if ((toktype == T_DELIMITER) && ((token[0] == '+') || (token[0] == '-')))
+    {
+      op = token[0];
+      gettoken ();
+    }
+  result = level6 (result);
+  if (op == '-')
+    result *= (-1);
+  if (op == '!')
+    result = !result;
+  return result;
+}
+
+int 
+level6 (int result)
+{
+  if ((token[0] == '(') && (toktype == T_DELIMITER))
+    {
+      gettoken ();
+      result = level2 (result);
+      if (token[0] != ')')
+	serror (2);
+      gettoken ();
+    }
+  else
+    result = primitive (result);
+  return result;
+}
+
+int 
+primitive (int result)
+{
+  if (toktype == T_CONSTANT)
+    result = atoi (token);
+  else if (toktype == T_VARIABLE)
+    result = findvar (token);
+  else
+    serror (1);
+  gettoken ();
+  return result;
+}
+
+int 
+main (int argc, char **argv)
+{
+  {
+    int c;
+    for (c = 0; c <= 25; c++)
+      vars[c] = 0;
+  }
+  t = 0;
+
+  strcpy (prog, argv[1]);
+  strcat (prog, "$");
+  result = getexp (result);
+  printf ("%d\n", result);
+  exit (0);
+
+
+
+
+#ifdef THIS_PROGRAM_IS_NOT_REALLY_AS_CRAPPY_AS_YOU_THINK
+}
+#else
+}
+#endif
+
+/*
+ * rpn.c
+ * 
+ * RPN calculator - May 1993 Chris Pressey
+ * 
+ * Compilation : acc rpn.c -o rpn
+ * 
+ * Usage : rpn rpn-expressions		; executes and exits
+ *         rpn				; goes into interactive mode
+ *         rpn <rpn-file		; runs rpn-file through rpn
+ * 
+ * To do : add size (size stack), sum (sum stack), mean (mean stack), sd (take
+ * standard deviation of stack)
+ * 
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+struct stack			/* stack structure, for values on stack */
+{
+  double val;
+  struct stack *next;
+} *head;			/* head of stack */
+
+struct word			/* word structure, for words (pre- and user- */
+{				/* defined) */
+  char name[80];		/* name of word */
+  char macro[80];		/* macro (user-defined; only executed if
+				 * fcn==0) */
+  int fcn;			/* built-in fcn or 0 for user-defined fcn */
+  struct word *next;
+} *whead;			/* head of words */
+
+struct vari			/* variable structure, for variables */
+{
+  char name[80];		/* name of variable */
+  double value;			/* values of variable (doubles only) */
+  struct vari *next;
+} *vhead;			/* head of variables */
+
+/* prototypes */
+
+/* word-handling */
+struct word *addword(char *name, char *macro, int fcn);
+struct word *lookup(char *name);
+void initwords();
+void makeword();
+
+/* variable-handling */
+struct vari *addvari(char *name);
+struct vari *getvari(char *name);
+void setvari(char *name, double value);
+
+/* stack-handling */
+void push(double val);
+double pop();
+
+/* functions */
+void dofunc(struct word * w);
+double factorial(double p);
+double fibonacci(double p);
+void words();
+void vars();
+
+/* parsing and interpreting */
+void process(char *s);
+void procstr(char *s);
+
+main(argc, argv)
+  int argc;
+  char **argv;
+{
+  char s[80];
+  int i;
+
+  head = NULL;			/* init */
+  whead = NULL;
+  vhead = NULL;
+  initwords();
+  if (argc != 1)
+  {
+    for(i=2;i<=argc;i++) procstr(argv[i-1]);
+    exit(0);
+  }
+  scanf("%s", s);		/* process commands/values from stdin */
+  while (!feof(stdin))
+  {
+    process(s);
+    scanf("%s", s);
+  }
+}
+
+/*
+ * processes the word in s according to parsing rules.
+ *
+ * if word starts with a digit or a -digit, it is converted to a float and put
+ * on the stack.
+ * 
+ * if word starts with a = then the variable following equals is assigned the
+ * last value popped off the stack.
+ * 
+ * if word starts with a * a variable is defined using that word.
+ * 
+ * if word is in words list, that function is executed.
+ * 
+ * if word is in variables list, the value of it is pushed onto the stack.
+ * 
+ * otherwise generates an error.
+ */
+void process(char *s)
+{
+  struct word *w;
+  struct vari *v;
+
+  if (isdigit(s[0]) || ((s[0] == '-') && (isdigit(s[1]))))
+    push(atof(s));
+  else if (s[0] == '=')
+    setvari(s + 1, pop());
+  else if ((s[0] == '*') && (isalpha(s[1])))
+    addvari(s + 1);
+  else if (w = lookup(s))
+    dofunc(w);
+  else if (v = getvari(s))
+    push(v->value);
+  else
+    printf("unknown command '%s'\n", s);
+}
+
+/*
+ * processes each word in the string s.
+ */
+void procstr(char *s)
+{
+  char *h=strdup(s);
+  char *g;
+  g = strtok(h, " ");
+  while (g)
+  {
+    process(g);
+    g = strtok(NULL, " ");
+  }
+  free(h);			/* called with strdup(), so we must free */
+}
+
+/*
+ * adds a unique word to the list of words.
+ */
+struct word *addword(char *name, char *macro, int fcn)
+{
+  struct word *new;
+  for (new = whead; new; new = new->next)
+    if (!strcmp(new->name, name))
+    {
+      printf("already exists\n");
+      return NULL;
+    }
+  new = (struct word *) malloc(sizeof(struct word));
+  strcpy(new->name, name);
+  strcpy(new->macro, macro);
+  new->fcn = fcn;
+
+  new->next = whead;
+  whead = new;
+  return new;
+}
+
+/*
+ * attempts to find the word 'name' in the words list.  returns NULL if it
+ * could not be found.
+ */
+struct word *lookup(char *name)
+{
+  struct word *l = whead;
+  struct word *k = NULL;
+
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      k = l;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+  return (k);
+}
+
+/*
+ * initialize the words list with all the built-in words.
+ */
+void initwords()
+{
+  addword("bye", "", 200);
+  addword("vars", "", 101);
+  addword("words", "", 100);
+  addword(";", "", 81);
+  addword(":", "", 80);
+
+  addword("sd", "", 53);
+  addword("mean", "", 52);
+  addword("sum", "", 51);
+  addword("size", "", 50);
+
+  addword("!", "", 13);
+  addword("fib", "", 14);
+
+  addword("rnd", "", 40);
+
+  addword("sign", "", 34);
+  addword("abs", "", 33);
+  addword("round", "", 32);
+  addword("frac", "", 31);
+  addword("int", "", 30);
+
+  addword("phi", "", 27);
+  addword("pi", "", 26);
+  addword("atan", "", 25);
+  addword("acos", "", 24);
+  addword("asin", "", 23);
+
+  addword("tan", "", 22);
+  addword("cos", "", 21);
+  addword("sin", "", 20);
+
+  addword("inv", "", 12);
+  addword("exp", "", 11);
+  addword("log", "", 10);
+  addword("ln", "", 9);
+  addword("sqrt", "", 8);
+  addword("sqr", "", 7);
+
+  addword("^", "", 6);
+
+  addword(".", "", 1);
+
+  addword("/", "", 5);
+  addword("*", "", 4);
+  addword("-", "", 3);
+  addword("+", "", 2);
+}
+
+/*
+ * makes a word, reading between the : and ;, defining the new word's macro,
+ * and adds it.
+ */
+void makeword()
+{
+  char s[80];
+  char t[80];
+  char y[180];
+  scanf("%s", s);
+  strcpy(y, "");
+  scanf("%s", t);
+  while (strcmp(t, ";"))
+  {
+    strcat(y, t);
+    strcat(y, " ");
+    scanf("%s", t);
+  }
+  addword(s, y, 0);
+}
+
+/*
+ * pushes a value onto the stack.
+ */
+void push(double val)
+{
+  struct stack *s;
+  s = (struct stack *) malloc(sizeof(struct stack));
+  s->val = val;
+  s->next = head;
+  head = s;
+}
+
+/*
+ * pops a value off the stack. generates error and returns 0.0 in case of
+ * underflow.
+ */
+double pop()
+{
+  double v;
+  struct stack *s = head;
+  if (s)
+  {
+    v = head->val;
+    head = head->next;
+    free(s);
+    return v;
+  } else
+  {
+    printf("stack underflow\n");
+    return 0.0;
+  }
+}
+
+/*
+ * adds a unique variable to the vari list.
+ */
+struct vari *addvari(char *name)
+{
+  struct vari *v;
+  for (v = vhead; v; v = v->next)
+    if (!strcmp(v->name, name))
+    {
+      printf("already exists\n");
+      return NULL;
+    }
+  v = (struct vari *) malloc(sizeof(struct vari));
+  strcpy(v->name, name);
+  v->next = vhead;
+  vhead = v;
+}
+
+/*
+ * gets the value of a variable off the variable list.
+ */
+struct vari *getvari(char *name)
+{
+  struct vari *l = vhead;
+  struct vari *k = NULL;
+
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      k = l;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+  return (k);
+}
+
+/*
+ * sets the value of a variable
+ */
+void setvari(char *name, double value)
+{
+  struct vari *l = vhead;
+  while (l)
+  {
+    if (!strcmp(name, l->name))
+    {
+      l->value = value;
+      l = NULL;
+    } else
+      l = l->next;
+  }
+}
+
+/*
+ * calculates p!
+ */
+double factorial(double p)
+{
+  if (p <= 1.0)
+    return p;
+  else
+    return (p * factorial(p - 1.0));
+}
+
+/*
+ * calculates fib(p) (fib(1)==1, fib(2)==1, fib(n)==fib(n-1)+fib(n-2))
+ */
+double fibonacci(double p)
+{
+  if (p <= 2.0)
+    return 1.0;
+  else
+    return (fibonacci(p - 1.0) + fibonacci(p - 2.0));
+}
+
+/*
+ * lists all words in bf's words list
+ */
+void words()
+{
+  struct word *w;
+  for (w = whead; w; w = w->next)
+    printf("%s ", w->name);
+  printf("\n");
+}
+
+/*
+ * list all variables in bf's vari list
+ */
+void vars()
+{
+  struct vari *v;
+  for (v = vhead; v; v = v->next)
+    printf("%-16s %f\n", v->name, v->value);
+}
+
+/*
+ * execute function of a word.  if w->fcn is 0, it will run processtr on the
+ * word.  otherwise, a built-in function will be called. see the rpn
+ * documentation on built-in functions.
+ */
+void dofunc(struct word * w)
+{
+  double a, b;
+  switch (w->fcn)
+  {
+    case 1:			/* output (.) */
+      printf("%f\n", pop());
+      break;
+    case 2:			/* add (+) */
+      push(pop() + pop());
+      break;
+    case 3:			/* subtract (-) */
+      a = pop();
+      b = pop();
+      push(b - a);
+      break;
+    case 4:			/* multiply (*) */
+      push(pop() * pop());
+      break;
+    case 5:			/* divide (/) */
+      a = pop();
+      b = pop();
+      push(b / a);
+      break;
+    case 6:			/* exponential (^) */
+      a = pop();
+      b = pop();
+      push(pow(b, a));
+      break;
+    case 7:			/* square (sqr) */
+      a = pop();
+      push(a * a);
+      break;
+    case 8:			/* square root (sqrt) */
+      push(sqrt(pop()));
+      break;
+    case 9:			/* natural logarithm (ln) */
+      push(log(pop()));
+      break;
+    case 10:			/* log base 10 (log) */
+      push(log10(pop()));
+      break;
+    case 11:			/* e^x (exp) */
+      push(exp(pop()));
+      break;
+    case 12:			/* inversion (inv) */
+      push(1.0 / pop());
+      break;
+    case 13:			/* factorial (!) */
+      push(factorial(pop()));
+      break;
+    case 14:			/* fibonacci (fib) */
+      push(fibonacci(pop()));
+      break;
+    case 20:			/* sine (sin) */
+      push(sin(pop()));
+      break;
+    case 21:			/* cosine (cos) */
+      push(cos(pop()));
+      break;
+    case 22:			/* tangent (tan) */
+      push(tan(pop()));
+      break;
+    case 23:			/* arcsine (asin) */
+      push(asin(pop()));
+      break;
+    case 24:			/* arccosine (acos) */
+      push(acos(pop()));
+      break;
+    case 25:			/* arctangent (atan) */
+      push(atan(pop()));
+      break;
+    case 26:			/* pi (pi) */
+      push(3.1415926);
+      break;
+    case 80:			/* define word (: ... ;) */
+      makeword();
+      break;
+    case 81:			/* null (;) */
+      break;
+    case 100:			/* list known words (words) */
+      words();
+      break;
+    case 101:			/* list variables (vars) */
+      vars();
+      break;
+    case 200:			/* exit bf (bye) */
+      exit(0);
+      break;
+    default:			/* user-defined word */
+      procstr(w->macro);
+  }
+}