added some documentation and started on compiler for custom language (not C) based on previous prototypes. pretty broken state rn.
This commit is contained in:
+21
-5
@@ -4,12 +4,15 @@ use std::str::Chars;
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
// Keywords
|
// Keywords
|
||||||
|
Fn,
|
||||||
|
Let,
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
Loop,
|
Loop,
|
||||||
Break,
|
Break,
|
||||||
Return,
|
Return,
|
||||||
Continue,
|
Continue,
|
||||||
|
Include,
|
||||||
|
|
||||||
// Identifiers and literals
|
// Identifiers and literals
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
@@ -24,7 +27,7 @@ pub enum Token {
|
|||||||
Semicolon, // ;
|
Semicolon, // ;
|
||||||
Colon, // :
|
Colon, // :
|
||||||
Comma, // ,
|
Comma, // ,
|
||||||
Pipe, // |
|
// Pipe, // |
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Plus, // +
|
Plus, // +
|
||||||
@@ -39,6 +42,7 @@ pub enum Token {
|
|||||||
LessEqual, // <=
|
LessEqual, // <=
|
||||||
Greater, // >
|
Greater, // >
|
||||||
GreaterEqual, // >=
|
GreaterEqual, // >=
|
||||||
|
RightArrow, // ->
|
||||||
|
|
||||||
// Special
|
// Special
|
||||||
Eof,
|
Eof,
|
||||||
@@ -47,7 +51,10 @@ pub enum Token {
|
|||||||
impl Token {
|
impl Token {
|
||||||
pub fn tt(&self) -> &str {
|
pub fn tt(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
|
Token::Include => "Include",
|
||||||
|
Token::Fn => "Fn",
|
||||||
Token::If => "If",
|
Token::If => "If",
|
||||||
|
Token::Let => "Let",
|
||||||
Token::Else => "Else",
|
Token::Else => "Else",
|
||||||
Token::Loop => "Loop",
|
Token::Loop => "Loop",
|
||||||
Token::Break => "Break",
|
Token::Break => "Break",
|
||||||
@@ -63,7 +70,8 @@ impl Token {
|
|||||||
Token::Semicolon => "Semicolon",
|
Token::Semicolon => "Semicolon",
|
||||||
Token::Colon => "Colon",
|
Token::Colon => "Colon",
|
||||||
Token::Comma => "Comma",
|
Token::Comma => "Comma",
|
||||||
Token::Pipe => "Pipe",
|
Token::RightArrow => "RightArrow",
|
||||||
|
// Token::Pipe => "Pipe",
|
||||||
Token::Plus => "Plus",
|
Token::Plus => "Plus",
|
||||||
Token::Minus => "Minus",
|
Token::Minus => "Minus",
|
||||||
Token::Star => "Star",
|
Token::Star => "Star",
|
||||||
@@ -168,11 +176,17 @@ impl<'a> Lexer<'a> {
|
|||||||
Some(';') => Token::Semicolon,
|
Some(';') => Token::Semicolon,
|
||||||
Some(':') => Token::Colon,
|
Some(':') => Token::Colon,
|
||||||
Some(',') => Token::Comma,
|
Some(',') => Token::Comma,
|
||||||
Some('|') => Token::Pipe,
|
// Some('|') => Token::Pipe,
|
||||||
Some('+') => Token::Plus,
|
Some('+') => Token::Plus,
|
||||||
Some('-') => Token::Minus,
|
|
||||||
Some('*') => Token::Star,
|
Some('*') => Token::Star,
|
||||||
Some('/') => Token::Slash,
|
Some('/') => Token::Slash,
|
||||||
|
Some('-') => {
|
||||||
|
if self.match_next('>') {
|
||||||
|
Token::RightArrow
|
||||||
|
} else {
|
||||||
|
Token::Minus
|
||||||
|
}
|
||||||
|
}
|
||||||
Some('!') => {
|
Some('!') => {
|
||||||
if self.match_next('=') {
|
if self.match_next('=') {
|
||||||
Token::BangEqual
|
Token::BangEqual
|
||||||
@@ -218,12 +232,14 @@ impl<'a> Lexer<'a> {
|
|||||||
let mut ident = c.to_string();
|
let mut ident = c.to_string();
|
||||||
ident.push_str(&self.read_identifier());
|
ident.push_str(&self.read_identifier());
|
||||||
match ident.as_str() {
|
match ident.as_str() {
|
||||||
|
"fn" => Token::Fn,
|
||||||
"if" => Token::If,
|
"if" => Token::If,
|
||||||
"else" => Token::Else,
|
"else" => Token::Else,
|
||||||
"loop" => Token::Loop,
|
"loop" => Token::Loop,
|
||||||
"break" => Token::Break,
|
"break" => Token::Break,
|
||||||
"return" => Token::Return,
|
"return" => Token::Return,
|
||||||
"continue" => Token::Continue,
|
"continue" => Token::Continue,
|
||||||
|
"include" => Token::Include,
|
||||||
_ => Token::Identifier(ident),
|
_ => Token::Identifier(ident),
|
||||||
}
|
}
|
||||||
} else if c.is_ascii_digit() {
|
} else if c.is_ascii_digit() {
|
||||||
@@ -331,7 +347,7 @@ mod tests {
|
|||||||
assert_eq!(lexer.next_token(), Token::Colon);
|
assert_eq!(lexer.next_token(), Token::Colon);
|
||||||
assert_eq!(lexer.next_token(), Token::Identifier("Func".to_string()));
|
assert_eq!(lexer.next_token(), Token::Identifier("Func".to_string()));
|
||||||
assert_eq!(lexer.next_token(), Token::Assign);
|
assert_eq!(lexer.next_token(), Token::Assign);
|
||||||
assert_eq!(lexer.next_token(), Token::Pipe);
|
// assert_eq!(lexer.next_token(), Token::Pipe);
|
||||||
assert_eq!(lexer.next_token(), Token::Identifier("x".to_string()));
|
assert_eq!(lexer.next_token(), Token::Identifier("x".to_string()));
|
||||||
assert_eq!(lexer.next_token(), Token::Colon);
|
assert_eq!(lexer.next_token(), Token::Colon);
|
||||||
assert_eq!(lexer.next_token(), Token::Identifier("U32".to_string()));
|
assert_eq!(lexer.next_token(), Token::Identifier("U32".to_string()));
|
||||||
|
|||||||
+12
-4
@@ -1,7 +1,12 @@
|
|||||||
|
#![feature(try_trait_v2)]
|
||||||
|
|
||||||
use std::{fs, path::Path};
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parserprototype;
|
||||||
|
use parserprototype::Parser;
|
||||||
|
|
||||||
|
use crate::parserprototype::ParseResult;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
@@ -13,13 +18,16 @@ fn main() {
|
|||||||
let tokens = lexer.collect::<Vec<_>>();
|
let tokens = lexer.collect::<Vec<_>>();
|
||||||
println!("{tokens:?}");
|
println!("{tokens:?}");
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
let ast = match parser.parse() {
|
let ast = match parser.parse() {
|
||||||
Ok(ast) => ast,
|
ParseResult::Accept(ast) => ast,
|
||||||
Err(e) => {
|
ParseResult::Reject(e) => {
|
||||||
eprintln!("Error: {e:?}");
|
eprintln!("Error: {e:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ParseResult::Deny => {
|
||||||
|
panic!("Parser denied parsing")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
println!("{ast:?}");
|
println!("{ast:?}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,435 @@
|
|||||||
|
use crate::lexer::Token;
|
||||||
|
use crate::{expect_tt, expect_value};
|
||||||
|
use core::fmt;
|
||||||
|
use std::ops::{ControlFlow, FromResidual, Try};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ParseResult<T, E> {
|
||||||
|
Accept(T),
|
||||||
|
Deny,
|
||||||
|
Reject(E),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum CompilerError {
|
||||||
|
UnexpectedToken(Token),
|
||||||
|
UnexpectedEndOfInput,
|
||||||
|
UnexpectedCharacter(char),
|
||||||
|
InvalidSyntax(String),
|
||||||
|
Generic(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Parser {
|
||||||
|
tokens: Vec<Token>,
|
||||||
|
idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
|
Self { tokens, idx: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(&mut self) -> ParseResult<Program, CompilerError> {
|
||||||
|
let mut declarations = Vec::new();
|
||||||
|
|
||||||
|
while let ParseResult::Accept(_) = self.peek_next() {
|
||||||
|
declarations.push(self.parse_declaration()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseResult::Accept(Program {
|
||||||
|
imports: vec![],
|
||||||
|
declarations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_declaration(&mut self) -> ParseResult<Declaration, CompilerError> {
|
||||||
|
if expect_tt!(self.peek_next()?, Fn).accepted() {
|
||||||
|
let x = self.parse_func();
|
||||||
|
println!("function {:?}", x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", self.peek_next()?);
|
||||||
|
|
||||||
|
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_func(&mut self) -> ParseResult<Declaration, CompilerError> {
|
||||||
|
// expect function keyword
|
||||||
|
//
|
||||||
|
println!("pre name! {:?}", self.peek_next()?);
|
||||||
|
|
||||||
|
let _ = expect_tt!(self.next()?, Fn);
|
||||||
|
|
||||||
|
println!("this is the name! {:?}", self.peek_next()?);
|
||||||
|
|
||||||
|
// expect function name
|
||||||
|
let name = match self.next()? {
|
||||||
|
Token::Identifier(name) => name,
|
||||||
|
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// expect left paren
|
||||||
|
let _ = expect_tt!(self.next()?, LParen);
|
||||||
|
|
||||||
|
let mut params = Vec::new();
|
||||||
|
while expect_tt!(self.peek_next()?, Identifier).accepted() {
|
||||||
|
let arg = self.parse_var_decl()?;
|
||||||
|
params.push(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect right paren
|
||||||
|
let _ = expect_tt!(self.next()?, RParen);
|
||||||
|
|
||||||
|
// see if we can parse the return type!
|
||||||
|
let mut return_type = TypeId::Void;
|
||||||
|
|
||||||
|
if expect_tt!(self.peek_next()?, RightArrow).accepted() {
|
||||||
|
let _ = self.next();
|
||||||
|
return_type = self.parse_type()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect left brace
|
||||||
|
let _ = expect_tt!(self.next()?, LBrace);
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
|
||||||
|
// expect right brace
|
||||||
|
let _ = expect_tt!(self.next()?, RBrace);
|
||||||
|
|
||||||
|
ParseResult::Accept(Declaration::Function {
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
return_type,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_var_decl(&mut self) -> ParseResult<Variable, CompilerError> {
|
||||||
|
let name = match self.next()? {
|
||||||
|
Token::Identifier(name) => name,
|
||||||
|
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = expect_tt!(self.next()?, Colon);
|
||||||
|
|
||||||
|
let type_ = self.parse_type()?;
|
||||||
|
|
||||||
|
ParseResult::Accept(Variable {
|
||||||
|
name,
|
||||||
|
param_type: Some(type_),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_type(&mut self) -> ParseResult<TypeId, CompilerError> {
|
||||||
|
// get the type name incl namespace
|
||||||
|
let typename = self.parse_identifier()?;
|
||||||
|
|
||||||
|
match typename.name.as_str() {
|
||||||
|
"u32" => ParseResult::Accept(TypeId::U32),
|
||||||
|
"u16" => ParseResult::Accept(TypeId::U16),
|
||||||
|
"u8" => ParseResult::Accept(TypeId::U8),
|
||||||
|
"i32" => ParseResult::Accept(TypeId::I32),
|
||||||
|
"i16" => ParseResult::Accept(TypeId::I16),
|
||||||
|
"i8" => ParseResult::Accept(TypeId::I8),
|
||||||
|
"void" => ParseResult::Accept(TypeId::Void),
|
||||||
|
"char" => ParseResult::Accept(TypeId::Char),
|
||||||
|
_ => todo!("Implement parsing for other types!!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_identifier(&mut self) -> ParseResult<Name, CompilerError> {
|
||||||
|
let primary = match self.next()? {
|
||||||
|
Token::Identifier(namespace) => namespace,
|
||||||
|
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
|
||||||
|
};
|
||||||
|
|
||||||
|
if expect_tt!(self.peek_next()?, Colon).accepted() {
|
||||||
|
let _ = expect_tt!(self.next()?, Colon);
|
||||||
|
let _ = expect_tt!(self.next()?, Colon);
|
||||||
|
|
||||||
|
let secondary = match self.next()? {
|
||||||
|
Token::Identifier(name) => name,
|
||||||
|
id => return ParseResult::Reject(CompilerError::UnexpectedToken(id)),
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseResult::Accept(Name {
|
||||||
|
namespace: Some(primary),
|
||||||
|
name: secondary,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ParseResult::Accept(Name {
|
||||||
|
namespace: None,
|
||||||
|
name: primary,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self) -> ParseResult<Token, CompilerError> {
|
||||||
|
if self.idx >= self.tokens.len() {
|
||||||
|
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
|
||||||
|
} else {
|
||||||
|
let token = self.tokens[self.idx].clone();
|
||||||
|
println!("NEXT {:?}", token);
|
||||||
|
self.idx += 1;
|
||||||
|
ParseResult::Accept(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek_next(&self) -> ParseResult<Token, CompilerError> {
|
||||||
|
if self.idx >= self.tokens.len() {
|
||||||
|
ParseResult::Reject(CompilerError::UnexpectedEndOfInput)
|
||||||
|
} else {
|
||||||
|
ParseResult::Accept(self.tokens[self.idx].clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Program {
|
||||||
|
pub imports: Vec<Dependency>,
|
||||||
|
pub declarations: Vec<Declaration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Declaration {
|
||||||
|
Function {
|
||||||
|
name: String,
|
||||||
|
return_type: TypeId,
|
||||||
|
params: Vec<Variable>,
|
||||||
|
body: Block,
|
||||||
|
},
|
||||||
|
Variable {
|
||||||
|
name: String,
|
||||||
|
init: Option<ConstExpr>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Dependency {
|
||||||
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Variable {
|
||||||
|
pub name: String,
|
||||||
|
pub param_type: Option<TypeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Name {
|
||||||
|
pub name: String,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TypeId {
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
Char,
|
||||||
|
Void,
|
||||||
|
Ptr(Box<TypeId>),
|
||||||
|
Ref(Box<TypeId>),
|
||||||
|
Array(Box<TypeId>, usize),
|
||||||
|
Struct {
|
||||||
|
name: Name,
|
||||||
|
fields: Vec<(String, TypeId)>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Block = Vec<Statement>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Statement {
|
||||||
|
Block(Block),
|
||||||
|
Assign {
|
||||||
|
var: Variable,
|
||||||
|
value: Option<Box<Expression>>,
|
||||||
|
},
|
||||||
|
Expression {
|
||||||
|
expr: Expression,
|
||||||
|
},
|
||||||
|
If {
|
||||||
|
condition: Expression,
|
||||||
|
then_stmt: Block,
|
||||||
|
else_stmt: Block,
|
||||||
|
},
|
||||||
|
While {
|
||||||
|
condition: Expression,
|
||||||
|
body: Vec<Statement>,
|
||||||
|
},
|
||||||
|
Loop(Block),
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
Return(Option<Expression>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ConstExpr {
|
||||||
|
Number(i32),
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ConstExpr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ConstExpr::Number(n) => write!(f, "{}", n),
|
||||||
|
ConstExpr::String(s) => write!(f, "\"{}\"", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Expression {
|
||||||
|
Empty,
|
||||||
|
Binary {
|
||||||
|
op: BinaryOperator,
|
||||||
|
left: Box<Expression>,
|
||||||
|
right: Box<Expression>,
|
||||||
|
},
|
||||||
|
Unary {
|
||||||
|
op: UnaryOperator,
|
||||||
|
operand: Box<Expression>,
|
||||||
|
},
|
||||||
|
Variable {
|
||||||
|
name: Name,
|
||||||
|
expr_type: Option<TypeId>,
|
||||||
|
},
|
||||||
|
Number {
|
||||||
|
value: i32,
|
||||||
|
},
|
||||||
|
Call {
|
||||||
|
name: Name,
|
||||||
|
args: Vec<Expression>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum BinaryOperator {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Eq,
|
||||||
|
Ne,
|
||||||
|
Lt,
|
||||||
|
Gt,
|
||||||
|
Le,
|
||||||
|
Ge,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BinaryOperator {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BinaryOperator::Add => write!(f, "+"),
|
||||||
|
BinaryOperator::Sub => write!(f, "-"),
|
||||||
|
BinaryOperator::Mul => write!(f, "*"),
|
||||||
|
BinaryOperator::Div => write!(f, "/"),
|
||||||
|
BinaryOperator::Eq => write!(f, "=="),
|
||||||
|
BinaryOperator::Ne => write!(f, "!="),
|
||||||
|
BinaryOperator::Lt => write!(f, "<"),
|
||||||
|
BinaryOperator::Gt => write!(f, ">"),
|
||||||
|
BinaryOperator::Le => write!(f, "<="),
|
||||||
|
BinaryOperator::Ge => write!(f, ">="),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum UnaryOperator {
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UnaryOperator {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
UnaryOperator::Plus => write!(f, "+"),
|
||||||
|
UnaryOperator::Minus => write!(f, "-"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> ParseResult<T, E> {
|
||||||
|
pub fn accepted(&self) -> bool {
|
||||||
|
matches!(self, ParseResult::Accept(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ParseResultResidual<T> {
|
||||||
|
Deny,
|
||||||
|
Reject(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Try for ParseResult<T, E> {
|
||||||
|
type Output = T;
|
||||||
|
type Residual = ParseResultResidual<E>;
|
||||||
|
|
||||||
|
fn from_output(output: T) -> Self {
|
||||||
|
ParseResult::Accept(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
|
||||||
|
match self {
|
||||||
|
ParseResult::Accept(v) => ControlFlow::Continue(v),
|
||||||
|
ParseResult::Deny => ControlFlow::Break(ParseResultResidual::Deny),
|
||||||
|
ParseResult::Reject(e) => ControlFlow::Break(ParseResultResidual::Reject(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> FromResidual for ParseResult<T, E> {
|
||||||
|
fn from_residual(residual: ParseResultResidual<E>) -> Self {
|
||||||
|
match residual {
|
||||||
|
ParseResultResidual::Deny => ParseResult::Deny,
|
||||||
|
ParseResultResidual::Reject(e) => ParseResult::Reject(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect_tt {
|
||||||
|
($token:expr, $($variant:ident),+) => {{
|
||||||
|
let tt = $token.tt().to_string();
|
||||||
|
|
||||||
|
// for some reason the code trips tf out without this line
|
||||||
|
|
||||||
|
println!("token {:?}", $token);
|
||||||
|
|
||||||
|
let mut vs = String::new();
|
||||||
|
$(
|
||||||
|
let s = stringify!($variant);
|
||||||
|
vs.push_str(s);
|
||||||
|
vs.push_str("|");
|
||||||
|
)+
|
||||||
|
|
||||||
|
match tt.as_str() {
|
||||||
|
$(
|
||||||
|
stringify!($variant) => ParseResult::Accept($token.clone()),
|
||||||
|
)+
|
||||||
|
_ => {
|
||||||
|
println!("EXPECTED!! {} [{}]", tt, vs);
|
||||||
|
// let expected = format!("[{}]", vec![$(stringify!($variant)),+].join(" | "));
|
||||||
|
ParseResult::Reject(CompilerError::UnexpectedToken($token.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect_value {
|
||||||
|
($token:expr, $variant:expr) => {{
|
||||||
|
match $token {
|
||||||
|
$variant(x) => ParseResult::Accept(x),
|
||||||
|
_ => {
|
||||||
|
let expected = format!("[{}]")
|
||||||
|
ParseResult::Reject(CompilerError::UnexpectedToken($token.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
@@ -1,8 +1,2 @@
|
|||||||
main: Func = | x: U32, y: U32 | {
|
fn factorial(n: u32) -> u32 {}
|
||||||
res = add(x, y);
|
fn main(x: u32, y: u32) -> u32 {}
|
||||||
print(res);
|
|
||||||
|
|
||||||
if res > 10 {
|
|
||||||
print("res is greater than 10");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,843 @@
|
|||||||
|
# DSA Project Roadmap & Task Breakdown
|
||||||
|
|
||||||
|
> **Damn Simple Architecture** — Full ecosystem development plan including emulator, assembler, compiler, debugger, and tooling infrastructure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Phase 1: Foundation & Core Infrastructure](#phase-1-foundation--core-infrastructure)
|
||||||
|
- [1.1 Binary Format & Linking System](#11-binary-format--linking-system)
|
||||||
|
- [1.2 Assembler Rewrite](#12-assembler-rewrite)
|
||||||
|
- [1.3 Documentation Updates](#13-documentation-updates)
|
||||||
|
2. [Phase 2: Compiler Development](#phase-2-compiler-development)
|
||||||
|
- [2.1 Language Design & Implementation](#21-language-design--implementation)
|
||||||
|
- [2.2 Standard Library](#22-standard-library)
|
||||||
|
3. [Phase 3: Build System & Package Management](#phase-3-build-system--package-management)
|
||||||
|
- [3.1 Build System](#31-build-system)
|
||||||
|
- [3.2 Package Management System](#32-package-management-system)
|
||||||
|
4. [Phase 4: Debugger & Development Tools](#phase-4-debugger--development-tools)
|
||||||
|
- [4.1 Debug Symbol System](#41-debug-symbol-system)
|
||||||
|
- [4.2 Debugger Implementation](#42-debugger-implementation)
|
||||||
|
- [4.3 Enhanced Editor Integration](#43-enhanced-editor-integration)
|
||||||
|
5. [Phase 5: Integration & Polish](#phase-5-integration--polish)
|
||||||
|
6. [Phase 6: Future Enhancements (NTH)](#phase-6-future-enhancements-nth)
|
||||||
|
7. [Summary Timeline](#summary-timeline)
|
||||||
|
8. [Critical Path](#critical-path)
|
||||||
|
9. [Recommended Work Order](#recommended-work-order)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Foundation & Core Infrastructure
|
||||||
|
|
||||||
|
**Estimated Duration: 3–4 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.1 Binary Format & Linking System
|
||||||
|
|
||||||
|
> **Priority: CRITICAL** — Everything depends on this.
|
||||||
|
> **Total Estimate: 1.5 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.1.1 Design New Binary Format Specification
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** None
|
||||||
|
**Deliverable:** `docs/binary-format-spec.md`
|
||||||
|
|
||||||
|
- [ ] Research existing object file formats (ELF, COFF, Mach-O) for inspiration
|
||||||
|
- [ ] Design `.dsb` object file format specification
|
||||||
|
- [ ] Symbol table structure
|
||||||
|
- [ ] Relocation table format
|
||||||
|
- [ ] Section definitions (code, data, rodata, bss)
|
||||||
|
- [ ] Debug information structure
|
||||||
|
- [ ] Metadata headers
|
||||||
|
- [ ] Design `.dse` executable format specification
|
||||||
|
- [ ] Entry point definition
|
||||||
|
- [ ] Memory layout requirements
|
||||||
|
- [ ] Linking metadata
|
||||||
|
- [ ] Document format specifications in markdown
|
||||||
|
- [ ] Create format version strategy for future compatibility
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.1.2 Implement DSB Object File Writer
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 1.1.1
|
||||||
|
**Deliverable:** `dsa-binary-format` crate v0.1.0
|
||||||
|
|
||||||
|
- [ ] Create new crate: `dsa-binary-format`
|
||||||
|
- [ ] Implement object file structures
|
||||||
|
- [ ] Header structure
|
||||||
|
- [ ] Symbol table builder
|
||||||
|
- [ ] Section manager
|
||||||
|
- [ ] Relocation entry creator
|
||||||
|
- [ ] Write serialization logic
|
||||||
|
- [ ] Add validation and error handling
|
||||||
|
- [ ] Write unit tests for each structure
|
||||||
|
- [ ] Integration tests for complete object files
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.1.3 Build Linker Program
|
||||||
|
|
||||||
|
**Estimate: 4 days**
|
||||||
|
**Dependencies:** 1.1.2
|
||||||
|
**Deliverable:** `dsa-link` executable
|
||||||
|
|
||||||
|
- [ ] Create new crate: `dsa-linker`
|
||||||
|
- [ ] Implement symbol resolution
|
||||||
|
- [ ] Global symbol table
|
||||||
|
- [ ] Symbol conflict detection
|
||||||
|
- [ ] Weak symbol handling
|
||||||
|
- [ ] Implement relocation processing
|
||||||
|
- [ ] Address calculation
|
||||||
|
- [ ] Patch generation
|
||||||
|
- [ ] Cross-section references
|
||||||
|
- [ ] Build executable generator
|
||||||
|
- [ ] Combine sections
|
||||||
|
- [ ] Generate final memory layout
|
||||||
|
- [ ] Write `.dse` output
|
||||||
|
- [ ] Add linker script support (basic)
|
||||||
|
- [ ] Comprehensive error messages
|
||||||
|
- [ ] Test suite with complex linking scenarios
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.2 Assembler Rewrite
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Required for all compiled code.
|
||||||
|
> **Total Estimate: 1.5 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.2.1 Assembler Architecture Design
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** 1.1.1
|
||||||
|
**Deliverable:** `docs/assembler-architecture.md`
|
||||||
|
|
||||||
|
- [ ] Design multi-pass architecture
|
||||||
|
- [ ] Pass 1: Symbol collection
|
||||||
|
- [ ] Pass 2: Macro expansion
|
||||||
|
- [ ] Pass 3: Code generation
|
||||||
|
- [ ] Pass 4: Relocation generation
|
||||||
|
- [ ] Plan error handling strategy
|
||||||
|
- [ ] Design threading model for parallel file processing
|
||||||
|
- [ ] Define module/import resolution system
|
||||||
|
- [ ] Plan integration points with DSC compiler
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.2.2 Implement Core Assembler
|
||||||
|
|
||||||
|
**Estimate: 5 days**
|
||||||
|
**Dependencies:** 1.1.2, 1.2.1
|
||||||
|
**Deliverable:** `dsa-asm` executable v2.0.0
|
||||||
|
|
||||||
|
- [ ] Create new crate: `dsa-assembler-ng` (next-gen)
|
||||||
|
- [ ] Implement lexer with better error recovery
|
||||||
|
- [ ] Build parser with detailed error messages
|
||||||
|
- [ ] Instruction parsing
|
||||||
|
- [ ] Directive handling
|
||||||
|
- [ ] Macro system
|
||||||
|
- [ ] Include resolution
|
||||||
|
- [ ] Symbol table management
|
||||||
|
- [ ] Code generator outputting to DSB format
|
||||||
|
- [ ] Multi-threading for file parsing
|
||||||
|
- [ ] Comprehensive test suite
|
||||||
|
- [ ] Error message testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.2.3 Import System & DSC Integration
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 1.2.2, 2.1.2
|
||||||
|
**Deliverable:** Working import system
|
||||||
|
|
||||||
|
- [ ] Design import protocol between DSC and assembler
|
||||||
|
- [ ] Implement symbol table merging
|
||||||
|
- [ ] Handle pre-compiled object imports
|
||||||
|
- [ ] Test DSC → Assembly → Object pipeline
|
||||||
|
- [ ] Document integration process
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.3 Documentation Updates
|
||||||
|
|
||||||
|
> **Priority: MEDIUM** — Can be done alongside development.
|
||||||
|
> **Total Estimate: 3 days (distributed)**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.3.1 Update Assembly Documentation
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** 1.2.2
|
||||||
|
**Deliverable:** Updated `docs/dsa-assembly-reference.md`
|
||||||
|
|
||||||
|
- [ ] Review all instruction documentation
|
||||||
|
- [ ] Document new pseudo-instructions
|
||||||
|
- [ ] Update calling convention docs
|
||||||
|
- [ ] Add examples for new features
|
||||||
|
- [ ] Document assembler directives
|
||||||
|
- [ ] Macro system documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.3.2 Architecture Documentation
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** None (can start anytime)
|
||||||
|
**Deliverable:** `docs/dsa-architecture.md`
|
||||||
|
|
||||||
|
- [ ] Document ISA specification
|
||||||
|
- [ ] Memory model documentation
|
||||||
|
- [ ] Interrupt handling
|
||||||
|
- [ ] Hardware peripheral specs
|
||||||
|
- [ ] Timing/performance characteristics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 1.3.3 Build Tools Documentation
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** 1.2.2, 1.1.3, 3.1.2
|
||||||
|
**Deliverable:** `docs/build-tools-guide.md`
|
||||||
|
|
||||||
|
- [ ] Assembler usage guide
|
||||||
|
- [ ] Linker usage guide
|
||||||
|
- [ ] Build system guide
|
||||||
|
- [ ] Tutorial: Building a simple program
|
||||||
|
- [ ] Tutorial: Multi-file projects
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Compiler Development
|
||||||
|
|
||||||
|
**Estimated Duration: 3–4 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.1 Language Design & Implementation
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Core functionality.
|
||||||
|
> **Total Estimate: 2.5 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.1.1 Language Syntax Design
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** None
|
||||||
|
**Deliverable:** `docs/language-spec.md`
|
||||||
|
|
||||||
|
- [ ] Define syntax goals (simplicity, systems programming)
|
||||||
|
- [ ] Design type system
|
||||||
|
- [ ] Primitive types
|
||||||
|
- [ ] Pointers/references
|
||||||
|
- [ ] Structs
|
||||||
|
- [ ] Arrays
|
||||||
|
- [ ] Function types
|
||||||
|
- [ ] Control flow syntax
|
||||||
|
- [ ] Function declaration syntax
|
||||||
|
- [ ] Module/import system
|
||||||
|
- [ ] Operator precedence
|
||||||
|
- [ ] Write EBNF grammar
|
||||||
|
- [ ] Create example programs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.1.2 Lexer & Parser Implementation
|
||||||
|
|
||||||
|
**Estimate: 4 days**
|
||||||
|
**Dependencies:** 2.1.1
|
||||||
|
**Deliverable:** Parser in `dsc-compiler` crate
|
||||||
|
|
||||||
|
- [ ] Adapt existing C lexer to new syntax
|
||||||
|
- [ ] Implement new parser for designed syntax
|
||||||
|
- [ ] AST node definitions
|
||||||
|
- [ ] Error recovery mechanisms
|
||||||
|
- [ ] Comprehensive parser tests
|
||||||
|
- [ ] Syntax error message quality testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.1.3 Code Generation Improvements
|
||||||
|
|
||||||
|
**Estimate: 5 days**
|
||||||
|
**Dependencies:** 2.1.2, 1.2.2
|
||||||
|
**Deliverable:** Working code generator
|
||||||
|
|
||||||
|
- [ ] Review and fix existing codegen issues
|
||||||
|
- [ ] Implement missing language features
|
||||||
|
- [ ] Structs
|
||||||
|
- [ ] Arrays
|
||||||
|
- [ ] Pointers/memory operations
|
||||||
|
- [ ] For loops
|
||||||
|
- [ ] Switch statements
|
||||||
|
- [ ] Break/continue
|
||||||
|
- [ ] Optimize register allocation further
|
||||||
|
- [ ] Implement proper function calling conventions
|
||||||
|
- [ ] Add constant folding optimization
|
||||||
|
- [ ] Dead code elimination
|
||||||
|
- [ ] Test each feature thoroughly
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.1.4 Type Checking & Semantic Analysis
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 2.1.2
|
||||||
|
**Deliverable:** Type checker integrated in compiler
|
||||||
|
|
||||||
|
- [ ] Implement type checker
|
||||||
|
- [ ] Symbol table for scoping
|
||||||
|
- [ ] Type inference where applicable
|
||||||
|
- [ ] Const checking
|
||||||
|
- [ ] Definite assignment analysis
|
||||||
|
- [ ] Comprehensive semantic error messages
|
||||||
|
- [ ] Test suite for type errors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 Standard Library
|
||||||
|
|
||||||
|
> **Priority: MEDIUM** — Needed for useful programs.
|
||||||
|
> **Total Estimate: 1 week**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.2.1 Core Runtime Library (in Assembly)
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 1.2.2
|
||||||
|
**Deliverable:** `lib/runtime/` directory
|
||||||
|
|
||||||
|
- [ ] Memory allocation (malloc/free)
|
||||||
|
- [ ] String operations
|
||||||
|
- [ ] Math functions
|
||||||
|
- [ ] I/O functions (improved print, read)
|
||||||
|
- [ ] System call interface
|
||||||
|
- [ ] Tests for each function
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2.2.2 Standard Library (in DSC)
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 2.1.3, 2.2.1
|
||||||
|
**Deliverable:** `lib/std/` directory
|
||||||
|
|
||||||
|
- [ ] String module
|
||||||
|
- [ ] Collections (array utilities, maybe simple list)
|
||||||
|
- [ ] File I/O module
|
||||||
|
- [ ] Math utilities
|
||||||
|
- [ ] Tests and examples
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: Build System & Package Management
|
||||||
|
|
||||||
|
**Estimated Duration: 2–3 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.1 Build System
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Required for complex projects.
|
||||||
|
> **Total Estimate: 1.5 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.1.1 Build System Design
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** None
|
||||||
|
**Deliverable:** `docs/build-system-design.md`
|
||||||
|
|
||||||
|
- [ ] Define project structure conventions
|
||||||
|
- [ ] Design build manifest format (`dsa-project.toml` or similar)
|
||||||
|
- [ ] Dependency resolution strategy
|
||||||
|
- [ ] Build cache design
|
||||||
|
- [ ] Incremental build strategy
|
||||||
|
- [ ] Multi-target support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.1.2 Build Tool Implementation
|
||||||
|
|
||||||
|
**Estimate: 5 days**
|
||||||
|
**Dependencies:** 3.1.1, 1.2.2, 1.1.3, 2.1.3
|
||||||
|
**Deliverable:** `dsa-build` executable
|
||||||
|
|
||||||
|
- [ ] Create crate: `dsa-build`
|
||||||
|
- [ ] Manifest parser
|
||||||
|
- [ ] Dependency graph builder
|
||||||
|
- [ ] Task orchestrator
|
||||||
|
- [ ] Compilation tasks
|
||||||
|
- [ ] Assembly tasks
|
||||||
|
- [ ] Linking tasks
|
||||||
|
- [ ] Build cache implementation
|
||||||
|
- [ ] Parallel build support
|
||||||
|
- [ ] Clean, rebuild commands
|
||||||
|
- [ ] Watch mode for development
|
||||||
|
- [ ] Comprehensive tests
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.1.3 Project Management Commands
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 3.1.2
|
||||||
|
**Deliverable:** Enhanced `dsa-build` with project management
|
||||||
|
|
||||||
|
- [ ] `dsa new <project>` — Create new project
|
||||||
|
- [ ] `dsa init` — Initialize in existing directory
|
||||||
|
- [ ] `dsa add <dependency>` — Add dependency
|
||||||
|
- [ ] Binary vs library project types
|
||||||
|
- [ ] Template system for project scaffolding
|
||||||
|
- [ ] Documentation for each command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.2 Package Management System
|
||||||
|
|
||||||
|
> **Priority: MEDIUM** — Enables code sharing.
|
||||||
|
> **Total Estimate: 1.5 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.2.1 Package Registry Design
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 3.1.1
|
||||||
|
**Deliverable:** `docs/package-registry-design.md`
|
||||||
|
|
||||||
|
- [ ] Decide: Git monorepo vs custom hosting
|
||||||
|
- [ ] Design package naming conventions
|
||||||
|
- [ ] Version resolution strategy (semver)
|
||||||
|
- [ ] Package manifest format
|
||||||
|
- [ ] Security considerations
|
||||||
|
- [ ] Package storage format (source/binary/both)
|
||||||
|
- [ ] API design for registry server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.2.2 Local Package Manager Tool
|
||||||
|
|
||||||
|
**Estimate: 4 days**
|
||||||
|
**Dependencies:** 3.2.1, 3.1.2
|
||||||
|
**Deliverable:** `dsa-pkg` tool integrated with `dsa-build`
|
||||||
|
|
||||||
|
- [ ] Create crate: `dsa-pkg`
|
||||||
|
- [ ] Package index synchronization
|
||||||
|
- [ ] Dependency resolver
|
||||||
|
- [ ] Package download/cache system
|
||||||
|
- [ ] Integration with build system
|
||||||
|
- [ ] Commands:
|
||||||
|
- [ ] `dsa install <package>`
|
||||||
|
- [ ] `dsa publish`
|
||||||
|
- [ ] `dsa search <query>`
|
||||||
|
- [ ] `dsa update`
|
||||||
|
- [ ] Lock file generation
|
||||||
|
- [ ] Test with mock registry
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3.2.3 Package Registry Implementation
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 3.2.1
|
||||||
|
**Deliverable:** Package registry (URL or repo)
|
||||||
|
|
||||||
|
- [ ] If **Git monorepo** approach:
|
||||||
|
- [ ] Set up repository structure
|
||||||
|
- [ ] CI/CD for validation
|
||||||
|
- [ ] Submission process
|
||||||
|
- [ ] Package browser website
|
||||||
|
- [ ] If **custom hosting**:
|
||||||
|
- [ ] Simple web server (Rust + Axum/Actix)
|
||||||
|
- [ ] Package upload API
|
||||||
|
- [ ] Package search API
|
||||||
|
- [ ] Basic web UI
|
||||||
|
- [ ] Database for metadata
|
||||||
|
- [ ] Documentation for publishing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: Debugger & Development Tools
|
||||||
|
|
||||||
|
**Estimated Duration: 3–4 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.1 Debug Symbol System
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Foundation for debugging.
|
||||||
|
> **Total Estimate: 1 week**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.1.1 Debug Symbol Format Design
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** 1.1.1
|
||||||
|
**Deliverable:** `docs/debug-symbol-format.md`
|
||||||
|
|
||||||
|
- [ ] Design symbol table format
|
||||||
|
- [ ] Function addresses → names
|
||||||
|
- [ ] Line number → address mapping
|
||||||
|
- [ ] Variable location information
|
||||||
|
- [ ] Type information
|
||||||
|
- [ ] Define symbol table file format
|
||||||
|
- [ ] Plan for embedding in DSE/DSB files
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.1.2 Symbol Generation in Tools
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 4.1.1, 1.2.2, 2.1.3
|
||||||
|
**Deliverable:** Debug symbols in build output
|
||||||
|
|
||||||
|
- [ ] Modify assembler to emit debug symbols
|
||||||
|
- [ ] Modify compiler to emit debug symbols
|
||||||
|
- [ ] Source file/line tracking
|
||||||
|
- [ ] Variable scope tracking
|
||||||
|
- [ ] Linker merges debug symbols
|
||||||
|
- [ ] Test symbol generation pipeline
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.1.3 Symbol Table Loader in Emulator
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 4.1.2
|
||||||
|
**Deliverable:** Symbol loading in emulator crate
|
||||||
|
|
||||||
|
- [ ] Implement symbol table parser
|
||||||
|
- [ ] Build address → symbol lookup (HashMap)
|
||||||
|
- [ ] Build symbol → address lookup
|
||||||
|
- [ ] Memory efficient storage
|
||||||
|
- [ ] Tests for symbol resolution
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 Debugger Implementation
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Major productivity boost.
|
||||||
|
> **Total Estimate: 2 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.2.1 Core Debugger Features
|
||||||
|
|
||||||
|
**Estimate: 5 days**
|
||||||
|
**Dependencies:** 4.1.3
|
||||||
|
**Deliverable:** Debugger backend
|
||||||
|
|
||||||
|
- [ ] Execution control
|
||||||
|
- [ ] Step instruction
|
||||||
|
- [ ] Step over function calls
|
||||||
|
- [ ] Continue to breakpoint
|
||||||
|
- [ ] Run to cursor
|
||||||
|
- [ ] Breakpoint system
|
||||||
|
- [ ] Address breakpoints
|
||||||
|
- [ ] Conditional breakpoints
|
||||||
|
- [ ] Watchpoints (memory access)
|
||||||
|
- [ ] Register inspection
|
||||||
|
- [ ] Memory inspection
|
||||||
|
- [ ] Stack trace generation
|
||||||
|
- [ ] Test debugger commands
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.2.2 Disassembler with Symbol Resolution
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** 4.1.3
|
||||||
|
**Deliverable:** Enhanced disassembler
|
||||||
|
|
||||||
|
- [ ] Instruction decoder
|
||||||
|
- [ ] Format with labels instead of addresses
|
||||||
|
- [ ] Show function names at call sites
|
||||||
|
- [ ] Inline comments with variable names
|
||||||
|
- [ ] Color coding for instruction types
|
||||||
|
- [ ] Tests for disassembly output
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.2.3 Pseudo-Instruction Decompiler
|
||||||
|
|
||||||
|
> ⚠️ **COMPLEX TASK** — Separate pass to decompile assembly into readable pseudo-instructions.
|
||||||
|
|
||||||
|
**Estimate: 4 days**
|
||||||
|
**Dependencies:** 4.2.2
|
||||||
|
**Deliverable:** Pseudo-instruction view mode
|
||||||
|
|
||||||
|
- [ ] Pattern recognition for common sequences
|
||||||
|
- [ ] Function prologue/epilogue
|
||||||
|
- [ ] Multiplication using shifts/adds
|
||||||
|
- [ ] Division
|
||||||
|
- [ ] Conditional moves
|
||||||
|
- [ ] Control flow reconstruction
|
||||||
|
- [ ] If/else detection
|
||||||
|
- [ ] Loop detection
|
||||||
|
- [ ] Switch statement detection
|
||||||
|
- [ ] Expression reconstruction
|
||||||
|
- [ ] Format as higher-level pseudo-code
|
||||||
|
- [ ] Extensive pattern testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.2.4 Execution History Tracking
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 4.2.1
|
||||||
|
**Deliverable:** Execution trace feature
|
||||||
|
|
||||||
|
- [ ] Circular buffer for instruction history
|
||||||
|
- [ ] Register state snapshots over time
|
||||||
|
- [ ] Configurable history depth
|
||||||
|
- [ ] Efficient memory usage
|
||||||
|
- [ ] Playback/reverse debugging (basic)
|
||||||
|
- [ ] Export trace to file
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.3 Enhanced Editor Integration
|
||||||
|
|
||||||
|
> **Priority: MEDIUM** — UX improvement.
|
||||||
|
> **Total Estimate: 1 week**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.3.1 Tiling Window System
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** None (UI work)
|
||||||
|
**Deliverable:** Panel system in emulator
|
||||||
|
|
||||||
|
- [ ] Research Rust tiling libraries (`egui_tiles`, or custom)
|
||||||
|
- [ ] Design panel layout system
|
||||||
|
- [ ] Code editor panel
|
||||||
|
- [ ] Disassembly panel
|
||||||
|
- [ ] Register panel
|
||||||
|
- [ ] Memory panel
|
||||||
|
- [ ] Console panel
|
||||||
|
- [ ] Implement drag-and-drop panel management
|
||||||
|
- [ ] Save/load layouts
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.3.2 Assembly Editor Improvements
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 4.3.1
|
||||||
|
**Deliverable:** Enhanced assembly editor
|
||||||
|
|
||||||
|
- [ ] Syntax highlighting for DSA assembly
|
||||||
|
- [ ] Auto-completion for instructions
|
||||||
|
- [ ] Label/symbol auto-completion
|
||||||
|
- [ ] Error highlighting
|
||||||
|
- [ ] Inline documentation tooltips
|
||||||
|
- [ ] Jump-to-definition for labels
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.3.3 High-Level Language Editor
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 4.3.1, 2.1.4
|
||||||
|
**Deliverable:** DSC language editor
|
||||||
|
|
||||||
|
- [ ] Syntax highlighting for DSC language
|
||||||
|
- [ ] Basic auto-completion
|
||||||
|
- [ ] Bracket matching
|
||||||
|
- [ ] Error highlighting from compiler
|
||||||
|
- [ ] Go-to-definition (using debug symbols)
|
||||||
|
- [ ] Inline type hints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4.3.4 Integrate Build Tools in Editor
|
||||||
|
|
||||||
|
**Estimate: 1 day**
|
||||||
|
**Dependencies:** 4.3.1, 3.1.2
|
||||||
|
**Deliverable:** Integrated build experience
|
||||||
|
|
||||||
|
- [ ] Build button/command in UI
|
||||||
|
- [ ] Show build output in console panel
|
||||||
|
- [ ] Error navigation (click to jump to source)
|
||||||
|
- [ ] Hot reload on successful build
|
||||||
|
- [ ] Build status indicator
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: Integration & Polish
|
||||||
|
|
||||||
|
**Estimated Duration: 1–2 weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5.1 Tool Integration
|
||||||
|
|
||||||
|
> **Priority: HIGH** — Everything works together.
|
||||||
|
> **Total Estimate: 1 week**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 5.1.1 Unified Toolchain
|
||||||
|
|
||||||
|
**Estimate: 3 days**
|
||||||
|
**Dependencies:** All previous phases
|
||||||
|
**Deliverable:** `dsa` unified command-line tool
|
||||||
|
|
||||||
|
- [ ] Create meta-crate: `dsa-tools`
|
||||||
|
- [ ] Unified CLI with subcommands
|
||||||
|
- [ ] `dsa build`
|
||||||
|
- [ ] `dsa run`
|
||||||
|
- [ ] `dsa debug`
|
||||||
|
- [ ] `dsa test`
|
||||||
|
- [ ] `dsa pkg`
|
||||||
|
- [ ] Shared configuration system
|
||||||
|
- [ ] Tool interop testing
|
||||||
|
- [ ] Documentation for workflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 5.1.2 Emulator Integration
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 5.1.1, 4.3.4
|
||||||
|
**Deliverable:** Fully integrated development environment
|
||||||
|
|
||||||
|
- [ ] Add build tools as emulator dependencies
|
||||||
|
- [ ] In-editor build triggered from emulator
|
||||||
|
- [ ] Debugger uses build output directly
|
||||||
|
- [ ] Source-level debugging with line mapping
|
||||||
|
- [ ] Test full edit → build → debug cycle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 5.1.3 Documentation & Tutorials
|
||||||
|
|
||||||
|
**Estimate: 2 days**
|
||||||
|
**Dependencies:** 5.1.2
|
||||||
|
**Deliverable:** Complete documentation suite
|
||||||
|
|
||||||
|
- [ ] Getting started guide
|
||||||
|
- [ ] Full tutorial: Building a simple game
|
||||||
|
- [ ] Debugger usage guide
|
||||||
|
- [ ] Best practices document
|
||||||
|
- [ ] Troubleshooting guide
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: Future Enhancements (NTH)
|
||||||
|
|
||||||
|
> **Priority: LOW** — Nice to have, long-term goal.
|
||||||
|
> **Estimated Duration: 4+ weeks**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6.1 Command-Line Emulator
|
||||||
|
|
||||||
|
> ⚠️ **COMPLEX LONG-TERM GOAL** — Requires significant design and UX consideration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6.1.1 Design Phase
|
||||||
|
|
||||||
|
**Estimate: 1 week**
|
||||||
|
**Dependencies:** None
|
||||||
|
**Deliverable:** `docs/cli-emulator-design.md`
|
||||||
|
|
||||||
|
- [ ] UX research for terminal-based debuggers
|
||||||
|
- [ ] Design TUI layout (using `ratatui` or similar)
|
||||||
|
- [ ] Command syntax design
|
||||||
|
- [ ] Scripting support design
|
||||||
|
- [ ] Accessibility considerations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6.1.2 Implementation
|
||||||
|
|
||||||
|
**Estimate: 3+ weeks**
|
||||||
|
**Dependencies:** 6.1.1, Phase 4 complete
|
||||||
|
**Deliverable:** `dsa-emu-cli` executable
|
||||||
|
|
||||||
|
- [ ] TUI framework setup
|
||||||
|
- [ ] Core emulator integration
|
||||||
|
- [ ] Command parser
|
||||||
|
- [ ] Panel rendering (code, registers, memory, etc.)
|
||||||
|
- [ ] Keyboard shortcuts
|
||||||
|
- [ ] Mouse support
|
||||||
|
- [ ] Configuration system
|
||||||
|
- [ ] Extensive usability testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary Timeline
|
||||||
|
|
||||||
|
| Phase | Duration | Key Dependencies |
|
||||||
|
|---|---|---|
|
||||||
|
| Phase 1: Foundation | 3–4 weeks | None |
|
||||||
|
| Phase 2: Compiler | 3–4 weeks | Phase 1 complete |
|
||||||
|
| Phase 3: Build System | 2–3 weeks | Phases 1–2 complete |
|
||||||
|
| Phase 4: Debugger | 3–4 weeks | Phases 1–3 complete |
|
||||||
|
| Phase 5: Integration | 1–2 weeks | Phases 1–4 complete |
|
||||||
|
| Phase 6: CLI Emulator *(NTH)* | 4+ weeks | Phase 4 complete |
|
||||||
|
|
||||||
|
**Total Estimated Time: 12–17 weeks (3–4 months) for Phases 1–5**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critical Path
|
||||||
|
|
||||||
|
The following tasks are on the critical path and will block other work if delayed:
|
||||||
|
|
||||||
|
```
|
||||||
|
1.1.1 Binary format design
|
||||||
|
└── 1.1.2 Object file writer
|
||||||
|
└── 1.1.3 Linker
|
||||||
|
└── 1.2.2 Assembler rewrite
|
||||||
|
└── 2.1.3 Compiler codegen
|
||||||
|
└── 3.1.2 Build system
|
||||||
|
└── 4.1.2 Debug symbols
|
||||||
|
└── 4.2.1 Debugger
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Work Order
|
||||||
|
|
||||||
|
| Weeks | Focus | Tasks |
|
||||||
|
|---|---|---|
|
||||||
|
| 1–2 | Binary Format & Linker | 1.1.1 → 1.1.2 → 1.1.3 |
|
||||||
|
| 3–4 | Assembler Rewrite | 1.2.1 → 1.2.2 |
|
||||||
|
| 5–6 | Compiler Syntax & Parser | 2.1.1 → 2.1.2 *(start 1.3 docs in parallel)* |
|
||||||
|
| 7–9 | Compiler Codegen & Types | 2.1.3 → 2.1.4 *(start 2.2.1 runtime in parallel)* |
|
||||||
|
| 10–11 | Build System | 3.1.1 → 3.1.2 → 3.1.3 |
|
||||||
|
| 12–13 | Package Management *(if desired now)* | 3.2.1 → 3.2.2 → 3.2.3 |
|
||||||
|
| 14–15 | Debug Symbols | 4.1.1 → 4.1.2 → 4.1.3 |
|
||||||
|
| 16–18 | Core Debugger | 4.2.1 → 4.2.2 → 4.2.4 |
|
||||||
|
| 19–20 | Editor Enhancements | 4.3.1 → 4.3.2 → 4.3.3 → 4.3.4 |
|
||||||
|
| 21–22 | Integration & Polish | 5.1.1 → 5.1.2 → 5.1.3 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Time estimates assume ~6–8 productive hours per day.
|
||||||
|
- Add **20–30% buffer** for unexpected issues.
|
||||||
|
- Testing time is included in each estimate.
|
||||||
|
- Documentation is distributed throughout rather than batched at the end.
|
||||||
|
- Package management (3.2) can be deferred if time-constrained.
|
||||||
|
- Pseudo-instruction decompiler (4.2.3) can be a stretch goal.
|
||||||
|
- CLI emulator (Phase 6) is explicitly a "nice to have" and should not block other work.
|
||||||
Binary file not shown.
@@ -0,0 +1,427 @@
|
|||||||
|
# DSA Assembly Language Instruction Reference
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document provides a comprehensive reference for the DSA (Damn Simple Architecture) assembly language, including all hardware instructions and pseudo-instructions with their syntax variations and usage examples.
|
||||||
|
|
||||||
|
## Calling Convention
|
||||||
|
|
||||||
|
| Step | Responsibility | Action | Description |
|
||||||
|
|------|----------------|--------|-------------|
|
||||||
|
| 1 | **Caller** | Push arguments | Push exactly n arguments to the stack (in order, last argument pushed first) |
|
||||||
|
| 2 | **Caller** | Call function | Execute `call namespace::function` - this automatically pushes the return address (pcx) and jumps to the function |
|
||||||
|
| 3 | **Function** | Set up stack frame | Execute `push bpr; mov spr, bpr` to establish new stack frame |
|
||||||
|
| 4 | **Function** | Access arguments | Read arguments starting at `spr+8` (first 3 args at offsets 8, 12, 16) |
|
||||||
|
| 5 | **Function** | Execute function | Perform the function's operations using the arguments |
|
||||||
|
| 6 | **Function** | Store return value | Write return value (if any) to `spr+8` |
|
||||||
|
| 7 | **Function** | Restore stack frame | Execute `mov bpr, spr; pop bpr` to restore previous stack frame |
|
||||||
|
| 8 | **Function** | Return | Execute `return` pseudo-instruction to return to caller |
|
||||||
|
| 9 | **Caller** | Clean up stack | Pop exactly n arguments from the stack to clean up |
|
||||||
|
| 10 | **Caller** | Handle unused values | Use `pop zero` to discard any unused stack values if needed |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- The namespace in step 2 is the name assigned in the `include` statement
|
||||||
|
- The `call` pseudo-instruction automatically handles return address management so long as the callee does not mess with the stack
|
||||||
|
- Arguments are accessed by the callee using offsets from the base pointer (bpr)
|
||||||
|
|
||||||
|
## Registers
|
||||||
|
|
||||||
|
| Register | Type | Description |
|
||||||
|
|----------|------|---------------------------------------------------------------------------------------------------|
|
||||||
|
| `rg0-rgf` | General Purpose | General-purpose registers. |
|
||||||
|
| `acc` | Special | Accumulator for calculations and temporary storage - don't use this for variables as pseudo instructions may overwrite this implicitly! |
|
||||||
|
| `spr` | Special | Stack pointer |
|
||||||
|
| `bpr` | Special | Base pointer for stack frames |
|
||||||
|
| `ret` | Special | Return address register |
|
||||||
|
| `idr` | Privileged | Interrupt descriptor table address<br/>**on-read/write: protection fault (unless in kernel mode)** |
|
||||||
|
| `mmr` | Privileged | Hardware memory map table address<br/>**on-read/write: protection fault (unless in kernel mode)** |
|
||||||
|
| `zero` | Read-only | Always contains zero<br/>**on-read: always returns zero**<br/>**on-write: value is voided** |
|
||||||
|
| `pcx` | Read-only | Program counter<br/>**on-write: protection fault** |
|
||||||
|
| `noreg` | Placeholder | Indicates absence of register argument<br/>**on-read/write: illegal instruction fault** |
|
||||||
|
|
||||||
|
## Hardware Instructions
|
||||||
|
|
||||||
|
### Data Movement Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **MOV** | `src_reg, dest_reg` | Copy value from source to destination register |
|
||||||
|
| **MOVS** | `src_reg, dest_reg` | Copy with sign extension |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
mov rg0, rg1 ; Copy rg0 to rg1
|
||||||
|
movs rg0, rg1 ; Copy rg0 to rg1 with sign extension
|
||||||
|
```
|
||||||
|
### Memory Access Instructions
|
||||||
|
|
||||||
|
#### Load Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **LDB** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load byte from memory |
|
||||||
|
| **LDBS** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load byte with sign extension |
|
||||||
|
| **LDH** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load half-word (16-bit) |
|
||||||
|
| **LDHS** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load half-word with sign extension |
|
||||||
|
| **LDW** | `base_reg, dest_reg [, offset]`<br>`label, dest_reg [, offset]` | Load word (32-bit) |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
; Direct register addressing
|
||||||
|
ldb rg0, rg1 ; Load byte from address in rg0
|
||||||
|
ldw rg0, rg1, 8 ; Load word from (rg0 + 8)
|
||||||
|
|
||||||
|
; Label addressing
|
||||||
|
ldb buffer, rg2 ; Load byte from label 'buffer'
|
||||||
|
ldw stack, bpr ; Load stack address into base pointer
|
||||||
|
```
|
||||||
|
**Label Expansions:**
|
||||||
|
```asm
|
||||||
|
; ldb buffer, rg2 expands to:
|
||||||
|
lli buffer, rg2 ; Load lower 16 bits of buffer address
|
||||||
|
lui buffer, rg2 ; Load upper 16 bits of buffer address
|
||||||
|
ldb rg2, rg2 ; Load byte from address in rg2
|
||||||
|
|
||||||
|
; ldw stack, bpr expands to:
|
||||||
|
lli stack, bpr ; Load lower 16 bits of stack address
|
||||||
|
lui stack, bpr ; Load upper 16 bits of stack address
|
||||||
|
ldw bpr, bpr ; Load word from address in bpr
|
||||||
|
```
|
||||||
|
#### Store Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **STB** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store byte to memory |
|
||||||
|
| **STH** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store half-word to memory |
|
||||||
|
| **STW** | `src_reg, base_reg [, offset]`<br>`src_reg, label [, offset]` | Store word to memory |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
; Direct register addressing
|
||||||
|
stb rg0, rg1 ; Store byte from rg0 to address in rg1
|
||||||
|
stw rg0, rg1, 12 ; Store word to (rg1 + 12)
|
||||||
|
|
||||||
|
; Label addressing
|
||||||
|
stb acc, buffer ; Store byte from accumulator to 'buffer'
|
||||||
|
stw rg1, current ; Store word to 'current' variable
|
||||||
|
```
|
||||||
|
**Label Expansions:**
|
||||||
|
```asm
|
||||||
|
; stb acc, buffer expands to:
|
||||||
|
lli buffer, rgf ; Load lower 16 bits of buffer address
|
||||||
|
lui buffer, rgf ; Load upper 16 bits of buffer address
|
||||||
|
stb acc, rgf ; Store byte from acc to address in rgf
|
||||||
|
|
||||||
|
; stw rg1, current expands to:
|
||||||
|
lli current, rgf ; Load lower 16 bits of current address
|
||||||
|
lui current, rgf ; Load upper 16 bits of current address
|
||||||
|
stw rg1, rgf ; Store word from rg1 to address in rgf
|
||||||
|
```
|
||||||
|
### Immediate Load Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|------------------------------------------------------------------------|
|
||||||
|
| **LLI** | `imm, dest_reg` | Load 16-bit immediate into lower 16 bits<br/>**Clears upper 16 bits!** |
|
||||||
|
| **LUI** | `imm, dest_reg` | Load 16-bit immediate into upper 16 bits |
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
ensure that you always run **Lli** before **Lui** as **Lli** clears the upper 16 bits.
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
lli 0x1234, rg0 ; Load 0x1234 into lower 16 bits of rg0
|
||||||
|
lui 0xABCD, rg0 ; Load 0xABCD into upper 16 bits of rg0
|
||||||
|
```
|
||||||
|
### Jump Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **JMP** | `addr [, offset_reg]`<br>`imm, offset_reg` | Unconditional jump |
|
||||||
|
| **JEQ** | `addr [, offset_reg]` | Jump if equal flag set |
|
||||||
|
| **JNE** | `addr [, offset_reg]` | Jump if not equal flag set |
|
||||||
|
| **JGT** | `addr [, offset_reg]` | Jump if greater than flag set |
|
||||||
|
| **JGE** | `addr [, offset_reg]` | Jump if greater or equal flags set |
|
||||||
|
| **JLT** | `addr [, offset_reg]` | Jump if less than flag set |
|
||||||
|
| **JLE** | `addr [, offset_reg]` | Jump if less or equal flags set |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
jmp start ; Jump to label 'start'
|
||||||
|
jmp 4, ret ; Jump to address (4 + ret register)
|
||||||
|
jeq end ; Jump to 'end' if equal flag set
|
||||||
|
jgt loop ; Jump to 'loop' if greater than flag set
|
||||||
|
```
|
||||||
|
### Arithmetic Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **ADD** | `src1_reg, src2_reg, dest_reg` | Addition |
|
||||||
|
| **SUB** | `src1_reg, src2_reg, dest_reg` | Subtraction |
|
||||||
|
| **IADD** | `src_reg, imm [, dest_reg]` | Immediate addition |
|
||||||
|
| **ISUB** | `src_reg, imm [, dest_reg]` | Immediate subtraction |
|
||||||
|
| **INC** | `reg` | Increment register by 1 |
|
||||||
|
| **DEC** | `reg` | Decrement register by 1 |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
add rg0, rg1, rg2 ; rg2 = rg0 + rg1
|
||||||
|
sub rg0, rg1, rg2 ; rg2 = rg0 - rg1
|
||||||
|
iadd rg0, 10 ; rg0 = rg0 + 10
|
||||||
|
// or using alternate syntax
|
||||||
|
addi rg0, 1 ; rg0 = rg0 + 1
|
||||||
|
inc rg0 ; rg0 = rg0 + 1
|
||||||
|
```
|
||||||
|
### Bitwise Operations
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **AND** | `src1_reg, src2_reg, dest_reg` | Bitwise AND |
|
||||||
|
| **OR** | `src1_reg, src2_reg, dest_reg` | Bitwise OR |
|
||||||
|
| **XOR** | `src1_reg, src2_reg, dest_reg` | Bitwise XOR |
|
||||||
|
| **NOT** | `src_reg, dest_reg` | Bitwise NOT |
|
||||||
|
| **NAND** | `src1_reg, src2_reg, dest_reg` | Bitwise NAND |
|
||||||
|
| **NOR** | `src1_reg, src2_reg, dest_reg` | Bitwise NOR |
|
||||||
|
| **XNOR** | `src1_reg, src2_reg, dest_reg` | Bitwise XNOR |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
and rg0, rg1, rg2 ; rg2 = rg0 & rg1
|
||||||
|
not rg0, rg1 ; rg1 = ~rg0
|
||||||
|
```
|
||||||
|
### Shift Operations
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **SHL** | `reg, shift_amount` | Shift left |
|
||||||
|
| **SHR** | `reg, shift_amount` | Shift right |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
shl rg0, 2 ; Shift rg0 left by 2 bits
|
||||||
|
shr rg0, 3 ; Shift rg0 right by 3 bits
|
||||||
|
```
|
||||||
|
### Comparison and Control
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **CMP** | `reg1, reg2` | Compare registers and set flags |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
cmp rg0, zero ; Compare rg0 with zero register
|
||||||
|
cmp rg1, rg2 ; Compare rg1 with rg2
|
||||||
|
```
|
||||||
|
### System Instructions
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **HLT** | - | Halt processor execution |
|
||||||
|
| **NOP** | - | No operation |
|
||||||
|
| **INT** | `interrupt_code` | Trigger interrupt |
|
||||||
|
| **IRT** | - | Return from interrupt |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
hlt ; Stop processor execution
|
||||||
|
int 0x21 ; Trigger interrupt 0x21
|
||||||
|
```
|
||||||
|
## Pseudo-Instructions
|
||||||
|
|
||||||
|
### Data Definition
|
||||||
|
|
||||||
|
| Mnemonic | Syntax | Description |
|
||||||
|
|----------|--------|-------------|
|
||||||
|
| **DB** | `name: value1 [, value2, ...]` | Define bytes |
|
||||||
|
| **DH** | `name: value1 [, value2, ...]` | Define half-words |
|
||||||
|
| **DW** | `name: value1 [, value2, ...]` | Define words |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
db message: "Hello World", 0
|
||||||
|
dh numbers: 1000, 2000, 3000
|
||||||
|
dw stack: 0x10000
|
||||||
|
```
|
||||||
|
### Memory Reservation
|
||||||
|
|
||||||
|
| Mnemonic | Syntax | Description |
|
||||||
|
|----------|--------|-------------|
|
||||||
|
| **RESB** | `name: size` | Reserve bytes |
|
||||||
|
| **RESH** | `name: size` | Reserve half-words |
|
||||||
|
| **RESW** | `name: size` | Reserve words |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
resb buffer: 256 ; Reserve 256 bytes
|
||||||
|
resh array: 100 ; Reserve space for 100 half-words
|
||||||
|
resw heap: 1024 ; Reserve space for 1024 words
|
||||||
|
```
|
||||||
|
### Stack Operations
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **PUSH** | `reg` | Push register value onto stack |
|
||||||
|
| **POP** | `reg` | Pop stack value into register |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
push rg0 ; Push rg0 value onto stack
|
||||||
|
pop ret ; Pop return address
|
||||||
|
```
|
||||||
|
### Memory Access Shortcuts
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **LWI** | `name, reg` | Load address into register |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
lwi string, rg1 ; Load address of 'string' into rg1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Function Control
|
||||||
|
|
||||||
|
| Mnemonic | Operands | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| **CALL** | `namespace::function` | Call a function with automatic return address management |
|
||||||
|
| **RETURN** | - | Return from a function to the caller |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
call print::print ; Call the print function from the print namespace
|
||||||
|
return ; Return from the current function
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module System
|
||||||
|
|
||||||
|
| Mnemonic | Syntax | Description |
|
||||||
|
|----------|--------|-------------|
|
||||||
|
| **INCLUDE** | `module_name "path"` | Include module |
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```asm
|
||||||
|
include print "print.dsa"
|
||||||
|
include fib "fib.dsa"
|
||||||
|
```
|
||||||
|
## Library Examples
|
||||||
|
|
||||||
|
### Multiplication Library (multiply.dsa)
|
||||||
|
|
||||||
|
```asm
|
||||||
|
// multiply.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include multiply "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for multiply:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load op 1
|
||||||
|
ldw bpr, rg1, 12 // load op 2
|
||||||
|
|
||||||
|
lli 0, acc // initialize accumulator
|
||||||
|
|
||||||
|
start:
|
||||||
|
add acc, rg0, acc
|
||||||
|
dec rg1
|
||||||
|
|
||||||
|
cmp rg1, zero
|
||||||
|
jgt start
|
||||||
|
|
||||||
|
end:
|
||||||
|
stw acc, bpr, 8 // store result for caller
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
```
|
||||||
|
|
||||||
|
### Print Library (print.dsa)
|
||||||
|
|
||||||
|
```asm
|
||||||
|
// print.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// call print::print
|
||||||
|
// pop zero
|
||||||
|
//
|
||||||
|
// usage for reset:
|
||||||
|
// call print::reset
|
||||||
|
|
||||||
|
dw display: 0x20000
|
||||||
|
dw current: 0x20000
|
||||||
|
|
||||||
|
// prints the given text to the screen.
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // get string address argument
|
||||||
|
ldw current, rg1 // get current display position
|
||||||
|
|
||||||
|
print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
iadd rg0, 1
|
||||||
|
iadd rg1, 1
|
||||||
|
|
||||||
|
cmp acc, zero
|
||||||
|
jne print_loop
|
||||||
|
jmp end
|
||||||
|
|
||||||
|
// return
|
||||||
|
end:
|
||||||
|
stw rg1, current
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
// resets the cursor position on the screen
|
||||||
|
reset:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
ldw display, rg1
|
||||||
|
stw rg1, current
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Program (main.dsa)
|
||||||
|
|
||||||
|
```asm
|
||||||
|
include print "./print.dsa"
|
||||||
|
|
||||||
|
dw stack: 0x10000
|
||||||
|
db string: "'To confuse your enemy, you must first confuse yourself' - Probably Sun Tzu."
|
||||||
|
|
||||||
|
init:
|
||||||
|
// set up a stack.
|
||||||
|
ldw stack, bpr
|
||||||
|
mov bpr, spr
|
||||||
|
|
||||||
|
start:
|
||||||
|
lwi string, rg1
|
||||||
|
|
||||||
|
// push string address argument
|
||||||
|
push rg1
|
||||||
|
// call print function
|
||||||
|
call print::print
|
||||||
|
// clean up stack
|
||||||
|
pop rg1
|
||||||
|
|
||||||
|
hlt
|
||||||
|
```
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# DSA File formatting specification.
|
||||||
|
|
||||||
|
First, a clarification on what formats this document references.
|
||||||
|
|
||||||
|
- .dsb: DSA Binary object, similar to a .o object file
|
||||||
|
- .dse: DSA Executable file, similar to a .exe/ELF binary
|
||||||
|
|
||||||
|
## Format Specification
|
||||||
|
|
||||||
|
### DSB binary format
|
||||||
Reference in New Issue
Block a user