1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-06-25 12:29:33 +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
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)
}

View File

@ -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
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
}
// 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

View File

@ -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.")
}

View File

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

View File

@ -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.")
}

View File

@ -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
}

View File

@ -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{

View File

@ -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)
}
i.Label = last + "/" + 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 = 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
}
}

View File

@ -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 {

View File

@ -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)