This commit is contained in:
2026-03-13 17:42:05 +00:00
parent 57ed7eb029
commit a4446cdb62
5 changed files with 206 additions and 0 deletions
+4
View File
@@ -186,6 +186,7 @@ pub enum Token {
Register(Register), Register(Register),
Immediate(u32), Immediate(u32),
StringLit(String), StringLit(String),
CharLit(char),
Opcode(Opcode), Opcode(Opcode),
} }
@@ -196,6 +197,7 @@ impl fmt::Display for Token {
Self::Register(register) => write!(f, "{register}",), Self::Register(register) => write!(f, "{register}",),
Self::Immediate(immediate) => write!(f, "{immediate}",), Self::Immediate(immediate) => write!(f, "{immediate}",),
Self::StringLit(string_lit) => write!(f, "{string_lit}",), Self::StringLit(string_lit) => write!(f, "{string_lit}",),
Self::CharLit(char_lit) => write!(f, "{char_lit}",),
Self::Opcode(opcode) => write!(f, "{opcode}",), Self::Opcode(opcode) => write!(f, "{opcode}",),
} }
} }
@@ -207,6 +209,7 @@ pub enum TokenType {
Register, Register,
Immediate, Immediate,
StringLit, StringLit,
CharLit,
Opcode, Opcode,
} }
@@ -218,6 +221,7 @@ impl TokenType {
Token::Register(_) => Self::Register, Token::Register(_) => Self::Register,
Token::Immediate(_) => Self::Immediate, Token::Immediate(_) => Self::Immediate,
Token::StringLit(_) => Self::StringLit, Token::StringLit(_) => Self::StringLit,
Token::CharLit(_) => Self::CharLit,
Token::Opcode(_) => Self::Opcode, Token::Opcode(_) => Self::Opcode,
} }
} }
+199
View File
@@ -0,0 +1,199 @@
use crate::assembler::{AssembleError, Token};
pub struct Lexer {
src: Vec<u8>,
module_id: u64,
}
impl Lexer {
pub fn new(src: String, module_id: u64) -> Self {
Self {
src: src.into_bytes().into_iter().rev().collect(),
module_id,
}
}
pub fn lexer(&mut self) -> Result<Vec<Token>, AssembleError> {
let mut tokens = Vec::new();
while !self.src.is_empty() {
if self.src.ends_with(b"//") {
self.src.pop();
self.src.pop();
self.parse_comment();
continue;
}
if self.src.ends_with(b"/*") {
self.src.pop();
self.src.pop();
self.parse_comment_multiline();
continue;
}
if self.src.ends_with(b"\"") {
self.src.pop();
tokens.push(Token::StringLit(self.parse_string_literal()));
}
if self.src.ends_with(b"'") {
self.src.pop();
tokens.push(Token::CharLit(self.parse_char_literal()));
}
if self.src.last().unwrap().is_ascii_digit() {
tokens.push(Token::Immediate(self.parse_number()));
}
}
Ok(tokens)
}
fn parse_number(&mut self) -> u32 {
match self.src.last_chunk::<2>() {
Some(b"0x") => {
self.src.pop();
self.src.pop();
let mut n = 0u32;
while let Some(&b) = self.src.last() {
if let Some(digit) = (b as char).to_digit(16) {
self.src.pop();
n = n * 16 + digit;
} else {
break;
}
}
n
}
Some(b"0b") => {
self.src.pop();
self.src.pop();
let mut n = 0u32;
while let Some(&b) = self.src.last() {
if b == b'0' || b == b'1' {
self.src.pop();
n = n * 2 + (b - b'0') as u32;
} else {
break;
}
}
n
}
Some(b"0o") => {
self.src.pop();
self.src.pop();
let mut n = 0u32;
while let Some(&b) = self.src.last() {
if matches!(b, b'0'..=b'7') {
self.src.pop();
n = n * 8 + (b - b'0') as u32;
} else {
break;
}
}
n
}
_ if self.src.last().is_some_and(|b| b.is_ascii_digit()) => {
let mut n = 0u32;
while let Some(&b) = self.src.last() {
if b.is_ascii_digit() {
self.src.pop();
n = n * 10 + (b - b'0') as u32;
} else {
break;
}
}
n
}
None if let Some(x) = self.src.last()
&& x.is_ascii_digit() =>
{
let x = *x;
self.src.pop();
(x - b'0') as u32
}
_ => panic!("Invalid syntax"),
}
}
// returns nothing as the assembler discards comments
fn parse_comment(&mut self) {
while !self.src.is_empty() && self.src.ends_with(b"\n") {
self.src.pop();
}
}
fn parse_comment_multiline(&mut self) {
while !self.src.is_empty() && self.src.ends_with(b"*/") {
self.src.pop();
}
}
fn parse_string_literal(&mut self) -> String {
let mut result = String::new();
while let Some(ch) = self.src.pop()
&& self.src.ends_with(b"\"")
{
if ch == b'\\' {
let escaped = self
.src
.pop()
.expect("A file should never end with a backslash!");
result.push(match escaped {
b'n' => '\n',
b't' => '\t',
b'r' => '\r',
b'"' => '\"',
b'\\' => '\\',
_ => escaped as char,
});
continue;
}
result.push(ch as char);
}
result
}
fn parse_char_literal(&mut self) -> char {
let ch = self
.src
.pop()
.expect("Unexpected EOF while parsing char literal");
if ch == b'\\' {
let escaped = self
.src
.pop()
.expect("A file should never end with a backslash!");
assert!(
self.src
.pop()
.expect("Unexpected EOF while parsing char literal")
!= b'\'',
"unterminated char literal"
);
match escaped {
b'n' => '\n',
b't' => '\t',
b'r' => '\r',
b'"' => '\"',
b'\\' => '\\',
_ => escaped as char,
}
} else {
assert!(
self.src
.pop()
.expect("Unexpected EOF while parsing char literal")
!= b'\'',
"unterminated char literal"
);
ch as char
}
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod lexer;
pub mod parser;
+1
View File
@@ -13,6 +13,7 @@
)] )]
pub mod assembler; pub mod assembler;
pub mod assemblerv2;
// mod util; // mod util;
pub mod prelude { pub mod prelude {