mirror of
https://github.com/golang/go
synced 2024-11-23 12:50:12 -07:00
cmd/asm: factor out line parsing from assembling
Currently cmd/asm's Parser.line both consumes a line of assembly from the lexer and assembles it. This CL separates these two steps so that the line parser can be reused for purposes other than generating a Prog stream. For #27539. Updates #17544. Change-Id: I452c9a2112fbcc1c94bf909efc0d1fcc71014812 Reviewed-on: https://go-review.googlesource.com/c/147097 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
30cc978085
commit
52b2220559
@ -38,8 +38,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
|
|||||||
parser := NewParser(ctxt, arch, tokenizer)
|
parser := NewParser(ctxt, arch, tokenizer)
|
||||||
|
|
||||||
err := tryParse(t, func() {
|
err := tryParse(t, func() {
|
||||||
parser.start(lex.Tokenize(test.input))
|
parser.Parse()
|
||||||
parser.line()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -91,7 +91,23 @@ func (p *Parser) pos() src.XPos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) Parse() (*obj.Prog, bool) {
|
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 {
|
if p.errorCount > 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
@ -100,8 +116,17 @@ func (p *Parser) Parse() (*obj.Prog, bool) {
|
|||||||
return p.firstProg, true
|
return p.firstProg, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// WORD [ arg {, arg} ] (';' | '\n')
|
// line consumes a single assembly line from p.lex of the form
|
||||||
func (p *Parser) line() bool {
|
//
|
||||||
|
// {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.
|
// Skip newlines.
|
||||||
var tok lex.ScanToken
|
var tok lex.ScanToken
|
||||||
for {
|
for {
|
||||||
@ -114,24 +139,29 @@ func (p *Parser) line() bool {
|
|||||||
case '\n', ';':
|
case '\n', ';':
|
||||||
continue
|
continue
|
||||||
case scanner.EOF:
|
case scanner.EOF:
|
||||||
return false
|
return "", "", nil, false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// First item must be an identifier.
|
// First item must be an identifier.
|
||||||
if tok != scanner.Ident {
|
if tok != scanner.Ident {
|
||||||
p.errorf("expected identifier, found %q", p.lex.Text())
|
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()
|
word, cond = p.lex.Text(), ""
|
||||||
var cond string
|
operands = scratch[:0]
|
||||||
operands := make([][]lex.Token, 0, 3)
|
|
||||||
// Zero or more comma-separated operands, one per loop.
|
// Zero or more comma-separated operands, one per loop.
|
||||||
nesting := 0
|
nesting := 0
|
||||||
colon := -1
|
colon := -1
|
||||||
for tok != '\n' && tok != ';' {
|
for tok != '\n' && tok != ';' {
|
||||||
// Process one operand.
|
// 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 {
|
for {
|
||||||
tok = p.lex.Next()
|
tok = p.lex.Next()
|
||||||
if len(operands) == 0 && len(items) == 0 {
|
if len(operands) == 0 && len(items) == 0 {
|
||||||
@ -148,12 +178,12 @@ func (p *Parser) line() bool {
|
|||||||
if tok == ':' {
|
if tok == ':' {
|
||||||
// Labels.
|
// Labels.
|
||||||
p.pendingLabels = append(p.pendingLabels, word)
|
p.pendingLabels = append(p.pendingLabels, word)
|
||||||
return true
|
goto next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tok == scanner.EOF {
|
if tok == scanner.EOF {
|
||||||
p.errorf("unexpected EOF")
|
p.errorf("unexpected EOF")
|
||||||
return false
|
return "", "", nil, false
|
||||||
}
|
}
|
||||||
// Split operands on comma. Also, the old syntax on x86 for a "register pair"
|
// 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.
|
// was AX:DX, for which the new syntax is DX, AX. Note the reordering.
|
||||||
@ -162,7 +192,7 @@ func (p *Parser) line() bool {
|
|||||||
// Remember this location so we can swap the operands below.
|
// Remember this location so we can swap the operands below.
|
||||||
if colon >= 0 {
|
if colon >= 0 {
|
||||||
p.errorf("invalid ':' in operand")
|
p.errorf("invalid ':' in operand")
|
||||||
return true
|
return word, cond, operands, true
|
||||||
}
|
}
|
||||||
colon = len(operands)
|
colon = len(operands)
|
||||||
}
|
}
|
||||||
@ -188,16 +218,7 @@ func (p *Parser) line() bool {
|
|||||||
p.errorf("missing operand")
|
p.errorf("missing operand")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.pseudo(word, operands) {
|
return word, cond, operands, true
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) instruction(op obj.As, word, cond string, operands [][]lex.Token) {
|
func (p *Parser) instruction(op obj.As, word, cond string, operands [][]lex.Token) {
|
||||||
|
Loading…
Reference in New Issue
Block a user