diff interps/c-intercal/src/oil.y @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/c-intercal/src/oil.y	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,779 @@
+/*****************************************************************************
+
+NAME
+    oil.y -- compiler for Optimizer Idiom Language files
+
+LICENSE TERMS
+    Copyright (C) 2007 Alex Smith
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+***************************************************************************/
+
+%{
+
+#include "bconfig.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Autoconf lets us know if we have _Bool available, usually. On DJGPP there's
+   an occasional bug that I haven't managed to reproduce that leaves
+   SIZEOF_BOOL as the null string, so detect that ick_first. */
+#if 100 - SIZEOF__BOOL - 1 == 101
+/* The bug happened, so play safe. */
+  typedef int mybool;
+#else
+# if SIZEOF__BOOL > 0
+  typedef _Bool mybool;
+# else
+  typedef int mybool;
+# endif
+#endif
+
+/* Define strdup if it isn't available */
+#ifndef HAVE_STRDUP
+char* strdup(const char* s)
+{
+  char* t=malloc(strlen(s)+1);
+  if(t) strcpy(t,s);
+  return t;
+}
+#endif
+
+/*
+#define YYDEBUG 1
+int yydebug=1;
+*/
+
+/* Each semantic value represents either a constraint on a node that needs to
+   be true for the optimization template to match, or part of the replacement
+   for the optimization template. */
+struct ickstype
+{
+  unsigned depth;     /* The number of child nodes this is from the root */
+  unsigned long path; /* Bits from the end of this number represent the
+			 sequence of lvals (=0) or rvals (=1) this is from the
+			 root; depth bits from the end are relevant, and the
+			 bit nearest the root is least significant */
+  const char* condition; /* Points to a constant string; the condition to generate
+			 on that node. Could also point to something the lexer
+			 mallocs, but then the lexer has to keep track of being
+			 able to free it again. If this is NULL, it means that
+			 there isn't a condition other than maybe mustbemesh */
+  const char* nodetypename; /* The name of the type of node this condition matches,
+		         or NULL for a LEXERLEAF */
+  mybool usec;        /* Whether to append the value of c to the condition */
+  mybool mustbemesh;  /* Must this node be a mesh or mesh32? */
+  mybool cxneeded;    /* True means calculate c and x for the node and the
+			 condition is on those; false means append 'condition'
+			 to the node itself to form the condition and c and x
+			 aren't needed */
+  mybool width32;     /* Generate a 32-bit node? */
+  mybool ublo;        /* Is this a UBLO (if set, generate conditions
+			 to check width)? */
+  unsigned long c;    /* The value to append to the condition */
+  int replnum;        /* Number of this group for replacements */
+  struct ickstype *n1;/* n1 and n2 are pointers to other conditions that */
+  struct ickstype *n2;/* also have to be satisified */
+};
+
+#define YYSTYPE YYSTYPE
+
+#define MAXOPTNAMELEN 64
+char optname[MAXOPTNAMELEN]="undefined";
+
+typedef struct ickstype *YYSTYPE;
+
+void splitend(void);
+void splitstart(void);
+
+void treedepthup(YYSTYPE, mybool);
+void treefree(YYSTYPE);
+void gennodepath(unsigned, unsigned long);
+mybool treeshapecond(YYSTYPE, mybool);
+YYSTYPE treenscheck(YYSTYPE, YYSTYPE, int);
+void treecxcond(YYSTYPE);
+void treerepcount(YYSTYPE, int*);
+void treerepgen(YYSTYPE, YYSTYPE*, int*);
+
+int countgetchar(void);
+int countungetc(int, FILE*);
+int cgccol;
+int cgcrow;
+
+/* #defines for chaining together template expressions; here, s is the type
+   of expression (e.g. select, bitwise and, unary and) that's chaining the
+   expressions together and n is the nonterminal that's the rval */
+#define BINARYEXPR(s,m,l,r,w) do{ \
+                          m=malloc(sizeof(struct ickstype)); \
+                          m->n1=l; \
+                          m->n2=r; \
+                          m->usec=0; \
+			  m->condition="->opcode==" s; \
+                          m->nodetypename=s; \
+                          m->mustbemesh=0; \
+                          m->cxneeded=0; \
+			  m->depth=0; \
+			  m->path=0; \
+                          m->replnum=0; \
+                          m->width32=w; \
+                          m->ublo=0; \
+			  treedepthup(m->n1,0); \
+			  treedepthup(m->n2,1); \
+                          } while(0)
+
+#define UNARYEXPR(s,m,r,w,u) do{ \
+                          m=malloc(sizeof(struct ickstype)); \
+                          m->n1=0; \
+                          m->n2=r; \
+                          m->usec=0; \
+			  m->condition="->opcode==" s; \
+                          m->nodetypename=s; \
+                          m->mustbemesh=0; \
+                          m->cxneeded=0; \
+			  m->depth=0; \
+			  m->path=0; \
+                          m->replnum=0; \
+                          m->width32=w; \
+                          m->ublo=u; \
+			  treedepthup(m->n2,1); \
+                        } while(0)
+
+/* Error handling and lexing */
+int yylex(void);
+int yyerror(char const *);
+
+/* Split the output file */
+#define SPLITMAX 20
+int splitcount=SPLITMAX;
+int filenumber=0;
+mybool inloop=0;
+%}
+
+/* Various conditions can come out from the lexer. The most common is a char,
+   which represents that C or INTERCAL operation in a template. Non-character
+   tokens are used for the various possible leaves in a template, though:
+   .1 A 16-bit expression (number 1, for replacements)
+   :1 A 32-bit expression (number 1, for replacements)
+   _1 An expression of any width (again, number 1 for replacements)
+   #1 A constant with the value 1
+   #{x==1}3 A constant which equals 1 (number 3, for replacements)
+   Note that in the last example, the expression is written strictly in C;
+   for instance,
+   #{ick_iselect(x,x)==1}4
+   would select a constant that's a power of 2 (ick_iselect is the C name for the
+   INTERCAL operation 'select').
+   .{c&0xfffffffe==0}5 A 16-bit expression (number 5, for replacements) which
+   has been analysed to not possibly have any bits other than the least
+   significant set (c is here the list of all potentially set bits)
+   All of these come out as correctly set LEXERLEAFs.
+
+   Expressions with identical numbers must be node-for-node identical, except
+   for number 0 (which is like _ in Prolog, it means 'can be anything and
+   disregard the value). This holds true even if they have different sigils.
+   Expressions can use each other's c and x values with the notation c5, x4,
+   and so on; replacement numbers are limited to 1 digit.
+
+   The other things that can come out from the lexer are sparks, ears, and
+   parentheses (any mix, we're not fussy). */
+
+%token LEXERLEAF
+
+%%
+
+input: /**/ | input optimization ;
+
+optimization: template '-' '>' replacement
+{
+  static YYSTYPE tempmem[10];
+  static int replcount[10];
+  /* Handle splitting the file. */
+  if(splitcount) splitcount--;
+  if(!splitcount && !inloop)
+  {
+    splitcount=SPLITMAX;
+    splitend();
+    ++filenumber;
+    splitstart();
+  }
+  /* This is where we actually generate the optimizer code. */
+  /* Tree-shape and is-constant conditions */
+  printf("  checknodeactbits(np);\n");
+  if(treeshapecond($1,1)) printf("  if(1"); printf(")\n  do\n  {\n");
+  /* Nodesame and cxdata conditions */
+  {
+    int i=10;
+    YYSTYPE temp;
+    while(--i)
+    {
+      temp=treenscheck($1,0,i);
+      if(temp)
+      {
+	printf("    x%d=np",i);
+	gennodepath(temp->depth,temp->path);
+	printf("->constant; c%d=np",i);
+	gennodepath(temp->depth,temp->path);
+	printf("->optdata;\n");
+      }
+      tempmem[i]=temp;
+      replcount[i]=0; /* we need to zero this somewhere, may as well be here */
+    }
+    treecxcond($1);
+  }
+  /* If we reach this point in the generated code, we have an optimizer
+     template match. */
+  printf("    OPTING(%s);\n",optname);
+
+  /* We now need to replace np with its replacement. This is done by creating
+     a new nodetree, copying across tempmem'd nodes where necessary, and then
+     substituting one for the other. (This is an inefficient but general way
+     to do this.) One special case is needed; because pointers into the root
+     node need to continue pointing there, the temporary node tp is copied
+     member-for-member and then freed again. To make coding optimizations
+     easier, the root stays as the same width no matter what. */
+  printf("    tp=newnode();\n");
+  treerepcount($4,replcount);
+  treerepgen($4,tempmem,replcount);
+  printf("    nodefree(np->lval); nodefree(np->rval);\n");
+  printf("    tempw=np->width; *np=*tp; np->width=tempw; free(tp);\n");
+  printf("  } while(0);\n\n");
+  /* Free the template and replacement now they're finished being used. */
+  treefree($1);
+  treefree($4);
+}
+|      '<' LEXERLEAF '-' LEXERLEAF
+{
+  if(!$2->mustbemesh||!$4->mustbemesh)
+  {
+    yyerror("syntax error in <#..#()->()> construct");
+    free($2); free($4);
+    YYERROR;
+  }
+  printf("  r=%luLU; while(r<=%luLU) {\n",$2->c,$4->c);
+  free($2); free($4);
+  inloop=1;
+}
+|      '>' {printf("  r++;\n  }\n"); inloop=0;};
+
+template: expr3 ;
+
+expr3: '(' expr2 ')' {$$=$2;}
+|      '"' expr2 '"' {$$=$2;}
+|      '\'' expr2 '\'' {$$=$2;}
+
+expr: expr3
+|     LEXERLEAF ;
+
+expr2: expr '$' expr {BINARYEXPR("MINGLE",$$,$1,$3,1);}
+|      expr '~' expr {BINARYEXPR("SELECT",$$,$1,$3,1);}
+|      expr '~' '1' '6' expr {BINARYEXPR("SELECT",$$,$1,$5,0);}
+|      expr '~' '3' '2' expr {BINARYEXPR("SELECT",$$,$1,$5,1);}
+|      '&' '1' '6' expr {UNARYEXPR("AND",$$,$4,0,1);}
+|      '&' '3' '2' expr {UNARYEXPR("AND",$$,$4,1,1);}
+|      'V' '1' '6' expr {UNARYEXPR("OR",$$,$4,0,1);}
+|      'V' '3' '2' expr {UNARYEXPR("OR",$$,$4,1,1);}
+|      '?' '1' '6' expr {UNARYEXPR("XOR",$$,$4,0,1);}
+|      '?' '3' '2' expr {UNARYEXPR("XOR",$$,$4,1,1);}
+|      '^' '1' '6' expr {UNARYEXPR("FIN",$$,$4,0,1);}
+|      '^' '3' '2' expr {UNARYEXPR("FIN",$$,$4,1,1);}
+|      '@' '1' '6' expr {UNARYEXPR("WHIRL",$$,$4,0,1);}
+|      '@' '2' '1' '6' expr {UNARYEXPR("WHIRL2",$$,$5,0,1);}
+|      '@' '3' '1' '6' expr {UNARYEXPR("WHIRL3",$$,$5,0,1);}
+|      '@' '4' '1' '6' expr {UNARYEXPR("WHIRL4",$$,$5,0,1);}
+|      '@' '5' '1' '6' expr {UNARYEXPR("WHIRL5",$$,$5,0,1);}
+|      '@' '3' '2' expr {UNARYEXPR("WHIRL",$$,$4,1,1);}
+|      '@' '2' '3' '2' expr {UNARYEXPR("WHIRL2",$$,$5,1,1);}
+|      '@' '3' '3' '2' expr {UNARYEXPR("WHIRL3",$$,$5,1,1);}
+|      '@' '4' '3' '2' expr {UNARYEXPR("WHIRL4",$$,$5,1,1);}
+|      '@' '5' '3' '2' expr {UNARYEXPR("WHIRL5",$$,$5,1,1);}
+|      expr '&' expr {BINARYEXPR("C_AND",$$,$1,$3,1);}
+|      expr '&' '1' '6' expr {BINARYEXPR("C_AND",$$,$1,$5,0);}
+|      expr '&' '3' '2' expr {BINARYEXPR("C_AND",$$,$1,$5,1);}
+|      expr '|' expr {BINARYEXPR("C_OR",$$,$1,$3,1);}
+|      expr '|' '1' '6' expr {BINARYEXPR("C_OR",$$,$1,$5,0);}
+|      expr '|' '3' '2' expr {BINARYEXPR("C_OR",$$,$1,$5,1);}
+|      expr '^' expr {BINARYEXPR("C_XOR",$$,$1,$3,1);}
+|      expr '^' '1' '6' expr {BINARYEXPR("C_XOR",$$,$1,$5,0);}
+|      expr '^' '3' '2' expr {BINARYEXPR("C_XOR",$$,$1,$5,1);}
+|      expr '+' expr {BINARYEXPR("C_PLUS",$$,$1,$3,1);}
+|      expr '+' '1' '6' expr {BINARYEXPR("C_PLUS",$$,$1,$5,0);}
+|      expr '+' '3' '2' expr {BINARYEXPR("C_PLUS",$$,$1,$5,1);}
+|      expr '-' expr {BINARYEXPR("C_MINUS",$$,$1,$3,1);}
+|      expr '-' '1' '6' expr {BINARYEXPR("C_MINUS",$$,$1,$5,0);}
+|      expr '-' '3' '2' expr {BINARYEXPR("C_MINUS",$$,$1,$5,1);}
+|      expr '*' expr {BINARYEXPR("C_TIMES",$$,$1,$3,1);}
+|      expr '*' '1' '6' expr {BINARYEXPR("C_TIMES",$$,$1,$5,0);}
+|      expr '*' '3' '2' expr {BINARYEXPR("C_TIMES",$$,$1,$5,1);}
+|      expr '/' expr {BINARYEXPR("C_DIVIDEBY",$$,$1,$3,1);}
+|      expr '/' '1' '6' expr {BINARYEXPR("C_DIVIDEBY",$$,$1,$5,0);}
+|      expr '/' '3' '2' expr {BINARYEXPR("C_DIVIDEBY",$$,$1,$5,1);}
+|      expr '%' expr {BINARYEXPR("C_MODULUS",$$,$1,$3,1);}
+|      expr '%' '1' '6' expr {BINARYEXPR("C_MODULUS",$$,$1,$5,0);}
+|      expr '%' '3' '2' expr {BINARYEXPR("C_MODULUS",$$,$1,$5,1);}
+|      expr '>' expr {BINARYEXPR("C_GREATER",$$,$1,$3,1);}
+|      expr '>' '1' '6' expr {BINARYEXPR("C_GREATER",$$,$1,$5,0);}
+|      expr '>' '3' '2' expr {BINARYEXPR("C_GREATER",$$,$1,$5,1);}
+|      expr '<' expr {BINARYEXPR("C_LESS",$$,$1,$3,1);}
+|      expr '<' '1' '6' expr {BINARYEXPR("C_LESS",$$,$1,$5,0);}
+|      expr '<' '3' '2' expr {BINARYEXPR("C_LESS",$$,$1,$5,1);}
+|      '~' '1' '6' expr {UNARYEXPR("C_NOT",$$,$4,0,1);}
+|      '~' '3' '2' expr {UNARYEXPR("C_NOT",$$,$4,1,1);}
+|      expr '!' '=' expr {BINARYEXPR("C_NOTEQUAL",$$,$1,$4,0);}
+|      expr '!' '=' '1' '6' expr {BINARYEXPR("C_NOTEQUAL",$$,$1,$6,0);}
+|      expr '!' '=' '3' '2' expr {BINARYEXPR("C_NOTEQUAL",$$,$1,$6,1);}
+|      expr '=' '=' expr {BINARYEXPR("C_ISEQUAL",$$,$1,$4,0);}
+|      expr '=' '=' '1' '6' expr {BINARYEXPR("C_ISEQUAL",$$,$1,$6,0);}
+|      expr '=' '=' '3' '2' expr {BINARYEXPR("C_ISEQUAL",$$,$1,$6,1);}
+|      expr '&' '&' expr {BINARYEXPR("C_LOGICALAND",$$,$1,$4,0);}
+|      expr '&' '&' '1' '6' expr {BINARYEXPR("C_LOGICALAND",$$,$1,$6,0);}
+|      expr '&' '&' '3' '2' expr {BINARYEXPR("C_LOGICALAND",$$,$1,$6,1);}
+|      expr '|' '|' expr {BINARYEXPR("C_LOGICALOR",$$,$1,$4,0);}
+|      expr '|' '|' '1' '6' expr {BINARYEXPR("C_LOGICALOR",$$,$1,$6,0);}
+|      expr '|' '|' '3' '2' expr {BINARYEXPR("C_LOGICALOR",$$,$1,$6,1);}
+|      expr '>' '>' expr {BINARYEXPR("C_RSHIFTBY",$$,$1,$4,1);}
+|      expr '>' '>' '1' '6' expr {BINARYEXPR("C_RSHIFTBY",$$,$1,$6,0);}
+|      expr '>' '>' '3' '2' expr {BINARYEXPR("C_RSHIFTBY",$$,$1,$6,1);}
+|      expr '<' '<' expr {BINARYEXPR("C_LSHIFTBY",$$,$1,$4,1);}
+|      expr '<' '<' '1' '6' expr {BINARYEXPR("C_LSHIFTBY",$$,$1,$6,0);}
+|      expr '<' '<' '3' '2' expr {BINARYEXPR("C_LSHIFTBY",$$,$1,$6,1);}
+|      '!' expr {UNARYEXPR("C_LOGICALNOT",$$,$2,0,0);}
+|      '!' '1' '6' expr {UNARYEXPR("C_LOGICALNOT",$$,$4,0,0);}
+|      '!' '3' '2' expr {UNARYEXPR("C_LOGICALNOT",$$,$4,1,0);}
+|      expr ;
+
+replacement: expr3;
+
+%%
+
+#define MAXTOFREE 1000
+
+char* tofree[MAXTOFREE]={0};
+int tfi=0;
+
+int yylex(void)
+{
+  int c;
+  unsigned long acc;
+
+  /* Whitespace is completely insignificant here, even inside && and other
+     two-character operators. Just to be different, though, it /is/ significant
+     inside constructs like .1 and #{1}2; in such cases, it isn't allowed. */
+  c=countgetchar();
+  while(isspace(c)) c=countgetchar();
+  while(c==';'||c=='[')
+  {
+    /* Comments go from a semicolon/hybrid to the end of the line. */
+    if(c==';')
+    {
+      c=countgetchar();
+      while(c!='\n') c=countgetchar();
+      while(isspace(c)) c=countgetchar();
+    }
+    /* Square brackets set the name for optimizations. */
+    if(c=='[')
+    {
+      int i=0;
+      c=countgetchar();
+      while(c!=']')
+      {
+	optname[i++]=c;
+	c=countgetchar();
+	if(i==MAXOPTNAMELEN-1) {i=0; yyerror("optimization name too long");}
+      }
+      optname[i]=0;
+      c=countgetchar();
+      while(isspace(c)) c=countgetchar();
+    }
+  }
+  if(c==EOF) return 0;
+  switch(c)
+  {
+  case '#':
+    c=countgetchar();
+    if(c!='{')
+    {
+      acc=0;
+      while(isdigit(c))
+      {
+	acc*=10;
+	acc+=(c-'0');
+	c=countgetchar();
+      }
+      yylval=malloc(sizeof(struct ickstype));
+      yylval->depth=0;
+      yylval->path=0;
+      yylval->condition="->constant==";
+      yylval->nodetypename=0;
+      yylval->usec=1;
+      yylval->mustbemesh=1;
+      yylval->cxneeded=0;
+      yylval->c=acc;
+      yylval->replnum=0;
+      yylval->n1=0;
+      yylval->n2=0;
+      yylval->ublo=0;
+      yylval->width32=1; /* generate MESH32 not MESH; we can still AND16 it,
+			    etc., if necessary */
+      countungetc(c, stdin);
+      return LEXERLEAF;
+    }
+    countungetc(c, stdin);
+    c='#';
+    /* fall through */
+  case '_':
+  case ':':
+  case '.':
+    yylval=malloc(sizeof(struct ickstype));
+    yylval->depth=0;
+    yylval->path=0;
+    yylval->condition=0; /* _ or # */
+    yylval->width32=1; /* should never matter, but you never
+			  know... */
+    yylval->ublo=0;
+    if(c==':') yylval->condition="->width==32";
+    if(c=='.') {yylval->condition="->width==16"; yylval->width32=0;}
+    yylval->nodetypename=0;
+    yylval->usec=0;
+    yylval->mustbemesh=c=='#';
+    yylval->cxneeded=0;
+    c=countgetchar();
+    if(c=='{')
+    {
+      /* Create a new node to hold the c/x condition */
+      yylval->n1=malloc(sizeof(struct ickstype));
+      yylval->n1->depth=0;
+      yylval->n1->path=0;
+      {
+	static char buf[512];
+	int bi=0;
+	c=countgetchar();
+	while(c!='}')
+	{
+	  buf[bi++]=c;
+	  if(bi==511) {yyerror("{quoted} string too long"); bi=0;}
+	  c=countgetchar();
+	}
+	buf[bi]=0;
+	yylval->n1->condition=tofree[tfi++]=strdup(buf);
+	if(tfi==MAXTOFREE) {yyerror("Too many {quoted} strings"); tfi--;}
+	c=countgetchar();
+      }
+      yylval->n1->nodetypename=0;
+      yylval->n1->usec=0;
+      yylval->n1->mustbemesh=0;
+      yylval->n1->cxneeded=1;
+      yylval->n1->n1=0;
+      yylval->n1->n2=0;
+      yylval->n1->width32=yylval->width32;
+      yylval->n1->ublo=0;
+    }
+    else yylval->n1=0;
+    yylval->replnum=0;
+    if(yylval->n1) yylval->n1->replnum=c-'0'; else yylval->replnum=c-'0';
+    yylval->n2=0;
+    return LEXERLEAF;
+  default:
+    return c;
+  }
+}
+
+void treedepthup(YYSTYPE v, mybool i)
+{
+  if(!v) return;
+  treedepthup(v->n1,i);
+  treedepthup(v->n2,i);
+  v->depth++;
+  v->path<<=1;
+  v->path|=i;
+  if(v->depth>30) yyerror("Nesting too deep in template or replacement\n");
+}
+
+void treefree(YYSTYPE v)
+{
+  if(!v) return;
+  treefree(v->n1);
+  treefree(v->n2);
+  free(v);
+}
+
+void gennodepath(unsigned depth, unsigned long path)
+{
+  while(depth--)
+  {
+    if(path&1) printf("->rval"); else printf("->lval");
+    path>>=1;
+  }
+}
+
+mybool treeshapecond(YYSTYPE v, mybool firstopt)
+{
+  if(!v) return firstopt;
+  /* To prevent possibly dereferencing a null pointer, check the root ick_first */
+  if(v->mustbemesh) /* it's a must-be-constant constraint */
+  {
+    printf(firstopt?"  if((np":" &&\n     (np");
+    gennodepath(v->depth,v->path);
+    printf("->opcode==MESH || np");
+    gennodepath(v->depth,v->path);
+    printf("->opcode==MESH32)");
+    firstopt=0;
+  }
+  if(v->condition&&!v->cxneeded) /* it's a tree-shape constraint */
+  {
+    printf(firstopt?"  if(np":" &&\n     np");
+    gennodepath(v->depth,v->path);
+    printf("%s",v->condition);
+    if(v->usec) printf("%luLU",v->c);
+    firstopt=0;
+  }
+  if(v->ublo) /* generate a width check */
+  {
+    printf(firstopt?"  if(np":" &&\n     np");
+    gennodepath(v->depth,v->path);
+    printf("->width==%d",v->width32?32:16);
+    firstopt=0;
+  }
+  firstopt=treeshapecond(v->n1,firstopt);
+  return treeshapecond(v->n2,firstopt);
+}
+
+YYSTYPE treenscheck(YYSTYPE v, YYSTYPE prev, int replnum)
+{
+  if(!v) return prev;
+  prev=treenscheck(v->n1,prev,replnum);
+  prev=treenscheck(v->n2,prev,replnum);
+  if(v->replnum!=replnum) return prev;
+  if(prev)
+  {
+    printf("    if(!nodessame(np");
+    gennodepath(prev->depth,prev->path);
+    printf(",np");
+    gennodepath(v->depth,v->path);
+    printf(")) break;\n");
+  }
+  return v;
+}
+
+void treecxcond(YYSTYPE v)
+{
+  if(!v) return;
+  if(v->cxneeded&&strcmp(v->condition,"1"))
+  {
+    if(v->replnum)
+      printf("    x=x%d; c=c%d; ",v->replnum,v->replnum);
+    else
+    {
+      printf("    x=np");
+      gennodepath(v->depth,v->path);
+      printf("->constant;\n    c=np");
+      gennodepath(v->depth,v->path);
+      printf("->optdata;\n    ");
+    }
+    printf("if(!(%s)) break;\n",v->condition);
+  }
+  treecxcond(v->n1);
+  treecxcond(v->n2);
+}
+
+void treerepcount(YYSTYPE v, int* rc)
+{
+  if(!v) return;
+  if(!(v->nodetypename)&&v->replnum&&!(v->cxneeded)) rc[v->replnum]++;
+  treerepcount(v->n1, rc);
+  treerepcount(v->n2, rc);
+}
+
+void treerepgen(YYSTYPE v, YYSTYPE* refs, int* rc)
+{
+  if(!v) return;
+  /* We absolutely have to generate the root node ick_first here, because otherwise
+     the nodes in question won't exist. */
+  if(v->nodetypename) /* Generate an intermediate node */
+  {
+    printf("    MAYBENEWNODE(tp");
+    gennodepath(v->depth,v->path);
+    printf(");\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->opcode=%s;\n    tp",v->nodetypename);
+    gennodepath(v->depth,v->path);
+    printf("->width=%d;\n",v->width32?32:16);
+    /* optdata will be filled in by checknodeactbits before the ick_next idiom is
+       tested; constant is irrelevant, lval and rval are NULL at present and
+       will be filled in by later recursions of this function, and I seriously
+       hope that nextslat is never filled in by an optimizer idiom. */
+  }
+  else if(v->replnum&&!(v->cxneeded))
+  {
+    /* Copy a node from the template. The node ought not to be allocated at
+       this point, so we can safely just ick_assign to it with a new malloced
+       node. */
+    if(refs[v->replnum])
+    {
+      if(rc[v->replnum]>1||!refs[v->replnum]->depth)
+      {
+	/* The node actually has to be copied, either because another copy is
+	   needed or because it's np itself that's being copied over. */
+	rc[v->replnum]--;
+	printf("    tp");
+	gennodepath(v->depth,v->path);
+	printf("=nodecopy(np");
+	gennodepath(refs[v->replnum]->depth,refs[v->replnum]->path);
+	printf(");\n");
+      }
+      else
+      {
+	/* This can be optimized slightly by moving rather than copying,
+	   zeroing backlinks so that the node won't be freed. */
+	rc[v->replnum]--;
+	printf("    tp");
+	gennodepath(v->depth,v->path);
+	printf("=np");
+	gennodepath(refs[v->replnum]->depth,refs[v->replnum]->path);
+	printf(";\n    np");
+	gennodepath(refs[v->replnum]->depth,refs[v->replnum]->path);
+	printf("=0;\n");
+      }
+    }
+    else yyerror("Replacement isn't in the template");
+  }
+  else if(v->cxneeded)
+  {
+    /* Generate a constant node based on an expression (#{expr}0). */
+    printf("    MAYBENEWNODE(tp");
+    gennodepath(v->depth,v->path);
+    printf(");\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->opcode=MESH32;\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->width=32;\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->constant=(%s);\n",v->condition);
+  }
+  else if(v->mustbemesh&&!v->n1)
+  {
+    /* Generate a constant node based on a constant (#65535). */
+    printf("    MAYBENEWNODE(tp");
+    gennodepath(v->depth,v->path);
+    printf(");\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->opcode=MESH32;\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->width=32;\n    tp");
+    gennodepath(v->depth,v->path);
+    printf("->constant=(%luLU);\n",v->c);
+  }
+  else if(v->mustbemesh&&v->n1)
+    /* let this node's n1 handle it */ ;
+  else
+    yyerror("can't figure out how to generate a replacement node\n");
+  treerepgen(v->n1,refs,rc);
+  treerepgen(v->n2,refs,rc);
+}
+
+int yyerror(char const *s)
+{
+  fprintf(stderr,"Error at (%d:%d): \"%s\"\n",cgcrow,cgccol,s);
+  return 0; /* this return value is ignored anyway */
+}
+
+static int cgcpushback=0;
+
+int countgetchar(void)
+{
+  int c=getchar();
+  if(cgcpushback) {cgcpushback=0; return c;}
+  cgccol++;
+  if(c=='\n') {cgccol=0; cgcrow++;}
+  return c;
+}
+
+int countungetc(int c, FILE* f)
+{
+  ungetc(c,f);
+  cgcpushback=1;
+  return c;
+}
+
+void splitstart(void)
+{
+  static char fname[]="oilout00.c";
+  if(filenumber>255)
+  {
+    filenumber=255;
+    fprintf(stdout,"Input file too long.\n");
+  }
+  sprintf(fname,"oilout%02x.c",filenumber);
+  freopen(fname,"w",stdout);
+  puts("/* Automatically generated output, edit source and recompile to "
+       "change */");
+  printf("#include \"oil.h\"\n"
+	 "int optimize_pass1_%x(node *np)\n"
+	 "{"
+	 "  int opted=0;\n"
+	 "  unsigned long c,c1,c2,c3,c4,c5,c6,c7,c8,c9;\n"
+	 "  unsigned long x,x1,x2,x3,x4,x5,x6,x7,x8,x9,r;\n"
+	 "  int tempw;\n"
+	 "  node *tp;\n", filenumber);
+}
+
+void splitend(void)
+{
+  /* Disabling warnings about unused variables. gcc will optimize this right
+     out, and in any case the raise(SIGSEGV) will be unreachable (but will
+     cause a pretty recognizable error because it'll be caught by the handler
+     for SIGSEGV and output an internal error, with an obvious debug backtrace
+     if -U is used). */
+  printf("  c=c1=c2=c3=c4=c5=c6=c7=c8=c9=0;\n"
+	 "  x=x1=x2=x3=x4=x5=x6=x7=x8=x9=r=0;\n"
+	 "  if(c+c1+c2+c3+c4+c5+c6+c7+c8+c9+r+\n"
+	 "     x+x1+x2+x3+x4+x5+x6+x7+x8+x9) raise(SIGSEGV);\n");
+  printf("  return opted;\n}\n");
+  fclose(stdout);
+}
+
+int main(void)
+{
+  int e,i;
+  /*
+    "  if(!np) return 0;\n"
+    "  if(np->lval) opted|=optimize_pass1(np->lval);\n"
+    "  if(np->rval) opted|=optimize_pass1(np->rval);\n"
+  */
+  splitstart();
+  cgccol=0;
+  cgcrow=1;
+  e=yyparse();
+  while(tfi--) free(tofree[tfi]);
+  splitend();
+  freopen("oilout-m.c","w",stdout);
+  puts("/* Automatically generated output, edit source and recompile to "
+       "change */");
+  puts("#include \"ick.h\"");
+  i=filenumber+1;
+  while(i--) printf("extern int optimize_pass1_%x(node*);\n",i);
+  puts("int optimize_pass1(node* np)\n"
+       "{\n"
+       "  int opted=0;\n"
+       "  if(!np) return 0;\n"
+       "  if(np->lval) opted|=optimize_pass1(np->lval);\n"
+       "  if(np->rval) opted|=optimize_pass1(np->rval);");
+  i=filenumber+1;
+  while(i--) printf("  opted|=optimize_pass1_%x(np);\n",i);
+  puts("  return opted;\n"
+       "}");
+  return e;
+}