Skip to content

Commit

Permalink
local variables
Browse files Browse the repository at this point in the history
  • Loading branch information
Ianyourgod committed Jun 26, 2024
1 parent 7c30825 commit bc5a886
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/code_gen/secondpass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl Pass {

fn emit_operand(&mut self, operand: &nodes::Operand, instructions: &mut Vec<nodes::Instruction>, context: &mut nodes::Context) -> nodes::Operand {
match operand {
&nodes::Operand::Pseudo(ref identifier) => {
nodes::Operand::Pseudo(ref identifier) => {
let offset = context.var_map.get(&identifier.name);
match offset {
Some(offset) => {
Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
use nix::unistd::execvp;
use std::{ffi::{CStr, CString}, process::exit};

mod parser;
mod lexer;
mod parser;
mod semantic_analysis;
mod tacky;
mod code_gen;
mod emitter;
Expand All @@ -28,6 +29,9 @@ fn compile_program(input: String, input_name: String, outfile_name: &String, inc

let program = parser.parse_program();

let mut resolver = semantic_analysis::Analysis::new(program.clone());
let program = resolver.run();

let mut tacky = tacky::Tacky::new(program);
let program = tacky.generate();

Expand Down
71 changes: 37 additions & 34 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ impl Parser {
program.function_definitions.push(fn_def.clone());
self.next_token();
}

program
}

Expand Down Expand Up @@ -166,13 +167,13 @@ impl Parser {
Box::new(nodes::Statement::VariableDeclaration(nodes::VariableDeclaration {
kind,
ident: nodes::Identifier { value: ident },
expr,
expr: Some(expr),
}))
} else if self.cur_token.kind == lexer::TokenType::SemiColon {
Box::new(nodes::Statement::VariableDeclaration(nodes::VariableDeclaration {
kind,
ident: nodes::Identifier { value: ident },
expr: Box::new(nodes::Expression::Literal(nodes::Literal::Int(0))), // todo: add some kind of undefined value
expr: None
}))
} else {
self.error(format!("expected = or ;, found {:#?}", self.cur_token.kind), self.cur_token.line, self.cur_token.pos, self.cur_token.length, Some(1));
Expand Down Expand Up @@ -353,6 +354,7 @@ impl Parser {

fn get_precidence(&self, token: &lexer::TokenType) -> i8 {
match token {
lexer::TokenType::Assign => 1,
lexer::TokenType::Or => 5,
lexer::TokenType::And => 10,
lexer::TokenType::Equal | lexer::TokenType::NotEqual => 30,
Expand Down Expand Up @@ -406,6 +408,14 @@ impl Parser {
lexer::TokenType::LessThan | lexer::TokenType::GreaterThan |
lexer::TokenType::LessThanEqual | lexer::TokenType::GreaterThanEqual |
lexer::TokenType::And | lexer::TokenType::Or => true,
lexer::TokenType::Assign => true,
_ => false,
}
}

fn is_assignment(&self) -> bool {
match self.cur_token.kind {
lexer::TokenType::Assign => true,
_ => false,
}
}
Expand All @@ -415,11 +425,27 @@ impl Parser {
let prec = self.get_precidence(&self.cur_token.kind);
while self.is_binop() &&
prec >= min_prec {

let operator = self.parse_binop();
self.next_token();
let right = self.parse_expression(prec + 1);
node = Box::new(nodes::Expression::BinOp(node, operator, right));

if self.is_assignment() {
let ident = match *node {
nodes::Expression::Var(ref ident) => {
ident.clone()
},
_ => {
self.error("Expected identifier".to_string(), self.cur_token.line, self.cur_token.pos, self.cur_token.length, Some(1));
panic!();
},
};

self.next_token();
let right = self.parse_expression(prec + 1);
node = Box::new(nodes::Expression::Assignment(ident, right));
} else {
let operator = self.parse_binop();
self.next_token();
let right = self.parse_expression(prec + 1);
node = Box::new(nodes::Expression::BinOp(node, operator, right));
}
}
node
}
Expand Down Expand Up @@ -466,33 +492,10 @@ impl Parser {
fn parse_identifier(&mut self) -> Box<nodes::Expression> {
let ident = self.cur_token.literal.clone();
self.next_token();

if self.cur_token.kind != lexer::TokenType::LParen {
return Box::new(nodes::Expression::Identifier(nodes::Identifier {
value: ident,
}));
}

self.next_token();

let mut args: Vec<Box<nodes::Expression>> = vec![];

if self.cur_token.kind != lexer::TokenType::RParen {
loop {
args.push(self.parse_expression(0));

if self.cur_token.kind == lexer::TokenType::RParen {
break;
}
if self.cur_token.kind != lexer::TokenType::Comma {
self.error(format!("Expected RParen, found {:#?}", self.cur_token.kind), self.cur_token.line, self.cur_token.pos, self.cur_token.length, Some(1));
}
}
}

self.next_token();

Box::new(nodes::Expression::FunctionCall(ident, args))

Box::new(nodes::Expression::Var(nodes::Identifier {
value: ident,
}))
}


Expand Down
5 changes: 2 additions & 3 deletions src/parser/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub struct FunctionArg {
pub struct VariableDeclaration {
pub kind: String, // just int rn
pub ident: Identifier,
pub expr: Box<Expression>,
pub expr: Option<Box<Expression>>,
}

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -72,11 +72,10 @@ pub struct CompoundStatement {
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Literal(Literal),
Identifier(Identifier),
Var(Identifier),
BinOp(Box<Expression>, BinOp, Box<Expression>),
UnaryOp(UnaryOp, Box<Expression>),
Assignment(Identifier, Box<Expression>),
Conditional(Box<Expression>, Box<Expression>, Box<Expression>),
FunctionCall(String, Vec<Box<Expression>>),
}

Expand Down
22 changes: 22 additions & 0 deletions src/semantic_analysis.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::parser;
mod variable_resolution_pass;

pub struct Analysis {
pub ast: parser::nodes::Program,
}

impl Analysis {
pub fn new(ast: parser::nodes::Program) -> Self {
Self {
ast,
}
}

pub fn run(&mut self) -> parser::nodes::Program {
let mut first_pass = variable_resolution_pass::Pass::new(&self.ast);

let program = first_pass.run();

program
}
}
122 changes: 122 additions & 0 deletions src/semantic_analysis/variable_resolution_pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::parser::nodes;

pub struct Pass {
pub program: nodes::Program,
pub error_func: Option<fn(String, String, String, usize, usize, usize, Option<i32>)>,
context: Context,
}

pub struct Context {
pub var_map: std::collections::HashMap<String, String>,
pub tmp_n: i32,
}

impl Context {
fn new() -> Context {
Context { var_map: std::collections::HashMap::new(), tmp_n: -1 }
}

}

impl Pass {
pub fn new(program: &nodes::Program) -> Pass {
Pass { program: program.clone(), error_func: None, context: Context::new() }
}

pub fn run(&mut self) -> nodes::Program {
let mut program = nodes::Program {
function_definitions: Vec::new(),
};

for function in self.program.function_definitions.clone() {
let body = match *function.body {
nodes::Statement::Compound(compound) => compound,
_ => panic!()
};

let mut statements: Vec<Box<nodes::Statement>> = Vec::new();

for statement in body.statements {
statements.push(self.resolve_statement(statement));
}

let new_function = nodes::FunctionDeclaration {
function_name: function.function_name.clone(),
body: Box::new(nodes::Statement::Compound(nodes::CompoundStatement {
statements,
})),
return_type: function.return_type.clone(),
params: function.params.clone(), // todo: run resolve vars on params
};

program.function_definitions.push(new_function);
}

program
}

fn make_temporary(&mut self) -> String {
self.context.tmp_n += 1;
format!(".localvar{}", self.context.tmp_n)
}

fn resolve_statement(&mut self, statement: Box<nodes::Statement>) -> Box<nodes::Statement> {
match *statement {
nodes::Statement::VariableDeclaration(decl) => {
if self.context.var_map.contains_key(&decl.ident.value) {
panic!("Variable {} already declared in scope", decl.ident.value)
}

let new_ident = self.make_temporary();

self.context.var_map.insert(decl.ident.value.clone(), new_ident.clone());

let new_decl = nodes::VariableDeclaration {
kind: decl.kind.clone(),
ident: nodes::Identifier { value: new_ident },
expr: if decl.expr.is_some() { Some(self.resolve_expression(decl.expr.unwrap())) } else { None },
};

Box::new(nodes::Statement::VariableDeclaration(new_decl))
},
nodes::Statement::ExpressionStatement(expr) => {
Box::new(nodes::Statement::ExpressionStatement(nodes::ExpressionStatement {
expression: self.resolve_expression(expr.expression)
}))
},
nodes::Statement::ReturnStatement(ret) => {
Box::new(nodes::Statement::ReturnStatement(nodes::ReturnStatement {
return_value: self.resolve_expression(ret.return_value)
}))
},

_ => statement,
}
}

fn resolve_expression(&mut self, expr: Box<nodes::Expression>) -> Box<nodes::Expression> {
match *expr {
nodes::Expression::Var(ref ident) => {
if self.context.var_map.contains_key(&ident.value) {
Box::new(nodes::Expression::Var(nodes::Identifier { value: self.context.var_map.get(&ident.value).unwrap().clone() }))
} else {
panic!("Variable {} not found in scope", ident.value)
}
},
nodes::Expression::Assignment(ref ident, ref expr) => {
if self.context.var_map.contains_key(&ident.value) {
Box::new(nodes::Expression::Assignment(nodes::Identifier { value: self.context.var_map.get(&ident.value).unwrap().clone() }, self.resolve_expression(expr.clone())))
} else {
expr.clone()
}
},
nodes::Expression::BinOp(ref left, ref op, ref right) => {
Box::new(nodes::Expression::BinOp(self.resolve_expression(left.clone()), op.clone(), self.resolve_expression(right.clone())))
},
nodes::Expression::UnaryOp(ref op, ref expr) => {
Box::new(nodes::Expression::UnaryOp(op.clone(), self.resolve_expression(expr.clone())))
},
_ => expr,
}
}
}
23 changes: 17 additions & 6 deletions src/tacky.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,33 +54,41 @@ impl Tacky {
program
}

fn emit_tacky_statement(&mut self, statement: &parser::nodes::Statement, instructions: &mut nodes::CompoundInstruction) -> nodes::Value {
fn emit_tacky_statement(&mut self, statement: &parser::nodes::Statement, instructions: &mut nodes::CompoundInstruction) {
match statement {
parser::nodes::Statement::ReturnStatement(return_statement) => {
let return_value = self.emit_tacky_expression(&*return_statement.return_value, instructions);
instructions.instructions.push(nodes::Instruction::Return(nodes::Return {
return_value
}));
nodes::Value::Empty
}
parser::nodes::Statement::FunctionDeclaration(ref function_declaration) => {
let mut body = nodes::CompoundInstruction {
instructions: Vec::new(),
};
self.emit_tacky_statement(&*function_declaration.body, &mut body);
nodes::Value::Empty
}
parser::nodes::Statement::Compound(ref compound_statement) => {
for statement in &compound_statement.statements {
self.emit_tacky_statement(statement, instructions);
}
nodes::Value::Empty
}
parser::nodes::Statement::ExpressionStatement(ref expression) => {
nodes::Value::Empty // skip since it aint doing anything
self.emit_tacky_expression(&*expression.expression, instructions);
}
parser::nodes::Statement::VariableDeclaration(ref decl) => {
let var = nodes::Value::Identifier(decl.ident.value.clone());
let value = match &decl.expr {
Some(value) => self.emit_tacky_expression(&*value, instructions),
None => nodes::Value::Constant(0),
};
instructions.instructions.push(nodes::Instruction::Copy(nodes::Copy {
src: value,
dest: var,
}));
}
_ => panic!("Not implemented yet: {:?}", statement)
}
};
}

fn emit_tacky_expression(&mut self, expression: &parser::nodes::Expression, instructions: &mut nodes::CompoundInstruction) -> nodes::Value {
Expand Down Expand Up @@ -156,6 +164,9 @@ impl Tacky {
}));
dest
}
parser::nodes::Expression::Var(ident) => {
nodes::Value::Identifier(ident.value.clone())
}
_ => panic!("Not implemented yet")
}
}
Expand Down
3 changes: 2 additions & 1 deletion test.ag
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
fn main(argc: int) -> int {
return 1 >= 1;
let a: int = 5;
return a;
}
2 changes: 1 addition & 1 deletion todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ wow todos for the argent language

## The List

- [ ] Rewrite to use tacky and 3 pass compiler
- [ ] Rewrite to use tacky and a lot of compiler passes
- [ ] Match
- [ ] Do while?
- [ ] Option
Expand Down

0 comments on commit bc5a886

Please sign in to comment.