assembler still very broken, dependency resolution works, now working on expanding pseudoinstructions
This commit is contained in:
+27
-20
@@ -1,20 +1,12 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{AssembleError, parser::Opcode};
|
||||
use crate::{
|
||||
AssembleError,
|
||||
model::{Module, Opcode, Symbol, Token},
|
||||
};
|
||||
use common::prelude::Register;
|
||||
|
||||
pub type Symbol = String;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Token {
|
||||
Symbol(Symbol),
|
||||
Register(Register),
|
||||
Immediate(u32),
|
||||
StringLit(String),
|
||||
Opcode(Opcode),
|
||||
}
|
||||
|
||||
pub fn lexer(mut program: String) -> Result<Vec<Token>, AssembleError> {
|
||||
pub fn lexer(mut program: String, module: u64) -> Result<Vec<Token>, AssembleError> {
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
program = program.replace(",", "");
|
||||
@@ -30,7 +22,6 @@ pub fn lexer(mut program: String) -> Result<Vec<Token>, AssembleError> {
|
||||
|
||||
if let Some(stripped) = token.strip_prefix('"') {
|
||||
literal.push_str(stripped);
|
||||
println!("literal: {literal}");
|
||||
}
|
||||
|
||||
if !literal.is_empty() {
|
||||
@@ -61,9 +52,9 @@ pub fn lexer(mut program: String) -> Result<Vec<Token>, AssembleError> {
|
||||
tokens.push(token);
|
||||
} else if let Some(token) = parse_decimal(token)? {
|
||||
tokens.push(token);
|
||||
} else if let Some(token) = parse_label(token)? {
|
||||
} else if let Some(token) = parse_label(token, module)? {
|
||||
tokens.push(token);
|
||||
} else if let Some(token) = parse_symbol(token)? {
|
||||
} else if let Some(token) = parse_symbol(token, module)? {
|
||||
tokens.push(token);
|
||||
} else {
|
||||
return Err(AssembleError::Generic);
|
||||
@@ -126,18 +117,34 @@ pub fn parse_decimal(token: &str) -> Result<Option<Token>, AssembleError> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_label(token: &str) -> Result<Option<Token>, AssembleError> {
|
||||
pub fn parse_label(token: &str, module: u64) -> Result<Option<Token>, AssembleError> {
|
||||
if !token.ends_with(":") {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(Token::Symbol(token[0..token.len() - 1].to_string())))
|
||||
Ok(Some(Token::Symbol(Symbol {
|
||||
name: token[0..token.len() - 1].to_string(),
|
||||
module: Module::Resolved(module),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_symbol(token: &str) -> Result<Option<Token>, AssembleError> {
|
||||
pub fn parse_symbol(token: &str, module: u64) -> Result<Option<Token>, AssembleError> {
|
||||
if token.chars().next().unwrap().is_numeric() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(Token::Symbol(token.to_string())))
|
||||
let mut split = token.splitn(2, "::");
|
||||
let symbol1 = split.next().unwrap().to_string();
|
||||
|
||||
if let Some(symbol2) = split.next() {
|
||||
Ok(Some(Token::Symbol(Symbol {
|
||||
name: symbol2.to_string(),
|
||||
module: Module::Unresolved(symbol1),
|
||||
})))
|
||||
} else {
|
||||
Ok(Some(Token::Symbol(Symbol {
|
||||
name: symbol1,
|
||||
module: Module::Resolved(module),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
+92
-3
@@ -1,14 +1,91 @@
|
||||
use core::fmt;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
fs,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use common::prelude::Instruction;
|
||||
|
||||
use crate::{lexer::Token, parser::TokenType};
|
||||
use crate::{
|
||||
model::{Node, Token, TokenType},
|
||||
parser::{Parser, Program},
|
||||
};
|
||||
|
||||
pub mod lexer;
|
||||
pub mod model;
|
||||
pub mod parser;
|
||||
|
||||
pub fn assemble(_src: &str) -> Vec<Instruction> {
|
||||
todo!()
|
||||
pub fn assemble(src: &PathBuf) -> Vec<Instruction> {
|
||||
let mut modules = HashSet::<u64>::new();
|
||||
let mut program = Program::new();
|
||||
|
||||
let hash = quick_hash(src);
|
||||
modules.insert(hash);
|
||||
|
||||
match prepare_dependency(src.clone(), &mut modules, &mut program) {
|
||||
Ok(_) => {}
|
||||
Err(err) => println!("BIG ERROR {:?}", err),
|
||||
}
|
||||
|
||||
for node in program.nodes {
|
||||
println!("{:?}", node);
|
||||
}
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn prepare_dependency(
|
||||
path: PathBuf,
|
||||
modules: &mut HashSet<u64>,
|
||||
program: &mut Program,
|
||||
) -> Result<(), AssembleError> {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
if let Ok(path) = path.canonicalize() {
|
||||
log(&format!(
|
||||
"{:20} {:20} [{}]",
|
||||
"Building",
|
||||
filename,
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
|
||||
let src = fs::read_to_string(&path)
|
||||
.map_err(|_| AssembleError::InvalidFile(path.clone()))?;
|
||||
let file_hash = quick_hash(&path);
|
||||
|
||||
log(&format!("{:20} {:20}", "Tokenising", filename));
|
||||
let tokens = lexer::lexer(src, file_hash)?;
|
||||
|
||||
log(&format!("{:20} {:20}", "Parsing", filename));
|
||||
let mut parser = Parser::new(tokens);
|
||||
|
||||
log(&format!("{:20} {:20}", "Resolving Deps", filename));
|
||||
let deps = parser
|
||||
.parse_nodes()?
|
||||
.resolve_dependencies()?
|
||||
.get_dependencies()?;
|
||||
program.add_module(parser.get());
|
||||
|
||||
for dep in deps {
|
||||
log(&format!(
|
||||
"{:20} {:20}",
|
||||
"Including",
|
||||
dep.file_name().unwrap().to_str().unwrap()
|
||||
));
|
||||
|
||||
if !modules.contains(&quick_hash(&dep)) {
|
||||
modules.insert(quick_hash(&dep));
|
||||
prepare_dependency(dep, modules, program)?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(src: Vec<Node>) -> Result<Vec<Instruction>, AssembleError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
/// TODO: disassembling functionality
|
||||
@@ -23,6 +100,7 @@ pub fn disassemble(_: Vec<Instruction>) -> String {
|
||||
#[derive(Debug)]
|
||||
pub enum AssembleError {
|
||||
Generic,
|
||||
InvalidFile(PathBuf),
|
||||
UnexpectedToken(Token, TokenType),
|
||||
}
|
||||
|
||||
@@ -33,6 +111,17 @@ impl fmt::Display for AssembleError {
|
||||
AssembleError::UnexpectedToken(tok, expected) => {
|
||||
write!(f, "Unexpected token {tok:?}, expected {expected:?}")
|
||||
}
|
||||
AssembleError::InvalidFile(path) => write!(f, "Invalid file {path:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn quick_hash(value: &PathBuf) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
value.canonicalize().unwrap().to_str().hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
fn log(message: &str) {
|
||||
println!("\x1b[32mINFO:\x1b[0m {}", message);
|
||||
}
|
||||
|
||||
+18
-10
@@ -1,17 +1,25 @@
|
||||
use std::fs;
|
||||
use std::{fs, io::Write, path::PathBuf};
|
||||
|
||||
use assembler::{lexer, parser::Parser};
|
||||
use common::prelude::{ITypeArgs, Instruction, RTypeArgs, Register};
|
||||
|
||||
fn main() {
|
||||
let program = fs::read_to_string("../resources/dsa/print.dsa").unwrap();
|
||||
let tokens = lexer::lexer(program).unwrap();
|
||||
|
||||
println!("{tokens:?}");
|
||||
|
||||
let parser = Parser::new(tokens);
|
||||
|
||||
for node in parser {
|
||||
println!("{node:?}");
|
||||
// parse args:
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() != 5 || args[1] != "-i" || args[3] != "-o" {
|
||||
eprintln!("Usage: binary_name -i input_path -o output_path");
|
||||
std::process::exit(1);
|
||||
}
|
||||
let input_path = &args[2];
|
||||
let output_path = &args[4];
|
||||
|
||||
let src = PathBuf::from(input_path);
|
||||
let mut output_file = fs::File::create(output_path).unwrap();
|
||||
|
||||
let res = assembler::assemble(&src)
|
||||
.iter()
|
||||
.map(|i| i.encode())
|
||||
.for_each(|i| {
|
||||
output_file.write_all(&i.to_be_bytes()).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use common::prelude::Register;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[expect(dead_code)]
|
||||
pub struct Node(pub Option<Symbol>, pub Opcode, pub Vec<Token>);
|
||||
|
||||
impl fmt::Display for Node {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let symbol = match &self.0 {
|
||||
Some(symbol) => format!("{}", symbol),
|
||||
None => "".to_string(),
|
||||
};
|
||||
|
||||
write!(f, "Node: {} {} {:?}", symbol, self.1, self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}::{}", self.module, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Module {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Module::Unresolved(name) => write!(f, "{}", name),
|
||||
Module::Resolved(name) => write!(f, "{}", name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Opcode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
pub module: Module,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Module {
|
||||
Resolved(u64),
|
||||
Unresolved(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Token {
|
||||
Symbol(Symbol),
|
||||
Register(Register),
|
||||
Immediate(u32),
|
||||
StringLit(String),
|
||||
Opcode(Opcode),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum TokenType {
|
||||
Symbol,
|
||||
Register,
|
||||
Immediate,
|
||||
StringLit,
|
||||
Opcode,
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
pub fn from_token(token: &Token) -> TokenType {
|
||||
match token {
|
||||
Token::Symbol(_) => TokenType::Symbol,
|
||||
Token::Register(_) => TokenType::Register,
|
||||
Token::Immediate(_) => TokenType::Immediate,
|
||||
Token::StringLit(_) => TokenType::StringLit,
|
||||
Token::Opcode(_) => TokenType::Opcode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Opcode {
|
||||
// Real instructions (0x00-0x26)
|
||||
Nop,
|
||||
Mov,
|
||||
Movs,
|
||||
Ldb,
|
||||
Ldbs,
|
||||
Ldh,
|
||||
Ldhs,
|
||||
Ldw,
|
||||
Stb,
|
||||
Sth,
|
||||
Stw,
|
||||
Lli,
|
||||
Lui,
|
||||
Jmp,
|
||||
Jeq,
|
||||
Jne,
|
||||
Jgt,
|
||||
Jge,
|
||||
Jlt,
|
||||
Jle,
|
||||
Cmp,
|
||||
Inc,
|
||||
Dec,
|
||||
Shl,
|
||||
Shr,
|
||||
Add,
|
||||
Sub,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
Xor,
|
||||
Nand,
|
||||
Nor,
|
||||
Xnor,
|
||||
Int,
|
||||
Irt,
|
||||
Hlt,
|
||||
Iadd,
|
||||
Isub,
|
||||
// Pseudo-instructions
|
||||
Db,
|
||||
Dh,
|
||||
Dw,
|
||||
Resb,
|
||||
Resh,
|
||||
Resw,
|
||||
Push,
|
||||
Pop,
|
||||
Lwi,
|
||||
Include,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OpcodeFromStrError {
|
||||
InvalidRegister(&'static str),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for OpcodeFromStrError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidRegister(reg) => write!(f, "register does not exist: {reg}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for OpcodeFromStrError {}
|
||||
|
||||
impl FromStr for Opcode {
|
||||
type Err = OpcodeFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"nop" => Ok(Self::Nop),
|
||||
"mov" => Ok(Self::Mov),
|
||||
"movs" => Ok(Self::Movs),
|
||||
"ldb" => Ok(Self::Ldb),
|
||||
"ldbs" => Ok(Self::Ldbs),
|
||||
"ldh" => Ok(Self::Ldh),
|
||||
"ldhs" => Ok(Self::Ldhs),
|
||||
"ldw" => Ok(Self::Ldw),
|
||||
"stb" => Ok(Self::Stb),
|
||||
"sth" => Ok(Self::Sth),
|
||||
"stw" => Ok(Self::Stw),
|
||||
"lli" => Ok(Self::Lli),
|
||||
"lui" => Ok(Self::Lui),
|
||||
"jmp" => Ok(Self::Jmp),
|
||||
"jeq" => Ok(Self::Jeq),
|
||||
"jne" => Ok(Self::Jne),
|
||||
"jgt" => Ok(Self::Jgt),
|
||||
"jge" => Ok(Self::Jge),
|
||||
"jlt" => Ok(Self::Jlt),
|
||||
"jle" => Ok(Self::Jle),
|
||||
"cmp" => Ok(Self::Cmp),
|
||||
"inc" => Ok(Self::Inc),
|
||||
"dec" => Ok(Self::Dec),
|
||||
"shl" => Ok(Self::Shl),
|
||||
"shr" => Ok(Self::Shr),
|
||||
"add" => Ok(Self::Add),
|
||||
"sub" => Ok(Self::Sub),
|
||||
"and" => Ok(Self::And),
|
||||
"or" => Ok(Self::Or),
|
||||
"not" => Ok(Self::Not),
|
||||
"xor" => Ok(Self::Xor),
|
||||
"nand" => Ok(Self::Nand),
|
||||
"nor" => Ok(Self::Nor),
|
||||
"xnor" => Ok(Self::Xnor),
|
||||
"int" => Ok(Self::Int),
|
||||
"irt" => Ok(Self::Irt),
|
||||
"hlt" => Ok(Self::Hlt),
|
||||
"iadd" => Ok(Self::Iadd),
|
||||
"isub" => Ok(Self::Isub),
|
||||
"db" => Ok(Self::Db),
|
||||
"dh" => Ok(Self::Dh),
|
||||
"dw" => Ok(Self::Dw),
|
||||
"resb" => Ok(Self::Resb),
|
||||
"resh" => Ok(Self::Resh),
|
||||
"resw" => Ok(Self::Resw),
|
||||
"push" => Ok(Self::Push),
|
||||
"pop" => Ok(Self::Pop),
|
||||
"lwi" => Ok(Self::Lwi),
|
||||
"include" => Ok(Self::Include),
|
||||
_ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
pub const OPCODES: &[&str] = &[
|
||||
// Real instructions (0x00-0x26)
|
||||
"nop", "mov", "movs", "ldb", "ldbs", "ldh", "ldhs", "ldw", "stb", "sth", "stw",
|
||||
"lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc",
|
||||
"dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor",
|
||||
"xnor", "int", "irt", "hlt", "iadd", "isub", // Pseudo-instructions
|
||||
"db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi", "include",
|
||||
];
|
||||
|
||||
pub fn to_opcode_value(&self) -> Option<u8> {
|
||||
match self {
|
||||
Self::Nop => Some(0x00),
|
||||
Self::Mov => Some(0x01),
|
||||
Self::Movs => Some(0x02),
|
||||
Self::Ldb => Some(0x03),
|
||||
Self::Ldbs => Some(0x04),
|
||||
Self::Ldh => Some(0x05),
|
||||
Self::Ldhs => Some(0x06),
|
||||
Self::Ldw => Some(0x07),
|
||||
Self::Stb => Some(0x08),
|
||||
Self::Sth => Some(0x09),
|
||||
Self::Stw => Some(0x0A),
|
||||
Self::Lli => Some(0x0B),
|
||||
Self::Lui => Some(0x0C),
|
||||
Self::Jmp => Some(0x0D),
|
||||
Self::Jeq => Some(0x0E),
|
||||
Self::Jne => Some(0x0F),
|
||||
Self::Jgt => Some(0x10),
|
||||
Self::Jge => Some(0x11),
|
||||
Self::Jlt => Some(0x12),
|
||||
Self::Jle => Some(0x13),
|
||||
Self::Cmp => Some(0x14),
|
||||
Self::Inc => Some(0x15),
|
||||
Self::Dec => Some(0x16),
|
||||
Self::Shl => Some(0x17),
|
||||
Self::Shr => Some(0x18),
|
||||
Self::Add => Some(0x19),
|
||||
Self::Sub => Some(0x1A),
|
||||
Self::And => Some(0x1B),
|
||||
Self::Or => Some(0x1C),
|
||||
Self::Not => Some(0x1D),
|
||||
Self::Xor => Some(0x1E),
|
||||
Self::Nand => Some(0x1F),
|
||||
Self::Nor => Some(0x20),
|
||||
Self::Xnor => Some(0x21),
|
||||
Self::Int => Some(0x22),
|
||||
Self::Irt => Some(0x23),
|
||||
Self::Hlt => Some(0x24),
|
||||
Self::Iadd => Some(0x25),
|
||||
Self::Isub => Some(0x26),
|
||||
// Pseudo-instructions don't have opcode values
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_pseudo_instruction(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Db
|
||||
| Self::Dh
|
||||
| Self::Dw
|
||||
| Self::Resb
|
||||
| Self::Resh
|
||||
| Self::Resw
|
||||
| Self::Push
|
||||
| Self::Pop
|
||||
| Self::Lwi
|
||||
)
|
||||
}
|
||||
}
|
||||
+144
-256
@@ -1,73 +1,35 @@
|
||||
use core::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::AssembleError;
|
||||
use crate::lexer::{Symbol, Token};
|
||||
use common::prelude::{Instruction, Register};
|
||||
|
||||
use crate::model::{Module, Node, Opcode, Symbol, Token, TokenType};
|
||||
use crate::{AssembleError, quick_hash};
|
||||
|
||||
pub struct Parser {
|
||||
tokens: Vec<Token>,
|
||||
nodes: Vec<Node>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum TokenType {
|
||||
Symbol,
|
||||
Register,
|
||||
Immediate,
|
||||
StringLit,
|
||||
Opcode,
|
||||
pub struct Program {
|
||||
pub nodes: Vec<Node>,
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
fn from_token(token: &Token) -> TokenType {
|
||||
match token {
|
||||
Token::Symbol(_) => TokenType::Symbol,
|
||||
Token::Register(_) => TokenType::Register,
|
||||
Token::Immediate(_) => TokenType::Immediate,
|
||||
Token::StringLit(_) => TokenType::StringLit,
|
||||
Token::Opcode(_) => TokenType::Opcode,
|
||||
}
|
||||
impl Program {
|
||||
pub fn new() -> Program {
|
||||
Program { nodes: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
// TODO: MAKE SURE I DO THE BIT SHIFT FOR LUI CODEGEN
|
||||
pub fn add_module(&mut self, module: Vec<Node>) {
|
||||
self.nodes.extend(module);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct Node(Option<Symbol>, Opcode, Vec<Token>);
|
||||
|
||||
impl Iterator for Parser {
|
||||
type Item = Result<Node, AssembleError>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<Node, AssembleError>> {
|
||||
if self.tokens.is_empty() {
|
||||
return None;
|
||||
pub fn parser(&mut self) -> Parser {
|
||||
Parser {
|
||||
tokens: vec![],
|
||||
nodes: self.nodes.clone(),
|
||||
}
|
||||
|
||||
Some(self.parse_instruction())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +37,128 @@ impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> Parser {
|
||||
Parser {
|
||||
tokens: tokens.into_iter().rev().collect(),
|
||||
nodes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_nodes(&mut self) -> Result<&mut Self, AssembleError> {
|
||||
while !self.tokens.is_empty() {
|
||||
let ins = self.parse_instruction()?;
|
||||
self.nodes.push(ins);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn get_dependencies(&mut self) -> Result<Vec<PathBuf>, AssembleError> {
|
||||
let mut dependencies = Vec::new();
|
||||
for node in &self.nodes {
|
||||
if let Opcode::Include = node.1 {
|
||||
if let Token::StringLit(path) = node.2.get(1).unwrap() {
|
||||
dependencies.push(PathBuf::from(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(dependencies)
|
||||
}
|
||||
|
||||
pub fn resolve_dependencies(&mut self) -> Result<&mut Self, AssembleError> {
|
||||
// first we get a list of imports
|
||||
let mut dependencies = Vec::new();
|
||||
for node in &self.nodes {
|
||||
if let Opcode::Include = node.1 {
|
||||
// we want the path, and the name
|
||||
let name = if let Token::Symbol(name) = node.2.get(0).unwrap() {
|
||||
name.name.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
}; //node.2.get(0).unwrap()
|
||||
let path = if let Token::StringLit(path) = node.2.get(1).unwrap() {
|
||||
path
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let hash = quick_hash(&PathBuf::from(path).canonicalize().unwrap());
|
||||
|
||||
dependencies.push((name, hash));
|
||||
}
|
||||
}
|
||||
|
||||
let mut changes = Vec::<(u32, u32, Symbol)>::new();
|
||||
// now we resolve the symbols on all the nodes
|
||||
// we need to check all operands for unresolved signals
|
||||
for (i, node) in self.nodes.clone().iter().enumerate() {
|
||||
let Node(_, _, operands) = node;
|
||||
for (j, token) in operands.iter().enumerate() {
|
||||
if let Token::Symbol(symbol) = token {
|
||||
for d in &dependencies {
|
||||
if let Module::Unresolved(name) = symbol.module.clone() {
|
||||
if name != d.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let symbol = Symbol {
|
||||
name: symbol.name.clone(),
|
||||
module: Module::Resolved(d.1),
|
||||
};
|
||||
changes.push((i as u32, j as u32, symbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i, j, symbol) in changes {
|
||||
self.nodes[i as usize].2[j as usize] = Token::Symbol(symbol);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Vec<Node> {
|
||||
self.nodes.clone()
|
||||
}
|
||||
|
||||
pub fn expand_pseudo_ops(&mut self) -> Result<&mut Self, AssembleError> {
|
||||
for node in self.nodes.iter_mut() {
|
||||
match node.1 {
|
||||
Opcode::Db | Opcode::Dh | Opcode::Dw => todo!(),
|
||||
Opcode::Resb | Opcode::Resh | Opcode::Resw => todo!(),
|
||||
|
||||
Opcode::Push => {
|
||||
// inc SPR
|
||||
// STW reg, SPR
|
||||
let label = node.0.clone();
|
||||
let reg = node.2.get(0).unwrap();
|
||||
|
||||
vec![
|
||||
Node(
|
||||
label.clone(),
|
||||
Opcode::Inc,
|
||||
vec![Token::Register(Register::Spr)],
|
||||
),
|
||||
Node(
|
||||
label.clone(),
|
||||
Opcode::Stw,
|
||||
vec![reg.clone(), Token::Register(Register::Spr)],
|
||||
),
|
||||
];
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn resolve_symbols(&mut self) -> Result<&mut Self, AssembleError> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn instructions(&mut self) -> Vec<Instruction> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn parse_instruction(&mut self) -> Result<Node, AssembleError> {
|
||||
if self.tokens.is_empty() {
|
||||
unreachable!();
|
||||
@@ -170,6 +251,12 @@ impl Parser {
|
||||
args = vec![reg];
|
||||
}
|
||||
|
||||
Opcode::Include => {
|
||||
let mod_name = self.expect(TokenType::Symbol)?;
|
||||
let path = self.expect(TokenType::StringLit)?;
|
||||
args = vec![mod_name, path];
|
||||
}
|
||||
|
||||
// J-type instructions
|
||||
Opcode::Jmp
|
||||
| Opcode::Jeq
|
||||
@@ -312,202 +399,3 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Opcode {
|
||||
// Real instructions (0x00-0x26)
|
||||
Nop,
|
||||
Mov,
|
||||
Movs,
|
||||
Ldb,
|
||||
Ldbs,
|
||||
Ldh,
|
||||
Ldhs,
|
||||
Ldw,
|
||||
Stb,
|
||||
Sth,
|
||||
Stw,
|
||||
Lli,
|
||||
Lui,
|
||||
Jmp,
|
||||
Jeq,
|
||||
Jne,
|
||||
Jgt,
|
||||
Jge,
|
||||
Jlt,
|
||||
Jle,
|
||||
Cmp,
|
||||
Inc,
|
||||
Dec,
|
||||
Shl,
|
||||
Shr,
|
||||
Add,
|
||||
Sub,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
Xor,
|
||||
Nand,
|
||||
Nor,
|
||||
Xnor,
|
||||
Int,
|
||||
Irt,
|
||||
Hlt,
|
||||
Iadd,
|
||||
Isub,
|
||||
// Pseudo-instructions
|
||||
Db,
|
||||
Dh,
|
||||
Dw,
|
||||
Resb,
|
||||
Resh,
|
||||
Resw,
|
||||
Push,
|
||||
Pop,
|
||||
Lwi,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OpcodeFromStrError {
|
||||
InvalidRegister(&'static str),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for OpcodeFromStrError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidRegister(reg) => write!(f, "register does not exist: {reg}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for OpcodeFromStrError {}
|
||||
|
||||
impl FromStr for Opcode {
|
||||
type Err = OpcodeFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"nop" => Ok(Self::Nop),
|
||||
"mov" => Ok(Self::Mov),
|
||||
"movs" => Ok(Self::Movs),
|
||||
"ldb" => Ok(Self::Ldb),
|
||||
"ldbs" => Ok(Self::Ldbs),
|
||||
"ldh" => Ok(Self::Ldh),
|
||||
"ldhs" => Ok(Self::Ldhs),
|
||||
"ldw" => Ok(Self::Ldw),
|
||||
"stb" => Ok(Self::Stb),
|
||||
"sth" => Ok(Self::Sth),
|
||||
"stw" => Ok(Self::Stw),
|
||||
"lli" => Ok(Self::Lli),
|
||||
"lui" => Ok(Self::Lui),
|
||||
"jmp" => Ok(Self::Jmp),
|
||||
"jeq" => Ok(Self::Jeq),
|
||||
"jne" => Ok(Self::Jne),
|
||||
"jgt" => Ok(Self::Jgt),
|
||||
"jge" => Ok(Self::Jge),
|
||||
"jlt" => Ok(Self::Jlt),
|
||||
"jle" => Ok(Self::Jle),
|
||||
"cmp" => Ok(Self::Cmp),
|
||||
"inc" => Ok(Self::Inc),
|
||||
"dec" => Ok(Self::Dec),
|
||||
"shl" => Ok(Self::Shl),
|
||||
"shr" => Ok(Self::Shr),
|
||||
"add" => Ok(Self::Add),
|
||||
"sub" => Ok(Self::Sub),
|
||||
"and" => Ok(Self::And),
|
||||
"or" => Ok(Self::Or),
|
||||
"not" => Ok(Self::Not),
|
||||
"xor" => Ok(Self::Xor),
|
||||
"nand" => Ok(Self::Nand),
|
||||
"nor" => Ok(Self::Nor),
|
||||
"xnor" => Ok(Self::Xnor),
|
||||
"int" => Ok(Self::Int),
|
||||
"irt" => Ok(Self::Irt),
|
||||
"hlt" => Ok(Self::Hlt),
|
||||
"iadd" => Ok(Self::Iadd),
|
||||
"isub" => Ok(Self::Isub),
|
||||
"db" => Ok(Self::Db),
|
||||
"dh" => Ok(Self::Dh),
|
||||
"dw" => Ok(Self::Dw),
|
||||
"resb" => Ok(Self::Resb),
|
||||
"resh" => Ok(Self::Resh),
|
||||
"resw" => Ok(Self::Resw),
|
||||
"push" => Ok(Self::Push),
|
||||
"pop" => Ok(Self::Pop),
|
||||
"lwi" => Ok(Self::Lwi),
|
||||
_ => Err(OpcodeFromStrError::InvalidRegister("unknown opcode")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
pub const OPCODES: &[&str] = &[
|
||||
// Real instructions (0x00-0x26)
|
||||
"nop", "mov", "movs", "ldb", "ldbs", "ldh", "ldhs", "ldw", "stb", "sth", "stw",
|
||||
"lli", "lui", "jmp", "jeq", "jne", "jgt", "jge", "jlt", "jle", "cmp", "inc",
|
||||
"dec", "shl", "shr", "add", "sub", "and", "or", "not", "xor", "nand", "nor",
|
||||
"xnor", "int", "irt", "hlt", "iadd", "isub", // Pseudo-instructions
|
||||
"db", "dh", "dw", "resb", "resh", "resw", "push", "pop", "lwi",
|
||||
];
|
||||
|
||||
pub fn to_opcode_value(&self) -> Option<u8> {
|
||||
match self {
|
||||
Self::Nop => Some(0x00),
|
||||
Self::Mov => Some(0x01),
|
||||
Self::Movs => Some(0x02),
|
||||
Self::Ldb => Some(0x03),
|
||||
Self::Ldbs => Some(0x04),
|
||||
Self::Ldh => Some(0x05),
|
||||
Self::Ldhs => Some(0x06),
|
||||
Self::Ldw => Some(0x07),
|
||||
Self::Stb => Some(0x08),
|
||||
Self::Sth => Some(0x09),
|
||||
Self::Stw => Some(0x0A),
|
||||
Self::Lli => Some(0x0B),
|
||||
Self::Lui => Some(0x0C),
|
||||
Self::Jmp => Some(0x0D),
|
||||
Self::Jeq => Some(0x0E),
|
||||
Self::Jne => Some(0x0F),
|
||||
Self::Jgt => Some(0x10),
|
||||
Self::Jge => Some(0x11),
|
||||
Self::Jlt => Some(0x12),
|
||||
Self::Jle => Some(0x13),
|
||||
Self::Cmp => Some(0x14),
|
||||
Self::Inc => Some(0x15),
|
||||
Self::Dec => Some(0x16),
|
||||
Self::Shl => Some(0x17),
|
||||
Self::Shr => Some(0x18),
|
||||
Self::Add => Some(0x19),
|
||||
Self::Sub => Some(0x1A),
|
||||
Self::And => Some(0x1B),
|
||||
Self::Or => Some(0x1C),
|
||||
Self::Not => Some(0x1D),
|
||||
Self::Xor => Some(0x1E),
|
||||
Self::Nand => Some(0x1F),
|
||||
Self::Nor => Some(0x20),
|
||||
Self::Xnor => Some(0x21),
|
||||
Self::Int => Some(0x22),
|
||||
Self::Irt => Some(0x23),
|
||||
Self::Hlt => Some(0x24),
|
||||
Self::Iadd => Some(0x25),
|
||||
Self::Isub => Some(0x26),
|
||||
// Pseudo-instructions don't have opcode values
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_pseudo_instruction(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Db
|
||||
| Self::Dh
|
||||
| Self::Dw
|
||||
| Self::Resb
|
||||
| Self::Resh
|
||||
| Self::Resw
|
||||
| Self::Push
|
||||
| Self::Pop
|
||||
| Self::Lwi
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user