$NetBSD: patch-cc,v 1.1 2005/11/02 08:56:40 taca Exp $

--- parse.y.orig	2005-05-12 01:21:33.000000000 +0900
+++ parse.y
@@ -13,6 +13,10 @@
 %{
 
 #define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+#ifndef YYSTACK_USE_ALLOCA
+#define YYSTACK_USE_ALLOCA 0
+#endif
 
 #include "ruby.h"
 #include "env.h"
@@ -23,6 +27,19 @@
 #include <errno.h>
 #include <ctype.h>
 
+#define YYMALLOC	rb_parser_malloc
+#define YYREALLOC	rb_parser_realloc
+#define YYCALLOC	rb_parser_calloc
+#define YYFREE 	rb_parser_free
+#define malloc	YYMALLOC
+#define realloc	YYREALLOC
+#define calloc	YYCALLOC
+#define free	YYFREE
+static void *rb_parser_malloc _((size_t));
+static void *rb_parser_realloc _((void *, size_t));
+static void *rb_parser_calloc _((size_t, size_t));
+static void rb_parser_free _((void *));
+
 #define yyparse ruby_yyparse
 #define yylex ruby_yylex
 #define yyerror ruby_yyerror
@@ -2450,6 +2467,10 @@ terms		: term
 none		: /* none */ {$$ = 0;}
 		;
 %%
+#ifdef yystacksize
+#undef YYMALLOC
+#endif
+
 #include "regex.h"
 #include "util.h"
 
@@ -2528,6 +2549,9 @@ int ruby_in_compile = 0;
 int ruby__end__seen;
 
 static VALUE ruby_debug_lines;
+#ifdef YYMALLOC
+static NODE *parser_heap;
+#endif
 
 static NODE*
 yycompile(f, line)
@@ -2992,7 +3016,7 @@ static void
 dispose_string(str)
     VALUE str;
 {
-    free(RSTRING(str)->ptr);
+    xfree(RSTRING(str)->ptr);
     rb_gc_force_recycle(str);
 }
 
@@ -3320,6 +3344,7 @@ yylex()
     register int c;
     int space_seen = 0;
     int cmd_state;
+    enum lex_state last_state;
 
     if (lex_strterm) {
 	int token;
@@ -4207,6 +4232,7 @@ yylex()
 	return '%';
 
       case '$':
+	last_state = lex_state;
 	lex_state = EXPR_END;
 	newtok();
 	c = nextc();
@@ -4249,7 +4275,13 @@ yylex()
 	    tokadd('$');
 	    tokadd(c);
 	    c = nextc();
-	    tokadd(c);
+	    if (is_identchar(c)) {
+		tokadd(c);
+	    }
+	    else {
+		pushback(c);
+	    }
+	  gvar:
 	    tokfix();
 	    yylval.id = rb_intern(tok());
 	    /* xxx shouldn't check if valid option variable */
@@ -4259,6 +4291,11 @@ yylex()
 	  case '`':		/* $`: string before last match */
 	  case '\'':		/* $': string after last match */
 	  case '+':		/* $+: string matches last paren. */
+	    if (last_state == EXPR_FNAME) {
+		tokadd('$');
+		tokadd(c);
+		goto gvar;
+	    }
 	    yylval.node = NEW_BACK_REF(c);
 	    return tBACK_REF;
 
@@ -4271,6 +4308,7 @@ yylex()
 		c = nextc();
 	    } while (ISDIGIT(c));
 	    pushback(c);
+	    if (last_state == EXPR_FNAME) goto gvar;
 	    tokfix();
 	    yylval.node = NEW_NTH_REF(atoi(tok()+1));
 	    return tNTH_REF;
@@ -4348,8 +4386,8 @@ yylex()
 
     {
 	int result = 0;
-	enum lex_state last_state = lex_state;
 
+	last_state = lex_state;
 	switch (tok()[0]) {
 	  case '$':
 	    lex_state = EXPR_END;
@@ -5563,11 +5601,11 @@ local_pop()
     struct local_vars *local = lvtbl->prev;
 
     if (lvtbl->tbl) {
-	if (!lvtbl->nofree) free(lvtbl->tbl);
+	if (!lvtbl->nofree) xfree(lvtbl->tbl);
 	else lvtbl->tbl[0] = lvtbl->cnt;
     }
     ruby_dyna_vars = lvtbl->dyna_vars;
-    free(lvtbl);
+    xfree(lvtbl);
     lvtbl = local;
 }
 
@@ -5675,7 +5713,7 @@ top_local_setup()
 		rb_mem_clear(ruby_scope->local_vars+i, len-i);
 	    }
 	    if (ruby_scope->local_tbl && ruby_scope->local_vars[-1] == 0) {
-		free(ruby_scope->local_tbl);
+		xfree(ruby_scope->local_tbl);
 	    }
 	    ruby_scope->local_vars[-1] = 0;
 	    ruby_scope->local_tbl = local_tbl();
@@ -5726,7 +5764,7 @@ dyna_init(node, pre)
 int
 ruby_parser_stack_on_heap()
 {
-#if defined(YYBISON) && !defined(C_ALLOCA)
+#if defined(YYMALLOC)
     return Qfalse;
 #else
     return Qtrue;
@@ -5736,6 +5774,12 @@ ruby_parser_stack_on_heap()
 void
 rb_gc_mark_parser()
 {
+#if defined YYMALLOC
+    rb_gc_mark((VALUE)parser_heap);
+#elif defined yystacksize
+    if (yyvsp) rb_gc_mark_locations((VALUE *)yyvs, (VALUE *)yyvsp);
+#endif
+
     if (!ruby_in_compile) return;
 
     rb_gc_mark_maybe((VALUE)yylval.node);
@@ -5837,6 +5881,99 @@ internal_id()
     return ID_INTERNAL | (++last_id << ID_SCOPE_SHIFT);
 }
 
+static int
+is_special_global_name(m)
+    const char *m;
+{
+    switch (*m) {
+      case '~': case '*': case '$': case '?': case '!': case '@':
+      case '/': case '\\': case ';': case ',': case '.': case '=':
+      case ':': case '<': case '>': case '\"':
+      case '&': case '`': case '\'': case '+':
+      case '0':
+	++m;
+	break;
+      case '-':
+	++m;
+	if (is_identchar(*m)) m += mbclen(*m);
+	break;
+      default:
+	if (!ISDIGIT(*m)) return 0;
+	do ++m; while (ISDIGIT(*m));
+    }
+    return !*m;
+}
+
+int
+rb_symname_p(name)
+    const char *name;
+{
+    const char *m = name;
+    int localid = Qfalse;
+
+    if (!m) return Qfalse;
+    switch (*m) {
+      case '\0':
+	return Qfalse;
+
+      case '$':
+	if (is_special_global_name(++m)) return Qtrue;
+	goto id;
+
+      case '@':
+	if (*++m == '@') ++m;
+	goto id;
+
+      case '<':
+	switch (*++m) {
+	  case '<': ++m; break;
+	  case '=': if (*++m == '>') ++m; break;
+	  default: break;
+	}
+	break;
+
+      case '>':
+	if (*++m == '>') ++m;
+	break;
+
+      case '=':
+	switch (*++m) {
+	  case '~': ++m; break;
+	  case '=': if (*++m == '=') ++m; break;
+	  default: return Qfalse;
+	}
+	break;
+
+      case '*':
+	if (*++m == '*') ++m;
+	break;
+
+      case '+': case '-':
+	if (*++m == '@') ++m;
+	break;
+
+      case '|': case '^': case '&': case '/': case '%': case '~': case '`':
+	break;
+
+      case '[':
+	if (*++m == ']' && *++m == '=') ++m;
+	break;
+
+      default:
+	localid = !ISUPPER(*m);
+      id:
+	if (*m != '_' && !ISALPHA(*m) && !ismbchar(*m)) return Qfalse;
+	while (is_identchar(*m)) m += mbclen(*m);
+	if (localid) {
+	    switch (*m) {
+	      case '!': case '?': case '=': ++m;
+	    }
+	}
+	break;
+    }
+    return *m ? Qfalse : Qtrue;
+}
+
 ID
 rb_intern(name)
     const char *name;
@@ -5853,8 +5990,7 @@ rb_intern(name)
     switch (*name) {
       case '$':
 	id |= ID_GLOBAL;
-	m++;
-	if (!is_identchar(*m)) m++;
+	if (is_special_global_name(++m)) goto new_id;
 	break;
       case '@':
 	if (name[1] == '@') {
@@ -5867,7 +6003,7 @@ rb_intern(name)
 	m++;
 	break;
       default:
-	if (name[0] != '_' && !ISALPHA(name[0]) && !ismbchar(name[0])) {
+	if (name[0] != '_' && ISASCII(name[0]) && !ISALNUM(name[0])) {
 	    /* operators */
 	    int i;
 
@@ -5901,10 +6037,13 @@ rb_intern(name)
 	}
 	break;
     }
-    while (m <= name + last && is_identchar(*m)) {
-	m += mbclen(*m);
+    if (!ISDIGIT(*m)) {
+	while (m <= name + last && is_identchar(*m)) {
+	    m += mbclen(*m);
+	}
     }
     if (*m) id = ID_JUNK;
+  new_id:
     id |= ++last_id << ID_SCOPE_SHIFT;
   id_regist:
     name = strdup(name);
@@ -6085,3 +6224,65 @@ rb_lastline_set(val)
 	special_local_set('_', val);
     }
 }
+
+#ifdef YYMALLOC
+#define HEAPCNT(n, size) ((n) * (size) / sizeof(YYSTYPE))
+#define NEWHEAP(cnt) rb_node_newnode(NODE_ALLOCA, 0, (VALUE)parser_heap, cnt)
+#define ADD2HEAP(n, ptr) ((parser_heap = (n))->u1.node = (ptr))
+
+static void *
+rb_parser_malloc(size)
+    size_t size;
+{
+    NODE *n = NEWHEAP(HEAPCNT(1, size));
+
+    return ADD2HEAP(n, xmalloc(size));
+}
+
+static void *
+rb_parser_calloc(nelem, size)
+    size_t nelem, size;
+{
+    NODE *n = NEWHEAP(HEAPCNT(nelem, size));
+
+    return ADD2HEAP(n, xcalloc(nelem, size));
+}
+
+static void *
+rb_parser_realloc(ptr, size)
+    void *ptr;
+    size_t size;
+{
+    NODE *n;
+    size_t cnt = HEAPCNT(1, size);
+
+    if (ptr && (n = parser_heap) != NULL) {
+	do {
+	    if (n->u1.node == ptr) {
+		n->u1.node = ptr = xrealloc(ptr, size);
+		if (n->u3.cnt) n->u3.cnt = cnt;
+		return ptr;
+	    }
+	} while ((n = n->u2.node) != NULL);
+    }
+    n = NEWHEAP(cnt);
+    return ADD2HEAP(n, xrealloc(ptr, size));
+}
+
+static void
+rb_parser_free(ptr)
+    void *ptr;
+{
+    NODE **prev = &parser_heap, *n;
+
+    while (n = *prev) {
+	if (n->u1.node == ptr) {
+	    *prev = n->u2.node;
+	    rb_gc_force_recycle((VALUE)n);
+	    break;
+	}
+	prev = &n->u2.node;
+    }
+    xfree(ptr);
+}
+#endif
