Changed for to not implement DOWNTO.
This commit is contained in:
parent
ee74135839
commit
4f51572477
4 changed files with 64 additions and 252 deletions
|
|
@ -11,15 +11,12 @@ import (
|
||||||
|
|
||||||
// ForCommand handles FOR loop statements
|
// ForCommand handles FOR loop statements
|
||||||
// Syntax: FOR <var> = <start> TO <end> [STEP <step>]
|
// Syntax: FOR <var> = <start> TO <end> [STEP <step>]
|
||||||
//
|
|
||||||
// FOR <var> = <start> DOWNTO <end> [STEP <step>]
|
|
||||||
type ForCommand struct {
|
type ForCommand struct {
|
||||||
varName string
|
varName string
|
||||||
varKind compiler.VarKind
|
varKind compiler.VarKind
|
||||||
startOp *compiler.OperandInfo
|
startOp *compiler.OperandInfo
|
||||||
endOp *compiler.OperandInfo
|
endOp *compiler.OperandInfo
|
||||||
stepOp *compiler.OperandInfo
|
stepOp *compiler.OperandInfo
|
||||||
isDownto bool
|
|
||||||
useLongJump bool
|
useLongJump bool
|
||||||
loopLabel string
|
loopLabel string
|
||||||
skipLabel string
|
skipLabel string
|
||||||
|
|
@ -90,12 +87,11 @@ func (c *ForCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
||||||
IsVar: startIsVar,
|
IsVar: startIsVar,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse direction (TO or DOWNTO)
|
// Parse direction (TO only)
|
||||||
direction := strings.ToUpper(params[4])
|
direction := strings.ToUpper(params[4])
|
||||||
if direction != "TO" && direction != "DOWNTO" {
|
if direction != "TO" {
|
||||||
return fmt.Errorf("FOR: expected 'TO' or 'DOWNTO' at position 5, got %q", params[4])
|
return fmt.Errorf("FOR: expected 'TO' at position 5, got %q (DOWNTO is not supported)", params[4])
|
||||||
}
|
}
|
||||||
c.isDownto = (direction == "DOWNTO")
|
|
||||||
|
|
||||||
// Parse end value
|
// Parse end value
|
||||||
endVarName, endVarKind, endValue, endIsVar, parseErr := compiler.ParseOperandParam(
|
endVarName, endVarKind, endValue, endIsVar, parseErr := compiler.ParseOperandParam(
|
||||||
|
|
@ -161,7 +157,6 @@ func (c *ForCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
||||||
VarKind: c.varKind,
|
VarKind: c.varKind,
|
||||||
EndOperand: c.endOp,
|
EndOperand: c.endOp,
|
||||||
StepOperand: c.stepOp,
|
StepOperand: c.stepOp,
|
||||||
IsDownto: c.isDownto,
|
|
||||||
LoopLabel: c.loopLabel,
|
LoopLabel: c.loopLabel,
|
||||||
SkipLabel: c.skipLabel,
|
SkipLabel: c.skipLabel,
|
||||||
})
|
})
|
||||||
|
|
@ -179,16 +174,7 @@ func (c *ForCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) {
|
||||||
// Emit loop label
|
// Emit loop label
|
||||||
asm = append(asm, c.loopLabel)
|
asm = append(asm, c.loopLabel)
|
||||||
|
|
||||||
// Generate comparison
|
// Generate comparison for TO loop: continue if var <= end (skip if var > end)
|
||||||
// TO: continue if var <= end (skip if var > end)
|
|
||||||
// DOWNTO: continue if var >= end (skip if var < end)
|
|
||||||
var op comparisonOp
|
|
||||||
if c.isDownto {
|
|
||||||
op = opGreaterEqual // skip if var < end
|
|
||||||
} else {
|
|
||||||
op = opLessEqual // skip if var > end
|
|
||||||
}
|
|
||||||
|
|
||||||
varOp := &operandInfo{
|
varOp := &operandInfo{
|
||||||
varName: c.varName,
|
varName: c.varName,
|
||||||
varKind: c.varKind,
|
varKind: c.varKind,
|
||||||
|
|
@ -204,7 +190,7 @@ func (c *ForCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gen, err := newComparisonGenerator(
|
gen, err := newComparisonGenerator(
|
||||||
op,
|
opLessEqual,
|
||||||
varOp,
|
varOp,
|
||||||
endOp,
|
endOp,
|
||||||
c.useLongJump,
|
c.useLongJump,
|
||||||
|
|
@ -231,14 +217,14 @@ func (c *ForCommand) generateAssignment() []string {
|
||||||
if c.startOp.IsVar {
|
if c.startOp.IsVar {
|
||||||
// Destination: byte
|
// Destination: byte
|
||||||
if c.varKind == compiler.KindByte {
|
if c.varKind == compiler.KindByte {
|
||||||
// byte → byte or word → byte (take low byte)
|
// byte → byte or word → byte (take low byte)
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
||||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
||||||
return asm
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination: word
|
// Destination: word
|
||||||
// byte → word (zero-extend)
|
// byte → word (zero-extend)
|
||||||
if c.startOp.VarKind == compiler.KindByte {
|
if c.startOp.VarKind == compiler.KindByte {
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
||||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
||||||
|
|
@ -247,7 +233,7 @@ func (c *ForCommand) generateAssignment() []string {
|
||||||
return asm
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
// word → word (copy both bytes)
|
// word → word (copy both bytes)
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
asm = append(asm, fmt.Sprintf("\tlda %s", c.startOp.VarName))
|
||||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
asm = append(asm, fmt.Sprintf("\tsta %s", c.varName))
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s+1", c.startOp.VarName))
|
asm = append(asm, fmt.Sprintf("\tlda %s+1", c.startOp.VarName))
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,9 @@ func TestForBasicTO(t *testing.T) {
|
||||||
"\tlda #$00",
|
"\tlda #$00",
|
||||||
"\tsta i",
|
"\tsta i",
|
||||||
"_LOOPSTART1",
|
"_LOOPSTART1",
|
||||||
"\tlda i",
|
"\tlda #$0a",
|
||||||
"\tcmp #$0a",
|
"\tcmp i",
|
||||||
"\tbeq _L1",
|
"\tbcc _LOOPEND1",
|
||||||
"\tbcc _L1",
|
|
||||||
"\tjmp _LOOPEND1",
|
|
||||||
"_L1",
|
|
||||||
},
|
},
|
||||||
wantNext: []string{
|
wantNext: []string{
|
||||||
"\tinc i",
|
"\tinc i",
|
||||||
|
|
@ -50,135 +47,20 @@ func TestForBasicTO(t *testing.T) {
|
||||||
"\tsta counter",
|
"\tsta counter",
|
||||||
"\tsta counter+1",
|
"\tsta counter+1",
|
||||||
"_LOOPSTART1",
|
"_LOOPSTART1",
|
||||||
"\tlda counter+1",
|
"\tlda #$03",
|
||||||
"\tcmp #$03",
|
"\tcmp counter+1",
|
||||||
"\tbcc _L1",
|
"\tbcc _LOOPEND1",
|
||||||
"\tbne _L2",
|
"\tbne _L1",
|
||||||
"\tlda counter",
|
"\tlda #$e8",
|
||||||
"\tcmp #$e8",
|
"\tcmp counter",
|
||||||
"\tbeq _L1",
|
"\tbcc _LOOPEND1",
|
||||||
"\tbcc _L1",
|
|
||||||
"_L2",
|
|
||||||
"\tjmp _LOOPEND1",
|
|
||||||
"_L1",
|
"_L1",
|
||||||
},
|
},
|
||||||
wantNext: []string{
|
wantNext: []string{
|
||||||
"\tinc counter",
|
"\tinc counter",
|
||||||
"\tbne _L3",
|
|
||||||
"\tinc counter+1",
|
|
||||||
"_L3",
|
|
||||||
"\tjmp _LOOPSTART1",
|
|
||||||
"_LOOPEND1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
pragma := preproc.NewPragma()
|
|
||||||
ctx := compiler.NewCompilerContext(pragma)
|
|
||||||
tt.setupVars(ctx.SymbolTable)
|
|
||||||
|
|
||||||
forCmd := &ForCommand{}
|
|
||||||
nextCmd := &NextCommand{}
|
|
||||||
|
|
||||||
forLine := preproc.Line{
|
|
||||||
Text: tt.forLine,
|
|
||||||
Kind: preproc.Source,
|
|
||||||
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
|
||||||
}
|
|
||||||
nextLine := preproc.Line{
|
|
||||||
Text: "NEXT",
|
|
||||||
Kind: preproc.Source,
|
|
||||||
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := forCmd.Interpret(forLine, ctx); err != nil {
|
|
||||||
t.Fatalf("FOR Interpret() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
forAsm, err := forCmd.Generate(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("FOR Generate() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := nextCmd.Interpret(nextLine, ctx); err != nil {
|
|
||||||
t.Fatalf("NEXT Interpret() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nextAsm, err := nextCmd.Generate(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("NEXT Generate() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !equalAsm(forAsm, tt.wantFor) {
|
|
||||||
t.Errorf("FOR Generate() mismatch\ngot:\n%s\nwant:\n%s",
|
|
||||||
strings.Join(forAsm, "\n"),
|
|
||||||
strings.Join(tt.wantFor, "\n"))
|
|
||||||
}
|
|
||||||
if !equalAsm(nextAsm, tt.wantNext) {
|
|
||||||
t.Errorf("NEXT Generate() mismatch\ngot:\n%s\nwant:\n%s",
|
|
||||||
strings.Join(nextAsm, "\n"),
|
|
||||||
strings.Join(tt.wantNext, "\n"))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForBasicDOWNTO(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
forLine string
|
|
||||||
setupVars func(*compiler.SymbolTable)
|
|
||||||
wantFor []string
|
|
||||||
wantNext []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "byte var DOWNTO byte literal",
|
|
||||||
forLine: "FOR i = 10 DOWNTO 0",
|
|
||||||
setupVars: func(st *compiler.SymbolTable) {
|
|
||||||
st.AddVar("i", "", compiler.KindByte, 0)
|
|
||||||
},
|
|
||||||
wantFor: []string{
|
|
||||||
"\tlda #$0a",
|
|
||||||
"\tsta i",
|
|
||||||
"_LOOPSTART1",
|
|
||||||
"\tlda i",
|
|
||||||
"\tbne _L1",
|
|
||||||
"\tjmp _LOOPEND1",
|
|
||||||
"_L1",
|
|
||||||
},
|
|
||||||
wantNext: []string{
|
|
||||||
"\tdec i",
|
|
||||||
"\tjmp _LOOPSTART1",
|
|
||||||
"_LOOPEND1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "word var DOWNTO word literal",
|
|
||||||
forLine: "FOR counter = 1000 DOWNTO 0",
|
|
||||||
setupVars: func(st *compiler.SymbolTable) {
|
|
||||||
st.AddVar("counter", "", compiler.KindWord, 0)
|
|
||||||
},
|
|
||||||
wantFor: []string{
|
|
||||||
"\tlda #$e8",
|
|
||||||
"\tsta counter",
|
|
||||||
"\tlda #$03",
|
|
||||||
"\tsta counter+1",
|
|
||||||
"_LOOPSTART1",
|
|
||||||
"\tlda counter",
|
|
||||||
"\tbne _L1",
|
|
||||||
"\tlda counter+1",
|
|
||||||
"\tbne _L1",
|
|
||||||
"\tjmp _LOOPEND1",
|
|
||||||
"_L1",
|
|
||||||
},
|
|
||||||
wantNext: []string{
|
|
||||||
"\tlda counter",
|
|
||||||
"\tbne _L2",
|
"\tbne _L2",
|
||||||
"\tdec counter+1",
|
"\tinc counter+1",
|
||||||
"_L2",
|
"_L2",
|
||||||
"\tdec counter",
|
|
||||||
"\tjmp _LOOPSTART1",
|
"\tjmp _LOOPSTART1",
|
||||||
"_LOOPEND1",
|
"_LOOPEND1",
|
||||||
},
|
},
|
||||||
|
|
@ -262,23 +144,6 @@ func TestForWithSTEP(t *testing.T) {
|
||||||
},
|
},
|
||||||
description: "STEP 2 should use adc #$02",
|
description: "STEP 2 should use adc #$02",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "byte var DOWNTO with STEP 3",
|
|
||||||
forLine: "FOR i = 10 DOWNTO 0 STEP 3",
|
|
||||||
setupVars: func(st *compiler.SymbolTable) {
|
|
||||||
st.AddVar("i", "", compiler.KindByte, 0)
|
|
||||||
},
|
|
||||||
checkNextAsm: func(asm []string) bool {
|
|
||||||
// Should contain sbc #$03
|
|
||||||
for _, line := range asm {
|
|
||||||
if strings.Contains(line, "sbc #$03") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
description: "STEP 3 should use sbc #$03",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "byte var TO with variable STEP",
|
name: "byte var TO with variable STEP",
|
||||||
forLine: "FOR i = 0 TO 10 STEP stepval",
|
forLine: "FOR i = 0 TO 10 STEP stepval",
|
||||||
|
|
@ -419,7 +284,26 @@ func TestForNested(t *testing.T) {
|
||||||
t.Fatalf("NEXT 1 error = %v", err)
|
t.Fatalf("NEXT 1 error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if asm1[0] == asm2[0] {
|
// Find loop start labels in the generated assembly
|
||||||
|
loopLabel1 := ""
|
||||||
|
loopLabel2 := ""
|
||||||
|
for _, line := range asm1 {
|
||||||
|
if strings.HasPrefix(line, "_LOOPSTART") {
|
||||||
|
loopLabel1 = line
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, line := range asm2 {
|
||||||
|
if strings.HasPrefix(line, "_LOOPSTART") {
|
||||||
|
loopLabel2 = line
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if loopLabel1 == "" || loopLabel2 == "" {
|
||||||
|
t.Fatal("Could not find loop labels")
|
||||||
|
}
|
||||||
|
if loopLabel1 == loopLabel2 {
|
||||||
t.Error("Nested loops should have different labels")
|
t.Error("Nested loops should have different labels")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -562,7 +446,28 @@ func TestForInvalidDirection(t *testing.T) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Should fail with invalid direction keyword")
|
t.Fatal("Should fail with invalid direction keyword")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), "TO") && !strings.Contains(err.Error(), "DOWNTO") {
|
if !strings.Contains(err.Error(), "TO") {
|
||||||
|
t.Errorf("Wrong error message: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForDOWNTORejected(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||||
|
|
||||||
|
cmd := &ForCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: "FOR i = 10 DOWNTO 0",
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cmd.Interpret(line, ctx)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Should fail with DOWNTO")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "not supported") {
|
||||||
t.Errorf("Wrong error message: %v", err)
|
t.Errorf("Wrong error message: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
// NextCommand handles NEXT statements
|
// NextCommand handles NEXT statements
|
||||||
// Syntax: NEXT
|
// Syntax: NEXT
|
||||||
// Increments/decrements loop variable and jumps back to loop start
|
// Increments loop variable and jumps back to loop start
|
||||||
type NextCommand struct {
|
type NextCommand struct {
|
||||||
info *compiler.ForLoopInfo
|
info *compiler.ForLoopInfo
|
||||||
}
|
}
|
||||||
|
|
@ -58,12 +58,8 @@ func (c *NextCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
||||||
func (c *NextCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) {
|
func (c *NextCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
// Generate increment/decrement
|
// Generate increment
|
||||||
if c.info.IsDownto {
|
asm = append(asm, c.generateIncrement(ctx)...)
|
||||||
asm = append(asm, c.generateDecrement(ctx)...)
|
|
||||||
} else {
|
|
||||||
asm = append(asm, c.generateIncrement(ctx)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump back to loop start
|
// Jump back to loop start
|
||||||
asm = append(asm, fmt.Sprintf("\tjmp %s", c.info.LoopLabel))
|
asm = append(asm, fmt.Sprintf("\tjmp %s", c.info.LoopLabel))
|
||||||
|
|
@ -84,16 +80,6 @@ func (c *NextCommand) generateIncrement(ctx *compiler.CompilerContext) []string
|
||||||
return c.generateAdd()
|
return c.generateAdd()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NextCommand) generateDecrement(ctx *compiler.CompilerContext) []string {
|
|
||||||
// Check for step = 1 literal optimization
|
|
||||||
if !c.info.StepOperand.IsVar && c.info.StepOperand.Value == 1 {
|
|
||||||
return c.generateDecrementByOne(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// General case: var = var - step
|
|
||||||
return c.generateSubtract()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *NextCommand) generateIncrementByOne(ctx *compiler.CompilerContext) []string {
|
func (c *NextCommand) generateIncrementByOne(ctx *compiler.CompilerContext) []string {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
|
|
@ -112,25 +98,6 @@ func (c *NextCommand) generateIncrementByOne(ctx *compiler.CompilerContext) []st
|
||||||
return asm
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NextCommand) generateDecrementByOne(ctx *compiler.CompilerContext) []string {
|
|
||||||
var asm []string
|
|
||||||
|
|
||||||
if c.info.VarKind == compiler.KindByte {
|
|
||||||
asm = append(asm, fmt.Sprintf("\tdec %s", c.info.VarName))
|
|
||||||
return asm
|
|
||||||
}
|
|
||||||
|
|
||||||
// Word variable - handle borrow from high byte
|
|
||||||
label := ctx.GeneralStack.Push()
|
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.info.VarName))
|
|
||||||
asm = append(asm, fmt.Sprintf("\tbne %s", label))
|
|
||||||
asm = append(asm, fmt.Sprintf("\tdec %s+1", c.info.VarName))
|
|
||||||
asm = append(asm, label)
|
|
||||||
asm = append(asm, fmt.Sprintf("\tdec %s", c.info.VarName))
|
|
||||||
|
|
||||||
return asm
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *NextCommand) generateAdd() []string {
|
func (c *NextCommand) generateAdd() []string {
|
||||||
var asm []string
|
var asm []string
|
||||||
|
|
||||||
|
|
@ -175,48 +142,3 @@ func (c *NextCommand) generateAdd() []string {
|
||||||
|
|
||||||
return asm
|
return asm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NextCommand) generateSubtract() []string {
|
|
||||||
var asm []string
|
|
||||||
|
|
||||||
// var = var - step
|
|
||||||
stepOp := c.info.StepOperand
|
|
||||||
|
|
||||||
asm = append(asm, "\tsec")
|
|
||||||
|
|
||||||
// Load var low byte
|
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s", c.info.VarName))
|
|
||||||
|
|
||||||
// Subtract step low byte
|
|
||||||
if stepOp.IsVar {
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsbc %s", stepOp.VarName))
|
|
||||||
} else {
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsbc #$%02x", uint8(stepOp.Value&0xFF)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store low byte
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsta %s", c.info.VarName))
|
|
||||||
|
|
||||||
// If variable is word, handle high byte
|
|
||||||
if c.info.VarKind == compiler.KindWord {
|
|
||||||
// Load var high byte
|
|
||||||
asm = append(asm, fmt.Sprintf("\tlda %s+1", c.info.VarName))
|
|
||||||
|
|
||||||
// Subtract step high byte (with borrow)
|
|
||||||
if stepOp.IsVar {
|
|
||||||
if stepOp.VarKind == compiler.KindWord {
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsbc %s+1", stepOp.VarName))
|
|
||||||
} else {
|
|
||||||
asm = append(asm, "\tsbc #0")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hi := uint8((stepOp.Value >> 8) & 0xFF)
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsbc #$%02x", hi))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store high byte
|
|
||||||
asm = append(asm, fmt.Sprintf("\tsta %s+1", c.info.VarName))
|
|
||||||
}
|
|
||||||
|
|
||||||
return asm
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ type ForLoopInfo struct {
|
||||||
VarKind VarKind
|
VarKind VarKind
|
||||||
EndOperand *OperandInfo
|
EndOperand *OperandInfo
|
||||||
StepOperand *OperandInfo
|
StepOperand *OperandInfo
|
||||||
IsDownto bool
|
|
||||||
LoopLabel string
|
LoopLabel string
|
||||||
SkipLabel string
|
SkipLabel string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue