Website Summary Files Commits Branches @commit @diff @stats
path: root / assembler / src / parser
diff options
context:
space:
mode:
Commit9517d3d05e86621b6c4ed58edd7f5821632e0872 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-02-14 08:23:08 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-02-14 08:24:27 +0200
Files2d633e6452e8167bada5db90d061cbdbd8ffcf89 /assembler/src/parser
tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.tar
tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.tar.gz
tonkobali-9517d3d05e86621b6c4ed58edd7f5821632e0872.zip
Parent2cf1097e124c5a0c5836987416b080b6aa4cdd0f (diff)
feat(assembler): Implemented semantic analysis
4 files changed, 94 insertions, 11 deletions
-rw-r--r--assembler/src/parser/code_gen.rs11
-rw-r--r--assembler/src/parser/instruction.rs46
-rw-r--r--assembler/src/parser/mod.rs25
-rw-r--r--assembler/src/parser/semantic.rs23
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());
+ }
+ }
+ }
+}