Index: env.h
===================================================================
RCS file: /src/ruby/env.h,v
retrieving revision 1.7
diff -u -r1.7 env.h
--- env.h	2001/02/14 05:51:57	1.7
+++ env.h	2001/05/08 07:26:37
@@ -32,6 +32,9 @@
 
 #define FRAME_ALLOCA 0
 #define FRAME_MALLOC 1
+#ifdef TAIL_RECURSIVE
+#define FRAME_DONT_TAILJUMP 2
+#endif /* TAIL_RECURSIVE */
 
 extern struct SCOPE {
     struct RBasic super;
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.175
diff -u -r1.175 eval.c
--- eval.c	2001/05/07 09:26:23	1.175
+++ eval.c	2001/05/08 07:26:37
@@ -502,6 +502,13 @@
 static struct FRAME *top_frame;
 static struct SCOPE *top_scope;
 
+#ifdef TAIL_RECURSIVE
+static VALUE tail_call_recv = Qnil;
+static ID tail_call_mid = 0;
+static VALUE tail_call_args = Qnil;
+static int tail_call_scope = 0;
+#endif /* TAIL_RECURSIVE */
+
 #define PUSH_FRAME() {			\
     struct FRAME _frame;		\
     _frame.prev = ruby_frame;		\
@@ -583,10 +590,18 @@
        rb_gc_force_recycle((VALUE)tag); \
 } while (0)
 
+#ifdef TAIL_RECURSIVE
+#define POP_BLOCK() 			\
+   POP_BLOCK_TAG(_block.tag);		\
+   ruby_frame->flags |= _block.frame.flags & FRAME_DONT_TAILJUMP; \
+   ruby_block = _block.prev; 		\
+}
+#else /* not TAIL_RECURSIVE */
 #define POP_BLOCK() 			\
    POP_BLOCK_TAG(_block.tag);		\
    ruby_block = _block.prev; 		\
 }
+#endif /* TAIL_RECURSIVE */
 
 struct RVarmap *ruby_dyna_vars;
 #define PUSH_VARS() {			\
@@ -785,6 +800,9 @@
 #define TAG_RAISE	0x6
 #define TAG_THROW	0x7
 #define TAG_FATAL	0x8
+#ifdef TAIL_RECURSIVE
+#define TAG_TAILJUMP	0x9
+#endif
 #define TAG_MASK	0xf
 
 VALUE ruby_class;
@@ -1972,6 +1990,10 @@
 static void return_check _((void));
 #define return_value(v) prot_tag->retval = (v)
 
+#ifdef TAIL_RECURSIVE
+static void optimize_tail_call _((NODE*));
+#endif /* TAIL_RECURSIVE */
+
 static VALUE
 rb_eval(self, n)
     VALUE self;
@@ -2322,6 +2344,10 @@
 	result = rb_yield_0(result, 0, 0, 0);
 	break;
 
+      case NODE_BINDING:
+	result = rb_f_binding(self);
+	break;
+
       case NODE_RESCUE:
       retry_entry:
         {
@@ -2508,6 +2534,68 @@
 	result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
 	break;
 
+#ifdef TAIL_RECURSIVE
+      case NODE_TAIL_CALL:
+        {
+	  VALUE recv;
+	  int argc; VALUE *argv; /* used in SETUP_ARGS */
+	  TMP_PROTECT;
+
+	  BEGIN_CALLARGS;
+	  recv = rb_eval(self, node->nd_recv);
+	  SETUP_ARGS(node->nd_args);
+	  END_CALLARGS;
+	  if (ruby_frame->flags & FRAME_DONT_TAILJUMP) {
+	      result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
+	  }
+	  else {
+	      tail_call_recv = recv;
+	      tail_call_mid = node->nd_mid;
+	      tail_call_args = rb_ary_new4(argc, argv);
+	      tail_call_scope = 0;
+	      return_check();
+	      JUMP_TAG(TAG_TAILJUMP);
+	  }
+        }
+	break;
+
+      case NODE_TAIL_FCALL:
+        {
+	  int argc; VALUE *argv; /* used in SETUP_ARGS */
+	  TMP_PROTECT;
+
+	  BEGIN_CALLARGS;
+	  SETUP_ARGS(node->nd_args);
+	  END_CALLARGS;
+	  if (ruby_frame->flags & FRAME_DONT_TAILJUMP) {
+	      result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
+	  }
+	  else {
+	      tail_call_recv = self;
+	      tail_call_mid = node->nd_mid;
+	      tail_call_args = rb_ary_new4(argc, argv);
+	      tail_call_scope = 1;
+	      return_check();
+	      JUMP_TAG(TAG_TAILJUMP);
+	  }
+        }
+	break;
+
+      case NODE_TAIL_VCALL:
+	if (ruby_frame->flags & FRAME_DONT_TAILJUMP) {
+	    result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+	}
+	else {
+	    tail_call_recv = self;
+	    tail_call_mid = node->nd_mid;
+	    tail_call_args = Qnil;
+	    tail_call_scope = 2;
+	    return_check();
+	    JUMP_TAG(TAG_TAILJUMP);
+	}
+	break;
+#endif /* TAIL_RECURSIVE */
+
       case NODE_SUPER:
       case NODE_ZSUPER:
 	{
@@ -2953,6 +3041,9 @@
 	    if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) {
 		noex |= NOEX_UNDEF;
 	    }
+#ifdef TAIL_RECURSIVE
+	    optimize_tail_call(node->nd_defn);
+#endif /* TAIL_RECURSIVE */
 
 	    defn = copy_node_scope(node->nd_defn, ruby_cref);
 	    rb_add_method(ruby_class, node->nd_mid, defn, noex);
@@ -4464,14 +4555,18 @@
     VALUE *argv;		/* OK */
     int scope;
 {
+    VALUE result;
     NODE  *body;		/* OK */
     int    noex;
-    ID     id = mid;
+    ID     id;
     struct cache_entry *ent;
+    int state;
 
     if (!klass) {
 	rb_raise(rb_eNotImpError, "method call on terminated object");
     }
+  again:
+    id = mid;
     /* is it in the method cache? */
     ent = cache + EXPR1(klass, mid);
     if (ent->mid == mid && ent->klass == klass) {
@@ -4505,7 +4600,42 @@
 	}
     }
 
+#ifdef TAIL_RECURSIVE
+    if (nd_type(body) == NODE_CFUNC)
+	return rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF);
+
+    PUSH_TAG(PROT_NONE);
+    if ((state = EXEC_TAG()) == 0) {
+	result = rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF);
+    }
+    POP_TAG();
+    switch (state) {
+      case 0:
+	return result;
+      case TAG_TAILJUMP:
+	recv = tail_call_recv;
+	klass = CLASS_OF(recv);
+	mid = tail_call_mid;
+	if (NIL_P(tail_call_args)) {
+	    argc = 0;
+	    argv = 0;
+	}
+	else {
+	    argc = RARRAY(tail_call_args)->len;
+	    argv = RARRAY(tail_call_args)->ptr;
+	}
+	scope = tail_call_scope;
+	tail_call_recv = Qnil;
+	tail_call_mid = 0;
+	tail_call_args = Qnil;
+	tail_call_scope = 0;
+	goto again;
+      default:
+	JUMP_TAG(state);
+    }
+#else /* not TAIL_RECURSIVE */
     return rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF);
+#endif /* TAIL_RECURSIVE */
 }
 
 VALUE
@@ -5851,6 +5981,11 @@
     rb_global_variable((VALUE*)&ruby_eval_tree);
     rb_global_variable((VALUE*)&ruby_dyna_vars);
 
+#ifdef TAIL_RECURSIVE
+    rb_global_variable(&tail_call_recv);
+    rb_global_variable(&tail_call_args);
+#endif /* TAIL_RECURSIVE */
+
     rb_define_virtual_variable("$@", errat_getter, errat_setter);
     rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter);
 
@@ -6212,6 +6347,10 @@
     scope_dup(data->scope);
     proc_save_safe_level(proc);
 
+#ifdef TAIL_RECURSIVE
+    ruby_block->frame.flags |= FRAME_DONT_TAILJUMP;
+#endif /* TAIL_RECURSIVE */
+
     return proc;
 }
 
@@ -6815,7 +6954,9 @@
     rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
     rb_define_global_function("proc", rb_f_lambda, 0);
     rb_define_global_function("lambda", rb_f_lambda, 0);
+#if 0
     rb_define_global_function("binding", rb_f_binding, 0);
+#endif
     rb_cBinding = rb_define_class("Binding", rb_cObject);
     rb_undef_method(CLASS_OF(rb_cBinding), "new");
     rb_define_method(rb_cBinding, "clone", bind_clone, 0);
@@ -8872,3 +9013,142 @@
 	tt = tt->prev;
     }
 }
+
+#ifdef TAIL_RECURSIVE
+static void
+optimize_return(node)
+    NODE *node;
+{
+  again:
+    if (!node) return;
+
+    switch (nd_type(node)) {
+      case NODE_SCOPE:
+	node = node->nd_next;
+	goto again;
+
+      case NODE_BLOCK:
+	while (node->nd_next) {
+	    optimize_return(node->nd_head);
+	    node = node->nd_next;
+	}
+	node = node->nd_head;
+	goto again;
+
+      case NODE_BEGIN:
+	node = node->nd_body;
+	goto again;
+
+      case NODE_NEWLINE:
+	node = node->nd_next;
+	goto again;
+
+      case NODE_IF:
+	optimize_return(node->nd_body);
+	optimize_return(node->nd_else);
+	break;
+
+      case NODE_CASE:
+	node = node->nd_body;
+	while (node) {
+	    if (nd_type(node) != NODE_WHEN)
+		goto again;
+	    optimize_return(node->nd_body);
+	    node = node->nd_next;
+	}
+	break;
+
+      case NODE_WHILE:
+      case NODE_UNTIL:
+      case NODE_FOR:
+	node = node->nd_body;
+	goto again;
+
+      case NODE_RETURN:
+	if (node->nd_stts) {
+	    node = node->nd_stts;
+	    switch (nd_type(node)) {
+	      case NODE_CALL:
+		nd_set_type(node, NODE_TAIL_CALL);
+		break;
+	      case NODE_FCALL:
+		nd_set_type(node, NODE_TAIL_FCALL);
+		break;
+	      case NODE_VCALL:
+		nd_set_type(node, NODE_TAIL_VCALL);
+		break;
+	    }
+	}
+	break;
+
+      case NODE_ITER:		/* maybe catch */
+      case NODE_RESCUE:
+      case NODE_ENSURE:
+      default:
+	break;
+    }
+}
+  
+static void
+optimize_tail_call(node)
+    NODE *node;
+{
+  again:
+    if (!node) return;
+
+    switch (nd_type(node)) {
+      case NODE_SCOPE:
+	node = node->nd_next;
+	goto again;
+
+      case NODE_BLOCK:
+	while (node->nd_next) {
+	    optimize_return(node->nd_head);
+	    node = node->nd_next;
+	}
+	node = node->nd_head;
+	goto again;
+
+      case NODE_BEGIN:
+	node = node->nd_body;
+	goto again;
+
+      case NODE_NEWLINE:
+	node = node->nd_next;
+	goto again;
+
+      case NODE_IF:
+	optimize_tail_call(node->nd_body);
+	optimize_tail_call(node->nd_else);
+	break;
+
+      case NODE_CASE:
+	node = node->nd_body;
+	while (node) {
+	    if (nd_type(node) != NODE_WHEN)
+		goto again;
+	    optimize_tail_call(node->nd_body);
+	    node = node->nd_next;
+	}
+	break;
+
+      case NODE_CALL:
+	nd_set_type(node, NODE_TAIL_CALL);
+	break;
+
+      case NODE_FCALL:
+	nd_set_type(node, NODE_TAIL_FCALL);
+	break;
+
+      case NODE_VCALL:
+	nd_set_type(node, NODE_TAIL_VCALL);
+	break;
+
+      case NODE_RESCUE:
+      case NODE_ENSURE:
+      default:
+	optimize_return(node);
+	break;
+    }
+}
+#endif /* TAIL_RECURSIVE */
Index: keywords
===================================================================
RCS file: /src/ruby/keywords,v
retrieving revision 1.3
diff -u -r1.3 keywords
--- keywords	2000/05/30 04:24:01	1.3
+++ keywords	2001/05/08 07:26:37
@@ -40,3 +40,4 @@
 when, kWHEN, kWHEN, EXPR_BEG
 while, kWHILE, kWHILE_MOD, EXPR_BEG
 yield, kYIELD, kYIELD, EXPR_ARG
+binding, kBINDING, kBINDING, EXPR_END
Index: lex.c
===================================================================
RCS file: /src/ruby/lex.c,v
retrieving revision 1.5
diff -u -r1.5 lex.c
--- lex.c	2000/05/30 04:24:01	1.5
+++ lex.c	2001/05/08 07:26:37
@@ -2,12 +2,12 @@
 /* Command-line: gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$ ./keywords  */
 struct kwtable {char *name; int id[2]; enum lex_state state;};
 
-#define TOTAL_KEYWORDS 40
+#define TOTAL_KEYWORDS 41
 #define MIN_WORD_LENGTH 2
 #define MAX_WORD_LENGTH 8
-#define MIN_HASH_VALUE 6
-#define MAX_HASH_VALUE 55
-/* maximum key range = 50, duplicates = 0 */
+#define MIN_HASH_VALUE 4
+#define MAX_HASH_VALUE 59
+/* maximum key range = 56, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -19,32 +19,32 @@
 {
   static unsigned char asso_values[] =
     {
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 11, 56, 56, 36, 56,  1, 37,
-      31,  1, 56, 56, 56, 56, 29, 56,  1, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56,  1, 56, 32,  1,  2,
-       1,  1,  4, 23, 56, 17, 56, 20,  9,  2,
-       9, 26, 14, 56,  5,  1,  1, 16, 56, 21,
-      20,  9, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
-      56, 56, 56, 56, 56, 56
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 12, 60, 60, 35, 60,  1,  3,
+      31,  1, 60, 60, 60, 60, 29, 60,  1, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60,  1, 60, 26,  1, 20,
+       1,  1,  4, 31, 60, 27, 60, 30,  7, 11,
+       1,  1, 19, 60,  7,  1,  8, 14, 60, 23,
+      22, 16, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 60, 60, 60, 60, 60
     };
   register int hval = len;
 
@@ -71,48 +71,51 @@
 {
   static struct kwtable wordlist[] =
     {
-      {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+      {"do", kDO, kDO, EXPR_BEG},
+      {""},
       {"end", kEND, kEND, EXPR_END},
       {"else", kELSE, kELSE, EXPR_BEG},
-      {"case", kCASE, kCASE, EXPR_BEG},
+      {"END", klEND, klEND, EXPR_END},
       {"ensure", kENSURE, kENSURE, EXPR_BEG},
-      {"module", kMODULE, kMODULE, EXPR_BEG},
+      {"or", kOR, kOR, EXPR_BEG},
       {"elsif", kELSIF, kELSIF, EXPR_BEG},
       {"def", kDEF, kDEF, EXPR_FNAME},
-      {"rescue", kRESCUE, kRESCUE_MOD, EXPR_END},
-      {"not", kNOT, kNOT, EXPR_BEG},
+      {"redo", kREDO, kREDO, EXPR_END},
       {"then", kTHEN, kTHEN, EXPR_BEG},
-      {"yield", kYIELD, kYIELD, EXPR_ARG},
-      {"for", kFOR, kFOR, EXPR_BEG},
+      {"rescue", kRESCUE, kRESCUE_MOD, EXPR_END},
       {"self", kSELF, kSELF, EXPR_END},
       {"false", kFALSE, kFALSE, EXPR_END},
-      {"retry", kRETRY, kRETRY, EXPR_END},
+      {"nil", kNIL, kNIL, EXPR_END},
+      {"module", kMODULE, kMODULE, EXPR_BEG},
+      {"not", kNOT, kNOT, EXPR_BEG},
+      {"for", kFOR, kFOR, EXPR_BEG},
       {"return", kRETURN, kRETURN, EXPR_MID},
-      {"true", kTRUE, kTRUE, EXPR_END},
-      {"if", kIF, kIF_MOD, EXPR_BEG},
-      {"defined?", kDEFINED, kDEFINED, EXPR_ARG},
-      {"super", kSUPER, kSUPER, EXPR_ARG},
+      {"yield", kYIELD, kYIELD, EXPR_ARG},
       {"undef", kUNDEF, kUNDEF, EXPR_FNAME},
-      {"break", kBREAK, kBREAK, EXPR_END},
-      {"in", kIN, kIN, EXPR_BEG},
-      {"do", kDO, kDO, EXPR_BEG},
-      {"nil", kNIL, kNIL, EXPR_END},
-      {"until", kUNTIL, kUNTIL_MOD, EXPR_BEG},
+      {"defined?", kDEFINED, kDEFINED, EXPR_ARG},
+      {"case", kCASE, kCASE, EXPR_BEG},
+      {"true", kTRUE, kTRUE, EXPR_END},
       {"unless", kUNLESS, kUNLESS_MOD, EXPR_BEG},
-      {"or", kOR, kOR, EXPR_BEG},
-      {"next", kNEXT, kNEXT, EXPR_END},
       {"when", kWHEN, kWHEN, EXPR_BEG},
-      {"redo", kREDO, kREDO, EXPR_END},
+      {"in", kIN, kIN, EXPR_BEG},
       {"and", kAND, kAND, EXPR_BEG},
+      {"super", kSUPER, kSUPER, EXPR_ARG},
+      {"if", kIF, kIF_MOD, EXPR_BEG},
+      {"until", kUNTIL, kUNTIL_MOD, EXPR_BEG},
+      {"next", kNEXT, kNEXT, EXPR_END},
+      {"retry", kRETRY, kRETRY, EXPR_END},
+      {"break", kBREAK, kBREAK, EXPR_END},
       {"begin", kBEGIN, kBEGIN, EXPR_BEG},
       {"__LINE__", k__LINE__, k__LINE__, EXPR_END},
-      {"class", kCLASS, kCLASS, EXPR_CLASS},
+      {"binding", kBINDING, kBINDING, EXPR_END},
       {"__FILE__", k__FILE__, k__FILE__, EXPR_END},
-      {"END", klEND, klEND, EXPR_END},
       {"BEGIN", klBEGIN, klBEGIN, EXPR_END},
-      {"while", kWHILE, kWHILE_MOD, EXPR_BEG},
       {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
+      {"class", kCLASS, kCLASS, EXPR_CLASS},
+      {""}, {""}, {""},
+      {"while", kWHILE, kWHILE_MOD, EXPR_BEG},
+      {""}, {""},
       {"alias", kALIAS, kALIAS, EXPR_FNAME}
     };
 
Index: node.h
===================================================================
RCS file: /src/ruby/node.h,v
retrieving revision 1.22
diff -u -r1.22 node.h
--- node.h	2001/05/02 04:22:11	1.22
+++ node.h	2001/05/08 07:26:37
@@ -58,6 +58,11 @@
     NODE_CALL,
     NODE_FCALL,
     NODE_VCALL,
+#ifdef TAIL_RECURSIVE
+    NODE_TAIL_CALL,
+    NODE_TAIL_FCALL,
+    NODE_TAIL_VCALL,
+#endif /* TAIL_RECURSIVE */
     NODE_SUPER,
     NODE_ZSUPER,
     NODE_ARRAY,
@@ -65,6 +70,7 @@
     NODE_HASH,
     NODE_RETURN,
     NODE_YIELD,
+    NODE_BINDING,
     NODE_LVAR,
     NODE_DVAR,
     NODE_GVAR,
@@ -258,6 +264,7 @@
 #define NEW_ENSURE(b,en) rb_node_newnode(NODE_ENSURE,b,0,en)
 #define NEW_RETURN(s) rb_node_newnode(NODE_RETURN,s,0,0)
 #define NEW_YIELD(a) rb_node_newnode(NODE_YIELD,a,0,0)
+#define NEW_BINDING() rb_node_newnode(NODE_BINDING,0,0,0)
 #define NEW_LIST(a)  NEW_ARRAY(a)
 #define NEW_ARRAY(a) rb_node_newnode(NODE_ARRAY,a,1,0)
 #define NEW_ZARRAY() rb_node_newnode(NODE_ZARRAY,0,0,0)
Index: parse.y
===================================================================
RCS file: /src/ruby/parse.y,v
retrieving revision 1.95
diff -u -r1.95 parse.y
--- parse.y	2001/05/07 09:26:24	1.95
+++ parse.y	2001/05/08 07:26:38
@@ -170,6 +170,7 @@
 	kDO_BLOCK
 	kRETURN
 	kYIELD
+	kBINDING
 	kSUPER
 	kSELF
 	kNIL
@@ -659,7 +660,7 @@
 		| kFOR | kIF_MOD | kIN | kMODULE | kNEXT | kNIL | kNOT
 		| kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF | kSUPER
 		| kTHEN | kTRUE | kUNDEF | kUNLESS_MOD | kUNTIL_MOD | kWHEN
-		| kWHILE_MOD | kYIELD | kRESCUE_MOD
+		| kWHILE_MOD | kYIELD | kBINDING | kRESCUE_MOD
 
 arg		: lhs '=' arg
 		    {
@@ -1156,6 +1157,10 @@
 		| kYIELD
 		    {
 			$$ = NEW_YIELD(0);
+		    }
+		| kBINDING
+		    {
+			$$ = NEW_BINDING();
 		    }
 		| kDEFINED opt_nl '(' {in_defined = 1;} expr ')'
 		    {
