diff --git a/src/compile_flisp.rs b/src/compile_flisp.rs index 8da1878..d6b3ead 100644 --- a/src/compile_flisp.rs +++ b/src/compile_flisp.rs @@ -5,11 +5,20 @@ use crate::*; ///Technically illegal address for use in register -> register transfers const ABOVE_STACK_OFFSET: isize = -1; +///Name (lifetime from source code), (Type, Stack position (from the bottom)) +type Variables<'a, 'b> = &'b mut HashMap<&'a str, (Type, isize)>; + +///Name (lifetime from source code), Type +type GlobalVariables<'a, 'b> = &'b mut HashMap<&'a str, Type>; + +///Name, Argument list (not named) +type Functions<'a, 'b> = &'b mut HashMap<&'a str, &'a [Variable<'a>]>; + #[derive(Debug, PartialEq)] struct State<'a, 'b, 'c, 'd, 'e, 'f> { - variables: &'b mut HashMap<&'a str, (Type, isize)>, - global_variables: &'c mut HashMap<&'a str, Type>, - functions: &'d mut HashMap<&'a str, &'a [Variable<'a>]>, + variables: Variables<'a, 'b>, + global_variables: GlobalVariables<'a, 'c>, + functions: Functions<'a, 'd>, stack_size: &'f mut isize, scope_name: &'e str, line_id: usize, @@ -66,8 +75,15 @@ fn compile_element<'a>( optimise: bool, ) -> Result>, CompileError> { let res = match element { - LanguageElement::VariableDeclaration { typ, name } => { - if state.scope_name == "global" { + LanguageElement::VariableDeclaration { + typ, + name, + is_static, + } => { + if state.scope_name == "global" || *is_static { + if state.scope_name == "global" && !is_static { + return Err(CompileError(line!(), "Nonstatic global variable!")); + } if state.global_variables.contains_key(name) { dbg!(element); return Err(CompileError(line!(), "Name already exists in scope!")); @@ -108,7 +124,12 @@ fn compile_element<'a>( statement } - LanguageElement::VariableDeclarationAssignment { typ, name, value } => { + LanguageElement::VariableDeclarationAssignment { + typ, + name, + value, + is_static, + } => { let global_def = |val: &StatementElement| match val { StatementElement::Num(n) => Ok(*n), StatementElement::Char(c) => Ok(*c as isize), @@ -118,7 +139,10 @@ fn compile_element<'a>( "Non constant in array initialisation", )), }; - if state.scope_name == "global" { + if state.scope_name == "global" || *is_static { + if state.scope_name == "global" && !is_static { + return Err(CompileError(line!(), "Nonstatic global variable!")); + } if state.global_variables.contains_key(name) { dbg!(element); return Err(CompileError(line!(), "Name already exists in scope!")); diff --git a/src/flisp_instructions.rs b/src/flisp_instructions.rs index faa0f70..21c319b 100644 --- a/src/flisp_instructions.rs +++ b/src/flisp_instructions.rs @@ -88,7 +88,7 @@ impl fmt::Display for Instruction { Instruction::TSTA => write!(f, "\tTSTA\t"), Instruction::COMA => write!(f, "\tCOMA\t"), Instruction::RTS => write!(f, "\tRTS\t"), - Instruction::Label(l) => write!(f, "{}", l), + Instruction::Label(l) => write!(f, "{}", l.strip_prefix("global::").unwrap_or(l)), Instruction::FCB(bytes) => { //Maybe insert a newline every eight values? write!(f, "\tFCB\t")?; @@ -126,16 +126,6 @@ impl fmt::UpperHex for Instruction { Instruction::DEC(a) => write!(f, "\tDEC\t{:X}", *a), Instruction::LSL(a) => write!(f, "\rLSL\t{:X}", *a), Instruction::LSR(a) => write!(f, "\tLSR\t{:X}", *a), - Instruction::LSLA => write!(f, "\tLSLA\t"), - Instruction::LSRA => write!(f, "\tLSRA\t"), - Instruction::INCA => write!(f, "\tINCA\t"), - Instruction::DECA => write!(f, "\tDECA\t"), - Instruction::PSHA => write!(f, "\tPSHA\t"), - Instruction::PULA => write!(f, "\tPULA\t"), - Instruction::TSTA => write!(f, "\tTSTA\t"), - Instruction::COMA => write!(f, "\tCOMA\t"), - Instruction::RTS => write!(f, "\tRTS\t"), - Instruction::Label(l) => write!(f, "{}", l), Instruction::FCB(bytes) => { write!(f, "\tFCB\t")?; for &val in bytes.iter().take(bytes.len() - 1) { @@ -143,6 +133,7 @@ impl fmt::UpperHex for Instruction { } write!(f, "${:02X}", bytes[bytes.len() - 1]) } + instruction => write!(f, "{}", instruction), } } } @@ -310,8 +301,8 @@ impl fmt::Display for Addressing { Addressing::SP(d) => write!(f, "{:03},SP", *d % 256), Addressing::Xn(d) => write!(f, "{:03},X", *d % 256), Addressing::Yn(d) => write!(f, "{:03},Y", *d % 256), - Addressing::Label(l) => write!(f, "{}", l), - Addressing::DataLabel(l) => write!(f, "#{}", l), + Addressing::Label(l) => write!(f, "{}", l.strip_prefix("global::").unwrap_or(l)), + Addressing::DataLabel(l) => write!(f, "#{}", l.strip_prefix("global::").unwrap_or(l)), Addressing::AX => write!(f, "A,X"), Addressing::AY => write!(f, "A,Y"), } @@ -326,10 +317,7 @@ impl fmt::UpperHex for Addressing { Addressing::SP(d) => write!(f, "${:02X},SP", *d as u8), Addressing::Xn(d) => write!(f, "${:02X},X", *d as u8), Addressing::Yn(d) => write!(f, "${:02X},Y", *d as u8), - Addressing::Label(l) => write!(f, "{}", l), - Addressing::DataLabel(l) => write!(f, "#{}", l), - Addressing::AX => write!(f, "A,X"), - Addressing::AY => write!(f, "A,Y"), + adr => write!(f, "{}", adr), } } } diff --git a/src/language_element.rs b/src/language_element.rs index 47f32b8..7cc4628 100644 --- a/src/language_element.rs +++ b/src/language_element.rs @@ -9,6 +9,7 @@ pub(crate) enum LanguageElement<'a> { VariableDeclaration { typ: Type, name: &'a str, + is_static: bool, }, VariableAssignment { name: &'a str, @@ -18,6 +19,7 @@ pub(crate) enum LanguageElement<'a> { typ: Type, name: &'a str, value: StatementElement<'a>, + is_static: bool, }, PointerAssignment { ptr: StatementElement<'a>, diff --git a/src/parser.rs b/src/parser.rs index 07c8ac5..50df2a3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -68,6 +68,33 @@ fn construct_structure_from_tokens<'a>( typ, name, value: rhs_parsed, + is_static: false, + } + } + + //Static pointer variable declaration + [Static, Decl(t), Deref(d), Assign, ..] => { + let mut typ = Type::Ptr(Box::new(t.clone())); + let mut r = d.as_ref(); + let name; + while let [Deref(b)] = r.as_ref() { + typ = Type::Ptr(Box::new(typ)); + r = b; + } + if let [Token::Name(n)] = r { + name = *n; + } else { + dbg!(tokens); + return Err(ParseError(line!(), "Couldn't parse name/pointer type")); + } + let rhs = &tokens[4..]; + let rhs_verified = StatementToken::from_tokens(rhs)?; + let rhs_parsed = StatementElement::from_tokens(rhs_verified)?; + LanguageElement::VariableDeclarationAssignment { + typ, + name, + value: rhs_parsed, + is_static: true, } } @@ -80,6 +107,20 @@ fn construct_structure_from_tokens<'a>( typ: t.clone(), name: *n, value: rhs_parsed, + is_static: false, + } + } + + //Static variable declaration + [Static, Decl(t), Token::Name(n), Assign, ..] => { + let rhs = &tokens[4..]; + let rhs_verified = StatementToken::from_tokens(rhs)?; + let rhs_parsed = StatementElement::from_tokens(rhs_verified)?; + LanguageElement::VariableDeclarationAssignment { + typ: t.clone(), + name: *n, + value: rhs_parsed, + is_static: true, } } @@ -110,6 +151,14 @@ fn construct_structure_from_tokens<'a>( [Decl(t), Token::Name(n)] => LanguageElement::VariableDeclaration { typ: t.clone(), name: *n, + is_static: false, + }, + + //Static variable declaration (without init) + [Static, Decl(t), Token::Name(n)] => LanguageElement::VariableDeclaration { + typ: t.clone(), + name: *n, + is_static: true, }, //If else if @@ -231,7 +280,11 @@ pub(crate) fn type_check( for line in block { match line { - LanguageElement::VariableDeclaration { typ, name } => variables.push(Variable { + LanguageElement::VariableDeclaration { + typ, + name, + is_static: _, + } => variables.push(Variable { typ: typ.clone(), name: *name, }), @@ -242,7 +295,12 @@ pub(crate) fn type_check( } } - LanguageElement::VariableDeclarationAssignment { typ, name, value } => { + LanguageElement::VariableDeclarationAssignment { + typ, + name, + value, + is_static: _, + } => { variables.push(Variable { typ: typ.clone(), name: *name, diff --git a/src/statement_element.rs b/src/statement_element.rs index 8514710..d14619b 100644 --- a/src/statement_element.rs +++ b/src/statement_element.rs @@ -595,21 +595,39 @@ fn do_operation<'a>( pub(crate) fn move_declarations_first(block: &mut Block) { let give_value = |element: &LanguageElement| -> usize { match element { - LanguageElement::VariableDeclaration { typ: _, name: _ } => 0, + LanguageElement::VariableDeclaration { + typ: _, + name: _, + is_static: true, + } => 0, LanguageElement::VariableDeclarationAssignment { typ: _, name: _, value: _, + is_static: true, } => 0, + LanguageElement::VariableDeclaration { + typ: _, + name: _, + is_static: false, + } => 1, + + LanguageElement::VariableDeclarationAssignment { + typ: _, + name: _, + value: _, + is_static: false, + } => 1, + LanguageElement::FunctionDeclaration { typ: _, name: _, args: _, block: _, - } => 0, - _ => 1, + } => 2, + _ => 3, } }; block.sort_by_key(give_value); diff --git a/tests/test23.c b/tests/test23.c index ccffdd2..d720331 100644 --- a/tests/test23.c +++ b/tests/test23.c @@ -1,4 +1,5 @@ -int foo = 54; +static int foo = 54; -***foo = 56; -*58 = ****foo; \ No newline at end of file +int main() { + static int bar = 432; +} \ No newline at end of file diff --git a/todo b/todo new file mode 100644 index 0000000..fb71376 --- /dev/null +++ b/todo @@ -0,0 +1 @@ +Change all `'a str`s to `Cow`s