diff --git a/src/engine.rs b/src/engine.rs
index d0e0b30..6cd06f3 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -1,4 +1,25 @@
 //! 正規表現エンジン
-// mod codegen;
-// mod evaluator;
-mod parser;
\ No newline at end of file
+
+use std::fmt::{self, Display};
+mod codegen;
+mod evaluator;
+mod parser;
+
+#[derive(Debug)]
+pub enum Instruction {
+    Char(char),
+    Match,
+    Jump(usize),
+    Split(usize, usize),
+}
+
+impl Display for Instruction {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Instruction::Char(c) => write!(f, "char {}", c),
+            Instruction::Match => write!(f, "match"),
+            Instruction::Jump(addr) => write!(f, "jump {:>04}", addr),
+            Instruction::Split(addr1, addr2) => write!(f, "split {:>04}, {:>04}", addr1, addr2),
+        }
+    }
+}
diff --git a/src/engine/codegen.rs b/src/engine/codegen.rs
new file mode 100644
index 0000000..6ef088f
--- /dev/null
+++ b/src/engine/codegen.rs
@@ -0,0 +1,226 @@
+//! ASTからコード生成を行う
+use super::{parser::AST, Instruction};
+use crate::helper::safe_add;
+use std::{
+    error::Error,
+    fmt::{self, Display},
+};
+
+/// コード生成エラーを表す型
+#[derive(Debug)]
+pub enum CodeGenError {
+    PCOverFlow,
+    FailStar,
+    FailOr,
+    FailQuestion,
+}
+
+impl Display for CodeGenError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "CodeGenError: {:?}", self)
+    }
+}
+
+impl Error for CodeGenError {}
+
+/// コード生成器
+#[derive(Default, Debug)]
+struct Generator {
+    pc: usize,
+    insts: Vec<Instruction>,
+}
+
+/// コード生成を行う関数
+pub fn get_code(ast: &AST) -> Result<Vec<Instruction>, CodeGenError> {
+    let mut generator = Generator::default();
+    generator.gen_code(ast)?;
+    Ok(generator.insts)
+}
+
+/// コード生成器のメソッド定義
+impl Generator {
+    /// コード生成を行う関数の入り口
+    fn gen_code(&mut self, ast: &AST) -> Result<(), CodeGenError> {
+        self.gen_expr(ast)?;
+        self.inc_pc()?;
+        self.insts.push(Instruction::Match);
+        Ok(())
+    }
+
+    /// ASTをパターン分けしコード生成を行う関数
+    fn gen_expr(&mut self, ast: &AST) -> Result<(), CodeGenError> {
+        match ast {
+            AST::Char(c) => self.gen_char(*c)?,
+            AST::Or(e1, e2) => self.gen_or(e1, e2)?,
+            AST::Plus(e) => self.gen_plus(e)?,
+            AST::Star(e1) => {
+                match &**e1 {
+                    // `(a*)*`のように`Star`が二重となっている場合にスタックオーバーフローする問題を回避するため、
+                    // このような`(((r*)*)*...*)*`を再帰的に処理して1つの`r*`へと変換する。
+                    AST::Star(_) => self.gen_expr(&e1)?,
+                    AST::Seq(e2) if e2.len() == 1 => {
+                        if let Some(e3 @ AST::Star(_)) = e2.get(0) {
+                            self.gen_expr(e3)?
+                        } else {
+                            self.gen_star(e1)?
+                        }
+                    }
+                    e => self.gen_star(&e)?,
+                }
+            }
+            AST::Question(e) => self.gen_question(e)?,
+            AST::Seq(v) => self.gen_seq(v)?,
+        }
+
+        Ok(())
+    }
+
+    /// char命令生成関数
+    fn gen_char(&mut self, c: char) -> Result<(), CodeGenError> {
+        let inst = Instruction::Char(c);
+        self.insts.push(inst);
+        self.inc_pc()?;
+        Ok(())
+    }
+
+    /// OR演算子のコード生成器。
+    ///
+    /// 以下のようなコードを生成。
+    ///
+    /// ```text
+    ///     split L1, L2
+    /// L1: e1のコード
+    ///     jmp L3
+    /// L2: e2のコード
+    /// L3:
+    /// ```
+    fn gen_or(&mut self, e1: &AST, e2: &AST) -> Result<(), CodeGenError> {
+        // split L1, L2
+        let split_addr = self.pc;
+        self.inc_pc()?;
+        let split = Instruction::Split(self.pc, 0); // L1 = self.pc。L2は仮に0と設定
+        self.insts.push(split);
+
+        // L1: e1のコード
+        self.gen_expr(e1)?;
+
+        // jmp L3
+        let jmp_addr = self.pc;
+        self.insts.push(Instruction::Jump(0)); // L3を仮に0と設定
+
+        // L2の値を設定
+        self.inc_pc()?;
+        if let Some(Instruction::Split(_, l2)) = self.insts.get_mut(split_addr) {
+            *l2 = self.pc;
+        } else {
+            return Err(CodeGenError::FailOr);
+        }
+
+        // L2: e2のコード
+        self.gen_expr(e2)?;
+
+        // L3の値を設定
+        if let Some(Instruction::Jump(l3)) = self.insts.get_mut(jmp_addr) {
+            *l3 = self.pc;
+        } else {
+            return Err(CodeGenError::FailOr);
+        }
+
+        Ok(())
+    }
+
+    /// ?限量子のコード生成器。
+    ///
+    /// 以下のようなコードを生成
+    ///
+    /// ```text
+    ///     split L1, L2
+    /// L1: eのコード
+    /// L2:
+    /// ```
+    fn gen_question(&mut self, e: &AST) -> Result<(), CodeGenError> {
+        // split L1, L2
+        let split_addr = self.pc;
+        self.inc_pc()?;
+        let split = Instruction::Split(self.pc, 0); // self.pcがL1。L2を仮に0と設定
+        self.insts.push(split);
+
+        // L1: eのコード
+        self.gen_expr(e)?;
+
+        // L2の値を設定
+        if let Some(Instruction::Split(_, l2)) = self.insts.get_mut(split_addr) {
+            *l2 = self.pc;
+            Ok(())
+        } else {
+            Err(CodeGenError::FailQuestion)
+        }
+    }
+
+    /// 以下のようなコードを生成
+    ///
+    /// ```text
+    /// L1: eのコード
+    ///     split L1, L2
+    /// L2:
+    /// ```
+    fn gen_plus(&mut self, e: &AST) -> Result<(), CodeGenError> {
+        // L1: eのコード
+        let l1 = self.pc;
+        self.gen_expr(e)?;
+
+        // split L1, L2
+        self.inc_pc()?;
+        let split = Instruction::Split(l1, self.pc); // self.pcがL2
+        self.insts.push(split);
+
+        Ok(())
+    }
+
+    /// *限量子のコード生成器。
+    ///
+    /// 以下のようなコードを生成
+    ///
+    /// ```text
+    /// L1: split L2, L3
+    /// L2: eのコード
+    ///     jump L1
+    /// L3:
+    /// ```
+    fn gen_star(&mut self, e: &AST) -> Result<(), CodeGenError> {
+        // L1: split L2, L3
+        let l1 = self.pc;
+        self.inc_pc()?;
+        let split = Instruction::Split(self.pc, 0); // self.pcがL2。L3を仮に0と設定
+        self.insts.push(split);
+
+        // L2: eのコード
+        self.gen_expr(e)?;
+
+        // jump L1
+        self.inc_pc()?;
+        self.insts.push(Instruction::Jump(l1));
+
+        // L3の値を設定
+        if let Some(Instruction::Split(_, l3)) = self.insts.get_mut(l1) {
+            *l3 = self.pc;
+            Ok(())
+        } else {
+            Err(CodeGenError::FailStar)
+        }
+    }
+
+    /// 連続する正規表現のコード生成
+    fn gen_seq(&mut self, exprs: &[AST]) -> Result<(), CodeGenError> {
+        for e in exprs {
+            self.gen_expr(e)?;
+        }
+
+        Ok(())
+    }
+
+    /// プログラムカウンタをインクリメント
+    fn inc_pc(&mut self) -> Result<(), CodeGenError> {
+        safe_add(&mut self.pc, &1, || CodeGenError::PCOverFlow)
+    }
+}
diff --git a/src/engine/evaluator.rs b/src/engine/evaluator.rs
new file mode 100644
index 0000000..9ad5105
--- /dev/null
+++ b/src/engine/evaluator.rs
@@ -0,0 +1,151 @@
+//! 命令列と入力文字列を受け取り、マッチングを行う
+use super::Instruction;
+use crate::helper::safe_add;
+use std::{
+    collections::VecDeque,
+    error::Error,
+    fmt::{self, Display},
+};
+
+#[derive(Debug)]
+pub enum EvalError {
+    PCOverFlow,
+    SPOverFlow,
+    InvalidPC,
+    InvalidContext,
+}
+
+impl Display for EvalError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "CodeGenError: {:?}", self)
+    }
+}
+
+impl Error for EvalError {}
+
+/// 命令列の評価を行う関数。
+///
+/// instが命令列となり、その命令列を用いて入力文字列lineにマッチさせる。
+/// is_depthがtrueの場合に深さ優先探索を、falseの場合に幅優先探索を行う。
+///
+/// 実行時エラーが起きた場合はErrを返す。
+/// マッチ成功時はOk(true)を、失敗時はOk(false)を返す。
+pub fn eval(inst: &[Instruction], line: &[char], is_depth: bool) -> Result<bool, EvalError> {
+    if is_depth {
+        eval_depth(inst, line, 0, 0)
+    } else {
+        eval_width(inst, line)
+    }
+}
+
+/// 深さ優先探索で再帰的にマッチングを行う評価器
+fn eval_depth(
+    inst: &[Instruction],
+    line: &[char],
+    mut pc: usize,
+    mut sp: usize,
+) -> Result<bool, EvalError> {
+    loop {
+        let next = if let Some(i) = inst.get(pc) {
+            i
+        } else {
+            return Err(EvalError::InvalidPC);
+        };
+
+        match next {
+            Instruction::Char(c) => {
+                if let Some(sp_c) = line.get(sp) {
+                    if c == sp_c {
+                        safe_add(&mut pc, &1, || EvalError::PCOverFlow)?;
+                        safe_add(&mut sp, &1, || EvalError::SPOverFlow)?;
+                    } else {
+                        return Ok(false);
+                    }
+                } else {
+                    return Ok(false);
+                }
+            }
+            Instruction::Match => {
+                return Ok(true);
+            }
+            Instruction::Jump(addr) => {
+                pc = *addr;
+            }
+            Instruction::Split(addr1, addr2) => {
+                if eval_depth(inst, line, *addr1, sp)? || eval_depth(inst, line, *addr2, sp)? {
+                    return Ok(true);
+                } else {
+                    return Ok(false);
+                }
+            }
+        }
+    }
+}
+
+fn pop_ctx(
+    pc: &mut usize,
+    sp: &mut usize,
+    ctx: &mut VecDeque<(usize, usize)>,
+) -> Result<(), EvalError> {
+    if let Some((p, s)) = ctx.pop_back() {
+        *pc = p;
+        *sp = s;
+        Ok(())
+    } else {
+        Err(EvalError::InvalidContext)
+    }
+}
+
+/// 幅優先探索で再帰的にマッチングを行う評価器
+fn eval_width(inst: &[Instruction], line: &[char]) -> Result<bool, EvalError> {
+    let mut ctx = VecDeque::new();
+    let mut pc = 0;
+    let mut sp = 0;
+
+    loop {
+        let next = if let Some(i) = inst.get(pc) {
+            i
+        } else {
+            return Err(EvalError::InvalidPC);
+        };
+
+        match next {
+            Instruction::Char(c) => {
+                if let Some(sp_c) = line.get(sp) {
+                    if c == sp_c {
+                        safe_add(&mut pc, &1, || EvalError::PCOverFlow)?;
+                        safe_add(&mut sp, &1, || EvalError::SPOverFlow)?;
+                    } else {
+                        if ctx.is_empty() {
+                            return Ok(false);
+                        } else {
+                            pop_ctx(&mut pc, &mut sp, &mut ctx)?;
+                        }
+                    }
+                } else {
+                    if ctx.is_empty() {
+                        return Ok(false);
+                    } else {
+                        pop_ctx(&mut pc, &mut sp, &mut ctx)?;
+                    }
+                }
+            }
+            Instruction::Match => {
+                return Ok(true);
+            }
+            Instruction::Jump(addr) => {
+                pc = *addr;
+            }
+            Instruction::Split(addr1, addr2) => {
+                pc = *addr1;
+                ctx.push_back((*addr2, sp));
+                continue;
+            }
+        }
+
+        if !ctx.is_empty() {
+            ctx.push_back((pc, sp));
+            pop_ctx(&mut pc, &mut sp, &mut ctx)?;
+        }
+    }
+}
diff --git a/src/helper.rs b/src/helper.rs
new file mode 100644
index 0000000..e88163b
--- /dev/null
+++ b/src/helper.rs
@@ -0,0 +1,24 @@
+pub trait SafeAdd: Sized {
+    fn safe_add(&self, n: &Self) -> Option<Self>;
+}
+
+impl SafeAdd for usize {
+    fn safe_add(&self, n: &Self) -> Option<Self> {
+        self.checked_add(*n)
+    }
+}
+
+pub fn safe_add<T, F, E>(dst: &mut T, src: &T, f: F) -> Result<(), E>
+where
+    T: SafeAdd,
+    F: Fn() -> E,
+{
+    if let Some(n) = dst.safe_add(src) {
+        *dst = n;
+        Ok(())
+    } else {
+        Err(f())
+    }
+}
+
+pub type DynError = Box<dyn std::error::Error + Send + Sync + 'static>;
diff --git a/src/lib.rs b/src/lib.rs
index 46370bf..47da32c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,6 @@
 //! regex::print(expr); // 正規表現のASTと命令列を表示
 //! ```
 mod engine;
-// mod helper;
+mod helper;
 
-// pub use engine::{do_matching, print};
\ No newline at end of file
+// pub use engine::{do_matching, print};