Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/codegen.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/codegen.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/codegen.c	(revision 439)
@@ -9,4 +9,5 @@
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 #include <mruby.h>
 #include <mruby/compile.h>
@@ -24,4 +25,6 @@
 #endif
 
+#define MAXARG_S (1<<16)
+
 typedef mrb_ast_node node;
 typedef struct mrb_parser_state parser_state;
@@ -37,5 +40,5 @@
 struct loopinfo {
   enum looptype type;
-  int pc1, pc2, pc3, acc;
+  int pc0, pc1, pc2, pc3, acc;
   int ensure_level;
   struct loopinfo *prev;
@@ -51,7 +54,8 @@
   node *lv;
 
-  int sp;
-  int pc;
-  int lastlabel;
+  uint16_t sp;
+  uint16_t pc;
+  uint16_t lastpc;
+  uint16_t lastlabel;
   int ainfo:15;
   mrb_bool mscope:1;
@@ -59,15 +63,13 @@
   struct loopinfo *loop;
   int ensure_level;
-  char const *filename;
+  mrb_sym filename_sym;
   uint16_t lineno;
 
   mrb_code *iseq;
   uint16_t *lines;
-  int icapa;
+  uint32_t icapa;
 
   mrb_irep *irep;
-  size_t pcapa;
-  size_t scapa;
-  size_t rcapa;
+  uint32_t pcapa, scapa, rcapa;
 
   uint16_t nlocals;
@@ -101,10 +103,12 @@
     codegen_scope *tmp = s->prev;
     mrb_free(s->mrb, s->iseq);
+    mrb_free(s->mrb, s->lines);
     mrb_pool_close(s->mpool);
     s = tmp;
   }
 #ifndef MRB_DISABLE_STDIO
-  if (s->filename && s->lineno) {
-    fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
+  if (s->filename_sym && s->lineno) {
+    const char *filename = mrb_sym_name_len(s->mrb, s->filename_sym, NULL);
+    fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message);
   }
   else {
@@ -125,13 +129,4 @@
 
 static void*
-codegen_malloc(codegen_scope *s, size_t len)
-{
-  void *p = mrb_malloc_simple(s->mrb, len);
-
-  if (!p) codegen_error(s, "mrb_malloc");
-  return p;
-}
-
-static void*
 codegen_realloc(codegen_scope *s, void *p, size_t len)
 {
@@ -145,24 +140,133 @@
 new_label(codegen_scope *s)
 {
-  s->lastlabel = s->pc;
-  return s->pc;
-}
-
-static inline int
-genop(codegen_scope *s, mrb_code i)
-{
-  if (s->pc == s->icapa) {
+  return s->lastlabel = s->pc;
+}
+
+static void
+emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
+{
+  if (pc >= MAXARG_S || s->icapa >= MAXARG_S) {
+    codegen_error(s, "too big code block");
+  }
+  if (pc >= s->icapa) {
     s->icapa *= 2;
+    if (s->icapa > MAXARG_S) {
+      s->icapa = MAXARG_S;
+    }
     s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
     if (s->lines) {
-      s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
-      s->irep->lines = s->lines;
-    }
-  }
-  s->iseq[s->pc] = i;
+      s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa);
+    }
+  }
   if (s->lines) {
-    s->lines[s->pc] = s->lineno;
-  }
-  return s->pc++;
+    if (s->lineno > 0 || pc == 0)
+      s->lines[pc] = s->lineno;
+    else
+      s->lines[pc] = s->lines[pc-1];
+  }
+  s->iseq[pc] = i;
+}
+
+static void
+emit_S(codegen_scope *s, int pc, uint16_t i)
+{
+  uint8_t hi = i>>8;
+  uint8_t lo = i&0xff;
+
+  emit_B(s, pc,   hi);
+  emit_B(s, pc+1, lo);
+}
+
+static void
+gen_B(codegen_scope *s, uint8_t i)
+{
+  emit_B(s, s->pc, i);
+  s->pc++;
+}
+
+static void
+gen_S(codegen_scope *s, uint16_t i)
+{
+  emit_S(s, s->pc, i);
+  s->pc += 2;
+}
+
+static void
+genop_0(codegen_scope *s, mrb_code i)
+{
+  s->lastpc = s->pc;
+  gen_B(s, i);
+}
+
+static void
+genop_1(codegen_scope *s, mrb_code i, uint16_t a)
+{
+  s->lastpc = s->pc;
+  if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+  }
+}
+
+static void
+genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+  s->lastpc = s->pc;
+  if (a > 0xff && b > 0xff) {
+    gen_B(s, OP_EXT3);
+    gen_B(s, i);
+    gen_S(s, a);
+    gen_S(s, b);
+  }
+  else if (b > 0xff) {
+    gen_B(s, OP_EXT2);
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    gen_S(s, b);
+  }
+  else if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+    gen_B(s, (uint8_t)b);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    gen_B(s, (uint8_t)b);
+  }
+}
+
+static void
+genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c)
+{
+  genop_2(s, i, a, b);
+  gen_B(s, c);
+}
+
+static void
+genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+  genop_1(s, i, a);
+  gen_S(s, b);
+}
+
+static void
+genop_W(codegen_scope *s, mrb_code i, uint32_t a)
+{
+  uint8_t a1 = (a>>16) & 0xff;
+  uint8_t a2 = (a>>8) & 0xff;
+  uint8_t a3 = a & 0xff;
+
+  s->lastpc = s->pc;
+  gen_B(s, i);
+  gen_B(s, a1);
+  gen_B(s, a2);
+  gen_B(s, a3);
 }
 
@@ -178,240 +282,241 @@
 }
 
-static int
-genop_peep(codegen_scope *s, mrb_code i, int val)
-{
-  /* peephole optimization */
-  if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) {
-    mrb_code i0 = s->iseq[s->pc-1];
-    int c1 = GET_OPCODE(i);
-    int c0 = GET_OPCODE(i0);
-
-    switch (c1) {
+static
+mrb_bool
+on_eval(codegen_scope *s)
+{
+  if (s && s->parser && s->parser->on_eval)
+    return TRUE;
+  return FALSE;
+}
+
+struct mrb_insn_data
+mrb_decode_insn(const mrb_code *pc)
+{
+  struct mrb_insn_data data = { 0 };
+  mrb_code insn = READ_B();
+  uint16_t a = 0;
+  uint16_t b = 0;
+  uint8_t  c = 0;
+
+  switch (insn) {
+#define FETCH_Z() /* empty */
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+  }
+  switch (insn) {
+  case OP_EXT1:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  case OP_EXT2:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  case OP_EXT3:
+    insn = READ_B();
+    switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+    }
+    break;
+  default:
+    break;
+  }
+  data.insn = insn;
+  data.a = a;
+  data.b = b;
+  data.c = c;
+  return data;
+}
+
+static struct mrb_insn_data
+mrb_last_insn(codegen_scope *s)
+{
+  if (s->pc == s->lastpc) {
+    struct mrb_insn_data data;
+
+    data.insn = OP_NOP;
+    return data;
+  }
+  return mrb_decode_insn(&s->iseq[s->lastpc]);
+}
+
+static mrb_bool
+no_peephole(codegen_scope *s)
+{
+  return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc;
+}
+
+static uint16_t
+genjmp(codegen_scope *s, mrb_code i, uint16_t pc)
+{
+  uint16_t pos;
+
+  s->lastpc = s->pc;
+  gen_B(s, i);
+  pos = s->pc;
+  gen_S(s, pc);
+  return pos;
+}
+
+static uint16_t
+genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val)
+{
+  uint16_t pos;
+
+  if (!no_peephole(s) && !val) {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    if (data.insn == OP_MOVE && data.a == a) {
+      s->pc = s->lastpc;
+      a = data.b;
+    }
+  }
+
+  s->lastpc = s->pc;
+  if (a > 0xff) {
+    gen_B(s, OP_EXT1);
+    gen_B(s, i);
+    gen_S(s, a);
+    pos = s->pc;
+    gen_S(s, pc);
+  }
+  else {
+    gen_B(s, i);
+    gen_B(s, (uint8_t)a);
+    pos = s->pc;
+    gen_S(s, pc);
+  }
+  return pos;
+}
+
+static void
+gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
+{
+  if (no_peephole(s)) {
+  normal:
+    genop_2(s, OP_MOVE, dst, src);
+    if (on_eval(s)) {
+      genop_0(s, OP_NOP);
+    }
+    return;
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    switch (data.insn) {
     case OP_MOVE:
-      if (GETARG_A(i) == GETARG_B(i)) {
-        /* skip useless OP_MOVE */
-        return 0;
-      }
-      if (val) break;
-      switch (c0) {
-      case OP_MOVE:
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          /* skip overriden OP_MOVE */
-          s->pc--;
-          s->iseq[s->pc] = i;
-        }
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) {
-          /* skip swapping OP_MOVE */
-          return 0;
-        }
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->pc--;
-          return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val);
-        }
-        break;
-      case OP_LOADI:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
-          return 0;
-        }
-        break;
-      case OP_ARRAY:
-      case OP_HASH:
-      case OP_RANGE:
-      case OP_AREF:
-      case OP_GETUPVAR:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
-          return 0;
-        }
-        break;
-      case OP_LOADSYM:
-      case OP_GETGLOBAL:
-      case OP_GETIV:
-      case OP_GETCV:
-      case OP_GETCONST:
-      case OP_GETSPECIAL:
-      case OP_LOADL:
-      case OP_STRING:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
-          return 0;
-        }
-        break;
-      case OP_SCLASS:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
-          return 0;
-        }
-        break;
-      case OP_LOADNIL:
-      case OP_LOADSELF:
-      case OP_LOADT:
-      case OP_LOADF:
-      case OP_OCLASS:
-        if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
-          return 0;
-        }
-        break;
-      default:
-        break;
-      }
+      if (dst == src) return;             /* remove useless MOVE */
+      if (data.b == dst && data.a == src) /* skip swapping MOVE */
+        return;
+      goto normal;
+    case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF:
+    case OP_LOADI__1:
+    case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+    case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+      if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+      s->pc = s->lastpc;
+      genop_1(s, data.insn, dst);
       break;
-    case OP_SETIV:
-    case OP_SETCV:
-    case OP_SETCONST:
-    case OP_SETMCNST:
-    case OP_SETGLOBAL:
-      if (val) break;
-      if (c0 == OP_MOVE) {
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
-          return 0;
-        }
-      }
-      break;
-    case OP_SETUPVAR:
-      if (val) break;
-      if (c0 == OP_MOVE) {
-        if (GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
-          return 0;
-        }
-      }
-      break;
-    case OP_EPOP:
-      if (c0 == OP_EPOP) {
-        s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
-        return 0;
-      }
-      break;
-    case OP_POPERR:
-      if (c0 == OP_POPERR) {
-        s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
-        return 0;
-      }
-      break;
-    case OP_RETURN:
-      switch (c0) {
-      case OP_RETURN:
-        return 0;
-      case OP_MOVE:
-        if (GETARG_A(i0) >= s->nlocals) {
-          s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
-          return 0;
-        }
-        break;
-      case OP_SETIV:
-      case OP_SETCV:
-      case OP_SETCONST:
-      case OP_SETMCNST:
-      case OP_SETUPVAR:
-      case OP_SETGLOBAL:
-        s->pc--;
-        genop_peep(s, i0, NOVAL);
-        i0 = s->iseq[s->pc-1];
-        return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
-#if 0
-      case OP_SEND:
-        if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
-          s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0));
-          return;
-        }
-        break;
-#endif
-      default:
-        break;
-      }
-      break;
-    case OP_ADD:
-    case OP_SUB:
-      if (c0 == OP_LOADI) {
-        int c = GETARG_sBx(i0);
-
-        if (c1 == OP_SUB) c = -c;
-        if (c > 127 || c < -127) break;
-        if (0 <= c)
-          s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
-        else
-          s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
-        return 0;
-      }
-    case OP_STRCAT:
-      if (c0 == OP_STRING) {
-        mrb_value v = s->irep->pool[GETARG_Bx(i0)];
-
-        if (mrb_string_p(v) && RSTRING_LEN(v) == 0) {
-          s->pc--;
-          return 0;
-        }
-      }
-      if (c0 == OP_LOADNIL) {
-        if (GETARG_B(i) == GETARG_A(i0)) {
-          s->pc--;
-          return 0;
-        }
-      }
-      break;
-    case OP_JMPIF:
-    case OP_JMPNOT:
-      if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
-        s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
-        return s->pc-1;
-      }
+    case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM:
+    case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
+    case OP_GETCONST: case OP_STRING:
+    case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH:
+      if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+      s->pc = s->lastpc;
+      genop_2(s, data.insn, dst, data.b);
       break;
     default:
+      goto normal;
+    }
+  }
+}
+
+static void
+gen_return(codegen_scope *s, uint8_t op, uint16_t src)
+{
+  if (no_peephole(s)) {
+    genop_1(s, op, src);
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    if (data.insn == OP_MOVE && src == data.a) {
+      s->pc = s->lastpc;
+      genop_1(s, op, data.b);
+    }
+    else if (data.insn != OP_RETURN) {
+      genop_1(s, op, src);
+    }
+  }
+}
+
+static void
+gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
+{
+  if (no_peephole(s)) {
+  normal:
+    genop_1(s, op, dst);
+    return;
+  }
+  else {
+    struct mrb_insn_data data = mrb_last_insn(s);
+
+    switch (data.insn) {
+    case OP_LOADI__1:
+      if (op == OP_ADD) op = OP_SUB;
+      else op = OP_ADD;
+      data.b = 1;
+      goto replace;
+    case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+    case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+      data.b = data.insn - OP_LOADI_0;
+      /* fall through */
+    case OP_LOADI:
+    replace:
+      if (data.b >= 128) goto normal;
+      s->pc = s->lastpc;
+      if (op == OP_ADD) {
+        genop_2(s, OP_ADDI, dst, (uint8_t)data.b);
+      }
+      else {
+        genop_2(s, OP_SUBI, dst, (uint8_t)data.b);
+      }
       break;
-    }
-  }
-  return genop(s, i);
+    default:
+      goto normal;
+    }
+  }
+}
+
+static int
+dispatch(codegen_scope *s, uint16_t pos0)
+{
+  uint16_t newpos;
+
+  s->lastlabel = s->pc;
+  newpos = PEEK_S(s->iseq+pos0);
+  emit_S(s, pos0, s->pc);
+  return newpos;
 }
 
 static void
-scope_error(codegen_scope *s)
-{
-  exit(EXIT_FAILURE);
-}
-
-static inline void
-dispatch(codegen_scope *s, int pc)
-{
-  int diff = s->pc - pc;
-  mrb_code i = s->iseq[pc];
-  int c = GET_OPCODE(i);
-
-  s->lastlabel = s->pc;
-  switch (c) {
-  case OP_JMP:
-  case OP_JMPIF:
-  case OP_JMPNOT:
-  case OP_ONERR:
-    break;
-  default:
-#ifndef MRB_DISABLE_STDIO
-    fprintf(stderr, "bug: dispatch on non JMP op\n");
-#endif
-    scope_error(s);
-    break;
-  }
-  if (diff > MAXARG_sBx) {
-    codegen_error(s, "too distant jump address");
-  }
-  s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
-}
-
-static void
-dispatch_linked(codegen_scope *s, int pc)
-{
-  mrb_code i;
-  int pos;
-
-  if (!pc) return;
+dispatch_linked(codegen_scope *s, uint16_t pos)
+{
+  if (pos==0) return;
   for (;;) {
-    i = s->iseq[pc];
-    pos = GETARG_sBx(i);
-    dispatch(s, pc);
-    if (!pos) break;
-    pc = pos;
+    pos = dispatch(s, pos);
+    if (pos==0) break;
   }
 }
@@ -419,17 +524,7 @@
 #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
 static void
-push_(codegen_scope *s)
-{
-  if (s->sp > 511) {
-    codegen_error(s, "too complex expression");
-  }
-  s->sp++;
-  nregs_update;
-}
-
-static void
-push_n_(codegen_scope *s, size_t n)
-{
-  if (s->sp+n > 511) {
+push_n_(codegen_scope *s, int n)
+{
+  if (s->sp+n >= 0xffff) {
     codegen_error(s, "too complex expression");
   }
@@ -438,9 +533,17 @@
 }
 
-#define push() push_(s)
+static void
+pop_n_(codegen_scope *s, int n)
+{
+  if ((int)s->sp-n < 0) {
+    codegen_error(s, "stack pointer underflow");
+  }
+  s->sp-=n;
+}
+
+#define push() push_n_(s,1)
 #define push_n(n) push_n_(s,n)
-#define pop_(s) ((s)->sp--)
-#define pop() pop_(s)
-#define pop_n(n) (s->sp-=(n))
+#define pop() pop_n_(s,1)
+#define pop_n(n) pop_n_(s,n)
 #define cursp() (s->sp)
 
@@ -448,5 +551,5 @@
 new_lit(codegen_scope *s, mrb_value val)
 {
-  size_t i;
+  int i;
   mrb_value *pv;
 
@@ -457,5 +560,5 @@
       pv = &s->irep->pool[i];
 
-      if (mrb_type(*pv) != MRB_TT_STRING) continue;
+      if (!mrb_string_p(*pv)) continue;
       if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
       if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
@@ -463,11 +566,16 @@
     }
     break;
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
     for (i=0; i<s->irep->plen; i++) {
+      mrb_float f1, f2;
       pv = &s->irep->pool[i];
-      if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
-      if (mrb_float(*pv) == mrb_float(val)) return i;
-    }
-    break;
+      if (!mrb_float_p(*pv)) continue;
+      f1 = mrb_float(*pv);
+      f2 = mrb_float(val);
+      if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i;
+    }
+    break;
+#endif
   case MRB_TT_FIXNUM:
     for (i=0; i<s->irep->plen; i++) {
@@ -492,7 +600,8 @@
   switch (mrb_type(val)) {
   case MRB_TT_STRING:
-    *pv = mrb_str_pool(s->mrb, val);
-    break;
-
+    *pv = mrb_str_pool(s->mrb, RSTRING_PTR(val), RSTRING_LEN(val), RSTR_NOFREE_P(RSTRING(val)));
+    break;
+
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
 #ifdef MRB_WORD_BOXING
@@ -500,4 +609,5 @@
     break;
 #endif
+#endif
   case MRB_TT_FIXNUM:
     *pv = val;
@@ -511,50 +621,21 @@
 }
 
-/* method symbols should be fit in 9 bits */
-#define MAXMSYMLEN 512
 /* maximum symbol numbers */
-#define MAXSYMLEN 65536
+#define MAXSYMLEN 0x10000
 
 static int
-new_msym(codegen_scope *s, mrb_sym sym)
-{
-  size_t i, len;
+new_sym(codegen_scope *s, mrb_sym sym)
+{
+  int i, len;
 
   mrb_assert(s->irep);
 
   len = s->irep->slen;
-  if (len > MAXMSYMLEN) len = MAXMSYMLEN;
   for (i=0; i<len; i++) {
     if (s->irep->syms[i] == sym) return i;
-    if (s->irep->syms[i] == 0) break;
-  }
-  if (i == MAXMSYMLEN) {
-    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")");
-  }
-  s->irep->syms[i] = sym;
-  if (i == s->irep->slen) s->irep->slen++;
-  return i;
-}
-
-static int
-new_sym(codegen_scope *s, mrb_sym sym)
-{
-  size_t i;
-
-  for (i=0; i<s->irep->slen; i++) {
-    if (s->irep->syms[i] == sym) return i;
-  }
-  if (s->irep->slen == MAXSYMLEN) {
-    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")");
-  }
-
-  if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) {
-    s->scapa = MAXSYMLEN;
-    s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN);
-    for (i = s->irep->slen; i < MAXMSYMLEN; i++) {
-      static const mrb_sym mrb_sym_zero = { 0 };
-      s->irep->syms[i] = mrb_sym_zero;
-    }
-    s->irep->slen = MAXMSYMLEN;
+  }
+  if (s->irep->slen >= s->scapa) {
+    s->scapa *= 2;
+    s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa);
   }
   s->irep->syms[s->irep->slen] = sym;
@@ -574,6 +655,10 @@
 }
 
-#define sym(x) ((mrb_sym)(intptr_t)(x))
-#define lv_name(lv) sym((lv)->car)
+#define nint(x) ((int)(intptr_t)(x))
+#define nchar(x) ((char)(intptr_t)(x))
+#define nsym(x) ((mrb_sym)(intptr_t)(x))
+
+#define lv_name(lv) nsym((lv)->car)
+
 static int
 lv_idx(codegen_scope *s, mrb_sym id)
@@ -597,5 +682,4 @@
   struct loopinfo *lp;
   node *n2;
-  mrb_code c;
 
   /* generate receiver */
@@ -603,7 +687,4 @@
   /* generate loop-block */
   s = scope_new(s->mrb, s, NULL);
-  if (s == NULL) {
-    raise_error(prev, "unexpected scope");
-  }
 
   push();                       /* push for a block parameter */
@@ -611,5 +692,5 @@
   /* generate loop variable */
   n2 = tree->car;
-  genop(s, MKOP_Ax(OP_ENTER, 0x40000));
+  genop_W(s, OP_ENTER, 0x40000);
   if (n2->car && !n2->car->cdr && !n2->cdr) {
     gen_assignment(s, n2->car->car, 1, NOVAL);
@@ -625,16 +706,13 @@
   codegen(s, tree->cdr->cdr->car, VAL);
   pop();
-  if (s->pc > 0) {
-    c = s->iseq[s->pc-1];
-    if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel)
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
-  }
+  gen_return(s, OP_RETURN, cursp());
   loop_pop(s, NOVAL);
   scope_finish(s);
   s = prev;
-  genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
+  genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
+  push();pop(); /* space for a block */
   pop();
-  idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
-  genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
+  idx = new_sym(s, mrb_intern_lit(s->mrb, "each"));
+  genop_3(s, OP_SENDB, cursp(), idx, 0);
 }
 
@@ -642,10 +720,6 @@
 lambda_body(codegen_scope *s, node *tree, int blk)
 {
-  mrb_code c;
   codegen_scope *parent = s;
   s = scope_new(s->mrb, s, tree->car);
-  if (s == NULL) {
-    raise_error(parent, "unexpected scope");
-  }
 
   s->mscope = !blk;
@@ -653,45 +727,59 @@
   if (blk) {
     struct loopinfo *lp = loop_push(s, LOOP_BLOCK);
-    lp->pc1 = new_label(s);
+    lp->pc0 = new_label(s);
   }
   tree = tree->cdr;
-  if (tree->car) {
+  if (tree->car == NULL) {
+    genop_W(s, OP_ENTER, 0);
+  }
+  else {
     mrb_aspec a;
     int ma, oa, ra, pa, ka, kd, ba;
     int pos, i;
-    node *n, *opt;
-
+    node *opt;
+    node *margs, *pargs;
+    node *tail;
+
+    /* mandatory arguments */
     ma = node_len(tree->car->car);
-    n = tree->car->car;
-    while (n) {
-      n = n->cdr;
-    }
+    margs = tree->car->car;
+    tail = tree->car->cdr->cdr->cdr->cdr;
+
+    /* optional arguments */
     oa = node_len(tree->car->cdr->car);
+    /* rest argument? */
     ra = tree->car->cdr->cdr->car ? 1 : 0;
+    /* mandatory arugments after rest argument */
     pa = node_len(tree->car->cdr->cdr->cdr->car);
-    ka = kd = 0;
-    ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
+    pargs = tree->car->cdr->cdr->cdr->car;
+    /* keyword arguments */
+    ka = tail? node_len(tail->cdr->car) : 0;
+    /* keyword dictionary? */
+    kd = tail && tail->cdr->cdr->car? 1 : 0;
+    /* block argument? */
+    ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0;
 
     if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
       codegen_error(s, "too many formal arguments");
     }
-    a = ((mrb_aspec)(ma & 0x1f) << 18)
-      | ((mrb_aspec)(oa & 0x1f) << 13)
-      | ((ra & 1) << 12)
-      | ((pa & 0x1f) << 7)
-      | ((ka & 0x1f) << 2)
-      | ((kd & 1)<< 1)
-      | (ba & 1);
-    s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */
-      | ((ra & 1) << 5)
-      | (pa & 0x1f);
-    genop(s, MKOP_Ax(OP_ENTER, a));
+    a = MRB_ARGS_REQ(ma)
+      | MRB_ARGS_OPT(oa)
+      | (ra? MRB_ARGS_REST() : 0)
+      | MRB_ARGS_POST(pa)
+      | MRB_ARGS_KEY(ka, kd)
+      | (ba? MRB_ARGS_BLOCK() : 0);
+    s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */
+      | ((ra & 0x1) << 6)
+      | ((pa & 0x1f) << 1)
+      | ((ka | kd) != 0 ? 0x01 : 0x00);
+    genop_W(s, OP_ENTER, a);
+    /* generate jump table for optional arguments initializer */
     pos = new_label(s);
     for (i=0; i<oa; i++) {
       new_label(s);
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      genjmp(s, OP_JMP, 0);
     }
     if (oa > 0) {
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      genjmp(s, OP_JMP, 0);
     }
     opt = tree->car->cdr->car;
@@ -700,29 +788,87 @@
       int idx;
 
-      dispatch(s, pos+i);
+      dispatch(s, pos+i*3+1);
       codegen(s, opt->car->cdr, VAL);
-      idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car);
       pop();
-      genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL);
+      idx = lv_idx(s, nsym(opt->car->car));
+      gen_move(s, idx, cursp(), 0);
       i++;
       opt = opt->cdr;
     }
     if (oa > 0) {
-      dispatch(s, pos+i);
-    }
-  }
+      dispatch(s, pos+i*3+1);
+    }
+
+    /* keyword arguments */
+    if (tail) {
+      node *kwds = tail->cdr->car;
+      int kwrest = 0;
+
+      if (tail->cdr->cdr->car) {
+        kwrest = 1;
+      }
+      mrb_assert(nint(tail->car) == NODE_ARGS_TAIL);
+      mrb_assert(node_len(tail) == 4);
+
+      while (kwds) {
+        int jmpif_key_p, jmp_def_set = -1;
+        node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car;
+        mrb_sym kwd_sym = nsym(kwd->cdr->car);
+
+        mrb_assert(nint(kwd->car) == NODE_KW_ARG);
+
+        if (def_arg) {
+          genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+          jmpif_key_p = genjmp2(s, OP_JMPIF, lv_idx(s, kwd_sym), 0, 0);
+          codegen(s, def_arg, VAL);
+          pop();
+          gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
+          jmp_def_set = genjmp(s, OP_JMP, 0);
+          dispatch(s, jmpif_key_p);
+        }
+        genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+        if (jmp_def_set != -1) {
+          dispatch(s, jmp_def_set);
+        }
+        i++;
+
+        kwds = kwds->cdr;
+      }
+      if (tail->cdr->car && !kwrest) {
+        genop_0(s, OP_KEYEND);
+      }
+    }
+
+    /* argument destructuring */
+    if (margs) {
+      node *n = margs;
+
+      pos = 1;
+      while (n) {
+        if (nint(n->car->car) == NODE_MASGN) {
+          gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+        }
+        pos++;
+        n = n->cdr;
+      }
+    }
+    if (pargs) {
+      node *n = margs;
+
+      pos = ma+oa+ra+1;
+      while (n) {
+        if (nint(n->car->car) == NODE_MASGN) {
+          gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+        }
+        pos++;
+        n = n->cdr;
+      }
+    }
+  }
+
   codegen(s, tree->cdr->car, VAL);
   pop();
   if (s->pc > 0) {
-    c = s->iseq[s->pc-1];
-    if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) {
-      if (s->nregs == 0) {
-        genop(s, MKOP_A(OP_LOADNIL, 0));
-        genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-      }
-      else {
-        genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
-      }
-    }
+    gen_return(s, OP_RETURN, cursp());
   }
   if (blk) {
@@ -737,23 +883,9 @@
 {
   codegen_scope *scope = scope_new(s->mrb, s, tree->car);
-  if (scope == NULL) {
-    raise_error(s, "unexpected scope");
-  }
 
   codegen(scope, tree->cdr, VAL);
+  gen_return(scope, OP_RETURN, scope->sp-1);
   if (!s->iseq) {
-    genop(scope, MKOP_A(OP_STOP, 0));
-  }
-  else if (!val) {
-    genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-  }
-  else {
-    if (scope->nregs == 0) {
-      genop(scope, MKOP_A(OP_LOADNIL, 0));
-      genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
-    }
-    else {
-      genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL);
-    }
+    genop_0(scope, OP_STOP);
   }
   scope_finish(scope);
@@ -769,5 +901,5 @@
 {
   while (t) {
-    if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE;
+    if (nint(t->car->car) == NODE_SPLAT) return FALSE;
     t = t->cdr;
   }
@@ -782,5 +914,5 @@
   char *name2;
 
-  name = mrb_sym2name_len(s->mrb, a, &len);
+  name = mrb_sym_name_len(s->mrb, a, &len);
   name2 = (char *)codegen_palloc(s,
                                  (size_t)len
@@ -805,10 +937,10 @@
 
   while (t) {
-    is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
+    is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */
     if (
       n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
       || is_splat) {
       if (val) {
-        if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
+        if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) {
           codegen(s, t->car->cdr, VAL);
           pop();
@@ -816,13 +948,18 @@
         else {
           pop_n(n);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+          if (n == 0 && is_splat) {
+            genop_1(s, OP_LOADNIL, cursp());
+          }
+          else {
+            genop_2(s, OP_ARRAY, cursp(), n);
+          }
           push();
           codegen(s, t->car, VAL);
           pop(); pop();
           if (is_splat) {
-            genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+            genop_1(s, OP_ARYCAT, cursp());
           }
           else {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
         }
@@ -832,9 +969,9 @@
           codegen(s, t->car, VAL);
           pop(); pop();
-          if ((intptr_t)t->car->car == NODE_SPLAT) {
-            genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+          if (nint(t->car->car) == NODE_SPLAT) {
+            genop_1(s, OP_ARYCAT, cursp());
           }
           else {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
           t = t->cdr;
@@ -860,6 +997,6 @@
 gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
 {
-  mrb_sym sym = name ? name : sym(tree->cdr->car);
-  int idx, skip = 0;
+  mrb_sym sym = name ? name : nsym(tree->cdr->car);
+  int skip = 0;
   int n = 0, noop = 0, sendv = 0, blk = 0;
 
@@ -867,14 +1004,7 @@
   if (safe) {
     int recv = cursp()-1;
-    genop(s, MKOP_A(OP_LOADNIL, cursp()));
-    push();
-    genop(s, MKOP_AB(OP_MOVE, cursp(), recv));
-    push(); pop();              /* space for a block */
-    pop();
-    idx = new_msym(s, mrb_intern_lit(s->mrb, "=="));
-    genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1));
-    skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
-  }
-  idx = new_msym(s, sym);
+    gen_move(s, cursp(), recv, 1);
+    skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+  }
   tree = tree->cdr->cdr->car;
   if (tree) {
@@ -885,12 +1015,13 @@
     }
   }
-  if (sp) {
+  if (sp) {                     /* last argument pushed (attr=) */
     if (sendv) {
+      gen_move(s, cursp(), sp, 0);
       pop();
-      genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp));
+      genop_1(s, OP_ARYPUSH, cursp());
       push();
     }
     else {
-      genop(s, MKOP_AB(OP_MOVE, cursp(), sp));
+      gen_move(s, cursp(), sp, 0);
       push();
       n++;
@@ -901,7 +1032,5 @@
     codegen(s, tree->cdr, VAL);
     pop();
-  }
-  else {
-    blk = cursp();
+    blk = 1;
   }
   push();pop();
@@ -909,40 +1038,41 @@
   {
     mrb_int symlen;
-    const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
+    const char *symname = mrb_sym_name_len(s->mrb, sym, &symlen);
 
     if (!noop && symlen == 1 && symname[0] == '+' && n == 1)  {
-      genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val);
+      gen_addsub(s, OP_ADD, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '-' && n == 1)  {
-      genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val);
+      gen_addsub(s, OP_SUB, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '*' && n == 1)  {
-      genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n));
+      genop_1(s, OP_MUL, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '/' && n == 1)  {
-      genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n));
+      genop_1(s, OP_DIV, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '<' && n == 1)  {
-      genop(s, MKOP_ABC(OP_LT, cursp(), idx, n));
+      genop_1(s, OP_LT, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_LE, cursp(), idx, n));
+      genop_1(s, OP_LE, cursp());
     }
     else if (!noop && symlen == 1 && symname[0] == '>' && n == 1)  {
-      genop(s, MKOP_ABC(OP_GT, cursp(), idx, n));
+      genop_1(s, OP_GT, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_GE, cursp(), idx, n));
+      genop_1(s, OP_GE, cursp());
     }
     else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1)  {
-      genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
+      genop_1(s, OP_EQ, cursp());
     }
     else {
-      if (sendv) n = CALL_MAXARGS;
-      if (blk > 0) {                   /* no block */
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n));
+      int idx = new_sym(s, sym);
+
+      if (sendv) {
+        genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx);
       }
       else {
-        genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n));
+        genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n);
       }
     }
@@ -960,17 +1090,19 @@
 {
   int idx;
-  int type = (intptr_t)tree->car;
+  int type = nint(tree->car);
 
   tree = tree->cdr;
   switch (type) {
   case NODE_GVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
-    break;
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETGV, sp, idx);
+    break;
+  case NODE_ARG:
   case NODE_LVAR:
-    idx = lv_idx(s, sym(tree));
+    idx = lv_idx(s, nsym(tree));
     if (idx > 0) {
       if (idx != sp) {
-        genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val);
+        gen_move(s, idx, sp, val);
+        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       break;
@@ -981,7 +1113,7 @@
 
       while (up) {
-        idx = lv_idx(up, sym(tree));
+        idx = lv_idx(up, nsym(tree));
         if (idx > 0) {
-          genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val);
+          genop_3(s, OP_SETUPVAR, sp, idx, lv);
           break;
         }
@@ -991,23 +1123,27 @@
     }
     break;
+  case NODE_NVAR:
+    idx = nint(tree);
+    codegen_error(s, "Can't assign to numbered parameter");
+    break;
   case NODE_IVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETIV, sp, idx);
     break;
   case NODE_CVAR:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETCV, sp, idx);
     break;
   case NODE_CONST:
-    idx = new_sym(s, sym(tree));
-    genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val);
+    idx = new_sym(s, nsym(tree));
+    genop_2(s, OP_SETCONST, sp, idx);
     break;
   case NODE_COLON2:
-    idx = new_sym(s, sym(tree->cdr));
-    genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL);
+    gen_move(s, cursp(), sp, 0);
     push();
     codegen(s, tree->car, VAL);
     pop_n(2);
-    genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val);
+    idx = new_sym(s, nsym(tree->cdr));
+    genop_2(s, OP_SETMCNST, sp, idx);
     break;
 
@@ -1015,9 +1151,9 @@
   case NODE_SCALL:
     push();
-    gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL,
+    gen_call(s, tree, attrsym(s, nsym(tree->cdr->car)), sp, NOVAL,
              type == NODE_SCALL);
     pop();
     if (val) {
-      genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val);
+      gen_move(s, cursp(), sp, 0);
     }
     break;
@@ -1050,6 +1186,10 @@
     n = 0;
     while (t) {
-      genop(s, MKOP_ABC(OP_AREF, cursp(), rhs, n));
-      gen_assignment(s, t->car, cursp(), NOVAL);
+      int sp = cursp();
+
+      genop_3(s, OP_AREF, sp, rhs, n);
+      push();
+      gen_assignment(s, t->car, sp, NOVAL);
+      pop();
       n++;
       t = t->cdr;
@@ -1065,15 +1205,10 @@
       }
     }
-    if (val) {
-      genop(s, MKOP_AB(OP_MOVE, cursp(), rhs));
-    }
-    else {
-      pop();
-    }
-    push_n(post);
-    pop_n(post);
-    genop(s, MKOP_ABC(OP_APOST, cursp(), n, post));
+    gen_move(s, cursp(), rhs, val);
+    push_n(post+1);
+    pop_n(post+1);
+    genop_3(s, OP_APOST, cursp(), n, post);
     n = 1;
-    if (t->car) {               /* rest */
+    if (t->car && t->car != (node*)-1) { /* rest */
       gen_assignment(s, t->car, cursp(), NOVAL);
     }
@@ -1086,6 +1221,6 @@
       }
     }
-    if (!val) {
-      push();
+    if (val) {
+      gen_move(s, cursp(), rhs, 0);
     }
   }
@@ -1093,10 +1228,11 @@
 
 static void
-gen_send_intern(codegen_scope *s)
+gen_intern(codegen_scope *s)
 {
   pop();
-  genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
+  genop_1(s, OP_INTERN, cursp());
   push();
 }
+
 static void
 gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
@@ -1106,7 +1242,7 @@
 
     while (tree) {
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_STR:
-        if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0))
+        if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0))
           break;
         /* fall through */
@@ -1121,13 +1257,13 @@
           ++i;
           if (sym)
-            gen_send_intern(s);
+            gen_intern(s);
         }
         break;
       }
-      if (j >= 2) {
+      while (j >= 2) {
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
-        j = 1;
+        j--;
       }
       tree = tree->cdr;
@@ -1136,13 +1272,13 @@
       ++i;
       if (sym)
-        gen_send_intern(s);
+        gen_intern(s);
     }
     pop_n(i);
-    genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i));
+    genop_2(s, OP_ARRAY, cursp(), i);
     push();
   }
   else {
     while (tree) {
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_BEGIN: case NODE_BLOCK:
         codegen(s, tree->car, NOVAL);
@@ -1158,7 +1294,8 @@
   int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg));
 
-  genop(s, MKOP_ABx(OP_ERR, 1, idx));
-}
-
+  genop_1(s, OP_ERR, idx);
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 static double
 readint_float(codegen_scope *s, const char *p, int base)
@@ -1186,4 +1323,5 @@
   return f;
 }
+#endif
 
 static mrb_int
@@ -1233,10 +1371,8 @@
 gen_retval(codegen_scope *s, node *tree)
 {
-  if ((intptr_t)tree->car == NODE_SPLAT) {
-    genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0));
-    push();
+  if (nint(tree->car) == NODE_SPLAT) {
     codegen(s, tree, VAL);
-    pop(); pop();
-    genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+    pop();
+    genop_1(s, OP_ARYDUP, cursp());
   }
   else {
@@ -1254,5 +1390,5 @@
   if (!tree) {
     if (val) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -1265,12 +1401,15 @@
   }
   if (s->irep && s->filename_index != tree->filename_index) {
-    s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
-    mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
+    mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
+
+    mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+                               filename, s->lines, s->debug_start_pos, s->pc);
     s->debug_start_pos = s->pc;
     s->filename_index = tree->filename_index;
-    s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
-  }
-
-  nt = (intptr_t)tree->car;
+    s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index);
+  }
+
+  nt = nint(tree->car);
   s->lineno = tree->lineno;
   tree = tree->cdr;
@@ -1278,5 +1417,5 @@
   case NODE_BEGIN:
     if (val && !tree) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -1289,16 +1428,16 @@
   case NODE_RESCUE:
     {
-      int onerr, noexc, exend, pos1, pos2, tmp;
+      int noexc, exend, pos1, pos2, tmp;
       struct loopinfo *lp;
 
       if (tree->car == NULL) goto exit;
-      onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
       lp = loop_push(s, LOOP_BEGIN);
-      lp->pc1 = onerr;
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_ONERR, 0);
       codegen(s, tree->car, VAL);
       pop();
       lp->type = LOOP_RESCUE;
-      noexc = genop(s, MKOP_Bx(OP_JMP, 0));
-      dispatch(s, onerr);
+      noexc = genjmp(s, OP_JMP, 0);
+      dispatch(s, lp->pc1);
       tree = tree->cdr;
       exend = 0;
@@ -1308,5 +1447,5 @@
         int exc = cursp();
 
-        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
+        genop_1(s, OP_EXCEPT, exc);
         push();
         while (n2) {
@@ -1317,9 +1456,10 @@
           pos2 = 0;
           do {
-            if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+            if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
               codegen(s, n4->car, VAL);
-              genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
+              gen_move(s, cursp(), exc, 0);
+              push_n(2); pop_n(2); /* space for one arg and a block */
               pop();
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
             }
             else {
@@ -1328,11 +1468,11 @@
               }
               else {
-                genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
+                genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError")));
                 push();
               }
               pop();
-              genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1));
+              genop_2(s, OP_RESCUE, exc, cursp());
             }
-            tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+            tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
             pos2 = tmp;
             if (n4) {
@@ -1340,5 +1480,5 @@
             }
           } while (n4);
-          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genjmp(s, OP_JMP, 0);
           dispatch_linked(s, pos2);
 
@@ -1351,5 +1491,5 @@
             if (val) pop();
           }
-          tmp = genop(s, MKOP_sBx(OP_JMP, exend));
+          tmp = genjmp(s, OP_JMP, exend);
           exend = tmp;
           n2 = n2->cdr;
@@ -1358,5 +1498,5 @@
         if (pos1) {
           dispatch(s, pos1);
-          genop(s, MKOP_A(OP_RAISE, exc));
+          genop_1(s, OP_RAISE, exc);
         }
       }
@@ -1364,5 +1504,5 @@
       tree = tree->cdr;
       dispatch(s, noexc);
-      genop(s, MKOP_A(OP_POPERR, 1));
+      genop_1(s, OP_POPERR, 1);
       if (tree->car) {
         codegen(s, tree->car, val);
@@ -1378,16 +1518,14 @@
   case NODE_ENSURE:
     if (!tree->cdr || !tree->cdr->cdr ||
-        ((intptr_t)tree->cdr->cdr->car == NODE_BEGIN &&
+        (nint(tree->cdr->cdr->car) == NODE_BEGIN &&
          tree->cdr->cdr->cdr)) {
       int idx;
-      int epush = s->pc;
-
-      genop(s, MKOP_Bx(OP_EPUSH, 0));
+
       s->ensure_level++;
+      idx = scope_body(s, tree->cdr, NOVAL);
+      genop_1(s, OP_EPUSH, idx);
       codegen(s, tree->car, val);
-      idx = scope_body(s, tree->cdr, NOVAL);
-      s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx);
       s->ensure_level--;
-      genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
+      genop_1(s, OP_EPOP, 1);
     }
     else {                      /* empty ensure ignored */
@@ -1400,5 +1538,5 @@
       int idx = lambda_body(s, tree, 1);
 
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA));
+      genop_2(s, OP_LAMBDA, cursp(), idx);
       push();
     }
@@ -1409,5 +1547,5 @@
       int idx = lambda_body(s, tree, 1);
 
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK));
+      genop_2(s, OP_BLOCK, cursp(), idx);
       push();
     }
@@ -1416,12 +1554,12 @@
   case NODE_IF:
     {
-      int pos1, pos2;
-      node *e = tree->cdr->cdr->car;
+      int pos1, pos2, nil_p = FALSE;
+      node *elsepart = tree->cdr->cdr->car;
 
       if (!tree->car) {
-        codegen(s, e, val);
+        codegen(s, elsepart, val);
         goto exit;
       }
-      switch ((intptr_t)tree->car->car) {
+      switch (nint(tree->car->car)) {
       case NODE_TRUE:
       case NODE_INT:
@@ -1431,30 +1569,57 @@
       case NODE_FALSE:
       case NODE_NIL:
-        codegen(s, e, val);
+        codegen(s, elsepart, val);
         goto exit;
-      }
-      codegen(s, tree->car, VAL);
+      case NODE_CALL:
+        {
+          node *n = tree->car->cdr;
+          mrb_sym mid = nsym(n->cdr->car);
+          mrb_sym mnil = mrb_intern_lit(s->mrb, "nil?");
+          if (mid == mnil && n->cdr->cdr->car == NULL) {
+            nil_p = TRUE;
+            codegen(s, n->car, VAL);
+          }
+        }
+        break;
+      }
+      if (!nil_p) {
+        codegen(s, tree->car, VAL);
+      }
       pop();
-      pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
-
-      codegen(s, tree->cdr->car, val);
-      if (e) {
+      if (val || tree->cdr->car) {
+        if (nil_p) {
+          pos2 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          pos1 = genjmp(s, OP_JMP, 0);
+          dispatch(s, pos2);
+        }
+        else {
+          pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
+        }
+        codegen(s, tree->cdr->car, val);
         if (val) pop();
-        pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
-        dispatch(s, pos1);
-        codegen(s, e, val);
-        dispatch(s, pos2);
-      }
-      else {
-        if (val) {
-          pop();
-          pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+        if (elsepart || val) {
+          pos2 = genjmp(s, OP_JMP, 0);
           dispatch(s, pos1);
-          genop(s, MKOP_A(OP_LOADNIL, cursp()));
+          codegen(s, elsepart, val);
           dispatch(s, pos2);
-          push();
         }
         else {
           dispatch(s, pos1);
+        }
+      }
+      else {                    /* empty then-part */
+        if (elsepart) {
+          if (nil_p) {
+            pos1 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          }
+          else {
+            pos1 = genjmp2(s, OP_JMPIF, cursp(), 0, val);
+          }
+          codegen(s, elsepart, val);
+          dispatch(s, pos1);
+        }
+        else if (val && !nil_p) {
+          genop_1(s, OP_LOADNIL, cursp());
+          push();
         }
       }
@@ -1468,5 +1633,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+      pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
@@ -1480,5 +1645,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+      pos = genjmp2(s, OP_JMPIF, cursp(), 0, val);
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
@@ -1490,5 +1655,6 @@
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_JMP, 0);
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
@@ -1496,5 +1662,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc));
+      genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL);
 
       loop_pop(s, val);
@@ -1506,5 +1672,6 @@
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc0 = new_label(s);
+      lp->pc1 = genjmp(s, OP_JMP, 0);
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
@@ -1512,5 +1679,5 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc));
+      genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL);
 
       loop_pop(s, val);
@@ -1541,11 +1708,11 @@
           codegen(s, n->car, VAL);
           if (head) {
-            genop(s, MKOP_AB(OP_MOVE, cursp(), head));
-            pop();
-            if ((intptr_t)n->car->car == NODE_SPLAT) {
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+            gen_move(s, cursp(), head, 0);
+            push(); push(); pop(); pop(); pop();
+            if (nint(n->car->car) == NODE_SPLAT) {
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
             }
             else {
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+              genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1);
             }
           }
@@ -1553,15 +1720,15 @@
             pop();
           }
-          tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+          tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL);
           pos2 = tmp;
           n = n->cdr;
         }
         if (tree->car->car) {
-          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genjmp(s, OP_JMP, 0);
           dispatch_linked(s, pos2);
         }
         codegen(s, tree->car->cdr, val);
         if (val) pop();
-        tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
+        tmp = genjmp(s, OP_JMP, pos3);
         pos3 = tmp;
         if (pos1) dispatch(s, pos1);
@@ -1570,9 +1737,9 @@
       if (val) {
         int pos = cursp();
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         if (pos3) dispatch_linked(s, pos3);
         if (head) pop();
         if (cursp() != pos) {
-          genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+          gen_move(s, cursp(), pos, 0);
         }
         push();
@@ -1606,5 +1773,5 @@
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE));
+      genop_1(s, OP_RANGE_INC, cursp());
       push();
     }
@@ -1616,5 +1783,5 @@
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE));
+      genop_1(s, OP_RANGE_EXC, cursp());
       push();
     }
@@ -1623,9 +1790,9 @@
   case NODE_COLON2:
     {
-      int sym = new_sym(s, sym(tree->cdr));
+      int sym = new_sym(s, nsym(tree->cdr));
 
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       if (val) push();
     }
@@ -1634,8 +1801,8 @@
   case NODE_COLON3:
     {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      int sym = new_sym(s, nsym(tree));
+
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       if (val) push();
     }
@@ -1650,5 +1817,5 @@
         if (val) {
           pop_n(n);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+          genop_2(s, OP_ARRAY, cursp(), n);
           push();
         }
@@ -1661,4 +1828,5 @@
 
   case NODE_HASH:
+  case NODE_KW_HASH:
     {
       int len = 0;
@@ -1666,14 +1834,39 @@
 
       while (tree) {
-        codegen(s, tree->car->car, val);
-        codegen(s, tree->car->cdr, val);
-        len++;
+        if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
+          if (len > 0) {
+            pop_n(len*2);
+            if (!update) {
+              genop_2(s, OP_HASH, cursp(), len);
+            }
+            else {
+              pop();
+              genop_2(s, OP_HASHADD, cursp(), len);
+            }
+            push();
+          }
+          codegen(s, tree->car->cdr, VAL);
+          if (len > 0 || update) {
+            pop(); pop();
+            genop_1(s, OP_HASHCAT, cursp());
+            push();
+          }
+          update = TRUE;
+          len = 0;
+        }
+        else {
+          codegen(s, tree->car->car, val);
+          codegen(s, tree->car->cdr, val);
+          len++;
+        }
         tree = tree->cdr;
-        if (val && len == 126) {
+        if (val && len == 255) {
           pop_n(len*2);
-          genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
-          if (update) {
+          if (!update) {
+            genop_2(s, OP_HASH, cursp(), len);
+          }
+          else {
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+            genop_2(s, OP_HASHADD, cursp(), len);
           }
           push();
@@ -1684,8 +1877,12 @@
       if (val) {
         pop_n(len*2);
-        genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
-        if (update) {
+        if (!update) {
+          genop_2(s, OP_HASH, cursp(), len);
+        }
+        else {
           pop();
-          genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+          if (len > 0) {
+            genop_2(s, OP_HASHADD, cursp(), len);
+          }
         }
         push();
@@ -1710,5 +1907,5 @@
       int rhs = cursp();
 
-      if ((intptr_t)t->car == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
+      if (nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
         /* fixed rhs */
         t = t->cdr;
@@ -1728,5 +1925,5 @@
             }
             else {
-              genop(s, MKOP_A(OP_LOADNIL, rhs+n));
+              genop_1(s, OP_LOADNIL, rhs+n);
               gen_assignment(s, t->car, rhs+n, NOVAL);
             }
@@ -1752,5 +1949,5 @@
               rn = len - post - n;
             }
-            genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn));
+            genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn);
             gen_assignment(s, t->car, cursp(), NOVAL);
             n += rn;
@@ -1767,5 +1964,5 @@
         pop_n(len);
         if (val) {
-          genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len));
+          genop_2(s, OP_ARRAY, rhs, len);
           push();
         }
@@ -1784,16 +1981,16 @@
   case NODE_OP_ASGN:
     {
-      mrb_sym sym = sym(tree->cdr->car);
+      mrb_sym sym = nsym(tree->cdr->car);
       mrb_int len;
-      const char *name = mrb_sym2name_len(s->mrb, sym, &len);
+      const char *name = mrb_sym_name_len(s->mrb, sym, &len);
       int idx, callargs = -1, vsp = -1;
 
       if ((len == 2 && name[0] == '|' && name[1] == '|') &&
-          ((intptr_t)tree->car->car == NODE_CONST ||
-           (intptr_t)tree->car->car == NODE_CVAR)) {
+          (nint(tree->car->car) == NODE_CONST ||
+           nint(tree->car->car) == NODE_CVAR)) {
         int onerr, noexc, exc;
         struct loopinfo *lp;
 
-        onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
+        onerr = genjmp(s, OP_ONERR, 0);
         lp = loop_push(s, LOOP_BEGIN);
         lp->pc1 = onerr;
@@ -1801,14 +1998,16 @@
         codegen(s, tree->car, VAL);
         lp->type = LOOP_RESCUE;
-        genop(s, MKOP_A(OP_POPERR, 1));
-        noexc = genop(s, MKOP_Bx(OP_JMP, 0));
+        genop_1(s, OP_POPERR, 1);
+        noexc = genjmp(s, OP_JMP, 0);
         dispatch(s, onerr);
-        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
-        genop(s, MKOP_A(OP_LOADF, exc));
+        genop_1(s, OP_EXCEPT, exc);
+        genop_1(s, OP_LOADF, exc);
         dispatch(s, noexc);
         loop_pop(s, NOVAL);
       }
-      else if ((intptr_t)tree->car->car == NODE_CALL) {
+      else if (nint(tree->car->car) == NODE_CALL) {
         node *n = tree->car->cdr;
+        int base, i, nargs = 0;
+        callargs = 0;
 
         if (val) {
@@ -1817,35 +2016,24 @@
         }
         codegen(s, n->car, VAL);   /* receiver */
-        idx = new_msym(s, sym(n->cdr->car));
+        idx = new_sym(s, nsym(n->cdr->car));
+        base = cursp()-1;
         if (n->cdr->cdr->car) {
-          int base = cursp()-1;
-          int nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
-
-          /* copy receiver and arguments */
+          nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
           if (nargs >= 0) {
-            int i;
-
-            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
-            for (i=0; i<nargs; i++) {
-              genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
-            }
-            push_n(nargs+1);
-            pop_n(nargs+1);
             callargs = nargs;
           }
-          else {
-            /* varargs */
+          else { /* varargs */
             push();
-            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
-            genop(s, MKOP_AB(OP_MOVE, cursp()+1, base+1));
+            nargs = 1;
             callargs = CALL_MAXARGS;
           }
-          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
-        }
-        else {
-          genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1));
-          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
-          callargs = 0;
-        }
+        }
+        /* copy receiver and arguments */
+        gen_move(s, cursp(), base, 1);
+        for (i=0; i<nargs; i++) {
+          gen_move(s, cursp()+i+1, base+i+1, 1);
+        }
+        push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
+        genop_3(s, OP_SEND, cursp(), idx, callargs);
         push();
       }
@@ -1861,31 +2049,28 @@
         if (val) {
           if (vsp >= 0) {
-            genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
-          }
-          pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
+            gen_move(s, vsp, cursp(), 1);
+          }
+          pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
         }
         else {
-          pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL);
+          pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
         }
         codegen(s, tree->cdr->cdr->car, VAL);
         pop();
         if (val && vsp >= 0) {
-          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
-        }
-        if ((intptr_t)tree->car->car == NODE_CALL) {
-          mrb_sym m = sym(tree->car->cdr->cdr->car);
-          mrb_sym m2 = attrsym(s, m);
-
-          idx = new_msym(s, m2);
-          pop();
+          gen_move(s, vsp, cursp(), 1);
+        }
+        if (nint(tree->car->car) == NODE_CALL) {
           if (callargs == CALL_MAXARGS) {
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+            genop_1(s, OP_ARYPUSH, cursp());
           }
           else {
             pop_n(callargs);
-            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs+1));
-          }
+            callargs++;
+          }
+          pop();
+          idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
+          genop_3(s, OP_SEND, cursp(), idx, callargs);
         }
         else {
@@ -1899,31 +2084,31 @@
       pop(); pop();
 
-      idx = new_msym(s, sym);
       if (len == 1 && name[0] == '+')  {
-        genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val);
+        gen_addsub(s, OP_ADD, cursp());
       }
       else if (len == 1 && name[0] == '-')  {
-        genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val);
+        gen_addsub(s, OP_SUB, cursp());
       }
       else if (len == 1 && name[0] == '*')  {
-        genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1));
+        genop_1(s, OP_MUL, cursp());
       }
       else if (len == 1 && name[0] == '/')  {
-        genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1));
+        genop_1(s, OP_DIV, cursp());
       }
       else if (len == 1 && name[0] == '<')  {
-        genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1));
+        genop_1(s, OP_LT, cursp());
       }
       else if (len == 2 && name[0] == '<' && name[1] == '=')  {
-        genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1));
+        genop_1(s, OP_LE, cursp());
       }
       else if (len == 1 && name[0] == '>')  {
-        genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1));
+        genop_1(s, OP_GT, cursp());
       }
       else if (len == 2 && name[0] == '>' && name[1] == '=')  {
-        genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1));
+        genop_1(s, OP_GE, cursp());
       }
       else {
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1));
+        idx = new_sym(s, sym);
+        genop_3(s, OP_SEND, cursp(), idx, 1);
       }
       if (callargs < 0) {
@@ -1932,9 +2117,9 @@
       else {
         if (val && vsp >= 0) {
-          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+          gen_move(s, vsp, cursp(), 0);
         }
         if (callargs == CALL_MAXARGS) {
           pop();
-          genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+          genop_1(s, OP_ARYPUSH, cursp());
         }
         else {
@@ -1943,6 +2128,6 @@
         }
         pop();
-        idx = new_msym(s, attrsym(s,sym(tree->car->cdr->cdr->car)));
-        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+        idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
+        genop_3(s, OP_SEND, cursp(), idx, callargs);
       }
     }
@@ -1961,5 +2146,5 @@
         if (!s2) break;
       }
-      genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf)));
+      genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf));
       push(); push();         /* ARGARY pushes two values */
       pop(); pop();
@@ -1979,10 +2164,10 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push(); pop();
       }
       pop_n(n+1);
       if (sendv) n = CALL_MAXARGS;
-      genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n));
+      genop_2(s, OP_SUPER, cursp(), n);
       if (val) push();
     }
@@ -2001,5 +2186,5 @@
       }
       if (s2) ainfo = s2->ainfo;
-      genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)));
+      genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
       push(); push(); pop();    /* ARGARY pushes two values */
       if (tree && tree->cdr) {
@@ -2008,5 +2193,5 @@
       }
       pop(); pop();
-      genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS));
+      genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS);
       if (val) push();
     }
@@ -2018,11 +2203,11 @@
     }
     else {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
     }
     if (s->loop) {
-      genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN));
+      gen_return(s, OP_RETURN_BLK, cursp());
     }
     else {
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+      gen_return(s, OP_RETURN, cursp());
     }
     if (val) push();
@@ -2049,8 +2234,9 @@
         }
       }
+      push();pop(); /* space for a block */
       pop_n(n+1);
-      genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
+      genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf));
       if (sendv) n = CALL_MAXARGS;
-      genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
+      genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n);
       if (val) push();
     }
@@ -2068,8 +2254,8 @@
     else if (s->loop->type == LOOP_NORMAL) {
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
       }
       codegen(s, tree, NOVAL);
-      genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc));
+      genjmp(s, OP_JMP, s->loop->pc0);
     }
     else {
@@ -2079,7 +2265,7 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      }
-      genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      gen_return(s, OP_RETURN, cursp());
     }
     if (val) push();
@@ -2092,7 +2278,7 @@
     else {
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
-      }
-      genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
+      }
+      genjmp(s, OP_JMP, s->loop->pc2);
     }
     if (val) push();
@@ -2121,12 +2307,10 @@
         else {
           if (n > 0) {
-            while (n--) {
-              genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
-            }
+            genop_1(s, OP_POPERR, n);
           }
           if (s->ensure_level > lp->ensure_level) {
-            genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL);
-          }
-          genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
+            genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level);
+          }
+          genjmp(s, OP_JMP, lp->pc0);
         }
       }
@@ -2137,8 +2321,9 @@
   case NODE_LVAR:
     if (val) {
-      int idx = lv_idx(s, sym(tree));
+      int idx = lv_idx(s, nsym(tree));
 
       if (idx > 0) {
-        genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
+        gen_move(s, cursp(), idx, val);
+        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       else {
@@ -2147,7 +2332,7 @@
 
         while (up) {
-          idx = lv_idx(up, sym(tree));
+          idx = lv_idx(up, nsym(tree));
           if (idx > 0) {
-            genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv));
+            genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
             break;
           }
@@ -2160,28 +2345,39 @@
     break;
 
+  case NODE_NVAR:
+    if (val) {
+      int idx = nint(tree);
+
+      gen_move(s, cursp(), idx, val);
+      if (val && on_eval(s)) genop_0(s, OP_NOP);
+
+      push();
+    }
+    break;
+
   case NODE_GVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETGV, cursp(), sym);
+      if (val) push();
     }
     break;
 
   case NODE_IVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETIV, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETIV, cursp(), sym);
+      if (val) push();
     }
     break;
 
   case NODE_CVAR:
-    if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETCV, cursp(), sym));
-      push();
+    {
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETCV, cursp(), sym);
+      if (val) push();
     }
     break;
@@ -2189,27 +2385,17 @@
   case NODE_CONST:
     {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym));
-      if (val) {
-        push();
-      }
-    }
-    break;
-
-  case NODE_DEFINED:
-    codegen(s, tree, VAL);
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_GETCONST, cursp(), sym);
+      if (val) push();
+    }
     break;
 
   case NODE_BACK_REF:
     if (val) {
-      char buf[3];
-      int sym;
-
-      buf[0] = '$';
-      buf[1] = (char)(intptr_t)tree;
-      buf[2] = 0;
-      sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+      char buf[] = {'$', nchar(tree)};
+      int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf)));
+
+      genop_2(s, OP_GETGV, cursp(), sym);
       push();
     }
@@ -2222,7 +2408,7 @@
       int sym;
 
-      str = mrb_format(mrb, "$%S", mrb_fixnum_value((mrb_int)(intptr_t)tree));
+      str = mrb_format(mrb, "$%d", nint(tree));
       sym = new_sym(s, mrb_intern_str(mrb, str));
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+      genop_2(s, OP_GETGV, cursp(), sym);
       push();
     }
@@ -2234,5 +2420,5 @@
 
   case NODE_BLOCK_ARG:
-    codegen(s, tree, VAL);
+    codegen(s, tree, val);
     break;
 
@@ -2240,25 +2426,27 @@
     if (val) {
       char *p = (char*)tree->car;
-      int base = (intptr_t)tree->cdr->car;
+      int base = nint(tree->cdr->car);
       mrb_int i;
-      mrb_code co;
       mrb_bool overflow;
 
       i = readint_mrb_int(s, p, base, FALSE, &overflow);
+#ifndef MRB_WITHOUT_FLOAT
       if (overflow) {
         double f = readint_float(s, p, base);
         int off = new_lit(s, mrb_float_value(s->mrb, f));
 
-        genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
-      }
-      else {
-        if (i < MAXARG_sBx && i > -MAXARG_sBx) {
-          co = MKOP_AsBx(OP_LOADI, cursp(), i);
-        }
+        genop_2(s, OP_LOADL, cursp(), off);
+      }
+      else
+#endif
+      {
+        if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+        else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
+        else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, cursp());
+        else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i);
         else {
           int off = new_lit(s, mrb_fixnum_value(i));
-          co = MKOP_ABx(OP_LOADL, cursp(), off);
-        }
-        genop(s, co);
+          genop_2(s, OP_LOADL, cursp(), off);
+        }
       }
       push();
@@ -2266,4 +2454,5 @@
     break;
 
+#ifndef MRB_WITHOUT_FLOAT
   case NODE_FLOAT:
     if (val) {
@@ -2272,50 +2461,55 @@
       int off = new_lit(s, mrb_float_value(s->mrb, f));
 
-      genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+      genop_2(s, OP_LOADL, cursp(), off);
       push();
     }
     break;
+#endif
 
   case NODE_NEGATE:
     {
-      nt = (intptr_t)tree->car;
-      tree = tree->cdr;
+      nt = nint(tree->car);
       switch (nt) {
+#ifndef MRB_WITHOUT_FLOAT
       case NODE_FLOAT:
         if (val) {
-          char *p = (char*)tree;
+          char *p = (char*)tree->cdr;
           mrb_float f = mrb_float_read(p, NULL);
           int off = new_lit(s, mrb_float_value(s->mrb, -f));
 
-          genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+          genop_2(s, OP_LOADL, cursp(), off);
           push();
         }
         break;
+#endif
 
       case NODE_INT:
         if (val) {
-          char *p = (char*)tree->car;
-          int base = (intptr_t)tree->cdr->car;
+          char *p = (char*)tree->cdr->car;
+          int base = nint(tree->cdr->cdr->car);
           mrb_int i;
-          mrb_code co;
           mrb_bool overflow;
 
           i = readint_mrb_int(s, p, base, TRUE, &overflow);
+#ifndef MRB_WITHOUT_FLOAT
           if (overflow) {
             double f = readint_float(s, p, base);
             int off = new_lit(s, mrb_float_value(s->mrb, -f));
 
-            genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+            genop_2(s, OP_LOADL, cursp(), off);
           }
           else {
-            if (i < MAXARG_sBx && i > -MAXARG_sBx) {
-              co = MKOP_AsBx(OP_LOADI, cursp(), i);
+#endif
+            if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+            else if (i >= -0xffff) {
+              genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
             }
             else {
               int off = new_lit(s, mrb_fixnum_value(i));
-              co = MKOP_ABx(OP_LOADL, cursp(), off);
+              genop_2(s, OP_LOADL, cursp(), off);
             }
-            genop(s, co);
-          }
+#ifndef MRB_WITHOUT_FLOAT
+          }
+#endif
           push();
         }
@@ -2324,11 +2518,9 @@
       default:
         if (val) {
-          int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
-
-          genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
+          int sym = new_sym(s, mrb_intern_lit(s->mrb, "-@"));
+          codegen(s, tree, VAL);
+          pop();
+          genop_3(s, OP_SEND, cursp(), sym, 0);
           push();
-          codegen(s, tree, VAL);
-          pop(); pop();
-          genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
         }
         else {
@@ -2348,5 +2540,5 @@
 
       mrb_gc_arena_restore(s->mrb, ai);
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
       push();
     }
@@ -2361,5 +2553,5 @@
 
       if (!n) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
         break;
@@ -2370,5 +2562,5 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
@@ -2379,5 +2571,5 @@
 
       while (n) {
-        if ((intptr_t)n->car->car != NODE_STR) {
+        if (nint(n->car->car) != NODE_STR) {
           codegen(s, n->car, NOVAL);
         }
@@ -2401,10 +2593,10 @@
       int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
 
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
       codegen(s, tree->car, VAL);
       n = tree->cdr;
       while (n) {
-        if ((intptr_t)n->car->car == NODE_XSTR) {
+        if (nint(n->car->car) == NODE_XSTR) {
           n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
           mrb_assert(!n->cdr); /* must be the end */
@@ -2412,5 +2604,5 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
@@ -2419,5 +2611,5 @@
       pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      genop_3(s, OP_SEND, cursp(), sym, 1);
       if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
@@ -2433,11 +2625,11 @@
       int sym;
 
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
       push(); push();
       pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      genop_3(s, OP_SEND, cursp(), sym, 1);
       if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
@@ -2455,30 +2647,30 @@
       int argc = 1;
 
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       push();
-      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+      genop_2(s, OP_STRING, cursp(), off);
+      push();
       if (p2 || p3) {
+        if (p2) { /* opt */
+          off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
+          genop_2(s, OP_STRING, cursp(), off);
+        }
+        else {
+          genop_1(s, OP_LOADNIL, cursp());
+        }
         push();
-        if (p2) {
-          off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-          genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-        }
-        else {
-          genop(s, MKOP_A(OP_LOADNIL, cursp()));
-        }
         argc++;
-        if (p3) {
+        if (p3) { /* enc */
+          off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
+          genop_2(s, OP_STRING, cursp(), off);
           push();
-          off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
-          genop(s, MKOP_ABx(OP_STRING, cursp(), off));
           argc++;
-          pop();
-        }
-        pop();
-      }
-      pop();
+        }
+      }
+      push(); /* space for a block */
+      pop_n(argc+2);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+      genop_3(s, OP_SEND, cursp(), sym, argc);
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2495,6 +2687,6 @@
       char *p;
 
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop_1(s, OP_OCLASS, cursp());
+      genop_2(s, OP_GETMCNST, cursp(), sym);
       push();
       codegen(s, n->car, VAL);
@@ -2503,36 +2695,36 @@
         codegen(s, n->car, VAL);
         pop(); pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        genop_1(s, OP_STRCAT, cursp());
         push();
         n = n->cdr;
       }
       n = tree->cdr->cdr;
-      if (n->car) {
+      if (n->car) { /* tail */
         p = (char*)n->car;
         off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
         codegen(s, tree->car, VAL);
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+        genop_2(s, OP_STRING, cursp(), off);
         pop();
-        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
-      }
-      if (n->cdr->car) {
+        genop_1(s, OP_STRCAT, cursp());
+        push();
+      }
+      if (n->cdr->car) { /* opt */
         char *p2 = (char*)n->cdr->car;
-
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
+        genop_2(s, OP_STRING, cursp(), off);
         push();
+        argc++;
+      }
+      if (n->cdr->cdr) { /* enc */
+        char *p2 = (char*)n->cdr->cdr;
         off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+        genop_2(s, OP_STRING, cursp(), off);
+        push();
         argc++;
       }
-      if (n->cdr->cdr) {
-        char *p2 = (char*)n->cdr->cdr;
-
-        push();
-        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
-        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-        argc++;
-      }
-      pop_n(argc);
+      push(); /* space for a block */
+      pop_n(argc+2);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
-      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+      genop_3(s, OP_SEND, cursp(), sym, argc);
       mrb_gc_arena_restore(s->mrb, ai);
       push();
@@ -2542,5 +2734,5 @@
 
       while (n) {
-        if ((intptr_t)n->car->car != NODE_STR) {
+        if (nint(n->car->car) != NODE_STR) {
           codegen(s, n->car, NOVAL);
         }
@@ -2552,7 +2744,7 @@
   case NODE_SYM:
     if (val) {
-      int sym = new_sym(s, sym(tree));
-
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+      int sym = new_sym(s, nsym(tree));
+
+      genop_2(s, OP_LOADSYM, cursp(), sym);
       push();
     }
@@ -2562,5 +2754,5 @@
     codegen(s, tree, val);
     if (val) {
-      gen_send_intern(s);
+      gen_intern(s);
     }
     break;
@@ -2568,5 +2760,5 @@
   case NODE_SELF:
     if (val) {
-      genop(s, MKOP_A(OP_LOADSELF, cursp()));
+      genop_1(s, OP_LOADSELF, cursp());
       push();
     }
@@ -2575,5 +2767,5 @@
   case NODE_NIL:
     if (val) {
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      genop_1(s, OP_LOADNIL, cursp());
       push();
     }
@@ -2582,5 +2774,5 @@
   case NODE_TRUE:
     if (val) {
-      genop(s, MKOP_A(OP_LOADT, cursp()));
+      genop_1(s, OP_LOADT, cursp());
       push();
     }
@@ -2589,5 +2781,5 @@
   case NODE_FALSE:
     if (val) {
-      genop(s, MKOP_A(OP_LOADF, cursp()));
+      genop_1(s, OP_LOADF, cursp());
       push();
     }
@@ -2596,19 +2788,10 @@
   case NODE_ALIAS:
     {
-      int a = new_msym(s, sym(tree->car));
-      int b = new_msym(s, sym(tree->cdr));
-      int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method"));
-
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
-      push();
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a));
-      push();
-      genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
-      push();
-      genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      push();
-      pop_n(4);
-      genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
+      int a = new_sym(s, nsym(tree->car));
+      int b = new_sym(s, nsym(tree->cdr));
+
+      genop_2(s, OP_ALIAS, a, b);
       if (val) {
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
@@ -2618,38 +2801,13 @@
   case NODE_UNDEF:
     {
-      int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
-      int num = 0;
       node *t = tree;
 
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
-      push();
       while (t) {
-        int symbol;
-        if (num >= CALL_MAXARGS - 1) {
-          pop_n(num);
-          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num));
-          while (t) {
-            symbol = new_msym(s, sym(t->car));
-            push();
-            genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
-            pop();
-            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
-            t = t->cdr;
-          }
-          num = CALL_MAXARGS;
-          break;
-        }
-        symbol = new_msym(s, sym(t->car));
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
-        push();
+        int symbol = new_sym(s, nsym(t->car));
+        genop_1(s, OP_UNDEF, symbol);
         t = t->cdr;
-        num++;
-      }
-      pop();
-      if (num < CALL_MAXARGS) {
-        pop_n(num);
-      }
-      genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
+      }
       if (val) {
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
@@ -2660,11 +2818,12 @@
     {
       int idx;
+      node *body;
 
       if (tree->car->car == (node*)0) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       else if (tree->car->car == (node*)1) {
-        genop(s, MKOP_A(OP_OCLASS, cursp()));
+        genop_1(s, OP_OCLASS, cursp());
         push();
       }
@@ -2676,12 +2835,18 @@
       }
       else {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       pop(); pop();
-      idx = new_msym(s, sym(tree->car->cdr));
-      genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
-      idx = scope_body(s, tree->cdr->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      idx = new_sym(s, nsym(tree->car->cdr));
+      genop_2(s, OP_CLASS, cursp(), idx);
+      body = tree->cdr->cdr->car;
+      if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, body, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2695,9 +2860,9 @@
 
       if (tree->car->car == (node*)0) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        genop_1(s, OP_LOADNIL, cursp());
         push();
       }
       else if (tree->car->car == (node*)1) {
-        genop(s, MKOP_A(OP_OCLASS, cursp()));
+        genop_1(s, OP_OCLASS, cursp());
         push();
       }
@@ -2706,8 +2871,14 @@
       }
       pop();
-      idx = new_msym(s, sym(tree->car->cdr));
-      genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
-      idx = scope_body(s, tree->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      idx = new_sym(s, nsym(tree->car->cdr));
+      genop_2(s, OP_MODULE, cursp(), idx);
+      if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+          tree->cdr->car->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, tree->cdr->car, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2722,7 +2893,13 @@
       codegen(s, tree->car, VAL);
       pop();
-      genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
-      idx = scope_body(s, tree->cdr->car, val);
-      genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+      genop_1(s, OP_SCLASS, cursp());
+      if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+          tree->cdr->car->cdr->cdr == NULL) {
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      else {
+        idx = scope_body(s, tree->cdr->car, val);
+        genop_2(s, OP_EXEC, cursp(), idx);
+      }
       if (val) {
         push();
@@ -2733,15 +2910,15 @@
   case NODE_DEF:
     {
-      int sym = new_msym(s, sym(tree->car));
+      int sym = new_sym(s, nsym(tree->car));
       int idx = lambda_body(s, tree->cdr, 0);
 
-      genop(s, MKOP_A(OP_TCLASS, cursp()));
+      genop_1(s, OP_TCLASS, cursp());
       push();
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+      genop_2(s, OP_METHOD, cursp(), idx);
       push(); pop();
       pop();
-      genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+      genop_2(s, OP_DEF, cursp(), sym);
       if (val) {
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+        genop_2(s, OP_LOADSYM, cursp(), sym);
         push();
       }
@@ -2752,16 +2929,16 @@
     {
       node *recv = tree->car;
-      int sym = new_msym(s, sym(tree->cdr->car));
+      int sym = new_sym(s, nsym(tree->cdr->car));
       int idx = lambda_body(s, tree->cdr->cdr, 0);
 
       codegen(s, recv, VAL);
       pop();
-      genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
+      genop_1(s, OP_SCLASS, cursp());
       push();
-      genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+      genop_2(s, OP_METHOD, cursp(), idx);
       pop();
-      genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+      genop_2(s, OP_DEF, cursp(), sym);
       if (val) {
-        genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+        genop_2(s, OP_LOADSYM, cursp(), sym);
         push();
       }
@@ -2802,5 +2979,9 @@
   codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
 
-  if (!p) return NULL;
+  if (!p) {
+    if (prev)
+      codegen_error(prev, "unexpected scope");
+    return NULL;
+  }
   *p = codegen_scope_zero;
   p->mrb = mrb;
@@ -2825,5 +3006,5 @@
   p->irep->plen = 0;
 
-  p->scapa = MAXMSYMLEN;
+  p->scapa = 256;
   p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
   p->irep->slen = 0;
@@ -2850,6 +3031,6 @@
   p->ai = mrb_gc_arena_save(mrb);
 
-  p->filename = prev->filename;
-  if (p->filename) {
+  p->filename_sym = prev->filename_sym;
+  if (p->filename_sym) {
     p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
   }
@@ -2858,8 +3039,6 @@
   /* debug setting */
   p->debug_start_pos = 0;
-  if (p->filename) {
+  if (p->filename_sym) {
     mrb_debug_info_alloc(mrb, p->irep);
-    p->irep->filename = p->filename;
-    p->irep->lines = p->lines;
   }
   else {
@@ -2879,32 +3058,24 @@
   mrb_state *mrb = s->mrb;
   mrb_irep *irep = s->irep;
-  size_t fname_len;
-  char *fname;
-
+
+  if (s->nlocals >= 0x3ff) {
+    codegen_error(s, "too many local variables");
+  }
   irep->flags = 0;
   if (s->iseq) {
     irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
     irep->ilen = s->pc;
-    if (s->lines) {
-      irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc);
-    }
-    else {
-      irep->lines = 0;
-    }
   }
   irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
   irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
   irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
-  if (s->filename) {
-    irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
-    mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc);
-
-    fname_len = strlen(s->filename);
-    fname = (char*)codegen_malloc(s, fname_len + 1);
-    memcpy(fname, s->filename, fname_len);
-    fname[fname_len] = '\0';
-    irep->filename = fname;
-    irep->own_filename = TRUE;
-  }
+  if (s->filename_sym) {
+    mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
+
+    mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+                               filename, s->lines, s->debug_start_pos, s->pc);
+  }
+  mrb_free(s->mrb, s->lines);
 
   irep->nlocals = s->nlocals;
@@ -2921,5 +3092,5 @@
 
   p->type = t;
-  p->pc1 = p->pc2 = p->pc3 = 0;
+  p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0;
   p->prev = s->loop;
   p->ensure_level = s->ensure_level;
@@ -2939,4 +3110,5 @@
   else {
     struct loopinfo *loop;
+    int n = 0;
 
     if (tree) {
@@ -2945,10 +3117,15 @@
 
     loop = s->loop;
-    while (loop && loop->type == LOOP_BEGIN) {
-      genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
-      loop = loop->prev;
-    }
-    while (loop && loop->type == LOOP_RESCUE) {
-      loop = loop->prev;
+    while (loop) {
+      if (loop->type == LOOP_BEGIN) {
+        n++;
+        loop = loop->prev;
+      }
+      else if (loop->type == LOOP_RESCUE) {
+        loop = loop->prev;
+      }
+      else{
+        break;
+      }
     }
     if (!loop) {
@@ -2956,4 +3133,7 @@
       return;
     }
+    if (n > 0) {
+      genop_1(s, OP_POPERR, n);
+    }
 
     if (loop->type == LOOP_NORMAL) {
@@ -2961,17 +3141,17 @@
 
       if (s->ensure_level > s->loop->ensure_level) {
-        genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+        genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
       }
       if (tree) {
-        genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
-      }
-      tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+        gen_move(s, loop->acc, cursp(), 0);
+      }
+      tmp = genjmp(s, OP_JMP, loop->pc3);
       loop->pc3 = tmp;
     }
     else {
       if (!tree) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      }
-      genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK));
+        genop_1(s, OP_LOADNIL, cursp());
+      }
+      gen_return(s, OP_BREAK, cursp());
     }
   }
@@ -2981,14 +3161,14 @@
 loop_pop(codegen_scope *s, int val)
 {
+  if (val) {
+    genop_1(s, OP_LOADNIL, cursp());
+  }
   dispatch_linked(s, s->loop->pc3);
-  if (val) {
-    genop(s, MKOP_A(OP_LOADNIL, cursp()));
-  }
   s->loop = s->loop->prev;
   if (val) push();
 }
 
-MRB_API struct RProc*
-mrb_generate_code(mrb_state *mrb, parser_state *p)
+static struct RProc*
+generate_code(mrb_state *mrb, parser_state *p, int val)
 {
   codegen_scope *scope = scope_new(mrb, 0, 0);
@@ -2996,20 +3176,20 @@
   struct mrb_jmpbuf *prev_jmp = mrb->jmp;
 
-  if (!scope) {
-    return NULL;
-  }
   scope->mrb = mrb;
   scope->parser = p;
-  scope->filename = p->filename;
+  scope->filename_sym = p->filename_sym;
   scope->filename_index = p->current_filename_index;
 
   MRB_TRY(&scope->jmp) {
-    mrb->jmp = &scope->jmp; 
+    mrb->jmp = &scope->jmp;
     /* prepare irep */
-    codegen(scope, p->tree, NOVAL);
+    codegen(scope, p->tree, val);
     proc = mrb_proc_new(mrb, scope->irep);
     mrb_irep_decref(mrb, scope->irep);
     mrb_pool_close(scope->mpool);
     proc->c = NULL;
+    if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) {
+      proc->upper = NULL;
+    }
     mrb->jmp = prev_jmp;
     return proc;
@@ -3023,2 +3203,76 @@
   MRB_END_EXC(&scope->jmp);
 }
+
+MRB_API struct RProc*
+mrb_generate_code(mrb_state *mrb, parser_state *p)
+{
+  return generate_code(mrb, p, VAL);
+}
+
+void
+mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
+{
+  int i;
+
+  if (irep->lv) {
+    mrb_free(mrb, irep->lv);
+    irep->lv = NULL;
+  }
+
+  for (i = 0; i < irep->rlen; ++i) {
+    mrb_irep_remove_lv(mrb, irep->reps[i]);
+  }
+}
+
+#undef OPCODE
+#define Z 1
+#define S 3
+#define W 4
+/* instruction sizes */
+uint8_t mrb_insn_size[] = {
+#define B 2
+#define BB 3
+#define BBB 4
+#define BS 4
+#define SB 4
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+#undef BB
+#undef BS
+#undef SB
+#undef BBB
+};
+/* EXT1 instruction sizes */
+uint8_t mrb_insn_size1[] = {
+#define B 3
+#define BB 4
+#define BBB 5
+#define BS 5
+#define SB 5
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+};
+/* EXT2 instruction sizes */
+uint8_t mrb_insn_size2[] = {
+#define B 2
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef BB
+#undef BBB
+#undef BS
+#undef SB
+};
+/* EXT3 instruction sizes */
+#define BB 5
+#define BBB 6
+#define BS 4
+#define SB 5
+uint8_t mrb_insn_size3[] = {
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+};
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/keywords
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/keywords	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/keywords	(revision 439)
@@ -1,7 +1,4 @@
 %{
 struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
 %}
 
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/lex.def
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/lex.def	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/lex.def	(revision 439)
@@ -1,3 +1,3 @@
-/* ANSI-C code produced by gperf version 3.0.4 */
+/* ANSI-C code produced by gperf version 3.1 */
 /* Command-line: gperf -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k'1,3,$' /home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords  */
 
@@ -26,5 +26,5 @@
       && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
 /* The character set is not based on ISO-646.  */
-#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
 #endif
 
@@ -32,8 +32,5 @@
 
 struct kwtable {const char *name; int id[2]; enum mrb_lex_state_enum state;};
-const struct kwtable *mrb_reserved_word(const char *, unsigned int);
-static const struct kwtable *reserved_word(const char *, unsigned int);
-#define mrb_reserved_word(str, len) reserved_word(str, len)
-#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 5 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
 struct kwtable;
 
@@ -53,5 +50,5 @@
 #endif
 static unsigned int
-hash (register const char *str, register unsigned int len)
+hash (register const char *str, register size_t len)
 {
   static const unsigned char asso_values[] =
@@ -84,5 +81,5 @@
       51, 51, 51, 51, 51, 51
     };
-  register int hval = len;
+  register unsigned int hval = len;
 
   switch (hval)
@@ -99,97 +96,91 @@
 }
 
-#ifdef __GNUC__
-__inline
-#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
 const struct kwtable *
-mrb_reserved_word (register const char *str, register unsigned int len)
+mrb_reserved_word (register const char *str, register size_t len)
 {
   static const struct kwtable wordlist[] =
     {
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"break",        {keyword_break,       keyword_break},       EXPR_MID},
+#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"else",         {keyword_else,        keyword_else},        EXPR_BEG},
+#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"nil",          {keyword_nil,         keyword_nil},         EXPR_END},
+#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"ensure",       {keyword_ensure,      keyword_ensure},      EXPR_BEG},
+#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"end",          {keyword_end,         keyword_end},         EXPR_END},
+#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"then",         {keyword_then,        keyword_then},        EXPR_BEG},
+#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"not",          {keyword_not,         keyword_not},         EXPR_ARG},
+#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"false",        {keyword_false,       keyword_false},       EXPR_END},
+#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"self",         {keyword_self,        keyword_self},        EXPR_END},
+#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"elsif",        {keyword_elsif,       keyword_elsif},       EXPR_VALUE},
+#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"rescue",       {keyword_rescue,      modifier_rescue},     EXPR_MID},
+#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"true",         {keyword_true,        keyword_true},        EXPR_END},
+#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"until",        {keyword_until,       modifier_until},      EXPR_VALUE},
+#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"unless",       {keyword_unless,      modifier_unless},     EXPR_VALUE},
+#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"return",       {keyword_return,      keyword_return},      EXPR_MID},
 #line 18 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"break",        {keyword_break,       keyword_break},       EXPR_MID},
-#line 23 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"else",         {keyword_else,        keyword_else},        EXPR_BEG},
+      {"def",          {keyword_def,         keyword_def},         EXPR_FNAME},
+#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"and",          {keyword_and,         keyword_and},         EXPR_VALUE},
+#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"do",           {keyword_do,          keyword_do},          EXPR_BEG},
+#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"yield",        {keyword_yield,       keyword_yield},       EXPR_ARG},
+#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"for",          {keyword_for,         keyword_for},         EXPR_VALUE},
+#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"undef",        {keyword_undef,       keyword_undef},       EXPR_FNAME},
+#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"or",           {keyword_or,          keyword_or},          EXPR_VALUE},
+#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"in",           {keyword_in,          keyword_in},          EXPR_VALUE},
+#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"when",         {keyword_when,        keyword_when},        EXPR_VALUE},
+#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"retry",        {keyword_retry,       keyword_retry},       EXPR_END},
+#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"if",           {keyword_if,          modifier_if},         EXPR_VALUE},
+#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"case",         {keyword_case,        keyword_case},        EXPR_VALUE},
 #line 33 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"nil",          {keyword_nil,         keyword_nil},         EXPR_END},
-#line 26 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"ensure",       {keyword_ensure,      keyword_ensure},      EXPR_BEG},
-#line 25 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"end",          {keyword_end,         keyword_end},         EXPR_END},
-#line 42 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"then",         {keyword_then,        keyword_then},        EXPR_BEG},
-#line 34 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"not",          {keyword_not,         keyword_not},         EXPR_ARG},
-#line 27 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"false",        {keyword_false,       keyword_false},       EXPR_END},
-#line 40 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"self",         {keyword_self,        keyword_self},        EXPR_END},
-#line 24 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"elsif",        {keyword_elsif,       keyword_elsif},       EXPR_VALUE},
-#line 37 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"rescue",       {keyword_rescue,      modifier_rescue},     EXPR_MID},
-#line 43 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"true",         {keyword_true,        keyword_true},        EXPR_END},
-#line 46 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"until",        {keyword_until,       modifier_until},      EXPR_VALUE},
-#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"unless",       {keyword_unless,      modifier_unless},     EXPR_VALUE},
-#line 39 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"return",       {keyword_return,      keyword_return},      EXPR_MID},
-#line 21 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"def",          {keyword_def,         keyword_def},         EXPR_FNAME},
-#line 16 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"and",          {keyword_and,         keyword_and},         EXPR_VALUE},
-#line 22 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"do",           {keyword_do,          keyword_do},          EXPR_BEG},
-#line 49 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"yield",        {keyword_yield,       keyword_yield},       EXPR_ARG},
+      {"redo",         {keyword_redo,        keyword_redo},        EXPR_END},
+#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"next",         {keyword_next,        keyword_next},        EXPR_MID},
+#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"super",        {keyword_super,       keyword_super},       EXPR_ARG},
 #line 28 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"for",          {keyword_for,         keyword_for},         EXPR_VALUE},
-#line 44 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"undef",        {keyword_undef,       keyword_undef},       EXPR_FNAME},
-#line 35 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"or",           {keyword_or,          keyword_or},          EXPR_VALUE},
-#line 30 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"in",           {keyword_in,          keyword_in},          EXPR_VALUE},
-#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"when",         {keyword_when,        keyword_when},        EXPR_VALUE},
-#line 38 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"retry",        {keyword_retry,       keyword_retry},       EXPR_END},
-#line 29 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"if",           {keyword_if,          modifier_if},         EXPR_VALUE},
-#line 19 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"case",         {keyword_case,        keyword_case},        EXPR_VALUE},
-#line 36 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"redo",         {keyword_redo,        keyword_redo},        EXPR_END},
-#line 32 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"next",         {keyword_next,        keyword_next},        EXPR_MID},
-#line 41 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"super",        {keyword_super,       keyword_super},       EXPR_ARG},
-#line 31 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"module",       {keyword_module,      keyword_module},      EXPR_VALUE},
-#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"begin",        {keyword_begin,       keyword_begin},       EXPR_BEG},
+#line 9 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__LINE__",     {keyword__LINE__,     keyword__LINE__},     EXPR_END},
+#line 8 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__FILE__",     {keyword__FILE__,     keyword__FILE__},     EXPR_END},
+#line 7 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
+#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+      {"END",          {keyword_END,         keyword_END},         EXPR_END},
 #line 12 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__LINE__",     {keyword__LINE__,     keyword__LINE__},     EXPR_END},
-#line 11 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__FILE__",     {keyword__FILE__,     keyword__FILE__},     EXPR_END},
+      {"alias",        {keyword_alias,       keyword_alias},       EXPR_FNAME},
 #line 10 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
-#line 14 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"END",          {keyword_END,         keyword_END},         EXPR_END},
-#line 15 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-      {"alias",        {keyword_alias,       keyword_alias},       EXPR_FNAME},
-#line 13 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"BEGIN",        {keyword_BEGIN,       keyword_BEGIN},       EXPR_END},
       {""},
-#line 20 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 17 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"class",        {keyword_class,       keyword_class},       EXPR_CLASS},
       {""}, {""},
-#line 48 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+#line 45 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
       {"while",        {keyword_while,       modifier_while},      EXPR_VALUE}
     };
@@ -197,7 +188,7 @@
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
     {
-      register int key = hash (str, len);
-
-      if (key <= MAX_HASH_VALUE && key >= 0)
+      register unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
         {
           register const char *s = wordlist[key].name;
@@ -209,4 +200,4 @@
   return 0;
 }
-#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
-
+#line 47 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
+
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/node.h
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/node.h	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/node.h	(revision 439)
@@ -10,6 +10,4 @@
 enum node_type {
   NODE_METHOD,
-  NODE_FBODY,
-  NODE_CFUNC,
   NODE_SCOPE,
   NODE_BLOCK,
@@ -17,5 +15,4 @@
   NODE_CASE,
   NODE_WHEN,
-  NODE_OPT_N,
   NODE_WHILE,
   NODE_UNTIL,
@@ -41,5 +38,4 @@
   NODE_SCALL,
   NODE_FCALL,
-  NODE_VCALL,
   NODE_SUPER,
   NODE_ZSUPER,
@@ -47,4 +43,5 @@
   NODE_ZARRAY,
   NODE_HASH,
+  NODE_KW_HASH,
   NODE_RETURN,
   NODE_YIELD,
@@ -55,9 +52,8 @@
   NODE_CONST,
   NODE_CVAR,
+  NODE_NVAR,
   NODE_NTH_REF,
   NODE_BACK_REF,
   NODE_MATCH,
-  NODE_MATCH2,
-  NODE_MATCH3,
   NODE_INT,
   NODE_FLOAT,
@@ -72,8 +68,8 @@
   NODE_DREGX,
   NODE_DREGX_ONCE,
-  NODE_LIST,
   NODE_ARG,
-  NODE_ARGSCAT,
-  NODE_ARGSPUSH,
+  NODE_ARGS_TAIL,
+  NODE_KW_ARG,
+  NODE_KW_REST_ARGS,
   NODE_SPLAT,
   NODE_TO_ARY,
@@ -89,10 +85,6 @@
   NODE_COLON2,
   NODE_COLON3,
-  NODE_CREF,
   NODE_DOT2,
   NODE_DOT3,
-  NODE_FLIP2,
-  NODE_FLIP3,
-  NODE_ATTRSET,
   NODE_SELF,
   NODE_NIL,
@@ -100,13 +92,6 @@
   NODE_FALSE,
   NODE_DEFINED,
-  NODE_NEWLINE,
   NODE_POSTEXE,
-  NODE_ALLOCA,
-  NODE_DMETHOD,
-  NODE_BMETHOD,
-  NODE_MEMO,
-  NODE_IFUNC,
   NODE_DSYM,
-  NODE_ATTRASGN,
   NODE_HEREDOC,
   NODE_LITERAL_DELIM,
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/parse.y
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/parse.y	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/core/parse.y	(revision 439)
@@ -11,11 +11,5 @@
 #endif
 #define YYERROR_VERBOSE 1
-/*
- * Force yacc to use our memory management.  This is a little evil because
- * the macros assume that "parser_state *p" is in scope
- */
-#define YYMALLOC(n)    mrb_malloc(p->mrb, (n))
-#define YYFREE(o)      mrb_free(p->mrb, (o))
-#define YYSTACK_USE_ALLOCA 0
+#define YYSTACK_USE_ALLOCA 1
 
 #include <ctype.h>
@@ -28,4 +22,5 @@
 #include <mruby/error.h>
 #include <mruby/throw.h>
+#include <mruby/string.h>
 #include "node.h"
 
@@ -77,4 +72,7 @@
 #define intn(x) ((int)(intptr_t)(x))
 
+#define NUM_SUFFIX_R   (1<<0)
+#define NUM_SUFFIX_I   (1<<1)
+
 static inline mrb_sym
 intern_cstr_gen(parser_state *p, const char *s)
@@ -91,10 +89,5 @@
 #define intern(s,len) intern_gen(p,(s),(len))
 
-static inline mrb_sym
-intern_gen_c(parser_state *p, const char c)
-{
-  return mrb_intern(p->mrb, &c, 1);
-}
-#define intern_c(c) intern_gen_c(p,(c))
+#define intern_lit(s) mrb_intern_lit(p->mrb, s)
 
 static void
@@ -134,4 +127,8 @@
   c->lineno = p->lineno;
   c->filename_index = p->current_filename_index;
+  /* beginning of next partial file; need to point the previous file */
+  if (p->lineno == 0 && p->current_filename_index > 0) {
+    c->filename_index-- ;
+  }
   return c;
 }
@@ -186,10 +183,9 @@
 
   if (!a) return b;
+  if (!b) return a;
   while (c->cdr) {
     c = c->cdr;
   }
-  if (b) {
-    c->cdr = b;
-  }
+  c->cdr = b;
   return a;
 }
@@ -216,4 +212,24 @@
 #undef strdup
 #define strdup(s) parser_strdup(p, s)
+
+static void
+dump_int(uint16_t i, char *s)
+{
+  char *p = s;
+  char *t = s;
+
+  while (i > 0) {
+    *p++ = (i % 10)+'0';
+    i /= 10;
+  }
+  if (p == s) *p++ = '0';
+  *p = 0;
+  p--;  /* point the last char */
+  while (t < p) {
+    char c = *t;
+    *t++ = *p;
+    *p-- = c;
+  }
+}
 
 /* xxx ----------------------------- */
@@ -280,8 +296,40 @@
 }
 
+static void
+local_add_blk(parser_state *p, mrb_sym blk)
+{
+  /* allocate register for block */
+  local_add_f(p, blk ? blk : mrb_intern_lit(p->mrb, "&"));
+}
+
+static void
+local_add_kw(parser_state *p, mrb_sym kwd)
+{
+  /* allocate register for keywords hash */
+  local_add_f(p, kwd ? kwd : mrb_intern_lit(p->mrb, "**"));
+}
+
 static node*
 locals_node(parser_state *p)
 {
   return p->locals ? p->locals->car : NULL;
+}
+
+static void
+nvars_nest(parser_state *p)
+{
+  p->nvars = cons(nint(0), p->nvars);
+}
+
+static void
+nvars_block(parser_state *p)
+{
+  p->nvars = cons(nint(-2), p->nvars);
+}
+
+static void
+nvars_unnest(parser_state *p)
+{
+  p->nvars = p->nvars->cdr;
 }
 
@@ -569,4 +617,11 @@
 }
 
+/* (:kw_hash (k . v) (k . v)...) */
+static node*
+new_kw_hash(parser_state *p, node *a)
+{
+  return cons((node*)NODE_KW_HASH, a);
+}
+
 /* (:sym . a) */
 static node*
@@ -613,4 +668,14 @@
 }
 
+/* (:nvar . a) */
+static node*
+new_nvar(parser_state *p, int num)
+{
+  int nvars = intn(p->nvars->car);
+
+  p->nvars->car = nint(nvars > num ? nvars : num);
+  return cons((node*)NODE_NVAR, nint(num));
+}
+
 /* (:const . a) */
 static node*
@@ -672,5 +737,33 @@
 }
 
-/* (m o r m2 b) */
+static void
+local_add_margs(parser_state *p, node *n)
+{
+  while (n) {
+    if (n->car->car == (node*)NODE_MASGN) {
+      node *t = n->car->cdr->cdr;
+
+      n->car->cdr->cdr = NULL;
+      while (t) {
+        local_add_f(p, sym(t->car));
+        t = t->cdr;
+      }
+      local_add_margs(p, n->car->cdr->car->car);
+      local_add_margs(p, n->car->cdr->car->cdr->cdr->car);
+    }
+    n = n->cdr;
+  }
+}
+
+static void
+local_add_lv(parser_state *p, node *lv)
+{
+  while (lv) {
+    local_add_f(p, sym(lv->car));
+    lv = lv->cdr;
+  }
+}
+
+/* (m o r m2 tail) */
 /* m: (a b c) */
 /* o: ((a . e1) (b . e2)) */
@@ -679,14 +772,60 @@
 /* b: a */
 static node*
-new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
+new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
 {
   node *n;
 
-  n = cons(m2, nsym(blk));
+  local_add_margs(p, m);
+  local_add_margs(p, m2);
+  n = cons(m2, tail);
   n = cons(nsym(rest), n);
   n = cons(opt, n);
+  while (opt) {
+    /* opt: (sym . (opt . lv)) -> (sym . opt) */
+    local_add_lv(p, opt->car->cdr->cdr);
+    opt->car->cdr = opt->car->cdr->car;
+    opt = opt->cdr;
+  }
   return cons(m, n);
 }
 
+/* (:args_tail keywords rest_keywords_sym block_sym) */
+static node*
+new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
+{
+  node *k;
+
+  if (kws || kwrest) {
+    local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
+  }
+
+  local_add_blk(p, blk);
+
+  /* allocate register for keywords arguments */
+  /* order is for Proc#parameters */
+  for (k = kws; k; k = k->cdr) {
+    if (!k->car->cdr->cdr->car) { /* allocate required keywords */
+      local_add_f(p, sym(k->car->cdr->car));
+    }
+  }
+  for (k = kws; k; k = k->cdr) {
+    if (k->car->cdr->cdr->car) { /* allocate keywords with default */
+      local_add_lv(p, k->car->cdr->cdr->car->cdr);
+      k->car->cdr->cdr->car = k->car->cdr->cdr->car->car;
+      local_add_f(p, sym(k->car->cdr->car));
+    }
+  }
+
+  return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk));
+}
+
+/* (:kw_arg kw_sym def_arg) */
+static node*
+new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
+{
+  mrb_assert(kw);
+  return list3((node*)NODE_KW_ARG, nsym(kw), def_arg);
+}
+
 /* (:block_arg . a) */
 static node*
@@ -696,8 +835,39 @@
 }
 
+static node*
+setup_numparams(parser_state *p, node *a)
+{
+  int nvars = intn(p->nvars->car);
+  if (nvars > 0) {
+    int i;
+    mrb_sym sym;
+    // m || opt || rest || tail
+    if (a && (a->car || (a->cdr && a->cdr->car) || (a->cdr->cdr && a->cdr->cdr->car) || (a->cdr->cdr->cdr->cdr && a->cdr->cdr->cdr->cdr->car))) {
+      yyerror(p, "ordinary parameter is defined");
+    }
+    else if (p->locals) {
+      /* p->locals should not be NULL unless error happens before the point */
+      node* args = 0;
+      for (i = nvars; i > 0; i--) {
+        char buf[3];
+
+        buf[0] = '_';
+        buf[1] = i+'0';
+        buf[2] = '\0';
+        sym = intern_cstr(buf);
+        args = cons(new_arg(p, sym), args);
+        p->locals->car = cons(nsym(sym), p->locals->car);
+      }
+      a = new_args(p, args, 0, 0, 0, 0);
+    }
+  }
+  return a;
+}
+
 /* (:block arg body) */
 static node*
 new_block(parser_state *p, node *a, node *b)
 {
+  a = setup_numparams(p, a);
   return list4((node*)NODE_BLOCK, locals_node(p), a, b);
 }
@@ -726,4 +896,11 @@
 }
 
+/* (:masgn mlhs mrhs) no check */
+static node*
+new_masgn_param(parser_state *p, node *a, node *b)
+{
+  return cons((node*)NODE_MASGN, cons(a, b));
+}
+
 /* (:asgn lhs rhs) */
 static node*
@@ -734,21 +911,49 @@
 }
 
+static node*
+new_imaginary(parser_state *p, node *imaginary)
+{
+  return new_call(p, new_const(p, intern_lit("Kernel")), intern_lit("Complex"), list1(list2(list3((node*)NODE_INT, (node*)strdup("0"), nint(10)), imaginary)), 1);
+}
+
+static node*
+new_rational(parser_state *p, node *rational)
+{
+  return new_call(p, new_const(p, intern_lit("Kernel")), intern_lit("Rational"), list1(list1(rational)), 1);
+}
+
 /* (:int . i) */
 static node*
-new_int(parser_state *p, const char *s, int base)
-{
-  return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
-}
-
+new_int(parser_state *p, const char *s, int base, int suffix)
+{
+  node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base));
+  if (suffix & NUM_SUFFIX_R) {
+    result = new_rational(p, result);
+  }
+  if (suffix & NUM_SUFFIX_I) {
+    result = new_imaginary(p, result);
+  }
+  return result;
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 /* (:float . i) */
 static node*
-new_float(parser_state *p, const char *s)
-{
-  return cons((node*)NODE_FLOAT, (node*)strdup(s));
-}
+new_float(parser_state *p, const char *s, int suffix)
+{
+  node* result = cons((node*)NODE_FLOAT, (node*)strdup(s));
+  if (suffix & NUM_SUFFIX_R) {
+    result = new_rational(p, result);
+  }
+  if (suffix & NUM_SUFFIX_I) {
+    result = new_imaginary(p, result);
+  }
+  return result;
+}
+#endif
 
 /* (:str . (s . len)) */
 static node*
-new_str(parser_state *p, const char *s, int len)
+new_str(parser_state *p, const char *s, size_t len)
 {
   return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len)));
@@ -762,4 +967,84 @@
 }
 
+static int
+string_node_p(node *n)
+{
+  return (int)((enum node_type)(intptr_t)n->car == NODE_STR);
+}
+
+static node*
+composite_string_node(parser_state *p, node *a, node *b)
+{
+  size_t newlen = (size_t)a->cdr + (size_t)b->cdr;
+  char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1);
+  memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr);
+  str[newlen] = '\0';
+  a->car = (node*)str;
+  a->cdr = (node*)newlen;
+  cons_free(b);
+  return a;
+}
+
+static node*
+concat_string(parser_state *p, node *a, node *b)
+{
+  if (string_node_p(a)) {
+    if (string_node_p(b)) {
+      /* a == NODE_STR && b == NODE_STR */
+      composite_string_node(p, a->cdr, b->cdr);
+      cons_free(b);
+      return a;
+    }
+    else {
+      /* a == NODE_STR && b == NODE_DSTR */
+
+      if (string_node_p(b->cdr->car)) {
+        /* a == NODE_STR && b->[NODE_STR, ...] */
+        composite_string_node(p, a->cdr, b->cdr->car->cdr);
+        cons_free(b->cdr->car);
+        b->cdr->car = a;
+        return b;
+      }
+    }
+  }
+  else {
+    node *c; /* last node of a */
+    for (c = a; c->cdr != NULL; c = c->cdr) ;
+
+    if (string_node_p(b)) {
+      /* a == NODE_DSTR && b == NODE_STR */
+      if (string_node_p(c->car)) {
+        /* a->[..., NODE_STR] && b == NODE_STR */
+        composite_string_node(p, c->car->cdr, b->cdr);
+        cons_free(b);
+        return a;
+      }
+
+      push(a, b);
+      return a;
+    }
+    else {
+      /* a == NODE_DSTR && b == NODE_DSTR */
+      if (string_node_p(c->car) && string_node_p(b->cdr->car)) {
+        /* a->[..., NODE_STR] && b->[NODE_STR, ...] */
+        node *d = b->cdr;
+        cons_free(b);
+        composite_string_node(p, c->car->cdr, d->car->cdr);
+        cons_free(d->car);
+        c->cdr = d->cdr;
+        cons_free(d);
+        return a;
+      }
+      else {
+        c->cdr = b->cdr;
+        cons_free(b);
+        return a;
+      }
+    }
+  }
+
+  return new_dstr(p, list2(a, b));
+}
+
 /* (:str . (s . len)) */
 static node*
@@ -780,5 +1065,5 @@
 new_dsym(parser_state *p, node *a)
 {
-  return cons((node*)NODE_DSYM, new_dstr(p, a));
+  return cons((node*)NODE_DSYM, a);
 }
 
@@ -1024,9 +1309,7 @@
   if (p->parsing_heredoc == NULL) {
     p->lstate = EXPR_BEG;
-    p->cmd_start = TRUE;
     end_strterm(p);
     p->lex_strterm = p->lex_strterm_before_heredoc;
     p->lex_strterm_before_heredoc = NULL;
-    p->heredoc_end_now = TRUE;
   }
   else {
@@ -1105,11 +1388,12 @@
         keyword__ENCODING__
 
-%token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
+%token <id>  tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL_TAG
 %token <nd>  tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
-%token <nd>  tSTRING tSTRING_PART tSTRING_MID tLABEL_END
+%token <nd>  tSTRING tSTRING_PART tSTRING_MID
 %token <nd>  tNTH_REF tBACK_REF
 %token <num> tREGEXP_END
-
-%type <nd> singleton string string_rep string_interp xstring regexp
+%token <num> tNUMPARAM
+
+%type <nd> singleton string string_fragment string_rep string_interp xstring regexp
 %type <nd> literal numeric cpath symbol
 %type <nd> top_compstmt top_stmts top_stmt
@@ -1122,5 +1406,5 @@
 %type <nd> command_asgn command_rhs mrhs superclass block_call block_command
 %type <nd> f_block_optarg f_block_opt
-%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs
+%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_margs
 %type <nd> assoc_list assocs assoc undef_list backref for_var
 %type <nd> block_param opt_block_param block_param_def f_opt
@@ -1132,4 +1416,8 @@
 %type <nd> heredoc words symbols
 %type <num> call_op call_op2     /* 0:'&.', 1:'.', 2:'::' */
+
+%type <nd> args_tail opt_args_tail f_kwarg f_kw f_kwrest
+%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail
+%type <id> f_label
 
 %token tUPLUS             /* unary+ */
@@ -1158,4 +1446,5 @@
 %token tLBRACE_ARG        /* { */
 %token tSTAR              /* * */
+%token tDSTAR             /* ** */
 %token tAMPER             /* & */
 %token tLAMBDA            /* -> */
@@ -1179,5 +1468,5 @@
 %right '=' tOP_ASGN
 %left modifier_rescue
-%right '?' ':'
+%right '?' ':' tLABEL_TAG
 %nonassoc tDOT2 tDOT3
 %left  tOROP
@@ -1237,4 +1526,5 @@
                     {
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   '{' top_compstmt '}'
@@ -1242,4 +1532,5 @@
                       yyerror(p, "BEGIN not supported");
                       local_resume(p, $<nd>2);
+                      nvars_unnest(p);
                       $$ = 0;
                     }
@@ -1359,7 +1650,7 @@
                       $$ = new_op_asgn(p, $1, $2, $3);
                     }
-                | primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs
-                    {
-                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
+                | primary_value '[' opt_call_args ']' tOP_ASGN command_rhs
+                    {
+                      $$ = new_op_asgn(p, new_call(p, $1, intern_lit("[]"), $3, '.'), $5, $6);
                     }
                 | primary_value call_op tIDENTIFIER tOP_ASGN command_rhs
@@ -1385,5 +1676,5 @@
                       $$ = new_begin(p, 0);
                     }
-		;
+                ;
 
 command_rhs     : command_call   %prec tOP_ASGN
@@ -1439,4 +1730,5 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                     }
                   opt_block_param
@@ -1446,4 +1738,5 @@
                       $$ = new_block(p, $3, $4);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -1588,7 +1881,7 @@
                       assignable(p, $1);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 | primary_value call_op tIDENTIFIER
@@ -1627,7 +1920,7 @@
                       assignable(p, $1);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 | primary_value call_op tIDENTIFIER
@@ -1659,4 +1952,8 @@
                       backref_error(p, $1);
                       $$ = 0;
+                    }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "can't assign to numbered parameter");
                     }
                 ;
@@ -1713,33 +2010,34 @@
                 ;
 
-op              : '|'           { $$ = intern_c('|');   }
-                | '^'           { $$ = intern_c('^');   }
-                | '&'           { $$ = intern_c('&');   }
-                | tCMP          { $$ = intern("<=>",3); }
-                | tEQ           { $$ = intern("==",2);  }
-                | tEQQ          { $$ = intern("===",3); }
-                | tMATCH        { $$ = intern("=~",2);  }
-                | tNMATCH       { $$ = intern("!~",2);  }
-                | '>'           { $$ = intern_c('>');   }
-                | tGEQ          { $$ = intern(">=",2);  }
-                | '<'           { $$ = intern_c('<');   }
-                | tLEQ          { $$ = intern("<=",2);  }
-                | tNEQ          { $$ = intern("!=",2);  }
-                | tLSHFT        { $$ = intern("<<",2);  }
-                | tRSHFT        { $$ = intern(">>",2);  }
-                | '+'           { $$ = intern_c('+');   }
-                | '-'           { $$ = intern_c('-');   }
-                | '*'           { $$ = intern_c('*');   }
-                | tSTAR         { $$ = intern_c('*');   }
-                | '/'           { $$ = intern_c('/');   }
-                | '%'           { $$ = intern_c('%');   }
-                | tPOW          { $$ = intern("**",2);  }
-                | '!'           { $$ = intern_c('!');   }
-                | '~'           { $$ = intern_c('~');   }
-                | tUPLUS        { $$ = intern("+@",2);  }
-                | tUMINUS       { $$ = intern("-@",2);  }
-                | tAREF         { $$ = intern("[]",2);  }
-                | tASET         { $$ = intern("[]=",3); }
-                | '`'           { $$ = intern_c('`');   }
+op              : '|'           { $$ = intern_lit("|");   }
+                | '^'           { $$ = intern_lit("^");   }
+                | '&'           { $$ = intern_lit("&");   }
+                | tCMP          { $$ = intern_lit("<=>"); }
+                | tEQ           { $$ = intern_lit("==");  }
+                | tEQQ          { $$ = intern_lit("==="); }
+                | tMATCH        { $$ = intern_lit("=~");  }
+                | tNMATCH       { $$ = intern_lit("!~");  }
+                | '>'           { $$ = intern_lit(">");   }
+                | tGEQ          { $$ = intern_lit(">=");  }
+                | '<'           { $$ = intern_lit("<");   }
+                | tLEQ          { $$ = intern_lit("<=");  }
+                | tNEQ          { $$ = intern_lit("!=");  }
+                | tLSHFT        { $$ = intern_lit("<<");  }
+                | tRSHFT        { $$ = intern_lit(">>");  }
+                | '+'           { $$ = intern_lit("+");   }
+                | '-'           { $$ = intern_lit("-");   }
+                | '*'           { $$ = intern_lit("*");   }
+                | tSTAR         { $$ = intern_lit("*");   }
+                | '/'           { $$ = intern_lit("/");   }
+                | '%'           { $$ = intern_lit("%");   }
+                | tPOW          { $$ = intern_lit("**");  }
+                | tDSTAR        { $$ = intern_lit("**");  }
+                | '!'           { $$ = intern_lit("!");   }
+                | '~'           { $$ = intern_lit("~");   }
+                | tUPLUS        { $$ = intern_lit("+@");  }
+                | tUMINUS       { $$ = intern_lit("-@");  }
+                | tAREF         { $$ = intern_lit("[]");  }
+                | tASET         { $$ = intern_lit("[]="); }
+                | '`'           { $$ = intern_lit("`");   }
                 ;
 
@@ -1766,7 +2064,7 @@
                       $$ = new_op_asgn(p, $1, $2, $3);
                     }
-                | primary_value '[' opt_call_args rbracket tOP_ASGN arg_rhs
-                    {
-                      $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3, '.'), $5, $6);
+                | primary_value '[' opt_call_args ']' tOP_ASGN arg_rhs
+                    {
+                      $$ = new_op_asgn(p, new_call(p, $1, intern_lit("[]"), $3, '.'), $5, $6);
                     }
                 | primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs
@@ -1925,4 +2223,8 @@
                       $$ = new_if(p, cond($1), $3, $6);
                     }
+                | arg '?' arg opt_nl tLABEL_TAG arg
+                    {
+                      $$ = new_if(p, cond($1), $3, $6);
+                    }
                 | primary
                     {
@@ -1939,9 +2241,9 @@
                 | args comma assocs trailer
                     {
-                      $$ = push($1, new_hash(p, $3));
+                      $$ = push($1, new_kw_hash(p, $3));
                     }
                 | assocs trailer
                     {
-                      $$ = cons(new_hash(p, $1), 0);
+                      $$ = cons(new_kw_hash(p, $1), 0);
                       NODE_LINENO($$, $1);
                     }
@@ -1960,5 +2262,5 @@
                 ;
 
-paren_args      : '(' opt_call_args rparen
+paren_args      : '(' opt_call_args ')'
                     {
                       $$ = $2;
@@ -1971,18 +2273,18 @@
 
 opt_call_args   : none
-                | call_args
-                | args ','
+                | call_args opt_terms
+                | args comma
                     {
                       $$ = cons($1,0);
                       NODE_LINENO($$, $1);
                     }
-                | args comma assocs ','
-                    {
-                      $$ = cons(push($1, new_hash(p, $3)), 0);
+                | args comma assocs comma
+                    {
+                      $$ = cons(push($1, new_kw_hash(p, $3)), 0);
                       NODE_LINENO($$, $1);
                     }
-                | assocs ','
-                    {
-                      $$ = cons(list1(new_hash(p, $1)), 0);
+                | assocs comma
+                    {
+                      $$ = cons(list1(new_kw_hash(p, $1)), 0);
                       NODE_LINENO($$, $1);
                     }
@@ -2002,10 +2304,10 @@
                 | assocs opt_block_arg
                     {
-                      $$ = cons(list1(new_hash(p, $1)), $2);
+                      $$ = cons(list1(new_kw_hash(p, $1)), $2);
                       NODE_LINENO($$, $1);
                     }
                 | args comma assocs opt_block_arg
                     {
-                      $$ = cons(push($1, new_hash(p, $3)), $4);
+                      $$ = cons(push($1, new_kw_hash(p, $3)), $4);
                       NODE_LINENO($$, $1);
                     }
@@ -2045,5 +2347,5 @@
 
 comma           : ','
-                | ','  heredoc_bodies
+                | ','  opt_nl heredoc_bodies
                 ;
 
@@ -2096,4 +2398,8 @@
                 | var_ref
                 | backref
+                | tNUMPARAM
+                    {
+                      $$ = new_nvar(p, $1);
+                    }
                 | tFID
                     {
@@ -2248,4 +2554,5 @@
                         yyerror(p, "class definition in method body");
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   bodystmt
@@ -2255,4 +2562,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>4);
+                      nvars_unnest(p);
                     }
                 | keyword_class
@@ -2265,4 +2573,5 @@
                     {
                       $<nd>$ = cons(local_switch(p), nint(p->in_single));
+                      nvars_block(p);
                       p->in_single = 0;
                     }
@@ -2273,4 +2582,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>6->car);
+                      nvars_unnest(p);
                       p->in_def = $<num>4;
                       p->in_single = intn($<nd>6->cdr);
@@ -2282,4 +2592,5 @@
                         yyerror(p, "module definition in method body");
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   bodystmt
@@ -2289,4 +2600,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>3);
+                      nvars_unnest(p);
                     }
                 | keyword_def fname
@@ -2298,4 +2610,5 @@
                       p->in_def++;
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   f_arglist
@@ -2306,4 +2619,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>4);
+                      nvars_unnest(p);
                       p->in_def--;
                       p->cmdarg_stack = $<stack>3;
@@ -2320,4 +2634,5 @@
                       p->lstate = EXPR_ENDFN; /* force for args */
                       $<nd>$ = local_switch(p);
+                      nvars_block(p);
                     }
                   f_arglist
@@ -2328,4 +2643,5 @@
                       SET_LINENO($$, $1);
                       local_resume(p, $<nd>6);
+                      nvars_unnest(p);
                       p->in_single--;
                       p->cmdarg_stack = $<stack>4;
@@ -2388,41 +2704,22 @@
                 ;
 
-f_marg          : f_norm_arg
-                    {
-                      $$ = new_arg(p, $1);
-                    }
-                | tLPAREN f_margs rparen
-                    {
-                      $$ = new_masgn(p, $2, 0);
-                    }
-                ;
-
-f_marg_list     : f_marg
-                    {
-                      $$ = list1($1);
-                    }
-                | f_marg_list ',' f_marg
-                    {
-                      $$ = push($1, $3);
-                    }
-                ;
-
-f_margs         : f_marg_list
+f_margs         : f_arg
                     {
                       $$ = list3($1,0,0);
                     }
-                | f_marg_list ',' tSTAR f_norm_arg
+                | f_arg ',' tSTAR f_norm_arg
                     {
                       $$ = list3($1, new_arg(p, $4), 0);
                     }
-                | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
+                | f_arg ',' tSTAR f_norm_arg ',' f_arg
                     {
                       $$ = list3($1, new_arg(p, $4), $6);
                     }
-                | f_marg_list ',' tSTAR
-                    {
+                | f_arg ',' tSTAR
+                    {
+                      local_add_f(p, 0);
                       $$ = list3($1, (node*)-1, 0);
                     }
-                | f_marg_list ',' tSTAR ',' f_marg_list
+                | f_arg ',' tSTAR ',' f_arg
                     {
                       $$ = list3($1, (node*)-1, $5);
@@ -2432,5 +2729,5 @@
                       $$ = list3(0, new_arg(p, $2), 0);
                     }
-                | tSTAR f_norm_arg ',' f_marg_list
+                | tSTAR f_norm_arg ',' f_arg
                     {
                       $$ = list3(0, new_arg(p, $2), $4);
@@ -2438,69 +2735,102 @@
                 | tSTAR
                     {
+                      local_add_f(p, 0);
                       $$ = list3(0, (node*)-1, 0);
                     }
-                | tSTAR ',' f_marg_list
-                    {
-                      $$ = list3(0, (node*)-1, $3);
-                    }
-                ;
-
-block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+                | tSTAR ','
+                    {
+                      local_add_f(p, 0);
+                    }
+                  f_arg
+                    {
+                      $$ = list3(0, (node*)-1, $4);
+                    }
+                ;
+
+block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, $3, $4);
+                    }
+                | f_block_kwarg opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, 0, $2);
+                    }
+                | f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, $1, $2);
+                    }
+                | f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, 0, $1);
+                    }
+                ;
+
+opt_block_args_tail : ',' block_args_tail
+                    {
+                      $$ = $2;
+                    }
+                | /* none */
+                    {
+                      $$ = new_args_tail(p, 0, 0, 0);
+                    }
+                ;
+
+block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, 0, $6);
                     }
-                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, $7, $8);
                     }
-                | f_arg ',' f_block_optarg opt_f_block_arg
+                | f_arg ',' f_block_optarg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, 0, $4);
                     }
-                | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, $5, $6);
                     }
-                | f_arg ',' f_rest_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, 0, $4);
                     }
-                | f_arg ','
-                    {
-                      $$ = new_args(p, $1, 0, 0, 0, 0);
-                    }
-                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' opt_block_args_tail
+                    {
+                      $$ = new_args(p, $1, 0, 0, 0, $3);
+                    }
+                | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, $5, $6);
                     }
-                | f_arg opt_f_block_arg
+                | f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, $1, 0, 0, 0, $2);
                     }
-                | f_block_optarg ',' f_rest_arg opt_f_block_arg
+                | f_block_optarg ',' f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, 0, $4);
                     }
-                | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, $5, $6);
                     }
-                | f_block_optarg opt_f_block_arg
+                | f_block_optarg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, 0, $2);
                     }
-                | f_block_optarg ',' f_arg opt_f_block_arg
+                | f_block_optarg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, $3, $4);
                     }
-                | f_rest_arg opt_f_block_arg
+                | f_rest_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, 0, $2);
                     }
-                | f_rest_arg ',' f_arg opt_f_block_arg
+                | f_rest_arg ',' f_arg opt_block_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, $3, $4);
                     }
-                | f_block_arg
+                | block_args_tail
                     {
                       $$ = new_args(p, 0, 0, 0, 0, $1);
@@ -2509,6 +2839,10 @@
 
 opt_block_param : none
+                    {
+                      local_add_blk(p, 0);
+                      $$ = 0;
+                    }
                 | block_param_def
-                    {
+                   {
                       p->cmd_start = TRUE;
                       $$ = $1;
@@ -2516,5 +2850,5 @@
                 ;
 
-block_param_def : '|' opt_bv_decl '|'
+block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|'
                     {
                       $$ = 0;
@@ -2522,4 +2856,5 @@
                 | tOROP
                     {
+                      local_add_blk(p, 0);
                       $$ = 0;
                     }
@@ -2567,5 +2902,5 @@
                       $$ = $2;
                     }
-                | keyword_do_LAMBDA compstmt keyword_end
+                | keyword_do_LAMBDA bodystmt keyword_end
                     {
                       $$ = $2;
@@ -2576,11 +2911,13 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                     }
                   opt_block_param
-                  compstmt
+                  bodystmt
                   keyword_end
                     {
                       $$ = new_block(p,$3,$4);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -2630,9 +2967,9 @@
                 | primary_value call_op paren_args
                     {
-                      $$ = new_call(p, $1, intern("call",4), $3, $2);
+                      $$ = new_call(p, $1, intern_lit("call"), $3, $2);
                     }
                 | primary_value tCOLON2 paren_args
                     {
-                      $$ = new_call(p, $1, intern("call",4), $3, tCOLON2);
+                      $$ = new_call(p, $1, intern_lit("call"), $3, tCOLON2);
                     }
                 | keyword_super paren_args
@@ -2644,7 +2981,7 @@
                       $$ = new_zsuper(p);
                     }
-                | primary_value '[' opt_call_args rbracket
-                    {
-                      $$ = new_call(p, $1, intern("[]",2), $3, '.');
+                | primary_value '[' opt_call_args ']'
+                    {
+                      $$ = new_call(p, $1, intern_lit("[]"), $3, '.');
                     }
                 ;
@@ -2653,4 +2990,5 @@
                     {
                       local_nest(p);
+                      nvars_nest(p);
                       $<num>$ = p->lineno;
                     }
@@ -2661,16 +2999,19 @@
                       SET_LINENO($$, $<num>2);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 | keyword_do
                     {
                       local_nest(p);
+                      nvars_nest(p);
                       $<num>$ = p->lineno;
                     }
                   opt_block_param
-                  compstmt keyword_end
+                  bodystmt keyword_end
                     {
                       $$ = new_block(p,$3,$4);
                       SET_LINENO($$, $<num>2);
                       local_unnest(p);
+                      nvars_unnest(p);
                     }
                 ;
@@ -2734,5 +3075,12 @@
                 ;
 
-string          : tCHAR
+string          : string_fragment
+                | string string_fragment
+                    {
+                      $$ = concat_string(p, $1, $2);
+                    }
+                ;
+
+string_fragment : tCHAR
                 | tSTRING
                 | tSTRING_BEG tSTRING
@@ -2854,10 +3202,11 @@
 symbol          : basic_symbol
                     {
+                      p->lstate = EXPR_ENDARG;
                       $$ = new_sym(p, $1);
                     }
                 | tSYMBEG tSTRING_BEG string_rep tSTRING
                     {
-                      p->lstate = EXPR_END;
-                      $$ = new_dsym(p, push($3, $4));
+                      p->lstate = EXPR_ENDARG;
+                      $$ = new_dsym(p, new_dstr(p, push($3, $4)));
                     }
                 ;
@@ -2865,5 +3214,4 @@
 basic_symbol    : tSYMBEG sym
                     {
-                      p->lstate = EXPR_END;
                       $$ = $2;
                     }
@@ -2932,4 +3280,8 @@
                       assignable(p, $1);
                     }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "can't assign to numbered parameter");
+                    }
                 ;
 
@@ -2956,5 +3308,5 @@
                 | keyword__FILE__
                     {
-                      const char *fn = p->filename;
+                      const char *fn = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
                       if (!fn) {
                         fn = "(null)";
@@ -2966,6 +3318,15 @@
                       char buf[16];
 
-                      snprintf(buf, sizeof(buf), "%d", p->lineno);
-                      $$ = new_int(p, buf, 10);
+                      dump_int(p->lineno, buf);
+                      $$ = new_int(p, buf, 10, 0);
+                    }
+                | keyword__ENCODING__
+                    {
+#ifdef MRB_UTF8_STRING
+                      const char *enc = "UTF-8";
+#else
+                      const char *enc = "ASCII-8BIT";
+#endif
+                      $$ = new_str(p, enc, strlen(enc));
                     }
                 ;
@@ -3007,57 +3368,150 @@
                 ;
 
-f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+f_label         : tIDENTIFIER tLABEL_TAG
+                    {
+                      local_nest(p);
+                    }
+                ;
+
+f_kw            : f_label arg
+                    {
+                      void_expr_error(p, $2);
+                      $$ = new_kw_arg(p, $1, cons($2, locals_node(p)));
+                      local_unnest(p);
+                    }
+                | f_label
+                    {
+                      $$ = new_kw_arg(p, $1, 0);
+                      local_unnest(p);
+                    }
+                ;
+
+f_block_kw      : f_label primary_value
+                    {
+                      $$ = new_kw_arg(p, $1, cons($2, locals_node(p)));
+                      local_unnest(p);
+                    }
+                | f_label
+                    {
+                      $$ = new_kw_arg(p, $1, 0);
+                      local_unnest(p);
+                    }
+                ;
+
+f_block_kwarg   : f_block_kw
+                    {
+                      $$ = list1($1);
+                    }
+                | f_block_kwarg ',' f_block_kw
+                    {
+                      $$ = push($1, $3);
+                    }
+                ;
+
+f_kwarg         : f_kw
+                    {
+                      $$ = list1($1);
+                    }
+                | f_kwarg ',' f_kw
+                    {
+                      $$ = push($1, $3);
+                    }
+                ;
+
+kwrest_mark     : tPOW
+                | tDSTAR
+                ;
+
+f_kwrest        : kwrest_mark tIDENTIFIER
+                    {
+                      $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2));
+                    }
+                | kwrest_mark
+                    {
+                      $$ = cons((node*)NODE_KW_REST_ARGS, 0);
+                    }
+                ;
+
+args_tail       : f_kwarg ',' f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, $3, $4);
+                    }
+                | f_kwarg opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, $1, 0, $2);
+                    }
+                | f_kwrest opt_f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, $1, $2);
+                    }
+                | f_block_arg
+                    {
+                      $$ = new_args_tail(p, 0, 0, $1);
+                    }
+                ;
+
+opt_args_tail   : ',' args_tail
+                    {
+                      $$ = $2;
+                    }
+                | /* none */
+                    {
+                      $$ = new_args_tail(p, 0, 0, 0);
+                    }
+                ;
+
+f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, 0, $6);
                     }
-                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, $5, $7, $8);
                     }
-                | f_arg ',' f_optarg opt_f_block_arg
+                | f_arg ',' f_optarg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, 0, $4);
                     }
-                | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_optarg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, $3, 0, $5, $6);
                     }
-                | f_arg ',' f_rest_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, 0, $4);
                     }
-                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, $3, $5, $6);
                     }
-                | f_arg opt_f_block_arg
+                | f_arg opt_args_tail
                     {
                       $$ = new_args(p, $1, 0, 0, 0, $2);
                     }
-                | f_optarg ',' f_rest_arg opt_f_block_arg
+                | f_optarg ',' f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, 0, $4);
                     }
-                | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+                | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, $3, $5, $6);
                     }
-                | f_optarg opt_f_block_arg
+                | f_optarg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, 0, $2);
                     }
-                | f_optarg ',' f_arg opt_f_block_arg
+                | f_optarg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, $1, 0, $3, $4);
                     }
-                | f_rest_arg opt_f_block_arg
+                | f_rest_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, 0, $2);
                     }
-                | f_rest_arg ',' f_arg opt_f_block_arg
+                | f_rest_arg ',' f_arg opt_args_tail
                     {
                       $$ = new_args(p, 0, 0, $1, $3, $4);
                     }
-                | f_block_arg
+                | args_tail
                     {
                       $$ = new_args(p, 0, 0, 0, 0, $1);
@@ -3065,5 +3519,5 @@
                 | /* none */
                     {
-                      local_add_f(p, 0);
+                      local_add_f(p, mrb_intern_lit(p->mrb, "&"));
                       $$ = new_args(p, 0, 0, 0, 0, 0);
                     }
@@ -3090,4 +3544,9 @@
                       $$ = 0;
                     }
+                | tNUMPARAM
+                    {
+                      yyerror(p, "formal argument cannot be a numbered parameter");
+                      $$ = 0;
+                    }
                 ;
 
@@ -3107,7 +3566,13 @@
                       $$ = new_arg(p, $1);
                     }
-                | tLPAREN f_margs rparen
-                    {
-                      $$ = new_masgn(p, $2, 0);
+                | tLPAREN
+                    {
+                      $<nd>$ = local_switch(p);
+                    }
+                  f_margs rparen
+                    {
+                      $$ = new_masgn_param(p, $3, p->locals->car);
+                      local_resume(p, $<nd>2);
+                      local_add_f(p, 0);
                     }
                 ;
@@ -3126,4 +3591,5 @@
                     {
                       local_add_f(p, $1);
+                      local_nest(p);
                       $$ = $1;
                     }
@@ -3133,5 +3599,6 @@
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(nsym($1), $2);
+                      $$ = cons(nsym($1), cons($2, locals_node(p)));
+                      local_unnest(p);
                     }
                 ;
@@ -3140,5 +3607,6 @@
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(nsym($1), $2);
+                      $$ = cons(nsym($1), cons($2, locals_node(p)));
+                      local_unnest(p);
                     }
                 ;
@@ -3175,5 +3643,5 @@
                 | restarg_mark
                     {
-                      local_add_f(p, 0);
+                      local_add_f(p, mrb_intern_lit(p->mrb, "*"));
                       $$ = -1;
                     }
@@ -3186,5 +3654,4 @@
 f_block_arg     : blkarg_mark tIDENTIFIER
                     {
-                      local_add_f(p, $2);
                       $$ = $2;
                     }
@@ -3197,5 +3664,4 @@
                 | none
                     {
-                      local_add_f(p, 0);
                       $$ = 0;
                     }
@@ -3244,8 +3710,12 @@
                       NODE_LINENO($$, $1);
                     }
-                | assocs ',' assoc
+                | assocs comma assoc
                     {
                       $$ = push($1, $3);
                     }
+                ;
+
+label_tag       : tLABEL_TAG
+                | tLABEL_TAG heredoc_bodies
                 ;
 
@@ -3256,23 +3726,23 @@
                       $$ = cons($1, $3);
                     }
-                | tLABEL arg
+                | tIDENTIFIER label_tag arg
+                    {
+                      void_expr_error(p, $3);
+                      $$ = cons(new_sym(p, $1), $3);
+                    }
+                | string_fragment label_tag arg
+                    {
+                      void_expr_error(p, $3);
+                      if ($1->car == (node*)NODE_DSTR) {
+                        $$ = cons(new_dsym(p, $1), $3);
+                      }
+                      else {
+                        $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
+                      }
+                    }
+                | tDSTAR arg
                     {
                       void_expr_error(p, $2);
-                      $$ = cons(new_sym(p, $1), $2);
-                    }
-                | tLABEL_END arg
-                    {
-                      void_expr_error(p, $2);
-                      $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
-                    }
-                | tSTRING_BEG tLABEL_END arg
-                    {
-                      void_expr_error(p, $3);
-                      $$ = cons(new_sym(p, new_strsym(p, $2)), $3);
-                    }
-                | tSTRING_BEG string_rep tLABEL_END arg
-                    {
-                      void_expr_error(p, $4);
-                      $$ = cons(new_dsym(p, push($2, $3)), $4);
+                      $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
                     }
                 ;
@@ -3323,12 +3793,9 @@
                 ;
 
-rparen          : opt_nl ')'
-                ;
-
-rbracket        : opt_nl ']'
+rparen          : opt_terms ')'
                 ;
 
 trailer         : /* none */
-                | nl
+                | terms
                 | comma
                 ;
@@ -3362,10 +3829,11 @@
 {
   char* c;
-  int n;
+  size_t n;
 
   if (! p->capture_errors) {
 #ifndef MRB_DISABLE_STDIO
-    if (p->filename) {
-      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+    if (p->filename_sym) {
+      const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+      fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s);
     }
     else {
@@ -3386,9 +3854,11 @@
 
 static void
-yyerror_i(parser_state *p, const char *fmt, int i)
+yyerror_c(parser_state *p, const char *msg, char c)
 {
   char buf[256];
 
-  snprintf(buf, sizeof(buf), fmt, i);
+  strncpy(buf, msg, sizeof(buf) - 2);
+  buf[sizeof(buf) - 2] = '\0';
+  strncat(buf, &c, 1);
   yyerror(p, buf);
 }
@@ -3398,13 +3868,14 @@
 {
   char* c;
-  int n;
+  size_t n;
 
   if (! p->capture_errors) {
 #ifndef MRB_DISABLE_STDIO
-    if (p->filename) {
-      fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s);
+    if (p->filename_sym) {
+      const char *filename = mrb_sym_name_len(p->mrb, p->filename_sym, NULL);
+      fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s);
     }
     else {
-      fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s);
+      fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s);
     }
 #endif
@@ -3428,9 +3899,12 @@
 
 static void
-yywarning_s(parser_state *p, const char *fmt, const char *s)
+yywarning_s(parser_state *p, const char *msg, const char *s)
 {
   char buf[256];
 
-  snprintf(buf, sizeof(buf), fmt, s);
+  strncpy(buf, msg, sizeof(buf) - 1);
+  buf[sizeof(buf) - 1] = '\0';
+  strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1);
+  strncat(buf, s, sizeof(buf) - strlen(buf) - 1);
   yywarning(p, buf);
 }
@@ -3441,14 +3915,14 @@
   int c;
 
-  c = (int)(intptr_t)n->car;
+  c = intn(n->car);
 
   if (c == NODE_NTH_REF) {
-    yyerror_i(p, "can't set variable $%" MRB_PRId, (mrb_int)(intptr_t)n->cdr);
+    yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0');
   }
   else if (c == NODE_BACK_REF) {
-    yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
+    yyerror_c(p, "can't set variable $", (char)intn(n->cdr));
   }
   else {
-    mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
+    mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %d", c);
   }
 }
@@ -3460,5 +3934,5 @@
 
   if (n == NULL) return;
-  c = (int)(intptr_t)n->car;
+  c = intn(n->car);
   switch (c) {
   case NODE_BREAK:
@@ -3471,6 +3945,8 @@
   case NODE_AND:
   case NODE_OR:
-    void_expr_error(p, n->cdr->car);
-    void_expr_error(p, n->cdr->cdr);
+    if (n->cdr) {
+      void_expr_error(p, n->cdr->car);
+      void_expr_error(p, n->cdr->cdr);
+    }
     break;
   case NODE_BEGIN:
@@ -3492,4 +3968,25 @@
 
 static inline int
+nextc0(parser_state *p)
+{
+  int c;
+#ifndef MRB_DISABLE_STDIO
+  if (p->f) {
+    if (feof(p->f)) return -1;
+    c = fgetc(p->f);
+    if (c == EOF) return -1;
+  }
+  else
+#endif
+    if (!p->s || p->s >= p->send) {
+      return -1;
+    }
+    else {
+      c = (unsigned char)*p->s++;
+    }
+  return c;
+}
+
+static inline int
 nextc(parser_state *p)
 {
@@ -3499,5 +3996,5 @@
     node *tmp;
 
-    c = (int)(intptr_t)p->pb->car;
+    c = intn(p->pb->car);
     tmp = p->pb;
     p->pb = p->pb->cdr;
@@ -3505,18 +4002,6 @@
   }
   else {
-#ifndef MRB_DISABLE_STDIO
-    if (p->f) {
-      if (feof(p->f)) goto eof;
-      c = fgetc(p->f);
-      if (c == EOF) goto eof;
-    }
-    else
-#endif
-      if (!p->s || p->s >= p->send) {
-        goto eof;
-      }
-      else {
-        c = (unsigned char)*p->s++;
-      }
+    c = nextc0(p);
+    if (c < 0) goto eof;
   }
   if (c >= 0) {
@@ -3524,10 +4009,9 @@
   }
   if (c == '\r') {
-    c = nextc(p);
-    if (c != '\n') {
-      pushback(p, c);
-      return '\r';
-    }
-    return c;
+    const int lf = nextc0(p);
+    if (lf == '\n') {
+      return '\n';
+    }
+    if (lf > 0) pushback(p, lf);
   }
   return c;
@@ -3548,5 +4032,5 @@
     p->column--;
   }
-  p->pb = cons((node*)(intptr_t)c, p->pb);
+  p->pb = cons(nint(c), p->pb);
 }
 
@@ -3573,5 +4057,5 @@
     if (c0 == -1) return c0;    /* do not skip partial EOF */
     if (c0 >= 0) --p->column;
-    list = push(list, (node*)(intptr_t)c0);
+    list = push(list, nint(c0));
   } while(n--);
   if (p->pb) {
@@ -3594,5 +4078,5 @@
 peeks(parser_state *p, const char *s)
 {
-  int len = strlen(s);
+  size_t len = strlen(s);
 
 #ifndef MRB_DISABLE_STDIO
@@ -3630,5 +4114,5 @@
     s++;
     if (peeks(p, s)) {
-      int len = strlen(s);
+      size_t len = strlen(s);
 
       while (len--) {
@@ -3752,9 +4236,9 @@
 #define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
 
-static int
+static int32_t
 scan_oct(const int *start, int len, int *retlen)
 {
   const int *s = start;
-  int retval = 0;
+  int32_t retval = 0;
 
   /* mrb_assert(len <= 3) */
@@ -3763,5 +4247,5 @@
     retval |= *s++ - '0';
   }
-  *retlen = s - start;
+  *retlen = (int)(s - start);
 
   return retval;
@@ -3769,9 +4253,9 @@
 
 static int32_t
-scan_hex(const int *start, int len, int *retlen)
+scan_hex(parser_state *p, const int *start, int len, int *retlen)
 {
   static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
   const int *s = start;
-  int32_t retval = 0;
+  uint32_t retval = 0;
   char *tmp;
 
@@ -3782,7 +4266,7 @@
     s++;
   }
-  *retlen = s - start;
-
-  return retval;
+  *retlen = (int)(s - start);
+
+  return (int32_t)retval;
 }
 
@@ -3790,12 +4274,16 @@
 read_escape_unicode(parser_state *p, int limit)
 {
-  int32_t c;
   int buf[9];
   int i;
+  int32_t hex;
 
   /* Look for opening brace */
   i = 0;
   buf[0] = nextc(p);
-  if (buf[0] < 0) goto eof;
+  if (buf[0] < 0) {
+  eof:
+    yyerror(p, "invalid escape character syntax");
+    return -1;
+  }
   if (ISXDIGIT(buf[0])) {
     /* \uxxxx form */
@@ -3812,15 +4300,10 @@
     pushback(p, buf[0]);
   }
-  c = scan_hex(buf, i, &i);
-  if (i == 0) {
-  eof:
-    yyerror(p, "Invalid escape character syntax");
+  hex = scan_hex(p, buf, i, &i);
+  if (i == 0 || hex > 0x10FFFF || (hex & 0xFFFFF800) == 0xD800) {
+    yyerror(p, "invalid Unicode code point");
     return -1;
   }
-  if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
-    yyerror(p, "Invalid Unicode code point");
-    return -1;
-  }
-  return c;
+  return hex;
 }
 
@@ -3888,11 +4371,10 @@
       }
     }
-    c = scan_hex(buf, i, &i);
     if (i == 0) {
-      yyerror(p, "Invalid escape character syntax");
-      return 0;
-    }
-  }
-  return c;
+      yyerror(p, "invalid hex escape");
+      return -1;
+    }
+    return scan_hex(p, buf, i, &i);
+  }
 
   case 'u':     /* Unicode */
@@ -3961,9 +4443,8 @@
   int c;
   string_type type = (string_type)(intptr_t)p->lex_strterm->car;
-  int nest_level = (intptr_t)p->lex_strterm->cdr->car;
-  int beg = (intptr_t)p->lex_strterm->cdr->cdr->car;
-  int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr;
+  int nest_level = intn(p->lex_strterm->cdr->car);
+  int beg = intn(p->lex_strterm->cdr->cdr->car);
+  int end = intn(p->lex_strterm->cdr->cdr->cdr);
   parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
-  int cmd_state = p->cmd_start;
 
   if (beg == 0) beg = -3;       /* should never happen */
@@ -3990,16 +4471,20 @@
         }
         if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) {
-          if (c < 0) {
-            p->parsing_heredoc = NULL;
-          }
-          else {
-            return tHEREDOC_END;
-          }
+          return tHEREDOC_END;
         }
       }
       if (c < 0) {
         char buf[256];
-        snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term);
-        yyerror(p, buf);
+        const char s1[] = "can't find heredoc delimiter \"";
+        const char s2[] = "\" anywhere before EOF";
+
+        if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) {
+          yyerror(p, "can't find heredoc delimiter anywhere before EOF");
+        } else {
+          strcpy(buf, s1);
+          strcat(buf, hinf->term);
+          strcat(buf, s2);
+          yyerror(p, buf);
+        }
         return 0;
       }
@@ -4013,9 +4498,9 @@
     else if (c == beg) {
       nest_level++;
-      p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+      p->lex_strterm->cdr->car = nint(nest_level);
     }
     else if (c == end) {
       nest_level--;
-      p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+      p->lex_strterm->cdr->car = nint(nest_level);
     }
     else if (c == '\\') {
@@ -4119,5 +4604,5 @@
 
   tokfix(p);
-  p->lstate = EXPR_END;
+  p->lstate = EXPR_ENDARG;
   end_strterm(p);
 
@@ -4145,4 +4630,5 @@
       case 'u': f |= 16; break;
       case 'n': f |= 32; break;
+      case 'o': break;
       default: tokadd(p, re_opt); break;
       }
@@ -4151,7 +4637,12 @@
     if (toklen(p)) {
       char msg[128];
+
+      strcpy(msg, "unknown regexp option");
       tokfix(p);
-      snprintf(msg, sizeof(msg), "unknown regexp option%s - %s",
-          toklen(p) > 1 ? "s" : "", tok(p));
+      if (toklen(p) > 1) {
+        strcat(msg, "s");
+      }
+      strcat(msg, " - ");
+      strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1);
       yyerror(p, msg);
     }
@@ -4180,15 +4671,46 @@
   }
   pylval.nd = new_str(p, tok(p), toklen(p));
-  if (IS_LABEL_POSSIBLE()) {
-    if (IS_LABEL_SUFFIX(0)) {
-      p->lstate = EXPR_BEG;
-      nextc(p);
-      return tLABEL_END;
-    }
-  }
 
   return tSTRING;
 }
 
+static int
+number_literal_suffix(parser_state *p)
+{
+  int c, result = 0;
+  node *list = 0;
+  int column = p->column;
+  int mask = NUM_SUFFIX_R|NUM_SUFFIX_I;
+
+  while ((c = nextc(p)) != -1) {
+    list = push(list, (node*)(intptr_t)c);
+
+    if ((mask & NUM_SUFFIX_I) && c == 'i') {
+      result |= (mask & NUM_SUFFIX_I);
+      mask &= ~NUM_SUFFIX_I;
+      /* r after i, rational of complex is disallowed */
+      mask &= ~NUM_SUFFIX_R;
+      continue;
+    }
+    if ((mask & NUM_SUFFIX_R) && c == 'r') {
+      result |= (mask & NUM_SUFFIX_R);
+      mask &= ~NUM_SUFFIX_R;
+      continue;
+    }
+    if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+      p->column = column;
+      if (p->pb) {
+        p->pb = append((node*)list, p->pb);
+      }
+      else {
+        p->pb = list;
+      }
+      return 0;
+    }
+    pushback(p, c);
+    break;
+  }
+  return result;
+}
 
 static int
@@ -4311,64 +4833,87 @@
   case -2:      /* end of a file */
   case '\n':
-    maybe_heredoc:
+  maybe_heredoc:
     heredoc_treat_nextline(p);
-  switch (p->lstate) {
-  case EXPR_BEG:
-  case EXPR_FNAME:
-  case EXPR_DOT:
-  case EXPR_CLASS:
-  case EXPR_VALUE:
-    p->lineno++;
     p->column = 0;
+    switch (p->lstate) {
+    case EXPR_BEG:
+    case EXPR_FNAME:
+    case EXPR_DOT:
+    case EXPR_CLASS:
+    case EXPR_VALUE:
+      p->lineno++;
+      if (p->parsing_heredoc != NULL) {
+        if (p->lex_strterm) {
+          return parse_string(p);
+        }
+      }
+      goto retry;
+    default:
+      break;
+    }
     if (p->parsing_heredoc != NULL) {
-      if (p->lex_strterm) {
-        return parse_string(p);
-      }
-    }
-    goto retry;
-  default:
-    break;
-  }
-  if (p->parsing_heredoc != NULL) {
+      return '\n';
+    }
+    while ((c = nextc(p))) {
+      switch (c) {
+      case ' ': case '\t': case '\f': case '\r':
+      case '\13': /* '\v' */
+        space_seen = 1;
+        break;
+      case '#': /* comment as a whitespace */
+        pushback(p, '#');
+        p->lineno++;
+        goto retry;
+      case '.':
+        if (!peek(p, '.')) {
+          pushback(p, '.');
+          p->lineno++;
+          goto retry;
+        }
+        pushback(p, c);
+        goto normal_newline;
+      case '&':
+        if (peek(p, '.')) {
+          pushback(p, '&');
+          p->lineno++;
+          goto retry;
+        }
+        pushback(p, c);
+        goto normal_newline;
+      case -1:                  /* EOF */
+      case -2:                  /* end of a file */
+        goto normal_newline;
+      default:
+        pushback(p, c);
+        goto normal_newline;
+      }
+    }
+  normal_newline:
+    p->cmd_start = TRUE;
+    p->lstate = EXPR_BEG;
     return '\n';
-  }
-  while ((c = nextc(p))) {
-    switch (c) {
-    case ' ': case '\t': case '\f': case '\r':
-    case '\13': /* '\v' */
-      space_seen = 1;
-      break;
-    case '.':
-      if ((c = nextc(p)) != '.') {
-        pushback(p, c);
-        pushback(p, '.');
-        goto retry;
-      }
-    case -1:                  /* EOF */
-    case -2:                  /* end of a file */
-      goto normal_newline;
-    default:
-      pushback(p, c);
-      goto normal_newline;
-    }
-  }
-  normal_newline:
-  p->cmd_start = TRUE;
-  p->lstate = EXPR_BEG;
-  return '\n';
 
   case '*':
     if ((c = nextc(p)) == '*') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("**",2);
+        pylval.id = intern_lit("**");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
       }
       pushback(p, c);
-      c = tPOW;
+      if (IS_SPCARG(c)) {
+        yywarning(p, "'**' interpreted as argument prefix");
+        c = tDSTAR;
+      }
+      else if (IS_BEG()) {
+        c = tDSTAR;
+      }
+      else {
+        c = tPOW; /* "**", "argument prefix" */
+      }
     }
     else {
       if (c == '=') {
-        pylval.id = intern_c('*');
+        pylval.id = intern_lit("*");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4486,5 +5031,5 @@
     if (c == '<') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("<<",2);
+        pylval.id = intern_lit("<<");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4508,5 +5053,5 @@
     if (c == '>') {
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern(">>",2);
+        pylval.id = intern_lit(">>");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4579,5 +5124,8 @@
         if (c2) {
           char buf[256];
-          snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2);
+          char cc[] = { (char)c2, '\0' };
+
+          strcpy(buf, "invalid character syntax; use ?\\");
+          strncat(buf, cc, 2);
           yyerror(p, buf);
         }
@@ -4590,8 +5138,8 @@
     newtok(p);
     /* need support UTF-8 if configured */
-    if ((isalnum(c) || c == '_')) {
+    if ((ISALNUM(c) || c == '_')) {
       int c2 = nextc(p);
       pushback(p, c2);
-      if ((isalnum(c2) || c2 == '_')) {
+      if ((ISALNUM(c2) || c2 == '_')) {
         goto ternary;
       }
@@ -4606,5 +5154,5 @@
     tokfix(p);
     pylval.nd = new_str(p, tok(p), toklen(p));
-    p->lstate = EXPR_END;
+    p->lstate = EXPR_ENDARG;
     return tCHAR;
 
@@ -4613,5 +5161,5 @@
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("&&",2);
+        pylval.id = intern_lit("&&");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4625,5 +5173,5 @@
     }
     else if (c == '=') {
-      pylval.id = intern_c('&');
+      pylval.id = intern_lit("&");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4652,5 +5200,5 @@
       p->lstate = EXPR_BEG;
       if ((c = nextc(p)) == '=') {
-        pylval.id = intern("||",2);
+        pylval.id = intern_lit("||");
         p->lstate = EXPR_BEG;
         return tOP_ASGN;
@@ -4660,5 +5208,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('|');
+      pylval.id = intern_lit("|");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4684,5 +5232,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('+');
+      pylval.id = intern_lit("+");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4712,5 +5260,5 @@
     }
     if (c == '=') {
-      pylval.id = intern_c('-');
+      pylval.id = intern_lit("-");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -4753,7 +5301,8 @@
   {
     int is_float, seen_point, seen_e, nondigit;
+    int suffix = 0;
 
     is_float = seen_point = seen_e = nondigit = 0;
-    p->lstate = EXPR_END;
+    p->lstate = EXPR_ENDARG;
     newtok(p);
     if (c == '-' || c == '+') {
@@ -4786,5 +5335,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 16);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 16, suffix);
         return tINTEGER;
       }
@@ -4810,5 +5360,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 2);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 2, suffix);
         return tINTEGER;
       }
@@ -4834,5 +5385,6 @@
         }
         else if (nondigit) goto trailing_uc;
-        pylval.nd = new_int(p, tok(p), 10);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, tok(p), 10, suffix);
         return tINTEGER;
       }
@@ -4867,5 +5419,6 @@
           tokfix(p);
           if (nondigit) goto trailing_uc;
-          pylval.nd = new_int(p, tok(p), 8);
+          suffix = number_literal_suffix(p);
+          pylval.nd = new_int(p, tok(p), 8, suffix);
           return tINTEGER;
         }
@@ -4884,5 +5437,6 @@
       else {
         pushback(p, c);
-        pylval.nd = new_int(p, "0", 10);
+        suffix = number_literal_suffix(p);
+        pylval.nd = new_int(p, "0", 10, suffix);
         return tINTEGER;
       }
@@ -4952,8 +5506,13 @@
     if (nondigit) {
       trailing_uc:
-      yyerror_i(p, "trailing '%c' in number", nondigit);
+      yyerror_c(p, "trailing non digit in number: ", (char)nondigit);
     }
     tokfix(p);
     if (is_float) {
+#ifdef MRB_WITHOUT_FLOAT
+      yywarning_s(p, "floating point numbers are not supported", tok(p));
+      pylval.nd = new_int(p, "0", 10, 0);
+      return tINTEGER;
+#else
       double d;
       char *endp;
@@ -4962,14 +5521,17 @@
       d = mrb_float_read(tok(p), &endp);
       if (d == 0 && endp == tok(p)) {
-        yywarning_s(p, "corrupted float value %s", tok(p));
+        yywarning_s(p, "corrupted float value", tok(p));
       }
       else if (errno == ERANGE) {
-        yywarning_s(p, "float %s out of range", tok(p));
+        yywarning_s(p, "float out of range", tok(p));
         errno = 0;
       }
-      pylval.nd = new_float(p, tok(p));
+      suffix = number_literal_suffix(p);
+      pylval.nd = new_float(p, tok(p), suffix);
       return tFLOAT;
-    }
-    pylval.nd = new_int(p, tok(p), 10);
+#endif
+    }
+    suffix = number_literal_suffix(p);
+    pylval.nd = new_int(p, tok(p), 10, suffix);
     return tINTEGER;
   }
@@ -4985,5 +5547,5 @@
       p->lstate = EXPR_ENDFN;
     else
-      p->lstate = EXPR_ENDARG;
+      p->lstate = EXPR_END;
     return c;
 
@@ -4998,12 +5560,17 @@
       return tCOLON2;
     }
-    if (IS_END() || ISSPACE(c)) {
+    if (!space_seen && IS_END()) {
       pushback(p, c);
       p->lstate = EXPR_BEG;
-      return ':';
+      return tLABEL_TAG;
+    }
+    if (!ISSPACE(c) || IS_BEG()) {
+      pushback(p, c);
+      p->lstate = EXPR_FNAME;
+      return tSYMBEG;
     }
     pushback(p, c);
-    p->lstate = EXPR_FNAME;
-    return tSYMBEG;
+    p->lstate = EXPR_BEG;
+    return ':';
 
   case '/':
@@ -5013,5 +5580,5 @@
     }
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('/');
+      pylval.id = intern_lit("/");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5032,5 +5599,5 @@
   case '^':
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('^');
+      pylval.id = intern_lit("^");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5070,4 +5637,7 @@
     }
     else if (IS_SPCARG(-1)) {
+      c = tLPAREN_ARG;
+    }
+    else if (p->lstate == EXPR_END && space_seen) {
       c = tLPAREN_ARG;
     }
@@ -5147,5 +5717,5 @@
       else {
         term = nextc(p);
-        if (isalnum(term)) {
+        if (ISALNUM(term)) {
           yyerror(p, "unknown type of %string");
           return 0;
@@ -5206,5 +5776,5 @@
     }
     if ((c = nextc(p)) == '=') {
-      pylval.id = intern_c('%');
+      pylval.id = intern_lit("%");
       p->lstate = EXPR_BEG;
       return tOP_ASGN;
@@ -5260,5 +5830,5 @@
       tokadd(p, c);
       tokfix(p);
-      pylval.id = intern_cstr(tok(p));
+      pylval.id = intern(tok(p), toklen(p));
       return tGVAR;
 
@@ -5270,5 +5840,5 @@
       gvar:
       tokfix(p);
-      pylval.id = intern_cstr(tok(p));
+      pylval.id = intern(tok(p), toklen(p));
       return tGVAR;
 
@@ -5291,5 +5861,5 @@
         tokadd(p, c);
         c = nextc(p);
-      } while (c >= 0 && isdigit(c));
+      } while (c >= 0 && ISDIGIT(c));
       pushback(p, c);
       if (last_state == EXPR_FNAME) goto gvar;
@@ -5298,5 +5868,5 @@
         unsigned long n = strtoul(tok(p), NULL, 10);
         if (n > INT_MAX) {
-          yyerror_i(p, "capture group index must be <= %d", INT_MAX);
+          yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX));
           return 0;
         }
@@ -5333,10 +5903,10 @@
         return 0;
       }
-      else if (isdigit(c)) {
+      else if (ISDIGIT(c)) {
         if (p->tidx == 1) {
-          yyerror_i(p, "'@%c' is not allowed as an instance variable name", c);
+          yyerror_c(p, "wrong instance variable name: @", c);
         }
         else {
-          yyerror_i(p, "'@@%c' is not allowed as a class variable name", c);
+          yyerror_c(p, "wrong class variable name: @@", c);
         }
         return 0;
@@ -5354,5 +5924,13 @@
     default:
       if (!identchar(c)) {
-        yyerror_i(p,  "Invalid char '\\x%02X' in expression", c);
+        char buf[36];
+        const char s[] = "Invalid char in expression: 0x";
+        const char hexdigits[] = "0123456789ABCDEF";
+
+        strcpy(buf, s);
+        buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4];
+        buf[sizeof(s)]   = hexdigits[(c & 0x0f)];
+        buf[sizeof(s)+1] = 0;
+        yyerror(p, buf);
         goto retry;
       }
@@ -5400,4 +5978,37 @@
       break;
 
+    case '_':
+      if (toklen(p) == 2 && ISDIGIT(tok(p)[1]) && p->nvars) {
+        int n = tok(p)[1] - '0';
+        int nvar;
+
+        if (n > 0) {
+          node *nvars = p->nvars->cdr;
+
+          while (nvars) {
+            nvar = intn(nvars->car);
+            if (nvar == -2) break; /* top of the scope */
+            if (nvar > 0) {
+              yywarning(p, "numbered parameter used in outer block");
+              break;
+            }
+            nvars->car = nint(-1);
+            nvars = nvars->cdr;
+          }
+          nvar = intn(p->nvars->car);
+          if (nvar == -1) {
+            yywarning(p, "numbered parameter used in inner block");
+          }
+          if (nvar >= -1) {
+            pylval.num = n;
+            p->lstate = EXPR_END;
+            return tNUMPARAM;
+          }
+          else {
+            yywarning(p, "identifier for numbered parameter; consider another name");
+          }
+        }
+      }
+      /* fall through */
     default:
       if (toklast(p) == '!' || toklast(p) == '?') {
@@ -5406,4 +6017,13 @@
       else {
         if (p->lstate == EXPR_FNAME) {
+          if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
+              (!peek(p, '=') || (peek_n(p, '>', 1)))) {
+            result = tIDENTIFIER;
+            tokadd(p, c);
+            tokfix(p);
+          }
+          else {
+            pushback(p, c);
+          }
           if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') &&
               (!peek(p, '=') || (peek_n(p, '>', 1)))) {
@@ -5426,9 +6046,8 @@
       if (IS_LABEL_POSSIBLE()) {
         if (IS_LABEL_SUFFIX(0)) {
-          p->lstate = EXPR_BEG;
-          nextc(p);
+          p->lstate = EXPR_END;
           tokfix(p);
-          pylval.id = intern_cstr(tok(p));
-          return tLABEL;
+          pylval.id = intern(tok(p), toklen(p));
+          return tIDENTIFIER;
         }
       }
@@ -5488,12 +6107,10 @@
     }
     {
-      mrb_sym ident = intern_cstr(tok(p));
+      mrb_sym ident = intern(tok(p), toklen(p));
 
       pylval.id = ident;
-#if 0
-      if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
+      if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) {
         p->lstate = EXPR_END;
       }
-#endif
     }
     return result;
@@ -5524,4 +6141,5 @@
   p->capture_errors = cxt->capture_errors;
   p->no_optimize = cxt->no_optimize;
+  p->on_eval = cxt->on_eval;
   if (cxt->partial_hook) {
     p->cxt = cxt;
@@ -5536,5 +6154,5 @@
 
   if (!cxt) return;
-  if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return;
+  if (intn(p->tree->car) != NODE_SCOPE) return;
   n0 = n = p->tree->cdr->car;
   while (n) {
@@ -5559,5 +6177,5 @@
 
   MRB_TRY(p->jmp) {
-    int n;
+    int n = 1;
 
     p->cmd_start = TRUE;
@@ -5675,5 +6293,5 @@
 {
   if (s) {
-    int len = strlen(s);
+    size_t len = strlen(s);
     char *p = (char *)mrb_malloc(mrb, len + 1);
 
@@ -5702,19 +6320,23 @@
 
   sym = mrb_intern_cstr(p->mrb, f);
-  p->filename = mrb_sym2name_len(p->mrb, sym, NULL);
+  p->filename_sym = sym;
   p->lineno = (p->filename_table_length > 0)? 0 : 1;
 
   for (i = 0; i < p->filename_table_length; ++i) {
     if (p->filename_table[i] == sym) {
-      p->current_filename_index = i;
+      p->current_filename_index = (int)i;
       return;
     }
   }
 
+  if (p->filename_table_length == UINT16_MAX) {
+    yyerror(p, "too many files to compile");
+    return;
+  }
   p->current_filename_index = p->filename_table_length++;
 
   new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
   if (p->filename_table) {
-    memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
+    memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->current_filename_index);
   }
   p->filename_table = new_table;
@@ -5722,9 +6344,9 @@
 }
 
-MRB_API char const*
+MRB_API mrb_sym
 mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
-  if (idx >= p->filename_table_length) { return NULL; }
+  if (idx >= p->filename_table_length) return 0;
   else {
-    return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL);
+    return p->filename_table[idx];
   }
 }
@@ -5747,5 +6369,5 @@
 
 MRB_API parser_state*
-mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c)
+mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
 {
   parser_state *p;
@@ -5778,11 +6400,13 @@
   }
   if (!p->tree || p->nerr) {
+    if (c) c->parser_nerr = p->nerr;
     if (p->capture_errors) {
       char buf[256];
-      int n;
-
-      n = snprintf(buf, sizeof(buf), "line %d: %s\n",
-          p->error_buffer[0].lineno, p->error_buffer[0].message);
-      mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n));
+
+      strcpy(buf, "line ");
+      dump_int(p->error_buffer[0].lineno, buf+5);
+      strcat(buf, ": ");
+      strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1);
+      mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf)));
       mrb_parser_free(p);
       return mrb_undef_value();
@@ -5817,5 +6441,5 @@
     }
   }
-  proc->target_class = target;
+  MRB_PROC_SET_TARGET_CLASS(proc, target);
   if (mrb->c->ci) {
     mrb->c->ci->target_class = target;
@@ -5841,5 +6465,5 @@
 
 MRB_API mrb_value
-mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
+mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
 {
   return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
@@ -5847,5 +6471,5 @@
 
 MRB_API mrb_value
-mrb_load_nstring(mrb_state *mrb, const char *s, int len)
+mrb_load_nstring(mrb_state *mrb, const char *s, size_t len)
 {
   return mrb_load_nstring_cxt(mrb, s, len, NULL);
@@ -5885,4 +6509,68 @@
 }
 
+static void
+dump_args(mrb_state *mrb, node *n, int offset)
+{
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("mandatory args:\n");
+    dump_recur(mrb, n->car, offset+2);
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("optional args:\n");
+    {
+      node *n2 = n->car;
+
+      while (n2) {
+        dump_prefix(n2, offset+2);
+        printf("%s=\n", mrb_sym_name(mrb, sym(n2->car->car)));
+        mrb_parser_dump(mrb, n2->car->cdr, offset+3);
+        n2 = n2->cdr;
+      }
+    }
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("rest=*%s\n", mrb_sym_name(mrb, sym(n->car)));
+  }
+  n = n->cdr;
+  if (n->car) {
+    dump_prefix(n, offset+1);
+    printf("post mandatory args:\n");
+    dump_recur(mrb, n->car, offset+2);
+  }
+
+  n = n->cdr;
+  if (n) {
+    mrb_assert(intn(n->car) == NODE_ARGS_TAIL);
+    mrb_parser_dump(mrb, n, offset);
+  }
+}
+
+/*
+ * This function restores the GC arena on return.
+ * For this reason, if a process that further generates an object is
+ * performed at the caller, the string pointer returned as the return
+ * value may become invalid.
+ */
+static const char*
+str_dump(mrb_state *mrb, const char *str, int len)
+{
+  mrb_int ai = mrb_gc_arena_save(mrb);
+  mrb_value s;
+# if INT_MAX > MRB_INT_MAX / 4
+  /* check maximum length with "\xNN" charactor */
+  if (len > MRB_INT_MAX / 4) {
+    len = MRB_INT_MAX / 4;
+  }
+# endif
+  s = mrb_str_new(mrb, str, (mrb_int)len);
+  s = mrb_str_dump(mrb, s);
+  mrb_gc_arena_restore(mrb, ai);
+  return RSTRING_PTR(s);
+}
 #endif
 
@@ -5896,5 +6584,5 @@
   again:
   dump_prefix(tree, offset);
-  nodetype = (int)(intptr_t)tree->car;
+  nodetype = intn(tree->car);
   tree = tree->cdr;
   switch (nodetype) {
@@ -5956,5 +6644,6 @@
 
   case NODE_LAMBDA:
-    printf("NODE_BLOCK:\n");
+    printf("NODE_LAMBDA:\n");
+    dump_prefix(tree, offset);
     goto block;
 
@@ -5964,41 +6653,5 @@
     tree = tree->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      if (n->cdr) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
-      }
+      dump_args(mrb, tree->car, offset+1);
     }
     dump_prefix(tree, offset+1);
@@ -6123,5 +6776,5 @@
           if (n2->car) {
             if (!first_lval) printf(", ");
-            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+            printf("%s", mrb_sym_name(mrb, sym(n2->car)));
             first_lval = FALSE;
           }
@@ -6151,6 +6804,6 @@
     dump_prefix(tree, offset+1);
     printf("method='%s' (%d)\n",
-        mrb_sym2name(mrb, sym(tree->cdr->car)),
-        (int)(intptr_t)tree->cdr->car);
+        mrb_sym_dump(mrb, sym(tree->cdr->car)),
+        intn(tree->cdr->car));
     tree = tree->cdr->cdr->car;
     if (tree) {
@@ -6182,9 +6835,9 @@
     mrb_parser_dump(mrb, tree->car, offset+1);
     dump_prefix(tree, offset+1);
-    printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr)));
+    printf("::%s\n", mrb_sym_name(mrb, sym(tree->cdr)));
     break;
 
   case NODE_COLON3:
-    printf("NODE_COLON3: ::%s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_COLON3: ::%s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6196,4 +6849,17 @@
   case NODE_HASH:
     printf("NODE_HASH:\n");
+    while (tree) {
+      dump_prefix(tree, offset+1);
+      printf("key:\n");
+      mrb_parser_dump(mrb, tree->car->car, offset+2);
+      dump_prefix(tree, offset+1);
+      printf("value:\n");
+      mrb_parser_dump(mrb, tree->car->cdr, offset+2);
+      tree = tree->cdr;
+    }
+    break;
+
+  case NODE_KW_HASH:
+    printf("NODE_KW_HASH:\n");
     while (tree) {
       dump_prefix(tree, offset+1);
@@ -6269,5 +6935,5 @@
     tree = tree->cdr;
     dump_prefix(tree, offset+1);
-    printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
+    printf("op='%s' (%d)\n", mrb_sym_name(mrb, sym(tree->car)), intn(tree->car));
     tree = tree->cdr;
     mrb_parser_dump(mrb, tree->car, offset+1);
@@ -6321,21 +6987,25 @@
 
   case NODE_LVAR:
-    printf("NODE_LVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_LVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_GVAR:
-    printf("NODE_GVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_GVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_IVAR:
-    printf("NODE_IVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_IVAR %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
   case NODE_CVAR:
-    printf("NODE_CVAR %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree)));
+    break;
+
+  case NODE_NVAR:
+    printf("NODE_NVAR %d\n", intn(tree));
     break;
 
   case NODE_CONST:
-    printf("NODE_CONST %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6351,13 +7021,13 @@
 
   case NODE_BACK_REF:
-    printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree);
+    printf("NODE_BACK_REF: $%c\n", intn(tree));
     break;
 
   case NODE_NTH_REF:
-    printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree);
+    printf("NODE_NTH_REF: $%d\n", intn(tree));
     break;
 
   case NODE_ARG:
-    printf("NODE_ARG %s\n", mrb_sym2name(mrb, sym(tree)));
+    printf("NODE_ARG %s\n", mrb_sym_name(mrb, sym(tree)));
     break;
 
@@ -6368,5 +7038,5 @@
 
   case NODE_INT:
-    printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car);
+    printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car));
     break;
 
@@ -6376,23 +7046,23 @@
 
   case NODE_NEGATE:
-    printf("NODE_NEGATE\n");
+    printf("NODE_NEGATE:\n");
     mrb_parser_dump(mrb, tree, offset+1);
     break;
 
   case NODE_STR:
-    printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+    printf("NODE_STR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
     break;
 
   case NODE_DSTR:
-    printf("NODE_DSTR\n");
+    printf("NODE_DSTR:\n");
     dump_recur(mrb, tree, offset+1);
     break;
 
   case NODE_XSTR:
-    printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+    printf("NODE_XSTR %s len %d\n", str_dump(mrb, (char*)tree->car, intn(tree->cdr)), intn(tree->cdr));
     break;
 
   case NODE_DXSTR:
-    printf("NODE_DXSTR\n");
+    printf("NODE_DXSTR:\n");
     dump_recur(mrb, tree, offset+1);
     break;
@@ -6403,5 +7073,5 @@
 
   case NODE_DREGX:
-    printf("NODE_DREGX\n");
+    printf("NODE_DREGX:\n");
     dump_recur(mrb, tree->car, offset+1);
     dump_prefix(tree, offset);
@@ -6418,6 +7088,25 @@
 
   case NODE_SYM:
-    printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)),
-           (int)(intptr_t)tree);
+    printf("NODE_SYM :%s (%d)\n", mrb_sym_dump(mrb, sym(tree)),
+           intn(tree));
+    break;
+
+  case NODE_DSYM:
+    printf("NODE_DSYM:\n");
+    mrb_parser_dump(mrb, tree, offset+1);
+    break;
+
+  case NODE_WORDS:
+    printf("NODE_WORDS:\n");
+    dump_recur(mrb, tree, offset+1);
+    break;
+
+  case NODE_SYMBOLS:
+    printf("NODE_SYMBOLS:\n");
+    dump_recur(mrb, tree, offset+1);
+    break;
+
+  case NODE_LITERAL_DELIM:
+    printf("NODE_LITERAL_DELIM\n");
     break;
 
@@ -6440,6 +7129,6 @@
   case NODE_ALIAS:
     printf("NODE_ALIAS %s %s:\n",
-        mrb_sym2name(mrb, sym(tree->car)),
-        mrb_sym2name(mrb, sym(tree->cdr)));
+        mrb_sym_dump(mrb, sym(tree->car)),
+        mrb_sym_dump(mrb, sym(tree->cdr)));
     break;
 
@@ -6449,5 +7138,5 @@
       node *t = tree;
       while (t) {
-        printf(" %s", mrb_sym2name(mrb, sym(t->car)));
+        printf(" %s", mrb_sym_dump(mrb, sym(t->car)));
         t = t->cdr;
       }
@@ -6460,14 +7149,14 @@
     if (tree->car->car == (node*)0) {
       dump_prefix(tree, offset+1);
-      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else if (tree->car->car == (node*)1) {
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else {
       mrb_parser_dump(mrb, tree->car->car, offset+1);
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     if (tree->cdr->car) {
@@ -6485,14 +7174,14 @@
     if (tree->car->car == (node*)0) {
       dump_prefix(tree, offset+1);
-      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf(":%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else if (tree->car->car == (node*)1) {
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     else {
       mrb_parser_dump(mrb, tree->car->car, offset+1);
       dump_prefix(tree, offset+1);
-      printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr)));
+      printf("::%s\n", mrb_sym_name(mrb, sym(tree->car->cdr)));
     }
     dump_prefix(tree, offset+1);
@@ -6512,5 +7201,5 @@
     printf("NODE_DEF:\n");
     dump_prefix(tree, offset+1);
-    printf("%s\n", mrb_sym2name(mrb, sym(tree->car)));
+    printf("%s\n", mrb_sym_dump(mrb, sym(tree->car)));
     tree = tree->cdr;
     {
@@ -6525,5 +7214,5 @@
           if (n2->car) {
             if (!first_lval) printf(", ");
-            printf("%s", mrb_sym2name(mrb, sym(n2->car)));
+            printf("%s", mrb_sym_name(mrb, sym(n2->car)));
             first_lval = FALSE;
           }
@@ -6535,41 +7224,5 @@
     tree = tree->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      if (n->cdr) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
-      }
+      dump_args(mrb, tree->car, offset);
     }
     mrb_parser_dump(mrb, tree->cdr->car, offset+1);
@@ -6581,45 +7234,8 @@
     tree = tree->cdr;
     dump_prefix(tree, offset+1);
-    printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
+    printf(":%s\n", mrb_sym_dump(mrb, sym(tree->car)));
     tree = tree->cdr->cdr;
     if (tree->car) {
-      node *n = tree->car;
-
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("optional args:\n");
-        {
-          node *n2 = n->car;
-
-          while (n2) {
-            dump_prefix(n2, offset+2);
-            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
-            mrb_parser_dump(mrb, n2->car->cdr, 0);
-            n2 = n2->cdr;
-          }
-        }
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
-      }
-      n = n->cdr;
-      if (n->car) {
-        dump_prefix(n, offset+1);
-        printf("post mandatory args:\n");
-        dump_recur(mrb, n->car, offset+2);
-      }
-      n = n->cdr;
-      if (n) {
-        dump_prefix(n, offset+1);
-        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
-      }
+      dump_args(mrb, tree->car, offset+1);
     }
     tree = tree->cdr;
@@ -6637,4 +7253,35 @@
     break;
 
+  case NODE_ARGS_TAIL:
+    printf("NODE_ARGS_TAIL:\n");
+    {
+      node *kws = tree->car;
+
+      while (kws) {
+        mrb_parser_dump(mrb, kws->car, offset+1);
+        kws = kws->cdr;
+      }
+    }
+    tree = tree->cdr;
+    if (tree->car) {
+      mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS);
+      mrb_parser_dump(mrb, tree->car, offset+1);
+    }
+    tree = tree->cdr;
+    if (tree->car) {
+      dump_prefix(tree, offset+1);
+      printf("block='%s'\n", mrb_sym_name(mrb, sym(tree->car)));
+    }
+    break;
+
+  case NODE_KW_ARG:
+    printf("NODE_KW_ARG %s:\n", mrb_sym_name(mrb, sym(tree->car)));
+    mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
+    break;
+
+  case NODE_KW_REST_ARGS:
+    printf("NODE_KW_REST_ARGS %s\n", mrb_sym_name(mrb, sym(tree)));
+    break;
+
   default:
     printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
Index: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/mrbgem.rake
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/mrbgem.rake	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-compiler/mrbgem.rake	(revision 439)
@@ -24,8 +24,8 @@
     end
   end
-  file objfile("#{current_build_dir}/core/y.tab") => lex_def
 
   # Parser
-  file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y"] do |t|
+  file "#{current_build_dir}/core/y.tab.c" => ["#{current_dir}/core/parse.y", lex_def] do |t|
+    mkdir_p File.dirname t.name
     yacc.run t.name, t.prerequisites.first
   end
@@ -36,5 +36,5 @@
   end
 
-  file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs
+  file build.libmruby_core_static => core_objs
   build.libmruby << core_objs
 end
