From 65e7ca560fd3aa8b232f457d6358a2b8019740a5 Mon Sep 17 00:00:00 2001 From: Natapat Samutpong Date: Wed, 26 Jan 2022 05:06:57 +0700 Subject: [PATCH] feat: some bytecode compiling --- README.md | 8 +-- src/compile.rs | 151 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 17 +++++- src/parser.rs | 21 +++++++ 4 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 src/compile.rs diff --git a/README.md b/README.md index 2c0e9af..6da3198 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ another lisp dialect Compliation flow: ``` -Input(file) -> Parser -> Interpret(TODO) - String SExprs IO - |-> Compile(TODO) - File +Input(file) -> Parser -> Compile(Bytecode) -> Interpret + String SExprs Bytecode IO + |-> Compile + Assembly(?) ``` ## Installation diff --git a/src/compile.rs b/src/compile.rs new file mode 100644 index 0000000..3deed4a --- /dev/null +++ b/src/compile.rs @@ -0,0 +1,151 @@ +use std::fmt::Display; + +use crate::parser::Sexpr::{self, *}; + +#[derive(Clone, Debug, Copy)] +pub struct Register { value: i64 } + +impl Display for Register { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} + +/// Literal types for the bytecode. +#[derive(Clone, Debug)] +pub enum Type { + Int(i64), + Float(f64), + Bool(bool), + String(String), +} + +impl Display for Type { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Type::Int(i) => write!(f, "{}", i), + Type::Float(fl) => write!(f, "{}", fl), + Type::Bool(b) => write!(f, "{}", b), + Type::String(s) => write!(f, "{}", s), + } + } +} + +/// Instructions for the bytecode. +#[derive(Clone, Debug)] +pub enum Instr { + /// Call(Function Index, Arguments) + Call(usize, [Register; 6]), + + /// Stack manipulators + Push(usize, Type), Pop(usize, Register), + + JumpIfFalse(usize, Register, usize), +} + +impl Display for Instr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Instr::Call(idx, args) => write!(f, "{} call {} {} {} {} {} {}", idx, args[0], args[1], args[2], args[3], args[4], args[5]), + Instr::Push(idx, t) => write!(f, "{} push {}", idx, t), + Instr::Pop(idx, r) => write!(f, "{} pop {}", idx, r), + Instr::JumpIfFalse(idx, r, to) => write!(f, "{} jmpf {} {}", idx, r, to), + } + } +} + +pub struct Compiler { + /// The bytecode. + pub bytecode: Vec, + /// The stack. + pub stack: Vec, + /// The current register index. + pub register: Register, + /// The current label index. + pub label: usize, +} + +impl Compiler { + pub fn new() -> Compiler { + Compiler { + bytecode: Vec::new(), + stack: Vec::new(), + register: Register { value: 1 }, + label: 0, + } + } + + fn next_register(&mut self) -> Register { + let r = self.register; + self.register.value += 1; + r + } + + fn next_label(&mut self) -> usize { + let l = self.label; + self.label += 1; + l + } + + pub fn compile_sexpr(&mut self, ast: Sexpr) -> Vec { + let mut result: Vec = Vec::new(); + + match ast { + Cons(car, cdr) => { + match *car { + Symbol(f) => { + match f.as_str() { + "do" => { + for c in cdr { + result.append(&mut self.compile_sexpr(c)); + } + }, + "print" => { + let function_register = self.next_register(); + result.push(Instr::Push(self.next_label(), Type::Int(1))); + result.push(Instr::Pop(self.next_label(), function_register)); + + let arg = &cdr[0]; + let instrs = &mut self.compile_ast(arg); + result.append(&mut instrs.clone()); + + let arg_register = match instrs.last().unwrap() { + Instr::Pop(_, r) => *r, + _ => panic!("Expected mov instruction in `print`"), + }; + + result.push( + Instr::Call(self.next_label(), [ + function_register, + arg_register, + Register { value: 0 }, + Register { value: 0 }, + Register { value: 0 }, + Register { value: 0 } + ]) + ); + }, + _ => todo!(), + } + }, + _ => todo!(), + } + }, + _ => todo!() + } + + result + } + + fn compile_ast(&mut self, ast: &Sexpr) -> Vec { + let mut result = Vec::new(); + match ast { + Str(s) => { + result.push(Instr::Push(self.next_label(), Type::String(format!("\"{}\"", s)))); + result.push(Instr::Pop(self.next_label(), self.next_register())); + }, + _ => todo!() + } + result + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index eba7d8a..9961418 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{fs::read_to_string, path::Path}; +use std::{fs::{read_to_string, File}, path::Path, io::Write}; use structopt::StructOpt; @@ -11,18 +11,29 @@ use util::cover_paren; mod parser; use parser::{tokenize, Parser}; +mod compile; +use compile::Compiler; + fn main() { let args = Args::from_args(); let src = cover_paren(read_to_string(&args.file).unwrap()); - let _file_name = Path::new(&args.file).file_stem().unwrap().to_str().unwrap(); + let file_name = Path::new(&args.file).file_stem().unwrap().to_str().unwrap(); let tokens = tokenize(&src); let mut parser = Parser::new(tokens.clone()); let result = parser.parse(); match args.verbose { - 0 => println!("We don't do anything yet."), + 0 => { + let mut compiler = Compiler::new(); + let instrs = compiler.compile_sexpr(result.unwrap()); + + let mut file = File::create(format!("{}.bbb", file_name)).unwrap(); + for instr in instrs { + file.write_all(format!("{}\n", instr).as_bytes()).unwrap(); + } + }, 1 => println!("{:?}", result), 2 | _ => { println!("Tokens: {:?}", tokens); diff --git a/src/parser.rs b/src/parser.rs index 355f17a..37cc1d3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -9,6 +9,27 @@ pub enum Sexpr { Nil, } +impl std::fmt::Display for Sexpr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Int(i) => write!(f, "{}", i), + Float(fl) => write!(f, "{}", fl), + Str(s) => write!(f, "{}", s), + Boolean(b) => write!(f, "{}", b), + Symbol(s) => write!(f, "{}", s), + Cons(car, cdr) => { + write!(f, "(")?; + write!(f, "{}", car)?; + for c in cdr { + write!(f, " {}", c)?; + } + write!(f, ")") + }, + Nil => write!(f, "nil"), + } + } +} + pub type ParseResult = Result; pub struct Parser {