package compiler import ( "fmt" "strings" "c65gm/internal/preproc" ) // Compiler orchestrates the compilation process type Compiler struct { ctx *CompilerContext registry *CommandRegistry } // NewCompiler creates a new compiler with initialized context and registry func NewCompiler(pragma *preproc.Pragma) *Compiler { return &Compiler{ ctx: NewCompilerContext(pragma), registry: NewCommandRegistry(), } } // Context returns the compiler context (for registering commands that need it) func (c *Compiler) Context() *CompilerContext { return c.ctx } // Registry returns the command registry (for registering commands) func (c *Compiler) Registry() *CommandRegistry { return c.registry } // Compile processes preprocessed lines and generates assembly output func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) { var codeOutput []string for _, line := range lines { // Skip non-source lines (assembler and script handled differently) if line.Kind != preproc.Source { if line.Kind == preproc.Assembler { // Pass through assembler lines verbatim codeOutput = append(codeOutput, line.Text) } // Script lines ignored for now continue } // Skip empty/whitespace-only lines if strings.TrimSpace(line.Text) == "" { continue } // Find handler for this line cmd, found := c.registry.FindHandler(line) if !found { return nil, &UnhandledLineError{Line: line} } // Interpret the line if err := cmd.Interpret(line, c.ctx); err != nil { return nil, fmt.Errorf("%s:%d: %w", line.Filename, line.LineNo, err) } // Generate assembly asmLines, err := cmd.Generate(c.ctx) if err != nil { return nil, fmt.Errorf("%s:%d: %w", line.Filename, line.LineNo, err) } codeOutput = append(codeOutput, asmLines...) } // Assemble final output with headers and footers return c.assembleOutput(codeOutput), nil } // assembleOutput combines all generated sections into final assembly func (c *Compiler) assembleOutput(codeLines []string) []string { var output []string // Header comment output = append(output, ";Generated by c65gm") output = append(output, "") // Constants section if constLines := GenerateConstants(c.ctx.SymbolTable); len(constLines) > 0 { output = append(output, constLines...) } // Absolute addresses section if absLines := GenerateAbsolutes(c.ctx.SymbolTable); len(absLines) > 0 { output = append(output, absLines...) } // Main code section output = append(output, ";Main code") output = append(output, "") output = append(output, codeLines...) output = append(output, "") // Variables section if varLines := GenerateVariables(c.ctx.SymbolTable); len(varLines) > 0 { output = append(output, varLines...) } // Constant strings section if strLines := c.ctx.ConstStrHandler.GenerateConstStrDecls(); len(strLines) > 0 { output = append(output, ";Constant strings (from c65gm)") output = append(output, "") output = append(output, strLines...) output = append(output, "") } return output }