mirror of
https://github.com/zellyn/go6502.git
synced 2025-01-27 20:34:10 +00:00
Separated context out of Flavor
This commit is contained in:
parent
457446772a
commit
c7308bf05c
30
asm/asm.go
30
asm/asm.go
@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/flavors"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
@ -17,13 +18,17 @@ type Assembler struct {
|
||||
Opener lines.Opener
|
||||
Insts []*inst.I
|
||||
Macros map[string]macros.M
|
||||
Ctx *context.SimpleContext
|
||||
}
|
||||
|
||||
func NewAssembler(flavor flavors.F, opener lines.Opener) *Assembler {
|
||||
ctx := &context.SimpleContext{}
|
||||
flavor.InitContext(ctx)
|
||||
return &Assembler{
|
||||
Flavor: flavor,
|
||||
Opener: opener,
|
||||
Macros: make(map[string]macros.M),
|
||||
Ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +52,7 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
lineSources = lineSources[1:]
|
||||
continue
|
||||
}
|
||||
in, parseErr := a.Flavor.ParseInstr(line, false)
|
||||
in, parseErr := a.Flavor.ParseInstr(a.Ctx, line, false)
|
||||
if len(ifdefs) > 0 && !ifdefs[0] && in.Type != inst.TypeIfdefElse && in.Type != inst.TypeIfdefEnd {
|
||||
// we're in an inactive ifdef branch
|
||||
continue
|
||||
@ -83,17 +88,17 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
return in.Errorf(`error calling macro "%s": %v`, m.Name, err)
|
||||
}
|
||||
lineSources = append([]lines.LineSource{subLs}, lineSources...)
|
||||
a.Flavor.PushMacroCall(m.Name, macroCall, m.Locals)
|
||||
a.Ctx.PushMacroCall(m.Name, macroCall, m.Locals)
|
||||
case inst.TypeMacroEnd:
|
||||
// If we reached here, it's in a macro call, not a definition.
|
||||
if !a.Flavor.PopMacroCall() {
|
||||
if !a.Ctx.PopMacroCall() {
|
||||
return in.Errorf("unexpected end of macro")
|
||||
}
|
||||
case inst.TypeIfdef:
|
||||
if len(in.Exprs) == 0 {
|
||||
panic(fmt.Sprintf("Ifdef got parsed with no expression: %s", line))
|
||||
}
|
||||
val, err := in.Exprs[0].Eval(a.Flavor, in.Line)
|
||||
val, err := in.Exprs[0].Eval(a.Ctx, in.Line)
|
||||
if err != nil {
|
||||
return in.Errorf("cannot eval ifdef condition: %v", err)
|
||||
}
|
||||
@ -163,14 +168,14 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
if done {
|
||||
return in.Errorf("end of file while reading macro %s", m.Name)
|
||||
}
|
||||
in2, err := a.Flavor.ParseInstr(line, true)
|
||||
in2, err := a.Flavor.ParseInstr(a.Ctx, line, true)
|
||||
if a.Flavor.LocalMacroLabels() && in2.Label != "" {
|
||||
m.Locals[in2.Label] = true
|
||||
}
|
||||
m.Lines = append(m.Lines, line.Parse.Text())
|
||||
if err == nil && in2.Type == inst.TypeMacroEnd {
|
||||
a.Macros[m.Name] = m
|
||||
a.Flavor.AddMacroName(m.Name)
|
||||
a.Ctx.AddMacroName(m.Name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -178,9 +183,9 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
|
||||
// Clear out stuff that may be hanging around from the previous pass, set origin to default, etc.
|
||||
func (a *Assembler) initPass() {
|
||||
a.Flavor.SetLastLabel("") // No last label (yet)
|
||||
a.Flavor.RemoveChanged() // Remove any variables whose value ever changed.
|
||||
a.Flavor.SetAddr(a.Flavor.DefaultOrigin())
|
||||
a.Ctx.SetLastLabel("") // No last label (yet)
|
||||
a.Ctx.RemoveChanged() // Remove any variables whose value ever changed.
|
||||
a.Ctx.SetAddr(a.Flavor.DefaultOrigin())
|
||||
}
|
||||
|
||||
// passInst performs a pass on a single instruction. It forces the
|
||||
@ -188,16 +193,15 @@ func (a *Assembler) initPass() {
|
||||
// arguments. If final is true, and the instruction cannot be
|
||||
// finalized, it returns an error.
|
||||
func (a *Assembler) passInst(in *inst.I, final bool) (isFinal bool, err error) {
|
||||
// fmt.Printf("PLUGH: in.Compute(a.Flavor, true, true) on %s\n", in)
|
||||
isFinal, err = in.Compute(a.Flavor, final)
|
||||
isFinal, err = in.Compute(a.Ctx, final)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Update address
|
||||
addr, _ := a.Flavor.GetAddr()
|
||||
addr, _ := a.Ctx.GetAddr()
|
||||
in.Addr = addr
|
||||
a.Flavor.SetAddr(addr + in.Width)
|
||||
a.Ctx.SetAddr(addr + in.Width)
|
||||
|
||||
return isFinal, nil
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ type Context interface {
|
||||
Get(name string) (uint16, bool)
|
||||
SetAddr(uint16)
|
||||
GetAddr() (uint16, bool)
|
||||
DivZero() (uint16, error)
|
||||
DivZero() *uint16
|
||||
SetDivZero(uint16)
|
||||
RemoveChanged()
|
||||
Clear()
|
||||
SettingOn(name string) error
|
||||
@ -19,7 +20,7 @@ type Context interface {
|
||||
PushMacroCall(name string, number int, locals map[string]bool)
|
||||
PopMacroCall() bool
|
||||
GetMacroCall() (string, int, map[string]bool)
|
||||
|
||||
SetOnOffDefaults(map[string]bool)
|
||||
LastLabel() string
|
||||
SetLastLabel(label string)
|
||||
}
|
||||
@ -39,6 +40,7 @@ type SimpleContext struct {
|
||||
onOffDefaults map[string]bool
|
||||
macroNames map[string]bool
|
||||
macroCalls []macroCall
|
||||
divZeroVal *uint16
|
||||
}
|
||||
|
||||
type symbolValue struct {
|
||||
@ -52,10 +54,6 @@ func (sc *SimpleContext) fix() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) DivZero() (uint16, error) {
|
||||
return 0, fmt.Errorf("Not implemented: context.SimpleContext.DivZero()")
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) Get(name string) (uint16, bool) {
|
||||
if name == "*" {
|
||||
return sc.GetAddr()
|
||||
@ -185,3 +183,11 @@ func (sc *SimpleContext) LastLabel() string {
|
||||
func (sc *SimpleContext) SetLastLabel(l string) {
|
||||
sc.lastLabel = l
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) DivZero() *uint16 {
|
||||
return sc.divZeroVal
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) SetDivZero(val uint16) {
|
||||
sc.divZeroVal = &val
|
||||
}
|
||||
|
@ -174,7 +174,11 @@ func (e *E) Eval(ctx context.Context, ln *lines.Line) (uint16, error) {
|
||||
return 0, nil
|
||||
case OpDiv:
|
||||
if r == 0 {
|
||||
return ctx.DivZero()
|
||||
z := ctx.DivZero()
|
||||
if z == nil {
|
||||
return 0, ln.Errorf("divizion by zero")
|
||||
}
|
||||
return *z, nil
|
||||
}
|
||||
return l / r, nil
|
||||
case OpAnd:
|
||||
|
@ -11,16 +11,14 @@ import (
|
||||
// AS65 implements the AS65-compatible assembler flavor.
|
||||
// See http://www.kingswood-consulting.co.uk/assemblers/
|
||||
|
||||
type AS65 struct {
|
||||
context.SimpleContext
|
||||
}
|
||||
type AS65 struct{}
|
||||
|
||||
func New() *AS65 {
|
||||
return &AS65{}
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *AS65) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
func (a *AS65) ParseInstr(ctx context.Context, line lines.Line, quick bool) (inst.I, error) {
|
||||
return inst.I{}, nil
|
||||
}
|
||||
|
||||
@ -47,3 +45,6 @@ func (a *AS65) LocalMacroLabels() bool {
|
||||
func (a *AS65) String() string {
|
||||
return "as65"
|
||||
}
|
||||
|
||||
func (a *AS65) InitContext(ctx context.Context) {
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
)
|
||||
|
||||
type F interface {
|
||||
ParseInstr(Line lines.Line, quick bool) (inst.I, error)
|
||||
ParseInstr(ctx context.Context, Line lines.Line, quick bool) (inst.I, error)
|
||||
DefaultOrigin() uint16
|
||||
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
|
||||
LocalMacroLabels() bool
|
||||
String() string
|
||||
context.Context
|
||||
InitContext(context.Context)
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package merlin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/expr"
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
@ -38,6 +38,8 @@ func New() *Merlin {
|
||||
m.InvCharChars = `"`
|
||||
m.MacroArgSep = ";"
|
||||
m.SuffixForWide = true
|
||||
m.LocalMacroLabelsVal = true
|
||||
m.DefaultOriginVal = 0x8000
|
||||
|
||||
m.Directives = map[string]oldschool.DirectiveInfo{
|
||||
"ORG": {inst.TypeOrg, m.ParseAddress, 0},
|
||||
@ -77,16 +79,18 @@ func New() *Merlin {
|
||||
"!": expr.OpXor,
|
||||
}
|
||||
|
||||
m.SetOnOffDefaults(map[string]bool{
|
||||
"LST": true, // Display listing: not used
|
||||
"XC": false, // Extended commands: not implemented yet
|
||||
"EXP": false, // How to print macro calls
|
||||
"LSTDO": false, // List conditional code?
|
||||
"TR": false, // truncate listing to 3 bytes?
|
||||
"CYC": false, // print cycle times?
|
||||
})
|
||||
m.InitContextFunc = func(ctx context.Context) {
|
||||
ctx.SetOnOffDefaults(map[string]bool{
|
||||
"LST": true, // Display listing: not used
|
||||
"XC": false, // Extended commands: not implemented yet
|
||||
"EXP": false, // How to print macro calls
|
||||
"LSTDO": false, // List conditional code?
|
||||
"TR": false, // truncate listing to 3 bytes?
|
||||
"CYC": false, // print cycle times?
|
||||
})
|
||||
}
|
||||
|
||||
m.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
|
||||
m.SetAsciiVariation = func(ctx context.Context, in *inst.I, lp *lines.Parse) {
|
||||
if in.Command != "ASC" && in.Command != "DCI" {
|
||||
panic(fmt.Sprintf("Unimplemented/unknown ascii directive: '%s'", in.Command))
|
||||
}
|
||||
@ -108,11 +112,11 @@ func New() *Merlin {
|
||||
// the "command column" value, which caused isMacroCall to return
|
||||
// true, and the lp to be pointing to the following character
|
||||
// (probably whitespace).
|
||||
m.ParseMacroCall = func(in inst.I, lp *lines.Parse) (inst.I, bool, error) {
|
||||
m.ParseMacroCall = func(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, bool, error) {
|
||||
if in.Command == "" {
|
||||
return in, false, nil
|
||||
}
|
||||
byName := m.HasMacroName(in.Command)
|
||||
byName := ctx.HasMacroName(in.Command)
|
||||
|
||||
// It's not a macro call.
|
||||
if in.Command != ">>>" && in.Command != "PMC" && !byName {
|
||||
@ -127,7 +131,7 @@ func New() *Merlin {
|
||||
return in, true, in.Errorf("Expected macro name, got char '%c'", c)
|
||||
}
|
||||
in.Command = lp.Emit()
|
||||
if !m.HasMacroName(in.Command) {
|
||||
if !ctx.HasMacroName(in.Command) {
|
||||
return in, true, in.Errorf("Unknown macro: '%s'", in.Command)
|
||||
}
|
||||
if !lp.Consume(" ./,-(") {
|
||||
@ -153,13 +157,13 @@ func New() *Merlin {
|
||||
return in, true, nil
|
||||
}
|
||||
|
||||
m.FixLabel = func(label string) (string, error) {
|
||||
_, macroCount, locals := m.GetMacroCall()
|
||||
m.FixLabel = func(ctx context.Context, label string) (string, error) {
|
||||
_, macroCount, locals := ctx.GetMacroCall()
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
case label[0] == ':':
|
||||
if last := m.LastLabel(); last == "" {
|
||||
if last := ctx.LastLabel(); last == "" {
|
||||
return "", fmt.Errorf("sublabel '%s' without previous label", label)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
@ -178,15 +182,7 @@ func New() *Merlin {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Merlin) Zero() (uint16, error) {
|
||||
return 0, errors.New("Division by zero.")
|
||||
}
|
||||
|
||||
func (m *Merlin) DefaultOrigin() uint16 {
|
||||
return 0x8000
|
||||
}
|
||||
|
||||
func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (m *Merlin) ParseInclude(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(whitespace)
|
||||
lp.AcceptUntil(";")
|
||||
filename := strings.TrimSpace(lp.Emit())
|
||||
@ -204,7 +200,3 @@ func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.Final = true
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (m *Merlin) LocalMacroLabels() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package oldschool
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@ -25,7 +26,7 @@ const fileChars = Letters + Digits + "."
|
||||
|
||||
type DirectiveInfo struct {
|
||||
Type inst.Type
|
||||
Func func(inst.I, *lines.Parse) (inst.I, error)
|
||||
Func func(context.Context, inst.I, *lines.Parse) (inst.I, error)
|
||||
Var inst.Variant
|
||||
}
|
||||
|
||||
@ -40,32 +41,34 @@ const (
|
||||
// Base implements the S-C Macro Assembler-compatible assembler flavor.
|
||||
// See http://www.txbobsc.com/scsc/ and http://stjarnhimlen.se/apple2/
|
||||
type Base struct {
|
||||
Name string
|
||||
Directives map[string]DirectiveInfo
|
||||
Operators map[string]expr.Operator
|
||||
context.SimpleContext
|
||||
LabelChars string
|
||||
LabelColons Requiredness
|
||||
ExplicitARegister Requiredness
|
||||
HexCommas Requiredness
|
||||
SpacesForComment int // this many spaces after command means it's the comment field
|
||||
StringEndOptional bool // can omit closing delimeter from string args?
|
||||
SuffixForWide bool // is eg. "LDA:" a force-wide on "LDA"? (Merlin)
|
||||
CommentChar rune
|
||||
BinaryChar rune
|
||||
MsbChars string
|
||||
LsbChars string
|
||||
ImmediateChars string
|
||||
operatorChars string
|
||||
CharChars string
|
||||
InvCharChars string
|
||||
MacroArgSep string
|
||||
LocalMacroLabels bool
|
||||
ExtraCommenty func(string) bool
|
||||
SetAsciiVariation func(*inst.I, *lines.Parse)
|
||||
ParseMacroCall func(inst.I, *lines.Parse) (inst.I, bool, error)
|
||||
FixLabel func(label string) (string, error)
|
||||
IsNewParentLabel func(label string) bool
|
||||
Name string
|
||||
Directives map[string]DirectiveInfo
|
||||
Operators map[string]expr.Operator
|
||||
LabelChars string
|
||||
LabelColons Requiredness
|
||||
ExplicitARegister Requiredness
|
||||
HexCommas Requiredness
|
||||
SpacesForComment int // this many spaces after command means it's the comment field
|
||||
StringEndOptional bool // can omit closing delimeter from string args?
|
||||
SuffixForWide bool // is eg. "LDA:" a force-wide on "LDA"? (Merlin)
|
||||
CommentChar rune
|
||||
BinaryChar rune
|
||||
MsbChars string
|
||||
LsbChars string
|
||||
ImmediateChars string
|
||||
operatorChars string
|
||||
CharChars string
|
||||
InvCharChars string
|
||||
MacroArgSep string
|
||||
ExtraCommenty func(string) bool
|
||||
SetAsciiVariation func(context.Context, *inst.I, *lines.Parse)
|
||||
ParseMacroCall func(context.Context, inst.I, *lines.Parse) (inst.I, bool, error)
|
||||
IsNewParentLabel func(label string) bool
|
||||
InitContextFunc func(context.Context)
|
||||
FixLabel func(context.Context, string) (string, error)
|
||||
LocalMacroLabelsVal bool
|
||||
DivZeroVal *uint16
|
||||
DefaultOriginVal uint16
|
||||
}
|
||||
|
||||
func (a *Base) String() string {
|
||||
@ -73,7 +76,7 @@ func (a *Base) String() string {
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *Base) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
func (a *Base) ParseInstr(ctx context.Context, line lines.Line, quick bool) (inst.I, error) {
|
||||
lp := line.Parse
|
||||
in := inst.I{Line: &line}
|
||||
|
||||
@ -125,13 +128,13 @@ func (a *Base) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
// If appropriate, set the last parent label.
|
||||
if !quick {
|
||||
parent := a.IsNewParentLabel(in.Label)
|
||||
newL, err := a.FixLabel(in.Label)
|
||||
newL, err := a.FixLabel(ctx, in.Label)
|
||||
if err != nil {
|
||||
return in, in.Errorf("%v", err)
|
||||
}
|
||||
in.Label = newL
|
||||
if parent {
|
||||
a.SetLastLabel(in.Label)
|
||||
ctx.SetLastLabel(in.Label)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,16 +145,12 @@ func (a *Base) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
in.Type = inst.TypeNone
|
||||
return in, nil
|
||||
}
|
||||
return a.parseCmd(in, lp, quick)
|
||||
}
|
||||
|
||||
func (a *Base) DefaultOrigin() uint16 {
|
||||
return 0x0800
|
||||
return a.parseCmd(ctx, in, lp, quick)
|
||||
}
|
||||
|
||||
// parseCmd parses the "command" part of an instruction: we expect to be
|
||||
// looking at a non-whitespace character.
|
||||
func (a *Base) parseCmd(in inst.I, lp *lines.Parse, quick bool) (inst.I, error) {
|
||||
func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, quick bool) (inst.I, error) {
|
||||
if !lp.AcceptRun(cmdChars) && !(a.Directives["="].Func != nil && lp.Accept("=")) {
|
||||
c := lp.Next()
|
||||
return in, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
||||
@ -170,7 +169,7 @@ func (a *Base) parseCmd(in inst.I, lp *lines.Parse, quick bool) (inst.I, error)
|
||||
}
|
||||
// Give ParseMacroCall a chance
|
||||
if a.ParseMacroCall != nil {
|
||||
i, isMacro, err := a.ParseMacroCall(in, lp)
|
||||
i, isMacro, err := a.ParseMacroCall(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -185,16 +184,16 @@ func (a *Base) parseCmd(in inst.I, lp *lines.Parse, quick bool) (inst.I, error)
|
||||
if dir.Func == nil {
|
||||
return in, nil
|
||||
}
|
||||
return dir.Func(in, lp)
|
||||
return dir.Func(ctx, in, lp)
|
||||
}
|
||||
|
||||
if a.HasSetting(in.Command) {
|
||||
return a.parseSetting(in, lp)
|
||||
if ctx.HasSetting(in.Command) {
|
||||
return a.parseSetting(ctx, in, lp)
|
||||
}
|
||||
|
||||
if summary, ok := opcodes.ByName[in.Command]; ok {
|
||||
in.Type = inst.TypeOp
|
||||
return a.parseOpArgs(in, lp, summary, false)
|
||||
return a.parseOpArgs(ctx, in, lp, summary, false)
|
||||
}
|
||||
|
||||
// Merlin lets you say "LDA:" or "LDA@" or "LDAZ" to force non-zero-page.
|
||||
@ -203,14 +202,14 @@ func (a *Base) parseCmd(in inst.I, lp *lines.Parse, quick bool) (inst.I, error)
|
||||
if summary, ok := opcodes.ByName[prefix]; ok {
|
||||
in.Command = prefix
|
||||
in.Type = inst.TypeOp
|
||||
return a.parseOpArgs(in, lp, summary, true)
|
||||
return a.parseOpArgs(ctx, in, lp, summary, true)
|
||||
}
|
||||
}
|
||||
|
||||
return in, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
|
||||
}
|
||||
|
||||
func (a *Base) parseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) parseSetting(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.Type = inst.TypeSetting
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(Letters) {
|
||||
@ -220,9 +219,9 @@ func (a *Base) parseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.TextArg = lp.Emit()
|
||||
switch in.TextArg {
|
||||
case "ON":
|
||||
a.SettingOn(in.Command)
|
||||
ctx.SettingOn(in.Command)
|
||||
case "OFF":
|
||||
a.SettingOff(in.Command)
|
||||
ctx.SettingOff(in.Command)
|
||||
default:
|
||||
return in, in.Errorf("expecting ON/OFF, found '%s'", in.TextArg)
|
||||
}
|
||||
@ -269,7 +268,7 @@ 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) {
|
||||
func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summary opcodes.OpSummary, forceWide bool) (inst.I, error) {
|
||||
// MODE_IMPLIED: we don't really care what comes next: it's a comment.
|
||||
if summary.Modes == opcodes.MODE_IMPLIED {
|
||||
op := summary.Ops[0]
|
||||
@ -314,7 +313,7 @@ func (a *Base) parseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
return in, in.Errorf("%s doesn't support any indirect modes", in.Command)
|
||||
}
|
||||
xy := '-'
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
expr, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -371,12 +370,12 @@ func (a *Base) parseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
|
||||
}
|
||||
}
|
||||
|
||||
return common.DecodeOp(a, in, summary, indirect, xy, forceWide)
|
||||
return common.DecodeOp(ctx, in, summary, indirect, xy, forceWide)
|
||||
}
|
||||
|
||||
func (a *Base) ParseAddress(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseAddress(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
expr, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -387,9 +386,9 @@ func (a *Base) ParseAddress(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseAscii(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseAscii(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
a.SetAsciiVariation(&in, lp)
|
||||
a.SetAsciiVariation(ctx, &in, lp)
|
||||
var invert, invertLast byte
|
||||
switch in.Var {
|
||||
case inst.VarAscii:
|
||||
@ -424,9 +423,9 @@ func (a *Base) ParseAscii(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseBlockStorage(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseBlockStorage(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
ex, err := a.ParseExpression(in, lp)
|
||||
ex, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -434,10 +433,10 @@ func (a *Base) ParseBlockStorage(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseData(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
for {
|
||||
ex, err := a.ParseExpression(in, lp)
|
||||
ex, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -449,9 +448,9 @@ func (a *Base) ParseData(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseDo(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseDo(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
expr, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
@ -462,12 +461,18 @@ func (a *Base) ParseDo(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseEquate(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseEquate(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.ParseExpression(in, lp)
|
||||
expr, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
|
||||
xyzzy, err := expr.Eval(ctx, in.Line)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
_ = xyzzy
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
in.WidthKnown = true
|
||||
in.Width = 0
|
||||
@ -475,7 +480,7 @@ func (a *Base) ParseEquate(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseHexString(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.AcceptRun(Whitespace)
|
||||
for {
|
||||
lp.Ignore()
|
||||
@ -500,7 +505,7 @@ func (a *Base) ParseHexString(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseInclude(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(fileChars) {
|
||||
return in, in.Errorf("Expecting filename, found '%c'", lp.Next())
|
||||
@ -513,7 +518,7 @@ func (a *Base) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
|
||||
// For assemblers where the macro name follows the macro directive.
|
||||
func (a *Base) ParseMacroStart(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseMacroStart(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(cmdChars) {
|
||||
return in, in.Errorf("Expecting valid macro name, found '%c'", lp.Next())
|
||||
@ -526,7 +531,7 @@ func (a *Base) ParseMacroStart(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
|
||||
// For assemblers where the macro name is the label, followed by the directive.
|
||||
func (a *Base) MarkMacroStart(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) MarkMacroStart(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.TextArg, in.Label = in.Label, ""
|
||||
in.WidthKnown = true
|
||||
in.Width = 0
|
||||
@ -534,18 +539,18 @@ func (a *Base) MarkMacroStart(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseNoArgDir(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseNoArgDir(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.WidthKnown = true
|
||||
in.Width = 0
|
||||
in.Final = true
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseNotImplemented(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseNotImplemented(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, in.Errorf("not implemented (yet?): %s", in.Command)
|
||||
}
|
||||
|
||||
func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
func (a *Base) parseExpression(ctx context.Context, in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
|
||||
if a.operatorChars == "" {
|
||||
for k, _ := range a.Operators {
|
||||
@ -581,14 +586,14 @@ func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
}
|
||||
}
|
||||
|
||||
tree, err := a.ParseTerm(in, lp)
|
||||
tree, err := a.ParseTerm(ctx, in, lp)
|
||||
if err != nil {
|
||||
return &expr.E{}, err
|
||||
}
|
||||
|
||||
for lp.Accept(a.operatorChars) {
|
||||
c := lp.Emit()
|
||||
right, err := a.ParseTerm(in, lp)
|
||||
right, err := a.ParseTerm(ctx, in, lp)
|
||||
if err != nil {
|
||||
return &expr.E{}, err
|
||||
}
|
||||
@ -602,7 +607,7 @@ func (a *Base) ParseExpression(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
func (a *Base) ParseTerm(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
func (a *Base) ParseTerm(ctx context.Context, in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
ex := &expr.E{}
|
||||
top := ex
|
||||
|
||||
@ -688,7 +693,7 @@ func (a *Base) ParseTerm(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
|
||||
ex.Op = expr.OpLeaf
|
||||
ex.Text = lp.Emit()
|
||||
newL, err := a.FixLabel(ex.Text)
|
||||
newL, err := a.FixLabel(ctx, ex.Text)
|
||||
if err != nil {
|
||||
return &expr.E{}, in.Errorf("%v", err)
|
||||
}
|
||||
@ -715,18 +720,18 @@ func (a *Base) DefaultIsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != '.'
|
||||
}
|
||||
|
||||
func (a *Base) DefaultFixLabel(label string) (string, error) {
|
||||
func (a *Base) DefaultFixLabel(ctx context.Context, label string) (string, error) {
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
case label[0] == '.':
|
||||
if last := a.LastLabel(); last == "" {
|
||||
if last := ctx.LastLabel(); last == "" {
|
||||
return "", fmt.Errorf("sublabel '%s' without previous label", label)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
}
|
||||
case label[0] == ':':
|
||||
_, macroCall, _ := a.GetMacroCall()
|
||||
_, macroCall, _ := ctx.GetMacroCall()
|
||||
if macroCall == 0 {
|
||||
return "", fmt.Errorf("macro-local label '%s' seen outside macro", label)
|
||||
} else {
|
||||
@ -735,3 +740,24 @@ func (a *Base) DefaultFixLabel(label string) (string, error) {
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (a *Base) LocalMacroLabels() bool {
|
||||
return a.LocalMacroLabelsVal
|
||||
}
|
||||
|
||||
func (a *Base) Zero() (uint16, error) {
|
||||
if a.DivZeroVal == nil {
|
||||
return 0, errors.New("Division by zero.")
|
||||
}
|
||||
return *a.DivZeroVal, nil
|
||||
}
|
||||
|
||||
func (a *Base) DefaultOrigin() uint16 {
|
||||
return a.DefaultOriginVal
|
||||
}
|
||||
|
||||
func (a *Base) InitContext(ctx context.Context) {
|
||||
if a.InitContextFunc != nil {
|
||||
a.InitContextFunc(ctx)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package redbook
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/expr"
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
@ -37,6 +38,7 @@ func newRedbook(name string) *RedBook {
|
||||
r.MsbChars = "/"
|
||||
r.ImmediateChars = "#"
|
||||
r.HexCommas = oldschool.ReqOptional
|
||||
r.DefaultOriginVal = 0x0800
|
||||
|
||||
r.Directives = map[string]oldschool.DirectiveInfo{
|
||||
"ORG": {inst.TypeOrg, r.ParseAddress, 0},
|
||||
@ -67,14 +69,16 @@ func newRedbook(name string) *RedBook {
|
||||
"=": expr.OpEq,
|
||||
}
|
||||
|
||||
r.SetOnOffDefaults(map[string]bool{
|
||||
"MSB": true, // MSB defaults to true, as per manual
|
||||
"LST": true, // Display listing: not used
|
||||
})
|
||||
r.InitContextFunc = func(ctx context.Context) {
|
||||
ctx.SetOnOffDefaults(map[string]bool{
|
||||
"MSB": true, // MSB defaults to true, as per manual
|
||||
"LST": true, // Display listing: not used
|
||||
})
|
||||
}
|
||||
|
||||
r.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
|
||||
r.SetAsciiVariation = func(ctx context.Context, in *inst.I, lp *lines.Parse) {
|
||||
if in.Command == "ASC" {
|
||||
if r.Setting("MSB") {
|
||||
if ctx.Setting("MSB") {
|
||||
in.Var = inst.VarAsciiHi
|
||||
} else {
|
||||
in.Var = inst.VarAscii
|
||||
@ -93,7 +97,3 @@ func newRedbook(name string) *RedBook {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RedBook) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package scma
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/expr"
|
||||
"github.com/zellyn/go6502/asm/flavors/oldschool"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
@ -29,6 +30,9 @@ func New() *SCMA {
|
||||
a.ImmediateChars = "#"
|
||||
a.CharChars = "'"
|
||||
a.MacroArgSep = ","
|
||||
a.DefaultOriginVal = 0x0800
|
||||
divZeroVal := uint16(0xffff)
|
||||
a.DivZeroVal = &divZeroVal
|
||||
|
||||
a.Directives = map[string]oldschool.DirectiveInfo{
|
||||
".IN": {inst.TypeInclude, a.ParseInclude, 0},
|
||||
@ -67,7 +71,7 @@ func New() *SCMA {
|
||||
return strings.HasPrefix(s, commentWhitespacePrefix)
|
||||
}
|
||||
|
||||
a.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
|
||||
a.SetAsciiVariation = func(ctx context.Context, in *inst.I, lp *lines.Parse) {
|
||||
// For S-C Assembler, leading "-" flips high bit
|
||||
invert := lp.Consume("-")
|
||||
invertLast := in.Command == ".AT"
|
||||
@ -87,7 +91,7 @@ func New() *SCMA {
|
||||
// the "command column" value, which caused isMacroCall to return
|
||||
// true, and the lp to be pointing to the following character
|
||||
// (probably whitespace).
|
||||
a.ParseMacroCall = func(in inst.I, lp *lines.Parse) (inst.I, bool, error) {
|
||||
a.ParseMacroCall = func(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, bool, error) {
|
||||
if in.Command == "" || in.Command[0] != '>' {
|
||||
// not a macro call
|
||||
return in, false, nil
|
||||
@ -117,11 +121,3 @@ func New() *SCMA {
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *SCMA) Zero() (uint16, error) {
|
||||
return uint16(0xffff), nil
|
||||
}
|
||||
|
||||
func (a *SCMA) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package flavors
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -24,15 +23,23 @@ func h(s string) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
type asmFactory func() *asm.Assembler
|
||||
|
||||
func TestMultiline(t *testing.T) {
|
||||
o := lines.NewTestOpener()
|
||||
|
||||
ss := asm.NewAssembler(scma.New(), o)
|
||||
ra := asm.NewAssembler(redbook.NewRedbookA(), o)
|
||||
mm := asm.NewAssembler(merlin.New(), o)
|
||||
ss := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(scma.New(), o)
|
||||
})
|
||||
ra := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(redbook.NewRedbookA(), o)
|
||||
})
|
||||
mm := asmFactory(func() *asm.Assembler {
|
||||
return asm.NewAssembler(merlin.New(), o)
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
a *asm.Assembler // assembler
|
||||
af asmFactory // assembler factory
|
||||
name string // name
|
||||
i []string // main file: lines
|
||||
ii map[string][]string // other files: lines
|
||||
@ -293,42 +300,41 @@ func TestMultiline(t *testing.T) {
|
||||
if !tt.active {
|
||||
continue
|
||||
}
|
||||
fmt.Println(tt.name)
|
||||
a := tt.af()
|
||||
if tt.b == "" && len(tt.ps) == 0 {
|
||||
t.Fatalf(`%d("%s" - %s): test case must specify bytes or pieces`, i, tt.name, tt.a.Flavor)
|
||||
t.Fatalf(`%d("%s" - %s): test case must specify bytes or pieces`, i, tt.name, a.Flavor)
|
||||
}
|
||||
tt.a.Reset()
|
||||
o.Clear()
|
||||
o["TESTFILE"] = strings.Join(tt.i, "\n")
|
||||
for k, v := range tt.ii {
|
||||
o[k] = strings.Join(v, "\n")
|
||||
}
|
||||
if err := tt.a.Load("TESTFILE", 0); err != nil {
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Load("TESTFILE") failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
if err := a.Load("TESTFILE", 0); err != nil {
|
||||
t.Fatalf(`%d("%s" - %s): a.Load("TESTFILE") failed: %s`, i, tt.name, a.Flavor, err)
|
||||
}
|
||||
err := tt.a.Pass2()
|
||||
err := a.Pass2()
|
||||
if err != nil {
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Pass(true) failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
t.Fatalf(`%d("%s" - %s): a.Pass(true) failed: %s`, i, tt.name, a.Flavor, err)
|
||||
}
|
||||
|
||||
if tt.b != "" {
|
||||
bb, err := tt.a.RawBytes()
|
||||
bb, err := a.RawBytes()
|
||||
if err != nil {
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.RawBytes() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
t.Fatalf(`%d("%s" - %s): a.RawBytes() failed: %s`, i, tt.name, a.Flavor, err)
|
||||
}
|
||||
hx := hex.EncodeToString(bb)
|
||||
if hx != tt.b {
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.RawBytes()=[%s]; want [%s]`, i, tt.name, tt.a.Flavor, hx, tt.b)
|
||||
t.Fatalf(`%d("%s" - %s): a.RawBytes()=[%s]; want [%s]`, i, tt.name, a.Flavor, hx, tt.b)
|
||||
}
|
||||
}
|
||||
if len(tt.ps) != 0 {
|
||||
m, err := tt.a.Membuf()
|
||||
m, err := a.Membuf()
|
||||
if err != nil {
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Membuf() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
t.Fatalf(`%d("%s" - %s): a.Membuf() failed: %s`, i, tt.name, a.Flavor, err)
|
||||
}
|
||||
ps := m.Pieces()
|
||||
if !reflect.DeepEqual(ps, tt.ps) {
|
||||
t.Fatalf(`%d("%s" - %s): tt.Membuf().Pieces() = %v; want %v`, i, tt.name, tt.a.Flavor, ps, tt.ps)
|
||||
t.Fatalf(`%d("%s" - %s): tt.Membuf().Pieces() = %v; want %v`, i, tt.name, a.Flavor, ps, tt.ps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/flavors"
|
||||
"github.com/zellyn/go6502/asm/flavors/as65"
|
||||
"github.com/zellyn/go6502/asm/flavors/merlin"
|
||||
@ -20,7 +21,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
mm := merlin.New()
|
||||
|
||||
tests := []struct {
|
||||
a flavors.F // assembler flavor
|
||||
f flavors.F // assembler flavor
|
||||
i string // input string
|
||||
p string // printed instruction, expected
|
||||
b string // bytes, expected
|
||||
@ -209,6 +210,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
{ss, ` .AT -DABCD`, "{data/b}", "c1c243"},
|
||||
{ss, ` .AT /ABC/`, "{data/b}", "4142c3"},
|
||||
{ss, `>SAM AB,$12,"A B","A, B, "" C"`, `{call SAM {"AB", "$12", "A B", "A, B, \" C"}}`, ""},
|
||||
// {ss, " LDA #3/0", "{LDA/imm (lsb (/ $0003 $0000))}", "a9ff"},
|
||||
}
|
||||
|
||||
// TODO(zellyn): Add tests for finalization of four SCMA directives:
|
||||
@ -220,30 +222,32 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
// TODO(zellyn): Test AS65 and Merlin too.
|
||||
|
||||
// Initialize to a known state for testing.
|
||||
tt.a.Clear()
|
||||
tt.a.SetAddr(0x2345)
|
||||
tt.a.Set("A.B", 0x6789)
|
||||
tt.a.Set("C.D", 0x789a)
|
||||
tt.a.Set("L2", 0x6789)
|
||||
tt.a.Set("L3", 0x789a)
|
||||
tt.a.AddMacroName("INCW")
|
||||
tt.a.AddMacroName("M1")
|
||||
ctx := &context.SimpleContext{}
|
||||
ctx.Clear()
|
||||
ctx.SetAddr(0x2345)
|
||||
ctx.Set("A.B", 0x6789)
|
||||
ctx.Set("C.D", 0x789a)
|
||||
ctx.Set("L2", 0x6789)
|
||||
ctx.Set("L3", 0x789a)
|
||||
ctx.AddMacroName("INCW")
|
||||
ctx.AddMacroName("M1")
|
||||
tt.f.InitContext(ctx)
|
||||
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i), false)
|
||||
inst, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), false)
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.a, tt.i, err)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.f, tt.i, err)
|
||||
continue
|
||||
}
|
||||
if inst.Line.Parse == nil {
|
||||
t.Errorf("Got empty inst.Line.Parse on input '%s'", tt.i)
|
||||
}
|
||||
_, err = inst.Compute(tt.a, true)
|
||||
_, err = inst.Compute(ctx, true)
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.a, true) => error: %s`, i, tt.a, tt.i, inst, err)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, inst, err)
|
||||
continue
|
||||
}
|
||||
if inst.String() != tt.p {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") = %s; want %s`, i, tt.a, tt.i, inst.String(), tt.p)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") = %s; want %s`, i, tt.f, tt.i, inst.String(), tt.p)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -251,7 +255,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
hx := hex.EncodeToString(inst.Data)
|
||||
// xxxxxx sets the width, but doesn't expect actual data
|
||||
if hx != tt.b && (len(tt.b) == 0 || tt.b[0] != 'x') {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s").Data = [%s]; want [%s]`, i, tt.a, tt.i, hx, tt.b)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s").Data = [%s]; want [%s]`, i, tt.f, tt.i, hx, tt.b)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -275,7 +279,7 @@ func TestSimpleErrors(t *testing.T) {
|
||||
mm := merlin.New()
|
||||
|
||||
tests := []struct {
|
||||
a flavors.F // assembler flavor
|
||||
f flavors.F // assembler flavor
|
||||
i string // input string
|
||||
}{
|
||||
|
||||
@ -289,13 +293,13 @@ func TestSimpleErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
// TODO(zellyn): Test AS65 and Merlin too.
|
||||
if tt.a != ss {
|
||||
if tt.f != ss {
|
||||
continue
|
||||
}
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i), false)
|
||||
ctx := &context.SimpleContext{}
|
||||
inst, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), false)
|
||||
if err == nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") want err; got %s`, i, tt.a, tt.i, inst)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") want err; got %s`, i, tt.f, tt.i, inst)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user