@@ -91,7 +91,23 @@ func (p *Parser) pos() src.XPos {
91
91
}
92
92
93
93
func (p * Parser ) Parse () (* obj.Prog , bool ) {
94
- for p .line () {
94
+ scratch := make ([][]lex.Token , 0 , 3 )
95
+ for {
96
+ word , cond , operands , ok := p .line (scratch )
97
+ if ! ok {
98
+ break
99
+ }
100
+ scratch = operands
101
+
102
+ if p .pseudo (word , operands ) {
103
+ continue
104
+ }
105
+ i , present := p .arch .Instructions [word ]
106
+ if present {
107
+ p .instruction (i , word , cond , operands )
108
+ continue
109
+ }
110
+ p .errorf ("unrecognized instruction %q" , word )
95
111
}
96
112
if p .errorCount > 0 {
97
113
return nil , false
@@ -100,8 +116,17 @@ func (p *Parser) Parse() (*obj.Prog, bool) {
100
116
return p .firstProg , true
101
117
}
102
118
103
- // WORD [ arg {, arg} ] (';' | '\n')
104
- func (p * Parser ) line () bool {
119
+ // line consumes a single assembly line from p.lex of the form
120
+ //
121
+ // {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
122
+ //
123
+ // It adds any labels to p.pendingLabels and returns the word, cond,
124
+ // operand list, and true. If there is an error or EOF, it returns
125
+ // ok=false.
126
+ //
127
+ // line may reuse the memory from scratch.
128
+ func (p * Parser ) line (scratch [][]lex.Token ) (word , cond string , operands [][]lex.Token , ok bool ) {
129
+ next:
105
130
// Skip newlines.
106
131
var tok lex.ScanToken
107
132
for {
@@ -114,24 +139,29 @@ func (p *Parser) line() bool {
114
139
case '\n' , ';' :
115
140
continue
116
141
case scanner .EOF :
117
- return false
142
+ return "" , "" , nil , false
118
143
}
119
144
break
120
145
}
121
146
// First item must be an identifier.
122
147
if tok != scanner .Ident {
123
148
p .errorf ("expected identifier, found %q" , p .lex .Text ())
124
- return false // Might as well stop now.
149
+ return "" , "" , nil , false // Might as well stop now.
125
150
}
126
- word := p .lex .Text ()
127
- var cond string
128
- operands := make ([][]lex.Token , 0 , 3 )
151
+ word , cond = p .lex .Text (), ""
152
+ operands = scratch [:0 ]
129
153
// Zero or more comma-separated operands, one per loop.
130
154
nesting := 0
131
155
colon := - 1
132
156
for tok != '\n' && tok != ';' {
133
157
// Process one operand.
134
- items := make ([]lex.Token , 0 , 3 )
158
+ var items []lex.Token
159
+ if cap (operands ) > len (operands ) {
160
+ // Reuse scratch items slice.
161
+ items = operands [:cap (operands )][len (operands )][:0 ]
162
+ } else {
163
+ items = make ([]lex.Token , 0 , 3 )
164
+ }
135
165
for {
136
166
tok = p .lex .Next ()
137
167
if len (operands ) == 0 && len (items ) == 0 {
@@ -148,12 +178,12 @@ func (p *Parser) line() bool {
148
178
if tok == ':' {
149
179
// Labels.
150
180
p .pendingLabels = append (p .pendingLabels , word )
151
- return true
181
+ goto next
152
182
}
153
183
}
154
184
if tok == scanner .EOF {
155
185
p .errorf ("unexpected EOF" )
156
- return false
186
+ return "" , "" , nil , false
157
187
}
158
188
// Split operands on comma. Also, the old syntax on x86 for a "register pair"
159
189
// was AX:DX, for which the new syntax is DX, AX. Note the reordering.
@@ -162,7 +192,7 @@ func (p *Parser) line() bool {
162
192
// Remember this location so we can swap the operands below.
163
193
if colon >= 0 {
164
194
p .errorf ("invalid ':' in operand" )
165
- return true
195
+ return word , cond , operands , true
166
196
}
167
197
colon = len (operands )
168
198
}
@@ -188,16 +218,7 @@ func (p *Parser) line() bool {
188
218
p .errorf ("missing operand" )
189
219
}
190
220
}
191
- if p .pseudo (word , operands ) {
192
- return true
193
- }
194
- i , present := p .arch .Instructions [word ]
195
- if present {
196
- p .instruction (i , word , cond , operands )
197
- return true
198
- }
199
- p .errorf ("unrecognized instruction %q" , word )
200
- return true
221
+ return word , cond , operands , true
201
222
}
202
223
203
224
func (p * Parser ) instruction (op obj.As , word , cond string , operands [][]lex.Token ) {
0 commit comments