/*
 *   ReadIn() reads in a programmable life generation.
 */
#include "stdio.h"
static long vsize, hsize ;
#define MAXSIZE 60000L
#define MAXSTACK 20
#define MINX 1
#define MAXX (hsize - 2)
#define MINY 1
#define MAXY (vsize - 2)
#define RLEX (40)
#define RLEY (40)
static char *arr[26] ;
static short dirs[] = { -1, 0, 0, -1, 1, 0, 0, 1 } ;
static int sp ;
static long xstack[MAXSTACK], ystack[MAXSTACK] ;
static char dirstack[MAXSTACK], onstack[MAXSTACK], ddirstack[MAXSTACK] ;
static long x, y, dir, on, ddir ;
static short *globala ;
static int isrle ;
readin(a, hs, vs)
short *a ;
long hs, vs ;
{
   int c ;
   char *p ;
   int i ;
   char *prog ;

   hsize = hs ;
   vsize = vs ;
   globala = a ;
   for (i=0; i<26; i++)
      arr[i] = NULL ;
   prog = (char *)AllocMem(MAXSIZE, 0L) ;
   if (prog == NULL) return ;
/*
 *   First, we read the program into memory, stripping comments and
 *   other nonsense characters.  We enclose the whole thing in an
 *   extra pair of parenthesis.
 */
   x = hsize / 2 ;
   y = vsize / 2 ;
   dir = 2 ;
   ddir = 2 ;
   p = prog ;
   *p++ = '(' ;
   while ((c=getchar())!=EOF) {
      if (c=='<') {
         while ((c=getchar())!=EOF && c!='>') ;
         if (c==EOF || (c=getchar())==EOF) break ;
      }
      if (c >= 'A' && c <= 'Z')
         c += 'a' - 'A' ;
      if (c == '#' || (isrle && c == 'x')) {
         dir = 4 ;
         x = RLEX ;
         y = RLEY ;
         if (isrle == 0)
            isrle = 1 ;
         while ((c=getchar())!=EOF)
            if (c == 10)
               break ;
      }
      if (isrle) {
         switch(c) {
            case 'o': c = '*' ; break ;
            case 'b': c = '.' ; break ;
            case ',': c = '.' ; break ;
            case '.': isrle = 2 ; break ;
            case 10 : if (isrle == 2) c = '$' ; break ;
            default: break ;
         }
      }
      if (c == '!')
         break ;
      if ((c >= 'a' && c <= 'z') || c=='+' || c=='-' || c=='(' || c==')' ||
          c=='[' || c==']' || c=='=' || (c >= '0' && c <= '9') || c=='.' ||
          c=='*' || c==',' || c=='$' || c=='!') {
         *p++ = c ;
         if (prog + MAXSIZE - 3 <= p) {
            printf("Out of room in program space.\n") ;
            goto out ;
         }
      }
   }
   *p++ = ')' ;
/*
 *   Now we process the thing.
 */
   on = 0 ;
   sp = MAXSTACK - 1 ;
   process(prog) ;
out:   
   FreeMem(prog, MAXSIZE) ;
}
/*
 *   This routine actually does the processing.
 */
process(where)
char *where ;
{
   long param ;

   if (*where != '(')
      printf("Expected open paren!\n") ;
   where++ ;
   while (*where != ')' && *where != 0) {
      if (*where >= '0' && *where <= '9') {
         param = 0 ;
         while (*where >= '0' && *where <= '9')
            param = 10 * param + *where++ - '0' ;
      } else
         param = 1 ;
      if (*where == '(') {
         while (param > 0) {
            process(where) ;
            param-- ;
         }
         skip(&where) ;
      } else if (*where=='=') {
         where++ ;
         if (*where < 'a' || *where > 'z') {
            printf("Can't define that char!\n") ;
            *where = 'a' ;
         }
         if (where[1] != '(')
            printf("Expected definition to start with (!\n") ;
         arr[*where-'a'] = where + 1 ;
         where++ ;
         skip(&where) ;
      } else
         doone(*where++, param) ;
   }
}
/*
 *   This routine handles a single character.
 */
doone(c, param)
char c ;
long param ;
{
   switch(c) {
case '[' :
      if (sp < 0) {
         printf("Stack overflow!\n") ;
         sp = 0 ;
      }
      xstack[sp] = x ;
      ystack[sp] = y ;
      dirstack[sp] = dir ;
      ddirstack[sp] = ddir ;
      onstack[sp] = on ;
      sp-- ;
      goto setpoint ;
case ']' :
      sp++ ;
      if (sp >= MAXSTACK) {
         printf("Stack underflow!\n") ;
         sp = MAXSTACK-1 ;
      }
      x = xstack[sp] ;
      y = ystack[sp] ;
      dir = dirstack[sp] ;
      ddir = ddirstack[sp] ;
      on = onstack[sp] ;
      goto setpoint ;
case 'x' :
      x = param ;
      if (x < MINX)
         x = MINX ;
      if (x > MAXX)
         x = MAXX ;
      goto setpoint ;
case 'y' :
      y = param ;
      if (y < MINY)
         x = MINY ;
      if (y > MAXY)
         y = MAXY ;
      goto setpoint ;
case '.' :
      while (param > 0) {
         x += dirs[dir] ;
         y += dirs[dir+1] ;
         if (x < MINX)
            x = MAXX ;
         if (x > MAXX)
            x = MINX ;
         if (y < MINY)
            y = MAXY ;
         if (y > MAXY)
            y = MINY ;
         param-- ;
      }
      break ;
case 'f' :
      while (param > 0) {
         x += dirs[dir] ;
         y += dirs[dir+1] ;
         if (x < MINX)
            x = MAXX ;
         if (x > MAXX)
            x = MINX ;
         if (y < MINY)
            y = MAXY ;
         if (y > MAXY)
            y = MINY ;
         if (on)
            set(x, y) ;
         param-- ;
      }
      break ;
case '*' :
      while (param > 0) {
         x += dirs[dir] ;
         y += dirs[dir+1] ;
         if (x < MINX)
            x = MAXX ;
         if (x > MAXX)
            x = MINX ;
         if (y < MINY)
            y = MAXY ;
         if (y > MAXY)
            y = MINY ;
         set(x, y) ;
         param-- ;
      }
      break ;
case ',' :
      while (param > 0) {
         x += dirs[(dir + ddir) & 6] ;
         y += dirs[((dir + ddir) & 6) + 1] ;
         if (x < MINX)
            x = MAXX ;
         if (x > MAXX)
            x = MINX ;
         if (y < MINY)
            y = MAXY ;
         if (y > MAXY)
            y = MINY ;
         param-- ;
      }
      break ;
case '$' :
      x = RLEX ;
      y = y + param ;
      break ;
case 'l' :
      dir = (dir - ddir) & 6 ;
      break ;
case 'r' :
      dir = (dir + ddir) & 6 ;
      break ;
case 'b' :
      dir = (dir + 4) & 6 ;
      break ;
case 'u' :
      on = 0 ;
      break ;
case 'd' :
      on = 1 ;
      goto setpoint ;
case '+' :
      ddir = 2 ;
      break ;
case '-' :
      ddir = - ddir ;
      break ;
default:
      if (c < 'a' || c > 'z' || 
            arr[c - 'a']==NULL) {
         printf("Bogus! %d\n", c) ;
      } else {
         while (param > 0) {
            process(arr[c-'a']) ;
            param-- ;
         }
      }
      break ;
setpoint:
      if (on)
         set(x, y) ;
      break ;
   }
}
/*
 *   This routine skips to the end of a routine by counting
 *   parenthesis, if any.
 */
skip(where)
char **where ;
{
   char *p = *where ;
   int parencount = 1 ;

   if (*p++ == '(') {
      while (parencount > 0) {
         if (*p == '(')
            parencount++ ;
         else if (*p == ')')
            parencount-- ;
         else if (*p == 0) {
            *where = p ;
            break ;
         }
         p++ ;
      }
   }
   *where = p ;
}
