mirror of
https://github.com/zellyn/go6502.git
synced 2024-12-28 10:29:53 +00:00
Moving more stuff to first pass.
This commit is contained in:
parent
cab917364e
commit
c07a3732a6
38
asm/asm.go
38
asm/asm.go
@ -32,6 +32,11 @@ func NewAssembler(flavor flavors.F, opener lines.Opener) *Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
type ifdef struct {
|
||||
active bool
|
||||
in inst.I
|
||||
}
|
||||
|
||||
// Load loads a new assembler file, deleting any previous data.
|
||||
func (a *Assembler) Load(filename string, prefix int) error {
|
||||
a.initPass()
|
||||
@ -41,7 +46,7 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
return err
|
||||
}
|
||||
lineSources := []lines.LineSource{ls}
|
||||
ifdefs := []bool{}
|
||||
ifdefs := []ifdef{}
|
||||
macroCall := 0
|
||||
for len(lineSources) > 0 {
|
||||
line, done, err := lineSources[0].Next()
|
||||
@ -52,14 +57,18 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
lineSources = lineSources[1:]
|
||||
continue
|
||||
}
|
||||
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
|
||||
inactive := len(ifdefs) > 0 && !ifdefs[0].active
|
||||
mode := flavors.ParseModeNormal
|
||||
if inactive {
|
||||
mode = flavors.ParseModeInactive
|
||||
}
|
||||
in, parseErr := a.Flavor.ParseInstr(a.Ctx, line, mode)
|
||||
if inactive && in.Type != inst.TypeIfdefElse && in.Type != inst.TypeIfdefEnd {
|
||||
// we're still in an inactive ifdef branch
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if parseErr != nil {
|
||||
return parseErr
|
||||
}
|
||||
|
||||
if _, err := a.passInst(&in, false); err != nil {
|
||||
@ -102,13 +111,13 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
if err != nil {
|
||||
return in.Errorf("cannot eval ifdef condition: %v", err)
|
||||
}
|
||||
ifdefs = append([]bool{val != 0}, ifdefs...)
|
||||
ifdefs = append([]ifdef{{val != 0, in}}, ifdefs...)
|
||||
|
||||
case inst.TypeIfdefElse:
|
||||
if len(ifdefs) == 0 {
|
||||
return in.Errorf("ifdef else branch encountered outside ifdef: %s", line)
|
||||
}
|
||||
ifdefs[0] = !ifdefs[0]
|
||||
ifdefs[0].active = !ifdefs[0].active
|
||||
case inst.TypeIfdefEnd:
|
||||
if len(ifdefs) == 0 {
|
||||
return in.Errorf("ifdef end encountered outside ifdef: %s", line)
|
||||
@ -132,6 +141,9 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
}
|
||||
a.Insts = append(a.Insts, &in)
|
||||
}
|
||||
if len(ifdefs) > 0 {
|
||||
return ifdefs[0].in.Errorf("Ifdef not closed before end of file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -168,7 +180,7 @@ 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(a.Ctx, line, true)
|
||||
in2, err := a.Flavor.ParseInstr(a.Ctx, line, flavors.ParseModeMacroSave)
|
||||
if a.Flavor.LocalMacroLabels() && in2.Label != "" {
|
||||
m.Locals[in2.Label] = true
|
||||
}
|
||||
@ -193,13 +205,17 @@ 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) {
|
||||
if in.Type == inst.TypeOrg {
|
||||
a.Ctx.SetAddr(in.Addr)
|
||||
return true, nil
|
||||
}
|
||||
isFinal, err = in.Compute(a.Ctx, final)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Update address
|
||||
addr, _ := a.Ctx.GetAddr()
|
||||
addr := a.Ctx.GetAddr()
|
||||
in.Addr = addr
|
||||
a.Ctx.SetAddr(addr + in.Width)
|
||||
|
||||
|
@ -133,8 +133,8 @@ http://twimgs.com/informationweek/byte/archive/Apple-II-Description/The-Apple-II
|
||||
It's a bit tricky:
|
||||
|
||||
1. Parse instruction.
|
||||
1. Set the org/target immediately, updating current address.
|
||||
2. Set the current label.
|
||||
1. Set the current label to the current address, unless it's an equate
|
||||
2. Set the org/target immediately, updating current address.
|
||||
3. Force equates to evaluate immediately.
|
||||
4. Evaluate instructions.
|
||||
|
||||
|
@ -6,7 +6,7 @@ type Context interface {
|
||||
Set(name string, value uint16)
|
||||
Get(name string) (uint16, bool)
|
||||
SetAddr(uint16)
|
||||
GetAddr() (uint16, bool)
|
||||
GetAddr() uint16
|
||||
DivZero() *uint16
|
||||
SetDivZero(uint16)
|
||||
RemoveChanged()
|
||||
@ -33,7 +33,7 @@ type macroCall struct {
|
||||
|
||||
type SimpleContext struct {
|
||||
symbols map[string]symbolValue
|
||||
addr int32
|
||||
addr uint16
|
||||
lastLabel string
|
||||
highbit byte // OR-mask for ASCII high bit
|
||||
onOff map[string]bool
|
||||
@ -56,7 +56,7 @@ func (sc *SimpleContext) fix() {
|
||||
|
||||
func (sc *SimpleContext) Get(name string) (uint16, bool) {
|
||||
if name == "*" {
|
||||
return sc.GetAddr()
|
||||
return sc.GetAddr(), true
|
||||
}
|
||||
sc.fix()
|
||||
s, found := sc.symbols[name]
|
||||
@ -64,14 +64,11 @@ func (sc *SimpleContext) Get(name string) (uint16, bool) {
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) SetAddr(addr uint16) {
|
||||
sc.addr = int32(addr)
|
||||
sc.addr = addr
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) GetAddr() (uint16, bool) {
|
||||
if sc.addr == -1 {
|
||||
return 0, false
|
||||
}
|
||||
return uint16(sc.addr), true
|
||||
func (sc *SimpleContext) GetAddr() uint16 {
|
||||
return sc.addr
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) Set(name string, value uint16) {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/flavors"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
)
|
||||
@ -18,7 +19,7 @@ func New() *AS65 {
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *AS65) ParseInstr(ctx context.Context, line lines.Line, quick bool) (inst.I, error) {
|
||||
func (a *AS65) ParseInstr(ctx context.Context, line lines.Line, mode flavors.ParseMode) (inst.I, error) {
|
||||
return inst.I{}, nil
|
||||
}
|
||||
|
||||
|
@ -170,11 +170,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
}
|
||||
|
||||
func RelativeAddr(c context.Context, in inst.I, val uint16) (byte, error) {
|
||||
curr, ok := c.GetAddr()
|
||||
if !ok {
|
||||
return 0, in.Errorf("cannot determine current address for '%s'", in.Command)
|
||||
}
|
||||
// Found both current and target addresses
|
||||
curr := c.GetAddr()
|
||||
offset := int32(val) - (int32(curr) + 2)
|
||||
if offset > 127 {
|
||||
return 0, in.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", in.Command, offset, curr+2, val)
|
||||
|
@ -6,8 +6,16 @@ import (
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
)
|
||||
|
||||
type ParseMode int
|
||||
|
||||
const (
|
||||
ParseModeNormal ParseMode = iota
|
||||
ParseModeMacroSave
|
||||
ParseModeInactive
|
||||
)
|
||||
|
||||
type F interface {
|
||||
ParseInstr(ctx context.Context, Line lines.Line, quick bool) (inst.I, error)
|
||||
ParseInstr(ctx context.Context, Line lines.Line, mode ParseMode) (inst.I, error)
|
||||
DefaultOrigin() uint16
|
||||
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
|
||||
LocalMacroLabels() bool
|
||||
|
@ -42,7 +42,7 @@ func New() *Merlin {
|
||||
m.DefaultOriginVal = 0x8000
|
||||
|
||||
m.Directives = map[string]oldschool.DirectiveInfo{
|
||||
"ORG": {inst.TypeOrg, m.ParseAddress, 0},
|
||||
"ORG": {inst.TypeOrg, m.ParseOrg, 0},
|
||||
"OBJ": {inst.TypeNone, nil, 0},
|
||||
"ENDASM": {inst.TypeEnd, m.ParseNoArgDir, 0},
|
||||
"=": {inst.TypeEqu, m.ParseEquate, inst.VarEquNormal},
|
||||
@ -66,6 +66,11 @@ func New() *Merlin {
|
||||
"PUT": {inst.TypeInclude, m.ParseInclude, 0},
|
||||
"USE": {inst.TypeInclude, m.ParseInclude, 0},
|
||||
}
|
||||
|
||||
m.EquateDirectives = map[string]bool{
|
||||
"=": true,
|
||||
}
|
||||
|
||||
m.Operators = map[string]expr.Operator{
|
||||
"*": expr.OpMul,
|
||||
"/": expr.OpDiv,
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/zellyn/go6502/asm/context"
|
||||
"github.com/zellyn/go6502/asm/expr"
|
||||
"github.com/zellyn/go6502/asm/flavors"
|
||||
"github.com/zellyn/go6502/asm/flavors/common"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
@ -44,6 +45,7 @@ type Base struct {
|
||||
Name string
|
||||
Directives map[string]DirectiveInfo
|
||||
Operators map[string]expr.Operator
|
||||
EquateDirectives map[string]bool
|
||||
LabelChars string
|
||||
LabelColons Requiredness
|
||||
ExplicitARegister Requiredness
|
||||
@ -76,7 +78,7 @@ func (a *Base) String() string {
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *Base) ParseInstr(ctx context.Context, line lines.Line, quick bool) (inst.I, error) {
|
||||
func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.ParseMode) (inst.I, error) {
|
||||
lp := line.Parse
|
||||
in := inst.I{Line: &line}
|
||||
|
||||
@ -124,49 +126,87 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, quick bool) (ins
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the label: munge for macros, relative labels, etc.
|
||||
// If appropriate, set the last parent label.
|
||||
if !quick {
|
||||
parent := a.IsNewParentLabel(in.Label)
|
||||
newL, err := a.FixLabel(ctx, in.Label)
|
||||
if err != nil {
|
||||
return in, in.Errorf("%v", err)
|
||||
}
|
||||
in.Label = newL
|
||||
if parent {
|
||||
ctx.SetLastLabel(in.Label)
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore whitespace at the start or after the label.
|
||||
lp.IgnoreRun(Whitespace)
|
||||
|
||||
if lp.Peek() == lines.Eol || lp.Peek() == a.CommentChar {
|
||||
in.Type = inst.TypeNone
|
||||
if mode == flavors.ParseModeNormal {
|
||||
if err := a.handleLabel(ctx, in); err != nil {
|
||||
return in, err
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
return a.parseCmd(ctx, in, lp, quick)
|
||||
return a.parseCmd(ctx, in, lp, mode)
|
||||
}
|
||||
|
||||
func (a *Base) handleLabel(ctx context.Context, in inst.I) error {
|
||||
if in.Label == "" {
|
||||
return nil
|
||||
}
|
||||
addr := ctx.GetAddr()
|
||||
|
||||
// Munge for macros, relative labels, etc. If appropriate,
|
||||
// set the last parent label.
|
||||
parent := a.IsNewParentLabel(in.Label)
|
||||
newL, err := a.FixLabel(ctx, in.Label)
|
||||
if err != nil {
|
||||
return in.Errorf("%v", err)
|
||||
}
|
||||
in.Label = newL
|
||||
if parent {
|
||||
ctx.SetLastLabel(in.Label)
|
||||
}
|
||||
|
||||
lval, lok := ctx.Get(in.Label)
|
||||
if lok && addr != lval {
|
||||
return in.Errorf("Trying to set label '%s' to $%04x, but it already has value $%04x", in.Label, addr, lval)
|
||||
}
|
||||
ctx.Set(in.Label, addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseCmd parses the "command" part of an instruction: we expect to be
|
||||
// looking at a non-whitespace character.
|
||||
func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, quick bool) (inst.I, error) {
|
||||
func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode flavors.ParseMode) (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)
|
||||
}
|
||||
in.Command = lp.Emit()
|
||||
|
||||
if quick {
|
||||
if mode == flavors.ParseModeMacroSave {
|
||||
// all we care about is labels (already covered) and end-of-macro.
|
||||
if dir, ok := a.Directives[in.Command]; ok {
|
||||
if dir.Type == inst.TypeMacroEnd {
|
||||
in.Type = inst.TypeMacroEnd
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
|
||||
return in, nil
|
||||
}
|
||||
|
||||
if mode == flavors.ParseModeInactive {
|
||||
// all we care about are endif and else.
|
||||
if dir, ok := a.Directives[in.Command]; ok {
|
||||
if dir.Type == inst.TypeIfdefElse || dir.Type == inst.TypeIfdefEnd {
|
||||
in.Type = dir.Type
|
||||
// It's weird, but handle labels on else/endif lines.
|
||||
if err := a.handleLabel(ctx, in); err != nil {
|
||||
return in, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// We don't need to handle labels if it's an equate.
|
||||
if !a.EquateDirectives[in.Command] {
|
||||
if err := a.handleLabel(ctx, in); err != nil {
|
||||
return in, err
|
||||
}
|
||||
}
|
||||
|
||||
// Give ParseMacroCall a chance
|
||||
if a.ParseMacroCall != nil {
|
||||
i, isMacro, err := a.ParseMacroCall(ctx, in, lp)
|
||||
@ -269,6 +309,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(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]
|
||||
@ -373,16 +414,21 @@ func (a *Base) parseOpArgs(ctx context.Context, in inst.I, lp *lines.Parse, summ
|
||||
return common.DecodeOp(ctx, in, summary, indirect, xy, forceWide)
|
||||
}
|
||||
|
||||
func (a *Base) ParseAddress(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) ParseOrg(ctx context.Context, in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
lp.IgnoreRun(Whitespace)
|
||||
expr, err := a.parseExpression(ctx, in, lp)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
in.Exprs = append(in.Exprs, expr)
|
||||
val, err := expr.Eval(ctx, in.Line)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
in.WidthKnown = true
|
||||
in.Width = 0
|
||||
in.Final = true
|
||||
in.Addr = val
|
||||
return in, nil
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ func newRedbook(name string) *RedBook {
|
||||
r.DefaultOriginVal = 0x0800
|
||||
|
||||
r.Directives = map[string]oldschool.DirectiveInfo{
|
||||
"ORG": {inst.TypeOrg, r.ParseAddress, 0},
|
||||
"ORG": {inst.TypeOrg, r.ParseOrg, 0},
|
||||
"OBJ": {inst.TypeNone, nil, 0},
|
||||
"ENDASM": {inst.TypeEnd, r.ParseNoArgDir, 0},
|
||||
"EQU": {inst.TypeEqu, r.ParseEquate, inst.VarEquNormal},
|
||||
@ -59,6 +59,12 @@ func newRedbook(name string) *RedBook {
|
||||
"REP": {inst.TypeNone, nil, 0}, // Repeat character
|
||||
"CHR": {inst.TypeNone, nil, 0}, // Set repeated character
|
||||
}
|
||||
|
||||
r.EquateDirectives = map[string]bool{
|
||||
"EQU": true,
|
||||
"EPZ": true,
|
||||
}
|
||||
|
||||
r.Operators = map[string]expr.Operator{
|
||||
"*": expr.OpMul,
|
||||
"/": expr.OpDiv,
|
||||
|
@ -36,7 +36,7 @@ func New() *SCMA {
|
||||
|
||||
a.Directives = map[string]oldschool.DirectiveInfo{
|
||||
".IN": {inst.TypeInclude, a.ParseInclude, 0},
|
||||
".OR": {inst.TypeOrg, a.ParseAddress, 0},
|
||||
".OR": {inst.TypeOrg, a.ParseOrg, 0},
|
||||
".TA": {inst.TypeTarget, a.ParseNotImplemented, 0},
|
||||
".TF": {inst.TypeNone, nil, 0},
|
||||
".EN": {inst.TypeEnd, a.ParseNoArgDir, 0},
|
||||
@ -56,6 +56,11 @@ func New() *SCMA {
|
||||
".EM": {inst.TypeMacroEnd, a.ParseNoArgDir, 0},
|
||||
".US": {inst.TypeNone, a.ParseNotImplemented, 0},
|
||||
}
|
||||
|
||||
a.EquateDirectives = map[string]bool{
|
||||
".EQ": true,
|
||||
}
|
||||
|
||||
a.Operators = map[string]expr.Operator{
|
||||
"*": expr.OpMul,
|
||||
"/": expr.OpDiv,
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/zellyn/go6502/asm/flavors/merlin"
|
||||
"github.com/zellyn/go6502/asm/flavors/redbook"
|
||||
"github.com/zellyn/go6502/asm/flavors/scma"
|
||||
"github.com/zellyn/go6502/asm/inst"
|
||||
"github.com/zellyn/go6502/asm/lines"
|
||||
)
|
||||
|
||||
@ -233,26 +234,29 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
ctx.AddMacroName("M1")
|
||||
tt.f.InitContext(ctx)
|
||||
|
||||
inst, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), false)
|
||||
in, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), flavors.ParseModeNormal)
|
||||
if err != nil {
|
||||
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)
|
||||
if in.Line.Parse == nil {
|
||||
t.Errorf("Got empty in.Line.Parse on input '%s'", tt.i)
|
||||
}
|
||||
_, err = inst.Compute(ctx, true)
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, inst, err)
|
||||
continue
|
||||
if in.Type != inst.TypeOrg {
|
||||
_, err = in.Compute(ctx, true)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, in, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if inst.String() != tt.p {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") = %s; want %s`, i, tt.f, tt.i, inst.String(), tt.p)
|
||||
if in.String() != tt.p {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") = %s; want %s`, i, tt.f, tt.i, in.String(), tt.p)
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.b != "?" {
|
||||
hx := hex.EncodeToString(inst.Data)
|
||||
hx := hex.EncodeToString(in.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.f, tt.i, hx, tt.b)
|
||||
@ -261,12 +265,12 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
|
||||
// Check length
|
||||
w := uint16(len(tt.b) / 2)
|
||||
if !inst.WidthKnown {
|
||||
t.Errorf(`%d. %s.WidthKnown is false`, i, inst)
|
||||
if !in.WidthKnown {
|
||||
t.Errorf(`%d. %s.WidthKnown is false`, i, in)
|
||||
continue
|
||||
}
|
||||
if inst.Width != w {
|
||||
t.Errorf(`%d. %s.Width=%d; want %d`, i, inst, inst.Width, w)
|
||||
if in.Width != w {
|
||||
t.Errorf(`%d. %s.Width=%d; want %d`, i, in, in.Width, w)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -297,9 +301,9 @@ func TestSimpleErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
ctx := &context.SimpleContext{}
|
||||
inst, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), false)
|
||||
in, err := tt.f.ParseInstr(ctx, lines.NewSimple(tt.i), flavors.ParseModeNormal)
|
||||
if err == nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") want err; got %s`, i, tt.f, tt.i, inst)
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") want err; got %s`, i, tt.f, tt.i, in)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -192,11 +192,13 @@ func (i I) String() string {
|
||||
|
||||
// Compute attempts to finalize the instruction.
|
||||
func (i *I) Compute(c context.Context, final bool) (bool, error) {
|
||||
if i.Type == TypeEqu || i.Type == TypeTarget || i.Type == TypeOrg {
|
||||
return i.computeMustKnow(c, final)
|
||||
// xyzzy - remove
|
||||
if i.Type == TypeOrg {
|
||||
panic("Compute called with TypeOrg")
|
||||
return true, nil
|
||||
}
|
||||
if err := i.computeLabel(c, final); err != nil {
|
||||
return false, err
|
||||
if i.Type == TypeEqu || i.Type == TypeTarget {
|
||||
return i.computeMustKnow(c, final)
|
||||
}
|
||||
if i.Final {
|
||||
return true, nil
|
||||
@ -218,29 +220,6 @@ func (i *I) Compute(c context.Context, final bool) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// computeLabel attempts to compute label values.
|
||||
func (i *I) computeLabel(c context.Context, final bool) error {
|
||||
if i.Label == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.Type == TypeEqu {
|
||||
panic("computeLabel should not be called for equates")
|
||||
}
|
||||
|
||||
addr, aok := c.GetAddr()
|
||||
if !aok {
|
||||
return nil
|
||||
}
|
||||
|
||||
lval, lok := c.Get(i.Label)
|
||||
if lok && addr != lval {
|
||||
return i.Errorf("Trying to set label '%s' to $%04x, but it already has value $%04x", i.Label, addr, lval)
|
||||
}
|
||||
c.Set(i.Label, addr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
if len(i.Data) > 0 {
|
||||
i.WidthKnown = true
|
||||
@ -335,9 +314,6 @@ func (i *I) computeMustKnow(c context.Context, final bool) (bool, error) {
|
||||
// Don't handle labels.
|
||||
return true, nil
|
||||
}
|
||||
if err := i.computeLabel(c, final); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -401,14 +377,7 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
|
||||
|
||||
// It's a branch
|
||||
if i.Mode == opcodes.MODE_RELATIVE {
|
||||
curr, ok := c.GetAddr()
|
||||
if !ok {
|
||||
if final {
|
||||
return false, i.Errorf("cannot determine current address for '%s'", i.Command)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
// Found both current and target addresses
|
||||
curr := c.GetAddr()
|
||||
offset := int32(val) - (int32(curr) + 2)
|
||||
if offset > 127 {
|
||||
return false, i.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", i.Command, offset, curr+2, val)
|
||||
|
Loading…
Reference in New Issue
Block a user