mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-14 13:35:00 +01:00
codegen works
This commit is contained in:
parent
eda2476021
commit
2df17352d1
6 changed files with 52 additions and 53 deletions
|
|
@ -23,9 +23,10 @@ impl Write for MockReadWrite {
|
||||||
|
|
||||||
fn run_bf(bf: &str) {
|
fn run_bf(bf: &str) {
|
||||||
let bump = Bump::new();
|
let bump = Bump::new();
|
||||||
let parsed = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap();
|
let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap();
|
||||||
let optimized = brainfuck::opts::optimize(&bump, &parsed);
|
let ir = brainfuck::opts::optimize(&bump, &ast);
|
||||||
brainfuck::ir_interpreter::run(&optimized, MockReadWrite, MockReadWrite);
|
let code = brainfuck::codegen::generate(&bump, &ir);
|
||||||
|
brainfuck::codegen_interpreter::run(&code, MockReadWrite, MockReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optimized(c: &mut Criterion) {
|
fn optimized(c: &mut Criterion) {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,14 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! compiles down to
|
//! compiles down to
|
||||||
//! ```text
|
//! ```text
|
||||||
//! Add | Add | JmpIfZero | Out | End | Sub | JmpIfNonZero | Jmp
|
//! Add | Add | JmpIfZero | Sub | JumpIfNotZero | Out | End
|
||||||
//! | | ^ | |
|
//! | ^ | ^
|
||||||
//! +-------------------+---------|----------+
|
//! +-------|-----------|---------|
|
||||||
//! +---------------------+
|
//! +-----------+
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! technically, the `JumpIfNotZero` would be an unconditional Jmp to the `JmpIfZero`, but that's
|
||||||
|
//! a needless indirection.
|
||||||
|
|
||||||
use crate::opts::{Ir, Stmt as IrStmt, StmtKind};
|
use crate::opts::{Ir, Stmt as IrStmt, StmtKind};
|
||||||
use crate::parse::Span;
|
use crate::parse::Span;
|
||||||
|
|
@ -26,7 +29,6 @@ pub enum Stmt {
|
||||||
SetNull,
|
SetNull,
|
||||||
JmpIfZero(usize),
|
JmpIfZero(usize),
|
||||||
JmpIfNonZero(usize),
|
JmpIfNonZero(usize),
|
||||||
Jmp(usize),
|
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,36 +38,28 @@ pub struct Code<'c> {
|
||||||
pub debug: Vec<Span, &'c Bump>,
|
pub debug: Vec<Span, &'c Bump>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnlinkedCode<'u> {
|
|
||||||
pub stmts: Vec<Vec<Stmt, &'u Bump>, &'u Bump>,
|
|
||||||
pub debug: Vec<Vec<Span, &'u Bump>, &'u Bump>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate<'c>(alloc: &'c Bump, ir: &Ir<'_>) -> Code<'c> {
|
pub fn generate<'c>(alloc: &'c Bump, ir: &Ir<'_>) -> Code<'c> {
|
||||||
let unlinked_alloc = Bump::new();
|
let stmts = Vec::new_in(alloc);
|
||||||
|
let debug = Vec::new_in(alloc);
|
||||||
|
let mut code = Code { stmts, debug };
|
||||||
|
|
||||||
let stmts = Vec::new_in(&unlinked_alloc);
|
generate_stmts(&mut code, &ir.stmts);
|
||||||
let debug = Vec::new_in(&unlinked_alloc);
|
code.stmts.push(Stmt::End);
|
||||||
let mut unlinked = UnlinkedCode { stmts, debug };
|
code.debug.push(Span::default());
|
||||||
|
|
||||||
generate_stmts(&unlinked_alloc, &mut unlinked, &ir.stmts);
|
|
||||||
|
|
||||||
link(alloc, &unlinked)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_stmts<'u>(alloc: &'u Bump, code: &mut UnlinkedCode<'u>, ir: &[IrStmt<'_>]) {
|
|
||||||
for ir_stmt in ir {
|
|
||||||
ir_to_stmt(alloc, code, ir_stmt, 0);
|
|
||||||
}
|
|
||||||
assert_eq!(code.stmts.len(), code.debug.len());
|
assert_eq!(code.stmts.len(), code.debug.len());
|
||||||
|
|
||||||
|
code
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ir_to_stmt<'u>(
|
fn generate_stmts<'c>(code: &mut Code<'c>, ir: &[IrStmt<'_>]) {
|
||||||
alloc: &'u Bump,
|
for ir_stmt in ir {
|
||||||
code: &mut UnlinkedCode<'u>,
|
ir_to_stmt(code, ir_stmt);
|
||||||
ir_stmt: &IrStmt<'_>,
|
}
|
||||||
current_block: usize,
|
debug_assert_eq!(code.stmts.len(), code.debug.len());
|
||||||
) {
|
}
|
||||||
|
|
||||||
|
fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) {
|
||||||
let stmt = match &ir_stmt.kind {
|
let stmt = match &ir_stmt.kind {
|
||||||
StmtKind::Add(n) => Stmt::Add(*n),
|
StmtKind::Add(n) => Stmt::Add(*n),
|
||||||
StmtKind::Sub(n) => Stmt::Sub(*n),
|
StmtKind::Sub(n) => Stmt::Sub(*n),
|
||||||
|
|
@ -75,20 +69,27 @@ fn ir_to_stmt<'u>(
|
||||||
StmtKind::In => Stmt::In,
|
StmtKind::In => Stmt::In,
|
||||||
StmtKind::SetNull => Stmt::SetNull,
|
StmtKind::SetNull => Stmt::SetNull,
|
||||||
StmtKind::Loop(instr) => {
|
StmtKind::Loop(instr) => {
|
||||||
let new_block = Vec::new_in(alloc);
|
let skip_jmp_idx = code.stmts.len();
|
||||||
let new_block_debug = Vec::new_in(alloc);
|
code.stmts.push(Stmt::JmpIfZero(usize::MAX)); // placeholder
|
||||||
code.stmts.push(new_block);
|
code.debug.push(ir_stmt.span);
|
||||||
code.stmts.push(new_block_debug);
|
|
||||||
|
// compile the loop body now
|
||||||
|
generate_stmts(code, &instr.stmts);
|
||||||
|
// if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected
|
||||||
|
let first_loop_body_idx = skip_jmp_idx + 1;
|
||||||
|
code.stmts.push(Stmt::JmpIfNonZero(first_loop_body_idx));
|
||||||
|
code.debug.push(ir_stmt.span);
|
||||||
|
|
||||||
|
// there will always at least be an `End` instruction after the loop
|
||||||
|
let after_loop_idx = code.stmts.len();
|
||||||
|
|
||||||
|
// fix the placeholder with the actual index
|
||||||
|
code.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx);
|
||||||
|
|
||||||
let current_block = code.stmts.len() - 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
code.stmts[current_block].push(stmt);
|
code.stmts.push(stmt);
|
||||||
code.debug[current_block].push(ir_stmt.span);
|
code.debug.push(ir_stmt.span);
|
||||||
}
|
|
||||||
|
|
||||||
fn link<'c>(alloc: &'c Bump, code: &UnlinkedCode<'_>) -> Code<'c> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,6 @@ impl<'c, W: Write, R: Read> Interpreter<'c, W, R> {
|
||||||
self.ip = pos;
|
self.ip = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Jmp(pos) => {
|
|
||||||
self.ip = pos;
|
|
||||||
}
|
|
||||||
Stmt::End => break,
|
Stmt::End => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ use bumpalo::Bump;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
mod codegen;
|
pub mod codegen;
|
||||||
mod codegen_interpreter;
|
pub mod codegen_interpreter;
|
||||||
pub mod opts;
|
pub mod opts;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ fn main() {
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let stdin = stdin.lock();
|
let stdin = stdin.lock();
|
||||||
|
|
||||||
brainfuck::run(&file, stdout, stdin, UseProfile::Yes).unwrap_or_else(|_| {
|
brainfuck::run(&file, stdout, stdin, UseProfile::No).unwrap_or_else(|_| {
|
||||||
eprintln!("error: Failed to parse brainfuck code");
|
eprintln!("error: Failed to parse brainfuck code");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Instrs<'ast> = Vec<(Instr<'ast>, Span), &'ast Bump>;
|
pub type Ast<'ast> = Vec<(Instr<'ast>, Span), &'ast Bump>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Instr<'ast> {
|
pub enum Instr<'ast> {
|
||||||
|
|
@ -47,13 +47,13 @@ pub enum Instr<'ast> {
|
||||||
Left,
|
Left,
|
||||||
Out,
|
Out,
|
||||||
In,
|
In,
|
||||||
Loop(Instrs<'ast>),
|
Loop(Ast<'ast>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ParseError;
|
pub struct ParseError;
|
||||||
|
|
||||||
pub fn parse<I>(alloc: &Bump, mut src: I) -> Result<Instrs<'_>, ParseError>
|
pub fn parse<I>(alloc: &Bump, mut src: I) -> Result<Ast<'_>, ParseError>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (usize, u8)>,
|
I: Iterator<Item = (usize, u8)>,
|
||||||
{
|
{
|
||||||
|
|
@ -85,7 +85,7 @@ fn parse_loop<'ast, I>(
|
||||||
src: &mut I,
|
src: &mut I,
|
||||||
depth: u16,
|
depth: u16,
|
||||||
start_idx: usize,
|
start_idx: usize,
|
||||||
) -> Result<(Instrs<'ast>, Span), ParseError>
|
) -> Result<(Ast<'ast>, Span), ParseError>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (usize, u8)>,
|
I: Iterator<Item = (usize, u8)>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue