Index: snowball/algorithms/english/stem_ISO_8859_1.sbl
===================================================================
--- snowball/algorithms/english/stem_ISO_8859_1.sbl	(revision 402)
+++ snowball/algorithms/english/stem_ISO_8859_1.sbl	(working copy)
@@ -1,8 +1,6 @@
 integers ( p1 p2 )
-booleans ( Y_found )
 
 routines (
-    prelude postlude
     mark_regions
     shortv
     R1 R2
@@ -22,13 +20,6 @@
 
 define valid_LI 'cdeghkmnrt'
 
-define prelude as (
-    unset Y_found
-    do ( ['{'}'] delete)
-    do ( ['y'] <-'Y' set Y_found)
-    do repeat(goto (v ['y']) <-'Y' set Y_found)
-)
-
 define mark_regions as (
     $p1 = limit
     $p2 = limit
@@ -199,13 +190,16 @@
     )
 )
 
-define postlude as (Y_found  repeat(goto (['Y']) <-'y'))
-
 define stem as (
+    booleans ( Y_found )
 
     exception1 or
     not hop 3 or (
-        do prelude
+	( // prelude
+	    do ( ['{'}'] delete)
+	    do ( ['y'] <-'Y' set Y_found)
+	    do repeat(goto (v ['y']) <-'Y' set Y_found)
+	)
         do mark_regions
         backwards (
 
@@ -223,6 +217,8 @@
                 do Step_5
             )
         )
-        do postlude
+        ( // postlude
+	    Y_found  repeat(goto (['Y']) <-'y')
+	)
     )
 )
Index: snowball/compiler/analyser.c
===================================================================
--- snowball/compiler/analyser.c	(revision 402)
+++ snowball/compiler/analyser.c	(working copy)
@@ -216,7 +216,7 @@
     error2(a, 33, type);
 }
 
-static void read_names(struct analyser * a, int type) {
+static void read_names(struct analyser * a, int type, struct node * local) {
     struct tokeniser * t = a->tokeniser;
     unless (get_token(a, c_bra)) return;
     repeat {
@@ -226,12 +226,16 @@
             p->b = copy_b(t->b);
             p->type = type;
             p->mode = -1; /* routines, externals */
-            p->count = a->name_count[type];
             p->referenced = false;
             p->used = false;
             p->grouping = 0;
             p->definition = 0;
-            a->name_count[type] ++;
+	    p->local = local;
+	    if (local) {
+		p->count = -1;
+	    } else {
+		p->count = a->name_count[type]++;
+	    }
             p->next = a->names;
             a->names = p;
         }
@@ -349,7 +353,7 @@
     return p;
 }
 
-static struct node * read_C_list(struct analyser * a) {
+static struct node * read_C_list(struct analyser * a, int block) {
     struct tokeniser * t = a->tokeniser;
     struct node * p = new_node(a, c_bra);
     struct node * p_end = 0;
@@ -357,6 +361,14 @@
         int token = read_token(t);
         if (token == c_ket) return p;
         if (token < 0) { omission_error(a, c_ket); return p; }
+	if (block)
+	{
+	    switch (token) {
+		case c_booleans:    read_names(a, t_boolean, p); continue;
+		case c_integers:    read_names(a, t_integer, p); continue;
+	    }
+	}
+	block = false;
         t->token_held = true;
         {
             struct node * q = read_C(a);
@@ -531,7 +543,7 @@
                 p->number++; break;
             case c_bra:
                 if (previous_token == c_bra) error(a, 19);
-                q = read_C_list(a); break;
+                q = read_C_list(a, false); break;
             default:
                 error(a, 3);
             case c_ket:
@@ -562,7 +574,7 @@
     int token = read_token(t);
     switch (token) {
         case c_bra:
-            return read_C_list(a);
+            return read_C_list(a, true);
         case c_backwards:
             {
                 int mode = a->mode;
@@ -830,12 +842,12 @@
     struct tokeniser * t = a->tokeniser;
     repeat {
         switch (read_token(t)) {
-            case c_strings:     read_names(a, t_string); break;
-            case c_booleans:    read_names(a, t_boolean); break;
-            case c_integers:    read_names(a, t_integer); break;
-            case c_routines:    read_names(a, t_routine); break;
-            case c_externals:   read_names(a, t_external); break;
-            case c_groupings:   read_names(a, t_grouping); break;
+            case c_strings:     read_names(a, t_string, NULL); break;
+            case c_booleans:    read_names(a, t_boolean, NULL); break;
+            case c_integers:    read_names(a, t_integer, NULL); break;
+            case c_routines:    read_names(a, t_routine, NULL); break;
+            case c_externals:   read_names(a, t_external, NULL); break;
+            case c_groupings:   read_names(a, t_grouping, NULL); break;
             case c_define:      read_define(a); break;
             case c_backwardmode:read_backwardmode(a); break;
             case c_ket:
@@ -883,7 +895,7 @@
         warned = false;
         until (q == 0) {
             if (! q->used && (q->type == t_routine ||
-                              q->type == t_grouping)) {
+                              q->type == t_grouping) && q->referenced) {
                 unless (warned) {
                     fprintf(stderr, "Declared and defined but not used:");
                     warned = true;
Index: snowball/compiler/generator.c
===================================================================
--- snowball/compiler/generator.c	(revision 402)
+++ snowball/compiler/generator.c	(working copy)
@@ -62,9 +62,17 @@
 
     int ch = "SBIrxg"[p->type];
     switch (p->type) {
-        case t_string:
         case t_boolean:
         case t_integer:
+	    if (p->count < 0) {
+		/* Local variable */
+		char * s = b_to_s(p->b);
+		ws(g, "v_"); ws(g, s);
+		free(s);
+		return;
+	    }
+	    /* FALLTHRU */
+        case t_string:
             wch(g, ch); wch(g, '['); wi(g, p->count); wch(g, ']'); return;
         case t_external:
             ws(g, g->options->externals_prefix); break;
@@ -75,7 +83,7 @@
 }
 
 static void wv(struct generator * g, struct name * p) {  /* reference to variable */
-    if (p->type < t_routine) ws(g, "z->");
+    if (p->type < t_routine && p->count >= 0) ws(g, "z->");
     wvn(g, p);
 }
 
@@ -383,8 +391,25 @@
 }
 
 static void generate_bra(struct generator * g, struct node * p) {
+    struct name * q = g->analyser->names;
+    int in_block = false;
+    while (q != 0) {
+	if (q->local == p) {
+	    if (!in_block) {
+		in_block = true;
+		w(g, "~{");
+	    } else {
+		w(g, "~M");
+	    }
+	    g->S[0] = "int"; /* q->type == t_boolean ? "unsigned char" : "int"; */
+	    g->V[0] = q;
+	    w(g, "~S0 ~W0 = 0;~N");
+	}
+        q = q->next;
+    }
     p = p->left;
     until (p == 0) { generate(g, p); p = p->right; }
+    if (in_block) w(g, "~}~N");
 }
 
 static void generate_and(struct generator * g, struct node * p) {
@@ -1171,7 +1196,7 @@
             case t_integer: g->S[1] = "I"; goto label0;
             case t_boolean: g->S[1] = "B";
             label0:
-                if (vp) {
+                if (vp && q->count >= 0) {
                     g->I[0] = q->count;
                     w(g, "#define ~S0");
                     str_append_b(g->outbuf, q->b);
@@ -1234,3 +1259,4 @@
     FREE(g);
 }
 
+
Index: snowball/compiler/header.h
===================================================================
--- snowball/compiler/header.h	(revision 402)
+++ snowball/compiler/header.h	(working copy)
@@ -129,8 +129,9 @@
     int type;                   /* t_string etc */
     int mode;                   /*    )_  for routines, externals */
     struct node * definition;   /*    )                           */
-    int count;                  /* 0, 1, 2 for each type */
+    int count;                  /* 0, 1, 2 for each type; -1 for a local variable (which doesn't need a slot in SN_env) */
     struct grouping * grouping; /* for grouping names */
+    struct node * local;        /* used to indicate which function a local variable is local to */
     byte referenced;
     byte used;
 
Index: website/compiler/snowman.html
===================================================================
--- website/compiler/snowman.html	(revision 395)
+++ website/compiler/snowman.html	(working copy)
@@ -67,6 +67,19 @@
 subsequently not used are merely reported in a warning message. A name may
 not be one of the reserved words of Snowball.
 
+<P>In addition to these global variables, you can also declare integers
+and booleans locally to a block.  For example,
+<BR><PRE>
+    integers ( a b )
+    routines ( swap_a_and_b )
+    
+    define swap_a_and_b as (
+        integers ( temp )
+	$temp = a
+	$a = b
+	$b = temp
+    )
+</PRE>
 <BR>&nbsp;<H2>3 Literals</H2>
 
 A literal integer is a digit sequence, and is always interpreted as
@@ -945,6 +958,10 @@
                     externals ( [&lt;r_name>]* ) ||
                     groupings ( [&lt;g_name>]* )
 
+&lt;localvar&gt;      ::= <!-- NOT YET: strings ( [&lt;s_name>]* ) ||
+                    -->integers ( [&lt;i_name>]* ) ||
+                    booleans ( [&lt;b_name>]* ) ||
+
 &lt;r_definition>  ::= define &lt;r_name> as C
 &lt;plus_or_minus> ::= + || -
 &lt;g_definition>  ::= define &lt;g_name> G [ &lt;plus_or_minus> G ]*
@@ -963,7 +980,7 @@
 
 &lt;s_command>     ::= $ &lt;s_name> C
 
-C               ::= ( [C]* ) ||
+C               ::= ( [&lt;local_var&gt;] [C]* ) ||
                     &lt;i_command> || &lt;s_command> || C or C || C and C ||
                     not C || test C || try C || do C || fail C ||
                     goto C || gopast C || repeat C || loop AE C ||
