mod lexer; mod parser; use std::fs::File; use std::io::{Write, BufRead, BufReader}; use clap::Parser; use parser::Program; pub(crate) type Word = i64; static PROGRAM_COUNTER: usize = 3; #[derive(Parser, Debug)] #[command(about, long_about = None)] struct Args { /// Path to source file source: String, /// Assembled binary output path #[arg(default_value = "program.bin")] destination: String, /// Where the first actual byte to be #[arg(short, long, default_value_t = 1024)] start_index: usize, /// Show intermediate representations #[arg(long, default_value_t = false)] debug: bool, } fn main() { let args = Args::parse(); /* Read */ let file = File::open(args.source).unwrap(); let lines = BufReader::new(file).lines(); /* Lex */ let mut tokens = Vec::new(); for line in lines.map_while(Result::ok) { tokens.extend(lexer::split(line)); } if args.debug { println!("\n### Lexed tokens ###\n"); println!("{:#?}", tokens); } /* Parse */ let mut prog = Program::new(tokens, args.start_index); if args.debug { println!("\n### Parsed tokens ###\n"); prog.print(0); } /* Semantic analysis */ prog.remove_definition_addresses(); if args.debug { println!("\n### After remove_definition_addresses ###\n"); prog.print(0); } prog.analyze(); /* Intermediate code gen */ prog.collapse_instructions(); if args.debug { println!("\n### After first collapse_instructions ###\n"); prog.print(0); } prog.collapse_instructions(); if args.debug { println!("\n### After second collapse_instructions ###\n"); prog.print(0); } /* Machine code gen */ prog.instructions_to_constants(); if args.debug { println!("\n### After instructions_to_constants ###\n"); prog.print(args.start_index); } let binary = prog.to_bytes(PROGRAM_COUNTER); let mut out = File::create(args.destination).unwrap(); out.write_all(&binary).unwrap(); }