mirror of
https://github.com/zellyn/go6502.git
synced 2025-02-07 02:30:38 +00:00
Implemented macro-local labels for Merlin
This commit is contained in:
parent
6a51d73b66
commit
8f04a118ab
@ -154,6 +154,9 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
Name: in.TextArg,
|
||||
Args: in.MacroArgs,
|
||||
}
|
||||
if a.Flavor.LocalMacroLabels() {
|
||||
m.Locals = make(map[string]bool)
|
||||
}
|
||||
for {
|
||||
line, done, err := ls.Next()
|
||||
if err != nil {
|
||||
@ -163,6 +166,9 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
return in.Errorf("end of file while reading macro %s", m.Name)
|
||||
}
|
||||
in2, err := a.Flavor.ParseInstr(line)
|
||||
if a.Flavor.LocalMacroLabels() && in2.Label != "" {
|
||||
m.Locals[in2.Label] = true
|
||||
}
|
||||
if err == nil && in2.Type == inst.TypeMacroEnd {
|
||||
a.Macros[m.Name] = m
|
||||
a.Flavor.AddMacroName(m.Name)
|
||||
|
@ -1,9 +1,10 @@
|
||||
package context
|
||||
|
||||
/* Labeler is an interface that the flavors implement to handle label correction. */
|
||||
type Labeler interface {
|
||||
LastLabel() string
|
||||
SetLastLabel(label string)
|
||||
FixLabel(label string, macroCall int) (string, error)
|
||||
FixLabel(label string, macroCall int, locals map[string]bool) (string, error)
|
||||
IsNewParentLabel(label string) bool
|
||||
}
|
||||
|
||||
|
@ -207,20 +207,20 @@ func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val uint16, labelM
|
||||
}
|
||||
|
||||
// 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)
|
||||
func (e *E) FixLabels(labeler context.Labeler, macroCall int, locals map[string]bool, ln *lines.Line) error {
|
||||
newL, err := labeler.FixLabel(e.Text, macroCall, locals)
|
||||
if err != nil {
|
||||
return ln.Errorf("%v", err)
|
||||
}
|
||||
e.Text = newL
|
||||
|
||||
if e.Left != nil {
|
||||
if err := e.Left.FixLabels(labeler, macroCall, ln); err != nil {
|
||||
if err := e.Left.FixLabels(labeler, macroCall, locals, ln); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if e.Right != nil {
|
||||
return e.Right.FixLabels(labeler, macroCall, ln)
|
||||
return e.Right.FixLabels(labeler, macroCall, locals, ln)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -45,6 +45,10 @@ func (a *AS65) IsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != '.'
|
||||
}
|
||||
|
||||
func (a *AS65) FixLabel(label string, macroCall int) (string, error) {
|
||||
func (a *AS65) FixLabel(label string, macroCall int, locals map[string]bool) (string, error) {
|
||||
panic("AS65.FixLabel not implemented yet.")
|
||||
}
|
||||
|
||||
func (a *AS65) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
// DecodeOp contains the common code that decodes an Opcode, once we
|
||||
// have fully parsed it.
|
||||
func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect bool, xy rune, forceWide bool) (inst.I, error) {
|
||||
i := inst.I{}
|
||||
ex := in.Exprs[0]
|
||||
|
||||
// At this point we've parsed the Opcode. Let's see if it makes sense.
|
||||
@ -20,10 +19,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
case 'x':
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_X)
|
||||
if !ok {
|
||||
return i, in.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
|
||||
return in, in.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
|
||||
}
|
||||
if forceWide {
|
||||
return i, in.Errorf("%s (addr,X) doesn't have a wide variant", in.Command)
|
||||
return in, in.Errorf("%s (addr,X) doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.Op = op.Byte
|
||||
in.WidthKnown = true
|
||||
@ -34,10 +33,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
case 'y':
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_Y)
|
||||
if !ok {
|
||||
return i, in.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
|
||||
return in, in.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s (addr),Y doesn't have a wide variant", in.Command)
|
||||
return in, fmt.Errorf("%s (addr),Y doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.WidthKnown = true
|
||||
in.MinWidth = 2
|
||||
@ -48,7 +47,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
default:
|
||||
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT)
|
||||
if !ok {
|
||||
return i, in.Errorf("%s doesn't support indirect (addr) mode", in.Command)
|
||||
return in, in.Errorf("%s doesn't support indirect (addr) mode", in.Command)
|
||||
}
|
||||
in.Op = op.Byte
|
||||
in.WidthKnown = true
|
||||
@ -66,7 +65,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
panic(fmt.Sprintf("opcode error: %s has no MODE_RELATIVE opcode", in.Command))
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
return in, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
}
|
||||
|
||||
in.Op = op.Byte
|
||||
@ -109,7 +108,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
opZp, zpOk := summary.OpForMode(zp)
|
||||
|
||||
if !summary.AnyModes(zp | wide) {
|
||||
return i, in.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
|
||||
return in, in.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
|
||||
}
|
||||
|
||||
if !summary.AnyModes(zp) {
|
||||
@ -128,7 +127,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS))
|
||||
}
|
||||
if forceWide {
|
||||
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
return in, fmt.Errorf("%s doesn't have a wide variant", in.Command)
|
||||
}
|
||||
in.Op = opZp.Byte
|
||||
in.WidthKnown = true
|
||||
|
@ -11,6 +11,7 @@ type F interface {
|
||||
DefaultOrigin() (uint16, error)
|
||||
SetWidthsOnFirstPass() bool
|
||||
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
|
||||
LocalMacroLabels() bool
|
||||
context.Context
|
||||
context.Labeler
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func New() *Merlin {
|
||||
for {
|
||||
s, err := m.ParseMacroArg(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, true, err
|
||||
return in, true, err
|
||||
}
|
||||
in.MacroArgs = append(in.MacroArgs, s)
|
||||
if !lp.Consume(";") {
|
||||
@ -177,7 +177,7 @@ func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
filename = strings.TrimSpace(filename[1:])
|
||||
}
|
||||
if filename == "" {
|
||||
return inst.I{}, in.Errorf("%s expects filename", in.Command)
|
||||
return in, in.Errorf("%s expects filename", in.Command)
|
||||
}
|
||||
in.TextArg = prefix + filename
|
||||
in.WidthKnown = true
|
||||
@ -187,15 +187,11 @@ func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (m *Merlin) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
|
||||
panic("Merlin.ReplaceMacroArgs not implemented yet.")
|
||||
}
|
||||
|
||||
func (m *Merlin) IsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != ':'
|
||||
}
|
||||
|
||||
func (m *Merlin) FixLabel(label string, macroCount int) (string, error) {
|
||||
func (m *Merlin) FixLabel(label string, macroCount int, locals map[string]bool) (string, error) {
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
@ -205,6 +201,13 @@ func (m *Merlin) FixLabel(label string, macroCount int) (string, error) {
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
}
|
||||
case locals[label]:
|
||||
return fmt.Sprintf("%s{%d}", label, macroCount), nil
|
||||
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (m *Merlin) LocalMacroLabels() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -74,14 +74,14 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
if lp.AcceptRun(Digits) {
|
||||
s := lp.Emit()
|
||||
if len(s) != 4 {
|
||||
return inst.I{}, line.Errorf("line number must be exactly 4 digits: %s", s)
|
||||
return in, line.Errorf("line number must be exactly 4 digits: %s", s)
|
||||
}
|
||||
if !lp.Consume(" ") && lp.Peek() != lines.Eol {
|
||||
return inst.I{}, line.Errorf("line number (%s) followed by non-space", s)
|
||||
return in, line.Errorf("line number (%s) followed by non-space", s)
|
||||
}
|
||||
i, err := strconv.ParseUint(s, 10, 16)
|
||||
if err != nil {
|
||||
return inst.I{}, line.Errorf("invalid line number: %s: %s", s, err)
|
||||
return in, line.Errorf("invalid line number: %s: %s", s, err)
|
||||
}
|
||||
in.DeclaredLine = uint16(i)
|
||||
}
|
||||
@ -107,7 +107,7 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
switch a.LabelColons {
|
||||
case ReqRequired:
|
||||
if !lp.Consume(":") {
|
||||
return inst.I{}, line.Errorf("label '%s' must end in colon", in.Label)
|
||||
return in, line.Errorf("label '%s' must end in colon", in.Label)
|
||||
}
|
||||
case ReqOptional:
|
||||
lp.Consume(":")
|
||||
@ -137,7 +137,7 @@ func (a *Base) SetWidthsOnFirstPass() bool {
|
||||
func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
if !lp.AcceptRun(cmdChars) && !(a.Directives["="].Func != nil && lp.Accept("=")) {
|
||||
c := lp.Next()
|
||||
return inst.I{}, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
||||
return in, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
||||
}
|
||||
in.Command = lp.Emit()
|
||||
|
||||
@ -145,7 +145,7 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
if a.ParseMacroCall != nil {
|
||||
i, isMacro, err := a.ParseMacroCall(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
if isMacro {
|
||||
return i, nil
|
||||
@ -180,7 +180,7 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return inst.I{}, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
|
||||
return in, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
|
||||
}
|
||||
|
||||
func (a *Base) ParseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
@ -188,7 +188,7 @@ func (a *Base) ParseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(Letters) {
|
||||
c := lp.Next()
|
||||
return inst.I{}, in.Errorf("expecting ON/OFF, found '%s'", c)
|
||||
return in, in.Errorf("expecting ON/OFF, found '%s'", c)
|
||||
}
|
||||
in.TextArg = lp.Emit()
|
||||
switch in.TextArg {
|
||||
@ -197,7 +197,7 @@ func (a *Base) ParseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
case "OFF":
|
||||
a.SettingOff(in.Command)
|
||||
default:
|
||||
return inst.I{}, in.Errorf("expecting ON/OFF, found '%s'", in.TextArg)
|
||||
return in, in.Errorf("expecting ON/OFF, found '%s'", in.TextArg)
|
||||
}
|
||||
return in, nil
|
||||
|
||||
@ -243,8 +243,6 @@ func (a *Base) ParseQuoted(in inst.I, lp *lines.Parse) (string, error) {
|
||||
// ParseOpArgs parses the arguments to an assembly op. We expect to be
|
||||
// looking at the first non-op character (probably whitespace)
|
||||
func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary, forceWide bool) (inst.I, error) {
|
||||
i := inst.I{}
|
||||
|
||||
// MODE_IMPLIED: we don't really care what comes next: it's a comment.
|
||||
if summary.Modes == opcodes.MODE_IMPLIED {
|
||||
op := summary.Ops[0]
|
||||
@ -271,7 +269,7 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
if atEnd {
|
||||
// Nothing left on line except comments.
|
||||
if !summary.AnyModes(opcodes.MODE_A) {
|
||||
return i, in.Errorf("%s with no arguments", in.Command)
|
||||
return in, in.Errorf("%s with no arguments", in.Command)
|
||||
}
|
||||
op, ok := summary.OpForMode(opcodes.MODE_A)
|
||||
if !ok {
|
||||
@ -288,20 +286,20 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
|
||||
indirect := lp.Consume("(")
|
||||
if indirect && !summary.AnyModes(opcodes.MODE_INDIRECT_ANY) {
|
||||
return i, in.Errorf("%s doesn't support any indirect modes", in.Command)
|
||||
return in, in.Errorf("%s doesn't support any indirect modes", in.Command)
|
||||
}
|
||||
xy := '-'
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return i, err
|
||||
return in, err
|
||||
}
|
||||
if !indirect && (expr.Text == "a" || expr.Text == "A") {
|
||||
if !summary.AnyModes(opcodes.MODE_A) {
|
||||
return i, in.Errorf("%s doesn't support A mode", in.Command)
|
||||
return in, in.Errorf("%s doesn't support A mode", in.Command)
|
||||
}
|
||||
switch a.ExplicitARegister {
|
||||
case ReqDisallowed:
|
||||
return i, in.Errorf("Assembler flavor doesn't support A mode", in.Command)
|
||||
return in, in.Errorf("Assembler flavor doesn't support A mode", in.Command)
|
||||
case ReqOptional, ReqRequired:
|
||||
op, ok := summary.OpForMode(opcodes.MODE_A)
|
||||
if !ok {
|
||||
@ -325,25 +323,25 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
xy = 'x'
|
||||
} else if lp.Consume("yY") {
|
||||
if indirect {
|
||||
return i, in.Errorf(",Y unexpected inside parens")
|
||||
return in, in.Errorf(",Y unexpected inside parens")
|
||||
}
|
||||
xy = 'y'
|
||||
} else {
|
||||
return i, in.Errorf("X or Y expected after comma")
|
||||
return in, in.Errorf("X or Y expected after comma")
|
||||
}
|
||||
}
|
||||
comma2 := false
|
||||
if indirect {
|
||||
if !lp.Consume(")") {
|
||||
return i, in.Errorf("Expected closing paren")
|
||||
return in, in.Errorf("Expected closing paren")
|
||||
}
|
||||
comma2 = lp.Consume(",")
|
||||
if comma2 {
|
||||
if comma {
|
||||
return i, in.Errorf("Cannot have ,X or ,Y twice.")
|
||||
return in, in.Errorf("Cannot have ,X or ,Y twice.")
|
||||
}
|
||||
if !lp.Consume("yY") {
|
||||
return i, in.Errorf("Only ,Y can follow parens.")
|
||||
return in, in.Errorf("Only ,Y can follow parens.")
|
||||
}
|
||||
xy = 'y'
|
||||
}
|
||||
@ -356,7 +354,7 @@ func (a *Base) ParseAddress(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
in.WidthKnown = true
|
||||
@ -384,13 +382,13 @@ func (a *Base) ParseAscii(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
delim := lp.Next()
|
||||
if delim == lines.Eol || strings.IndexRune(Whitespace, delim) >= 0 {
|
||||
return inst.I{}, in.Errorf("%s expects delimeter, found '%s'", in.Command, delim)
|
||||
return in, in.Errorf("%s expects delimeter, found '%s'", in.Command, delim)
|
||||
}
|
||||
lp.Ignore()
|
||||
lp.AcceptUntil(string(delim))
|
||||
delim2 := lp.Next()
|
||||
if delim != delim2 && !(delim2 == lines.Eol && a.StringEndOptional) {
|
||||
return inst.I{}, in.Errorf("%s: expected closing delimeter '%s'; got '%s'", in.Command, delim, delim2)
|
||||
return in, in.Errorf("%s: expected closing delimeter '%s'; got '%s'", in.Command, delim, delim2)
|
||||
}
|
||||
lp.Backup()
|
||||
in.Data = []byte(lp.Emit())
|
||||
@ -407,7 +405,7 @@ func (a *Base) ParseBlockStorage(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
ex, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, ex)
|
||||
return in, nil
|
||||
@ -418,7 +416,7 @@ func (a *Base) ParseData(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
for {
|
||||
ex, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, ex)
|
||||
if !lp.Consume(",") {
|
||||
@ -432,7 +430,7 @@ func (a *Base) ParseDo(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
in.WidthKnown = true
|
||||
@ -446,7 +444,7 @@ func (a *Base) ParseEquate(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, err
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
in.WidthKnown = true
|
||||
@ -461,15 +459,15 @@ func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
for {
|
||||
lp.Ignore()
|
||||
if !lp.AcceptRun(hexdigits) {
|
||||
return inst.I{}, in.Errorf("%s expects hex digits; got '%s'", in.Command, lp.Next())
|
||||
return in, in.Errorf("%s expects hex digits; got '%s'", in.Command, lp.Next())
|
||||
}
|
||||
hs := lp.Emit()
|
||||
if len(hs)%2 != 0 {
|
||||
return inst.I{}, in.Errorf("%s expects pairs of hex digits; got %d", in.Command, len(hs))
|
||||
return in, in.Errorf("%s expects pairs of hex digits; got %d", in.Command, len(hs))
|
||||
}
|
||||
data, err := hex.DecodeString(hs)
|
||||
if err != nil {
|
||||
return inst.I{}, in.Errorf("%s: error decoding hex string: %s", in.Command, err)
|
||||
return in, in.Errorf("%s: error decoding hex string: %s", in.Command, err)
|
||||
}
|
||||
in.Data = append(in.Data, data...)
|
||||
|
||||
@ -484,7 +482,7 @@ func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(fileChars) {
|
||||
return inst.I{}, in.Errorf("Expecting filename, found '%c'", lp.Next())
|
||||
return in, in.Errorf("Expecting filename, found '%c'", lp.Next())
|
||||
}
|
||||
in.TextArg = lp.Emit()
|
||||
in.WidthKnown = true
|
||||
@ -498,7 +496,7 @@ func (a *Base) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseMacroStart(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(cmdChars) {
|
||||
return inst.I{}, in.Errorf("Expecting valid macro name, found '%c'", lp.Next())
|
||||
return in, in.Errorf("Expecting valid macro name, found '%c'", lp.Next())
|
||||
}
|
||||
in.TextArg = lp.Emit()
|
||||
in.WidthKnown = true
|
||||
@ -527,7 +525,7 @@ func (a *Base) ParseNoArgDir(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
|
||||
func (a *Base) ParseNotImplemented(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return inst.I{}, in.Errorf("not implemented (yet?): %s", in.Command)
|
||||
return in, in.Errorf("not implemented (yet?): %s", in.Command)
|
||||
}
|
||||
|
||||
func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
@ -679,22 +677,23 @@ func (a *Base) ParseTerm(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
var macroArgRe = regexp.MustCompile("][0-9]+")
|
||||
|
||||
func (a *Base) ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error) {
|
||||
var err error
|
||||
line = strings.Replace(line, "]#", strconv.Itoa(len(args)), -1)
|
||||
line = string(macroArgRe.ReplaceAllFunc([]byte(line), func(in []byte) []byte {
|
||||
n, _ := strconv.Atoi(string(in[1:]))
|
||||
if n > 0 && n <= len(args) {
|
||||
return []byte(args[n-1])
|
||||
}
|
||||
return []byte{}
|
||||
return in
|
||||
}))
|
||||
return line, nil
|
||||
return line, err
|
||||
}
|
||||
|
||||
func (a *Base) IsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != '.'
|
||||
}
|
||||
|
||||
func (a *Base) FixLabel(label string, macroCall int) (string, error) {
|
||||
func (a *Base) FixLabel(label string, macroCall int, locals map[string]bool) (string, error) {
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
|
@ -94,3 +94,7 @@ func newRedbook() *RedBook {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RedBook) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func New() *SCMA {
|
||||
for {
|
||||
s, err := a.ParseMacroArg(in, lp)
|
||||
if err != nil {
|
||||
return inst.I{}, true, err
|
||||
return in, true, err
|
||||
}
|
||||
in.MacroArgs = append(in.MacroArgs, s)
|
||||
if !lp.Consume(",") {
|
||||
@ -117,3 +117,7 @@ func New() *SCMA {
|
||||
func (a *SCMA) Zero() (uint16, error) {
|
||||
return uint16(0xffff), nil
|
||||
}
|
||||
|
||||
func (a *SCMA) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -223,8 +223,9 @@ func (i *I) Compute(c context.Context, setWidth bool, final bool) (bool, error)
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
|
||||
func (i *I) FixLabels(labeler context.Labeler) error {
|
||||
macroCall := i.Line.GetMacroCall()
|
||||
macroLocals := i.Line.GetMacroLocals()
|
||||
parent := labeler.IsNewParentLabel(i.Label)
|
||||
newL, err := labeler.FixLabel(i.Label, macroCall)
|
||||
newL, err := labeler.FixLabel(i.Label, macroCall, macroLocals)
|
||||
if err != nil {
|
||||
return i.Errorf("%v", err)
|
||||
}
|
||||
@ -234,7 +235,7 @@ func (i *I) FixLabels(labeler context.Labeler) error {
|
||||
}
|
||||
|
||||
for _, e := range i.Exprs {
|
||||
if err := e.FixLabels(labeler, macroCall, i.Line); err != nil {
|
||||
if err := e.FixLabels(labeler, macroCall, macroLocals, i.Line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,10 @@ package lines
|
||||
import "fmt"
|
||||
|
||||
type Context struct {
|
||||
Filename string // Pointer to the filename
|
||||
Parent *Line // Pointer to parent line (eg. include, macro)
|
||||
MacroCall int
|
||||
Filename string // Pointer to the filename
|
||||
Parent *Line // Pointer to parent line (eg. include, macro)
|
||||
MacroCall int
|
||||
MacroLocals map[string]bool
|
||||
}
|
||||
|
||||
type Line struct {
|
||||
@ -45,6 +46,13 @@ func (c *Context) GetMacroCall() int {
|
||||
return c.Parent.GetMacroCall()
|
||||
}
|
||||
|
||||
func (l *Line) GetMacroLocals() map[string]bool {
|
||||
if l == nil || l.Context == nil {
|
||||
return nil
|
||||
}
|
||||
return l.Context.MacroLocals
|
||||
}
|
||||
|
||||
func (l *Line) GetMacroCall() int {
|
||||
if l == nil {
|
||||
return 0
|
||||
|
@ -7,14 +7,15 @@ import (
|
||||
)
|
||||
|
||||
type M struct {
|
||||
Name string
|
||||
Args []string
|
||||
Lines []string
|
||||
Name string
|
||||
Args []string
|
||||
Lines []string
|
||||
Locals map[string]bool // labels that should be scoped to macro invocation
|
||||
}
|
||||
|
||||
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, MacroCall: macroCall}
|
||||
context := lines.Context{Filename: "macro:" + m.Name, Parent: in.Line, MacroCall: macroCall, MacroLocals: m.Locals}
|
||||
for _, line := range m.Lines {
|
||||
// TODO(zellyn): implement named macro args
|
||||
subbed, err := flavor.ReplaceMacroArgs(line, in.MacroArgs, nil)
|
||||
|
Loading…
x
Reference in New Issue
Block a user