github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/asm/internal/lex/lex.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package lex implements lexical analysis for the assembler.
     6  package lex
     7  
     8  import (
     9  	"fmt"
    10  	"log"
    11  	"os"
    12  	"strings"
    13  	"text/scanner"
    14  
    15  	"github.com/gagliardetto/golang-go/cmd/internal/src"
    16  )
    17  
    18  // A ScanToken represents an input item. It is a simple wrapping of rune, as
    19  // returned by text/scanner.Scanner, plus a couple of extra values.
    20  type ScanToken rune
    21  
    22  const (
    23  	// Asm defines some two-character lexemes. We make up
    24  	// a rune/ScanToken value for them - ugly but simple.
    25  	LSH       ScanToken = -1000 - iota // << Left shift.
    26  	RSH                                // >> Logical right shift.
    27  	ARR                                // -> Used on ARM for shift type 3, arithmetic right shift.
    28  	ROT                                // @> Used on ARM for shift type 4, rotate right.
    29  	macroName                          // name of macro that should not be expanded
    30  )
    31  
    32  // IsRegisterShift reports whether the token is one of the ARM register shift operators.
    33  func IsRegisterShift(r ScanToken) bool {
    34  	return ROT <= r && r <= LSH // Order looks backwards because these are negative.
    35  }
    36  
    37  func (t ScanToken) String() string {
    38  	switch t {
    39  	case scanner.EOF:
    40  		return "EOF"
    41  	case scanner.Ident:
    42  		return "identifier"
    43  	case scanner.Int:
    44  		return "integer constant"
    45  	case scanner.Float:
    46  		return "float constant"
    47  	case scanner.Char:
    48  		return "rune constant"
    49  	case scanner.String:
    50  		return "string constant"
    51  	case scanner.RawString:
    52  		return "raw string constant"
    53  	case scanner.Comment:
    54  		return "comment"
    55  	default:
    56  		return fmt.Sprintf("%q", rune(t))
    57  	}
    58  }
    59  
    60  // NewLexer returns a lexer for the named file and the given link context.
    61  func NewLexer(name string) TokenReader {
    62  	input := NewInput(name)
    63  	fd, err := os.Open(name)
    64  	if err != nil {
    65  		log.Fatalf("%s\n", err)
    66  	}
    67  	input.Push(NewTokenizer(name, fd, fd))
    68  	return input
    69  }
    70  
    71  // The other files in this directory each contain an implementation of TokenReader.
    72  
    73  // A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what
    74  // the text of the most recently returned token is, and where it was found.
    75  // The underlying scanner elides all spaces except newline, so the input looks like a stream of
    76  // Tokens; original spacing is lost but we don't need it.
    77  type TokenReader interface {
    78  	// Next returns the next token.
    79  	Next() ScanToken
    80  	// The following methods all refer to the most recent token returned by Next.
    81  	// Text returns the original string representation of the token.
    82  	Text() string
    83  	// File reports the source file name of the token.
    84  	File() string
    85  	// Base reports the position base of the token.
    86  	Base() *src.PosBase
    87  	// SetBase sets the position base.
    88  	SetBase(*src.PosBase)
    89  	// Line reports the source line number of the token.
    90  	Line() int
    91  	// Col reports the source column number of the token.
    92  	Col() int
    93  	// Close does any teardown required.
    94  	Close()
    95  }
    96  
    97  // A Token is a scan token plus its string value.
    98  // A macro is stored as a sequence of Tokens with spaces stripped.
    99  type Token struct {
   100  	ScanToken
   101  	text string
   102  }
   103  
   104  // Make returns a Token with the given rune (ScanToken) and text representation.
   105  func Make(token ScanToken, text string) Token {
   106  	// If the symbol starts with center dot, as in ·x, rewrite it as ""·x
   107  	if token == scanner.Ident && strings.HasPrefix(text, "\u00B7") {
   108  		text = `""` + text
   109  	}
   110  	// Substitute the substitutes for . and /.
   111  	text = strings.Replace(text, "\u00B7", ".", -1)
   112  	text = strings.Replace(text, "\u2215", "/", -1)
   113  	return Token{ScanToken: token, text: text}
   114  }
   115  
   116  func (l Token) String() string {
   117  	return l.text
   118  }
   119  
   120  // A Macro represents the definition of a #defined macro.
   121  type Macro struct {
   122  	name   string   // The #define name.
   123  	args   []string // Formal arguments.
   124  	tokens []Token  // Body of macro.
   125  }
   126  
   127  // Tokenize turns a string into a list of Tokens; used to parse the -D flag and in tests.
   128  func Tokenize(str string) []Token {
   129  	t := NewTokenizer("command line", strings.NewReader(str), nil)
   130  	var tokens []Token
   131  	for {
   132  		tok := t.Next()
   133  		if tok == scanner.EOF {
   134  			break
   135  		}
   136  		tokens = append(tokens, Make(tok, t.Text()))
   137  	}
   138  	return tokens
   139  }