  This is the documentation of the rule control file.  Please read "README2.46"
  and "cback.doc2.46" before reading this file.

  The rules appear in this file in the same order as in "sun4/cback.rc2.46".
  If you print this file to read it, it is suggested that you also print
  "sun4/cback.rc2.46", to read in parallel.
  
#
#  Copyright (c) 1992, NewCode Technology, Inc.  All Rights Reserved.
#  You have the right to make copies of this file for use with cback.
#
#  Rules control file for cback version 2.46 on a sun4.
#  See 'rc.doc2.46' for documentation of these rules.
#
#  Simplification rules to make cfront output readable.
#  These rules do not discard any significant output of cfront.
#
input: (e) => e
  Remove parentheses when creating the parse tree.  The proper parentheses
  are added before the tree is output.
  
  This is one of the most useful rules and without it many of the other
  rules that affect expressions don't do anything since the parentheses
  prevent the recognition of the appropriate sections of the parse tree.

expr: (e) => e
  This has the same effect as 'input: (e) => e', but it happens later in
  the program.

expr: a,(b,c,d),e => a,b,c,d,e
  Reorder precedence in comma expressions to the more natural left to right
  precedence.

expr: &*e => e
expr: *&e => e
expr: (&a)->b => a.b
expr: (*a).b => a->b
  Many of these sequences of operators come into existence because of
  references passed to inline functions.  These rules change the expression
  to a simplified version.

expr: (a,b,c)%d => a,b,c%d
expr: (a,b,c)[d] => a,b,c[d]
expr: (a,b,c)?d:e => a,b,c?d:e
expr: (a,b,c).d => a,b,c.d
expr: (a,b,c)->d => a,b,c->d
expr: (a,b,f)(c,d,e) => a,b,f(c,d,e)
  Move a comma expression in the left side of an operator outside of the
  of the operator.

  There are similar rules which applies to the right side of operators.
  But since it may reorder the evaluation order it is considered a dangerous
  rule.  See below for the 'expr: a%(b,c,d) => b,c,a%d' rule.

expr: (T)(a,b,c) => a,b,(T)c
  Move a cast of a comma expression into the comma expression.

expr: ~(a,b,c) => a,b,~c
  Move a unary operator applied to a comma expression into the comma
  expression.  This applies to most of the unary operators that can take
  a comma expression, that is:

	*, &, -, ~, !

  It also applies to the comma operators which cannot take a comma
  expression, but which might have one temporarily created by inside
  cback, that is:

	--, ++

expr: i[a] => a[i]
  Reverse a vector operation that has its operands backwards to the more
  natural order, with the vector outside '[' and ']', and the index inside
  '[' and ']'.

expr! int a[7]; *a => a[0]
  Convert derefencing an array, to accessing the first element of that array.

bool: a&&(b&&c) => a&&b&&c
  Reorder right to left precedence in && expressions to the more natural left
  to right precedence.

bool: a||(b||c) => a||b||c
  Reorders right to left precedence in || expressions to the more natural left
  to right precedence.

expr: struct x *p; ((y *) p)->m => p->m
  Remove the cast of a struct pointer to another structure pointer when
  being used in a '->' expression if both structures have similar elements.

  For example in the following:

	struct y
	{ int	i;
	  short	s;
	  char	c;
	};

	struct x
	{ int	i;
	  short s;
	  char	c;
	  int	j;
	};

	struct x *p;

	char test ()
	{ return ((struct y *) p)->c;
	}

  The function is simplified to:

	char test ()
	{ return p->c;
	}

  Since the 'c' member of struct 'x', is identical to the 'c' offset of
  struct 'y'.  'Identical' means having the same name and same type, as
  well as all preceding members having the same name and same type.

  Expressions that this rule applies to are very common because of
  inheritance and inline functions.

  Due to a limitation in the current version, members with fields are not
  recognized as having the same type.

expr: struct x *p; ((y *) p)->m1 => p->m2
  This is the same as the previous rule, but the members don't have to 
  have the same name.

  Due to how cfront 2.x does padding inside of structure (creating different
  names for padding members in base and derived classes), this rule should be
  turned on for 'c' code created from a cfront 2.x derived program.

expr! union x *p; ((y *) p)->m => p->m
  This is the same as the rule applying the structures, but it applies
  to unions.  Unlike structures, the preceding members are not compared,
  since all members in a union have an offset of 0.

  Due to the fact that it is impossible to use inheritance from unions,
  expressions of this form should not be generated, and thus this rule
  should be turned off.

expr! union x *p; ((y *) p)->m1 => p->m2
  This is the same as the previous rule, but any member with the same
  type will be used.

void! --e => e--
  Change a predecrement to a postdecrement when the value of the predecrement
  is not used.

void! ++e => e++
  Change a preincrement to a postincrement when the value of the preincrement
  is not used.

#
#  Simplification rules which discard unused parts of expressions.
#
expr: (T)e => e // when T == typeof(e)
  Remove a cast of an expression to the same expression.

  The cast is considered identical if it is the same as the type of 'e',
  or the promoted type of 'e' in a rvalue context.  In other words, the
  following:

      long test ()
      { short e = 2;

	return (short) e + (int) e + (long) e;
      }

  Becomes:

      long test ()
      { short e = 2;

	return e + e + (long) e;
      }

  That is casting 'e' to either a 'short' or a 'int' is removed by this
  rule.  But of course casting 'e' to a 'long' is not.

bool: remove 0's and 1's in conditionals
  This removes most 0's and 1's in conditionals, it has the effect on all the
  following (expressed as rules normally are):

    !0 => 1
    !1 => 0
      Self explanatory.

    0?a:b => b
    1?a:b => a
      Return the appropriate part of a ternary expression.  This is only done
      if either:

	1.  The result would have the same type as the ternary expression.
	2.  The result is not used (appears in a void context).

      In other words the following:

	f (0 ? 2.0 : 3);

      is not converted:
	    
	f (3);

      Since the original ternary expression has the indirect effect of casting
      the 3 to a double.

    1||e => 1
    0&&e => 0
      Remove the second part of a '||' or '&&' which is never executed.

    0||e => e
    e||0 => e
    1&&e => e
    e&&1 => e
      Remove a useless test in a '||' or '&&'.  This is only done if either:

	1.  The test appears in a boolean or void context.
	2.  'e' has a value of either '0' or '1'.

      In other words the following:

	f (this && 1);

      is not converted to:

	f (this);

      Since the original '&&' had the effect of converting 'this' to
      a '0' or a '1'.

    e||1 => e,1
    e&&0 => e,0
      Convert a known value of a '||' or '&&' expression to a comma
      expression.

    a||(b,1) => a||b,1 => a?0:(b,0),1
    a&&(b,0) => a&&b,0 => a?b,0:0,0
      This is a more complex example of the previous rule, which converts a
      known value of a '||' or '&&' expression to a comma expression.
	    
      However this also needs to evaluate 'b' depending on the value of 'a'.
      If possible it converts it to the form like:

	a || b, 1

      which preserves the original '||' or '&&'.  However the type of 'b' may
      be void or a struct/union, in which case it would be invalid in a '||'
      or '&&' expression, so instead it is converted to a ternary expression
      like:

	(a ? 0 : (b, 0)), 1

      which although it looks longer than the original, should produce less
      code in most compilers.  In some compilers this might produce more code.

bool: (struct x *)e => e // when typeof(e) == (struct y *)
  Remove a cast of a structure pointer to another structure pointer, when it
  appears in a boolean context, that is being tested for nil or non-nil.

bool: (struct x *)a>(struct x *)b => a>b // when typeof(a&b) == (struct y *)
bool: (struct x *)a==(struct x *)b => a==b // when typeof(a&b) == (struct y *)
  Remove casts of struct pointers to another struct pointer, when they
  are being compared with each other.

  The first rule affects the four comparisons '>', '>=', '<', and '<='.
  The second rule affects the comparisons '==' and '!='.

  A '0' may appear on either side of the comparison, and the rule will
  still take effect.

bool: !!e => e
  Remove a double '!', if the 'e' appears in a boolean context, or 'e'
  has a value of either '0' or '1'.

bool: e!=0 => e
  Remove a comparasion to '0', if 'e' appears in a boolean context, or 'e'
  has a value of either '0' or '1'.

bool: var=7 => var=7,1
  Change an assignment of a constant to a variable, to a comma expression
  when used in a boolean expression.  In most cases other rules will then
  move the 'var=7' out of the boolean expression, leaving just the '1'
  in the boolean expression; then the '1' will often be removed by simplifying
  the boolean expression furthur.

  NOTE:  The value of the assigned constant may be zero, in which case the
  comma expression appends a '0' not a '1' to the original expression.  That
  is it behaves as if it was the following rule:

    bool: var=0 => var=0,0

expr: (struct x *)(struct y *)a => (struct x *)a
   Remove a double cast of an expression to a struct type.

expr: (T*)(struct x*)e => (T*)e // when typeof(e) == (struct y *)
   Remove a struct pointer cast when it is wedged in between a cast to any
   pointer on the left and an expression with a struct pointer type
   on the right.

expr: (struct x*)(char *)e => (struct x*)e // when typeof(e) == (struct y*)
   Remove a char pointer cast when it is wedged in between a struct pointer
   cast on the left and an expression with a struct pointer type on the right.

expr! !(a>b) => a<=b // when typeof(a&b) == double
expr: !(a>b) => a<=b // when typeof(a&b) == any integer
expr: !(a>b) => a<=b // when typeof(a&b) == any pointer
expr! !(a==b) => a!=b // when typeof(a&b) == double
expr: !(a==b) => a!=b // when typeof(a&b) == any integer
expr: !(a==b) => a!=b // when typeof(a&b) == any pointer
  These rules simplify comparisons.  The first three rules apply to the
  '>', '>=', '<', and '<=' operators.  The last three rules apply to
  '==' and '!=' operators.

  The rules are divided into what they operate on.  Due to the presence
  of 'NaN's in doubles, there is a possibility that both:

	a > b

  and
	
	a <= b

  return false, instead of being complements of one another.  Therefore
  the rule for doubles should be turned off if your c compiler generates
  'NaN's, or any other sort of double's whose opposing comparisons don't
  always have opposite results.

expr: !a?b:c => a?c:b
  Simplify a ternary expression.

expr: e+0 => e
  Remove an addition of a '0'.  This is only done if the '+' operator does
  not cause a default type conversion.  That is, in the following case:

	1 + (long) 0

  the '+ (double) 0' is not removed, although it is removed in the following
  case:

	1L + (long) 0

expr: e==0 => !e
  Simplify a comparison to 0.

void: a%b => a,b
  Discard binary operators appearing in a void context.  This applies to
  all binary operators except the assignment operators.

  A "void context" means the result is not used, that is:
  
    1.  An expression which appears as a statement.
    2.  The first or third part of a 'for' statement.
    3.  The left part of a comma expression.

  For example in the following:

    for (a; b, c; d)
      e;

  The expressions 'a', b', 'd', and 'e' are in a 'void context'.  Expression
  'c' is not in a "void context": it is used to as the test to terminate
  the for loop.

void: (T)e => e
  Discard casts appearing in a void context.

void: constant =>
  Discard constants appearing in a void context.

void: a.b => a
  Discard '.' operators appearing in a void context.

void: ~e => e
  Discard unary operators appearing in a void context.  This applies to
  the following unary operators:

	*, &, -, ~, !

void: a->b => a
  Discard '->' operators whose value is not used.

void: sizeof e =>
  Discard sizeof expressions appearing in a void context.

void: var =>
  Discard variables appearing in a void expression.

void: a[i] => a,i
  Discard '[]' operators appearing in a void context.

void: a&&b => a&&void(b) => a?b,0:0
void: a||b => a||void(b) => a?0:(b,0)
  When the result of an '&&' or '||' operator is not used, try to
  to eliminate the right side of the operator by assuming that its
  value is not used.  If it is totally eliminated, then try to eliminate
  the left side also.

  However, there is the possibility that the right side after being partially
  eliminated will no longer be valid as the right side of an '&&' or '||'
  operator (due to having a void or struct/union type).  If this is the
  case it is then converted to a ternary expression like:

	(a ? 0 : (b, 0))

  which although it looks longer than the original, should produce less code
  in most compilers.  In some compilers this might produce more code.

void: struct x { int m; }; *(struct x*)a=*(struct x*)b => a->m=b->m
  Convert copying a structue pointer, by casting it to another structure,
  to simply copying the first element, if that structure it is cast to, 
  only has one element, with a non-array type.

#
#  Rename variables and structure members.
#
dcln: T __0x; => T x;
  Rename automatic variables and static variables inside of a function back
  to their original names.  This recognizes variables that cfront 2.x
  generates.

  If a conflict would result from renaming the variable back to its
  original name it is not renamed.

  A conflict is defined as any variable at file scope or in the same
  function that has the same name after the '__0' is removed.
  
  Note that in the case of two variables in the function that are named
  the same, the first would be renamed, but the second and subsequent
  would not, even if they would not conflict.  This is a bit too
  restrictive, but is not very likely to happen.

  If a variable is renamed then its associated 'asm (".stab var:Ztl")'
  line is removed if any such line exists.

dcln: T _au0_x; => T x;
  Rename automatic variables back to their original names.  This recognizes
  variables that cfront 1.2 generates.

  If a conflict would result from renaming the variable back to its
  original name it is not renamed.  See comment above for definition
  of "conflict".

dcln: T _static_x; => T x;
  Rename static variables inside of functions back to their original names.
  This recognizes variables that cfront 1.2 generates.

  If a conflict would result from renaming the variable back to its
  original name it is not renamed.  See comment above for definition
  of "conflict".

dcln: struct x { T m__1x; } => struct x { T m; }
  Rename struct members back to their original names.  This recognizes
  members that cfront 2.x generates.

  If a conflict would result from renaming the member back to its
  original name it is not renamed.

  In certain pathological cases it is will get the original name wrong,
  for example the following c++ code:

    struct fools
    { int	gold__9A;
    };

    struct A__5fools
    { int	A;
    };

    struct again : fools
    {
    };

  creates the following c code:

    struct fools
    { int	gold__9A__5fools;
    }

    struct A__5fools
    { int	gold__9A__5fools;
    }

    struct again
    { int	gold__9A__5fools;
    };

  And in struct 'again' it is impossible to tell whether to rename
  'gold__9A__5fools' to 'gold__9A' or to 'gold'.
  
  In actuality (unlike the following rule which guesses at inheritance),
  the 2.x rule does not bother to guess at inheritance and incorrectly
  renames all three example to 'gold', even in struct 'fools'.  However,
  the resulting code will compile correctly.

dcln: struct x { T _x_m; } => struct x { T m; }
  Rename struct members back to their original names.  This recognizes
  members that cfront 1.2 generates.

  If a conflict would result from renaming the member back to its
  original name it is not renamed.

  To execute this rule it is necessary to attempt to guess what a 
  structure may have been derived from, and this is not always successful
  in pathological cases.  For example the following c++ code:

    struct a
    { int	b_d;
    };

    struct a_b
    { int	d;
    };

    struct e : a
    { int	f;
    };

  Creates the following c code:

    struct a
    { int	_a_b_d;
    };

    struct a_b
    { int	_a_b_d;
    };

    struct e
    { int	_a_b_d;
      int	_e_f;
    };

  And it is impossible to tell if 'e' is derived from 'a' or 'a_b', and thus
  whether to rename the member '_a_b_d' of struct 'e' to 'b_d' or to 'd'.

  The actual algorithm used will assume that 'e' is derived from 'a_b',
  and produce the wrong name in this pathological case.  However, the
  resulting code will compile correctly.

dcln: struct x { T1 y_m1; T2 x_m1; } => struct x { T1 y_m1; T2 m1; }
  When either of the previous two rules is in effect, a conflict
  may arise in renaming members back to their original name.

  If this is the case, this rule will still rename the last member with
  the same name.  For example, the following c++ source code:

    struct x
    { int	a;
      int	b;
    };

    struct y : x
    { int	b;
      int	c;
    };

  Creates the following c code:

    struct x
    { int	_x_a;
      int	_x_b;
    };

    struct y
    { int	_x_a;
      int	_x_b;
      int	_y_b;
      int	_y_c;
    };

  With the rule to rename struct members, and the above rule turned off
  it would generate:

    struct x
    { int	a;
      int	b;
    };

    struct y
    { int	a;
      int	_x_b;
      int	_y_b;
      int	c;
    };

  That is neither '_x_b' nor '_y_b' is renamed.  With the above rule turned
  on it would generate:

    struct x
    { int	a;
      int	b;
    };

    struct y
    { int	a;
      int	_x_b;
      int	b;
      int	c;
    };

  That is with '_x_b' being left alone, but '_y_b' being renamed to 'b'.

#
#  Remove unused declarations.
#
dcln! typedef int x (); x *y; => int (*y)();
  Remove 'typedefs', and substitute their types where they are used.

  The current version of cback always removes typedefs in structure members.

  This rule is temporarily turned off by default due to the fact that
  is causes problems with ansi output.  This problems will be fixed in
  future versions of cback and this rule will be turned on by default.

dcln: remove unused structs and variables
  Remove all unused structs, unions, and variables from the program.  This
  includes unused static functions.   The following seven rules are only in
  effect when this rule is turned on, and allow some control over what is
  removed.

  The special variable (used for the "patch" program):

    static struct __link { ... } __LINK = { ... };

  is never removed, even though '__LINK' is "unused" in the current file.

dcln: remove bodys of indirectly used structs
  Remove the body of a struct or union that is not actually needed to compile
  the resulting c code.  For example, the following:

	struct x
	{ double	a;
	};

	struct y
	{ int		b;
	};

	struct z
	{ struct x     *p;
	  struct y	q;
	};

	struct z v = { 0, { 0, } };

  is converted to:

	struct x;

	struct y
	{ int		b;
	};

	struct z
	{ struct x     *p;
	  struct y	q;
	};

	struct z	v = { 0, { 0, }, };

  Since 'struct x' is never used directly.

  Note that cback cannot read its own output if this rule is turned on.

dcln! static T __used_var_; =>
  All unused static variables are normally removed.  However static variables
  whose name begins with "__used_var_" are only removed if this rule is turned
  on.

dcln: static char unused[] = "..."; => // at {} scope
  All unused static variables are normally removed.  However static char
  arrays that are inside of functions are only removed if this rule is turned
  on.  This is to allow the following:

      void stub ()
      { static char	comment[] = "This is a stub function - do not release";
      }

  not to be removed by leaving this rule turned off.

file! static char unused[] = "..."; => // at file scope
  All unused static variables are normally removed.  However static char
  arrays at file scope are only removed if this rule is turned on.  This is
  to allow the following:

      static char copyright[] = "Copyright (c) 1992, NewCode Technology, Inc.";

      void main ()
      {
      }

  not to be removed by leaving this rule turned off.

file! static struct __link { ... } __LINK = { ... } =>
file! static struct __linkl { ... } __link = { ... } =>
  All unused static variables are normally removed.  However these special
  variables are created by cfront configured for the patch option.  Therefore,
  in its default mode, cback will not remove these special static variables.
  Turning this rules on will remove these special variables.  Useful if you
  really want to use the munch option with a patch configured cfront.

file! remove unused static _STD, _STI, _std, _sti functions
  All unused static functions are normally removed.  However these special
  functions are created by cfront to initialize statically allocated
  variables.  Therefore, in its default mode, cback does not remove static
  function which begin with the names '_STD', '_STI', '_std', or '_sti'.
  Turning this rule on will remove these special functions.  In the vast
  majority of cases this rule should be left turned off.

#
#  Statement Rules
#
stat: ; =>
  Remove null statements.

stat: a,b,c; => a; b; c;
  Convert statements consisting of a comma expression to separate statements.

stat: a&&b; => if (a) b;
stat: a||b; => if (!a) b;
stat: a?b:c; => if (a) b; else c;
  Convert a statement consisting of a conditional expression to an 'if'
  statement.

stat: if (1) s; => s
  Cleanup an 'if' statement with a trivially true condition.

stat: if (e) ; => e;
stat: if (e) ; else ; => e;
stat: if (e) s; else ; => if (e) s;
stat: if (e) ; else s; => if (!e) s;
  Cleanup 'if' statements with empty substatements.

stat! for (a,b,c; d;) s; => a; b; c; while (d) s;
  Cleanup a 'for' statement with a comma expression for the 'initial'
  expression and no 'end' by converting the 'initial' expression to
  separate statements, and the 'for' statement to a 'while' statement.
  
stat: for (a,b,c; d; e) s; => a; b; for (c; d; e) s;
  Cleanup up a 'for' statement with a comma expression for the 'initial'
  expression, by converting most of the 'initial' expression to separate
  statements.  The last part of the 'initial' expression is left in
  the 'for' statement (in contrast to the previous rule).

stat! for (; c;) s; => while (c) s;
  Convert a 'for' statement without an 'initial' or 'end' statment to a
  'while' statement.

stat: if (a,b,c) s; => a; b; if (c) s;
stat: switch (a,b,c) s; => a; b; switch (c) s;
stat: return a,b,c; => a; b; return c;
  Cleanup an 'if', 'switch', or 'return' statement with a comma expression by
  converting most of the comma expression to separate statements.

stat: return a?b:c; => if (a) return b; else return c;
stat: return (T*)(a?b:c); => if (a) return (T*)b; else ...;
  Convert a return expression with a ternary operator to an 'if' statement
  with two 'return' substatements.

#
#  Output Formatting
#
output: T a=b=c => T a=(b=c)
  Add an extra set of parentheses to an initialization of a variable with
  an assignment statement to make it more readable.  The following code:

	extern int f ();

	int test ()
	{ int	a;
	  int	b = a = f (20);

	  return a + b;
	}

  is converted to the following:

      extern int f ();

      int test ()
      { int	a;
	int	b = (a = f (20));

	return a + b;
      }

output: a?b:c?d:e => a?b:(c?d:e)
  Add an extra set of parentheses to a ternary expression as the last part
  of another ternary expression to make it more readable.

output: #line 7 "file.cc"
  Output '#line' statements to synchronize any error messages from 'cc' or
  for debugging.  This rule alone controls the output of '#line' statements.
  The following four rules modify how the '#lines' are output when this
  rule is turned on.

output: #line 7
  Don't output the filename on a '#line' if it is identical to the previous
  '#line'.  This rule makes output much more readable.

output: #7 "file.cc"
  Allows the linenumber to be output after the '#' without the 'line '
  keyword.

output! # 7 "file.cc"
  Similar to the previous rule but inserts a space between the '#' and
  the linenumber.

output! uninitialized variables with #line
  Output the '#line' on all declarations at the file scope including
  uninitialized declarations.  Usually the '#line' is not needed for
  these declarations, and thus this rule is off by default.

output: first uninitialized variable with #line
  Output the '#line' on the first declaration at file scope even if it is an
  uninitialized declaration, if no other '#line' has already been output.
  This rule may be needed for debuggers that need to see a '#line' before any
  declerations.

output: original first #line
  Output the first '#line' that was seen in the input as the first '#line'.
  This rule may be needed for debuggers that need to see a '#line' before any
  declerations.

#
#  Aggressive Rules
#
cleanup: STI
  Convert what an STI function does to an initialization operator when
  the STI functions consists only of assignments.  The actual code
  of the STI function is left inside a comment.  For example, the following:

    /*
     *  Input to cback, using 'cback -r /dev/null'
     */
    struct filebuf	 cin_file;
    struct istream	 cin;

    char _STIin_cc_ ()
    { ((((((((((struct streambuf *) (&cin_file)))->_streambuf__vptr
	       = streambuf__vtbl),
	    (((((struct streambuf *) (&cin_file)))->_streambuf_base
		= ((((struct streambuf *) (&cin_file)))->_streambuf_gptr
		     = ((((struct streambuf *) (&cin_file)))->_streambuf_pptr
			  = ((((struct streambuf *)
				 (&cin_file)))->_streambuf_eptr = 0)))),
	     (((((struct streambuf *) (&cin_file)))->_streambuf_alloc = 0),
	      (((((struct streambuf *) (&cin_file)))->_streambuf_fp = 0),
	       (((((struct streambuf *) (&cin_file))))))))))),
	 ((&cin_file)->_streambuf__vptr = filebuf__vtbl)),
	(((&cin_file)->_streambuf_fp = (&(_iob[0]))),
	 (((&cin_file)->_filebuf_opened = 1), (((&cin_file)))))));

      ((((&cin)->_istream_state = 0),
	(((&cin)->_istream_skipws = 1),
	 (((&cin)->_istream_tied_to = (&cout)),
	  (((&cin)->_istream_bp
	      = ((struct streambuf *) (&cin_file))), (((&cin))))))));
    }

  gets converted to:

    /*
     *  Actual output from cback, using 'cback -r /dev/null'
     */
    struct filebuf cin_file = { (char *) 0,
				(char *) 0,
				(char *) 0,
				0,
				0,
				&_iob[0],
				filebuf__vtbl,
				0,
				1,
			      };

    struct istream	cin = { (struct streambuf *) &cin_file, &cout, 1, 0, };

    char _STIin_cc_ ()
    { /*
      cin_file._vptr = streambuf__vtbl;
      cin_file.base = cin_file.gptr = cin_file.pptr = cin_file.eptr = 0;
      cin_file.alloc = 0;
      cin_file.fp = 0;
      cin_file._vptr = filebuf__vtbl;
      cin_file.fp = &_iob[0];
      cin_file.opened = 1;
      cin.state = 0;
      cin.skipws = 1;
      cin.tied_to = &cout;
      cin.bp = (struct streambuf *) &cin_file;
      */
    }

cleanup: trace variable usage
  This is a very agressive rule, it traces how variables are used, and does
  two things:

      1.  Removes any assignments to variables, when the value of the
	  variable is not subsequently used.

      2.  Does variable substitution when variables are set to constants.

  For example, the following code:

      void test ()
      { int	a;
	int	b;

	a = 7;
	b = f ();
	b = a;

	return b;
      }

  is converted to the following code:

      void test ()
      { f ();
	return 7;
      }

bool! a=(struct x*)__nw(sizeof(struct x)) => a,1
bool! __nw(sizeof(struct x)) => 1
void! __dl((char *)p) => p
  Remove calls to '__dl', '__dl__FPv', '__nw', and '__nw__FUi'.  These rules
  should only be turned on if your C++ code does not call 'new'.  That is, the
  code only allocates classes statically and not dynamically.

  Note:  these rule were spelled (and implemented) differently in cback version
	 1.49, 1.50, and 1.51, and are temporarily accepted in the old format
	 as:

	    bool! a=(struct x *)__nw(b) => a,b,1
	    bool! __nw(e) => e,1
	    void! __dl(e) => e

	 The new implementation allows the return the calls to '__dl' and
	 '__nw' to be in their overload version, that is '__dl__FPv' and
	 '__nw__FUi'.  It also checks more carefully for the type of
	 expression passed to '__dl' and '__nw' before applying these ruels.

bool! a=(struct x *)__nw__FUi(b) => a=(struct x *)__nw__FUi(b),1
  When testing the value of assignment to a variable from the function
  call '__nw__FUi', convert this to a comma expression with the last
  part being a '1'.  In other words assume that the value returned
  from '__nw__FUi' is always non-nil.

bool: &e->m => e,1 // when 'm' has a non-zero offset
  Convert an expression that in all normal situations has to have a non-zero
  value in a boolean context, to a 1.  That, is the expression '&e->m' is the
  same as 'e + offsetof(e, m)', and when 'm' has a non-zero offset, then
  unless 'e' has the very unusual value of 'e - offsetof(e,m)' the expression
  always evaluates to '1'.

bool: &var => 1
  Convert the address of a variable in a boolean context to a '1'.  No
  variable should have a address of zero according to the definition of
  the C language, therefore it will always evaluate to '1'.

bool: constant => 1
  Convert a non-zero constant to a '1' when used in a boolean context.
  A constant also means an variable of type vector or function (both
  of which are converted to the constant address of the variable, and 
  thus evaluate to '1' in a boolean constant).

dcln: extern int x (); static int x (); => static int x (); static int x ();
  When a function is declared inconsistently as both 'extern' and 'static',
  then modify all declarations of the function to be consistent in declaring
  the function as 'static'.   This rule needs to be used for c compilers
  which complain about a function changing its storage classes.  Such code
  is sometimes produced for inline functions which are later turned into
  static functions at the end of the file.

file! int x; => extern int x;
  Convert an uninitialized declaration to an extern.  Needed by C compilers
  that implement uninitialized common variables as initialized data
  variables.

expr: f(a,(b,c,d),e) => b,c,f(a,d,e)
expr: a%(b,c,d) => b,c,a%d
expr: a[b,c,d] => b,c,a[d]
  These rules simplify comma expressions by moving part of the comma
  expression outside of the operator.  However, these rules potentially
  change the order of evaluation, thus if there are interdependencies between
  expressions 'a' and 'b', the code could produce different results.

  Notice that the new order of evaluation is a valid order of evaluation
  for the original expression, thus the rule does make sense.
  However, a particular c compiler may chose different orders of evaluation
  for the two different expressions.

  If the code does produces different results because of this rule,
  you should consider changing the code.

expr: a||(a=b)?a||d?e:f,g:h => a||(a=b)?1||d?e:f,g:h
expr: a||(a=b)?c=a,c||d?e:f,g:h => a||(a=b)?c=a,1||d?e:f,g:h
stat: if (a||(a=b)) { a||c?d:e; f; } => if (a||(a=b)) { 1||c?d:e; f; }
  These rules, are designed to cleanup contructors.  The first and third
  rule are designed to cleanup constructors produced by cfront 2.0; the
  second rule, when used in conjection with the other two rules, is
  designed to also cleanup constructors produced by cfront 2.1.  For example
  the following code:

    __Xthis00ibkqga = &d,
    __Xthis00ibkqga
      || (__Xthis00ibkqga = (struct c *) __nw__FUi (sizeof (struct c)))
      ? __Xthis00yydqdl = (struct b *) __Xthis00ibkqga,
	__Xthis00yydqdl
	  || (__Xthis00yydqdl = (struct b *) __nw__FUi (sizeof (struct b)))
	  ? __Xthis00itvpcc = (struct a *) __Xthis00yydqdl,
	    __Xthis00itvpcc
	      || (__Xthis00itvpcc = (struct a *) __nw__FUi (sizeof (struct a)))
	      ? __Xthis00itvpcc->__vptr = __vtbl__1a, __Xthis00itvpcc->a1 = 10
	      : 0,
	    __Xthis00yydqdl = (struct b *) __Xthis00itvpcc,
	    __Xthis00yydqdl->__vptr = __vtbl__1b,
	    __Xthis00yydqdl->b1 = 10
	  : 0,
	__Xthis00ibkqga = (struct c *) __Xthis00yydqdl,
	__Xthis00ibkqga->__vptr = __vtbl__1c,
	__Xthis00ibkqga->c1 = 10
      : 0;

  is converted to the following code:

    __Xthis00ibkqga = &d,
    __Xthis00ibkqga
      || (__Xthis00ibkqga = (struct c *) __nw__FUi (sizeof (struct c)))
      ? __Xthis00yydqdl = (struct b *) __Xthis00ibkqga,
	__Xthis00itvpcc = (struct a *) __Xthis00yydqdl,
	__Xthis00itvpcc->__vptr = __ptbl_vec___d_[0],
	__Xthis00itvpcc->a1 = 10,
	__Xthis00yydqdl->__vptr = __ptbl_vec___d_[1],
	__Xthis00yydqdl->b1 = 10,
	__Xthis00ibkqga->__vptr = __ptbl_vec___d_[2],
	__Xthis00ibkqga->c1 = 10
      : 0;

expr: a=b,a=c => b,a=c
  Remove assignment to the same variable twice in a row.  This rule is
  only implemented for a few special cases, and is mostly useful for
  removing multiple assignments of 'vtbls'.

expr: strlen("abc") => (size_t)(sizeof"abc"-1)
  Convert a strlen function to a sizeof function.  This rule is unsafe
  if the implementation of 'strlen' is not the standard definition.

  Note:  the rule was spelled (and implemented) differently in versions of
	 cback prior to 1.52, and is temporarily accepted in the old format
	 as:

	    expr: strlen ("abc") => (int) sizeof "abc" - 1

	 The new implementation allows the return type of 'strlen' to
	 be either 'int' or 'unsigned int' and creates an expression of
	 the same type as the return type of 'strlen'.

expr: strrchr("Technology",'o') => "Technology"+7
  Convert a strrchr function with constant arguments to a string.  This rule
  is unsafe if the implementation of 'strrchr' is not the standard definition.

expr: (struct x *) ((char *) e + const_int) => &e->Ox
  Convert an offset of a structure pointer back to an expression using the
  actual members of the function.

  Note:  the rule was misspelled in versions of cback prior to 1.52, and is
	 temporarily accepted in the old format (with a 'P' instead of a 'O')
	 as:

	    expr: (struct x *) ((char *) e + const_int) => &e->Px

  To apply this rule correctly it is necessary to know member offsets
  within structures.  The machine specific size rules are used for
  this purpose. 

  For example the following code:

	__dt__4linkFv ((struct link *) ((char *) this + 12), 0);

  is converted to:
	
	__dt__4linkFv (&this->Olink, 0);

  This may help with symbolic debuggers.

expr! f((struct x *) e) => f(e) // when typeof(e) == (struct y *)
  Remove the cast of a struct pointer to another struct pointer when it
  is being passed as a function argument.

  This rule is only valid for non-ansi output, it makes the code more
  readable to a human reader.

expr: v=v => v,v
  Remove an assignment of a variable to itself.

expr! p->__vptr[7].d => p,(short)0
  Change the lookup of a multiple inheritance offset in the virtual table to a
  constant '0'.  This rule should only by used if multiple inhertiance is
  not used in the code at all, and therefore all multiple inheritance offsets
  are 0.  In this case, this rule can have a significant effect on both the
  resulting code size and the execute speed.

expr! (T1*)(T2*)a => (T1*)a
   Remove a double cast of an expression to a pointer type.  This rule is
   only safe if all pointer types are the same length.

expr! (T1*)(T2*)0 => (T1*)0
   Remove a double cast of a 0 to a pointer type.  This rule is turned off
   in this version, since it has not been thoroughly tested yet.

expr! (*(char(*)())pf)(a,b,c) => (*pf)(a,b,c) // when typeof(pf) == (int(*)())
   Remove a cast of a pointer to a function returning int, to a pointer to
   a function returning char in a function call.

file! move structs, unions, enums, and typedefs
  Reorder the declarations at the file level in the following order:

    1.  sun 'asm' header statements and #ident statments.
    2.  typedefs.
    3.  enum, struct, and unions without a body; these are created by the
	the following rule:

		dcln: remove bodys of indirectly used structs.

    4.  enum, struct, and unions.
    5.  sun 'asm' statements describing structs and unions.
    6.  extern functions.
    7.  extern variables.
    8.  everything else in the order in which it appeared originally.

  This rule is useful to make the output more readable to a human reader,
  and for certain compilers which need to see a struct definition before
  it is used as the return type of a function.

  This rule is temporarily turned off by default due to the fact that
  is causes problems with ansi output.  This problems will be fixed in
  future versions of cback and this rule will be turned on by default.

void! a?_new (b):0 => a,b
   Remove a call to operator 'new' when the result is not used.  This
   sometimes happens in constructors which assigns to 'this'.

#
#  Ptbl
#
ptbl! c compiler accepts 'static int x (); ...; static int x () { ... }'
  Unimplemented in the current version of cback.  This rule is supposed to
  tell cback that it is valid to insert a static declarations of a function
  before it is used.  This is not valid on some c compilers.

ptbl! c compiler accepts 'static mptr __vtbl__4name;' twice
  Unimplemented in the current version of cback.  This rule is supposed to
  tell cback that it is valid to insert a static declarations of a variable
  before it is used.  This is not valid on many c compilers.

ptbl! struct __mptr *__ptbl__4nameFILE = __vtbl__4name; => static ...
  Convert 'ptbl' declarations to static storage class.

ptbl: __ptbl__4nameFile => __vtbl__4name
  Remove cfront 2.0 'ptbl' declarations, and replace them by 'vtbl'.

ptbl: __ptbl_vec__file[0] => __vtbl__4name
  Remove cfront 2.1 'ptbl' declarations, and replace them by 'vtbl'.

#
#  Compiler characteristics
#
compiler! char is signed by default
compiler! char is unsigned by default
  The ansi C standard defines 'char' to mean either 'signed char' or
  'unsigned char' depending on the particular compiler, one of these
  rules can be turned on to inform cback whether char defaults to signed
  or unsigned.

  This is needed for code such as the following:

	char x;
	signed char x;

  And:
	
	unsigned char *get_string ();

	unsigned char *test (int a)
	{ unsigned char *z;

	  z = a ? get_string () : "";

	  return z;
	}

  In both cases, without the appropriate rule turned on, cback will complain
  about incompatiable types.  Turning the appropriate rule on will allow
  cback match 'char' (and derived types such as 'char *') with either
  'signed char' or 'unsigned char' (and derived types such as 'unsigned char *')
  as appropriate.

  Since cback only applies these rules when faced with an example such as
  above, it is probably safe to turn both rules on.  However, it is preferable
  to only turn the rule which applies to your ansi C compiler on.

#
#
#  DECstation (MIPS), HP 9000, SGI Machine, and Sun4 sizes
#
size: (*)()		4	4
size: **		4	4
size: char		1	1
size: char*		4	4
size: double		8	8
size: double*		4	4
size: float		4	4
size: float*		4	4
size: int		4	4
size: int*		4	4
size: long		4	4
size: long*		4	4
size: long long		0	0
size: long long*	0	0
size: short		2	2
size: short*		4	4
size: struct*		4	4
size: void*		4	4
  The sizes and alignments of different types that cfront uses to generate
  the C code.  The '(*)()' size is for all function pointers.  The '**' size
  is for all pointer to pointers.
  
  The sizes are only used for the following rule:

      expr: (struct x *) ((char *) e + const_int) => &e->Px

  None, some, or all of the sizes may be supplied.  For example, if function
  pointers are different sizes (depending on the type of function), then
  the size for '(*)()' must not be supplied.  Any struct which contains a
  member with a function pointer type, will then have offsets that cback
  cannot calculate, and thus the above rule will not be applied to that struct.

  The size of 'long long' and 'long long*' are both supplied as zero (i.e.:
  unknown size).

  Notice that the size of enum's and fields cannot be supplied in the rule
  file, and thus the above rule will not apply to structs which contain
  enum's or fields.

#
#  IBM RS6000 and Xenix 386 sizes
#
#size: (*)()		4	4
#size: **		4	4
#size: char		1	1
#size: char*		4	4
#size: double		8	4
#size: double*		4	4
#size: float		4	4
#size: float*		4	4
#size: int		4	4
#size: int*		4	4
#size: long		4	4
#size: long*		4	4
#size: long long		0	0
#size: long long*	0	0
#size: short		2	2
#size: short*		4	4
#size: struct*		4	4
#size: void*		4	4
  Commented out sizes for IBM RS6000 and Xenix 386, small model.  As explained
  in "cback.doc2.46", sizes cannot be turned off by using a '!', but have
  to be commented out.  This is an example of how this is done.

#
#  KSR Machine sizes
#
#size: (*)()		8	8
#size: **		8	8
#size: char		1	1
#size: char*		8	8
#size: double		8	8
#size: double*		8	8
#size: float		8	8
#size: float*		8	8
#size: int		4	4
#size: int*		8	8
#size: long		8	8
#size: long*		8	8
#size: long double	0	0
#size: long double*	0	0
#size: short		2	2
#size: short*		8	8
#size: struct*		8	8
#size: void*		8	8
  Commented out sizes for KSR Machine.

#
#  Macintosh A/UX and Sun3 sizes
#
#size: (*)()		4	2
#size: **		4	2
#size: char		1	1
#size: char*		4	2
#size: double		8	2
#size: double*		4	2
#size: float		4	2
#size: float*		4	2
#size: int		4	2
#size: int*		4	2
#size: long		4	2
#size: long*		4	2
#size: long long		0	0
#size: long long*	0	0
#size: short		2	2
#size: short*		4	2
#size: struct*		4	2
#size: void*		4	2
  Commented out sizes for Machintosh A/UX and Sun3.

#
#  Unimplemented
#
cleanup! char _STI_file_cc_ () { } =>
expr! (a?b,1:c,0)?d:e => a?(b,d):(c,e)
expr! (struct x *)(a?b:c) => a?(struct x *)b:(struct x *)c
expr! a?0:b => !a&&b
expr! a?1:b => a||b
expr! a?b:0 => a&&b
expr! a?b:1 => !a||b
expr! a?b:b => a,b
stat! if (a?b,1:c,0) d; else e; => if (a) { b; d; } else { c; e; }
  Not implemented in the current version of cback.

#
#  Rules for NewCode use only
#
dcln! suppress warning about ignoring #pragma linkage
  This is a undocumented pragma found on the SGI machine, and for now cback
  ignores this pragma and issues a warning that the pragma is being ignored.
  Turning this rule on will still ignore the pragma, but not issue a warning.

dcln! mark functions in asm statements
dcln! warn about 'asm' .stab references to undefined symbols
stat! asm ("..."); =>
  Special rules for assembly language manipulation.  These rules are meant for 
  NewCode internal use only, and are only described here for completeness.

stat! var=a?b,c:d; => if (a) var=b,c; else var=d;
  Convert an assignment consisting of a ternary expression with internal
  comma expressions, to an 'if' statement with two assignment substatements.
  This actually creates longer code on most compilers, but allows some
  compilers to actually compile code which generates:
  
	expression too complicated

  errors.

void! _new (e) => e
  Remove the function call to "new" when its return type is not used (appears
  in a void context).  This rule is meant for NewCode internal use only, and
  is only described here for completeness.

void! e?0:e_assert_fail("...",#,"...") => e
  Remove the function call that outputs a failed assertion error.  This rule
  is meant for NewCode internal use only, and is only described here for
  completeness.

void! e?e_fsoft(dbg_all,"...",#,"..."):0 => e
  Remove the function call that outputs a failed assertion error.  This rule
  is meant for NewCode internal use only, and is only described here for
  completeness.

#
#  ----  Put local modifications to rules after this line  -----
#
  After this comment you can copy a rule from above in the rule file,
  and then flip the ':' to a '!' to turn it off, or a '!' to a ':' to
  turn it on.  For example to stop '#' lines from appearing in the output,
  put the following line at the end of the file:

    output! #line 7 "file.cc"

  This is a copy of the rule which appears above but with a ':' instead
  of a '!'.

  AS A FINAL NOTE:

    This file closely follows "sun4/cback.rc2.46".  Therefore to recreate
    the default "sun4/cback.rc2.46" you can do the following:

	grep '^[#a-z]' rc.doc2.46 > sun4/rc.recreate

    The only differences will be the missing blank lines.
