}
func (p *Parser) Parse() (*obj.Prog, bool) {
- for p.line() {
+ scratch := make([][]lex.Token, 0, 3)
+ for {
+ word, cond, operands, ok := p.line(scratch)
+ if !ok {
+ break
+ }
+ scratch = operands
+
+ if p.pseudo(word, operands) {
+ continue
+ }
+ i, present := p.arch.Instructions[word]
+ if present {
+ p.instruction(i, word, cond, operands)
+ continue
+ }
+ p.errorf("unrecognized instruction %q", word)
}
if p.errorCount > 0 {
return nil, false
return p.firstProg, true
}
-// WORD [ arg {, arg} ] (';' | '\n')
-func (p *Parser) line() bool {
+// line consumes a single assembly line from p.lex of the form
+//
+// {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
+//
+// It adds any labels to p.pendingLabels and returns the word, cond,
+// operand list, and true. If there is an error or EOF, it returns
+// ok=false.
+//
+// line may reuse the memory from scratch.
+func (p *Parser) line(scratch [][]lex.Token) (word, cond string, operands [][]lex.Token, ok bool) {
+next:
// Skip newlines.
var tok lex.ScanToken
for {
case '\n', ';':
continue
case scanner.EOF:
- return false
+ return "", "", nil, false
}
break
}
// First item must be an identifier.
if tok != scanner.Ident {
p.errorf("expected identifier, found %q", p.lex.Text())
- return false // Might as well stop now.
+ return "", "", nil, false // Might as well stop now.
}
- word := p.lex.Text()
- var cond string
- operands := make([][]lex.Token, 0, 3)
+ word, cond = p.lex.Text(), ""
+ operands = scratch[:0]
// Zero or more comma-separated operands, one per loop.
nesting := 0
colon := -1
for tok != '\n' && tok != ';' {
// Process one operand.
- items := make([]lex.Token, 0, 3)
+ var items []lex.Token
+ if cap(operands) > len(operands) {
+ // Reuse scratch items slice.
+ items = operands[:cap(operands)][len(operands)][:0]
+ } else {
+ items = make([]lex.Token, 0, 3)
+ }
for {
tok = p.lex.Next()
if len(operands) == 0 && len(items) == 0 {
if tok == ':' {
// Labels.
p.pendingLabels = append(p.pendingLabels, word)
- return true
+ goto next
}
}
if tok == scanner.EOF {
p.errorf("unexpected EOF")
- return false
+ return "", "", nil, false
}
// Split operands on comma. Also, the old syntax on x86 for a "register pair"
// was AX:DX, for which the new syntax is DX, AX. Note the reordering.
// Remember this location so we can swap the operands below.
if colon >= 0 {
p.errorf("invalid ':' in operand")
- return true
+ return word, cond, operands, true
}
colon = len(operands)
}
p.errorf("missing operand")
}
}
- if p.pseudo(word, operands) {
- return true
- }
- i, present := p.arch.Instructions[word]
- if present {
- p.instruction(i, word, cond, operands)
- return true
- }
- p.errorf("unrecognized instruction %q", word)
- return true
+ return word, cond, operands, true
}
func (p *Parser) instruction(op obj.As, word, cond string, operands [][]lex.Token) {