package main import ( "flag" "fmt" "os" "strings" "c65gm/internal/commands" "c65gm/internal/compiler" "c65gm/internal/preproc" ) // c65gm - A 6502 Cross-Compiler for the ACME Cross-Assembler // Copyright (C) 1999, 2025 Mattias Hansson // Distributed under GPL. func main() { fmt.Println("c65gm - A 6502 Cross-Compiler for the ACME Cross-Assembler.") fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v1.0.0") fmt.Println("Distributed under GPL.") fmt.Println() inFile := flag.String("in", "", "input source file (required)") outFile := flag.String("out", "", "output assembly file (required)") flag.Parse() if *inFile == "" || *outFile == "" { _, _ = fmt.Fprintln(os.Stderr, "Error: -in and -out are required") flag.Usage() os.Exit(1) } if err := run(*inFile, *outFile); err != nil { if _, ok := err.(preproc.HaltError); ok { fmt.Println("Halted by #HALT directive") os.Exit(2) } _, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } fmt.Println("Compilation successful.") } func run(inFile, outFile string) error { // Preprocess lines, pragma, err := preproc.PreProcess(inFile) if err != nil { return fmt.Errorf("preprocessing failed: %w", err) } fmt.Printf("Preprocessed %d lines\n", len(lines)) // Create compiler and register commands comp := compiler.NewCompiler(pragma) registerCommands(comp) // Compile asmLines, err := comp.Compile(lines) if err != nil { return fmt.Errorf("compilation failed: %w", err) } fmt.Printf("Generated %d lines of assembly\n", len(asmLines)) // Write output if err := writeOutput(outFile, asmLines); err != nil { return fmt.Errorf("failed to write output: %w", err) } return nil } func registerCommands(comp *compiler.Compiler) { // Register all command handlers here // This is the single place where all commands are wired up comp.Registry().Register(&commands.ByteCommand{}) comp.Registry().Register(&commands.WordCommand{}) comp.Registry().Register(&commands.AddCommand{}) comp.Registry().Register(&commands.AndCommand{}) comp.Registry().Register(&commands.OrCommand{}) comp.Registry().Register(&commands.XorCommand{}) comp.Registry().Register(&commands.SubtractCommand{}) comp.Registry().Register(&commands.LetCommand{}) comp.Registry().Register(&commands.IfCommand{}) comp.Registry().Register(&commands.ElseCommand{}) comp.Registry().Register(&commands.EndIfCommand{}) comp.Registry().Register(&commands.WhileCommand{}) comp.Registry().Register(&commands.BreakCommand{}) comp.Registry().Register(&commands.WendCommand{}) comp.Registry().Register(&commands.FuncCommand{}) comp.Registry().Register(commands.NewCallCommand(comp.Context().FunctionHandler)) comp.Registry().Register(&commands.FendCommand{}) comp.Registry().Register(&commands.IncrCommand{}) comp.Registry().Register(&commands.DecrCommand{}) comp.Registry().Register(&commands.GotoCommand{}) comp.Registry().Register(&commands.LabelCommand{}) comp.Registry().Register(&commands.OriginCommand{}) comp.Registry().Register(&commands.PointerCommand{}) comp.Registry().Register(&commands.PeekCommand{}) comp.Registry().Register(&commands.PeekWCommand{}) comp.Registry().Register(&commands.PokeCommand{}) comp.Registry().Register(&commands.PokeWCommand{}) comp.Registry().Register(&commands.SubEndCommand{}) comp.Registry().Register(&commands.GosubCommand{}) comp.Registry().Register(&commands.ForCommand{}) comp.Registry().Register(&commands.NextCommand{}) comp.Registry().Register(&commands.SwitchCommand{}) comp.Registry().Register(&commands.CaseCommand{}) comp.Registry().Register(&commands.DefaultCommand{}) comp.Registry().Register(&commands.EndSwitchCommand{}) } func writeOutput(filename string, lines []string) error { return os.WriteFile(filename, []byte(strings.Join(lines, "\n")+"\n"), 0644) }