116 lines
3 KiB
Go
116 lines
3 KiB
Go
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
|
|
}
|