Nicolas Winkler 4 år sedan
förälder
incheckning
1633061ef3
8 ändrade filer med 231 tillägg och 59 borttagningar
  1. 113 43
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 2 2
      benchmark.py
  4. 42 10
      src/main.rs
  5. 1 0
      src/optimize.rs
  6. 24 4
      src/trans/c.rs
  7. 1 0
      src/trans/mod.rs
  8. 47 0
      src/trans/zombie_ir.rs

+ 113 - 43
Cargo.lock

@@ -1,150 +1,220 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 [[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
 name = "bitflags"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
 [[package]]
 name = "byteorder"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
 
 [[package]]
 name = "dynasm"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42a814e1edeb85dd2a3c6fc0d6bf76d02ca5695d438c70ecee3d90774f3259c5"
 dependencies = [
- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags",
+ "byteorder",
+ "lazy_static",
+ "owning_ref",
+ "proc-macro2",
+ "quote",
+ "syn",
 ]
 
 [[package]]
 name = "dynasmrt"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a393aaeb4441a48bcf47b5b6155971f82cc1eb77e22855403ccc0415ac8328d"
 dependencies = [
- "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder",
+ "memmap",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.43"
+version = "0.2.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
 
 [[package]]
 name = "memmap"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
 dependencies = [
- "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc",
+ "winapi",
 ]
 
 [[package]]
 name = "owning_ref"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
 dependencies = [
- "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait",
 ]
 
 [[package]]
 name = "proc-macro2"
 version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
 dependencies = [
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid",
 ]
 
 [[package]]
 name = "quote"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 dependencies = [
- "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
 ]
 
 [[package]]
 name = "stable_deref_trait"
 version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
 [[package]]
 name = "syn"
 version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
 dependencies = [
- "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
 ]
 
 [[package]]
 name = "typed-arena"
 version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
 
 [[package]]
 name = "unicode-xid"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
 
 [[package]]
 name = "winapi"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
 dependencies = [
- "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
 ]
 
 [[package]]
 name = "winapi-i686-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "zombie"
 version = "0.1.0"
 dependencies = [
- "dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "dynasmrt 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap",
+ "dynasm",
+ "dynasmrt",
+ "typed-arena",
+ "winapi",
 ]
-
-[metadata]
-"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
-"checksum dynasm 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "42a814e1edeb85dd2a3c6fc0d6bf76d02ca5695d438c70ecee3d90774f3259c5"
-"checksum dynasmrt 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a393aaeb4441a48bcf47b5b6155971f82cc1eb77e22855403ccc0415ac8328d"
-"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
-"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
-"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
-"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
-"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
-"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
-"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
-"checksum typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5"
-"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
-"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
-"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 1 - 0
Cargo.toml

@@ -13,3 +13,4 @@ dynasm = "0.5.2"
 dynasmrt = "0.5.2"
 winapi = "*"
 typed-arena = "1.4.1"
+clap = "2.33.3"

+ 2 - 2
benchmark.py

@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import os
 from timeit import default_timer as timer
@@ -16,7 +16,7 @@ for i in range(1, nTries):
     tries.append((end - start) * 1000)
 
 
-print("benchmark for commit: " + check_output(["git", "rev-parse", "HEAD"]))
+print("benchmark for commit: " + str(check_output(["git", "rev-parse", "HEAD"])))
 print(str(nTries) + " tries were run")
 print("")
 print("average time [ms]: " + str(np.mean(tries)))

+ 42 - 10
src/main.rs

@@ -9,7 +9,7 @@ extern crate typed_arena;
 
 use std::io::{self, Read};
 use std::fs::File;
-use std::env;
+use clap::{Arg, App};
 
 pub mod ir;
 pub mod parser;
@@ -24,11 +24,24 @@ use crate::ir::MutVisitor;
 use typed_arena::Arena;
 
 fn main() -> io::Result<()> {
-    let args: Vec<String> = env::args().collect();
+    let matches = App::new("Zombie")
+        .version("0.1.0")
+        .author("Nicolas Winkler <nicolas.winkler@gmx.ch>")
+        .about("Brainfuck interpreter and transpiler")
+        .arg(Arg::with_name("input")
+                 .index(1)
+                 .takes_value(true)
+                 .help("Input file"))
+        .arg(Arg::with_name("transpile")
+                 .long("transpile")
+                 .short("t")
+                 .takes_value(true)
+                 .help("Transpile to language"))
+        .get_matches();
     let mut buffer = String::new();
 
-    if args.len() > 1 {
-        File::open(&args[1])?.read_to_string(&mut buffer)?;
+    if let Some(input) = matches.value_of("input") {
+        File::open(&input)?.read_to_string(&mut buffer)?;
     }
     else {
         io::stdin().read_to_string(&mut buffer)?;
@@ -38,17 +51,36 @@ fn main() -> io::Result<()> {
     if let Ok(mut insts) = insts {
         let mut lin_loop_optimizer = optimize::LinOptimizer::new();
         lin_loop_optimizer.visit_instructions(&mut insts);
-        std::mem::replace(&mut insts, lin_loop_optimizer.instructions);
+        let _ = std::mem::replace(&mut insts, lin_loop_optimizer.instructions);
         
         //for ref inst in &insts {
             //println!("{}\n", inst.to_string());
         //}
         //println!("{}", trans::java::transpile(&insts));
-        let arena = Arena::new();
-        let dfg = optimize::create_dfg(&mut insts, &arena);
-        let c = trans::c::transpile_dfg(&dfg);
-        println!("{}", c);
-        //let _code = compile::compile(&insts);
+        //let c = trans::c::transpile_dfg(&dfg);
+        //println!("{}", c);
+        //println!("{}", trans::java::transpile(&insts));
+        
+        match matches.value_of("transpile") {
+            Some(lang) => {
+                let arena = Arena::new();
+                let dfg = optimize::create_dfg(&mut insts, &arena);
+                let code = if lang == "c" {
+                    //trans::c::transpile_dfg(&dfg)
+                    trans::c::transpile(&insts)
+                } else if lang == "java" {
+                    trans::java::transpile(&insts)
+                } else if lang == "zombie_ir" {
+                    trans::zombie_ir::transpile(&insts)
+                } else {
+                    "".to_owned()
+                };
+                println!("{}", code);
+            },
+            None => {
+                let _code = compile::compile(&insts);
+            }
+        }
     }
     else if let Err(msg) = insts {
         println!("error parsing: {}", msg);

+ 1 - 0
src/optimize.rs

@@ -283,6 +283,7 @@ impl ir::MutVisitor for LinOptimizer {
             }
             else if !dirty && increments.get(&0) == Some(&-1) {
                 self.offset = offset_before;
+                increments.remove(&0);
                 self.instructions.push(Instruction::LinearLoop{ offset: self.offset, factors: increments });
             }
             else {

+ 24 - 4
src/trans/c.rs

@@ -37,7 +37,7 @@ pub fn transpile_dfg(dfg: &optimize::DfgOptimizer) -> String {
 #include <string.h>
 #include <inttypes.h>
 
-#define OFF(X) (ptr + (uint16_t) (X))
+#define OFF(X) ((uint16_t)(ptr + (uint16_t) (X)))
 
 int main() {
     uint8_t* mem = (uint8_t*) calloc(0x10000, 1);
@@ -51,18 +51,34 @@ int main() {
 }
 
 fn generate_dfg(cfg: &Vec<DfInstr>, formatter: &mut Formatter) {
+    let mut memoffs: Vec<(i64, u64)> = Vec::new();
+    let mut tmp_counter: u64 = 0;
+    let offset_creator = |o: i64| {
+        if o < 0 {
+            format!("minus_{}", -o)
+        }
+        else {
+            format!("{}", o)
+        }
+    };
     for stmt in cfg {
         match stmt {
             DfInstr::MovePtr(off) => {
                 formatter.add_line(&format!("ptr += {};", off));
             },
             DfInstr::WriteMem(off, val) => {
-                formatter.add_line(&format!("mem[OFF({})] = {};", off, eval(val)));
+                formatter.add_line(&format!("uint8_t tmp_{} = {};", tmp_counter, eval(val)));
+                memoffs.push((*off, tmp_counter));
+                tmp_counter += 1;
             },
             DfInstr::Print(val) => {
                 formatter.add_line(&format!("putchar({});", eval(val)));
             },
             DfInstr::Loop(_val, instrs) => {
+                for (off, tmp) in &memoffs {
+                    formatter.add_line(&format!("mem[OFF({})] = tmp_{};", *off, *tmp));
+                }
+                memoffs.clear();
                 formatter.add_line("while(mem[OFF(0)]) {");
                 formatter.indent();
                 generate_dfg(&instrs, formatter);
@@ -71,6 +87,9 @@ fn generate_dfg(cfg: &Vec<DfInstr>, formatter: &mut Formatter) {
             },
         }
     }
+    for (off, tmp) in memoffs {
+        formatter.add_line(&format!("mem[OFF({})] = tmp_{};", off, tmp));
+    }
 }
 
 
@@ -91,10 +110,11 @@ impl Default for CTranspiler {
 #include <string.h>
 #include <inttypes.h>
 
-#define OFF(X) (ptr + (uint16_t) (X))
+#define OFF(X) ((uint16_t)(ptr + (uint16_t) (X)))
 
 int main() {
-    uint8_t* mem = (uint8_t*) calloc(0x10000, 1);
+    uint8_t* mem = (uint8_t*) malloc(0x10000 * sizeof(uint8_t));
+    memset(mem, 0, 0x10000 * sizeof(uint8_t));
     uint16_t ptr = 0;"#);
         transpiler.code_buf.indent();
         transpiler

+ 1 - 0
src/trans/mod.rs

@@ -3,4 +3,5 @@
 
 pub mod c;
 pub mod java;
+pub mod zombie_ir;
 

+ 47 - 0
src/trans/zombie_ir.rs

@@ -0,0 +1,47 @@
+use super::super::{ir, formatter};
+
+use ir::Instruction;
+use formatter::Formatter;
+
+pub fn transpile(instrs: &Vec<ir::Instruction>) -> String {
+    let mut formatter = Formatter::new();
+    generate(&mut formatter, instrs);
+    formatter.get_code()
+}
+
+
+fn generate(formatter: &mut Formatter, instrs: &Vec<Instruction>) {
+    for instr in instrs {
+        match instr {
+            Instruction::Nop => {},
+            Instruction::Add{ offset, value } => {
+                formatter.add_line(&format!("@{} += {}", offset, value));
+            },
+            Instruction::Set{ offset, value } => {
+                formatter.add_line(&format!("@{} = {})", offset, value));
+            },
+            Instruction::LinearLoop{ offset, factors } => {
+                for (off, factor) in factors {
+                    formatter.add_line(&format!("@{} = {} * @{}", offset + off, factor, offset));
+                }
+                formatter.add_line(&format!("@{} = 0 // End LL", offset));
+            },
+            Instruction::MovePtr(offset) => {
+                formatter.add_line(&format!("ptr += {}", offset));
+            },
+            Instruction::Loop(instructions) => {
+                formatter.add_line("Loop {");
+                formatter.indent();
+                generate(formatter, instructions);
+                formatter.unindent();
+                formatter.add_line("}");
+            },
+            Instruction::Read(offset) => {
+                formatter.add_line(&format!("Read(@{})", offset));
+            },
+            Instruction::Write(offset) => {
+                formatter.add_line(&format!("Write(@{})", offset));
+            }
+        }
+    }
+}