Skip to content

Commit

Permalink
I need to rethink this
Browse files Browse the repository at this point in the history
  • Loading branch information
3top1a committed Jan 17, 2025
1 parent b4d8dd3 commit e622370
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 227 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ printf(c)
basm("<>+-")

// Iterators work like in Rust
// For simplicity, if the iterator is a single number it is still ran
for ch in input_array {
// Indents are 8 wide tabs
printf(ch)
Expand Down
61 changes: 51 additions & 10 deletions examples/basic.🍺
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
x = 4
y = 5
// This will generate a single - because it's faster
z = 255
array = [1 2 3 4 5]
c = 'c'
// No arrays for now

x = 1
y = 2

fn + a b {
ret = 0
copy a ret
copy b ret
return ret
}

z = +( x y)
goto(z)
basm(".")
newline = '\n'
basm(".")
x = "\nHello, World!"
basm("<<<<<<<<<<<<.>.>.>.>.>.>.>.>.>.>.>.>.")


---


set x
> (alloc) + (add)

set y
> (alloc) ++ (add)


function call
allocate z
> (alloc)
new stack
>

set a
> (alloc) (copy)

set b
> (alloc) (copy)

copy a
copy b
return ret
(move ret to z)

pop stack
(zero b)
(zero a)

goto z
< (goto z)
print
.
39 changes: 29 additions & 10 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ pub enum Expression {
args: Vec<Expression>,
},

/// Unary arithmetic operation
Unary {
/// Operator
op: UnaryOperator,
/// Operand
operand: Box<Expression>,
},
// Now also a function
// /// Unary arithmetic operation
// Unary {
// Operator
// op: UnaryOperator,
// Operand
// operand: Box<Expression>,
// },

// Not used right now because maths are functions
// /// Basic arithmetic operation
Expand Down Expand Up @@ -57,7 +58,7 @@ pub enum Expression {
/// Variable name
name: String,
/// Range
range: Iterator,
range: AlcIterator,
/// Body
/// Should be of type Expression::Expression
body: Box<Expression>,
Expand All @@ -73,6 +74,16 @@ pub enum Expression {
/// Else branch
else_branch: Option<Box<Expression>>,
},

// Function
Function {
/// Name of the function
name: String,
/// Arguments
args: Vec<String>,
/// Body
body: Box<Expression>,
},
}

// Not used right now because maths are functions
Expand All @@ -96,12 +107,12 @@ pub enum UnaryOperator {
}

#[derive(Debug, PartialEq, Clone)]
pub enum Iterator {
pub enum AlcIterator {
Range {
start: Box<Expression>,
end: Box<Expression>,
},
Path(Box<Expression>),
Variable(Box<Expression>),
}

impl Expression {
Expand All @@ -111,4 +122,12 @@ impl Expression {
_ => None,
}
}

pub fn size(&self) -> usize {
match self {
Expression::Number(_) => 1,
Expression::Array(arr) => arr.iter().map(|e| e.size()).sum(),
_ => 0,
}
}
}
207 changes: 10 additions & 197 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,203 +2,16 @@ use std::collections::HashMap;
use std::str::from_utf8;
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;
// Codegen notes for myself:
// - Make the codegen also do comments, they will get removed in the optimization step
// - Functions: https://brainfuck.org/function_tutorial.b
// -

// 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::Path(x) => {
self.move_to(*self.variables.get(x).unwrap());
}
Expression::Call { name, args } => {
match name.as_str() {
"basm" => {
assert_eq!(args.len(), 1);
match args.get(0).unwrap() {
Expression::Array(x) => {
for value in x.iter() {
self.code += from_utf8(&[value.as_number().unwrap()]).unwrap()
}
}
_ => { todo!() }
}
}
_ => { todo!("Implement other functions"); }
}
}
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);
}
}
_ => {
todo!("Implement other expressions");
}
}
}
/// Because we do not yet know the length of functions, we need to make a list of all the
/// basic instructions and their purpose. This will be used to generate the code after initial
/// analysis.
enum AbstractInstruction {

}

Loading

0 comments on commit e622370

Please sign in to comment.