1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-06-15 18:29:47 +00:00

Only call compute on second pass.

This commit is contained in:
Zellyn Hunter 2014-09-09 17:32:15 -07:00
parent 072a4521de
commit 498b6c5a7d
4 changed files with 49 additions and 86 deletions

View File

@ -71,10 +71,15 @@ func (a *Assembler) Load(filename string, prefix int) error {
return parseErr return parseErr
} }
if _, err := a.passInst(&in, false); err != nil { if in.Type == inst.TypeOrg {
return err a.Ctx.SetAddr(in.Addr)
} }
// Update address
addr := a.Ctx.GetAddr()
in.Addr = addr
a.Ctx.SetAddr(addr + in.Width)
switch in.Type { switch in.Type {
case inst.TypeUnknown: case inst.TypeUnknown:
if parseErr != nil { if parseErr != nil {
@ -200,41 +205,26 @@ func (a *Assembler) initPass() {
a.Ctx.SetAddr(a.Flavor.DefaultOrigin()) a.Ctx.SetAddr(a.Flavor.DefaultOrigin())
} }
// passInst performs a pass on a single instruction. It forces the
// instruction to decide its width, but may not know all the
// 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()
in.Addr = addr
a.Ctx.SetAddr(addr + in.Width)
return isFinal, nil
}
// Pass2 performs the second assembly pass. It returns an error for // Pass2 performs the second assembly pass. It returns an error for
// any instruction that cannot be finalized. // any instruction that cannot be finalized.
func (a *Assembler) Pass2() error { func (a *Assembler) Pass2() error {
a.initPass() a.initPass()
for _, in := range a.Insts { for _, in := range a.Insts {
instFinal, err := a.passInst(in, true) if in.Type == inst.TypeOrg {
a.Ctx.SetAddr(in.Addr)
continue
}
err := in.Compute(a.Ctx)
if err != nil { if err != nil {
return err return err
} }
if !instFinal {
return in.Errorf("cannot finalize instruction: %s", in) // Update address
} addr := a.Ctx.GetAddr()
in.Addr = addr
a.Ctx.SetAddr(addr + in.Width)
} }
return nil return nil

View File

@ -581,11 +581,11 @@ func (a *Base) ParseEquate(ctx context.Context, in inst.I, lp *lines.Parse) (ins
return in, err return in, err
} }
xyzzy, err := expr.Eval(ctx, in.Line) val, err := expr.Eval(ctx, in.Line)
if err != nil { if err != nil {
return in, err return in, err
} }
_ = xyzzy ctx.Set(in.Label, val)
in.Exprs = append(in.Exprs, expr) in.Exprs = append(in.Exprs, expr)
in.Width = 0 in.Width = 0
in.Final = true in.Final = true

View File

@ -248,10 +248,8 @@ func TestSimpleCommonFunctions(t *testing.T) {
ctx.Set("L5", 0xcdef) ctx.Set("L5", 0xcdef)
if in.Type != inst.TypeOrg { if in.Type != inst.TypeOrg {
_, err = in.Compute(ctx, true) if err = in.Compute(ctx); err != nil {
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f) => error: %s`, i, tt.f, tt.i, in, err)
if err != nil {
t.Errorf(`%d. %s.ParseInstr("%s"): %s.Compute(tt.f, true) => error: %s`, i, tt.f, tt.i, in, err)
continue continue
} }
} }

View File

@ -191,42 +191,36 @@ func (i I) String() string {
} }
// Compute attempts to finalize the instruction. // Compute attempts to finalize the instruction.
func (i *I) Compute(c context.Context, final bool) (bool, error) { func (i *I) Compute(c context.Context) error {
// xyzzy - remove
if i.Type == TypeOrg {
panic("Compute called with TypeOrg")
return true, nil
}
if i.Type == TypeEqu || i.Type == TypeTarget { if i.Type == TypeEqu || i.Type == TypeTarget {
return i.computeMustKnow(c, final) return i.computeMustKnow(c)
} }
if i.Final { if i.Final {
return true, nil return nil
} }
switch i.Type { switch i.Type {
case TypeOp: case TypeOp:
return i.computeOp(c, final) return i.computeOp(c)
case TypeData: case TypeData:
return i.computeData(c, final) return i.computeData(c)
case TypeBlock: case TypeBlock:
return i.computeBlock(c, final) panic("Compute called with TypeBlock")
} }
// Everything else is zero-width // Everything else is zero-width
i.Width = 0 i.Width = 0
i.Final = true i.Final = true
return true, nil return nil
} }
func (i *I) computeData(c context.Context, final bool) (bool, error) { func (i *I) computeData(c context.Context) error {
if len(i.Data) > 0 { if len(i.Data) > 0 {
i.Width = uint16(len(i.Data)) i.Width = uint16(len(i.Data))
i.Final = true i.Final = true
return true, nil return nil
} }
allFinal := true
data := []byte{} data := []byte{}
var width uint16 var width uint16
for _, e := range i.Exprs { for _, e := range i.Exprs {
@ -240,15 +234,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
w = 2 w = 2
} }
width += w width += w
val, labelMissing, err := e.CheckedEval(c, i.Line) val, err := e.Eval(c, i.Line)
if err != nil && !labelMissing { if err != nil {
return false, err return err
}
if labelMissing {
allFinal = false
if final {
return false, err
}
} }
switch i.Var { switch i.Var {
case VarMixed: case VarMixed:
@ -269,12 +257,9 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
} }
} }
i.Width = width i.Width = width
if allFinal { i.Data = data
i.Data = data i.Final = true
i.Final = true return nil
}
return i.Final, nil
} }
func (i *I) computeBlock(c context.Context, final bool) (bool, error) { func (i *I) computeBlock(c context.Context, final bool) (bool, error) {
@ -291,46 +276,36 @@ func (i *I) computeBlock(c context.Context, final bool) (bool, error) {
return i.Final, nil return i.Final, nil
} }
func (i *I) computeMustKnow(c context.Context, final bool) (bool, error) { func (i *I) computeMustKnow(c context.Context) error {
i.Width = 0 i.Width = 0
i.Final = true i.Final = true
val, err := i.Exprs[0].Eval(c, i.Line) val, err := i.Exprs[0].Eval(c, i.Line)
if err != nil { if err != nil {
return false, err return err
} }
i.Value = val i.Value = val
switch i.Type { switch i.Type {
case TypeTarget: case TypeTarget:
return false, errors.New("Target not implemented yet.") return errors.New("Target not implemented yet.")
case TypeOrg: case TypeOrg:
c.SetAddr(val) c.SetAddr(val)
case TypeEqu: case TypeEqu:
c.Set(i.Label, val) c.Set(i.Label, val)
// Don't handle labels. // Don't handle labels.
return true, nil return nil
} }
return true, nil return nil
} }
func (i *I) computeOp(c context.Context, final bool) (bool, error) { func (i *I) computeOp(c context.Context) error {
// If the width is not known, we better have a ZeroPage alternative.
// An op with no args would be final already, so we must have an Expression. // An op with no args would be final already, so we must have an Expression.
if len(i.Exprs) == 0 { if len(i.Exprs) == 0 {
panic(fmt.Sprintf("Reached computeOp for '%s' with no expressions", i.Command)) panic(fmt.Sprintf("Reached computeOp for '%s' with no expressions", i.Command))
} }
val, labelMissing, err := i.Exprs[0].CheckedEval(c, i.Line) val, err := i.Exprs[0].Eval(c, i.Line)
// A real error // A real error
if !labelMissing && err != nil { if err != nil {
return false, err return err
}
if labelMissing {
// Don't know, do care.
if final {
return false, err
}
return false, nil
} }
// If we got here, we got an actual value. // If we got here, we got an actual value.
@ -340,10 +315,10 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
curr := c.GetAddr() curr := c.GetAddr()
offset := int32(val) - (int32(curr) + 2) offset := int32(val) - (int32(curr) + 2)
if offset > 127 { if offset > 127 {
return false, i.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", i.Command, offset, curr+2, val) return i.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", i.Command, offset, curr+2, val)
} }
if offset < -128 { if offset < -128 {
return false, i.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", i.Command, offset, curr+2, val) return i.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", i.Command, offset, curr+2, val)
} }
val = uint16(offset) val = uint16(offset)
} }
@ -359,7 +334,7 @@ func (i *I) computeOp(c context.Context, final bool) (bool, error) {
default: default:
panic(fmt.Sprintf("computeOp reached erroneously for '%s'", i.Command)) panic(fmt.Sprintf("computeOp reached erroneously for '%s'", i.Command))
} }
return true, nil return nil
} }
func (i I) Errorf(format string, a ...interface{}) error { func (i I) Errorf(format string, a ...interface{}) error {