github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/asm/lexbody.go (about)

     1  // Inferno utils/cc/lexbody
     2  // http://code.Google.Com/p/inferno-os/source/browse/utils/cc/lexbody
     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  	"fmt"
    36  	"os"
    37  	"strconv"
    38  	"strings"
    39  	"unicode/utf8"
    40  
    41  	"cmd/internal/obj"
    42  )
    43  
    44  /*
    45   * common code for all the assemblers
    46   */
    47  func pragpack() {
    48  	for getnsc() != '\n' {
    49  	}
    50  }
    51  
    52  func pragvararg() {
    53  	for getnsc() != '\n' {
    54  	}
    55  }
    56  
    57  func pragcgo(name string) {
    58  	for getnsc() != '\n' {
    59  	}
    60  }
    61  
    62  func pragfpround() {
    63  	for getnsc() != '\n' {
    64  	}
    65  }
    66  
    67  func pragtextflag() {
    68  	for getnsc() != '\n' {
    69  	}
    70  }
    71  
    72  func pragdataflag() {
    73  	for getnsc() != '\n' {
    74  	}
    75  }
    76  
    77  func pragprofile() {
    78  	for getnsc() != '\n' {
    79  	}
    80  }
    81  
    82  func pragincomplete() {
    83  	for getnsc() != '\n' {
    84  	}
    85  }
    86  
    87  func setinclude(p string) {
    88  	if p == "" {
    89  		return
    90  	}
    91  	for i := 1; i < len(include); i++ {
    92  		if p == include[i] {
    93  			return
    94  		}
    95  	}
    96  
    97  	include = append(include, p)
    98  }
    99  
   100  func errorexit() {
   101  	obj.Bflush(&bstdout)
   102  	if outfile != "" {
   103  		os.Remove(outfile)
   104  	}
   105  	os.Exit(2)
   106  }
   107  
   108  func pushio() {
   109  	i := iostack
   110  	if i == nil {
   111  		Yyerror("botch in pushio")
   112  		errorexit()
   113  	}
   114  
   115  	i.P = fi.P
   116  }
   117  
   118  func newio() {
   119  	var pushdepth int = 0
   120  
   121  	i := iofree
   122  	if i == nil {
   123  		pushdepth++
   124  		if pushdepth > 1000 {
   125  			Yyerror("macro/io expansion too deep")
   126  			errorexit()
   127  		}
   128  		i = new(Io)
   129  	} else {
   130  		iofree = i.Link
   131  	}
   132  	i.F = nil
   133  	i.P = nil
   134  	ionext = i
   135  }
   136  
   137  func newfile(s string, f *os.File) {
   138  	i := ionext
   139  	i.Link = iostack
   140  	iostack = i
   141  	i.F = f
   142  	if f == nil {
   143  		var err error
   144  		i.F, err = os.Open(s)
   145  		if err != nil {
   146  			Yyerror("%ca: %v", Thechar, err)
   147  			errorexit()
   148  		}
   149  	}
   150  
   151  	fi.P = nil
   152  	obj.Linklinehist(Ctxt, int(Lineno), s, 0)
   153  }
   154  
   155  var thetext *obj.LSym
   156  
   157  func Settext(s *obj.LSym) {
   158  	thetext = s
   159  }
   160  
   161  func LabelLookup(s *Sym) *Sym {
   162  	if thetext == nil {
   163  		s.Labelname = s.Name
   164  		return s
   165  	}
   166  
   167  	p := string(fmt.Sprintf("%s.%s", thetext.Name, s.Name))
   168  	lab := Lookup(p)
   169  
   170  	lab.Labelname = s.Name
   171  	return lab
   172  }
   173  
   174  func Lookup(symb string) *Sym {
   175  	// turn leading · into ""·
   176  	if strings.HasPrefix(symb, "·") {
   177  		symb = `""` + symb
   178  	}
   179  
   180  	// turn · (U+00B7) into .
   181  	// turn ∕ (U+2215) into /
   182  	symb = strings.Replace(symb, "·", ".", -1)
   183  	symb = strings.Replace(symb, "∕", "/", -1)
   184  
   185  	s := hash[symb]
   186  	if s != nil {
   187  		return s
   188  	}
   189  
   190  	s = new(Sym)
   191  	s.Name = symb
   192  	syminit(s)
   193  	hash[symb] = s
   194  	return s
   195  }
   196  
   197  func isalnum(c int) bool {
   198  	return isalpha(c) || isdigit(c)
   199  }
   200  
   201  func isalpha(c int) bool {
   202  	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
   203  }
   204  
   205  func isspace(c int) bool {
   206  	return c == ' ' || c == '\t' || c == '\r' || c == '\n'
   207  }
   208  
   209  func ISALPHA(c int) bool {
   210  	if isalpha(c) {
   211  		return true
   212  	}
   213  	if c >= utf8.RuneSelf {
   214  		return true
   215  	}
   216  	return false
   217  }
   218  
   219  var yybuf bytes.Buffer
   220  
   221  func (yyImpl) Error(s string) {
   222  	Yyerror("%s", s)
   223  }
   224  
   225  type Yylval struct {
   226  	Sym  *Sym
   227  	Lval int64
   228  	Sval string
   229  	Dval float64
   230  }
   231  
   232  func Yylex(yylval *Yylval) int {
   233  	var c1 int
   234  	var s *Sym
   235  
   236  	c := peekc
   237  	if c != IGN {
   238  		peekc = IGN
   239  		goto l1
   240  	}
   241  
   242  l0:
   243  	c = GETC()
   244  
   245  l1:
   246  	if c == EOF {
   247  		peekc = EOF
   248  		return -1
   249  	}
   250  
   251  	if isspace(c) {
   252  		if c == '\n' {
   253  			Lineno++
   254  			return ';'
   255  		}
   256  
   257  		goto l0
   258  	}
   259  
   260  	if ISALPHA(c) {
   261  		yybuf.Reset()
   262  		goto aloop
   263  	}
   264  	if isdigit(c) {
   265  		yybuf.Reset()
   266  		if c != '0' {
   267  			goto dc
   268  		}
   269  		yybuf.WriteByte(byte(c))
   270  		c = GETC()
   271  		c1 = 3
   272  		if c == 'x' || c == 'X' {
   273  			c1 = 4
   274  			c = GETC()
   275  		} else if c < '0' || c > '7' {
   276  			goto dc
   277  		}
   278  		yylval.Lval = 0
   279  		for {
   280  			if c >= '0' && c <= '9' {
   281  				if c > '7' && c1 == 3 {
   282  					break
   283  				}
   284  				yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
   285  				yylval.Lval += int64(c) - '0'
   286  				c = GETC()
   287  				continue
   288  			}
   289  
   290  			if c1 == 3 {
   291  				break
   292  			}
   293  			if c >= 'A' && c <= 'F' {
   294  				c += 'a' - 'A'
   295  			}
   296  			if c >= 'a' && c <= 'f' {
   297  				yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
   298  				yylval.Lval += int64(c) - 'a' + 10
   299  				c = GETC()
   300  				continue
   301  			}
   302  
   303  			break
   304  		}
   305  
   306  		goto ncu
   307  	}
   308  	switch c {
   309  	case '\n':
   310  		Lineno++
   311  		return ';'
   312  
   313  	case '#':
   314  		domacro()
   315  		goto l0
   316  
   317  	case '.':
   318  		c = GETC()
   319  		if ISALPHA(c) {
   320  			yybuf.Reset()
   321  			yybuf.WriteByte('.')
   322  			goto aloop
   323  		}
   324  
   325  		if isdigit(c) {
   326  			yybuf.Reset()
   327  			yybuf.WriteByte('.')
   328  			goto casedot
   329  		}
   330  
   331  		peekc = c
   332  		return '.'
   333  
   334  	case '_',
   335  		'@':
   336  		yybuf.Reset()
   337  		goto aloop
   338  
   339  	case '"':
   340  		var buf bytes.Buffer
   341  		c1 = 0
   342  		for {
   343  			c = escchar('"')
   344  			if c == EOF {
   345  				break
   346  			}
   347  			buf.WriteByte(byte(c))
   348  		}
   349  		yylval.Sval = buf.String()
   350  		return LSCONST
   351  
   352  	case '\'':
   353  		c = escchar('\'')
   354  		if c == EOF {
   355  			c = '\''
   356  		}
   357  		if escchar('\'') != EOF {
   358  			Yyerror("missing '")
   359  		}
   360  		yylval.Lval = int64(c)
   361  		return LCONST
   362  
   363  	case '/':
   364  		c1 = GETC()
   365  		if c1 == '/' {
   366  			for {
   367  				c = GETC()
   368  				if c == '\n' {
   369  					goto l1
   370  				}
   371  				if c == EOF {
   372  					Yyerror("eof in comment")
   373  					errorexit()
   374  				}
   375  			}
   376  		}
   377  
   378  		if c1 == '*' {
   379  			for {
   380  				c = GETC()
   381  				for c == '*' {
   382  					c = GETC()
   383  					if c == '/' {
   384  						goto l0
   385  					}
   386  				}
   387  
   388  				if c == EOF {
   389  					Yyerror("eof in comment")
   390  					errorexit()
   391  				}
   392  
   393  				if c == '\n' {
   394  					Lineno++
   395  				}
   396  			}
   397  		}
   398  
   399  	default:
   400  		return int(c)
   401  	}
   402  
   403  	peekc = c1
   404  	return int(c)
   405  
   406  casedot:
   407  	for {
   408  		yybuf.WriteByte(byte(c))
   409  		c = GETC()
   410  		if !(isdigit(c)) {
   411  			break
   412  		}
   413  	}
   414  
   415  	if c == 'e' || c == 'E' {
   416  		goto casee
   417  	}
   418  	goto caseout
   419  
   420  casee:
   421  	yybuf.WriteByte('e')
   422  	c = GETC()
   423  	if c == '+' || c == '-' {
   424  		yybuf.WriteByte(byte(c))
   425  		c = GETC()
   426  	}
   427  
   428  	for isdigit(c) {
   429  		yybuf.WriteByte(byte(c))
   430  		c = GETC()
   431  	}
   432  
   433  caseout:
   434  	peekc = c
   435  	if FPCHIP != 0 /*TypeKind(100016)*/ {
   436  		last = yybuf.String()
   437  		yylval.Dval = atof(last)
   438  		return LFCONST
   439  	}
   440  
   441  	Yyerror("assembler cannot interpret fp constants")
   442  	yylval.Lval = 1
   443  	return LCONST
   444  
   445  aloop:
   446  	yybuf.WriteByte(byte(c))
   447  	c = GETC()
   448  	if ISALPHA(c) || isdigit(c) || c == '_' || c == '$' {
   449  		goto aloop
   450  	}
   451  	peekc = c
   452  	last = yybuf.String()
   453  	s = Lookup(last)
   454  	if s.Macro != nil {
   455  		newio()
   456  		ionext.P = macexpand(s)
   457  		pushio()
   458  		ionext.Link = iostack
   459  		iostack = ionext
   460  		fi.P = ionext.P
   461  		if peekc != IGN {
   462  			fi.P = append(fi.P, byte(peekc))
   463  			peekc = IGN
   464  		}
   465  
   466  		goto l0
   467  	}
   468  
   469  	if s.Type == 0 {
   470  		s.Type = LNAME
   471  	}
   472  	if s.Type == LNAME || s.Type == LVAR || s.Type == LLAB {
   473  		yylval.Sym = s
   474  		yylval.Sval = last
   475  		return int(s.Type)
   476  	}
   477  
   478  	yylval.Lval = s.Value
   479  	yylval.Sval = last
   480  	return int(s.Type)
   481  
   482  dc:
   483  	for {
   484  		if !(isdigit(c)) {
   485  			break
   486  		}
   487  		yybuf.WriteByte(byte(c))
   488  		c = GETC()
   489  	}
   490  
   491  	if c == '.' {
   492  		goto casedot
   493  	}
   494  	if c == 'e' || c == 'E' {
   495  		goto casee
   496  	}
   497  	last = yybuf.String()
   498  	yylval.Lval = strtoll(last, nil, 10)
   499  
   500  ncu:
   501  	for c == 'U' || c == 'u' || c == 'l' || c == 'L' {
   502  		c = GETC()
   503  	}
   504  	peekc = c
   505  	return LCONST
   506  }
   507  
   508  func getc() int {
   509  	c := peekc
   510  	if c != IGN {
   511  		peekc = IGN
   512  		if c == '\n' {
   513  			Lineno++
   514  		}
   515  		return c
   516  	}
   517  
   518  	c = GETC()
   519  	if c == '\n' {
   520  		Lineno++
   521  	}
   522  	if c == EOF {
   523  		Yyerror("End of file")
   524  		errorexit()
   525  	}
   526  
   527  	return c
   528  }
   529  
   530  func getnsc() int {
   531  	var c int
   532  
   533  	for {
   534  		c = getc()
   535  		if !isspace(c) || c == '\n' {
   536  			return c
   537  		}
   538  	}
   539  }
   540  
   541  func unget(c int) {
   542  	peekc = c
   543  	if c == '\n' {
   544  		Lineno--
   545  	}
   546  }
   547  
   548  func escchar(e int) int {
   549  	var l int
   550  
   551  loop:
   552  	c := getc()
   553  	if c == '\n' {
   554  		Yyerror("newline in string")
   555  		return EOF
   556  	}
   557  
   558  	if c != '\\' {
   559  		if c == e {
   560  			return EOF
   561  		}
   562  		return c
   563  	}
   564  
   565  	c = getc()
   566  	if c >= '0' && c <= '7' {
   567  		l = c - '0'
   568  		c = getc()
   569  		if c >= '0' && c <= '7' {
   570  			l = l*8 + c - '0'
   571  			c = getc()
   572  			if c >= '0' && c <= '7' {
   573  				l = l*8 + c - '0'
   574  				return l
   575  			}
   576  		}
   577  
   578  		peekc = c
   579  		unget(c)
   580  		return l
   581  	}
   582  
   583  	switch c {
   584  	case '\n':
   585  		goto loop
   586  	case 'n':
   587  		return '\n'
   588  	case 't':
   589  		return '\t'
   590  	case 'b':
   591  		return '\b'
   592  	case 'r':
   593  		return '\r'
   594  	case 'f':
   595  		return '\f'
   596  	case 'a':
   597  		return 0x07
   598  	case 'v':
   599  		return 0x0b
   600  	case 'z':
   601  		return 0x00
   602  	}
   603  
   604  	return c
   605  }
   606  
   607  func pinit(f string) {
   608  	Lineno = 1
   609  	newio()
   610  	newfile(f, nil)
   611  	PC = 0
   612  	peekc = IGN
   613  	sym = 1
   614  	for _, s := range hash {
   615  		s.Macro = nil
   616  	}
   617  }
   618  
   619  func filbuf() int {
   620  	var n int
   621  
   622  loop:
   623  	i := iostack
   624  	if i == nil {
   625  		return EOF
   626  	}
   627  	if i.F == nil {
   628  		goto pop
   629  	}
   630  	n, _ = i.F.Read(i.B[:])
   631  	if n == 0 {
   632  		i.F.Close()
   633  		obj.Linklinehist(Ctxt, int(Lineno), "<pop>", 0)
   634  		goto pop
   635  	}
   636  	fi.P = i.B[1:n]
   637  	return int(i.B[0]) & 0xff
   638  
   639  pop:
   640  	iostack = i.Link
   641  	i.Link = iofree
   642  	iofree = i
   643  	i = iostack
   644  	if i == nil {
   645  		return EOF
   646  	}
   647  	fi.P = i.P
   648  	if len(fi.P) == 0 {
   649  		goto loop
   650  	}
   651  	tmp8 := fi.P
   652  	fi.P = fi.P[1:]
   653  	return int(tmp8[0]) & 0xff
   654  }
   655  
   656  var last string
   657  
   658  func Yyerror(a string, args ...interface{}) {
   659  	/*
   660  	 * hack to intercept message from yaccpar
   661  	 */
   662  	if a == "syntax error" || len(args) == 1 && a == "%s" && args[0] == "syntax error" {
   663  		Yyerror("syntax error, last name: %s", last)
   664  		return
   665  	}
   666  
   667  	prfile(Lineno)
   668  	fmt.Printf("%s\n", fmt.Sprintf(a, args...))
   669  	nerrors++
   670  	if nerrors > 10 {
   671  		fmt.Printf("too many errors\n")
   672  		errorexit()
   673  	}
   674  }
   675  
   676  func prfile(l int32) {
   677  	obj.Linkprfile(Ctxt, int(l))
   678  }
   679  
   680  func GETC() int {
   681  	if len(fi.P) == 0 {
   682  		return filbuf()
   683  	}
   684  	c := int(fi.P[0])
   685  	fi.P = fi.P[1:]
   686  	return c
   687  }
   688  
   689  func isdigit(c int) bool {
   690  	return '0' <= c && c <= '9'
   691  }
   692  
   693  func strtoll(s string, p *byte, base int) int64 {
   694  	if p != nil {
   695  		panic("strtoll")
   696  	}
   697  	n, err := strconv.ParseInt(s, base, 64)
   698  	if err != nil {
   699  		return 0
   700  	}
   701  	return n
   702  }
   703  
   704  func atof(s string) float64 {
   705  	f, err := strconv.ParseFloat(s, 64)
   706  	if err != nil {
   707  		return 0
   708  	}
   709  	return f
   710  }