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
|
// 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)
|
||||||
}
|
}
|
||||||
|
@ -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
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
|
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
|
||||||
|
@ -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.")
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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.")
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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{
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user