now compiling some trivial arithmetic

This commit is contained in:
mlokr 2024-05-10 22:54:12 +02:00
parent 81952cfc40
commit cf99091a45
9 changed files with 192 additions and 23 deletions

View file

@ -1,3 +1,3 @@
main := ||: int {
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4;
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
}

View file

@ -1,5 +1,8 @@
use {
crate::parser::{self, Expr},
crate::{
lexer,
parser::{self, Expr},
},
std::rc::Rc,
};
@ -66,6 +69,10 @@ impl Func {
self.tx();
}
fn div64(&mut self, reg0: Reg, reg1: Reg, reg2: Reg) {
self.diru64(reg0, ZERO, reg1, reg2);
}
fn relocate(&mut self, labels: &[Label], shift: i64) {
for reloc in self.relocs.drain(..) {
let label = &labels[reloc.id as usize];
@ -158,13 +165,14 @@ impl<'a> Codegen<'a> {
}
fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Expr<'a>>) -> Option<Value<'a>> {
use parser::Expr as E;
use {lexer::TokenKind as T, parser::Expr as E};
match *expr {
E::Decl {
name,
val: E::Closure { ret, body },
} => {
let frame = self.add_label(name);
self.gpa.init_caller();
self.ret = **ret;
self.expr(body, None);
self.write_fn_prelude(frame);
@ -194,7 +202,48 @@ impl<'a> Codegen<'a> {
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
loc: Loc::Imm(value),
}),
ast => unimplemented!("{:?}", ast),
E::BinOp { left, op, right } => {
let left = self.expr(left, expeted).unwrap();
let right = self.expr(right, Some(left.ty)).unwrap();
type Op = fn(&mut Func, u8, u8, u8);
type ImmOp = fn(&mut Func, u8, u8, u64);
let op = match op {
T::Plus => Func::add64 as Op,
T::Minus => Func::sub64 as Op,
T::Star => Func::mul64 as Op,
T::FSlash => Func::div64 as Op,
_ => unimplemented!("{:#?}", op),
};
let lhs = match left.loc {
Loc::Reg(reg) => reg,
Loc::Imm(imm) => {
let reg = self.gpa.allocate();
self.code.li64(reg, imm);
reg
}
};
let rhs = match right.loc {
Loc::Reg(reg) => reg,
Loc::Imm(imm) => {
let reg = self.gpa.allocate();
self.code.li64(reg, imm);
reg
}
};
op(&mut self.code, lhs, lhs, rhs);
self.gpa.free(rhs);
Some(Value {
ty: left.ty,
loc: Loc::Reg(lhs),
})
}
ast => unimplemented!("{:#?}", ast),
}
}
@ -328,14 +377,6 @@ mod tests {
let mut stack = [0_u64; 1024];
for (i, b) in out.iter().enumerate() {
write!(output, "{:02x}", b).unwrap();
if (i + 1) % 4 == 0 {
writeln!(output).unwrap();
}
}
writeln!(output).unwrap();
let mut vm = unsafe {
hbvm::Vm::<TestMem, 0>::new(TestMem, hbvm::mem::Address::new(out.as_ptr() as u64))
};
@ -356,5 +397,6 @@ mod tests {
crate::run_tests! { generate:
example => include_str!("../examples/main_fn.hb");
arithmetic => include_str!("../examples/arithmetic.hb");
}
}

View file

@ -11,7 +11,7 @@ impl Token {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum TokenKind {
Ident,
Number,
@ -22,6 +22,10 @@ pub enum TokenKind {
LBrack,
RBrack,
Decl,
Plus,
Minus,
Star,
FSlash,
Or,
Semi,
Colon,
@ -30,6 +34,44 @@ pub enum TokenKind {
Error,
}
impl std::fmt::Display for TokenKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use TokenKind as T;
let s = match self {
T::Ident => "<identifier>",
T::Number => "<number>",
T::LParen => "(",
T::RParen => ")",
T::LBrace => "{",
T::RBrace => "}",
T::LBrack => "[",
T::RBrack => "]",
T::Decl => ":=",
T::Plus => "+",
T::Minus => "-",
T::Star => "*",
T::FSlash => "/",
T::Or => "||",
T::Semi => ";",
T::Colon => ":",
T::Return => "return",
T::Eof => "<eof>",
T::Error => "<error>",
};
write!(f, "{}", s)
}
}
impl TokenKind {
pub fn precedence(&self) -> Option<u8> {
match self {
Self::Plus | Self::Minus => Some(2),
Self::Star | Self::FSlash => Some(3),
_ => None,
}
}
}
pub struct Lexer<'a> {
pos: u32,
bytes: &'a [u8],
@ -120,6 +162,10 @@ impl<'a> Iterator for Lexer<'a> {
false => T::Colon,
},
b';' => T::Semi,
b'+' => T::Plus,
b'-' => T::Minus,
b'*' => T::Star,
b'/' => T::FSlash,
b'|' => match self.advance_if(b'|') {
true => T::Or,
false => T::Error,

View file

@ -1,4 +1,5 @@
#![feature(noop_waker)]
#![feature(let_chains)]
#![feature(non_null_convenience)]
#![allow(dead_code)]
#![feature(const_mut_refs)]

View file

@ -45,6 +45,34 @@ impl<'a, 'b> Parser<'a, 'b> {
}
fn expr(&mut self) -> Expr<'a> {
let left = self.unit_expr();
self.bin_expr(left, 0)
}
fn bin_expr(&mut self, mut left: Expr<'a>, min_prec: u8) -> Expr<'a> {
loop {
let Some(prec) = self.token.kind.precedence() else {
break;
};
if prec < min_prec {
break;
}
let op = self.next().kind;
let right = self.unit_expr();
let right = self.bin_expr(right, prec);
left = Expr::BinOp {
left: self.arena.alloc(left),
right: self.arena.alloc(right),
op,
};
}
left
}
fn unit_expr(&mut self) -> Expr<'a> {
let token = self.next();
let expr = match token.kind {
TokenKind::Ident => {
@ -74,6 +102,11 @@ impl<'a, 'b> Parser<'a, 'b> {
Err(e) => self.report(format_args!("invalid number: {e}")),
},
},
TokenKind::LParen => {
let expr = self.expr();
self.expect_advance(TokenKind::RParen);
expr
}
tok => self.report(format_args!("unexpected token: {tok:?}")),
};
@ -140,6 +173,11 @@ pub enum Expr<'a> {
Number {
value: u64,
},
BinOp {
left: Ptr<'a, Expr<'a>>,
op: TokenKind,
right: Ptr<'a, Expr<'a>>,
},
}
impl<'a> std::fmt::Display for Expr<'a> {
@ -148,7 +186,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
static INDENT: Cell<usize> = Cell::new(0);
}
match self {
match *self {
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
Self::Closure { ret, body } => write!(f, "||: {} {}", ret, body),
Self::Return { val: Some(val) } => write!(f, "return {};", val),
@ -158,7 +196,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
writeln!(f, "{{")?;
INDENT.with(|i| i.set(i.get() + 1));
let res = crate::try_block(|| {
for stmt in *stmts {
for stmt in stmts {
for _ in 0..INDENT.with(|i| i.get()) {
write!(f, " ")?;
}
@ -171,6 +209,21 @@ impl<'a> std::fmt::Display for Expr<'a> {
res
}
Self::Number { value } => write!(f, "{}", value),
Self::BinOp { left, right, op } => {
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
if let Self::BinOp { op: lop, .. } = expr
&& op.precedence() > lop.precedence()
{
write!(f, "({})", expr)
} else {
write!(f, "{}", expr)
}
};
display_branch(f, left)?;
write!(f, " {} ", op)?;
display_branch(f, right)
}
}
}
}
@ -360,5 +413,6 @@ mod tests {
crate::run_tests! { parse:
example => include_str!("../examples/main_fn.hb");
arithmetic => include_str!("../examples/arithmetic.hb");
}
}

View file

@ -0,0 +1,2 @@
ret: 1
status: Ok(())

View file

@ -1,10 +1,2 @@
541f0005
00000001
4b010100
00000000
00005500
1f000000
00000000
00
ret: 1
status: Ok(())

View file

@ -0,0 +1,29 @@
Ident "main"
Decl ":="
Or "||"
Colon ":"
Ident "int"
LBrace "{"
Return "return"
Number "10"
Minus "-"
Number "20"
FSlash "/"
Number "2"
Plus "+"
Number "4"
Star "*"
LParen "("
Number "2"
Plus "+"
Number "2"
RParen ")"
Minus "-"
Number "4"
Star "*"
Number "4"
Plus "+"
Number "1"
Semi ";"
RBrace "}"
Eof ""

View file

@ -0,0 +1,3 @@
main := ||: int {
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
}