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:
parent
fd1253fc4f
commit
47de551af3
@ -50,11 +50,7 @@ func (a *Assembler) Load(filename string) error {
|
||||
// we're in an inactive ifdef branch
|
||||
continue
|
||||
}
|
||||
if in.Label != "" && in.Label[0] != '.' {
|
||||
a.Flavor.SetLastLabel(in.Label)
|
||||
}
|
||||
in.FixLabels(a.Flavor.GetLastLabel())
|
||||
if err != nil {
|
||||
if err := in.FixLabels(a.Flavor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -72,11 +68,12 @@ func (a *Assembler) Load(filename string) error {
|
||||
continue // no need to append
|
||||
return in.Errorf("macro start not (yet) implemented: %s", line)
|
||||
case inst.TypeMacroCall:
|
||||
macroCall++
|
||||
m, ok := a.Macros[in.Command]
|
||||
if !ok {
|
||||
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 {
|
||||
return in.Errorf(`error calling macro "%s": %v`, m.Name, err)
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ type Context interface {
|
||||
Zero() (uint16, error) // type ZeroFunc
|
||||
RemoveChanged()
|
||||
AddrKnown() bool
|
||||
GetLastLabel() string
|
||||
SetLastLabel(string)
|
||||
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() {
|
||||
sc.symbols = make(map[string]symbolValue)
|
||||
}
|
||||
|
20
asm/context/labels.go
Normal file
20
asm/context/labels.go
Normal 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
|
||||
}
|
@ -194,22 +194,21 @@ func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val uint16, labelM
|
||||
return val, false, err
|
||||
}
|
||||
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1
|
||||
func (e *E) FixLabels(last string, ln *lines.Line) error {
|
||||
if e.Text != "" && e.Text[0] == '.' {
|
||||
if last == "" {
|
||||
return ln.Errorf("reference to sub-label '%s' before full label.", e.Text)
|
||||
}
|
||||
e.Text = last + "/" + e.Text
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
|
||||
func (e *E) FixLabels(labeler context.Labeler, macroCall int, ln *lines.Line) error {
|
||||
newL, err := labeler.FixLabel(e.Text, macroCall)
|
||||
if err != nil {
|
||||
return ln.Errorf("%v", err)
|
||||
}
|
||||
e.Text = newL
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
if e.Right != nil {
|
||||
return e.Right.FixLabels(last, ln)
|
||||
return e.Right.FixLabels(labeler, macroCall, ln)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
type AS65 struct {
|
||||
context.SimpleContext
|
||||
context.LabelerBase
|
||||
}
|
||||
|
||||
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) {
|
||||
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.")
|
||||
}
|
||||
|
@ -12,4 +12,5 @@ type F interface {
|
||||
SetWidthsOnFirstPass() bool
|
||||
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
|
||||
context.Context
|
||||
context.Labeler
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
type Merlin struct {
|
||||
context.SimpleContext
|
||||
context.LabelerBase
|
||||
}
|
||||
|
||||
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) {
|
||||
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.")
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ type SCMA struct {
|
||||
directives map[string]directiveInfo
|
||||
operators map[string]expr.Operator
|
||||
context.SimpleContext
|
||||
context.LabelerBase
|
||||
}
|
||||
|
||||
func New() *SCMA {
|
||||
@ -570,3 +571,27 @@ func (a *SCMA) ReplaceMacroArgs(line string, args []string, kwargs map[string]st
|
||||
}))
|
||||
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
|
||||
}
|
||||
|
@ -140,14 +140,14 @@ func TestMultiline(t *testing.T) {
|
||||
" .MA INCD MACRO NAME",
|
||||
" INC ]1 CALL PARAMETER",
|
||||
" BNE :1 PRIVATE LABEL",
|
||||
" INC ]1+l",
|
||||
" INC ]1+1",
|
||||
":1",
|
||||
" .EM END OF DEFINITION",
|
||||
" >INCD PTR",
|
||||
"PTR .HS 0000",
|
||||
"ZPTR .EQ $42",
|
||||
" >INCD ZPTR",
|
||||
}, nil, "", true},
|
||||
}, nil, "ee0808d003ee09080000e642d002e643", true},
|
||||
|
||||
// Macro, conditional assembly
|
||||
{ss, "Macro, conditional assembly", []string{
|
||||
|
@ -181,17 +181,21 @@ func (i *I) Compute(c context.Context, setWidth bool, final bool) (bool, error)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1
|
||||
func (i *I) FixLabels(last string) error {
|
||||
if i.Label != "" && i.Label[0] == '.' {
|
||||
if last == "" {
|
||||
return i.Errorf("Reference to sub-label '%s' before full label.", i.Label)
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
|
||||
func (i *I) FixLabels(labeler context.Labeler) error {
|
||||
macroCall := i.Line.GetMacroCall()
|
||||
parent := labeler.IsNewParentLabel(i.Label)
|
||||
newL, err := labeler.FixLabel(i.Label, macroCall)
|
||||
if err != nil {
|
||||
return i.Errorf("%v", err)
|
||||
}
|
||||
i.Label = last + "/" + i.Label
|
||||
i.Label = newL
|
||||
if parent {
|
||||
labeler.SetLastLabel(i.Label)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -35,14 +35,21 @@ func NewSimple(s string) Line {
|
||||
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 {
|
||||
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 c.Parent.Context.GetMacroCall()
|
||||
return l.Context.GetMacroCall()
|
||||
}
|
||||
|
||||
func (l Line) Text() string {
|
||||
|
@ -12,9 +12,9 @@ type M struct {
|
||||
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
|
||||
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 {
|
||||
// TODO(zellyn): implement named macro args
|
||||
subbed, err := flavor.ReplaceMacroArgs(line, in.MacroArgs, nil)
|
||||
|
Loading…
Reference in New Issue
Block a user