github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/asm/macbody.go (about)

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