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"
dependencies = [
"dbg-pls",
"insta",
"logos",
]
@ -70,6 +71,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "crc32fast"
version = "1.3.2"
@ -108,6 +122,12 @@ dependencies = [
"syn",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "flate2"
version = "1.0.24"
@ -140,6 +160,20 @@ dependencies = [
"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]]
name = "itoa"
version = "1.0.2"
@ -345,6 +379,9 @@ name = "serde"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
@ -368,6 +405,24 @@ dependencies = [
"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]]
name = "smawk"
version = "0.3.1"
@ -407,6 +462,16 @@ dependencies = [
"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]]
name = "textwrap"
version = "0.15.0"

View file

@ -8,3 +8,6 @@ edition = "2021"
[dependencies]
dbg-pls = { version = "0.3.2", features = ["colors", "derive"] }
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;
mod error;
mod parser;
fn main() -> Result<(), io::Error> {
let file = std::fs::read_to_string("../test.at")?;
parser::run(&file);
let file = std::fs::read_to_string("./test.at")?;
let result = parser::parse(&file);
let _ = dbg_pls::color!(result);
Ok(())
}

View file

@ -1,6 +1,9 @@
use std::{fmt::Debug, iter::Peekable};
use dbg_pls::DebugPls;
use logos::{Lexer, Logos, Span};
use std::iter::Peekable;
use crate::error::{CompilerError, Result};
#[derive(Debug, Clone, PartialEq, Eq, Logos, DebugPls)]
pub enum Token<'a> {
@ -43,18 +46,13 @@ pub fn lex(src: &str) -> Lexer<'_, Token<'_>> {
<Token as Logos>::lexer(src)
}
pub fn run(src: &str) {
let tokens = lex(src).collect::<Vec<_>>();
dbg_pls::color!(tokens);
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, DebugPls)]
pub struct Stmt {
pub kind: StmtKind,
pub span: Span,
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, DebugPls)]
pub enum StmtKind {
Mov { to: Expr, from: Expr },
Add { to: Expr, value: Expr },
@ -64,54 +62,85 @@ pub enum StmtKind {
Jmp { to: Expr },
Je { to: Expr },
Cmp { rhs: Expr, lhs: Expr },
Label { name: String },
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, DebugPls)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, DebugPls)]
pub enum ExprKind {
Register,
Number,
Register(u8),
Number(u64),
Addr(Box<Expr>),
Name(String),
}
struct Parser<'a, I>
where
I: Iterator<Item = Token<'a>>,
I: Iterator<Item = (Token<'a>, Span)>,
{
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 {
($self:ident, $token:pat) => {
if let $token = $self.next()? {
return Err(CompilerError);
($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,
});
}
};
}
fn stmt(kind: StmtKind, span: Span) -> Stmt {
Stmt { kind, span }
}};
}
impl<'a, I> Parser<'a, I>
where
I: Iterator<Item = Token<'a>>,
I: Iterator<Item = (Token<'a>, Span)>,
{
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> {
Ok(match self.next()? {
let stmt = |kind, span| Stmt { kind, span };
let (token, span) = self.next()?;
Ok(match token {
Token::Mov => {
let to = self.expr()?;
expect!(self, Token::Comma);
@ -135,29 +164,101 @@ where
let rhs = self.expr()?;
stmt(StmtKind::Cmp { lhs, rhs }, Default::default())
}
Token::Add => {}
Token::Sub => {}
Token::Mul => {}
Token::Div => {}
Token::BracketOpen => {}
Token::BracketClose => {}
Token::Comma => {}
Token::Label(_) => {}
Token::Number(_) => {}
Token::Word(_) => {}
Token::Error => {}
Token::Add => {
let to = self.expr()?;
expect!(self, Token::Comma);
let value = self.expr()?;
stmt(StmtKind::Add { to, value }, Default::default())
}
Token::Sub => {
let to = self.expr()?;
expect!(self, Token::Comma);
let value = self.expr()?;
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> {
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>> {
self.iter.peek().ok_or(CompilerError)
fn peek(&mut self) -> Result<&(Token<'a>, Span)> {
self.iter.peek().ok_or(CompilerError::eof())
}
fn next(&mut self) -> Result<Token<'a>> {
self.iter.next().ok_or(CompilerError)
fn next(&mut self) -> Result<(Token<'a>, Span)> {
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 {}