Skip to content

Commit

Permalink
add function declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
kahveciderin committed Nov 3, 2024
1 parent 8b48794 commit 24596ce
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 29 deletions.
6 changes: 3 additions & 3 deletions run-asm.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
echo "Running file $1 with spike"

riscv64-unknown-elf-gcc output/$1.s -o output/$1.out
riscv64-unknown-elf-gcc output/$1.s -o output/$1.out -march=rv32imafdc -mabi=ilp32

if [ $? -ne 0 ]; then
echo "Error compiling file $1"
exit 1
fi

spike pk output/$1.out # --isa=RV32IMAFDC
spike --isa=RV32IMAFDC pk output/$1.out
RET_VAL=$?
echo "Return value: $RET_VAL"
exit $RET_VAL
exit $RET_VAL
122 changes: 113 additions & 9 deletions src/parser/function_definition.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use std::sync::Arc;

use winnow::{combinator, PResult, Parser};

use crate::{
parser::trivial_tokens::parse_comma,
types::{
function_definition::{FunctionArgument, FunctionDefinition},
datatype::Datatype,
function_definition::{
FunctionArgument, FunctionArgumentOptionalName, FunctionDeclaration, FunctionDefinition,
},
program::ProgramStatement,
},
utils::random_name::unique_identifier,
Expand All @@ -13,11 +18,21 @@ use super::{
datatype::parse_datatype,
identifier::parse_identifier,
scope::parse_scope,
trivial_tokens::{parse_close_paren, parse_open_paren},
trivial_tokens::{parse_close_paren, parse_open_paren, parse_semicolon, parse_void},
whitespace::parse_whitespace,
ParserSymbol, ParserVariable, Stream,
ParserStaticSymbol, ParserSymbol, ParserVariable, Stream,
};

fn duplicate_checker(input: impl Iterator<Item = String>) -> bool {
let mut seen = std::collections::HashSet::new();
for x in input {
if !seen.insert(x) {
return true;
}
}
false
}

pub fn parse_function_argument<'s>(input: &mut Stream<'s>) -> PResult<FunctionArgument> {
parse_whitespace(input)?;
let datatype = parse_datatype(input)?;
Expand All @@ -30,20 +45,51 @@ pub fn parse_function_argument<'s>(input: &mut Stream<'s>) -> PResult<FunctionAr
unique_name,
})
}
pub fn parse_function_argument_with_optional_name<'s>(
input: &mut Stream<'s>,
) -> PResult<FunctionArgumentOptionalName> {
parse_whitespace(input)?;
let datatype = parse_datatype(input)?;
let identifier =
combinator::opt(parse_identifier.map(|op| op.to_string())).parse_next(input)?;

Ok(FunctionArgumentOptionalName {
datatype,
name: identifier,
})
}

pub fn parse_function_definition<'s>(input: &mut Stream<'s>) -> PResult<ProgramStatement<'s>> {
pub fn parse_function_definition<'s>(input: &mut Stream<'s>) -> PResult<FunctionDefinition<'s>> {
parse_whitespace(input)?;

let return_type = parse_datatype(input)?;
let name = parse_identifier(input)?;

parse_open_paren(input)?;

let arguments: Vec<FunctionArgument> =
combinator::separated(0.., parse_function_argument, parse_comma).parse_next(input)?;

let arguments: Vec<_> = combinator::alt((
parse_void.map(|_| vec![]),
combinator::separated(0.., parse_function_argument, parse_comma),
))
.parse_next(input)?;
parse_close_paren(input)?;

if input
.state
.static_symbols
.iter()
.find(|x| x.name == name)
.is_some()
{
return Err(winnow::error::ErrMode::Backtrack(
winnow::error::ContextError::new(),
));
}

if duplicate_checker(arguments.iter().map(|x| x.name.to_string())) {
panic!("Duplicate argument names in function definition");
}

input.state.start_function_scope(
name.to_string(),
arguments.iter().map(|x| x.datatype.clone()).collect(),
Expand All @@ -62,11 +108,69 @@ pub fn parse_function_definition<'s>(input: &mut Stream<'s>) -> PResult<ProgramS

let body = parse_scope(input)?;

Ok(ProgramStatement::FunctionDefinition(FunctionDefinition {
Ok(FunctionDefinition {
return_type,
arguments,
name,
body,
scope_state: input.state.function_scope.clone(),
}))
})
}

pub fn parse_function_declaration<'s>(input: &mut Stream<'s>) -> PResult<FunctionDeclaration> {
parse_whitespace(input)?;

let return_type = parse_datatype(input)?;
let name = parse_identifier(input)?;

parse_open_paren(input)?;

let arguments: Vec<_> = combinator::alt((
parse_void.map(|_| vec![]),
combinator::separated(0.., parse_function_argument_with_optional_name, parse_comma),
))
.parse_next(input)?;

parse_close_paren(input)?;

parse_semicolon(input)?;

if duplicate_checker(arguments.iter().filter_map(|x| x.name.clone())) {
panic!("Duplicate argument names in function declaration");
}

if let Some(function) = input.state.static_symbols.iter().find(|x| x.name == name) {
if let Datatype::FunctionPointer {
return_type: r,
arguments: a,
} = &function.datatype
{
if *r.as_ref() != return_type.clone()
|| *a
!= arguments
.iter()
.map(|x| x.datatype.clone())
.collect::<Vec<_>>()
{
panic!(
"Function {} already declared with different signature",
name
);
}
}
}

input.state.add_static_symbol(ParserStaticSymbol {
name: name.to_string(),
datatype: Datatype::FunctionPointer {
return_type: Arc::new(return_type.clone()),
arguments: arguments.iter().map(|x| x.datatype.clone()).collect(),
},
});

Ok(FunctionDeclaration {
return_type,
arguments,
name: name.to_string(),
})
}
21 changes: 16 additions & 5 deletions src/parser/program.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
use winnow::{combinator, PResult, Parser};

use crate::types::program::Program;
use crate::types::program::{Program, ProgramStatement};

use super::{function_definition::parse_function_definition, whitespace::parse_whitespace, Stream};
use super::{
function_definition::{parse_function_declaration, parse_function_definition},
whitespace::parse_whitespace,
Stream,
};

pub fn parse_program<'s>(input: &mut Stream<'s>) -> PResult<Program<'s>> {
parse_whitespace(input)?;

let functions = combinator::repeat_till(0.., parse_function_definition, combinator::eof)
.map(|v| v.0)
.parse_next(input)?;
let functions = combinator::repeat_till(
0..,
combinator::alt((
parse_function_definition.map(ProgramStatement::FunctionDefinition),
parse_function_declaration.map(ProgramStatement::FunctionDeclaration),
)),
combinator::eof,
)
.map(|v| v.0)
.parse_next(input)?;

parse_whitespace(input)?;

Expand Down
10 changes: 10 additions & 0 deletions src/parser/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::types::scope::{Label, Scope, ScopeItem};
use super::{
declaration::parse_declaration,
expression::{fold::Fold, parse_expression},
function_definition::parse_function_declaration,
identifier::parse_identifier,
statement::parse_statement,
trivial_tokens::{parse_close_scope, parse_colon, parse_open_scope, parse_semicolon},
Expand All @@ -26,10 +27,19 @@ pub fn parse_declaration_scope_item<'s>(input: &mut Stream<'s>) -> PResult<Scope
.parse_next(input)
}

pub fn parse_function_declaration_scope_item<'s>(input: &mut Stream<'s>) -> PResult<ScopeItem> {
parse_whitespace(input)?;

parse_function_declaration
.map(ScopeItem::FunctionDeclaration)
.parse_next(input)
}

pub fn parse_scope_item<'s>(input: &mut Stream<'s>) -> PResult<ScopeItem> {
parse_whitespace(input)?;

combinator::alt((
parse_function_declaration_scope_item,
parse_declaration_scope_item,
parse_statement_scope_item,
parse_label,
Expand Down
4 changes: 4 additions & 0 deletions src/parser/trivial_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,7 @@ pub fn parse_double_plus<'s>(input: &mut Stream<'s>) -> PResult<&'s str> {
pub fn parse_double_minus<'s>(input: &mut Stream<'s>) -> PResult<&'s str> {
parse_multiple_chars(input, "--")
}

pub fn parse_void<'s>(input: &mut Stream<'s>) -> PResult<&'s str> {
parse_multiple_chars(input, "void")
}
14 changes: 10 additions & 4 deletions src/riscv/compile/function_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,17 @@ impl Compile for FunctionDefinition<'_> {
location: CompilerVariableLocation::Stack,
});

instructions.push(Instruction::Comment("Variable ".to_owned() + &variable.unique_name + " at address " + &address.to_string()));
instructions.push(Instruction::Comment(
"Variable ".to_owned()
+ &variable.unique_name
+ " at address "
+ &address.to_string(),
));

current_address += size as i32;
}

let mut current_address = 32 + stack_increase;
let mut current_address = 32 + stack_increase; // 32 is for the saved registers
for stack_variable in self.arguments.iter().skip(8) {
state.scope.variables.push(CompilerVariable {
name: stack_variable.unique_name.clone(),
Expand Down Expand Up @@ -147,8 +152,9 @@ impl Compile for FunctionDefinition<'_> {
}
}

impl Compile for FunctionDeclaration<'_> {
fn compile(&self, state: &mut CompilerState) -> Vec<Instruction> {
impl Compile for FunctionDeclaration {
fn compile(&self, _state: &mut CompilerState) -> Vec<Instruction> {
// we don't need to compile function declarations
vec![]
}
}
1 change: 1 addition & 0 deletions src/riscv/compile/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl Compile for ScopeItem {
match self {
ScopeItem::Statement(statement) => statement.compile(state),
ScopeItem::Declaration(declaration) => declaration.compile(state),
ScopeItem::FunctionDeclaration(function_declaration) => function_declaration.compile(state),
ScopeItem::Label(label) => label.compile(state),
}
}
Expand Down
14 changes: 10 additions & 4 deletions src/types/function_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ pub struct FunctionArgument {
pub datatype: Datatype,
}

#[derive(Debug, Clone)]
pub struct FunctionArgumentOptionalName {
pub name: Option<String>,
pub datatype: Datatype,
}

#[derive(Debug)]
pub struct FunctionDefinition<'s> {
pub name: &'s str,
Expand All @@ -18,9 +24,9 @@ pub struct FunctionDefinition<'s> {
pub scope_state: ParserScopeState,
}

#[derive(Debug)]
pub struct FunctionDeclaration<'s> {
pub name: &'s str,
pub arguments: Vec<FunctionArgument>,
#[derive(Debug, Clone)]
pub struct FunctionDeclaration {
pub name: String,
pub arguments: Vec<FunctionArgumentOptionalName>,
pub return_type: Datatype,
}
2 changes: 1 addition & 1 deletion src/types/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::function_definition::{FunctionDeclaration, FunctionDefinition};
#[derive(Debug)]
pub enum ProgramStatement<'s> {
FunctionDefinition(FunctionDefinition<'s>),
FunctionDeclaration(FunctionDeclaration<'s>),
FunctionDeclaration(FunctionDeclaration),
}

#[derive(Debug)]
Expand Down
5 changes: 4 additions & 1 deletion src/types/scope.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use super::{declaration::Declaration, statement::Statement};
use super::{
declaration::Declaration, function_definition::FunctionDeclaration, statement::Statement,
};

#[derive(Debug, Clone)]
pub enum ScopeItem {
Statement(Statement),
Declaration(Declaration),
FunctionDeclaration(FunctionDeclaration),
Label(Label),
}

Expand Down
4 changes: 2 additions & 2 deletions test-gcc.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
echo "Compiling file $1 with gcc"

riscv64-unknown-elf-gcc tests/$1.c -o output/$1-gcc.out
riscv64-unknown-elf-gcc tests/$1.c -o output/$1-gcc.out -march=rv32imafdc -mabi=ilp32

if [ $? -ne 0 ]; then
echo "Error compiling file $1"
exit 1
fi

spike pk output/$1-gcc.out
spike --isa=RV32IMAFDC pk output/$1-gcc.out
RET_VAL=$?
echo "Return value: $RET_VAL"
exit $RET_VAL
2 changes: 2 additions & 0 deletions tests/function_no_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ int foo() {
}

int main() {
int boo(void);

int a = foo();
return a;
}
18 changes: 18 additions & 0 deletions tests/putchar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
int putchar(int c);

int main() {
putchar(72);
putchar(101);
putchar(108);
putchar(108);
putchar(111);
putchar(44);
putchar(32);
putchar(87);
putchar(111);
putchar(114);
putchar(108);
putchar(100);
putchar(33);
putchar(10);
}

0 comments on commit 24596ce

Please sign in to comment.