rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/asm/macbody.go (about)

     1  // Inferno utils/cc/macbody
     2  // http://code.Google.Com/p/inferno-os/source/browse/utils/cc/macbody
     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  package asm
    32  
    33  import (
    34  	"bytes"
    35  	"cmd/internal/obj"
    36  	"fmt"
    37  	"os"
    38  	"strings"
    39  )
    40  
    41  const (
    42  	VARMAC = 0x80
    43  )
    44  
    45  func getnsn() int32 {
    46  	c := getnsc()
    47  	if c < '0' || c > '9' {
    48  		return -1
    49  	}
    50  	n := int32(0)
    51  	for c >= '0' && c <= '9' {
    52  		n = n*10 + int32(c) - '0'
    53  		c = getc()
    54  	}
    55  
    56  	unget(c)
    57  	return n
    58  }
    59  
    60  func getsym() *Sym {
    61  	c := getnsc()
    62  	if !isalpha(c) && c != '_' && c < 0x80 {
    63  		unget(c)
    64  		return nil
    65  	}
    66  
    67  	var buf bytes.Buffer
    68  	for {
    69  		buf.WriteByte(byte(c))
    70  		c = getc()
    71  		if isalnum(c) || c == '_' || c >= 0x80 {
    72  			continue
    73  		}
    74  		unget(c)
    75  		break
    76  	}
    77  	last = buf.String()
    78  	return Lookup(last)
    79  }
    80  
    81  func getsymdots(dots *int) *Sym {
    82  	s := getsym()
    83  	if s != nil {
    84  		return s
    85  	}
    86  
    87  	c := getnsc()
    88  	if c != '.' {
    89  		unget(c)
    90  		return nil
    91  	}
    92  
    93  	if getc() != '.' || getc() != '.' {
    94  		Yyerror("bad dots in macro")
    95  	}
    96  	*dots = 1
    97  	return Lookup("__VA_ARGS__")
    98  }
    99  
   100  func getcom() int {
   101  	var c int
   102  
   103  	for {
   104  		c = getnsc()
   105  		if c != '/' {
   106  			break
   107  		}
   108  		c = getc()
   109  		if c == '/' {
   110  			for c != '\n' {
   111  				c = getc()
   112  			}
   113  			break
   114  		}
   115  
   116  		if c != '*' {
   117  			break
   118  		}
   119  		c = getc()
   120  		for {
   121  			if c == '*' {
   122  				c = getc()
   123  				if c != '/' {
   124  					continue
   125  				}
   126  				c = getc()
   127  				break
   128  			}
   129  
   130  			if c == '\n' {
   131  				Yyerror("comment across newline")
   132  				break
   133  			}
   134  
   135  			c = getc()
   136  		}
   137  
   138  		if c == '\n' {
   139  			break
   140  		}
   141  	}
   142  
   143  	return c
   144  }
   145  
   146  func dodefine(cp string) {
   147  	var s *Sym
   148  
   149  	if i := strings.Index(cp, "="); i >= 0 {
   150  		p := cp[i+1:]
   151  		cp = cp[:i]
   152  		s = Lookup(cp)
   153  		s.Macro = &Macro{Text: p}
   154  	} else {
   155  		s = Lookup(cp)
   156  		s.Macro = &Macro{Text: "1"}
   157  	}
   158  
   159  	if debug['m'] != 0 {
   160  		fmt.Printf("#define (-D) %s %s\n", s.Name, s.Macro.Text)
   161  	}
   162  }
   163  
   164  var mactab = []struct {
   165  	Macname string
   166  	Macf    func()
   167  }{
   168  	{"ifdef", nil},  /* macif(0) */
   169  	{"ifndef", nil}, /* macif(1) */
   170  	{"else", nil},   /* macif(2) */
   171  	{"line", maclin},
   172  	{"define", macdef},
   173  	{"include", macinc},
   174  	{"undef", macund},
   175  	{"pragma", macprag},
   176  	{"endif", macend},
   177  }
   178  
   179  func domacro() {
   180  	s := getsym()
   181  	if s == nil {
   182  		s = Lookup("endif")
   183  	}
   184  	for i := 0; i < len(mactab); i++ {
   185  		if s.Name == mactab[i].Macname {
   186  			if mactab[i].Macf != nil {
   187  				mactab[i].Macf()
   188  			} else {
   189  				macif(i)
   190  			}
   191  			return
   192  		}
   193  	}
   194  
   195  	Yyerror("unknown #: %s", s.Name)
   196  	macend()
   197  }
   198  
   199  func macund() {
   200  	s := getsym()
   201  	macend()
   202  	if s == nil {
   203  		Yyerror("syntax in #undef")
   204  		return
   205  	}
   206  
   207  	s.Macro = nil
   208  }
   209  
   210  const (
   211  	NARG = 25
   212  )
   213  
   214  func macdef() {
   215  	var args [NARG]string
   216  	var n int
   217  	var i int
   218  	var c int
   219  	var dots int
   220  	var ischr int
   221  	var base bytes.Buffer
   222  
   223  	s := getsym()
   224  	if s == nil {
   225  		goto bad
   226  	}
   227  	if s.Macro != nil {
   228  		Yyerror("macro redefined: %s", s.Name)
   229  	}
   230  	c = getc()
   231  	n = -1
   232  	dots = 0
   233  	if c == '(' {
   234  		n++
   235  		c = getnsc()
   236  		if c != ')' {
   237  			unget(c)
   238  			var a *Sym
   239  			var c int
   240  			for {
   241  				a = getsymdots(&dots)
   242  				if a == nil {
   243  					goto bad
   244  				}
   245  				if n >= NARG {
   246  					Yyerror("too many arguments in #define: %s", s.Name)
   247  					goto bad
   248  				}
   249  
   250  				args[n] = a.Name
   251  				n++
   252  				c = getnsc()
   253  				if c == ')' {
   254  					break
   255  				}
   256  				if c != ',' || dots != 0 {
   257  					goto bad
   258  				}
   259  			}
   260  		}
   261  
   262  		c = getc()
   263  	}
   264  
   265  	if isspace(c) {
   266  		if c != '\n' {
   267  			c = getnsc()
   268  		}
   269  	}
   270  	ischr = 0
   271  	for {
   272  		if isalpha(c) || c == '_' {
   273  			var buf bytes.Buffer
   274  			buf.WriteByte(byte(c))
   275  			c = getc()
   276  			for isalnum(c) || c == '_' {
   277  				buf.WriteByte(byte(c))
   278  				c = getc()
   279  			}
   280  
   281  			symb := buf.String()
   282  			for i = 0; i < n; i++ {
   283  				if symb == args[i] {
   284  					break
   285  				}
   286  			}
   287  			if i >= n {
   288  				base.WriteString(symb)
   289  				continue
   290  			}
   291  
   292  			base.WriteByte('#')
   293  			base.WriteByte(byte('a' + i))
   294  			continue
   295  		}
   296  
   297  		if ischr != 0 {
   298  			if c == '\\' {
   299  				base.WriteByte(byte(c))
   300  				c = getc()
   301  			} else if c == ischr {
   302  				ischr = 0
   303  			}
   304  		} else {
   305  			if c == '"' || c == '\'' {
   306  				base.WriteByte(byte(c))
   307  				ischr = c
   308  				c = getc()
   309  				continue
   310  			}
   311  
   312  			if c == '/' {
   313  				c = getc()
   314  				if c == '/' {
   315  					c = getc()
   316  					for {
   317  						if c == '\n' {
   318  							break
   319  						}
   320  						c = getc()
   321  					}
   322  
   323  					continue
   324  				}
   325  
   326  				if c == '*' {
   327  					c = getc()
   328  					for {
   329  						if c == '*' {
   330  							c = getc()
   331  							if c != '/' {
   332  								continue
   333  							}
   334  							c = getc()
   335  							break
   336  						}
   337  
   338  						if c == '\n' {
   339  							Yyerror("comment and newline in define: %s", s.Name)
   340  							break
   341  						}
   342  
   343  						c = getc()
   344  					}
   345  
   346  					continue
   347  				}
   348  
   349  				base.WriteByte('/')
   350  				continue
   351  			}
   352  		}
   353  
   354  		if c == '\\' {
   355  			c = getc()
   356  			if c == '\n' {
   357  				c = getc()
   358  				continue
   359  			} else if c == '\r' {
   360  				c = getc()
   361  				if c == '\n' {
   362  					c = getc()
   363  					continue
   364  				}
   365  			}
   366  
   367  			base.WriteByte('\\')
   368  			continue
   369  		}
   370  
   371  		if c == '\n' {
   372  			break
   373  		}
   374  		if c == '#' {
   375  			if n > 0 {
   376  				base.WriteByte(byte(c))
   377  			}
   378  		}
   379  
   380  		base.WriteByte(byte(c))
   381  		c = GETC()
   382  		if c == '\n' {
   383  			Lineno++
   384  		}
   385  		if c == -1 {
   386  			Yyerror("eof in a macro: %s", s.Name)
   387  			break
   388  		}
   389  	}
   390  
   391  	s.Macro = &Macro{
   392  		Text: base.String(),
   393  		Narg: n + 1,
   394  		Dots: dots != 0,
   395  	}
   396  	if debug['m'] != 0 {
   397  		fmt.Printf("#define %s %s\n", s.Name, s.Macro.Text)
   398  	}
   399  	return
   400  
   401  bad:
   402  	if s == nil {
   403  		Yyerror("syntax in #define")
   404  	} else {
   405  		Yyerror("syntax in #define: %s", s.Name)
   406  	}
   407  	macend()
   408  }
   409  
   410  func macexpand(s *Sym) []byte {
   411  	if s.Macro.Narg == 0 {
   412  		if debug['m'] != 0 {
   413  			fmt.Printf("#expand %s %s\n", s.Name, s.Macro.Text)
   414  		}
   415  		return []byte(s.Macro.Text)
   416  	}
   417  
   418  	nargs := s.Macro.Narg - 1
   419  	dots := s.Macro.Dots
   420  
   421  	c := getnsc()
   422  	var arg []string
   423  	var cp string
   424  	var out bytes.Buffer
   425  	if c != '(' {
   426  		goto bad
   427  	}
   428  	c = getc()
   429  	if c != ')' {
   430  		unget(c)
   431  		l := 0
   432  		var buf bytes.Buffer
   433  		var c int
   434  		for {
   435  			c = getc()
   436  			if c == '"' {
   437  				for {
   438  					buf.WriteByte(byte(c))
   439  					c = getc()
   440  					if c == '\\' {
   441  						buf.WriteByte(byte(c))
   442  						c = getc()
   443  						continue
   444  					}
   445  
   446  					if c == '\n' {
   447  						goto bad
   448  					}
   449  					if c == '"' {
   450  						break
   451  					}
   452  				}
   453  			}
   454  
   455  			if c == '\'' {
   456  				for {
   457  					buf.WriteByte(byte(c))
   458  					c = getc()
   459  					if c == '\\' {
   460  						buf.WriteByte(byte(c))
   461  						c = getc()
   462  						continue
   463  					}
   464  
   465  					if c == '\n' {
   466  						goto bad
   467  					}
   468  					if c == '\'' {
   469  						break
   470  					}
   471  				}
   472  			}
   473  
   474  			if c == '/' {
   475  				c = getc()
   476  				switch c {
   477  				case '*':
   478  					for {
   479  						c = getc()
   480  						if c == '*' {
   481  							c = getc()
   482  							if c == '/' {
   483  								break
   484  							}
   485  						}
   486  					}
   487  
   488  					buf.WriteByte(' ')
   489  					continue
   490  
   491  				case '/':
   492  					for {
   493  						c = getc()
   494  						if !(c != '\n') {
   495  							break
   496  						}
   497  					}
   498  
   499  				default:
   500  					unget(c)
   501  					c = '/'
   502  				}
   503  			}
   504  
   505  			if l == 0 {
   506  				if c == ',' {
   507  					if len(arg) == nargs-1 && dots {
   508  						buf.WriteByte(',')
   509  						continue
   510  					}
   511  
   512  					arg = append(arg, buf.String())
   513  					buf.Reset()
   514  					continue
   515  				}
   516  
   517  				if c == ')' {
   518  					arg = append(arg, buf.String())
   519  					break
   520  				}
   521  			}
   522  
   523  			if c == '\n' {
   524  				c = ' '
   525  			}
   526  			buf.WriteByte(byte(c))
   527  			if c == '(' {
   528  				l++
   529  			}
   530  			if c == ')' {
   531  				l--
   532  			}
   533  		}
   534  	}
   535  
   536  	if len(arg) != nargs {
   537  		Yyerror("argument mismatch expanding: %s", s.Name)
   538  		return nil
   539  	}
   540  
   541  	cp = s.Macro.Text
   542  	for i := 0; i < len(cp); i++ {
   543  		c = int(cp[i])
   544  		if c == '\n' {
   545  			c = ' '
   546  		}
   547  		if c != '#' {
   548  			out.WriteByte(byte(c))
   549  			continue
   550  		}
   551  
   552  		i++
   553  		if i >= len(cp) {
   554  			goto bad
   555  		}
   556  		c = int(cp[i])
   557  		if c == '#' {
   558  			out.WriteByte(byte(c))
   559  			continue
   560  		}
   561  
   562  		c -= 'a'
   563  		if c < 0 || c >= len(arg) {
   564  			continue
   565  		}
   566  		out.WriteString(arg[c])
   567  	}
   568  
   569  	if debug['m'] != 0 {
   570  		fmt.Printf("#expand %s %s\n", s.Name, out.String())
   571  	}
   572  	return out.Bytes()
   573  
   574  bad:
   575  	Yyerror("syntax in macro expansion: %s", s.Name)
   576  	return nil
   577  }
   578  
   579  func macinc() {
   580  	var c int
   581  	var buf bytes.Buffer
   582  	var f *os.File
   583  	var hp string
   584  	var str string
   585  	var symb string
   586  
   587  	c0 := getnsc()
   588  	if c0 != '"' {
   589  		c = c0
   590  		if c0 != '<' {
   591  			goto bad
   592  		}
   593  		c0 = '>'
   594  	}
   595  
   596  	for {
   597  		c = getc()
   598  		if c == c0 {
   599  			break
   600  		}
   601  		if c == '\n' {
   602  			goto bad
   603  		}
   604  		buf.WriteByte(byte(c))
   605  	}
   606  	str = buf.String()
   607  
   608  	c = getcom()
   609  	if c != '\n' {
   610  		goto bad
   611  	}
   612  
   613  	for i := 0; i < len(include); i++ {
   614  		if i == 0 && c0 == '>' {
   615  			continue
   616  		}
   617  		symb = include[i]
   618  		symb += "/"
   619  		if symb == "./" {
   620  			symb = ""
   621  		}
   622  		symb += str
   623  		var err error
   624  		f, err = os.Open(symb)
   625  		if err == nil {
   626  			break
   627  		}
   628  	}
   629  
   630  	if f == nil {
   631  		symb = str
   632  	}
   633  	hp = symb
   634  	newio()
   635  	pushio()
   636  	newfile(hp, f)
   637  	return
   638  
   639  bad:
   640  	unget(c)
   641  	Yyerror("syntax in #include")
   642  	macend()
   643  }
   644  
   645  func maclin() {
   646  	var buf bytes.Buffer
   647  	var symb string
   648  
   649  	n := getnsn()
   650  	c := getc()
   651  	if n < 0 {
   652  		goto bad
   653  	}
   654  	for {
   655  		if c == ' ' || c == '\t' {
   656  			c = getc()
   657  			continue
   658  		}
   659  
   660  		if c == '"' {
   661  			break
   662  		}
   663  		if c == '\n' {
   664  			symb = "<noname>"
   665  			goto nn
   666  		}
   667  
   668  		goto bad
   669  	}
   670  
   671  	for {
   672  		c = getc()
   673  		if c == '"' {
   674  			break
   675  		}
   676  		buf.WriteByte(byte(c))
   677  	}
   678  	symb = buf.String()
   679  
   680  	c = getcom()
   681  	if c != '\n' {
   682  		goto bad
   683  	}
   684  
   685  nn:
   686  	obj.Linklinehist(Ctxt, int(Lineno), symb, int(n))
   687  	return
   688  
   689  bad:
   690  	unget(c)
   691  	Yyerror("syntax in #line")
   692  	macend()
   693  }
   694  
   695  func macif(f int) {
   696  	var c int
   697  	var l int
   698  	var bol int
   699  	var s *Sym
   700  
   701  	if f == 2 {
   702  		goto skip
   703  	}
   704  	s = getsym()
   705  	if s == nil {
   706  		goto bad
   707  	}
   708  	if getcom() != '\n' {
   709  		goto bad
   710  	}
   711  	if (s.Macro != nil) != (f != 0) {
   712  		return
   713  	}
   714  
   715  skip:
   716  	bol = 1
   717  	l = 0
   718  	for {
   719  		c = getc()
   720  		if c != '#' {
   721  			if !isspace(c) {
   722  				bol = 0
   723  			}
   724  			if c == '\n' {
   725  				bol = 1
   726  			}
   727  			continue
   728  		}
   729  
   730  		if !(bol != 0) {
   731  			continue
   732  		}
   733  		s = getsym()
   734  		if s == nil {
   735  			continue
   736  		}
   737  		if s.Name == "endif" {
   738  			if l != 0 {
   739  				l--
   740  				continue
   741  			}
   742  
   743  			macend()
   744  			return
   745  		}
   746  
   747  		if s.Name == "ifdef" || s.Name == "ifndef" {
   748  			l++
   749  			continue
   750  		}
   751  
   752  		if l == 0 && f != 2 && s.Name == "else" {
   753  			macend()
   754  			return
   755  		}
   756  	}
   757  
   758  bad:
   759  	Yyerror("syntax in #if(n)def")
   760  	macend()
   761  }
   762  
   763  func macprag() {
   764  	var c int
   765  
   766  	s := getsym()
   767  
   768  	if s != nil && s.Name == "lib" {
   769  		c0 := getnsc()
   770  		if c0 != '"' {
   771  			c = c0
   772  			if c0 != '<' {
   773  				goto bad
   774  			}
   775  			c0 = '>'
   776  		}
   777  
   778  		var buf bytes.Buffer
   779  		for {
   780  			c = getc()
   781  			if c == c0 {
   782  				break
   783  			}
   784  			if c == '\n' {
   785  				goto bad
   786  			}
   787  			buf.WriteByte(byte(c))
   788  		}
   789  		symb := buf.String()
   790  
   791  		c = getcom()
   792  		if c != '\n' {
   793  			goto bad
   794  		}
   795  
   796  		/*
   797  		 * put pragma-line in as a funny history
   798  		 */
   799  		obj.Linklinehist(Ctxt, int(Lineno), symb, -1)
   800  		return
   801  	}
   802  	if s != nil && s.Name == "pack" {
   803  		pragpack()
   804  		return
   805  	}
   806  
   807  	if s != nil && s.Name == "fpround" {
   808  		pragfpround()
   809  		return
   810  	}
   811  
   812  	if s != nil && s.Name == "textflag" {
   813  		pragtextflag()
   814  		return
   815  	}
   816  
   817  	if s != nil && s.Name == "dataflag" {
   818  		pragdataflag()
   819  		return
   820  	}
   821  
   822  	if s != nil && s.Name == "varargck" {
   823  		pragvararg()
   824  		return
   825  	}
   826  
   827  	if s != nil && s.Name == "incomplete" {
   828  		pragincomplete()
   829  		return
   830  	}
   831  
   832  	if s != nil && (strings.HasPrefix(s.Name, "cgo_") || strings.HasPrefix(s.Name, "dyn")) {
   833  		pragcgo(s.Name)
   834  		return
   835  	}
   836  
   837  	for getnsc() != '\n' {
   838  	}
   839  	return
   840  
   841  bad:
   842  	unget(c)
   843  	Yyerror("syntax in #pragma lib")
   844  	macend()
   845  }
   846  
   847  func macend() {
   848  	var c int
   849  
   850  	for {
   851  		c = getnsc()
   852  		if c < 0 || c == '\n' {
   853  			return
   854  		}
   855  	}
   856  }