parser works

This commit is contained in:
nora 2022-06-13 11:53:09 +02:00
parent ac63a8a5c7
commit 29219405ff
6 changed files with 227 additions and 43 deletions

3
.rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
imports_granularity = "Crate"
newline_style = "Unix"
group_imports = "StdExternalCrate"

65
Cargo.lock generated
View file

@ -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"

View file

@ -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
View 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>;

View file

@ -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(())
} }

View file

@ -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)
}
macro_rules! expect { fn invalid_token(span: Span) -> Self {
($self:ident, $token:pat) => { Self::new("Invalid token".to_string(), span)
if let $token = $self.next()? { }
return Err(CompilerError); fn eof() -> Self {
Self {
span: Default::default(),
msg: "Unexpected end of file".to_string(),
} }
}; }
} }
fn stmt(kind: StmtKind, span: Span) -> Stmt { macro_rules! expect {
Stmt { kind, span } ($self:ident, $token:pat) => {{
let (next, span) = $self.next()?;
if let $token = next {
span
} else {
return Err(CompilerError {
msg: format!(
concat!("Expected ", stringify!($token), ", found {:?}"),
next,
),
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 {}