1
2
3
4
5 package lex
6
7 import (
8 "io"
9 "os"
10 "strings"
11 "text/scanner"
12 "unicode"
13
14 "cmd/asm/internal/flags"
15 "cmd/internal/objabi"
16 "cmd/internal/src"
17 )
18
19
20
21
22 type Tokenizer struct {
23 tok ScanToken
24 s *scanner.Scanner
25 base *src.PosBase
26 line int
27 file *os.File
28 }
29
30 func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
31 var s scanner.Scanner
32 s.Init(r)
33
34 s.Whitespace = 1<<'\t' | 1<<'\r' | 1<<' '
35
36 s.Mode = scanner.ScanChars |
37 scanner.ScanFloats |
38 scanner.ScanIdents |
39 scanner.ScanInts |
40 scanner.ScanStrings |
41 scanner.ScanComments
42 s.Position.Filename = name
43 s.IsIdentRune = isIdentRune
44 return &Tokenizer{
45 s: &s,
46 base: src.NewFileBase(name, objabi.AbsFile(objabi.WorkingDir(), name, *flags.TrimPath)),
47 line: 1,
48 file: file,
49 }
50 }
51
52
53 func isIdentRune(ch rune, i int) bool {
54 if unicode.IsLetter(ch) {
55 return true
56 }
57 switch ch {
58 case '_':
59 return true
60 case '\u00B7':
61 return true
62 case '\u2215':
63 return true
64 }
65
66 return i > 0 && unicode.IsDigit(ch)
67 }
68
69 func (t *Tokenizer) Text() string {
70 switch t.tok {
71 case LSH:
72 return "<<"
73 case RSH:
74 return ">>"
75 case ARR:
76 return "->"
77 case ROT:
78 return "@>"
79 }
80 return t.s.TokenText()
81 }
82
83 func (t *Tokenizer) File() string {
84 return t.base.Filename()
85 }
86
87 func (t *Tokenizer) Base() *src.PosBase {
88 return t.base
89 }
90
91 func (t *Tokenizer) SetBase(base *src.PosBase) {
92 t.base = base
93 }
94
95 func (t *Tokenizer) Line() int {
96 return t.line
97 }
98
99 func (t *Tokenizer) Col() int {
100 return t.s.Pos().Column
101 }
102
103 func (t *Tokenizer) Next() ScanToken {
104 s := t.s
105 for {
106 t.tok = ScanToken(s.Scan())
107 if t.tok != scanner.Comment {
108 break
109 }
110 text := s.TokenText()
111 t.line += strings.Count(text, "\n")
112
113 if strings.HasPrefix(text, "//go:build") {
114 t.tok = BuildComment
115 break
116 }
117 }
118 switch t.tok {
119 case '\n':
120 t.line++
121 case '-':
122 if s.Peek() == '>' {
123 s.Next()
124 t.tok = ARR
125 return ARR
126 }
127 case '@':
128 if s.Peek() == '>' {
129 s.Next()
130 t.tok = ROT
131 return ROT
132 }
133 case '<':
134 if s.Peek() == '<' {
135 s.Next()
136 t.tok = LSH
137 return LSH
138 }
139 case '>':
140 if s.Peek() == '>' {
141 s.Next()
142 t.tok = RSH
143 return RSH
144 }
145 }
146 return t.tok
147 }
148
149 func (t *Tokenizer) Close() {
150 if t.file != nil {
151 t.file.Close()
152 }
153 }
154
View as plain text