diff options
| Commit | 1395b9eac37187227874c2bf4e768680c7dffd32 (patch) | |
|---|---|---|
| Author | 2025-02-13 21:53:10 +0200 | |
| Committer | 2025-02-13 21:53:10 +0200 | |
| Files | 50ad9f0c614e1ff07e20964a170b1f27116069ea /assembler/src | |
| tonkobali-1395b9eac37187227874c2bf4e768680c7dffd32.tar tonkobali-1395b9eac37187227874c2bf4e768680c7dffd32.tar.gz tonkobali-1395b9eac37187227874c2bf4e768680c7dffd32.zip | ||
| Parent | 3ea01bbd75cc252453cd21074f56eb9cc6cff317 (diff) | |
feat(assembler): Implement first step of parser
4 files changed, 140 insertions, 8 deletions
| -rw-r--r-- | assembler/src/lexer/mod.rs | 32 | ||||
| -rw-r--r-- | assembler/src/main.rs | 12 | ||||
| -rw-r--r-- | assembler/src/parser/instruction.rs | 0 | ||||
| -rw-r--r-- | assembler/src/parser/mod.rs | 104 |
diff --git a/assembler/src/lexer/mod.rs b/assembler/src/lexer/mod.rs index 617aca1..679df0f 100644 --- a/assembler/src/lexer/mod.rs +++ b/assembler/src/lexer/mod.rs @@ -1,9 +1,13 @@ +use crate::Word; + #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum Token { Label(String), Operator(String), Symbol(String), - Number(i64), + SymbolDef(String), + Number(Word), + Address(Word), String(String), } @@ -16,6 +20,7 @@ pub fn split(mut line: String) -> Vec<Token> { let mut has_label = false; let mut string_started = false; let mut skip_next = false; + let mut address = false; for c in line.chars() { buffer.push(c); @@ -52,31 +57,42 @@ pub fn split(mut line: String) -> Vec<Token> { } string_started = !string_started; }, - ',' | '\n' => { + ',' | '\n' | ';' => { buffer.pop(); if buffer.is_empty() { continue; } - if let Some(num) = buffer.parse::<i64>().ok() { - res.push(Token::Number(num)); + if let Some(num) = buffer.parse::<Word>().ok() { + if address { + address = false; + res.push(Token::Address(num)); + } + else { + res.push(Token::Number(num)); + } } else { res.push(Token::Symbol(buffer.clone())); } buffer.clear(); + + if c == ';' { break; } }, - '\\' => skip_next = true, - ';' => break, '=' => if buffer.is_empty() { panic!("Cannot begin the line with an =") } else if let Token::Operator(name) = &res[0] { - res[0] = Token::Symbol(name.clone()); + res[0] = Token::SymbolDef(name.clone()); buffer.clear(); } else { panic!("Before an = you may only have a symbol name!"); }, - 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '-' | '.' | '$' | '?' + '\\' => skip_next = true, + '%' => address = true, + '-' => if address { + panic!("Addresses cannot be negative!"); + }, + 'A'..='Z' | 'a'..='z' | '0'..='9' | '_' | '.' | '$' | '?' => {}, _ => panic!("Found invalid character '{}'", c), } diff --git a/assembler/src/main.rs b/assembler/src/main.rs index 0cda74e..ebd8177 100644 --- a/assembler/src/main.rs +++ b/assembler/src/main.rs @@ -1,18 +1,30 @@ mod lexer; +mod parser; use std::fs::File; use std::io::{BufRead, BufReader}; +use parser::Program; + +pub(crate) type Word = i64; + fn main() { let file_path = "./example.s"; + /* Read */ let file = File::open(file_path).unwrap(); let lines = BufReader::new(file).lines(); + /* Lex */ let mut tokens = Vec::new(); for line in lines.map_while(Result::ok) { tokens.extend(lexer::split(line)); } println!("{:#?}", tokens); + + /* Parse */ + let prog = Program::new(tokens); + + println!("{:#?}", prog); } diff --git a/assembler/src/parser/instruction.rs b/assembler/src/parser/instruction.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/assembler/src/parser/instruction.rs diff --git a/assembler/src/parser/mod.rs b/assembler/src/parser/mod.rs new file mode 100644 index 0000000..7061286 --- /dev/null +++ b/assembler/src/parser/mod.rs @@ -0,0 +1,104 @@ +use std::collections::HashMap; +use crate::{ Word, lexer::Token }; + +#[derive(Debug, Default)] +pub(crate) struct Instruction { + name: String, + args: Vec<Address>, +} + +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub(crate) enum Address { + Memory(usize), + Constants(usize), + Definitions(String), + Instruction(usize), + #[default] + None, +} + +impl Address { + fn take(&mut self) -> Address { + let val = self.clone(); + *self = Address::None; + val + } +} + +#[derive(Debug, Default)] +pub(crate) struct Program { + definitions: HashMap<String, Address>, + constants: Vec<Word>, + instructions: Vec<Instruction>, +} + +impl Program { + pub(crate) fn new(tokens: Vec<Token>) -> Program { + let mut prog = Program {..Default::default() }; + + let mut op_name = String::new(); + let mut op_args = Vec::new(); + let mut value = Address::None; + let mut symbol_def = String::new(); + + for token in tokens { + match token { + /* Names (lvalue) */ + Token::Operator(name) => { + if ! op_name.is_empty() { + prog.instructions.push(Instruction { + name: op_name, + args: op_args.clone(), + }); + } + op_name = name; + op_args.clear(); + }, + Token::Label(name) => { + // Predicting the index + let index = prog.instructions.len() + !op_name.is_empty() as usize; + prog.definitions.insert(name, Address::Instruction(index)); + }, + Token::SymbolDef(name) => symbol_def = name, + + /* Values (rvalue) */ + Token::Address(num) => { + value = Address::Memory(num as usize); + }, + Token::Number(num) => { + prog.constants.push(num); + value = Address::Constants(prog.constants.len() - 1); + }, + Token::String(str) => { + let index = prog.constants.len(); + for c in str.chars() { + prog.constants.push(c as Word); + } + value = Address::Constants(index); + }, + Token::Symbol(name) => { + value = Address::Definitions(name); + }, + } + + if value != Address::None { + if ! symbol_def.is_empty() { + prog.definitions.insert(symbol_def.clone(), value.take()); + symbol_def.clear(); + } + else { + op_args.push(value.take()); + } + } + } + + if ! op_name.is_empty() { + prog.instructions.push(Instruction { + name: op_name, + args: op_args.clone(), + }); + } + + prog + } +} |
