Skip to content

Commit

Permalink
Codegen just for assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
3top1a committed Jan 15, 2025
1 parent 673a37a commit 6f89f34
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 6 deletions.
5 changes: 5 additions & 0 deletions examples/basic.🍺
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
x = 4
y = 5
// This will generate a single - because it's faster
z = 255
array = [1 2 3 4 5]
182 changes: 182 additions & 0 deletions src/codegen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use std::collections::HashMap;
use crate::ast::Expression;

pub struct Codegen {
// Track current memory position
ptr: usize,
// Store generated code
code: String,
// Track variables and their memory locations
variables: HashMap<String, usize>,
// Track next available memory position
next_mem: usize,
}

impl Codegen {
pub fn new() -> Self {
Codegen {
ptr: 0,
variables: HashMap::new(),
next_mem: 0,
code: String::new(),
}
}

pub fn generate(&mut self, ast: Vec<Expression>) -> String {
for expr in ast.iter() {
self.generate_expression(expr);
}
self.code.clone()
}

fn move_to(&mut self, target: usize) {
let diff = target as i32 - self.ptr as i32;
if diff > 0 {
self.code.push_str(&">".repeat(diff as usize));
} else if diff < 0 {
self.code.push_str(&"<".repeat(-diff as usize));
}
self.ptr = target;
}

fn add_value(&mut self, value: u8) {
self.code.push_str(&format!("{}", "+".repeat(value as usize)));
}

fn sub_value(&mut self, value: u8) {
self.code.push_str(&format!("{}", "-".repeat(value as usize)));
}

fn set_new_value(&mut self, value: u8) {
// If it's closer to 255, subtract from 255
if value < 127 {
self.add_value(value);
} else {
self.sub_value((256u16 - value as u16) as u8);
}
}

fn allocate_memory(&mut self, size: usize) -> usize {
let start = self.next_mem;
self.next_mem += size;
start
}

fn copy_value(&mut self, from: usize, to: usize) {
// First need a temporary cell for the copy operation
let temp = self.next_mem;
self.next_mem += 1;

// Move to source position
self.move_to(from);

// If copying left
if to < from {
// Generate: [>+<-]+[<+>>+<-]>[<+>-]
// This preserves the original value
let distance = from - to;

// First copy to temp: [>+<-]
self.code.push('[');
self.code.push('>');
self.code.push('+');
self.code.push('<');
self.code.push('-');
self.code.push(']');

// Restore original: >+[<+>>+<-]>[<+>-]
self.code.push('>');
self.code.push('+');
self.code.push('[');
self.code.push('<');
self.code.push('+');
self.code.push('>');
self.code.push('>');
self.code.push('+');
self.code.push('<');
self.code.push('-');
self.code.push(']');
self.code.push('>');
self.code.push('[');
self.code.push('<');
self.code.push('+');
self.code.push('>');
self.code.push('-');
self.code.push(']');
}
// If copying right
else if to > from {
// Generate: [>+<-]+[>+<<+>-]<[>+<-]
let distance = to - from;

// First copy to temp: [>+<-]
self.code.push('[');
self.code.push('>');
self.code.push('+');
self.code.push('<');
self.code.push('-');
self.code.push(']');

// Restore original: >+[>+<<+>-]<[>+<-]
self.code.push('>');
self.code.push('+');
self.code.push('[');
self.code.push('>');
self.code.push('+');
self.code.push('<');
self.code.push('<');
self.code.push('+');
self.code.push('>');
self.code.push('-');
self.code.push(']');
self.code.push('<');
self.code.push('[');
self.code.push('>');
self.code.push('+');
self.code.push('<');
self.code.push('-');
self.code.push(']');
}

self.ptr = to;
}

fn generate_expression(&mut self, expression: &Expression) {
#[cfg(debug_assertions)]
dbg!(&expression);

match expression {
Expression::Number(x) => {
self.set_new_value(*x);
}
Expression::Assignment { name, value } => {
if self.variables.get(name).is_none() {
match *value.clone() {
Expression::Number(x) => {
let mem = self.allocate_memory(1);
self.variables.insert(name.clone(), mem);
self.move_to(mem);
self.generate_expression(value);
}
Expression::Array(x) => {
let mem = self.allocate_memory(x.len());
self.variables.insert(name.clone(), mem);
for (i, value) in x.iter().enumerate() {
self.move_to(mem + i);
self.generate_expression(value);
}
}
_ => {}
}
} else {
// Move to memory location
self.move_to(*self.variables.get(name).unwrap());

// Set value
self.add_value(3);
}
}
_ => {}
}
}
}
14 changes: 9 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod lexer;
mod parser;
mod tokens;
mod utils;
mod codegen;

fn main() {
let input = std::env::args().nth(1).map_or_else(
Expand All @@ -24,12 +25,15 @@ fn main() {

let tokens = lexer::tokenize_indexed(&input);

let output = tokens.iter().map(|x| x.token.clone()).collect::<Vec<_>>();
let normal_tokens = tokens.iter().map(|x| x.token.clone()).collect::<Vec<_>>();
#[cfg(debug_assertions)]
dbg!(&output);
dbg!(&normal_tokens);

let mut parser = parser::Parser::new(tokens, input);
let ast = parser.parse();
let ast = parser::Parser::new(tokens, input).parse();

println!("{:#?}", ast);
#[cfg(debug_assertions)]
dbg!(&ast);

let code = codegen::Codegen::new().generate(ast);
println!("{}", code);
}
30 changes: 29 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,28 @@ impl Parser {
self.current >= self.tokens.len()
}

pub fn parse(&mut self) -> Vec<Expression> {
pub fn parse(mut self) -> Vec<Expression> {
let mut expressions = Vec::new();

while !self.is_at_end() {
if let Some(expr) = self.parse_expression() {
// Check if the new expression is valid
if !self.valid(&expressions, &expr) {
let last_parsed_token = self.tokens[self.current - 1].clone();
eprintln!("Unexpected expression {:?} on line {}:", expr, last_parsed_token.line_number);
eprintln!("{}", last_parsed_token.line);
eprintln!(
"{}{}",
" ".repeat(last_parsed_token.chars_before - last_parsed_token.range.len()),
"^".repeat(last_parsed_token.range.len())
);
panic!();
}

expressions.push(expr);
} else {
// Print the generated AST anyway
#[cfg(debug_assertions)]
dbg!(expressions);

let itoken = self.ipeek().unwrap();
Expand Down Expand Up @@ -238,4 +252,18 @@ impl Parser {
_ => return None,
})
}

fn valid(&self, expressions: &Vec<Expression>, new: &Expression) -> bool {
match new {
Expression::Path(_) => {
// Check if the previous expression was also a path
if let Some(Expression::Path(_)) = expressions.last() {
return false;
}

true
},
_ => true,
}
}
}

0 comments on commit 6f89f34

Please sign in to comment.