--- ruby-1.8.7-p72/parse.y	2009-02-10 10:54:19.000000000 -0800
+++ parse.y	2009-02-11 00:02:31.000000000 -0800
@@ -91,6 +91,7 @@
     EXPR_FNAME,			/* ignore newline, no reserved words. */
     EXPR_DOT,			/* right after `.' or `::', no reserved words. */
     EXPR_CLASS,			/* immediate after `class', no here document. */
+    EXPR_VALUE			/* alike EXPR_BEG but label is disallowed. */
 } lex_state;
 static NODE *lex_strterm;
 
@@ -263,7 +264,7 @@
 	k__LINE__
 	k__FILE__
 
-%token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR
+%token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
 %token <node> tINTEGER tFLOAT tSTRING_CONTENT
 %token <node> tNTH_REF tBACK_REF
 %token <num>  tREGEXP_END
@@ -2505,6 +2506,10 @@
 		    {
 			$$ = list_append(NEW_LIST($1), $3);
 		    }
+               | tLABEL arg_value
+                   {
+                       $$ = list_append(NEW_LIST(NEW_LIT(ID2SYM($1))), $2);
+                   }
 		;
 
 operation	: tIDENTIFIER
@@ -3433,6 +3438,8 @@
 }
 
 #define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG)
+#define IS_BEG() (lex_state == EXPR_BEG || lex_state == EXPR_MID || \
+                  lex_state == EXPR_VALUE || lex_state == EXPR_CLASS)
 
 static int
 yylex()
@@ -3489,6 +3496,7 @@
 	  case EXPR_FNAME:
 	  case EXPR_DOT:
 	  case EXPR_CLASS:
+          case EXPR_VALUE:
 	    goto retry;
 	  default:
 	    break;
@@ -3518,7 +3526,7 @@
 		rb_warning("`*' interpreted as argument prefix");
 		c = tSTAR;
 	    }
-	    else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	    else if (IS_BEG()) {
 		c = tSTAR;
 	    }
 	    else {
@@ -3671,7 +3679,7 @@
 
       case '?':
 	if (lex_state == EXPR_END || lex_state == EXPR_ENDARG) {
-	    lex_state = EXPR_BEG;
+	    lex_state = EXPR_VALUE;
 	    return '?';
 	}
 	c = nextc();
@@ -3708,7 +3716,7 @@
 	    }
 	  ternary:
 	    pushback(c);
-	    lex_state = EXPR_BEG;
+	    lex_state = EXPR_VALUE;
 	    return '?';
 	}
 	else if (ismbchar(c)) {
@@ -3747,7 +3755,7 @@
 	    rb_warning("`&' interpreted as argument prefix");
 	    c = tAMPER;
 	}
-	else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	else if (IS_BEG()) {
 	    c = tAMPER;
 	}
 	else {
@@ -3801,7 +3809,7 @@
 	    lex_state = EXPR_BEG;
 	    return tOP_ASGN;
 	}
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
+	if (IS_BEG() ||
 	    (IS_ARG() && space_seen && !ISSPACE(c))) {
 	    if (IS_ARG()) arg_ambiguous();
 	    lex_state = EXPR_BEG;
@@ -3831,7 +3839,7 @@
 	    lex_state = EXPR_BEG;
 	    return tOP_ASGN;
 	}
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
+	if (IS_BEG() ||
 	    (IS_ARG() && space_seen && !ISSPACE(c))) {
 	    if (IS_ARG()) arg_ambiguous();
 	    lex_state = EXPR_BEG;
@@ -4090,8 +4098,7 @@
       case ':':
 	c = nextc();
 	if (c == ':') {
-	    if (lex_state == EXPR_BEG ||  lex_state == EXPR_MID ||
-		lex_state == EXPR_CLASS || (IS_ARG() && space_seen)) {
+	    if (IS_BEG() || (IS_ARG() && space_seen)) {
 		lex_state = EXPR_BEG;
 		return tCOLON3;
 	    }
@@ -4118,7 +4125,7 @@
 	return tSYMBEG;
 
       case '/':
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    lex_strterm = NEW_STRTERM(str_regexp, '/', 0);
 	    return tREGEXP_BEG;
 	}
@@ -4180,7 +4187,7 @@
 
       case '(':
 	command_start = Qtrue;
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    c = tLPAREN;
 	}
 	else if (space_seen) {
@@ -4210,7 +4217,7 @@
 	    pushback(c);
 	    return '[';
 	}
-	else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	else if (IS_BEG()) {
 	    c = tLBRACK;
 	}
 	else if (IS_ARG() && space_seen) {
@@ -4244,7 +4251,7 @@
 	return '\\';
 
       case '%':
-	if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
+	if (IS_BEG()) {
 	    int term;
 	    int paren;
 
@@ -4523,6 +4530,17 @@
 		}
 	    }
 
+            if ((lex_state == EXPR_BEG && !cmd_state) ||
+                lex_state == EXPR_ARG ||
+                lex_state == EXPR_CMDARG) {
+                if (peek(':') && !(lex_p + 1 < lex_pend && lex_p[1] == ':')) {
+                    lex_state = EXPR_BEG;
+                    nextc();
+                    yylval.id = rb_intern(tok());
+                    return tLABEL;
+                }
+            }
+
 	    if (lex_state != EXPR_DOT) {
 		const struct kwtable *kw;
 
@@ -4544,7 +4562,7 @@
 			    return kDO_BLOCK;
 			return kDO;
 		    }
-		    if (state == EXPR_BEG)
+		    if (state == EXPR_BEG || state == EXPR_VALUE)
 			return kw->id[0];
 		    else {
 			if (kw->id[0] != kw->id[1])
@@ -4554,17 +4572,10 @@
 		}
 	    }
 
-	    if (lex_state == EXPR_BEG ||
-		lex_state == EXPR_MID ||
+	    if (IS_BEG() ||
 		lex_state == EXPR_DOT ||
-		lex_state == EXPR_ARG ||
-		lex_state == EXPR_CMDARG) {
-		if (cmd_state) {
-		    lex_state = EXPR_CMDARG;
-		}
-		else {
-		    lex_state = EXPR_ARG;
-		}
+		IS_ARG()) {
+              lex_state = cmd_state ? EXPR_CMDARG : EXPR_ARG;
 	    }
 	    else {
 		lex_state = EXPR_END;

