1
0
mirror of https://github.com/zellyn/go6502.git synced 2025-01-01 06:32:50 +00:00

scma: first pass of macros complete

This commit is contained in:
Zellyn Hunter 2014-05-08 16:44:08 -07:00
parent fd1253fc4f
commit 47de551af3
12 changed files with 101 additions and 40 deletions

View File

@ -50,11 +50,7 @@ func (a *Assembler) Load(filename string) error {
// we're in an inactive ifdef branch // we're in an inactive ifdef branch
continue continue
} }
if in.Label != "" && in.Label[0] != '.' { if err := in.FixLabels(a.Flavor); err != nil {
a.Flavor.SetLastLabel(in.Label)
}
in.FixLabels(a.Flavor.GetLastLabel())
if err != nil {
return err return err
} }
@ -72,11 +68,12 @@ func (a *Assembler) Load(filename string) error {
continue // no need to append continue // no need to append
return in.Errorf("macro start not (yet) implemented: %s", line) return in.Errorf("macro start not (yet) implemented: %s", line)
case inst.TypeMacroCall: case inst.TypeMacroCall:
macroCall++
m, ok := a.Macros[in.Command] m, ok := a.Macros[in.Command]
if !ok { if !ok {
return in.Errorf(`unknown macro: "%s"`, in.Command) return in.Errorf(`unknown macro: "%s"`, in.Command)
} }
subLs, err := m.LineSource(a.Flavor, in) subLs, err := m.LineSource(a.Flavor, in, macroCall)
if err != nil { if err != nil {
return in.Errorf(`error calling macro "%s": %v`, m.Name, err) return in.Errorf(`error calling macro "%s": %v`, m.Name, err)
} }

View File

@ -12,8 +12,6 @@ type Context interface {
Zero() (uint16, error) // type ZeroFunc Zero() (uint16, error) // type ZeroFunc
RemoveChanged() RemoveChanged()
AddrKnown() bool AddrKnown() bool
GetLastLabel() string
SetLastLabel(string)
Clear() Clear()
} }
@ -91,14 +89,6 @@ func (sc *SimpleContext) RemoveChanged() {
} }
} }
func (sc *SimpleContext) GetLastLabel() string {
return sc.lastLabel
}
func (sc *SimpleContext) SetLastLabel(l string) {
sc.lastLabel = l
}
func (sc *SimpleContext) Clear() { func (sc *SimpleContext) Clear() {
sc.symbols = make(map[string]symbolValue) sc.symbols = make(map[string]symbolValue)
} }

20
asm/context/labels.go Normal file
View File

@ -0,0 +1,20 @@
package context
type Labeler interface {
LastLabel() string
SetLastLabel(label string)
FixLabel(label string, macroCall int) (string, error)
IsNewParentLabel(label string) bool
}
type LabelerBase struct {
lastLabel string
}
func (lb *LabelerBase) LastLabel() string {
return lb.lastLabel
}
func (lb *LabelerBase) SetLastLabel(l string) {
lb.lastLabel = l
}

View File

@ -194,22 +194,21 @@ func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val uint16, labelM
return val, false, err return val, false, err
} }
// FixLabels attempts to turn .1 into LAST_LABEL.1 // FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
func (e *E) FixLabels(last string, ln *lines.Line) error { func (e *E) FixLabels(labeler context.Labeler, macroCall int, ln *lines.Line) error {
if e.Text != "" && e.Text[0] == '.' { newL, err := labeler.FixLabel(e.Text, macroCall)
if last == "" { if err != nil {
return ln.Errorf("reference to sub-label '%s' before full label.", e.Text) return ln.Errorf("%v", err)
}
e.Text = last + "/" + e.Text
} }
e.Text = newL
if e.Left != nil { if e.Left != nil {
if err := e.Left.FixLabels(last, ln); err != nil { if err := e.Left.FixLabels(labeler, macroCall, ln); err != nil {
return err return err
} }
} }
if e.Right != nil { if e.Right != nil {
return e.Right.FixLabels(last, ln) return e.Right.FixLabels(labeler, macroCall, ln)
} }
return nil return nil

View File

@ -13,6 +13,7 @@ import (
type AS65 struct { type AS65 struct {
context.SimpleContext context.SimpleContext
context.LabelerBase
} }
func New() *AS65 { func New() *AS65 {
@ -39,3 +40,11 @@ func (a *AS65) SetWidthsOnFirstPass() bool {
func (a *AS65) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) { func (a *AS65) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
panic("AS65.ReplaceMacroArgs not implemented yet.") panic("AS65.ReplaceMacroArgs not implemented yet.")
} }
func (a *AS65) IsNewParentLabel(label string) bool {
return label != "" && label[0] != '.'
}
func (a *AS65) FixLabel(label string, macroCall int) (string, error) {
panic("AS65.FixLabel not implemented yet.")
}

View File

@ -12,4 +12,5 @@ type F interface {
SetWidthsOnFirstPass() bool SetWidthsOnFirstPass() bool
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
context.Context context.Context
context.Labeler
} }

View File

@ -14,6 +14,7 @@ import (
type Merlin struct { type Merlin struct {
context.SimpleContext context.SimpleContext
context.LabelerBase
} }
func New() *Merlin { func New() *Merlin {
@ -40,3 +41,11 @@ func (a *Merlin) SetWidthsOnFirstPass() bool {
func (a *Merlin) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) { func (a *Merlin) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
panic("Merlin.ReplaceMacroArgs not implemented yet.") panic("Merlin.ReplaceMacroArgs not implemented yet.")
} }
func (a *Merlin) IsNewParentLabel(label string) bool {
return label != "" && label[0] != '.'
}
func (a *Merlin) FixLabel(label string, macroCount int) (string, error) {
panic("Merlin.FixLabel not implemented yet.")
}

View File

@ -39,6 +39,7 @@ type SCMA struct {
directives map[string]directiveInfo directives map[string]directiveInfo
operators map[string]expr.Operator operators map[string]expr.Operator
context.SimpleContext context.SimpleContext
context.LabelerBase
} }
func New() *SCMA { func New() *SCMA {
@ -570,3 +571,27 @@ func (a *SCMA) ReplaceMacroArgs(line string, args []string, kwargs map[string]st
})) }))
return line, nil return line, nil
} }
func (a *SCMA) IsNewParentLabel(label string) bool {
return label != "" && label[0] != '.'
}
func (a *SCMA) FixLabel(label string, macroCall int) (string, error) {
switch {
case label == "":
return label, nil
case label[0] == '.':
if last := a.LastLabel(); last == "" {
return "", fmt.Errorf("sublabel '%s' without previous label", label)
} else {
return fmt.Sprintf("%s/%s", last, label), nil
}
case label[0] == ':':
if macroCall == 0 {
return "", fmt.Errorf("macro-local label '%s' seen outside macro", label)
} else {
return fmt.Sprintf("%s/%d", label, macroCall), nil
}
}
return label, nil
}

View File

@ -140,14 +140,14 @@ func TestMultiline(t *testing.T) {
" .MA INCD MACRO NAME", " .MA INCD MACRO NAME",
" INC ]1 CALL PARAMETER", " INC ]1 CALL PARAMETER",
" BNE :1 PRIVATE LABEL", " BNE :1 PRIVATE LABEL",
" INC ]1+l", " INC ]1+1",
":1", ":1",
" .EM END OF DEFINITION", " .EM END OF DEFINITION",
" >INCD PTR", " >INCD PTR",
"PTR .HS 0000", "PTR .HS 0000",
"ZPTR .EQ $42", "ZPTR .EQ $42",
" >INCD ZPTR", " >INCD ZPTR",
}, nil, "", true}, }, nil, "ee0808d003ee09080000e642d002e643", true},
// Macro, conditional assembly // Macro, conditional assembly
{ss, "Macro, conditional assembly", []string{ {ss, "Macro, conditional assembly", []string{

View File

@ -181,17 +181,21 @@ func (i *I) Compute(c context.Context, setWidth bool, final bool) (bool, error)
return true, nil return true, nil
} }
// FixLabels attempts to turn .1 into LAST_LABEL.1 // FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
func (i *I) FixLabels(last string) error { func (i *I) FixLabels(labeler context.Labeler) error {
if i.Label != "" && i.Label[0] == '.' { macroCall := i.Line.GetMacroCall()
if last == "" { parent := labeler.IsNewParentLabel(i.Label)
return i.Errorf("Reference to sub-label '%s' before full label.", i.Label) newL, err := labeler.FixLabel(i.Label, macroCall)
} if err != nil {
i.Label = last + "/" + i.Label return i.Errorf("%v", err)
}
i.Label = newL
if parent {
labeler.SetLastLabel(i.Label)
} }
for _, e := range i.Exprs { for _, e := range i.Exprs {
if err := e.FixLabels(last, i.Line); err != nil { if err := e.FixLabels(labeler, macroCall, i.Line); err != nil {
return err return err
} }
} }

View File

@ -35,14 +35,21 @@ func NewSimple(s string) Line {
return NewLine(s, 0, &Context{Filename: testFilename}) return NewLine(s, 0, &Context{Filename: testFilename})
} }
func (c Context) GetMacroCall() int { func (c *Context) GetMacroCall() int {
if c == nil {
return 0
}
if c.MacroCall > 0 { if c.MacroCall > 0 {
return c.MacroCall return c.MacroCall
} }
if c.Parent == nil || c.Parent.Context == nil { return c.Parent.GetMacroCall()
}
func (l *Line) GetMacroCall() int {
if l == nil {
return 0 return 0
} }
return c.Parent.Context.GetMacroCall() return l.Context.GetMacroCall()
} }
func (l Line) Text() string { func (l Line) Text() string {

View File

@ -12,9 +12,9 @@ type M struct {
Lines []string Lines []string
} }
func (m M) LineSource(flavor flavors.F, in inst.I) (lines.LineSource, error) { func (m M) LineSource(flavor flavors.F, in inst.I, macroCall int) (lines.LineSource, error) {
var ls []string var ls []string
context := lines.Context{Filename: "macro:" + m.Name, Parent: in.Line} context := lines.Context{Filename: "macro:" + m.Name, Parent: in.Line, MacroCall: macroCall}
for _, line := range m.Lines { for _, line := range m.Lines {
// TODO(zellyn): implement named macro args // TODO(zellyn): implement named macro args
subbed, err := flavor.ReplaceMacroArgs(line, in.MacroArgs, nil) subbed, err := flavor.ReplaceMacroArgs(line, in.MacroArgs, nil)