BEGIN		{ bp = "abcdefghijklmnop"; # 16 4k blocks is e-nuf.
		  fourk = 4096;
		  textfg = 0;	# Not in text segment to start with
		  needct = 0;   # Not collecting xfer vector for switch
		  errfile = "/dev/tty" # default; usually defined on cmd line.
#
# State transitions at label definition, label use, and end of 4k block.
#
#
#  |-------- Possible states of label --------|    |--- (action), next state --|
#
#  Name	    Block	Used,	Used,  "Lnnn:"     Label     Label    At end
#  of	    label's	prev	this   or ".set"   defn      use      of block
#  state    defined	block	block	output
#  	    in		  ?	  ?	yet?
#
#   0      undefined	  n	  n	  n	      4	   (c) 1	 x	
#   1      undefined	  n	  Y	  n	  (a) 4	       1     (e) 2	
#   2      undefined	  Y	  n	  n	  (b) 5	   (c) 3         2	
#   3      undefined	  Y	  Y	  n	(a,b) 5	       3     (e) 2	
#
#   4      this		  n	  -	  n	      x	       4	 6	
#   5      this		  Y       -	  Y	      x	       5	 7	
#
#   6      previous	  -	  n	  n	      x	   (c) 8	 6	
#   7      previous	  -	  n	  Y	      x	   (c) 9	 7	
#   8      previous	  -	  Y	  n	      x	       8   (d,e) 7	
#   9      previous	  -	  Y	  Y	      x	       9     (e) 7	
#
#   d      .data	  -	  -	  -	      x        x         x
#
#					(a)  Deallocate bounce space
#					(b)  Print "Lnnn:"
#					(c)  Allocate bounce space
#					(d)  Print " .set Lnnn,pLnnn"
#					(e)  Print "cLnnn: <bounce Lnnn>"
#
#  State 'd' is a kluge to handle Lnnn defining an ascii string in a .data
#  section.  Cleaner would be to have the defining label start with a different
#  letter, but that would require a worse kluge in the compiler.
#  
		  deftran = "4455xxxxxx";
		  usetran = "1133458989";
		  bountran= "x222676777";
#
# 3-char value is   no. of bytes, type, cc usage:
#				   	i = ignores
#					s = sets
#					u = uses
#					b = unconditional branch
#
	op["balr"] = "2 i";	 op["basr"] = "2 i";	 op["br"] = "2 b";
	op["lpr"] = "2 s";	 op["lnr"] = "2 s";	 op["ltr"] = "2 s";
	op["lcr"] = "2 s";	 op["nr"] = "2 s";	 op["clr"] = "2 s";
	op["or"] = "2 s";	 op["xr"] = "2 s";	 op["lr"] = "2 i";
	op["cr"] = "2 s";	 op["ar"] = "2 s";	 op["sr"] = "2 s";
	op["mr"] = "2 i";	 op["dr"] = "2 i";	 op["alr"] = "2 s";
	op["slr"] = "2 s";	 op["bctr"] = "2 i";

	op["adr"] = "2 s";	 op["sdr"] = "2 s";	 op["mdr"] = "2 i";
	op["ddr"] = "2 s";	 op["cdr"] = "2 s";	 

	op["sth"] = "4 i";	op["la"] = "4 i";	op["stc"] = "4 i";
	op["ic"] = "4 i";	op["ex"] = "4 s";	op["bal"] = "4 i";
	op["bas"] = "4 i";	op["b"] = "4 b";	op["bh"] = "4 u";
	op["bl"] = "4 u";	op["be"] = "4 u";	op["bnh"] = "4 u";
	op["bnl"] = "4 u";	op["bne"] = "4 u";	op["bm"] = "4 u";
	op["bz"] = "4 u";	op["bp"] = "4 u";	op["lh"] = "4 i";
	op["ch"] = "4 s";	op["ah"] = "4 s";	op["sh"] = "4 s";
	op["mh"] = "4 i";	op["st"] = "4 i";	op["n"] = "4 s";
	op["cl"] = "4 s";	op["o"] = "4 s";	op["x"] = "4 s";
	op["l"] = "4 i";	op["c"] = "4 s";	op["a"] = "4 s";
	op["s"] = "4 s";	op["m"] = "4 i";	op["d"] = "4 i";
	op["al"] = "4 s";	op["sl"] = "4 s";	op["srl"] = "4 s";
	op["sll"] = "4 s";	op["sra"] = "4 s";	op["sla"] = "4 s";
	op["stm"] = "4 i";	op["mvi"] = "4 i";	op["cli"] = "4 s";
	op["lm"] = "4 i";	op["xi"] = "4 s";	

	op["ld"] = "4 i";	op["std"] = "4 i";	op["le"] = "4 i";
	op["sd"] = "4 s";	op["aw"] = "4 s";

	op["mvc"] = "6 i";

	op[".text"] = "0t ";	op[".data"] = "0d ";	 op[".set"] = "0p ";	
	op[".using"] = "0p ";	op[".globl"] = "0p ";	 op[".ltorg"] = "0l ";
	op[".align"] = "0>b";	op[".ascii"] = "0a ";	 op[".int"] = "4cb";
	op[".short"] = "2cb";	op[".long"] = "4cb";
		}

		{ opidx = 1; opndidx = 2;
#		  print "|",frontct,backct,needct;
		}

# The following action looks for and processes labels.
# The record might be one of
#
# (1)   Lnnn:
# (2)   nonlabel (e.g. instruction or comment)
# (3)   1: nonlabel
# (4)   Pennn: .short Pfnnn (frame size, for prolog)
#

$1 ~ /:$/	{
		  l = substr($1,1,length($1)-1);
		  if (l ~ /^[0-9]/) {  # Temporary label 
		    if (tlabels[l] != 0) {
		      backct -= 8;
		      tlabels[l] = 0;
		    }
		  }
		  else if (l !~ /^L/) { 
		  	possfnname = l;
			if ((l ~ /^P/) && prolognnn == 0) next;
# The only "P" label is the .short for bumping sp in the prolog, and we
# already fabricated the labelled .short in the first block of this function.
		  }
		  else {

		  #		 Substr fails in following line:
		  #		 t = substr(labels[l] "0",1,1);
		  t = 0+substr(labels[l],1,1);
		  newstate = substr(deftran,t+1,1);
		  if (!textfg) {
			# Label defined outside of .text section.  Record its
			# presence and give it state 'd' to inhibit fancy
			# processing on subsequent use.
			print;
			if (labels[l] != "") {  #Alas, too late
			    print > errfile;
			    print "*** line " NR ": " l\
				" must not be defined outside .text segment"\
				> errfile;
			    exit;
			}
			labels[l] = "d ";
			next;
		  }
		  if (t ~/[13]/) backct -= 8;
		#		 Label used earlier in this block; we won't
		#		 need the bounce now it's defined.
		  labels[l] = newstate blockpfx;
		  $1 = blockpfx l ":";
		  if (newstate == 5) print l ":";
		}
		opidx=2; opndidx = 2;
		}

textfg == 0	{ # pass everything but .text through quickly
	  	  if ($opidx == ".text") textfg=1;
	  	  print; next
		}

$opidx ~ /^\|----/	{
		  blockpfx = "a"; # Start of a new function body 
		  bpi = 1;
		  frontct = 0;  # bytes of code so far in current block
		  backct  = 0;  # bytes of literals (w/o alignment) and bounces
		  prolognnn = 0;
		  split("",labels); # make labels and tlabels arrays; erase and
		  split("",tlabels);# reclaim space from previous elements.
		  split("",litpool);# Empty the pool of unique literals
		  print;
		  fnname = possfnname;
		  print blockpfx fnname":";
		  next;
		}

$opidx == ""	{ print; next } # Empty line

$opidx ~ /^\|/	{ print; next } # Ordinary comment

		{
		  opval = op[$opidx];
		  if (opval == "") {
			print > errfile;
			print "*** line " NL ": opcode not recognized" > errfile;
			next;
	    	  }
		  opct = substr(opval,1,1);
		  optype = substr(opval,2,1);
		  opccuse = substr(opval,3,1);
		  line = $0; 
		}

# .text
optype=="t"	{ print > errfile;
		  print "*** line " NR ": .text shouldn't appear here" > errfile;
		  next;
		}

# .data
optype=="d"	{ textfg=0;
		  print;
		  next;
		}
		  	
# .ascii, .set, .using, .globl
# only .ascii we should see here is <functionnames>
optype=="a" || optype=="p" { print; next}

# .align
optype==">"	{ t = substr("248",$opndidx,1);
		  frontct += (fourk-frontct)%t;
		}

# .int  (and .long, .short, etc. if they're added to op table)
optype=="c"	{ frontct += opct*split($opndidx, trash, ",") }
# BUG: a multi-constant .int could overrun a 4k block.

# machine opcodes
optype==" "	{ frontct += opct;
# assume that numeric labels are used only as entire operand fields
		  if ($opndidx ~ /[0-9]f/) {
		    tlabels[$opndidx] = 1;
		    backct += 8;
		  }
		}

$opndidx ~ /\$\./ {
		i = index($opndidx,"$");
		l = substr($opndidx,i);
		l = substr(l,1,index(l,")"));
		if (litpool[l] == 0) {
		  if ($opndidx ~ /\$\.short/)  backct += 2 ;
		  else if( $opndidx ~ /\$\.long/)  backct += 4 ;
		  else if( $opndidx ~ /\$\.dlong/)  backct += 8 ;
		  else print "*** line " NR ": Unrecognized literal type" > errfile;
		  litpool[l] = "1";
		}
		}

0 != (i=index($0,"L")) && i < (vbi = index($0 "|","|")) {
		  l = substr($0,i,5);
		  if (substr(l,5,1) !~/[0-9]/) l = substr(l,1,4);
#
#		l is now the label text: L123 or L9876.
#		There must be a better way...
#
		  u = labels[l];
		  if (u != "d ") {  #No label mapping unless defined in .text
			# t = substr(u"0",1,1);
		  	t = 0+substr(u,1,1);
		  	if (t ~ /[0267]/) backct += 8;
		  	labels[l] = substr(usetran,t+1,1) substr(u,2,1);
#	printf( "*** line " NR ": label %s, u=%s, t=%s, new s.t.=%s.\n", l,u,t,labels[l]);
		  	line = substr($0,1,i-1) blockpfx substr($0,i);
		  }
		  if ((substr($0,i+1) ~ /L/) && (index(substr($0,i+1),"L") < vbi-i)) {
			print line > errfile;
			print "*** line " NR ": Use of >1 label per line not supported" > errfile;
			exit;
		  }
		}

		{print line; needct=0}


0 != (i=index($0,"|#need")) { needct = substr($0,i+6) }
# The compiler has told us it needs needct bytes before block end.


0 != (i=index($0,"|#prolog")) {

# The compiler is announcing nnn for the Pxnnn prolog-creating labels.
# If the frame size turns out to be <4k, the compiler will output
# Pennn: .short Pfnnn 
# at the end of the function definition.  In a multi-block function, that
# won't be addressable; so we jump the gun and create that line at the end
# of the first block, and discard the real one when it finally appears.
# If the frame size turns out to be 4k or more, no Pennn is needed, and
# the one we may create will be a wasted 2 bytes.  Such is life.
#
# Note that a short function will pass through this filter unaffected,
# regardless of frame size.

		  prolognnn = 0+substr($0,i+8);
		  backct += 2;  # may need to insert unexpected .short at
				# end of first block
		}
(needct + frontct+6 +6-(frontct+2)%8 + backct+14 - fourk) > 0 {
		#
		# Above constants allow for effect of accepting next line:
		# needct:    We must be willing to accept "needct" bytes more
		# frontct+6: 6 bytes for possible ss instruction,
		# 6-(...)%8: 0-6 bytes for doubleword literal alignment,
		# backct+14: 6 bytes for inline bounce to 0(pbr),
		#          + 8 bytes for literal or for bounce code
		#              (next instr can't need both).

# Produce unlabelled bounce to get from end of block to start of next.
# If previous instruction was an unconditional branch, generate no code.
# Otherwise generate a 6-byte bounce:
#
#	either		a  pbr,<4096 from context-area table>
#	or		l  pbr,$.long(<addr of next 4k block>)
#
#	depending on whether it's safe to clobber the condition code; then
#
#			br pbr
#
# 
		  if (opccuse != "b") {
			if (opccuse == "s") print "  l \t pbr,$.long("\
				substr(bp,bpi+1,1) fnname ")";
			else print "  a \t pbr,CX4KTB+4(cxr)";
			print "  br \t pbr"
		  }
		  for (l in labels) {
			u = labels[l];
#	print "*** line " NR ": for " l "/" u "/";
			if (u == "d ") continue;
			t = substr(u,1,1);
			u = substr(u,2,1);
			if (t == 8) print "\t .set \t " l "," u l;
			if (t ~ /[1389]/) {
			    print blockpfx l ":\t a \t pbr,CX4KTB+(("\
				l "-" blockpfx fnname ")>12<2)(cxr)";
			    print "\t .short  0x47f0+pbr,("\
				l "-" fnname ")&4095";
#			  # print "\t b \t (" l "-" fnname ")&4095(pbr)";
			}
			labels[l] = substr(bountran,t+1,1) u;
#	print "*** line " NR ": redefined as /" labels[l] "/"
		  }
		  for (l in tlabels) {
			u = tlabels[l];
			if (u == 0) continue;
			print l ":\t a \t pbr,CX4KTB+(("l"f-"blockpfx fnname\
				")>12<2)(cxr)";
			    print "\t .short  0x47f0+pbr,("\
				l "-" fnname ")&4095";
#		    #	print "\t b \t (" l "f-" fnname ")&4095(pbr)";
			tlabels[l] = 0;
		  }
		  if (prolognnn != 0) {
			print "Pe" prolognnn ": \t .short  Pf" prolognnn;
			prolognnn = 0;
		  } 
		  print "  .ltorg";
		  print "9:\t .space\t " blockpfx fnname "-9b+4094; .align 2";
					# N.B. Above .align must match the one
					# the compiler emits before the prolog,
					# or block separation may not be 4096.
		  blockpfx = substr(bp,++bpi,1);
		  if (blockpfx == "") {
		      print "*** line " NR ": This function is TOO BIG!" > errfile;
		#      exit;
		  }
		  print blockpfx fnname ":";
		  print "  .using " blockpfx fnname ",pbr";
		  frontct = 0;
		  backct = 0;
		  split("",litpool);
		  next;
		}

# .ltorg --  end of function definition
optype == "l"	{
		   for (l in labels) {
			u = labels[l];
#	print "*** line " NR ": for " l "/" u "/";
			if (u == "d ") continue;
			t = substr(u,1,1);
			u = substr(u,2,1);
			if (t == 8) print "\t .set \t " l "," u l;
			if (t ~ /[1389]/) {
			    print blockpfx l ":\t a \t pbr,CX4KTB+(("\
				l "-" blockpfx fnname ")>12<2)(cxr)";
			    print "\t .short  0x47f0+pbr,("\
				l "-" fnname ")&4095";
#			  # print "\t b \t (" l "-" fnname ")&4095(pbr)";
			}
			labels[l] = substr(bountran,t+1,1) u;
#	print "*** line " NR ": redefined as /" labels[l] "/"
		  }

# A copy of the "for l in tlabels" loop above could go here, except that
# there shouldn't be any forward uses still pending.

		  next;
		}
