Working on finalizing width on pass1

This commit is contained in:
Zellyn Hunter 2014-09-04 17:48:11 -07:00
parent c07a3732a6
commit ddc6d85b46
5 changed files with 120 additions and 8 deletions

View File

@ -71,6 +71,10 @@ func (a *Assembler) Load(filename string, prefix int) error {
return parseErr
}
if mode == flavors.ParseModeNormal && !in.WidthKnown {
return in.Errorf("Width unknown")
}
if _, err := a.passInst(&in, false); err != nil {
return err
}

View File

@ -32,6 +32,11 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.WidthKnown = true
in.Width = 2
in.Mode = opcodes.MODE_INDIRECT_X
in.Var = inst.VarOpByte
if valKnown {
in.Final = true
in.Data = []byte{in.Op, byte(val)}
}
return in, nil
case 'y':
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_Y)
@ -45,6 +50,11 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.Width = 2
in.Mode = opcodes.MODE_INDIRECT_Y
in.Op = op.Byte
in.Var = inst.VarOpByte
if valKnown {
in.Final = true
in.Data = []byte{in.Op, byte(val)}
}
return in, nil
default:
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT)
@ -55,6 +65,11 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.WidthKnown = true
in.Width = 3
in.Mode = opcodes.MODE_INDIRECT
in.Var = inst.VarOpWord
if valKnown {
in.Final = true
in.Data = []byte{in.Op, byte(val), byte(val >> 8)}
}
return in, nil
}
}
@ -73,7 +88,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.WidthKnown = true
in.Width = 2
in.Mode = opcodes.MODE_RELATIVE
in.Var = inst.VarRelative
in.Var = inst.VarOpBranch
if valKnown {
b, err := RelativeAddr(c, in, val)
if err != nil {
@ -82,7 +97,6 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.Data = []byte{in.Op, b}
in.Final = true
}
return in, nil
}
@ -96,8 +110,11 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
in.WidthKnown = true
in.Width = 2
in.Mode = opcodes.MODE_IMMEDIATE
in.Var = inst.VarBytes
//xyzzy()
in.Var = inst.VarOpByte
if valKnown {
in.Data = []byte{in.Op, byte(val)}
in.Final = true
}
return in, nil
}

View File

@ -101,6 +101,9 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par
// Flavor considers this line extra commenty for some reason?
if a.ExtraCommenty != nil && a.ExtraCommenty(lp.Rest()) {
in.Type = inst.TypeNone
in.Final = true
in.WidthKnown = true
in.Width = 0
return in, nil
}
@ -108,6 +111,9 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par
trimmed := strings.TrimSpace(lp.Rest())
if trimmed == "" || trimmed[0] == '*' || rune(trimmed[0]) == a.CommentChar {
in.Type = inst.TypeNone
in.Final = true
in.WidthKnown = true
in.Width = 0
return in, nil
}
@ -136,6 +142,9 @@ func (a *Base) ParseInstr(ctx context.Context, line lines.Line, mode flavors.Par
return in, err
}
}
in.Final = true
in.WidthKnown = true
in.Width = 0
return in, nil
}
return a.parseCmd(ctx, in, lp, mode)
@ -179,9 +188,7 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl
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
}
in.Type = dir.Type
}
return in, nil
}
@ -189,8 +196,8 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl
if mode == flavors.ParseModeInactive {
// all we care about are endif and else.
if dir, ok := a.Directives[in.Command]; ok {
in.Type = dir.Type
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
@ -214,6 +221,9 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl
return in, err
}
if isMacro {
i.WidthKnown = true
i.Width = 0
i.Final = true
return i, nil
}
}
@ -222,6 +232,9 @@ func (a *Base) parseCmd(ctx context.Context, in inst.I, lp *lines.Parse, mode fl
in.Type = dir.Type
in.Var = dir.Var
if dir.Func == nil {
in.WidthKnown = true
in.Width = 0
in.Final = true
return in, nil
}
return dir.Func(ctx, in, lp)
@ -265,6 +278,9 @@ func (a *Base) parseSetting(ctx context.Context, in inst.I, lp *lines.Parse) (in
default:
return in, in.Errorf("expecting ON/OFF, found '%s'", in.TextArg)
}
in.WidthKnown = true
in.Width = 0
in.Final = true
return in, nil
}
@ -466,6 +482,9 @@ func (a *Base) ParseAscii(ctx context.Context, in inst.I, lp *lines.Parse) (inst
in.Data[i] ^= invertLast
}
}
in.Width = uint16(len(in.Data))
in.WidthKnown = true
in.Final = true
return in, nil
}
@ -476,6 +495,14 @@ func (a *Base) ParseBlockStorage(ctx context.Context, in inst.I, lp *lines.Parse
return in, err
}
in.Exprs = append(in.Exprs, ex)
val, err := ex.Eval(ctx, in.Line)
if err != nil {
return in, in.Errorf("Cannot evaluate size of block storage on first pass")
}
in.WidthKnown = true
in.Final = true
in.Width = val
return in, nil
}
@ -491,6 +518,60 @@ func (a *Base) ParseData(ctx context.Context, in inst.I, lp *lines.Parse) (inst.
break
}
}
switch in.Var {
case inst.VarBytes:
in.WidthKnown = true
in.Width = uint16(len(in.Exprs))
in.Final = true
for _, expr := range in.Exprs {
val, err := expr.Eval(ctx, in.Line)
if err != nil {
in.Final = false
in.Data = nil
}
in.Data = append(in.Data, byte(val))
}
case inst.VarWordsLe, inst.VarWordsBe:
in.WidthKnown = true
in.Width = 2 * uint16(len(in.Exprs))
in.Final = true
for _, expr := range in.Exprs {
val, err := expr.Eval(ctx, in.Line)
if err != nil {
in.Final = false
in.Data = nil
}
if in.Var == inst.VarWordsLe {
in.Data = append(in.Data, byte(val), byte(val>>8))
} else {
in.Data = append(in.Data, byte(val>>8), byte(val))
}
}
case inst.VarMixed:
in.WidthKnown = true
in.Final = true
for _, expr := range in.Exprs {
in.Width += expr.Width()
val, err := expr.Eval(ctx, in.Line)
if err != nil {
in.Final = false
in.Data = nil
} else {
if in.Final {
switch expr.Width() {
case 1:
in.Data = append(in.Data, byte(val))
case 2:
in.Data = append(in.Data, byte(val), byte(val>>8))
default:
return in, in.Errorf("Unsupported expression width: %d", expr.Width())
}
}
}
}
default:
return in, in.Errorf("Unknown Var(%d) with ParseData for %s", in.Var, in.Command)
}
return in, nil
}
@ -548,6 +629,9 @@ func (a *Base) ParseHexString(ctx context.Context, in inst.I, lp *lines.Parse) (
break
}
}
in.WidthKnown = true
in.Width = uint16(len(in.Data))
in.Final = true
return in, nil
}

View File

@ -239,6 +239,10 @@ func TestSimpleCommonFunctions(t *testing.T) {
t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.f, tt.i, err)
continue
}
if !in.WidthKnown {
t.Errorf(`%d. %s.ParseInstr("%s") => WidthKnown=false`, i, tt.f, tt.i)
continue
}
if in.Line.Parse == nil {
t.Errorf("Got empty in.Line.Parse on input '%s'", tt.i)
}

View File

@ -53,6 +53,9 @@ const (
VarRelative // For branches: a one-byte relative address
VarEquNormal // Equ: a normal equate
VarEquPageZero // Equ: a page-zero equate
VarOpByte // An op with a one-byte argument
VarOpWord // An op with a one-word argument
VarOpBranch // An op with a one-byte relative address argument
)
type I struct {