Skip to content

Commit

Permalink
feat: Add compound statements
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkajetanp committed Aug 14, 2024
1 parent c6024ee commit 338e3d6
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 78 deletions.
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# Ignore all
samples/*

# Unignore all with extensions
samples/!*.*

!samples/*.*
# Unignore all dirs
samples/!*/
!samples/*/

.vim/
.zed/
Expand Down
15 changes: 15 additions & 0 deletions samples/compound.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
int main(void) {
int a = 0;
if (a) {
int b = 2;
return b;
} else {
int c = 3;
if (a < c) {
return !a;
} else {
return 5;
}
}
return a;
}
8 changes: 8 additions & 0 deletions samples/conditional.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
int main(void) {
int a = 4;
int b = (a == 4) ? 8 : 2;
if (b == 6)
return 9;
else
return 3;
}
78 changes: 52 additions & 26 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::fmt;
use std::mem::discriminant;
use strum_macros::{Display, EnumIs};

#[inline(always)]
fn expect_token(expected: TokenKind, tokens: &mut VecDeque<TokenKind>) -> TokenKind {
let exp = discriminant(&expected);
let actual = discriminant(&tokens[0]);
Expand Down Expand Up @@ -42,30 +43,13 @@ impl Program {
}
}

#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, DisplayTree)]
#[allow(dead_code)]
pub struct Function {
pub name: Identifier,
pub return_type: String,
pub body: Vec<BlockItem>,
}

impl DisplayTree for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, style: display_tree::Style) -> std::fmt::Result {
writeln!(f, "{} {}", self.return_type, self.name)?;
for block in &self.body {
writeln!(
f,
"{}{} {}",
style.char_set.connector,
std::iter::repeat(style.char_set.horizontal)
.take(style.indentation as usize)
.collect::<String>(),
display_tree::format_tree!(*block)
)?;
}
Ok(())
}
#[tree]
pub body: Block,
}

impl Function {
Expand All @@ -77,19 +61,52 @@ impl Function {
expect_token(TokenKind::ParenOpen, tokens);
expect_token(TokenKind::Void, tokens);
expect_token(TokenKind::ParenClose, tokens);

let body = Block::parse(tokens);

Function {
name,
return_type: return_type.to_string(),
body,
}
}
}

#[derive(Debug, PartialEq, Clone)]
#[allow(dead_code)]
pub struct Block {
pub body: Vec<BlockItem>,
}

impl Block {
fn parse(tokens: &mut VecDeque<TokenKind>) -> Self {
expect_token(TokenKind::BraceOpen, tokens);

let mut body = vec![];
while !tokens.front().unwrap().to_owned().is_brace_close() {
body.push(BlockItem::parse(tokens));
}

expect_token(TokenKind::BraceClose, tokens);

Function {
name,
return_type: return_type.to_string(),
body,
Block { body }
}
}

impl DisplayTree for Block {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, style: display_tree::Style) -> std::fmt::Result {
for basic_block in &self.body {
writeln!(
f,
"{}{} {}",
style.char_set.connector,
std::iter::repeat(style.char_set.horizontal)
.take(style.indentation as usize)
.collect::<String>(),
display_tree::format_tree!(*basic_block)
)?;
}
Ok(())
}
}

Expand Down Expand Up @@ -170,6 +187,7 @@ pub enum Statement {
// TODO: manually implement DisplayTree
#[ignore_field] Option<Box<Statement>>,
),
Compound(#[tree] Block),
Null,
}

Expand Down Expand Up @@ -205,6 +223,10 @@ impl Statement {
};
Self::If(cond, then_stmt, else_stmt)
}
TokenKind::BraceOpen => {
let block = Block::parse(tokens);
Self::Compound(block)
}
_ => {
let exp = Self::Exp(Expression::parse(tokens, 0));
expect_token(TokenKind::Semicolon, tokens);
Expand Down Expand Up @@ -430,7 +452,9 @@ mod tests {
let function_expected = Function {
name: Identifier::new("main"),
return_type: "Int".to_owned(),
body: vec![BlockItem::Stmt(Statement::Return(Expression::Constant(7)))],
body: Block {
body: vec![BlockItem::Stmt(Statement::Return(Expression::Constant(7)))],
},
};

let program_expected = Program {
Expand Down Expand Up @@ -458,7 +482,9 @@ mod tests {
let function_expected = Function {
name: Identifier::new("main"),
return_type: "Int".to_owned(),
body: vec![BlockItem::Stmt(Statement::Return(Expression::Constant(6)))],
body: Block {
body: vec![BlockItem::Stmt(Statement::Return(Expression::Constant(6)))],
},
};

assert_eq!(Function::parse(&mut tokens), function_expected);
Expand Down
8 changes: 6 additions & 2 deletions src/grammar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ AST Definition
==========================

program = Program(function_definition)
function_definition = Function(identifier name, block_item* body)
function_definition = Function(identifier name, block body)
block = Block(block_item*)
block_item = S(statement) | D(declaration)
declaration = Declaration(identifier name, exp? init)
statement = Return(exp)
| Expression(exp)
| If(exp condition, statement then, statement? else)
| Compound(block)
| Null
exp = Constant(int)
| Var(identifier)
Expand All @@ -25,12 +27,14 @@ Grammar
==========================

<program> ::= <function>
<function> ::= "int" <identifier> "(" "void" ")" "{" {<block-item>} "}"
<function> ::= "int" <identifier> "(" "void" ")" <block>
<block> ::= "{" {<block-item>} "}"
<block-item> ::= <statement> | <declaration>
<declaration> ::= "int" <identifier> ["=" <exp>] ";"
<statement> ::= "return" <exp> ";"
| <exp> ";"
| "if" "(" <exp> ")" <statement> ["else" <statement>]
| <block>
| ";"
<exp> ::= <factor> | <exp> <binop> <exp> | <exp> "?" <exp> ":" <exp>
<factor> ::= <int> | <identifier> | <unop> <factor> | "(" <exp> ")"
Expand Down
35 changes: 23 additions & 12 deletions src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,8 @@ impl Function {
Function {
name: Identifier::generate(function.name),
return_type: function.return_type,
instructions: function
.body
instructions: Instruction::generate_from_block(function.body, ctx)
.into_iter()
.flat_map(|block| Instruction::generate_from_block(block, ctx))
// Implicit return 0 at the end of each function
.chain([Instruction::Return(Val::Constant(0))])
.collect(),
Expand All @@ -101,8 +99,16 @@ pub enum Instruction {
}

impl Instruction {
pub fn generate_from_block(block: ast::BlockItem, ctx: &mut IrCtx) -> Vec<Self> {
match block {
pub fn generate_from_block(block: ast::Block, ctx: &mut IrCtx) -> Vec<Self> {
block
.body
.into_iter()
.flat_map(|block| Instruction::generate_from_basic_block(block, ctx))
.collect()
}

pub fn generate_from_basic_block(basic_block: ast::BlockItem, ctx: &mut IrCtx) -> Vec<Self> {
match basic_block {
ast::BlockItem::Stmt(statement) => Self::generate_from_statement(statement, ctx),
ast::BlockItem::Decl(declaration) => Self::generate_from_declaration(declaration, ctx),
}
Expand Down Expand Up @@ -145,6 +151,7 @@ impl Instruction {
}
instructions
}
Statement::Compound(block) => Self::generate_from_block(block, ctx),
Statement::Null => vec![],
// _ => todo!(),
}
Expand Down Expand Up @@ -417,12 +424,14 @@ mod tests {
body: ast::Function {
name: ast::Identifier::new("main"),
return_type: "Int".to_owned(),
body: vec![ast::BlockItem::Stmt(ast::Statement::Return(
ast::Expression::Unary(
ast::UnaryOperator::Negation,
Box::new(ast::Expression::Constant(5)),
),
))],
body: ast::Block {
body: vec![ast::BlockItem::Stmt(ast::Statement::Return(
ast::Expression::Unary(
ast::UnaryOperator::Negation,
Box::new(ast::Expression::Constant(5)),
),
))],
},
},
};

Expand All @@ -446,7 +455,9 @@ mod tests {
let ast_fn = ast::Function {
name: ast::Identifier::new("main"),
return_type: "Int".to_owned(),
body: vec![ast::BlockItem::Stmt(stmt.clone())],
body: ast::Block {
body: vec![ast::BlockItem::Stmt(stmt.clone())],
},
};

let expected = Function {
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(let_chains)]

use display_tree::format_tree;
use std::fs;
use std::io::{Error, Write};
Expand Down
Loading

0 comments on commit 338e3d6

Please sign in to comment.