diff options
| Commit | 9517d3d05e86621b6c4ed58edd7f5821632e0872 (patch) | |
|---|---|---|
| Author | 2025-02-14 08:23:08 +0200 | |
| Committer | 2025-02-14 08:24:27 +0200 | |
| Files | 2d633e6452e8167bada5db90d061cbdbd8ffcf89 /assembler/src/parser | |
| tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.tar tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.tar.gz tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.zip | ||
| Parent | 2cf1097e124c5a0c5836987416b080b6aa4cdd0f (diff) | |
feat(assembler): Implemented semantic analysis
4 files changed, 94 insertions, 11 deletions
| -rw-r--r-- | assembler/src/parser/code_gen.rs | 11 | ||||
| -rw-r--r-- | assembler/src/parser/instruction.rs | 46 | ||||
| -rw-r--r-- | assembler/src/parser/mod.rs | 25 | ||||
| -rw-r--r-- | assembler/src/parser/semantic.rs | 23 |
diff --git a/assembler/src/parser/code_gen.rs b/assembler/src/parser/code_gen.rs index 7d6fc45..74a4fad 100644 --- a/assembler/src/parser/code_gen.rs +++ b/assembler/src/parser/code_gen.rs @@ -4,17 +4,6 @@ use super::{ Program, Address }; impl Program { /* Intermediate code generation */ - pub(crate) fn remove_definition_addresses(&mut self) { - for instr in &mut self.instructions { - for arg in &mut instr.args { - if let Address::Definitions(name) = arg { - *arg = self.definitions[name].clone(); - } - } - } - self.definitions.clear(); - } - pub(crate) fn collapse_instructions(&mut self) { let mut collapsed = Vec::new(); diff --git a/assembler/src/parser/instruction.rs b/assembler/src/parser/instruction.rs index c44c1de..18d67b7 100644 --- a/assembler/src/parser/instruction.rs +++ b/assembler/src/parser/instruction.rs @@ -1,5 +1,15 @@ use super::{ Instruction, Address }; +#[derive(Debug)] +pub(crate) enum ArgumentError { + UnknownInstruction, + TooMany, + TooFew, + NotLocation, + NotNumber, + NotString, +} + impl Instruction { fn new_subleq(a: &Address, b: &Address, c: &Address) -> Instruction { if let Address::Constants(_) = c { @@ -11,6 +21,42 @@ impl Instruction { } } + fn check_args_len(&self, expected: usize) -> Result<(), ArgumentError> { + if self.args.len() < expected { + return Err(ArgumentError::TooFew); + } + else if self.args.len() > 3 { + return Err(ArgumentError::TooMany); + } + Ok(()) + } + + pub(crate) fn check_args(&self) -> Result<(), ArgumentError> { + match &*self.name { + "subleq" => { + self.check_args_len(3)?; + + for arg in &self.args { + if ! arg.is_location() { + return Err(ArgumentError::NotLocation); + } + } + }, + "jmp" => { + self.check_args_len(1)?; + + if ! self.args[0].is_location() { + return Err(ArgumentError::NotLocation); + } + }, + "add" => { + self.check_args_len(2)?; + }, + _ => return Err(ArgumentError::UnknownInstruction), + } + Ok(()) + } + pub(crate) fn collapse(&mut self, next: usize) -> Vec<Instruction> { self.name = self.name.to_lowercase(); static Z: Address = Address::Memory(0); diff --git a/assembler/src/parser/mod.rs b/assembler/src/parser/mod.rs index 79b8835..d43b9c5 100644 --- a/assembler/src/parser/mod.rs +++ b/assembler/src/parser/mod.rs @@ -1,5 +1,6 @@ mod code_gen; mod syntax; +mod semantic; mod instruction; use std::{ @@ -53,6 +54,30 @@ impl Address { *self = Address::None; val } + + fn is_memory(&self) -> bool { + if let Address::Memory(_) = &self { true } else { false } + } + + fn is_constant(&self) -> bool { + if let Address::Constants(_) = &self { true } else { false } + } + + fn is_instruction(&self) -> bool { + if let Address::Instruction(_) = &self { true } else { false } + } + + fn is_definition(&self) -> bool { + if let Address::Definitions(_) = &self { true } else { false } + } + + fn is_none(&self) -> bool { + if let Address::None = &self { true } else { false } + } + + fn is_location(&self) -> bool { + self.is_memory() || self.is_instruction() + } } #[derive(Debug, Default, Clone)] diff --git a/assembler/src/parser/semantic.rs b/assembler/src/parser/semantic.rs new file mode 100644 index 0000000..47ba201 --- /dev/null +++ b/assembler/src/parser/semantic.rs @@ -0,0 +1,23 @@ +use super::{ Address, Program }; + +impl Program { + pub(crate) fn remove_definition_addresses(&mut self) { + for instr in &mut self.instructions { + for arg in &mut instr.args { + if let Address::Definitions(name) = arg { + *arg = self.definitions[name].clone(); + } + } + } + self.definitions.clear(); + } + + pub(crate) fn analyze(&self) { + for instr in &self.instructions { + let result = instr.check_args(); + if result.is_err() { + panic!("Instruction '{}' error: {:?}", instr.name, result.err().unwrap()); + } + } + } +} |
