package commands import ( "fmt" "strings" "c65gm/internal/compiler" "c65gm/internal/preproc" "c65gm/internal/utils" ) // PointerCommand handles POINTER statements // Syntax: POINTER TO|-> // Where target is: // - Variable name // - Label name // - Numeric address/expression type PointerCommand struct { pointerVarName string targetVarName string targetLabel string targetAddress uint16 isVar bool isLabel bool } func (c *PointerCommand) WillHandle(line preproc.Line) bool { params, err := utils.ParseParams(line.Text) if err != nil || len(params) != 4 { return false } return strings.ToUpper(params[0]) == "POINTER" } func (c *PointerCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error { // Clear state c.pointerVarName = "" c.targetVarName = "" c.targetLabel = "" c.targetAddress = 0 c.isVar = false c.isLabel = false params, err := utils.ParseParams(line.Text) if err != nil { return err } if len(params) != 4 { return fmt.Errorf("POINTER: expected 4 parameters, got %d", len(params)) } scope := ctx.CurrentScope() // Validate pointer variable (param 2) ptrVarName := params[1] ptrSym := ctx.SymbolTable.Lookup(ptrVarName, scope) if ptrSym == nil { return fmt.Errorf("POINTER: unknown variable %q", ptrVarName) } if !ptrSym.IsWord() { return fmt.Errorf("POINTER: variable %q is not a word", ptrVarName) } c.pointerVarName = ptrSym.FullName() // Validate separator (param 3) sep := strings.ToUpper(params[2]) if sep != "TO" && sep != "->" { return fmt.Errorf("POINTER: parameter #3 must be 'TO' or '->', got %q", params[2]) } // Parse target (param 4) targetParam := params[3] constLookup := func(name string) (int64, bool) { sym := ctx.SymbolTable.Lookup(name, scope) if sym != nil && sym.IsConst() { return int64(sym.Value), true } return 0, false } // Try ParseOperandParam - handles variables, constants, expressions varName, _, value, isVar, err := compiler.ParseOperandParam( targetParam, ctx.SymbolTable, scope, constLookup) if err != nil { // Not a variable or expression -> treat as label c.targetLabel = targetParam c.isLabel = true return nil } // It's either a variable or numeric address if isVar { c.targetVarName = varName c.isVar = true return nil } // Numeric address c.targetAddress = value c.isVar = false c.isLabel = false return nil } func (c *PointerCommand) Generate(ctx *compiler.CompilerContext) ([]string, error) { var asm []string // Label reference if c.isLabel { asm = append(asm, fmt.Sprintf("\tldx #<%s", c.targetLabel)) asm = append(asm, fmt.Sprintf("\tlda #>%s", c.targetLabel)) asm = append(asm, fmt.Sprintf("\tsta %s+1", c.pointerVarName)) asm = append(asm, fmt.Sprintf("\tstx %s", c.pointerVarName)) return asm, nil } // Variable reference if c.isVar { asm = append(asm, fmt.Sprintf("\tldx #<%s", c.targetVarName)) asm = append(asm, fmt.Sprintf("\tlda #>%s", c.targetVarName)) asm = append(asm, fmt.Sprintf("\tsta %s+1", c.pointerVarName)) asm = append(asm, fmt.Sprintf("\tstx %s", c.pointerVarName)) return asm, nil } // Numeric address - create temp label tempLabel := ctx.GeneralStack.Push() asm = append(asm, fmt.Sprintf("%s = %d", tempLabel, c.targetAddress)) asm = append(asm, fmt.Sprintf("\tldx #<%s", tempLabel)) asm = append(asm, fmt.Sprintf("\tlda #>%s", tempLabel)) asm = append(asm, fmt.Sprintf("\tsta %s+1", c.pointerVarName)) asm = append(asm, fmt.Sprintf("\tstx %s", c.pointerVarName)) return asm, nil }