Skip to content

Commit

Permalink
feat: start of visitor (basic vars)
Browse files Browse the repository at this point in the history
  • Loading branch information
SpideyZac committed Jun 3, 2024
1 parent d3abd8a commit d2c0e73
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 52 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ In fact, we have only added 3 instructions (and changed some) for compatability
| `store(size: i32);` | Pop a number off of the stack, and go to where this number points in the heap. Then, pop `size` numbers off of the stack. Store these numbers in reverse order at this location in the heap. |
| `load(size: i32);` | Pop a number off of the stack, and go to where this number points in the heap. Then, push `size` number of consecutive memory cells onto the stack. |
| `copy();` | Pop a number off of the stack, and go to where base_ptr - this number points in the stack. Then push the value in the stack back onto the stack again. |
| `mov();` | Pop a number off of the stack, and go to where base_ptr - this number points in the stack. Then pop another number off the stack. Put that number at that location in the stack. |
| `call(fn: i32);` | Call a user defined function by it's compiler assigned ID. |
| `call_foreign_fn(name: String);` | Call a foreign function by its name in source. |
| `begin_while();` | Start a while loop. For each iteration, pop a number off of the stack. If the number is not zero, continue the loop. |
| `end_while();` | Mark the end of a while loop. |
| `load_base_ptr();` | Load the base pointer of the established stack frame, which is always less than or equal to the stack pointer. |
| `establish_stack_frame();` | Calls `load_base_ptr` and sets the base_ptr to the current stack address |
| `establish_stack_frame();` | Calls `load_base_ptr` and sets the base_ptr to the current stack address. |
| `end_stack_frame(arg_size: i32, local_scope_size: i32);` | Pop `local_scope_size` numbers off of the stack. Then, restore the base_ptr by popping another number off the stack. Next, pop the return address (next instruction address) of off the stack. Finally, pop `arg_size` numbers off of the stack. |
| `set_return_register();` | Pop a number off of the stack, and set the return register to its value |
| `access_return_register();` | Push return register's value to the stack |
| `set_return_register();` | Pop a number off of the stack, and set the return register to its value. |
| `access_return_register();` | Push return register's value to the stack. |

Here is how the base_ptr works:

Expand Down
6 changes: 6 additions & 0 deletions src/compiler/ir.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::compiler::target::Target;

#[derive(Debug, Clone)]
pub enum IRStatement {
Push(f32),
Add,
Expand All @@ -12,6 +13,7 @@ pub enum IRStatement {
Store(i32),
Load(i32),
Copy,
Mov,
Call(String),
CallForeign(String),
BeginWhile,
Expand All @@ -37,6 +39,7 @@ impl IRStatement {
IRStatement::Store(floats) => target.store(*floats),
IRStatement::Load(floats) => target.load(*floats),
IRStatement::Copy => target.f_copy(),
IRStatement::Mov => target.mov(),
IRStatement::Call(name) => target.call_fn(name.clone()),
IRStatement::CallForeign(name) => target.call_foreign_fn(name.clone()),
IRStatement::BeginWhile => target.begin_while(),
Expand All @@ -52,6 +55,7 @@ impl IRStatement {
}
}

#[derive(Debug, Clone)]
pub struct IRFunction {
pub name: String,
pub statements: Vec<IRStatement>,
Expand All @@ -78,6 +82,7 @@ impl IRFunction {
}
}

#[derive(Debug, Clone)]
pub struct IRFunctionEntry {
pub stack_size: i32,
pub heap_size: i32,
Expand Down Expand Up @@ -113,6 +118,7 @@ impl IRFunctionEntry {
}
}

#[derive(Debug, Clone)]
pub struct IR {
pub functions: Vec<IRFunction>,
pub entry: IRFunctionEntry,
Expand Down
1 change: 1 addition & 0 deletions src/compiler/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub trait Target {
fn store(&self, floats: i32) -> String;
fn load(&self, floats: i32) -> String;
fn f_copy(&self) -> String;
fn mov(&self) -> String;

fn fn_header(&self, name: String) -> String;
fn fn_definition(&self, name: String, body: String) -> String;
Expand Down
11 changes: 11 additions & 0 deletions src/compiler/target/vm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ void machine_copy(machine *vm) {
machine_push(vm, vm->stack[vm->base_ptr - offset]);
}

void machine_mov(machine *vm) {
for (int i = 0; i < vm->stack_pointer; i++) {
printf("%f ", vm->stack[i]);
}

int offset = machine_pop(vm);
float value = machine_pop(vm);

vm->stack[vm->base_ptr - offset] = value;
}

void machine_add(machine *vm) {
machine_push(vm, machine_pop(vm) + machine_pop(vm));
}
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/target/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ impl Target for VM {
String::from("machine_copy(vm);\n")
}

fn mov(&self) -> String {
String::from("machine_mov(vm);\n")
}

fn fn_header(&self, name: String) -> String {
format!("void {}(machine* vm);\n", name)
}
Expand Down
274 changes: 273 additions & 1 deletion src/compiler/visit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,277 @@
use std::collections::HashMap;

use crate::compiler::ir;
use crate::lexer::tokens;
use crate::parser::ast;
use crate::parser::parser;

pub enum VariableTypes {
Number,
}

pub struct ScopeState {
pub variables: i32,
pub variable_map: HashMap<String, VariableTypes>,
pub variable_addresses: HashMap<String, i32>,
}

pub struct ProgramState {
pub is_inside_entry: bool,
pub function_name: String,
pub entry_function_state: ScopeState,
pub function_states: Vec<ScopeState>,
}

#[derive(Debug, Clone)]
pub struct VisitorError {
pub message: String,
pub token: ast::TokenNode,
}

pub struct Visitor<'a> {
pub ast_tree: parser::ParserReturn<'a>,
ast_tree: parser::ParserReturn<'a>,
ir: ir::IR,
errors: Vec<VisitorError>,
program_state: ProgramState,
}

impl<'a> Visitor<'a> {
pub fn new(ast_tree: parser::ParserReturn<'a>, stack_size: i32, heap_size: i32) -> Self {
let entry = ir::IRFunctionEntry::new(stack_size, heap_size, vec![]);
Self {
ast_tree,
ir: ir::IR::new(vec![], entry),
errors: vec![],
program_state: ProgramState {
is_inside_entry: true,
function_name: "".to_string(),
entry_function_state: ScopeState {
variables: 0,
variable_map: HashMap::new(),
variable_addresses: HashMap::new(),
},
function_states: vec![],
},
}
}

pub fn find_function_index_by_name(&self, name: String) -> Option<usize> {
self.ir.functions.iter().position(|f| f.name == name)
}

pub fn add_statements(&mut self, statements: Vec<ir::IRStatement>) {
if self.program_state.is_inside_entry {
self.ir.entry.statements.extend(statements);
} else {
let function = self
.ir
.functions
.iter_mut()
.find(|f| f.name == self.program_state.function_name)
.unwrap();
function.statements.extend(statements);
}
}
}

impl<'a> Visitor<'a> {
pub fn visit(&mut self) -> (ir::IR, Vec<VisitorError>) {
self.visit_program(self.ast_tree.ast.clone());

(self.ir.clone(), self.errors.clone())
}

pub fn visit_program(&mut self, program: ast::ProgramNode) {
for statement in &program.statements {
self.visit_statement(statement.clone());
}
}

pub fn visit_statement(&mut self, statement: ast::StatementNode) {
match statement.value {
ast::StatementNodeValueOption::Expression(expression) => {
self.visit_expression(expression.clone());
// TODO: setup IT variable from exp
}
ast::StatementNodeValueOption::VariableDeclarationStatement(
variable_declaration_statement,
) => {
self.visit_variable_declaration_statement(variable_declaration_statement.clone());
}
ast::StatementNodeValueOption::VariableAssignmentStatement(
variable_assignment_statement,
) => {
self.visit_variable_assignment_statement(variable_assignment_statement.clone());
}
_ => {}
}
}

pub fn visit_expression(&mut self, expression: ast::ExpressionNode) {
match expression.value {
ast::ExpressionNodeValueOption::NumberValue(number_value) => {
self.visit_number_value(number_value.clone());
}
_ => {}
}
}

pub fn visit_number_value(&mut self, number_value: ast::NumberValueNode) {
self.add_statements(vec![ir::IRStatement::Push(number_value.value() as f32)]);
}

pub fn visit_variable_declaration_statement(
&mut self,
variable_declaration_statement: ast::VariableDeclarationStatementNode,
) {
let name = match variable_declaration_statement.identifier.value() {
tokens::Token::Identifier(name) => name,
_ => panic!("Unexpected token"),
}
.clone();

let variable_type = match variable_declaration_statement.type_.value() {
tokens::Token::Word(word) => match word.as_str() {
"NUMBER" => VariableTypes::Number,
_ => panic!("Unexpected variable type"),
},
_ => panic!("Unexpected token"),
};

if self.program_state.is_inside_entry {
if self
.program_state
.entry_function_state
.variable_map
.contains_key(&name)
{
self.errors.push(VisitorError {
message: format!("Variable {} already declared", name),
token: variable_declaration_statement.identifier.clone(),
});
return;
}
self.program_state.entry_function_state.variables += 1;
self.program_state
.entry_function_state
.variable_map
.insert(name.clone(), variable_type);
self.program_state
.entry_function_state
.variable_addresses
.insert(name, -self.program_state.entry_function_state.variables);
self.add_statements(vec![ir::IRStatement::Push(0.0)]);
} else {
let index = self
.find_function_index_by_name(self.program_state.function_name.clone())
.unwrap();
let function = &mut self.program_state.function_states[index];
if function.variable_map.contains_key(&name) {
self.errors.push(VisitorError {
message: format!("Variable {} already declared", name),
token: variable_declaration_statement.identifier.clone(),
});
return;
}
function.variables += 1;
function.variable_map.insert(name.clone(), variable_type);
function.variable_addresses.insert(name, -function.variables);
self.add_statements(vec![ir::IRStatement::Push(0.0)]);
}
}

pub fn visit_variable_assignment_statement(
&mut self,
variable_assignment_statement: ast::VariableAssignmentStatementNode,
) {
if let ast::VariableAssignmentNodeVariableOption::Identifier(ident) =
&variable_assignment_statement.variable
{
let name = match ident.value() {
tokens::Token::Identifier(name) => name,
_ => panic!("Unexpected token"),
}
.clone();

if self.program_state.is_inside_entry {
if !self
.program_state
.entry_function_state
.variable_map
.contains_key(&name)
{
self.errors.push(VisitorError {
message: format!("Variable {} not declared", name),
token: ident.clone(),
});
return;
}

self.visit_expression(variable_assignment_statement.expression.clone());
self.add_statements(vec![
ir::IRStatement::Push(
*self
.program_state
.entry_function_state
.variable_addresses
.get(&name)
.unwrap() as f32,
),
ir::IRStatement::Mov,
]);
} else {
let index = self
.find_function_index_by_name(self.program_state.function_name.clone())
.unwrap();
let function = &mut self.program_state.function_states[index];
if !function.variable_map.contains_key(&name) {
self.errors.push(VisitorError {
message: format!("Variable {} not declared", name),
token: ident.clone(),
});
return;
}

let address = *function.variable_addresses.get(&name).unwrap() as f32;

self.visit_expression(variable_assignment_statement.expression.clone());
self.add_statements(vec![ir::IRStatement::Push(address), ir::IRStatement::Mov]);
}
}

if let ast::VariableAssignmentNodeVariableOption::VariableDeclerationStatement(var_dec) =
variable_assignment_statement.variable
{
self.visit_variable_declaration_statement(var_dec.clone());

let name = match var_dec.identifier.value() {
tokens::Token::Identifier(name) => name,
_ => panic!("Unexpected token"),
}
.clone();

if self.program_state.is_inside_entry {
self.add_statements(vec![ir::IRStatement::Push(
*self
.program_state
.entry_function_state
.variable_addresses
.get(&name)
.unwrap() as f32,
)]);
self.visit_expression(variable_assignment_statement.expression.clone());
self.add_statements(vec![ir::IRStatement::Mov]);
} else {
let index = self
.find_function_index_by_name(self.program_state.function_name.clone())
.unwrap();
let function = &mut self.program_state.function_states[index];

let address = *function.variable_addresses.get(&name).unwrap() as f32;

self.visit_expression(variable_assignment_statement.expression.clone());
self.add_statements(vec![ir::IRStatement::Push(address), ir::IRStatement::Mov]);
}
}
}
}
Loading

0 comments on commit d2c0e73

Please sign in to comment.