github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/5a/lex.c (about)

     1  // Inferno utils/5a/lex.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  #define	EXTERN
    32  #include <u.h>
    33  #include <libc.h>
    34  #include "a.h"
    35  #include "y.tab.h"
    36  
    37  enum
    38  {
    39  	Plan9	= 1<<0,
    40  	Unix	= 1<<1,
    41  	Windows	= 1<<2,
    42  };
    43  
    44  int
    45  systemtype(int sys)
    46  {
    47  #ifdef _WIN32
    48  	return sys&Windows;
    49  #else
    50  	return sys&Plan9;
    51  #endif
    52  }
    53  
    54  void
    55  main(int argc, char *argv[])
    56  {
    57  	char *p;
    58  	int c;
    59  
    60  	thechar = '5';
    61  	thestring = "arm";
    62  
    63  	ensuresymb(NSYMB);
    64  	memset(debug, 0, sizeof(debug));
    65  	cinit();
    66  	outfile = 0;
    67  	setinclude(".");
    68  	ARGBEGIN {
    69  	default:
    70  		c = ARGC();
    71  		if(c >= 0 && c < sizeof(debug))
    72  			debug[c] = 1;
    73  		break;
    74  
    75  	case 'o':
    76  		outfile = ARGF();
    77  		break;
    78  
    79  	case 'D':
    80  		p = ARGF();
    81  		if(p) {
    82  			if (nDlist%8 == 0) 
    83  				Dlist = allocn(Dlist, nDlist*sizeof(char *), 
    84  					8*sizeof(char *));
    85  			Dlist[nDlist++] = p;
    86  		}
    87  		break;
    88  
    89  	case 'I':
    90  		p = ARGF();
    91  		setinclude(p);
    92  		break;
    93  	case 't':
    94  		thechar = 't';
    95  		thestring = "thumb";
    96  		break;
    97  	} ARGEND
    98  	if(*argv == 0) {
    99  		print("usage: %ca [-options] file.s\n", thechar);
   100  		errorexit();
   101  	}
   102  	if(argc > 1){
   103  		print("can't assemble multiple files\n");
   104  		errorexit();
   105  	}
   106  	if(assemble(argv[0]))
   107  		errorexit();
   108  	exits(0);
   109  }
   110  
   111  int
   112  assemble(char *file)
   113  {
   114  	char *ofile, *p;
   115  	int i, of;
   116  
   117  	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
   118  	strcpy(ofile, file);
   119  	p = utfrrune(ofile, '/');
   120  	if(p) {
   121  		include[0] = ofile;
   122  		*p++ = 0;
   123  	} else
   124  		p = ofile;
   125  	if(outfile == 0) {
   126  		outfile = p;
   127  		if(outfile){
   128  			p = utfrrune(outfile, '.');
   129  			if(p)
   130  				if(p[1] == 's' && p[2] == 0)
   131  					p[0] = 0;
   132  			p = utfrune(outfile, 0);
   133  			p[0] = '.';
   134  			p[1] = thechar;
   135  			p[2] = 0;
   136  		} else
   137  			outfile = "/dev/null";
   138  	}
   139  
   140  	of = create(outfile, OWRITE, 0664);
   141  	if(of < 0) {
   142  		yyerror("%ca: cannot create %s", thechar, outfile);
   143  		errorexit();
   144  	}
   145  	Binit(&obuf, of, OWRITE);
   146  
   147  	pass = 1;
   148  	pinit(file);
   149  
   150  	Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
   151  
   152  	for(i=0; i<nDlist; i++)
   153  		dodefine(Dlist[i]);
   154  	yyparse();
   155  	if(nerrors) {
   156  		cclean();
   157  		return nerrors;
   158  	}
   159  
   160  	Bprint(&obuf, "\n!\n");
   161  
   162  	pass = 2;
   163  	outhist();
   164  	pinit(file);
   165  	for(i=0; i<nDlist; i++)
   166  		dodefine(Dlist[i]);
   167  	yyparse();
   168  	cclean();
   169  	return nerrors;
   170  }
   171  
   172  struct
   173  {
   174  	char	*name;
   175  	ushort	type;
   176  	ushort	value;
   177  } itab[] =
   178  {
   179  	"SP",		LSP,	D_AUTO,
   180  	"SB",		LSB,	D_EXTERN,
   181  	"FP",		LFP,	D_PARAM,
   182  	"PC",		LPC,	D_BRANCH,
   183  
   184  	"R",		LR,	0,
   185  	"R0",		LREG,	0,
   186  	"R1",		LREG,	1,
   187  	"R2",		LREG,	2,
   188  	"R3",		LREG,	3,
   189  	"R4",		LREG,	4,
   190  	"R5",		LREG,	5,
   191  	"R6",		LREG,	6,
   192  	"R7",		LREG,	7,
   193  	"R8",		LREG,	8,
   194  	"m",		LREG,	9, // avoid unintentionally clobber m/g using R9/R10
   195  	"g",		LREG,	10,
   196  	"R11",		LREG,	11,
   197  	"R12",		LREG,	12,
   198  	"R13",		LREG,	13,
   199  	"R14",		LREG,	14,
   200  	"R15",		LREG,	15,
   201  
   202  	"F",		LF,	0,
   203  
   204  	"F0",		LFREG,	0,
   205  	"F1",		LFREG,	1,
   206  	"F2",		LFREG,	2,
   207  	"F3",		LFREG,	3,
   208  	"F4",		LFREG,	4,
   209  	"F5",		LFREG,	5,
   210  	"F6",		LFREG,	6,
   211  	"F7",		LFREG,	7,
   212  	"F8",		LFREG,	8,
   213  	"F9",		LFREG,	9,
   214  	"F10",		LFREG,	10,
   215  	"F11",		LFREG,	11,
   216  	"F12",		LFREG,	12,
   217  	"F13",		LFREG,	13,
   218  	"F14",		LFREG,	14,
   219  	"F15",		LFREG,	15,
   220  
   221  	"C",		LC,	0,
   222  
   223  	"C0",		LCREG,	0,
   224  	"C1",		LCREG,	1,
   225  	"C2",		LCREG,	2,
   226  	"C3",		LCREG,	3,
   227  	"C4",		LCREG,	4,
   228  	"C5",		LCREG,	5,
   229  	"C6",		LCREG,	6,
   230  	"C7",		LCREG,	7,
   231  	"C8",		LCREG,	8,
   232  	"C9",		LCREG,	9,
   233  	"C10",		LCREG,	10,
   234  	"C11",		LCREG,	11,
   235  	"C12",		LCREG,	12,
   236  	"C13",		LCREG,	13,
   237  	"C14",		LCREG,	14,
   238  	"C15",		LCREG,	15,
   239  
   240  	"CPSR",		LPSR,	0,
   241  	"SPSR",		LPSR,	1,
   242  
   243  	"FPSR",		LFCR,	0,
   244  	"FPCR",		LFCR,	1,
   245  
   246  	".EQ",		LCOND,	0,
   247  	".NE",		LCOND,	1,
   248  	".CS",		LCOND,	2,
   249  	".HS",		LCOND,	2,
   250  	".CC",		LCOND,	3,
   251  	".LO",		LCOND,	3,
   252  	".MI",		LCOND,	4,
   253  	".PL",		LCOND,	5,
   254  	".VS",		LCOND,	6,
   255  	".VC",		LCOND,	7,
   256  	".HI",		LCOND,	8,
   257  	".LS",		LCOND,	9,
   258  	".GE",		LCOND,	10,
   259  	".LT",		LCOND,	11,
   260  	".GT",		LCOND,	12,
   261  	".LE",		LCOND,	13,
   262  	".AL",		LCOND,	Always,
   263  
   264  	".U",		LS,	C_UBIT,
   265  	".S",		LS,	C_SBIT,
   266  	".W",		LS,	C_WBIT,
   267  	".P",		LS,	C_PBIT,
   268  	".PW",		LS,	C_WBIT|C_PBIT,
   269  	".WP",		LS,	C_WBIT|C_PBIT,
   270  
   271  	".F",		LS,	C_FBIT,
   272  
   273  	".IBW",		LS,	C_WBIT|C_PBIT|C_UBIT,
   274  	".IAW",		LS,	C_WBIT|C_UBIT,
   275  	".DBW",		LS,	C_WBIT|C_PBIT,
   276  	".DAW",		LS,	C_WBIT,
   277  	".IB",		LS,	C_PBIT|C_UBIT,
   278  	".IA",		LS,	C_UBIT,
   279  	".DB",		LS,	C_PBIT,
   280  	".DA",		LS,	0,
   281  
   282  	"@",		LAT,	0,
   283  
   284  	"AND",		LTYPE1,	AAND,
   285  	"EOR",		LTYPE1,	AEOR,
   286  	"SUB",		LTYPE1,	ASUB,
   287  	"RSB",		LTYPE1,	ARSB,
   288  	"ADD",		LTYPE1,	AADD,
   289  	"ADC",		LTYPE1,	AADC,
   290  	"SBC",		LTYPE1,	ASBC,
   291  	"RSC",		LTYPE1,	ARSC,
   292  	"ORR",		LTYPE1,	AORR,
   293  	"BIC",		LTYPE1,	ABIC,
   294  
   295  	"SLL",		LTYPE1,	ASLL,
   296  	"SRL",		LTYPE1,	ASRL,
   297  	"SRA",		LTYPE1,	ASRA,
   298  
   299  	"MUL",		LTYPE1, AMUL,
   300  	"MULA",		LTYPEN, AMULA,
   301  	"DIV",		LTYPE1,	ADIV,
   302  	"MOD",		LTYPE1,	AMOD,
   303  
   304  	"MULL",		LTYPEM, AMULL,
   305  	"MULAL",	LTYPEM, AMULAL,
   306  	"MULLU",	LTYPEM, AMULLU,
   307  	"MULALU",	LTYPEM, AMULALU,
   308  
   309  	"MVN",		LTYPE2, AMVN,	/* op2 ignored */
   310  
   311  	"MOVB",		LTYPE3, AMOVB,
   312  	"MOVBU",	LTYPE3, AMOVBU,
   313  	"MOVH",		LTYPE3, AMOVH,
   314  	"MOVHU",	LTYPE3, AMOVHU,
   315  	"MOVW",		LTYPE3, AMOVW,
   316  
   317  	"MOVD",		LTYPE3, AMOVD,
   318  	"MOVDF",		LTYPE3, AMOVDF,
   319  	"MOVDW",	LTYPE3, AMOVDW,
   320  	"MOVF",		LTYPE3, AMOVF,
   321  	"MOVFD",		LTYPE3, AMOVFD,
   322  	"MOVFW",		LTYPE3, AMOVFW,
   323  	"MOVWD",	LTYPE3, AMOVWD,
   324  	"MOVWF",		LTYPE3, AMOVWF,
   325  
   326  	"LDREX",		LTYPE3, ALDREX,
   327  	"LDREXD",		LTYPE3, ALDREXD,
   328  	"STREX",		LTYPE9, ASTREX,
   329  	"STREXD",		LTYPE9, ASTREXD,
   330  
   331  /*
   332  	"NEGF",		LTYPEI, ANEGF,
   333  	"NEGD",		LTYPEI, ANEGD,
   334  	"SQTF",		LTYPEI,	ASQTF,
   335  	"SQTD",		LTYPEI,	ASQTD,
   336  	"RNDF",		LTYPEI,	ARNDF,
   337  	"RNDD",		LTYPEI,	ARNDD,
   338  	"URDF",		LTYPEI,	AURDF,
   339  	"URDD",		LTYPEI,	AURDD,
   340  	"NRMF",		LTYPEI,	ANRMF,
   341  	"NRMD",		LTYPEI,	ANRMD,
   342  */
   343  
   344  	"ABSF",		LTYPEI, AABSF,
   345  	"ABSD",		LTYPEI, AABSD,
   346  	"SQRTF",	LTYPEI, ASQRTF,
   347  	"SQRTD",	LTYPEI, ASQRTD,
   348  	"CMPF",		LTYPEL, ACMPF,
   349  	"CMPD",		LTYPEL, ACMPD,
   350  	"ADDF",		LTYPEK,	AADDF,
   351  	"ADDD",		LTYPEK,	AADDD,
   352  	"SUBF",		LTYPEK,	ASUBF,
   353  	"SUBD",		LTYPEK,	ASUBD,
   354  	"MULF",		LTYPEK,	AMULF,
   355  	"MULD",		LTYPEK,	AMULD,
   356  	"DIVF",		LTYPEK,	ADIVF,
   357  	"DIVD",		LTYPEK,	ADIVD,
   358  
   359  	"B",		LTYPE4, AB,
   360  	"BL",		LTYPE4, ABL,
   361  	"BX",		LTYPEBX,	ABX,
   362  
   363  	"BEQ",		LTYPE5,	ABEQ,
   364  	"BNE",		LTYPE5,	ABNE,
   365  	"BCS",		LTYPE5,	ABCS,
   366  	"BHS",		LTYPE5,	ABHS,
   367  	"BCC",		LTYPE5,	ABCC,
   368  	"BLO",		LTYPE5,	ABLO,
   369  	"BMI",		LTYPE5,	ABMI,
   370  	"BPL",		LTYPE5,	ABPL,
   371  	"BVS",		LTYPE5,	ABVS,
   372  	"BVC",		LTYPE5,	ABVC,
   373  	"BHI",		LTYPE5,	ABHI,
   374  	"BLS",		LTYPE5,	ABLS,
   375  	"BGE",		LTYPE5,	ABGE,
   376  	"BLT",		LTYPE5,	ABLT,
   377  	"BGT",		LTYPE5,	ABGT,
   378  	"BLE",		LTYPE5,	ABLE,
   379  	"BCASE",	LTYPE5,	ABCASE,
   380  
   381  	"SWI",		LTYPE6, ASWI,
   382  
   383  	"CMP",		LTYPE7,	ACMP,
   384  	"TST",		LTYPE7,	ATST,
   385  	"TEQ",		LTYPE7,	ATEQ,
   386  	"CMN",		LTYPE7,	ACMN,
   387  
   388  	"MOVM",		LTYPE8, AMOVM,
   389  
   390  	"SWPBU",	LTYPE9, ASWPBU,
   391  	"SWPW",		LTYPE9, ASWPW,
   392  
   393  	"RET",		LTYPEA, ARET,
   394  	"RFE",		LTYPEA, ARFE,
   395  
   396  	"TEXT",		LTYPEB, ATEXT,
   397  	"GLOBL",	LTYPEB, AGLOBL,
   398  	"DATA",		LTYPEC, ADATA,
   399  	"CASE",		LTYPED, ACASE,
   400  	"END",		LTYPEE, AEND,
   401  	"WORD",		LTYPEH, AWORD,
   402  	"NOP",		LTYPEI, ANOP,
   403  
   404  	"MCR",		LTYPEJ, 0,
   405  	"MRC",		LTYPEJ, 1,
   406  
   407  	"PLD",		LTYPEPLD, APLD,
   408  	"UNDEF",	LTYPEE,	AUNDEF,
   409  	"CLZ",		LTYPE2, ACLZ,
   410  
   411  	"MULWT",	LTYPE1, AMULWT,
   412  	"MULWB",	LTYPE1, AMULWB,
   413  	"MULAWT",	LTYPEN, AMULAWT,
   414  	"MULAWB",	LTYPEN, AMULAWB,
   415  
   416  	"USEFIELD",	LTYPEN, AUSEFIELD,
   417  	"PCDATA",	LTYPEPC,	APCDATA,
   418  	"FUNCDATA",	LTYPEF,	AFUNCDATA,
   419  
   420  	0
   421  };
   422  
   423  void
   424  cinit(void)
   425  {
   426  	Sym *s;
   427  	int i;
   428  
   429  	nullgen.sym = S;
   430  	nullgen.offset = 0;
   431  	nullgen.type = D_NONE;
   432  	nullgen.name = D_NONE;
   433  	nullgen.reg = NREG;
   434  	if(FPCHIP)
   435  		nullgen.dval = 0;
   436  	for(i=0; i<sizeof(nullgen.sval); i++)
   437  		nullgen.sval[i] = 0;
   438  
   439  	nerrors = 0;
   440  	iostack = I;
   441  	iofree = I;
   442  	peekc = IGN;
   443  	nhunk = 0;
   444  	for(i=0; i<NHASH; i++)
   445  		hash[i] = S;
   446  	for(i=0; itab[i].name; i++) {
   447  		s = slookup(itab[i].name);
   448  		s->type = itab[i].type;
   449  		s->value = itab[i].value;
   450  	}
   451  
   452  	pathname = allocn(pathname, 0, 100);
   453  	if(getwd(pathname, 99) == 0) {
   454  		pathname = allocn(pathname, 100, 900);
   455  		if(getwd(pathname, 999) == 0)
   456  			strcpy(pathname, "/???");
   457  	}
   458  }
   459  
   460  void
   461  syminit(Sym *s)
   462  {
   463  
   464  	s->type = LNAME;
   465  	s->value = 0;
   466  }
   467  
   468  int
   469  isreg(Gen *g)
   470  {
   471  
   472  	USED(g);
   473  	return 1;
   474  }
   475  
   476  void
   477  cclean(void)
   478  {
   479  
   480  	outcode(AEND, Always, &nullgen, NREG, &nullgen);
   481  	Bflush(&obuf);
   482  }
   483  
   484  void
   485  zname(char *n, int t, int s)
   486  {
   487  
   488  	BPUTC(&obuf, ANAME);
   489  	BPUTC(&obuf, t);	/* type */
   490  	BPUTC(&obuf, s);	/* sym */
   491  	while(*n) {
   492  		BPUTC(&obuf, *n);
   493  		n++;
   494  	}
   495  	BPUTC(&obuf, 0);
   496  }
   497  
   498  void
   499  zaddr(Gen *a, int s)
   500  {
   501  	int32 l;
   502  	int i;
   503  	char *n;
   504  	Ieee e;
   505  
   506  	BPUTC(&obuf, a->type);
   507  	BPUTC(&obuf, a->reg);
   508  	BPUTC(&obuf, s);
   509  	BPUTC(&obuf, a->name);
   510  	BPUTC(&obuf, 0);
   511  	switch(a->type) {
   512  	default:
   513  		print("unknown type %d\n", a->type);
   514  		exits("arg");
   515  
   516  	case D_NONE:
   517  	case D_REG:
   518  	case D_FREG:
   519  	case D_PSR:
   520  	case D_FPCR:
   521  		break;
   522  
   523  	case D_REGREG:
   524  	case D_REGREG2:
   525  		BPUTC(&obuf, a->offset);
   526  		break;
   527  
   528  	case D_CONST2:
   529  		l = a->offset2;
   530  		BPUTLE4(&obuf, l);
   531  		// fall through
   532  	case D_OREG:
   533  	case D_CONST:
   534  	case D_BRANCH:
   535  	case D_SHIFT:
   536  		l = a->offset;
   537  		BPUTLE4(&obuf, l);
   538  		break;
   539  
   540  	case D_SCONST:
   541  		n = a->sval;
   542  		for(i=0; i<NSNAME; i++) {
   543  			BPUTC(&obuf, *n);
   544  			n++;
   545  		}
   546  		break;
   547  
   548  	case D_FCONST:
   549  		ieeedtod(&e, a->dval);
   550  		BPUTLE4(&obuf, e.l);
   551  		BPUTLE4(&obuf, e.h);
   552  		break;
   553  	}
   554  }
   555  
   556  static int bcode[] =
   557  {
   558  	ABEQ,
   559  	ABNE,
   560  	ABCS,
   561  	ABCC,
   562  	ABMI,
   563  	ABPL,
   564  	ABVS,
   565  	ABVC,
   566  	ABHI,
   567  	ABLS,
   568  	ABGE,
   569  	ABLT,
   570  	ABGT,
   571  	ABLE,
   572  	AB,
   573  	ANOP,
   574  };
   575  
   576  void
   577  outcode(int a, int scond, Gen *g1, int reg, Gen *g2)
   578  {
   579  	int sf, st, t;
   580  	Sym *s;
   581  
   582  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   583  	if(a == AB){
   584  		a = bcode[scond&0xf];
   585  		scond = (scond & ~0xf) | Always;
   586  	}
   587  
   588  	if(pass == 1)
   589  		goto out;
   590  jackpot:
   591  	sf = 0;
   592  	s = g1->sym;
   593  	while(s != S) {
   594  		sf = s->sym;
   595  		if(sf < 0 || sf >= NSYM)
   596  			sf = 0;
   597  		t = g1->name;
   598  		if(h[sf].type == t)
   599  		if(h[sf].sym == s)
   600  			break;
   601  		zname(s->name, t, sym);
   602  		s->sym = sym;
   603  		h[sym].sym = s;
   604  		h[sym].type = t;
   605  		sf = sym;
   606  		sym++;
   607  		if(sym >= NSYM)
   608  			sym = 1;
   609  		break;
   610  	}
   611  	st = 0;
   612  	s = g2->sym;
   613  	while(s != S) {
   614  		st = s->sym;
   615  		if(st < 0 || st >= NSYM)
   616  			st = 0;
   617  		t = g2->name;
   618  		if(h[st].type == t)
   619  		if(h[st].sym == s)
   620  			break;
   621  		zname(s->name, t, sym);
   622  		s->sym = sym;
   623  		h[sym].sym = s;
   624  		h[sym].type = t;
   625  		st = sym;
   626  		sym++;
   627  		if(sym >= NSYM)
   628  			sym = 1;
   629  		if(st == sf)
   630  			goto jackpot;
   631  		break;
   632  	}
   633  	BPUTC(&obuf, a);
   634  	BPUTC(&obuf, scond);
   635  	BPUTC(&obuf, reg);
   636  	BPUTLE4(&obuf, stmtline);
   637  	zaddr(g1, sf);
   638  	zaddr(g2, st);
   639  
   640  out:
   641  	if(a != AGLOBL && a != ADATA)
   642  		pc++;
   643  }
   644  
   645  void
   646  outhist(void)
   647  {
   648  	Gen g;
   649  	Hist *h;
   650  	char *p, *q, *op, c;
   651  	int n;
   652   	char *tofree;
   653   	static int first = 1;
   654   	static char *goroot, *goroot_final;
   655   
   656   	if(first) {
   657   		// Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
   658   		first = 0;
   659   		goroot = getenv("GOROOT");
   660   		goroot_final = getenv("GOROOT_FINAL");
   661   		if(goroot == nil)
   662   			goroot = "";
   663   		if(goroot_final == nil)
   664   			goroot_final = goroot;
   665   		if(strcmp(goroot, goroot_final) == 0) {
   666   			goroot = nil;
   667   			goroot_final = nil;
   668   		}
   669   	}
   670   
   671   	tofree = nil;
   672  	g = nullgen;
   673  	c = '/';
   674  	for(h = hist; h != H; h = h->link) {
   675  		p = h->name;
   676   		if(p != nil && goroot != nil) {
   677   			n = strlen(goroot);
   678   			if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
   679   				tofree = smprint("%s%s", goroot_final, p+n);
   680   				p = tofree;
   681   			}
   682   		}
   683  		op = 0;
   684  		if(systemtype(Windows) && p && p[1] == ':'){
   685  			c = p[2];
   686  		} else if(p && p[0] != c && h->offset == 0 && pathname){
   687  			if(systemtype(Windows) && pathname[1] == ':') {
   688  				op = p;
   689  				p = pathname;
   690  				c = p[2];
   691  			} else if(pathname[0] == c){
   692  				op = p;
   693  				p = pathname;
   694  			}
   695  		}
   696  		while(p) {
   697  			q = strchr(p, c);
   698  			if(q) {
   699  				n = q-p;
   700  				if(n == 0){
   701  					n = 1;	/* leading "/" */
   702  					*p = '/';	/* don't emit "\" on windows */
   703  				}
   704  				q++;
   705  			} else {
   706  				n = strlen(p);
   707  				q = 0;
   708  			}
   709  			if(n) {
   710  				BPUTC(&obuf, ANAME);
   711  				BPUTC(&obuf, D_FILE);	/* type */
   712  				BPUTC(&obuf, 1);	/* sym */
   713  				BPUTC(&obuf, '<');
   714  				Bwrite(&obuf, p, n);
   715  				BPUTC(&obuf, 0);
   716  			}
   717  			p = q;
   718  			if(p == 0 && op) {
   719  				p = op;
   720  				op = 0;
   721  			}
   722  		}
   723  		g.offset = h->offset;
   724  
   725  		BPUTC(&obuf, AHISTORY);
   726  		BPUTC(&obuf, Always);
   727  		BPUTC(&obuf, 0);
   728  		BPUTLE4(&obuf, h->line);
   729  		zaddr(&nullgen, 0);
   730  		zaddr(&g, 0);
   731  
   732  		if(tofree) {
   733  			free(tofree);
   734  			tofree = nil;
   735  		}
   736  	}
   737  }
   738  
   739  #include "../cc/lexbody"
   740  #include "../cc/macbody"