3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rustでコンパイラ改

Last updated at Posted at 2013-07-13

※Rust0.7で作成しました。

今回は以下のリファクタリングを行いました。

  • copyは使わなくして、cloneを使うようにしました。
  • Joinableというトレイトを作って汎用的なJoinを作りました。
  • macroを使って複数のimplを1つに纏めました。
use join::Joinable;
use ast::*;

pub mod ast {

  #[deriving(Clone,ToStr)]
  pub enum E {
    ELdc(~T, int),
    EBin(~T, ~str, ~E, ~E),
    EPrint(~T, ~E),
    EBlock(~T, ~[~E]),
  }

  macro_rules! EOp(
    ($T:ident, $op:expr) => (
      pub fn $T(t: ~T, a: ~E, b: ~E) -> E {
        EBin(t, ~$op, a, b)
      }
    )
  )

  EOp!(EAdd, "add")
  EOp!(ESub, "sub")
  EOp!(EMul, "mul")
  EOp!(EDiv, "div")

  #[deriving(Clone,ToStr)]
  pub enum T {
    Ti(int),
    Tv,
    TFun(~T, ~[~T]),
  }

  #[deriving(Clone,ToStr)]
  pub enum R {
    pub RG(~T, ~str),
    pub RL(~T, ~str),
    pub RR(~T, ~str),
    pub RN(~T, ~str),
  }

  #[deriving(Clone,ToStr)]
  pub enum LL {
    LLCall(Option<~R>, ~R, ~[~R]),
    LLBin(Option<~R>, ~str, ~R, ~R),
  }

  macro_rules! impl_ToStr_for(
    ($T:ty) => (
      impl ToStr for $T {
        #[inline]
        fn to_str(&self) -> ~str {
          fmt!("%?", *self)
        }
      }
    )
  )

  macro_rules! impl_ToStr_for_Option(
    ($T:ty) => (
      impl ToStr for Option<$T> {
        fn to_str(&self) -> ~str {
          match *self {
            Some(ref r) => fmt!("Some(%?)",r),
            None => ~"None",
          }
        }
      }
    )
  )

  impl_ToStr_for!(~E)
  impl_ToStr_for!(~T)
  impl_ToStr_for!(~R)
  impl_ToStr_for!(~LL)

  impl_ToStr_for_Option!(~R)

  impl Eq for T {

    pub fn eq(&self, t:&T) -> bool {
      self.to_str() == t.to_str()
    }

    pub fn ne(&self, t:&T) -> bool {
      !(self == t)
    }

  }

  impl R {

    pub fn t(&self) -> ~T {
      match *self {
        RG(ref t, _) => t.clone(),
        RL(ref t, _) => t.clone(),
        RR(ref t, _) => t.clone(),
        RN(ref t, _) => t.clone(),
      }
    }

  }

  pub trait P {
    fn p(&self) -> ~str;
  }

  impl P for T {
    pub fn p(&self) -> ~str {
      match *self {
        Ti(ref i) => "i" + i.to_str(),
        Tv => ~"void",
        TFun(ref t, ref ls) => {
          t.p() + "(" + ls.map(|t| t.p()).join(", ") + ")*"
        }
      }
    }

  }

  impl P for R {
    pub fn p(&self) -> ~str {
      match *self {
        RG(_,ref id) => "@" + *id,
        RL(_,ref id) => "%" + *id,
        RR(_,ref id) => "%." + *id,
        RN(_,ref id) => id.clone(),
      }
    }

  }

}


fn main() {
//    println(os::getcwd().to_str());
//    println(os::getenv("PATH").unwrap());
//    os::setenv("PATH", os::getenv("PATH").unwrap());
//    println(readAll("test.rs"));
//    writeAll("tes.txt", "hogehoge");

  let ast = ~EBlock(~Tv, ~[
    ~EPrint(~Ti(32), ~ELdc(~Ti(32), 11)),
    ~EPrint(~Ti(32),
      ~EAdd(~Ti(32), ~ELdc(~Ti(32), 11), ~ELdc(~Ti(32), 22)))
  ]);
  println("ast=" + ast.to_str());

  let ll = kNormal(ast);
  println("ll=" + ll.to_str());
  
  emit("e.ll", ll);
  
  println(exec("llc e.ll -o e.s").to_str());
  println(exec("llvm-gcc -m64 e.s -o e").to_str());
  println(exec("./e").to_str());
}

mod interpreter {
  use ast::*;

  fn eval(e:&E)->int {

    match e {

      &ELdc(_, i) => i,

      &EBin(_, ~"add", ref a, ref b) => eval(*a) + eval(*b),

      &EBin(_, ref op, _, _) => fail!("operator "+*op),

      &EPrint(_, ref e) => {
        let e = eval(*e);
        println(e.to_str());
        e
      }

      &EBlock(_, ref ls) => {
        fn f(ls:&[~E],r:int)-> int {
          match ls {
            [] => r,
            [ref a, ..rest] => f(rest,eval(*a))
          }
        }
        f(*ls, 0)
      }
    }
  }
}

mod kNormal {
  use ast::*;
  use std::vec;

  fn gid(t:&T)-> ~R {
    ~RR(~(*t).clone(),~"")
  }

  static mut ls:Option<~[~LL]> = None;

  fn add(l:~LL) {
    unsafe {
      ls = Some(vec::append_one(ls.unwrap(), l));
    }
  }

  fn f(a: &E)-> ~R {

    match a {

      &EBin(ref t,ref op, ref a, ref b) => {
        let a = f(*a);
        let b = f(*b);
        let id = gid(*t);
        if (*t != a.t() || *t != b.t()) {fail!(fmt!("type mismatch %?",*t));}
        add(~LLBin(Some(id.clone()), op.clone(), a, b));
        id
      }

      &ELdc(ref t, ref i) => ~RN(t.clone(), i.to_str()),

      &EPrint(ref t, ref a) => {
        let a = f(*a);
        if (*t != a.t()) {fail!(fmt!("type mismatch t=%? ta=%?", t, a.t()))}
        add(~LLCall(None, ~RG(~TFun(~Tv, ~[t.clone()]), "print_" + t.p()), ~[a.clone()]));
        a
      }

      &EBlock(_,ref ls) => {
        fn f2(ls:&[~E],r:&R)-> ~R {
          match ls {
            [] => ~r.clone(),
            [ref e, ..rest] => f2(rest,f(*e)),
          }
        }
        f2(*ls, ~RN(~Tv,~""))
      }

    }

  }

  pub fn apply(e: &E) -> ~[~LL] {
    unsafe {
      ls = Some(~[]);
      f(e);
      ls.unwrap()
    }
  }
  
}

fn kNormal(a: &ast::E) -> ~[~ast::LL] {
  kNormal::apply(a)
}

pub mod emit {

  use ast::*;
  use asm;

  fn o(id: &Option<~R>, out: &str) {
    match id {
      &Some(ref id) =>asm::__(id.p() + " = " + out),
      &None => asm::__(out),
    }
  }

  fn emitLL(l: &LL) {
    match l {
      &LLCall(ref id, ref op, ref prms) => {
        let prms:~[~str] = prms.map(|a| a.t().p() + " " + a.p());
        o(id, fmt!("call %s %s(%s) nounwind",
          op.t().p(), op.p(), prms.join(", ")))
      }
      &LLBin(ref id, ref op, ref a, ref b) => {
        o(id, fmt!("%s %s %s, %s", *op, a.t().p(), a.p(), b.p()))
      }
    }
  }

  pub fn apply(file: &str, ls: &[~LL]) {

    asm::open(file);
    asm("@.str = private constant [4 x i8] c\"%d\\0A\\00\"");
    asm("define void @print_i32(i32 %a) nounwind ssp {");
    asm("entry:");
    asm::__("call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %a) nounwind");
    asm::__("ret void");
    asm("}");
    asm("define void @print_i8(i8 %a) nounwind ssp {");
    asm("entry:");
    asm::__("call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i8 %a) nounwind");
    asm::__("ret void");
    asm("}");

    asm("declare i32 @printf(i8*, ...) nounwind");

    asm("define i32 @main() nounwind ssp {");
    asm("entry:");

    ls.map(|l| emitLL(*l));
    

    asm::__("ret i32 0");
    asm("}");
    asm::close();
  }

}

pub fn emit(file: &str, ls: &[~ast::LL]) {
  emit::apply(file, ls);
}

pub fn genid(s:&str) -> ~str {
  static mut id:int = 0;
  unsafe {
    id += 1;
    s + id.to_str()
  }
}

fn readAll(file:&str) -> ~str {
  use std::io;
  use std::result;
  let reader = result::get(&io::file_reader(&Path(file)));
  let mut s = ~"";
  while !reader.eof() {
    s = s + reader.read_line() + "\n";
  }
  s
} 

fn writeAll(file:&str, s:&str) {
  use std::io;
  use std::result;
  let writer = result::get(&io::buffered_file_writer(&Path(file)));
  writer.write_str(s);
}

pub mod asm {

  use std::io;
  use std::result;

  pub static mut writer: Option<@Writer> = None;

  pub fn open(file:&str) {
    unsafe {
      writer = Some(result::get(&io::buffered_file_writer(&Path(file))));
    }
  }

  pub fn println(s:&str) {
    unsafe {
      writer.unwrap().write_str(s + "\n");
    }
  }

  pub fn close() {
    unsafe {
      writer = None;
    }
  }

  pub fn __(s:&str) {
    println("  " + s);
  }

}

pub fn asm(s:&str) {
  asm::println(s);
}

fn exec(cmd:&str) -> (int, ~str, ~str) {

  use std::str;
  use std::run;

  let mut cmds:~[&str] = cmd.split_str_iter(" ").collect();
  let prog:~str = cmds.shift().to_str();
  let args:~[~str] = cmds.map(|&s| s.to_str());
  let o = run::process_output(prog,args);

  unsafe {
    (o.status,
    str::raw::from_bytes(o.output),
    str::raw::from_bytes(o.error),
    )
  }

}

pub mod join {
  pub trait Joinable<T> {
    fn join(&self, sep:&str) -> ~str;
  }

  impl<T:ToStr> Joinable<T> for ~[T] {
    fn join(&self, sep:&str) -> ~str {
      let mut s:~str = ~"";
      for (*self).iter().advance |t| {
        match s {
          ~"" => s = t.to_str(),
          _ => s = s + sep + t.to_str(),
        }
      }
      s
    }
  }

}
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?