mirror of
https://github.com/Noratrieb/crapderive.git
synced 2026-01-14 16:45:08 +01:00
parser works
This commit is contained in:
parent
ac63a8a5c7
commit
29219405ff
6 changed files with 227 additions and 43 deletions
3
.rustfmt.toml
Normal file
3
.rustfmt.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
newline_style = "Unix"
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
65
Cargo.lock
generated
65
Cargo.lock
generated
|
|
@ -22,6 +22,7 @@ name = "asm-thing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dbg-pls",
|
"dbg-pls",
|
||||||
|
"insta",
|
||||||
"logos",
|
"logos",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -70,6 +71,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"terminal_size",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|
@ -108,6 +122,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
|
|
@ -140,6 +160,20 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "insta"
|
||||||
|
version = "1.14.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bcc3e639bcba360d9237acabd22014c16f3df772db463b7446cd81b070714767"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"once_cell",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"similar",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -345,6 +379,9 @@ name = "serde"
|
||||||
version = "1.0.137"
|
version = "1.0.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
|
|
@ -368,6 +405,24 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.8.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "similar"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smawk"
|
name = "smawk"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
@ -407,6 +462,16 @@ dependencies = [
|
||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,6 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dbg-pls = { version = "0.3.2", features = ["colors", "derive"] }
|
dbg-pls = { version = "0.3.2", features = ["colors", "derive"] }
|
||||||
logos = "0.12.1"
|
logos = "0.12.1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
insta = "1.14.1"
|
||||||
|
|
|
||||||
10
src/error.rs
Normal file
10
src/error.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
use dbg_pls::DebugPls;
|
||||||
|
use logos::Span;
|
||||||
|
|
||||||
|
#[derive(Debug, DebugPls)]
|
||||||
|
pub struct CompilerError {
|
||||||
|
pub msg: String,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, CompilerError>;
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
mod error;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
fn main() -> Result<(), io::Error> {
|
fn main() -> Result<(), io::Error> {
|
||||||
let file = std::fs::read_to_string("../test.at")?;
|
let file = std::fs::read_to_string("./test.at")?;
|
||||||
parser::run(&file);
|
let result = parser::parse(&file);
|
||||||
|
let _ = dbg_pls::color!(result);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
185
src/parser.rs
185
src/parser.rs
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::{fmt::Debug, iter::Peekable};
|
||||||
|
|
||||||
use dbg_pls::DebugPls;
|
use dbg_pls::DebugPls;
|
||||||
use logos::{Lexer, Logos, Span};
|
use logos::{Lexer, Logos, Span};
|
||||||
use std::iter::Peekable;
|
|
||||||
|
use crate::error::{CompilerError, Result};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Logos, DebugPls)]
|
#[derive(Debug, Clone, PartialEq, Eq, Logos, DebugPls)]
|
||||||
pub enum Token<'a> {
|
pub enum Token<'a> {
|
||||||
|
|
@ -43,18 +46,13 @@ pub fn lex(src: &str) -> Lexer<'_, Token<'_>> {
|
||||||
<Token as Logos>::lexer(src)
|
<Token as Logos>::lexer(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(src: &str) {
|
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
||||||
let tokens = lex(src).collect::<Vec<_>>();
|
|
||||||
dbg_pls::color!(tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct Stmt {
|
pub struct Stmt {
|
||||||
pub kind: StmtKind,
|
pub kind: StmtKind,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
||||||
pub enum StmtKind {
|
pub enum StmtKind {
|
||||||
Mov { to: Expr, from: Expr },
|
Mov { to: Expr, from: Expr },
|
||||||
Add { to: Expr, value: Expr },
|
Add { to: Expr, value: Expr },
|
||||||
|
|
@ -64,54 +62,85 @@ pub enum StmtKind {
|
||||||
Jmp { to: Expr },
|
Jmp { to: Expr },
|
||||||
Je { to: Expr },
|
Je { to: Expr },
|
||||||
Cmp { rhs: Expr, lhs: Expr },
|
Cmp { rhs: Expr, lhs: Expr },
|
||||||
|
Label { name: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
||||||
pub struct Expr {
|
pub struct Expr {
|
||||||
pub kind: ExprKind,
|
pub kind: ExprKind,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, DebugPls)]
|
||||||
pub enum ExprKind {
|
pub enum ExprKind {
|
||||||
Register,
|
Register(u8),
|
||||||
Number,
|
Number(u64),
|
||||||
Addr(Box<Expr>),
|
Addr(Box<Expr>),
|
||||||
|
Name(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Parser<'a, I>
|
struct Parser<'a, I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Token<'a>>,
|
I: Iterator<Item = (Token<'a>, Span)>,
|
||||||
{
|
{
|
||||||
iter: Peekable<I>,
|
iter: Peekable<I>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CompilerError;
|
impl CompilerError {
|
||||||
|
fn new(msg: String, span: Span) -> Self {
|
||||||
|
Self { span, msg }
|
||||||
|
}
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, CompilerError>;
|
fn not_allowed(span: Span, token: &str) -> Self {
|
||||||
|
Self::new(format!("`{token}` is not allowed here"), span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_token(span: Span) -> Self {
|
||||||
|
Self::new("Invalid token".to_string(), span)
|
||||||
|
}
|
||||||
|
fn eof() -> Self {
|
||||||
|
Self {
|
||||||
|
span: Default::default(),
|
||||||
|
msg: "Unexpected end of file".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! expect {
|
macro_rules! expect {
|
||||||
($self:ident, $token:pat) => {
|
($self:ident, $token:pat) => {{
|
||||||
if let $token = $self.next()? {
|
let (next, span) = $self.next()?;
|
||||||
return Err(CompilerError);
|
if let $token = next {
|
||||||
|
span
|
||||||
|
} else {
|
||||||
|
return Err(CompilerError {
|
||||||
|
msg: format!(
|
||||||
|
concat!("Expected ", stringify!($token), ", found {:?}"),
|
||||||
|
next,
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
}};
|
||||||
}
|
|
||||||
|
|
||||||
fn stmt(kind: StmtKind, span: Span) -> Stmt {
|
|
||||||
Stmt { kind, span }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Parser<'a, I>
|
impl<'a, I> Parser<'a, I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Token<'a>>,
|
I: Iterator<Item = (Token<'a>, Span)>,
|
||||||
{
|
{
|
||||||
fn program(&mut self) -> Result<Vec<Stmt>> {
|
fn program(&mut self) -> Result<Vec<Stmt>> {
|
||||||
todo!()
|
let mut stmts = Vec::new();
|
||||||
|
while let Ok(_) = self.peek() {
|
||||||
|
let stmt = self.stmt()?;
|
||||||
|
stmts.push(stmt);
|
||||||
|
}
|
||||||
|
Ok(stmts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stmt(&mut self) -> Result<Stmt> {
|
fn stmt(&mut self) -> Result<Stmt> {
|
||||||
Ok(match self.next()? {
|
let stmt = |kind, span| Stmt { kind, span };
|
||||||
|
|
||||||
|
let (token, span) = self.next()?;
|
||||||
|
Ok(match token {
|
||||||
Token::Mov => {
|
Token::Mov => {
|
||||||
let to = self.expr()?;
|
let to = self.expr()?;
|
||||||
expect!(self, Token::Comma);
|
expect!(self, Token::Comma);
|
||||||
|
|
@ -135,29 +164,101 @@ where
|
||||||
let rhs = self.expr()?;
|
let rhs = self.expr()?;
|
||||||
stmt(StmtKind::Cmp { lhs, rhs }, Default::default())
|
stmt(StmtKind::Cmp { lhs, rhs }, Default::default())
|
||||||
}
|
}
|
||||||
Token::Add => {}
|
Token::Add => {
|
||||||
Token::Sub => {}
|
let to = self.expr()?;
|
||||||
Token::Mul => {}
|
expect!(self, Token::Comma);
|
||||||
Token::Div => {}
|
let value = self.expr()?;
|
||||||
Token::BracketOpen => {}
|
stmt(StmtKind::Add { to, value }, Default::default())
|
||||||
Token::BracketClose => {}
|
}
|
||||||
Token::Comma => {}
|
Token::Sub => {
|
||||||
Token::Label(_) => {}
|
let to = self.expr()?;
|
||||||
Token::Number(_) => {}
|
expect!(self, Token::Comma);
|
||||||
Token::Word(_) => {}
|
let value = self.expr()?;
|
||||||
Token::Error => {}
|
stmt(StmtKind::Sub { to, value }, Default::default())
|
||||||
|
}
|
||||||
|
Token::Mul => {
|
||||||
|
let to = self.expr()?;
|
||||||
|
expect!(self, Token::Comma);
|
||||||
|
let value = self.expr()?;
|
||||||
|
stmt(StmtKind::Mul { to, value }, Default::default())
|
||||||
|
}
|
||||||
|
Token::Div => {
|
||||||
|
let to = self.expr()?;
|
||||||
|
expect!(self, Token::Comma);
|
||||||
|
let value = self.expr()?;
|
||||||
|
stmt(StmtKind::Div { to, value }, Default::default())
|
||||||
|
}
|
||||||
|
Token::Label(name) => stmt(
|
||||||
|
StmtKind::Label {
|
||||||
|
name: name.to_owned(),
|
||||||
|
},
|
||||||
|
Default::default(),
|
||||||
|
),
|
||||||
|
Token::BracketOpen => return Err(CompilerError::not_allowed(span, "[")),
|
||||||
|
Token::BracketClose => return Err(CompilerError::not_allowed(span, "]")),
|
||||||
|
Token::Comma => return Err(CompilerError::not_allowed(span, ",")),
|
||||||
|
Token::Number(_) => return Err(CompilerError::not_allowed(span, "{number}")),
|
||||||
|
Token::Word(_) => return Err(CompilerError::not_allowed(span, "{word}")),
|
||||||
|
Token::Error => return Err(CompilerError::invalid_token(span)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(&mut self) -> Result<Expr> {
|
fn expr(&mut self) -> Result<Expr> {
|
||||||
todo!()
|
let expr = |kind, span| Expr { kind, span };
|
||||||
|
|
||||||
|
let (token, span) = self.next()?;
|
||||||
|
Ok(match token {
|
||||||
|
Token::BracketOpen => {
|
||||||
|
let inner = self.expr()?;
|
||||||
|
let bclose_span = expect!(self, Token::BracketClose);
|
||||||
|
expr(ExprKind::Addr(Box::new(inner)), span.start..bclose_span.end)
|
||||||
|
}
|
||||||
|
Token::Number(n) => expr(ExprKind::Number(n), span),
|
||||||
|
Token::Word(name) => {
|
||||||
|
if let Some(r_number) = name.strip_prefix("r") {
|
||||||
|
if let Ok(n) = r_number.parse::<u8>() {
|
||||||
|
if n > 15 {
|
||||||
|
return Err(CompilerError::new(
|
||||||
|
format!("Only registers from 0..15 are available. Invalid register: {n}"),
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Ok(expr(ExprKind::Register(n), span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr(ExprKind::Name(name.to_owned()), span)
|
||||||
|
}
|
||||||
|
Token::Mov => return Err(CompilerError::not_allowed(span, "mov")),
|
||||||
|
Token::Jmp => return Err(CompilerError::not_allowed(span, "jmp")),
|
||||||
|
Token::Je => return Err(CompilerError::not_allowed(span, "je")),
|
||||||
|
Token::Cmp => return Err(CompilerError::not_allowed(span, "cmp")),
|
||||||
|
Token::Add => return Err(CompilerError::not_allowed(span, "add")),
|
||||||
|
Token::Sub => return Err(CompilerError::not_allowed(span, "sub")),
|
||||||
|
Token::Mul => return Err(CompilerError::not_allowed(span, "mul")),
|
||||||
|
Token::Div => return Err(CompilerError::not_allowed(span, "div")),
|
||||||
|
Token::BracketClose => return Err(CompilerError::not_allowed(span, "]")),
|
||||||
|
Token::Comma => return Err(CompilerError::not_allowed(span, ",")),
|
||||||
|
Token::Label(_) => return Err(CompilerError::not_allowed(span, "{label}")),
|
||||||
|
Token::Error => return Err(CompilerError::invalid_token(span)),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&mut self) -> Result<&Token<'a>> {
|
fn peek(&mut self) -> Result<&(Token<'a>, Span)> {
|
||||||
self.iter.peek().ok_or(CompilerError)
|
self.iter.peek().ok_or(CompilerError::eof())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Result<Token<'a>> {
|
fn next(&mut self) -> Result<(Token<'a>, Span)> {
|
||||||
self.iter.next().ok_or(CompilerError)
|
self.iter.next().ok_or(CompilerError::eof())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(src: &str) -> Result<Vec<Stmt>> {
|
||||||
|
let lexer = lex(src).spanned();
|
||||||
|
let mut parser = Parser {
|
||||||
|
iter: lexer.peekable(),
|
||||||
|
};
|
||||||
|
parser.program()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue