Imported from ../bash-2.0.tar.gz.
[platform/upstream/bash.git] / y.tab.c
diff --git a/y.tab.c b/y.tab.c
index 0b1fd09..406b32e 100644 (file)
--- a/y.tab.c
+++ b/y.tab.c
 #define        FUNCTION        271
 #define        IN      272
 #define        BANG    273
-#define        WORD    274
-#define        ASSIGNMENT_WORD 275
-#define        NUMBER  276
-#define        AND_AND 277
-#define        OR_OR   278
-#define        GREATER_GREATER 279
-#define        LESS_LESS       280
-#define        LESS_AND        281
-#define        GREATER_AND     282
-#define        SEMI_SEMI       283
-#define        LESS_LESS_MINUS 284
-#define        AND_GREATER     285
-#define        LESS_GREATER    286
-#define        GREATER_BAR     287
-#define        yacc_EOF        288
+#define        TIME    274
+#define        TIMEOPT 275
+#define        WORD    276
+#define        ASSIGNMENT_WORD 277
+#define        NUMBER  278
+#define        AND_AND 279
+#define        OR_OR   280
+#define        GREATER_GREATER 281
+#define        LESS_LESS       282
+#define        LESS_AND        283
+#define        GREATER_AND     284
+#define        SEMI_SEMI       285
+#define        LESS_LESS_MINUS 286
+#define        AND_GREATER     287
+#define        LESS_GREATER    288
+#define        GREATER_BAR     289
+#define        yacc_EOF        290
 
 #line 21 "./parse.y"
 
-#include <stdio.h>
+#include "config.h"
+
 #include "bashtypes.h"
-#include <signal.h>
 #include "bashansi.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if defined (HAVE_LOCALE_H)
+#  include <locale.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "memalloc.h"
+
 #include "shell.h"
+#include "trap.h"
 #include "flags.h"
-#include "input.h"
+#include "parser.h"
+#include "mailcheck.h"
+#include "builtins/common.h"
+#include "builtins/builtext.h"
 
 #if defined (READLINE)
+#  include "bashline.h"
 #  include <readline/readline.h>
 #endif /* READLINE */
 
 #include "maxpath.h"
 #endif /* PROMPT_STRING_DECODE */
 
-#define YYDEBUG 1
+#define RE_READ_TOKEN  -99
+#define NO_EXPANSION   -100
+
+#define YYDEBUG 0
+
 extern int eof_encountered;
-extern int no_line_editing;
+extern int no_line_editing, running_under_emacs;
 extern int current_command_number;
 extern int interactive, interactive_shell, login_shell;
+extern int sourcelevel;
 extern int posixly_correct;
 extern int last_command_exit_value;
 extern int interrupt_immediately;
 extern char *shell_name, *current_host_name;
+extern char *dist_version;
+extern int patch_level;
+extern int dump_translatable_strings;
 extern Function *last_shell_builtin, *this_shell_builtin;
-#if defined (READLINE)
-extern int bash_readline_initialized;
-#endif
 #if defined (BUFFERED_INPUT)
 extern int bash_input_fd_changed;
 #endif
@@ -93,12 +119,13 @@ extern int bash_input_fd_changed;
 /*                                                                 */
 /* **************************************************************** */
 
-/* This is kind of sickening.  In order to let these variables be seen by
-   all the functions that need them, I am forced to place their declarations
-   far away from the place where they should logically be found. */
-
+static char *ansiexpand ();
+static char *localeexpand ();
 static int reserved_word_acceptable ();
 static int read_token ();
+static int yylex ();
+static int read_token_word ();
+static void discard_parser_constructs ();
 
 static void report_syntax_error ();
 static void handle_eof_input_unit ();
@@ -106,6 +133,10 @@ static void prompt_again ();
 static void reset_readline_prompt ();
 static void print_prompt ();
 
+/* Default prompt strings */
+char *primary_prompt = PPROMPT;
+char *secondary_prompt = SPROMPT;
+
 /* PROMPT_STRING_POINTER points to one of these, never to an actual string. */
 char *ps1_prompt, *ps2_prompt;
 
@@ -114,31 +145,46 @@ char *ps1_prompt, *ps2_prompt;
 char **prompt_string_pointer = (char **)NULL;
 char *current_prompt_string;
 
+/* Non-zero means we expand aliases in commands. */
+int expand_aliases = 0;
+
+/* If non-zero, the decoded prompt string undergoes parameter and
+   variable substitution, command substitution, arithmetic substitution,
+   string expansion, process substitution, and quote removal in
+   decode_prompt_string. */
+int promptvars = 1;
+
 /* The decoded prompt string.  Used if READLINE is not defined or if
    editing is turned off.  Analogous to current_readline_prompt. */
 static char *current_decoded_prompt;
 
 /* The number of lines read from input while creating the current command. */
-int current_command_line_count = 0;
+int current_command_line_count;
 
 /* Variables to manage the task of reading here documents, because we need to
    defer the reading until after a complete command has been collected. */
 static REDIRECT *redir_stack[10];
-int need_here_doc = 0;
+int need_here_doc;
 
 /* Where shell input comes from.  History expansion is performed on each
    line when the shell is interactive. */
 static char *shell_input_line = (char *)NULL;
-static int shell_input_line_index = 0;
-static int shell_input_line_size = 0;  /* Amount allocated for shell_input_line. */
-static int shell_input_line_len = 0;   /* strlen (shell_input_line) */
+static int shell_input_line_index;
+static int shell_input_line_size;      /* Amount allocated for shell_input_line. */
+static int shell_input_line_len;       /* strlen (shell_input_line) */
 
 /* Either zero or EOF. */
-static int shell_input_line_terminator = 0;
+static int shell_input_line_terminator;
+
+/* The line number in a script on which a function definition starts. */
+static int function_dstart;
+
+/* The line number in a script on which a function body starts. */
+static int function_bstart;
 
 static REDIRECTEE redir;
 
-#line 122 "./parse.y"
+#line 166 "./parse.y"
 typedef union {
   WORD_DESC *word;             /* the word that we read. */
   int number;                  /* the number that we read. */
@@ -158,26 +204,26 @@ typedef union {
 
 
 
-#define        YYFINAL         258
+#define        YYFINAL         263
 #define        YYFLAG          -32768
-#define        YYNTBASE        45
+#define        YYNTBASE        47
 
-#define YYTRANSLATE(x) ((unsigned)(x) <= 288 ? yytranslate[x] : 73)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 290 ? yytranslate[x] : 78)
 
 static const char yytranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    35,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    37,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,    33,     2,    43,
-    44,     2,     2,     2,    40,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,    34,    39,
-     2,    38,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    35,     2,    45,
+    46,     2,     2,     2,    42,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,    36,    41,
+     2,    40,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,    41,    37,    42,     2,     2,     2,     2,     2,
+     2,     2,    43,    39,    44,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -193,99 +239,97 @@ static const char yytranslate[] = {     0,
      2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
      6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
     16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
-    26,    27,    28,    29,    30,    31,    32,    36
+    26,    27,    28,    29,    30,    31,    32,    33,    34,    38
 };
 
 #if YYDEBUG != 0
 static const short yyprhs[] = {     0,
-     0,     3,     5,     8,    10,    11,    14,    17,    20,    24,
-    28,    31,    35,    38,    42,    45,    49,    52,    56,    59,
-    63,    66,    70,    73,    77,    80,    84,    87,    91,    94,
-    98,   101,   104,   108,   110,   112,   114,   116,   119,   121,
-   124,   126,   128,   130,   133,   140,   147,   155,   163,   174,
-   185,   192,   200,   207,   213,   219,   221,   223,   225,   227,
-   229,   236,   243,   251,   259,   270,   281,   287,   294,   301,
-   309,   314,   320,   324,   330,   338,   345,   349,   354,   361,
-   367,   369,   372,   377,   382,   388,   394,   396,   399,   405,
-   411,   418,   425,   427,   431,   434,   436,   440,   444,   448,
-   453,   458,   463,   468,   473,   475,   478,   480,   482,   484,
-   485,   488,   490,   493,   496,   501,   506,   510,   514,   516,
-   519,   524
+     0,     3,     5,     8,    10,    12,    15,    18,    21,    25,
+    29,    32,    36,    39,    43,    46,    50,    53,    57,    60,
+    64,    67,    71,    74,    78,    81,    85,    88,    92,    95,
+    99,   102,   105,   109,   111,   113,   115,   117,   120,   122,
+   125,   127,   129,   132,   134,   136,   142,   148,   150,   152,
+   154,   156,   158,   165,   172,   180,   188,   199,   210,   217,
+   224,   232,   240,   251,   262,   269,   277,   284,   290,   297,
+   302,   306,   312,   320,   327,   331,   336,   343,   349,   351,
+   354,   359,   364,   370,   376,   379,   383,   385,   389,   392,
+   394,   397,   401,   405,   409,   414,   419,   424,   429,   434,
+   436,   438,   440,   442,   443,   446,   448,   451,   454,   459,
+   464,   468,   472,   474,   476,   479,   482,   486,   490,   495,
+   497,   499
 };
 
-static const short yyrhs[] = {    70,
-    35,     0,    35,     0,     1,    35,     0,    36,     0,     0,
-    46,    19,     0,    38,    19,     0,    39,    19,     0,    21,
-    38,    19,     0,    21,    39,    19,     0,    24,    19,     0,
-    21,    24,    19,     0,    25,    19,     0,    21,    25,    19,
-     0,    26,    21,     0,    21,    26,    21,     0,    27,    21,
-     0,    21,    27,    21,     0,    26,    19,     0,    21,    26,
-    19,     0,    27,    19,     0,    21,    27,    19,     0,    29,
-    19,     0,    21,    29,    19,     0,    27,    40,     0,    21,
-    27,    40,     0,    26,    40,     0,    21,    26,    40,     0,
-    30,    19,     0,    21,    31,    19,     0,    31,    19,     0,
-    32,    19,     0,    21,    32,    19,     0,    19,     0,    20,
-     0,    47,     0,    47,     0,    49,    47,     0,    48,     0,
-    50,    48,     0,    50,     0,    52,     0,    53,     0,    53,
-    49,     0,    10,    19,    69,    14,    65,    15,     0,    10,
-    19,    69,    41,    65,    42,     0,    10,    19,    34,    69,
-    14,    65,    15,     0,    10,    19,    34,    69,    41,    65,
-    42,     0,    10,    19,    69,    17,    46,    68,    69,    14,
-    65,    15,     0,    10,    19,    69,    17,    46,    68,    69,
-    41,    65,    42,     0,     8,    19,    69,    17,    69,     9,
-     0,     8,    19,    69,    17,    62,    69,     9,     0,     8,
-    19,    69,    17,    60,     9,     0,    12,    65,    14,    65,
-    15,     0,    13,    65,    14,    65,    15,     0,    54,     0,
-    57,     0,    56,     0,    58,     0,    55,     0,    11,    19,
-    69,    14,    65,    15,     0,    11,    19,    69,    41,    65,
-    42,     0,    11,    19,    34,    69,    14,    65,    15,     0,
-    11,    19,    34,    69,    41,    65,    42,     0,    11,    19,
-    69,    17,    46,    68,    69,    14,    65,    15,     0,    11,
-    19,    69,    17,    46,    68,    69,    41,    65,    42,     0,
-    19,    43,    44,    69,    58,     0,    19,    43,    44,    69,
-    58,    49,     0,    16,    19,    43,    44,    69,    58,     0,
-    16,    19,    43,    44,    69,    58,    49,     0,    16,    19,
-    69,    58,     0,    16,    19,    69,    58,    49,     0,    43,
-    65,    44,     0,     3,    65,     4,    65,     7,     0,     3,
-    65,     4,    65,     5,    65,     7,     0,     3,    65,     4,
-    65,    59,     7,     0,    41,    65,    42,     0,     6,    65,
-     4,    65,     0,     6,    65,     4,    65,     5,    65,     0,
-     6,    65,     4,    65,    59,     0,    61,     0,    62,    61,
-     0,    69,    64,    44,    65,     0,    69,    64,    44,    69,
-     0,    69,    43,    64,    44,    65,     0,    69,    43,    64,
-    44,    69,     0,    63,     0,    62,    63,     0,    69,    64,
-    44,    65,    28,     0,    69,    64,    44,    69,    28,     0,
-    69,    43,    64,    44,    65,    28,     0,    69,    43,    64,
-    44,    69,    28,     0,    19,     0,    64,    37,    19,     0,
-    69,    66,     0,    67,     0,    67,    35,    69,     0,    67,
-    33,    69,     0,    67,    34,    69,     0,    67,    22,    69,
-    67,     0,    67,    23,    69,    67,     0,    67,    33,    69,
-    67,     0,    67,    34,    69,    67,     0,    67,    35,    69,
-    67,     0,    72,     0,    18,    72,     0,    35,     0,    34,
-     0,    36,     0,     0,    69,    35,     0,    71,     0,    71,
-    33,     0,    71,    34,     0,    71,    22,    69,    71,     0,
-    71,    23,    69,    71,     0,    71,    33,    71,     0,    71,
-    34,    71,     0,    72,     0,    18,    72,     0,    72,    37,
-    69,    72,     0,    51,     0
+static const short yyrhs[] = {    73,
+    37,     0,    37,     0,     1,    37,     0,    38,     0,    21,
+     0,    48,    21,     0,    40,    21,     0,    41,    21,     0,
+    23,    40,    21,     0,    23,    41,    21,     0,    26,    21,
+     0,    23,    26,    21,     0,    27,    21,     0,    23,    27,
+    21,     0,    28,    23,     0,    23,    28,    23,     0,    29,
+    23,     0,    23,    29,    23,     0,    28,    21,     0,    23,
+    28,    21,     0,    29,    21,     0,    23,    29,    21,     0,
+    31,    21,     0,    23,    31,    21,     0,    29,    42,     0,
+    23,    29,    42,     0,    28,    42,     0,    23,    28,    42,
+     0,    32,    21,     0,    23,    33,    21,     0,    33,    21,
+     0,    34,    21,     0,    23,    34,    21,     0,    21,     0,
+    22,     0,    49,     0,    49,     0,    51,    49,     0,    50,
+     0,    52,    50,     0,    52,     0,    54,     0,    54,    51,
+     0,    55,     0,    57,     0,    12,    68,    14,    68,    15,
+     0,    13,    68,    14,    68,    15,     0,    56,     0,    60,
+     0,    59,     0,    61,     0,    58,     0,    10,    21,    72,
+    14,    67,    15,     0,    10,    21,    72,    43,    67,    44,
+     0,    10,    21,    36,    72,    14,    67,    15,     0,    10,
+    21,    36,    72,    43,    67,    44,     0,    10,    21,    72,
+    17,    48,    71,    72,    14,    67,    15,     0,    10,    21,
+    72,    17,    48,    71,    72,    43,    67,    44,     0,    11,
+    21,    72,    14,    67,    15,     0,    11,    21,    72,    43,
+    67,    44,     0,    11,    21,    36,    72,    14,    67,    15,
+     0,    11,    21,    36,    72,    43,    67,    44,     0,    11,
+    21,    72,    17,    48,    71,    72,    14,    67,    15,     0,
+    11,    21,    72,    17,    48,    71,    72,    43,    67,    44,
+     0,     8,    21,    72,    17,    72,     9,     0,     8,    21,
+    72,    17,    65,    72,     9,     0,     8,    21,    72,    17,
+    63,     9,     0,    21,    45,    46,    72,    61,     0,    16,
+    21,    45,    46,    72,    61,     0,    16,    21,    72,    61,
+     0,    45,    68,    46,     0,     3,    68,     4,    68,     7,
+     0,     3,    68,     4,    68,     5,    68,     7,     0,     3,
+    68,     4,    68,    62,     7,     0,    43,    67,    44,     0,
+     6,    68,     4,    68,     0,     6,    68,     4,    68,     5,
+    68,     0,     6,    68,     4,    68,    62,     0,    64,     0,
+    65,    64,     0,    72,    66,    46,    68,     0,    72,    66,
+    46,    72,     0,    72,    45,    66,    46,    68,     0,    72,
+    45,    66,    46,    72,     0,    64,    30,     0,    65,    64,
+    30,     0,    21,     0,    66,    39,    21,     0,    72,    69,
+     0,    67,     0,    72,    70,     0,    70,    37,    72,     0,
+    70,    35,    72,     0,    70,    36,    72,     0,    70,    24,
+    72,    70,     0,    70,    25,    72,    70,     0,    70,    35,
+    72,    70,     0,    70,    36,    72,    70,     0,    70,    37,
+    72,    70,     0,    75,     0,    37,     0,    36,     0,    38,
+     0,     0,    72,    37,     0,    74,     0,    74,    35,     0,
+    74,    36,     0,    74,    24,    72,    74,     0,    74,    25,
+    72,    74,     0,    74,    35,    74,     0,    74,    36,    74,
+     0,    75,     0,    76,     0,    18,    76,     0,    77,    76,
+     0,    77,    18,    76,     0,    18,    77,    76,     0,    76,
+    39,    72,    76,     0,    53,     0,    19,     0,    19,    20,
+     0
 };
 
 #endif
 
 #if YYDEBUG != 0
 static const short yyrline[] = { 0,
-   163,   172,   179,   195,   205,   207,   211,   216,   221,   226,
-   231,   236,   241,   247,   253,   258,   263,   268,   273,   278,
-   283,   288,   293,   300,   307,   312,   317,   322,   327,   332,
-   337,   353,   358,   365,   367,   369,   373,   377,   388,   390,
-   394,   396,   400,   402,   417,   419,   421,   423,   425,   427,
-   430,   432,   434,   436,   438,   440,   442,   444,   446,   448,
-   452,   458,   464,   470,   476,   482,   490,   493,   496,   499,
-   502,   505,   509,   513,   515,   517,   522,   526,   528,   530,
-   534,   535,   539,   541,   543,   545,   549,   550,   554,   556,
-   558,   560,   564,   566,   575,   583,   584,   585,   592,   596,
-   598,   600,   607,   609,   611,   613,   620,   621,   622,   625,
-   626,   635,   641,   650,   658,   660,   662,   669,   671,   673,
-   680,   683
+   209,   218,   225,   240,   250,   252,   256,   261,   266,   271,
+   276,   281,   286,   292,   298,   303,   308,   313,   318,   323,
+   328,   333,   338,   345,   352,   357,   362,   367,   372,   377,
+   382,   387,   392,   399,   401,   403,   407,   411,   422,   424,
+   428,   430,   432,   461,   463,   465,   467,   469,   471,   473,
+   475,   477,   481,   483,   485,   487,   489,   491,   495,   499,
+   503,   507,   511,   515,   521,   523,   525,   529,   533,   536,
+   540,   544,   546,   548,   553,   557,   559,   561,   565,   566,
+   570,   572,   574,   576,   580,   581,   585,   587,   596,   604,
+   605,   611,   612,   619,   623,   625,   627,   634,   636,   638,
+   642,   643,   644,   647,   648,   657,   663,   672,   680,   682,
+   684,   691,   694,   698,   700,   705,   710,   715,   722,   725,
+   729,   731
 };
 #endif
 
@@ -294,236 +338,238 @@ static const short yyrline[] = { 0,
 
 static const char * const yytname[] = {   "$","error","$undefined.","IF","THEN",
 "ELSE","ELIF","FI","CASE","ESAC","FOR","SELECT","WHILE","UNTIL","DO","DONE",
-"FUNCTION","IN","BANG","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND","OR_OR","GREATER_GREATER",
-"LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS","AND_GREATER",
-"LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'","'>'","'<'",
-"'-'","'{'","'}'","'('","')'","inputunit","words","redirection","simple_command_element",
-"redirections","simple_command","command","shell_command","shell_command_1",
-"select_command","function_def","subshell","if_command","group_command","elif_clause",
-"case_clause_1","pattern_list_1","case_clause_sequence","pattern_list","pattern",
-"list","list0","list1","list_terminator","newlines","simple_list","simple_list1",
-"pipeline", NULL
+"FUNCTION","IN","BANG","TIME","TIMEOPT","WORD","ASSIGNMENT_WORD","NUMBER","AND_AND",
+"OR_OR","GREATER_GREATER","LESS_LESS","LESS_AND","GREATER_AND","SEMI_SEMI","LESS_LESS_MINUS",
+"AND_GREATER","LESS_GREATER","GREATER_BAR","'&'","';'","'\\n'","yacc_EOF","'|'",
+"'>'","'<'","'-'","'{'","'}'","'('","')'","inputunit","word_list","redirection",
+"simple_command_element","redirection_list","simple_command","command","shell_command",
+"for_command","select_command","case_command","function_def","subshell","if_command",
+"group_command","elif_clause","case_clause","pattern_list","case_clause_sequence",
+"pattern","list","compound_list","list0","list1","list_terminator","newline_list",
+"simple_list","simple_list1","pipeline_command","pipeline","timespec", NULL
 };
 #endif
 
 static const short yyr1[] = {     0,
-    45,    45,    45,    45,    46,    46,    47,    47,    47,    47,
-    47,    47,    47,    47,    47,    47,    47,    47,    47,    47,
-    47,    47,    47,    47,    47,    47,    47,    47,    47,    47,
-    47,    47,    47,    48,    48,    48,    49,    49,    50,    50,
-    51,    51,    52,    52,    53,    53,    53,    53,    53,    53,
-    53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
-    54,    54,    54,    54,    54,    54,    55,    55,    55,    55,
-    55,    55,    56,    57,    57,    57,    58,    59,    59,    59,
-    60,    60,    61,    61,    61,    61,    62,    62,    63,    63,
-    63,    63,    64,    64,    65,    66,    66,    66,    66,    67,
-    67,    67,    67,    67,    67,    67,    68,    68,    68,    69,
-    69,    70,    70,    70,    71,    71,    71,    71,    71,    71,
-    72,    72
+    47,    47,    47,    47,    48,    48,    49,    49,    49,    49,
+    49,    49,    49,    49,    49,    49,    49,    49,    49,    49,
+    49,    49,    49,    49,    49,    49,    49,    49,    49,    49,
+    49,    49,    49,    50,    50,    50,    51,    51,    52,    52,
+    53,    53,    53,    54,    54,    54,    54,    54,    54,    54,
+    54,    54,    55,    55,    55,    55,    55,    55,    56,    56,
+    56,    56,    56,    56,    57,    57,    57,    58,    58,    58,
+    59,    60,    60,    60,    61,    62,    62,    62,    63,    63,
+    64,    64,    64,    64,    65,    65,    66,    66,    67,    68,
+    68,    69,    69,    69,    70,    70,    70,    70,    70,    70,
+    71,    71,    71,    72,    72,    73,    73,    73,    74,    74,
+    74,    74,    74,    75,    75,    75,    75,    75,    76,    76,
+    77,    77
 };
 
 static const short yyr2[] = {     0,
-     2,     1,     2,     1,     0,     2,     2,     2,     3,     3,
+     2,     1,     2,     1,     1,     2,     2,     2,     3,     3,
      2,     3,     2,     3,     2,     3,     2,     3,     2,     3,
      2,     3,     2,     3,     2,     3,     2,     3,     2,     3,
      2,     2,     3,     1,     1,     1,     1,     2,     1,     2,
-     1,     1,     1,     2,     6,     6,     7,     7,    10,    10,
-     6,     7,     6,     5,     5,     1,     1,     1,     1,     1,
-     6,     6,     7,     7,    10,    10,     5,     6,     6,     7,
-     4,     5,     3,     5,     7,     6,     3,     4,     6,     5,
-     1,     2,     4,     4,     5,     5,     1,     2,     5,     5,
-     6,     6,     1,     3,     2,     1,     3,     3,     3,     4,
-     4,     4,     4,     4,     1,     2,     1,     1,     1,     0,
-     2,     1,     2,     2,     4,     4,     3,     3,     1,     2,
-     4,     1
+     1,     1,     2,     1,     1,     5,     5,     1,     1,     1,
+     1,     1,     6,     6,     7,     7,    10,    10,     6,     6,
+     7,     7,    10,    10,     6,     7,     6,     5,     6,     4,
+     3,     5,     7,     6,     3,     4,     6,     5,     1,     2,
+     4,     4,     5,     5,     2,     3,     1,     3,     2,     1,
+     2,     3,     3,     3,     4,     4,     4,     4,     4,     1,
+     1,     1,     1,     0,     2,     1,     2,     2,     4,     4,
+     3,     3,     1,     1,     2,     2,     3,     3,     4,     1,
+     1,     2
 };
 
 static const short yydefact[] = {     0,
-     0,   110,     0,     0,     0,   110,   110,     0,     0,    34,
-    35,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     2,     4,     0,     0,   110,   110,    36,    39,    41,   122,
-    42,    43,    56,    60,    58,    57,    59,     0,   112,   119,
-     3,     0,     0,   110,   110,   110,     0,     0,   110,   120,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-    11,    13,    19,    15,    27,    21,    17,    25,    23,    29,
-    31,    32,     7,     8,     0,     0,    34,    40,    37,    44,
-     1,   110,   110,   113,   114,   110,   110,     0,   111,    95,
-    96,   105,     0,   110,     0,   110,     0,   110,   110,     0,
-     0,   110,    12,    14,    20,    16,    28,    22,    18,    26,
-    24,    30,    33,     9,    10,    77,    73,    38,     0,     0,
-   117,   118,     0,     0,   106,   110,   110,   110,   110,   110,
-   110,     0,   110,     5,   110,     0,   110,     5,   110,     0,
-     0,   110,    71,     0,   115,   116,     0,     0,   121,   110,
-   110,    74,     0,     0,     0,    98,    99,    97,     0,    81,
-   110,    87,     0,   110,   110,     0,     0,     0,   110,   110,
-     0,     0,     0,    54,    55,     0,    72,    67,     0,     0,
-    76,   100,   101,   102,   103,   104,    53,    82,    88,     0,
-    51,    93,     0,     0,     0,     0,    45,     6,   108,   107,
-   109,   110,    46,     0,     0,    61,   110,    62,    69,    68,
-    75,   110,   110,   110,   110,    52,     0,     0,   110,    47,
-    48,     0,    63,    64,     0,    70,    78,     0,     0,     0,
-   110,    94,    83,    84,   110,   110,   110,   110,   110,    80,
-    85,    86,    89,    90,     0,     0,     0,     0,    79,    91,
-    92,    49,    50,    65,    66,     0,     0,     0
+     0,   104,     0,     0,     0,   104,   104,     0,     0,   121,
+    34,    35,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     2,     4,     0,     0,   104,   104,    36,    39,    41,
+   120,    42,    44,    48,    45,    52,    50,    49,    51,     0,
+   106,   113,   114,     0,     3,    90,     0,     0,   104,   104,
+   104,     0,     0,   104,   115,     0,   122,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,    11,    13,    19,
+    15,    27,    21,    17,    25,    23,    29,    31,    32,     7,
+     8,     0,     0,     0,    34,    40,    37,    43,     1,   104,
+   104,   107,   108,   104,     0,   116,   104,   105,    89,    91,
+   100,     0,   104,     0,   104,     0,   104,   104,     0,     0,
+   118,   104,    12,    14,    20,    16,    28,    22,    18,    26,
+    24,    30,    33,     9,    10,    75,     0,    71,    38,     0,
+     0,   111,   112,     0,   117,     0,   104,   104,   104,   104,
+   104,   104,     0,   104,     0,   104,     0,   104,     0,   104,
+     0,     0,   104,    70,     0,   109,   110,     0,     0,   119,
+   104,   104,    72,     0,     0,     0,    93,    94,    92,     0,
+    79,   104,     0,   104,   104,     0,     5,     0,     0,   104,
+   104,     0,     0,     0,    46,    47,     0,    68,     0,     0,
+    74,    95,    96,    97,    98,    99,    67,    85,    80,     0,
+    65,    87,     0,     0,     0,     0,    53,     6,   102,   101,
+   103,   104,    54,     0,     0,    59,   104,    60,    69,    73,
+   104,   104,   104,   104,    86,    66,     0,     0,   104,    55,
+    56,     0,    61,    62,     0,    76,     0,     0,     0,   104,
+    88,    81,    82,   104,   104,   104,   104,   104,    78,    83,
+    84,     0,     0,     0,     0,    77,    57,    58,    63,    64,
+     0,     0,     0
 };
 
-static const short yydefgoto[] = {   256,
-   167,    27,    28,    80,    29,    30,    31,    32,    33,    34,
-    35,    36,    37,   153,   159,   160,   161,   162,   194,    42,
-    90,    91,   202,    43,    38,   121,    92
+static const short yydefgoto[] = {   261,
+   178,    28,    29,    88,    30,    31,    32,    33,    34,    35,
+    36,    37,    38,    39,   164,   170,   171,   172,   204,    46,
+    47,    99,   100,   212,    83,    40,   132,   101,    43,    44
 };
 
-static const short yypact[] = {   233,
-   -28,-32768,     2,    10,    15,-32768,-32768,    32,   437,    19,
--32768,   494,    46,    52,    -5,    39,    59,    61,    93,    95,
--32768,-32768,   102,   103,-32768,-32768,-32768,-32768,   462,-32768,
--32768,   478,-32768,-32768,-32768,-32768,-32768,    71,   116,    91,
--32768,   126,   301,-32768,   117,   118,   123,   139,    89,    91,
-   111,   137,   138,    75,    76,   141,   143,   146,   148,   149,
+static const short yypact[] = {   246,
+   -19,-32768,     8,    25,    29,-32768,-32768,    33,   354,     4,
+    34,-32768,   499,    46,    51,    32,    38,    56,    70,    72,
+    90,-32768,-32768,    97,   101,-32768,-32768,-32768,-32768,   161,
+-32768,   483,-32768,-32768,-32768,-32768,-32768,-32768,-32768,     6,
+   139,-32768,    84,   390,-32768,-32768,   120,   282,-32768,    89,
+    94,   112,   117,    87,    84,   462,-32768,    96,   123,   127,
+    52,    55,   128,   129,   133,   137,   140,-32768,-32768,-32768,
 -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768,   127,   131,-32768,-32768,-32768,   478,
--32768,-32768,-32768,   369,   369,-32768,-32768,   437,-32768,-32768,
-   101,    91,    37,-32768,    -4,-32768,    22,-32768,-32768,   133,
-   -23,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,   335,   335,
-    60,    60,   403,    98,    91,-32768,-32768,-32768,-32768,-32768,
--32768,     3,-32768,-32768,-32768,    33,-32768,-32768,-32768,   167,
-   172,-32768,   478,   -23,-32768,-32768,   369,   369,    91,-32768,
--32768,-32768,   181,   301,   301,   301,   301,   301,   186,-32768,
--32768,-32768,    21,-32768,-32768,   192,    83,   168,-32768,-32768,
-   194,    83,   175,-32768,-32768,   -23,   478,   478,   208,   214,
--32768,-32768,-32768,    87,    87,    87,-32768,-32768,-32768,    24,
--32768,-32768,   200,   -22,   205,   179,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,   207,   182,-32768,-32768,-32768,   478,   478,
--32768,-32768,-32768,-32768,-32768,-32768,    29,   204,-32768,-32768,
--32768,    34,-32768,-32768,    35,   478,   135,   301,   301,   301,
--32768,-32768,   198,   173,-32768,-32768,-32768,-32768,-32768,-32768,
-   199,   267,-32768,-32768,   213,   193,   222,   196,-32768,-32768,
--32768,-32768,-32768,-32768,-32768,   239,   240,-32768
+-32768,   121,   282,   122,-32768,-32768,-32768,   483,-32768,-32768,
+-32768,   318,   318,-32768,   462,    84,-32768,-32768,-32768,    92,
+-32768,   -10,-32768,     2,-32768,    14,-32768,-32768,   130,   -28,
+    84,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,    92,-32768,-32768,   282,
+   282,    10,    10,   426,    84,    93,-32768,-32768,-32768,-32768,
+-32768,-32768,    23,-32768,   148,-32768,    26,-32768,   148,-32768,
+   158,   164,-32768,-32768,   -28,-32768,-32768,   318,   318,    84,
+-32768,-32768,-32768,   178,   282,   282,   282,   282,   282,   177,
+   166,-32768,    -7,-32768,-32768,   176,-32768,    83,   153,-32768,
+-32768,   183,    83,   155,-32768,-32768,   -28,-32768,   193,   199,
+-32768,-32768,-32768,    57,    57,    57,-32768,-32768,   174,    -1,
+-32768,-32768,   184,   -29,   191,   163,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,   194,   167,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,   -13,   187,-32768,-32768,
+-32768,    27,-32768,-32768,    28,   103,   282,   282,   282,-32768,
+-32768,-32768,   282,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+   282,   197,   169,   201,   170,-32768,-32768,-32768,-32768,-32768,
+   217,   218,-32768
 };
 
 static const short yypgoto[] = {-32768,
-   104,   -30,   218,  -132,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,   -92,    28,-32768,   100,-32768,   105,    55,    -6,
--32768,  -130,    78,   -41,-32768,     6,    23
+    74,   -26,   195,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,   -97,   -12,-32768,    58,-32768,    30,    -3,
+     5,-32768,   -82,    45,    -2,-32768,     3,    22,    12,   220
 };
 
 
-#define        YYLAST          533
-
-
-static const short yytable[] = {    47,
-    48,    79,    93,    95,    97,    39,    41,   101,   143,   133,
-   177,    89,   134,    63,   218,    64,   164,    25,    75,    76,
-    44,   219,    40,   182,   183,   184,   185,   186,    45,   191,
-    89,    50,   216,    46,    65,   137,   135,    89,   138,   192,
-   119,   120,   192,   165,   123,   210,   169,   235,   237,   118,
-    49,   178,   132,   131,   136,    89,    89,    66,    89,    67,
-   144,    51,   139,   193,    61,   218,   193,    89,    89,    89,
-    62,    89,   231,   170,   236,   238,   226,    69,    68,    70,
-   124,    82,    83,   209,   154,   155,   156,   157,   158,   163,
-   122,   140,   141,   105,   108,   106,   109,   184,   185,   186,
-   176,   198,   150,   151,   152,    81,    40,    40,   126,   127,
-   125,    71,    79,    72,   107,   110,   199,   200,   201,   190,
-    73,    74,   126,   127,   145,   146,   166,    86,   168,    87,
-   171,   100,   173,   128,   129,   130,    98,    82,    83,   239,
-   151,    40,    40,   179,   180,   149,   118,    79,    84,    85,
-    94,    96,    99,   122,   102,   103,   104,   195,   196,   111,
-   222,   112,   204,   205,   113,   225,   114,   115,   116,    40,
-    40,   228,   229,   230,   117,     2,   142,   234,    79,   118,
-     3,   174,     4,     5,     6,     7,   175,   181,     8,   242,
-    88,    10,    11,    12,   187,   118,    13,    14,    15,    16,
-   244,    17,    18,    19,    20,   227,   197,    89,   206,   203,
-    23,    24,   233,    25,   211,    26,   208,   212,   192,   220,
-   221,   223,   232,   224,   241,   243,   250,   252,   245,   246,
-   247,   248,   249,     1,   253,     2,   254,   255,   257,   258,
-     3,   172,     4,     5,     6,     7,    78,   217,     8,   207,
-     9,    10,    11,    12,   240,     0,    13,    14,    15,    16,
-   188,    17,    18,    19,    20,   189,     0,    21,    22,     2,
-    23,    24,     0,    25,     3,    26,     4,     5,     6,     7,
-     0,     0,     8,     0,    88,    10,    11,    12,     0,     0,
-    13,    14,    15,    16,   251,    17,    18,    19,    20,     0,
-     0,    89,     0,     2,    23,    24,     0,    25,     3,    26,
-     4,     5,     6,     7,     0,     0,     8,     0,    88,    10,
-    11,    12,     0,     0,    13,    14,    15,    16,     0,    17,
-    18,    19,    20,     0,     0,    89,     0,     2,    23,    24,
-     0,    25,     3,    26,     4,     5,     6,     7,     0,     0,
-     8,     0,     9,    10,    11,    12,     0,     0,    13,    14,
-    15,    16,     0,    17,    18,    19,    20,     0,     0,    89,
-     0,     2,    23,    24,     0,    25,     3,    26,     4,     5,
-     6,     7,     0,     0,     8,     0,     9,    10,    11,    12,
-     0,     0,    13,    14,    15,    16,     0,    17,    18,    19,
-    20,     0,     0,     0,     0,     2,    23,    24,     0,    25,
-     3,    26,     4,     5,     6,     7,     0,     0,     8,     0,
-     0,    10,    11,    12,     0,     0,    13,    14,    15,    16,
-     0,    17,    18,    19,    20,     0,     0,    89,     0,     2,
-    23,    24,     0,    25,     3,    26,     4,     5,     6,     7,
-     0,     0,     8,     0,     0,    10,    11,    12,     0,     0,
-    13,    14,    15,    16,     0,    17,    18,    19,    20,     0,
-     0,     0,     0,     0,    23,    24,     0,    25,     0,    26,
-    77,    11,    12,     0,     0,    13,    14,    15,    16,     0,
-    17,    18,    19,    20,     0,     0,     0,     0,    12,    23,
-    24,    13,    14,    15,    16,     0,    17,    18,    19,    20,
-     0,     0,     0,     0,     0,    23,    24,    52,    53,    54,
-    55,     0,    56,     0,    57,    58,     0,     0,     0,     0,
-     0,    59,    60
+#define        YYLAST          540
+
+
+static const short yytable[] = {    48,
+   127,   201,    41,    48,    48,    87,   142,   226,    98,   228,
+    52,    53,   154,   202,    26,   144,   229,    45,   145,   202,
+    55,    42,    82,    57,    48,   228,    98,   148,    49,    98,
+   149,    84,   240,    90,    91,    98,   174,   203,    98,   180,
+   244,   246,    89,   203,   146,    50,   102,   104,   106,    51,
+    98,   110,    70,    54,    71,    96,   150,   188,    73,    98,
+    74,   129,    98,    98,    98,   175,    68,   111,   181,   245,
+   247,    69,   115,    72,   116,   118,    76,   119,    58,    75,
+   137,   138,   192,   193,   194,   195,   196,   130,   131,   219,
+    77,   134,    78,   117,    48,   133,   120,   161,   162,   163,
+   143,   136,   147,   208,    48,    48,   135,   248,   162,   155,
+    79,   151,   152,    42,    42,   137,   138,    80,   209,   210,
+   211,    81,    94,    97,   103,   107,   139,   140,   141,   105,
+   108,   109,   156,   157,   165,   166,   167,   168,   169,   173,
+   176,   112,   179,   113,   182,   160,   184,   114,   121,   122,
+   187,    42,    42,   123,   194,   195,   196,   124,    48,    48,
+   125,   133,    90,    91,   126,   189,   190,   128,   177,   200,
+   205,   206,   185,    92,    93,   153,   214,   215,   186,    42,
+    42,    85,    12,    13,   191,   197,    14,    15,    16,    17,
+   207,    18,    19,    20,    21,   198,   213,   216,   218,   220,
+    24,    25,   221,   225,   202,   230,   231,   241,   233,   232,
+   234,   257,   258,   260,   235,   259,   262,   263,    48,   237,
+   238,   239,   183,   249,    86,   236,   243,   217,    56,   199,
+     0,     0,   227,   242,     0,     0,     0,   251,     0,     0,
+   252,   253,   254,   255,   250,    48,     1,     0,     2,     0,
+     0,     0,   256,     3,     0,     4,     5,     6,     7,     0,
+     0,     8,     0,     9,    10,     0,    11,    12,    13,     0,
+     0,    14,    15,    16,    17,     0,    18,    19,    20,    21,
+     0,     0,    22,    23,     2,    24,    25,     0,    26,     3,
+    27,     4,     5,     6,     7,     0,     0,     8,     0,     9,
+    10,     0,    11,    12,    13,     0,     0,    14,    15,    16,
+    17,     0,    18,    19,    20,    21,     0,     0,    98,     0,
+     2,    24,    25,     0,    26,     3,    27,     4,     5,     6,
+     7,     0,     0,     8,     0,     9,    10,     0,    11,    12,
+    13,     0,     0,    14,    15,    16,    17,     0,    18,    19,
+    20,    21,     0,     0,     0,     0,     2,    24,    25,     0,
+    26,     3,    27,     4,     5,     6,     7,     0,     0,     8,
+     0,     0,    10,     0,    11,    12,    13,     0,     0,    14,
+    15,    16,    17,     0,    18,    19,    20,    21,     0,     0,
+     0,     0,     2,    24,    25,     0,    26,     3,    27,     4,
+     5,     6,     7,     0,     0,     8,     0,    95,     0,     0,
+    11,    12,    13,     0,     0,    14,    15,    16,    17,     0,
+    18,    19,    20,    21,     0,     0,     0,     0,     2,    24,
+    25,     0,    26,     3,    27,     4,     5,     6,     7,     0,
+     0,     8,     0,     0,     0,     0,    11,    12,    13,     0,
+     0,    14,    15,    16,    17,     0,    18,    19,    20,    21,
+     0,     0,    98,     0,     2,    24,    25,     0,    26,     3,
+    27,     4,     5,     6,     7,     0,     0,     8,     0,     0,
+     0,     0,    11,    12,    13,     0,     0,    14,    15,    16,
+    17,     0,    18,    19,    20,    21,     0,     0,     0,     0,
+     0,    24,    25,     0,    26,    13,    27,     0,    14,    15,
+    16,    17,     0,    18,    19,    20,    21,     0,     0,     0,
+     0,     0,    24,    25,    59,    60,    61,    62,     0,    63,
+     0,    64,    65,     0,     0,     0,     0,     0,    66,    67
 };
 
-static const short yycheck[] = {     6,
-     7,    32,    44,    45,    46,     0,    35,    49,   101,    14,
-   143,    35,    17,    19,    37,    21,    14,    41,    25,    26,
-    19,    44,     0,   154,   155,   156,   157,   158,    19,     9,
-    35,     9,     9,    19,    40,    14,    41,    35,    17,    19,
-    82,    83,    19,    41,    86,   178,    14,    14,    14,    80,
-    19,   144,    94,    17,    96,    35,    35,    19,    35,    21,
-   102,    43,    41,    43,    19,    37,    43,    35,    35,    35,
-    19,    35,    44,    41,    41,    41,   209,    19,    40,    19,
-    87,    22,    23,   176,   126,   127,   128,   129,   130,   131,
-    85,    98,    99,    19,    19,    21,    21,   228,   229,   230,
-   142,    19,     5,     6,     7,    35,    84,    85,    22,    23,
-    88,    19,   143,    19,    40,    40,    34,    35,    36,   161,
-    19,    19,    22,    23,   119,   120,   133,    37,   135,     4,
-   137,    43,   139,    33,    34,    35,    14,    22,    23,     5,
-     6,   119,   120,   150,   151,   123,   177,   178,    33,    34,
-    34,    34,    14,   148,    44,    19,    19,   164,   165,    19,
-   202,    19,   169,   170,    19,   207,    19,    19,    42,   147,
-   148,   213,   214,   215,    44,     3,    44,   219,   209,   210,
-     8,    15,    10,    11,    12,    13,    15,     7,    16,   231,
-    18,    19,    20,    21,     9,   226,    24,    25,    26,    27,
-    28,    29,    30,    31,    32,   212,    15,    35,    15,    42,
-    38,    39,   219,    41,     7,    43,    42,     4,    19,    15,
-    42,    15,    19,    42,   231,    28,    28,    15,   235,   236,
-   237,   238,   239,     1,    42,     3,    15,    42,     0,     0,
-     8,   138,    10,    11,    12,    13,    29,   193,    16,   172,
-    18,    19,    20,    21,   227,    -1,    24,    25,    26,    27,
-   161,    29,    30,    31,    32,   161,    -1,    35,    36,     3,
-    38,    39,    -1,    41,     8,    43,    10,    11,    12,    13,
-    -1,    -1,    16,    -1,    18,    19,    20,    21,    -1,    -1,
-    24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
-    -1,    35,    -1,     3,    38,    39,    -1,    41,     8,    43,
-    10,    11,    12,    13,    -1,    -1,    16,    -1,    18,    19,
-    20,    21,    -1,    -1,    24,    25,    26,    27,    -1,    29,
-    30,    31,    32,    -1,    -1,    35,    -1,     3,    38,    39,
-    -1,    41,     8,    43,    10,    11,    12,    13,    -1,    -1,
-    16,    -1,    18,    19,    20,    21,    -1,    -1,    24,    25,
-    26,    27,    -1,    29,    30,    31,    32,    -1,    -1,    35,
-    -1,     3,    38,    39,    -1,    41,     8,    43,    10,    11,
-    12,    13,    -1,    -1,    16,    -1,    18,    19,    20,    21,
-    -1,    -1,    24,    25,    26,    27,    -1,    29,    30,    31,
-    32,    -1,    -1,    -1,    -1,     3,    38,    39,    -1,    41,
-     8,    43,    10,    11,    12,    13,    -1,    -1,    16,    -1,
-    -1,    19,    20,    21,    -1,    -1,    24,    25,    26,    27,
-    -1,    29,    30,    31,    32,    -1,    -1,    35,    -1,     3,
-    38,    39,    -1,    41,     8,    43,    10,    11,    12,    13,
-    -1,    -1,    16,    -1,    -1,    19,    20,    21,    -1,    -1,
-    24,    25,    26,    27,    -1,    29,    30,    31,    32,    -1,
-    -1,    -1,    -1,    -1,    38,    39,    -1,    41,    -1,    43,
-    19,    20,    21,    -1,    -1,    24,    25,    26,    27,    -1,
-    29,    30,    31,    32,    -1,    -1,    -1,    -1,    21,    38,
-    39,    24,    25,    26,    27,    -1,    29,    30,    31,    32,
-    -1,    -1,    -1,    -1,    -1,    38,    39,    24,    25,    26,
-    27,    -1,    29,    -1,    31,    32,    -1,    -1,    -1,    -1,
-    -1,    38,    39
+static const short yycheck[] = {     2,
+    83,     9,     0,     6,     7,    32,    17,     9,    37,    39,
+     6,     7,   110,    21,    43,    14,    46,    37,    17,    21,
+     9,     0,    26,    20,    27,    39,    37,    14,    21,    37,
+    17,    27,    46,    24,    25,    37,    14,    45,    37,    14,
+    14,    14,    37,    45,    43,    21,    49,    50,    51,    21,
+    37,    54,    21,    21,    23,    44,    43,   155,    21,    37,
+    23,    88,    37,    37,    37,    43,    21,    56,    43,    43,
+    43,    21,    21,    42,    23,    21,    21,    23,    45,    42,
+    24,    25,   165,   166,   167,   168,   169,    90,    91,   187,
+    21,    94,    21,    42,    97,    93,    42,     5,     6,     7,
+   103,    97,   105,    21,   107,   108,    95,     5,     6,   112,
+    21,   107,   108,    92,    93,    24,    25,    21,    36,    37,
+    38,    21,    39,     4,    36,    14,    35,    36,    37,    36,
+    14,    45,   130,   131,   137,   138,   139,   140,   141,   142,
+   144,    46,   146,    21,   148,   134,   150,    21,    21,    21,
+   153,   130,   131,    21,   237,   238,   239,    21,   161,   162,
+    21,   159,    24,    25,    44,   161,   162,    46,    21,   172,
+   174,   175,    15,    35,    36,    46,   180,   181,    15,   158,
+   159,    21,    22,    23,     7,     9,    26,    27,    28,    29,
+    15,    31,    32,    33,    34,    30,    44,    15,    44,     7,
+    40,    41,     4,    30,    21,    15,    44,    21,    15,   212,
+    44,    15,    44,    44,   217,    15,     0,     0,   221,   222,
+   223,   224,   149,   236,    30,   221,   229,   183,     9,   172,
+    -1,    -1,   203,   229,    -1,    -1,    -1,   240,    -1,    -1,
+   244,   245,   246,   247,   240,   248,     1,    -1,     3,    -1,
+    -1,    -1,   248,     8,    -1,    10,    11,    12,    13,    -1,
+    -1,    16,    -1,    18,    19,    -1,    21,    22,    23,    -1,
+    -1,    26,    27,    28,    29,    -1,    31,    32,    33,    34,
+    -1,    -1,    37,    38,     3,    40,    41,    -1,    43,     8,
+    45,    10,    11,    12,    13,    -1,    -1,    16,    -1,    18,
+    19,    -1,    21,    22,    23,    -1,    -1,    26,    27,    28,
+    29,    -1,    31,    32,    33,    34,    -1,    -1,    37,    -1,
+     3,    40,    41,    -1,    43,     8,    45,    10,    11,    12,
+    13,    -1,    -1,    16,    -1,    18,    19,    -1,    21,    22,
+    23,    -1,    -1,    26,    27,    28,    29,    -1,    31,    32,
+    33,    34,    -1,    -1,    -1,    -1,     3,    40,    41,    -1,
+    43,     8,    45,    10,    11,    12,    13,    -1,    -1,    16,
+    -1,    -1,    19,    -1,    21,    22,    23,    -1,    -1,    26,
+    27,    28,    29,    -1,    31,    32,    33,    34,    -1,    -1,
+    -1,    -1,     3,    40,    41,    -1,    43,     8,    45,    10,
+    11,    12,    13,    -1,    -1,    16,    -1,    18,    -1,    -1,
+    21,    22,    23,    -1,    -1,    26,    27,    28,    29,    -1,
+    31,    32,    33,    34,    -1,    -1,    -1,    -1,     3,    40,
+    41,    -1,    43,     8,    45,    10,    11,    12,    13,    -1,
+    -1,    16,    -1,    -1,    -1,    -1,    21,    22,    23,    -1,
+    -1,    26,    27,    28,    29,    -1,    31,    32,    33,    34,
+    -1,    -1,    37,    -1,     3,    40,    41,    -1,    43,     8,
+    45,    10,    11,    12,    13,    -1,    -1,    16,    -1,    -1,
+    -1,    -1,    21,    22,    23,    -1,    -1,    26,    27,    28,
+    29,    -1,    31,    32,    33,    34,    -1,    -1,    -1,    -1,
+    -1,    40,    41,    -1,    43,    23,    45,    -1,    26,    27,
+    28,    29,    -1,    31,    32,    33,    34,    -1,    -1,    -1,
+    -1,    -1,    40,    41,    26,    27,    28,    29,    -1,    31,
+    -1,    33,    34,    -1,    -1,    -1,    -1,    -1,    40,    41
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
 #line 3 "/usr/local/lib/bison.simple"
@@ -1024,7 +1070,7 @@ yyreduce:
   switch (yyn) {
 
 case 1:
-#line 164 "./parse.y"
+#line 210 "./parse.y"
 {
                          /* Case of regular command.  Discard the error
                             safety net,and return the command just parsed. */
@@ -1035,7 +1081,7 @@ case 1:
                        ;
     break;}
 case 2:
-#line 173 "./parse.y"
+#line 219 "./parse.y"
 {
                          /* Case of regular command, but not a very
                             interesting one.  Return a NULL command. */
@@ -1044,7 +1090,7 @@ case 2:
                        ;
     break;}
 case 3:
-#line 181 "./parse.y"
+#line 226 "./parse.y"
 {
                          /* Error during parsing.  Return NULL command. */
                          global_command = (COMMAND *)NULL;
@@ -1061,9 +1107,9 @@ case 3:
                        ;
     break;}
 case 4:
-#line 196 "./parse.y"
+#line 241 "./parse.y"
 {
-                         /* Case of EOF seen by itself.  Do ignoreeof or 
+                         /* Case of EOF seen by itself.  Do ignoreeof or
                             not. */
                          global_command = (COMMAND *)NULL;
                          handle_eof_input_unit ();
@@ -1071,57 +1117,57 @@ case 4:
                        ;
     break;}
 case 5:
-#line 206 "./parse.y"
-{ yyval.word_list = (WORD_LIST *)NULL; ;
+#line 251 "./parse.y"
+{ yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ;
     break;}
 case 6:
-#line 208 "./parse.y"
+#line 253 "./parse.y"
 { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-1].word_list); ;
     break;}
 case 7:
-#line 212 "./parse.y"
+#line 257 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (1, r_output_direction, redir);
                        ;
     break;}
 case 8:
-#line 217 "./parse.y"
+#line 262 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (0, r_input_direction, redir);
                        ;
     break;}
 case 9:
-#line 222 "./parse.y"
+#line 267 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_output_direction, redir);
                        ;
     break;}
 case 10:
-#line 227 "./parse.y"
+#line 272 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_input_direction, redir);
                        ;
     break;}
 case 11:
-#line 232 "./parse.y"
+#line 277 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (1, r_appending_to, redir);
                        ;
     break;}
 case 12:
-#line 237 "./parse.y"
+#line 282 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_appending_to, redir);
                        ;
     break;}
 case 13:
-#line 242 "./parse.y"
+#line 287 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (0, r_reading_until, redir);
@@ -1129,7 +1175,7 @@ case 13:
                        ;
     break;}
 case 14:
-#line 248 "./parse.y"
+#line 293 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_reading_until, redir);
@@ -1137,63 +1183,63 @@ case 14:
                        ;
     break;}
 case 15:
-#line 254 "./parse.y"
+#line 299 "./parse.y"
 {
                          redir.dest = yyvsp[0].number;
                          yyval.redirect = make_redirection (0, r_duplicating_input, redir);
                        ;
     break;}
 case 16:
-#line 259 "./parse.y"
+#line 304 "./parse.y"
 {
                          redir.dest = yyvsp[0].number;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input, redir);
                        ;
     break;}
 case 17:
-#line 264 "./parse.y"
+#line 309 "./parse.y"
 {
                          redir.dest = yyvsp[0].number;
                          yyval.redirect = make_redirection (1, r_duplicating_output, redir);
                        ;
     break;}
 case 18:
-#line 269 "./parse.y"
+#line 314 "./parse.y"
 {
                          redir.dest = yyvsp[0].number;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output, redir);
                        ;
     break;}
 case 19:
-#line 274 "./parse.y"
+#line 319 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (0, r_duplicating_input_word, redir);
                        ;
     break;}
 case 20:
-#line 279 "./parse.y"
+#line 324 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_input_word, redir);
                        ;
     break;}
 case 21:
-#line 284 "./parse.y"
+#line 329 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (1, r_duplicating_output_word, redir);
                        ;
     break;}
 case 22:
-#line 289 "./parse.y"
+#line 334 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_duplicating_output_word, redir);
                        ;
     break;}
 case 23:
-#line 294 "./parse.y"
+#line 339 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection
@@ -1202,7 +1248,7 @@ case 23:
                        ;
     break;}
 case 24:
-#line 301 "./parse.y"
+#line 346 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection
@@ -1211,369 +1257,342 @@ case 24:
                        ;
     break;}
 case 25:
-#line 308 "./parse.y"
+#line 353 "./parse.y"
 {
                          redir.dest = 0L;
                          yyval.redirect = make_redirection (1, r_close_this, redir);
                        ;
     break;}
 case 26:
-#line 313 "./parse.y"
+#line 358 "./parse.y"
 {
                          redir.dest = 0L;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir);
                        ;
     break;}
 case 27:
-#line 318 "./parse.y"
+#line 363 "./parse.y"
 {
                          redir.dest = 0L;
                          yyval.redirect = make_redirection (0, r_close_this, redir);
                        ;
     break;}
 case 28:
-#line 323 "./parse.y"
+#line 368 "./parse.y"
 {
                          redir.dest = 0L;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_close_this, redir);
                        ;
     break;}
 case 29:
-#line 328 "./parse.y"
+#line 373 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (1, r_err_and_out, redir);
                        ;
     break;}
 case 30:
-#line 333 "./parse.y"
+#line 378 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_input_output, redir);
                        ;
     break;}
 case 31:
-#line 338 "./parse.y"
+#line 383 "./parse.y"
 {
-                         REDIRECT *t1, *t2;
-
                          redir.filename = yyvsp[0].word;
-                         if (posixly_correct)
-                           yyval.redirect = make_redirection (0, r_input_output, redir);
-                         else
-                           {
-                             t1 = make_redirection (0, r_input_direction, redir);
-                             redir.filename = copy_word (yyvsp[0].word);
-                             t2 = make_redirection (1, r_output_direction, redir);
-                             t1->next = t2;
-                             yyval.redirect = t1;
-                           }
+                         yyval.redirect = make_redirection (0, r_input_output, redir);
                        ;
     break;}
 case 32:
-#line 354 "./parse.y"
+#line 388 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (1, r_output_force, redir);
                        ;
     break;}
 case 33:
-#line 359 "./parse.y"
+#line 393 "./parse.y"
 {
                          redir.filename = yyvsp[0].word;
                          yyval.redirect = make_redirection (yyvsp[-2].number, r_output_force, redir);
                        ;
     break;}
 case 34:
-#line 366 "./parse.y"
+#line 400 "./parse.y"
 { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ;
     break;}
 case 35:
-#line 368 "./parse.y"
+#line 402 "./parse.y"
 { yyval.element.word = yyvsp[0].word; yyval.element.redirect = 0; ;
     break;}
 case 36:
-#line 370 "./parse.y"
+#line 404 "./parse.y"
 { yyval.element.redirect = yyvsp[0].redirect; yyval.element.word = 0; ;
     break;}
 case 37:
-#line 374 "./parse.y"
+#line 408 "./parse.y"
 {
                          yyval.redirect = yyvsp[0].redirect;
                        ;
     break;}
 case 38:
-#line 378 "./parse.y"
-{ 
-                         register REDIRECT *t = yyvsp[-1].redirect;
+#line 412 "./parse.y"
+{
+                         register REDIRECT *t;
 
-                         while (t->next)
-                           t = t->next;
-                         t->next = yyvsp[0].redirect; 
+                         for (t = yyvsp[-1].redirect; t->next; t = t->next)
+                           ;
+                         t->next = yyvsp[0].redirect;
                          yyval.redirect = yyvsp[-1].redirect;
                        ;
     break;}
 case 39:
-#line 389 "./parse.y"
+#line 423 "./parse.y"
 { yyval.command = make_simple_command (yyvsp[0].element, (COMMAND *)NULL); ;
     break;}
 case 40:
-#line 391 "./parse.y"
+#line 425 "./parse.y"
 { yyval.command = make_simple_command (yyvsp[0].element, yyvsp[-1].command); ;
     break;}
 case 41:
-#line 395 "./parse.y"
+#line 429 "./parse.y"
 { yyval.command = clean_simple_command (yyvsp[0].command); ;
     break;}
 case 42:
-#line 397 "./parse.y"
+#line 431 "./parse.y"
 { yyval.command = yyvsp[0].command; ;
     break;}
 case 43:
-#line 401 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
-    break;}
-case 44:
-#line 403 "./parse.y"
+#line 433 "./parse.y"
 {
-                         if (yyvsp[-1].command->redirects)
+                         COMMAND *tc;
+
+                         tc = yyvsp[-1].command;
+                         /* According to Posix.2 3.9.5, redirections
+                            specified after the body of a function should
+                            be attached to the function and performed when
+                            the function is executed, not as part of the
+                            function definition command. */
+                         if (tc->type == cm_function_def)
+                           {
+                             tc = tc->value.Function_def->command;
+                             if (tc->type == cm_group)
+                               tc = tc->value.Group->command;
+                           }
+                         if (tc->redirects)
                            {
                              register REDIRECT *t;
-                             for (t = yyvsp[-1].command->redirects; t->next; t = t->next)
+                             for (t = tc->redirects; t->next; t = t->next)
                                ;
                              t->next = yyvsp[0].redirect;
                            }
                          else
-                           yyvsp[-1].command->redirects = yyvsp[0].redirect;
+                           tc->redirects = yyvsp[0].redirect;
                          yyval.command = yyvsp[-1].command;
                        ;
     break;}
+case 44:
+#line 462 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
+    break;}
 case 45:
-#line 418 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
+#line 464 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 46:
-#line 420 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ;
+#line 466 "./parse.y"
+{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ;
     break;}
 case 47:
-#line 422 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
+#line 468 "./parse.y"
+{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ;
     break;}
 case 48:
-#line 424 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
+#line 470 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 49:
-#line 426 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ;
+#line 472 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 50:
-#line 428 "./parse.y"
-{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ;
+#line 474 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 51:
-#line 431 "./parse.y"
-{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ;
+#line 476 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 52:
-#line 433 "./parse.y"
-{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ;
+#line 478 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
     break;}
 case 53:
-#line 435 "./parse.y"
-{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ;
+#line 482 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
     break;}
 case 54:
-#line 437 "./parse.y"
-{ yyval.command = make_while_command (yyvsp[-3].command, yyvsp[-1].command); ;
+#line 484 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command); ;
     break;}
 case 55:
-#line 439 "./parse.y"
-{ yyval.command = make_until_command (yyvsp[-3].command, yyvsp[-1].command); ;
+#line 486 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
     break;}
 case 56:
-#line 441 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
+#line 488 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command); ;
     break;}
 case 57:
-#line 443 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
+#line 490 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ;
     break;}
 case 58:
-#line 445 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
+#line 492 "./parse.y"
+{ yyval.command = make_for_command (yyvsp[-8].word, REVERSE_LIST (yyvsp[-5].word_list, WORD_LIST *), yyvsp[-1].command); ;
     break;}
 case 59:
-#line 447 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
-    break;}
-case 60:
-#line 449 "./parse.y"
-{ yyval.command = yyvsp[0].command; ;
-    break;}
-case 61:
-#line 453 "./parse.y"
+#line 496 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command);
-#endif
                        ;
     break;}
-case 62:
-#line 459 "./parse.y"
+case 60:
+#line 500 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-4].word, add_string_to_list ("$@", (WORD_LIST *)NULL), yyvsp[-1].command);
-#endif
                        ;
     break;}
-case 63:
-#line 465 "./parse.y"
+case 61:
+#line 504 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command);
-#endif
                        ;
     break;}
-case 64:
-#line 471 "./parse.y"
+case 62:
+#line 508 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-5].word, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), yyvsp[-1].command);
-#endif
                        ;
     break;}
-case 65:
-#line 477 "./parse.y"
+case 63:
+#line 512 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command);
-#endif
                        ;
     break;}
-case 66:
-#line 483 "./parse.y"
+case 64:
+#line 516 "./parse.y"
 {
-#if defined (SELECT_COMMAND)
                          yyval.command = make_select_command (yyvsp[-8].word, (WORD_LIST *)reverse_list (yyvsp[-5].word_list), yyvsp[-1].command);
-#endif
                        ;
     break;}
+case 65:
+#line 522 "./parse.y"
+{ yyval.command = make_case_command (yyvsp[-4].word, (PATTERN_LIST *)NULL); ;
+    break;}
+case 66:
+#line 524 "./parse.y"
+{ yyval.command = make_case_command (yyvsp[-5].word, yyvsp[-2].pattern); ;
+    break;}
 case 67:
-#line 491 "./parse.y"
-{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ;
+#line 526 "./parse.y"
+{ yyval.command = make_case_command (yyvsp[-4].word, yyvsp[-1].pattern); ;
     break;}
 case 68:
-#line 494 "./parse.y"
-{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ;
+#line 530 "./parse.y"
+{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ;
     break;}
 case 69:
-#line 497 "./parse.y"
-{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command); ;
+#line 534 "./parse.y"
+{ yyval.command = make_function_def (yyvsp[-4].word, yyvsp[0].command, function_dstart, function_bstart); ;
     break;}
 case 70:
-#line 500 "./parse.y"
-{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-5].word, yyvsp[-1].command); ;
+#line 537 "./parse.y"
+{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command, function_dstart, function_bstart); ;
     break;}
 case 71:
-#line 503 "./parse.y"
-{ yyval.command = make_function_def (yyvsp[-2].word, yyvsp[0].command); ;
-    break;}
-case 72:
-#line 506 "./parse.y"
-{ yyvsp[-1].command->redirects = yyvsp[0].redirect; yyval.command = make_function_def (yyvsp[-3].word, yyvsp[-1].command); ;
-    break;}
-case 73:
-#line 510 "./parse.y"
+#line 541 "./parse.y"
 { yyvsp[-1].command->flags |= CMD_WANT_SUBSHELL; yyval.command = yyvsp[-1].command; ;
     break;}
-case 74:
-#line 514 "./parse.y"
+case 72:
+#line 545 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, (COMMAND *)NULL); ;
     break;}
-case 75:
-#line 516 "./parse.y"
+case 73:
+#line 547 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-5].command, yyvsp[-3].command, yyvsp[-1].command); ;
     break;}
-case 76:
-#line 518 "./parse.y"
+case 74:
+#line 549 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[-1].command); ;
     break;}
-case 77:
-#line 523 "./parse.y"
+case 75:
+#line 554 "./parse.y"
 { yyval.command = make_group_command (yyvsp[-1].command); ;
     break;}
-case 78:
-#line 527 "./parse.y"
+case 76:
+#line 558 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-2].command, yyvsp[0].command, (COMMAND *)NULL); ;
     break;}
-case 79:
-#line 529 "./parse.y"
+case 77:
+#line 560 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-4].command, yyvsp[-2].command, yyvsp[0].command); ;
     break;}
-case 80:
-#line 531 "./parse.y"
+case 78:
+#line 562 "./parse.y"
 { yyval.command = make_if_command (yyvsp[-3].command, yyvsp[-1].command, yyvsp[0].command); ;
     break;}
-case 82:
-#line 536 "./parse.y"
+case 80:
+#line 567 "./parse.y"
 { yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ;
     break;}
-case 83:
-#line 540 "./parse.y"
+case 81:
+#line 571 "./parse.y"
 { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ;
     break;}
-case 84:
-#line 542 "./parse.y"
+case 82:
+#line 573 "./parse.y"
 { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ;
     break;}
-case 85:
-#line 544 "./parse.y"
+case 83:
+#line 575 "./parse.y"
 { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, yyvsp[0].command); ;
     break;}
-case 86:
-#line 546 "./parse.y"
+case 84:
+#line 577 "./parse.y"
 { yyval.pattern = make_pattern_list (yyvsp[-2].word_list, (COMMAND *)NULL); ;
     break;}
-case 88:
-#line 551 "./parse.y"
-{ yyvsp[0].pattern->next = yyvsp[-1].pattern; yyval.pattern = yyvsp[0].pattern; ;
-    break;}
-case 89:
-#line 555 "./parse.y"
-{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ;
-    break;}
-case 90:
-#line 557 "./parse.y"
-{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ;
-    break;}
-case 91:
-#line 559 "./parse.y"
-{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, yyvsp[-1].command); ;
-    break;}
-case 92:
-#line 561 "./parse.y"
-{ yyval.pattern = make_pattern_list (yyvsp[-3].word_list, (COMMAND *)NULL); ;
+case 86:
+#line 582 "./parse.y"
+{ yyvsp[-1].pattern->next = yyvsp[-2].pattern; yyval.pattern = yyvsp[-1].pattern; ;
     break;}
-case 93:
-#line 565 "./parse.y"
+case 87:
+#line 586 "./parse.y"
 { yyval.word_list = make_word_list (yyvsp[0].word, (WORD_LIST *)NULL); ;
     break;}
-case 94:
-#line 567 "./parse.y"
+case 88:
+#line 588 "./parse.y"
 { yyval.word_list = make_word_list (yyvsp[0].word, yyvsp[-2].word_list); ;
     break;}
-case 95:
-#line 576 "./parse.y"
+case 89:
+#line 597 "./parse.y"
 {
                          yyval.command = yyvsp[0].command;
                          if (need_here_doc)
                            gather_here_documents ();
                         ;
     break;}
-case 98:
-#line 586 "./parse.y"
+case 91:
+#line 606 "./parse.y"
+{
+                         yyval.command = yyvsp[0].command;
+                       ;
+    break;}
+case 93:
+#line 613 "./parse.y"
 {
                          if (yyvsp[-2].command->type == cm_connection)
                            yyval.command = connect_async_list (yyvsp[-2].command, (COMMAND *)NULL, '&');
@@ -1581,16 +1600,16 @@ case 98:
                            yyval.command = command_connect (yyvsp[-2].command, (COMMAND *)NULL, '&');
                        ;
     break;}
-case 100:
-#line 597 "./parse.y"
+case 95:
+#line 624 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ;
     break;}
-case 101:
-#line 599 "./parse.y"
+case 96:
+#line 626 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ;
     break;}
-case 102:
-#line 601 "./parse.y"
+case 97:
+#line 628 "./parse.y"
 {
                          if (yyvsp[-3].command->type == cm_connection)
                            yyval.command = connect_async_list (yyvsp[-3].command, yyvsp[0].command, '&');
@@ -1598,35 +1617,28 @@ case 102:
                            yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '&');
                        ;
     break;}
-case 103:
-#line 608 "./parse.y"
+case 98:
+#line 635 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ;
     break;}
-case 104:
-#line 610 "./parse.y"
+case 99:
+#line 637 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, ';'); ;
     break;}
-case 105:
-#line 612 "./parse.y"
+case 100:
+#line 639 "./parse.y"
 { yyval.command = yyvsp[0].command; ;
     break;}
 case 106:
-#line 614 "./parse.y"
-{
-                         yyvsp[0].command->flags |= CMD_INVERT_RETURN;
-                         yyval.command = yyvsp[0].command;
-                       ;
-    break;}
-case 112:
-#line 636 "./parse.y"
+#line 658 "./parse.y"
 {
                          yyval.command = yyvsp[0].command;
                          if (need_here_doc)
                            gather_here_documents ();
                        ;
     break;}
-case 113:
-#line 642 "./parse.y"
+case 107:
+#line 664 "./parse.y"
 {
                          if (yyvsp[-1].command->type == cm_connection)
                            yyval.command = connect_async_list (yyvsp[-1].command, (COMMAND *)NULL, '&');
@@ -1636,24 +1648,24 @@ case 113:
                            gather_here_documents ();
                        ;
     break;}
-case 114:
-#line 651 "./parse.y"
+case 108:
+#line 673 "./parse.y"
 {
                          yyval.command = yyvsp[-1].command;
                          if (need_here_doc)
                            gather_here_documents ();
                        ;
     break;}
-case 115:
-#line 659 "./parse.y"
+case 109:
+#line 681 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, AND_AND); ;
     break;}
-case 116:
-#line 661 "./parse.y"
+case 110:
+#line 683 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, OR_OR); ;
     break;}
-case 117:
-#line 663 "./parse.y"
+case 111:
+#line 685 "./parse.y"
 {
                          if (yyvsp[-2].command->type == cm_connection)
                            yyval.command = connect_async_list (yyvsp[-2].command, yyvsp[0].command, '&');
@@ -1661,29 +1673,62 @@ case 117:
                            yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, '&');
                        ;
     break;}
-case 118:
-#line 670 "./parse.y"
+case 112:
+#line 692 "./parse.y"
 { yyval.command = command_connect (yyvsp[-2].command, yyvsp[0].command, ';'); ;
     break;}
-case 119:
-#line 672 "./parse.y"
+case 113:
+#line 695 "./parse.y"
 { yyval.command = yyvsp[0].command; ;
     break;}
-case 120:
-#line 674 "./parse.y"
+case 114:
+#line 699 "./parse.y"
+{ yyval.command = yyvsp[0].command; ;
+    break;}
+case 115:
+#line 701 "./parse.y"
 {
                          yyvsp[0].command->flags |= CMD_INVERT_RETURN;
                          yyval.command = yyvsp[0].command;
                        ;
     break;}
-case 121:
-#line 682 "./parse.y"
+case 116:
+#line 706 "./parse.y"
+{
+                         yyvsp[0].command->flags |= yyvsp[-1].number;
+                         yyval.command = yyvsp[0].command;
+                       ;
+    break;}
+case 117:
+#line 711 "./parse.y"
+{
+                         yyvsp[0].command->flags |= yyvsp[-2].number;
+                         yyval.command = yyvsp[0].command;
+                       ;
+    break;}
+case 118:
+#line 716 "./parse.y"
+{
+                         yyvsp[0].command->flags |= yyvsp[-1].number|CMD_INVERT_RETURN;
+                         yyval.command = yyvsp[0].command;
+                       ;
+    break;}
+case 119:
+#line 724 "./parse.y"
 { yyval.command = command_connect (yyvsp[-3].command, yyvsp[0].command, '|'); ;
     break;}
-case 122:
-#line 684 "./parse.y"
+case 120:
+#line 726 "./parse.y"
 { yyval.command = yyvsp[0].command; ;
     break;}
+case 121:
+#line 730 "./parse.y"
+{ yyval.number = CMD_TIME_PIPELINE; ;
+    break;}
+case 122:
+#line 732 "./parse.y"
+{ yyval.number = CMD_TIME_PIPELINE|CMD_TIME_POSIX; ;
+    break;}
 }
    /* the action file gets copied in in place of this dollarsign */
 #line 498 "/usr/local/lib/bison.simple"
@@ -1882,31 +1927,64 @@ yyerrhandle:
   yystate = yyn;
   goto yynewstate;
 }
-#line 686 "./parse.y"
+#line 734 "./parse.y"
+
 
+/* Possible states for the parser that require it to do special things. */
+#define PST_CASEPAT    0x001           /* in a case pattern list */
+#define PST_ALEXPNEXT  0x002           /* expand next word for aliases */
+#define PST_ALLOWOPNBRC        0x004           /* allow open brace for function def */
+#define PST_NEEDCLOSBRC        0x008           /* need close brace */
+#define PST_DBLPAREN   0x010           /* double-paren parsing */
+#define PST_SUBSHELL   0x020           /* ( ... ) subshell */
+#define PST_CMDSUBST   0x040           /* $( ... ) command substitution */
+#define PST_CASESTMT   0x080           /* parsing a case statement */
 
 /* Initial size to allocate for tokens, and the
    amount to grow them by. */
 #define TOKEN_DEFAULT_GROW_SIZE 512
 
+/* Shell meta-characters that, when unquoted, separate words. */
+#define shellmeta(c)   (strchr ("()<>;&|", (c)) != 0)
+#define shellbreak(c)  (strchr ("()<>;&| \t\n", (c)) != 0)
+#define shellquote(c)  ((c) == '"' || (c) == '`' || (c) == '\'')
+#define shellexp(c)    ((c) == '$' || (c) == '<' || (c) == '>')
+
 /* The token currently being read. */
-static int current_token = 0;
+static int current_token;
 
 /* The last read token, or NULL.  read_token () uses this for context
    checking. */
-static int last_read_token = 0;
+static int last_read_token;
 
 /* The token read prior to last_read_token. */
-static int token_before_that = 0;
+static int token_before_that;
+
+/* The token read prior to token_before_that. */
+static int two_tokens_ago;
 
 /* If non-zero, it is the token that we want read_token to return
    regardless of what text is (or isn't) present to be read.  This
-   is reset by read_token. */
-static int token_to_read = 0;
+   is reset by read_token.  If token_to_read == WORD or
+   ASSIGNMENT_WORD, yylval.word should be set to word_desc_to_read. */
+static int token_to_read;
+static WORD_DESC *word_desc_to_read;
+
+/* The current parser state. */
+static int parser_state;
 
 /* Global var is non-zero when end of file has been reached. */
 int EOF_Reached = 0;
 
+void
+debug_parser (i)
+     int i;
+{
+#if YYDEBUG != 0
+  yydebug = i;
+#endif
+}
+
 /* yy_getc () returns the next available character from input or EOF.
    yy_ungetc (c) makes `c' the next character to read.
    init_yy_io (get, unget, type, location) makes the function GET the
@@ -1916,6 +1994,7 @@ int EOF_Reached = 0;
    the input is coming from. */
 
 /* Unconditionally returns end-of-file. */
+int
 return_EOF ()
 {
   return (EOF);
@@ -1925,11 +2004,13 @@ return_EOF ()
    See ./input.h for a clearer description. */
 BASH_INPUT bash_input;
 
-/* Set all of the fields in BASH_INPUT to NULL. */
+/* Set all of the fields in BASH_INPUT to NULL.  Free bash_input.name if it
+   is non-null, avoiding a memory leak. */
 void
 initialize_bash_input ()
 {
-  bash_input.type = 0;
+  bash_input.type = st_none;
+  FREE (bash_input.name);
   bash_input.name = (char *)NULL;
   bash_input.location.file = (FILE *)NULL;
   bash_input.location.string = (char *)NULL;
@@ -1948,12 +2029,9 @@ init_yy_io (get, unget, type, name, location)
 {
   bash_input.type = type;
   FREE (bash_input.name);
+  bash_input.name = name ? savestring (name) : (char *)NULL;
 
-  if (name)
-    bash_input.name = savestring (name);
-  else
-    bash_input.name = (char *)NULL;
-
+  /* XXX */
 #if defined (CRAY)
   memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location));
 #else
@@ -1964,6 +2042,7 @@ init_yy_io (get, unget, type, name, location)
 }
 
 /* Call this to get the next character of input. */
+int
 yy_getc ()
 {
   return (*(bash_input.getter)) ();
@@ -1971,6 +2050,7 @@ yy_getc ()
 
 /* Call this to unget C.  That is, to make C the next character
    to be read. */
+int
 yy_ungetc (c)
      int c;
 {
@@ -1987,6 +2067,7 @@ input_file_descriptor ()
       return (fileno (bash_input.location.file));
     case st_bstream:
       return (bash_input.location.buffered_fd);
+    case st_stdin:
     default:
       return (fileno (stdin));
     }
@@ -2007,11 +2088,11 @@ int current_readline_line_index = 0;
 static int
 yy_readline_get ()
 {
+  SigHandler *old_sigint;
+  int line_len, c;
+
   if (!current_readline_line)
     {
-      SigHandler *old_sigint;
-      int line_len;
-
       if (!bash_readline_initialized)
        initialize_readline ();
 
@@ -2026,10 +2107,8 @@ yy_readline_get ()
          interrupt_immediately++;
        }
 
-      if (!current_readline_prompt)
-       current_readline_line = readline ("");
-      else
-       current_readline_line = readline (current_readline_prompt);
+      current_readline_line = readline (current_readline_prompt ?
+                                         current_readline_prompt : "");
 
       if (signal_is_ignored (SIGINT) == 0)
        {
@@ -2037,22 +2116,23 @@ yy_readline_get ()
          set_signal_handler (SIGINT, old_sigint);
        }
 
-      /* Reset the prompt to whatever is in the decoded value of
-        prompt_string_pointer. */
+#if 0
+      /* Reset the prompt to the decoded value of prompt_string_pointer. */
       reset_readline_prompt ();
+#endif
 
-      current_readline_line_index = 0;
-
-      if (!current_readline_line)
+      if (current_readline_line == 0)
        return (EOF);
 
+      current_readline_line_index = 0;
       line_len = strlen (current_readline_line);
+
       current_readline_line = xrealloc (current_readline_line, 2 + line_len);
       current_readline_line[line_len++] = '\n';
       current_readline_line[line_len] = '\0';
     }
 
-  if (!current_readline_line[current_readline_line_index])
+  if (current_readline_line[current_readline_line_index] == 0)
     {
       free (current_readline_line);
       current_readline_line = (char *)NULL;
@@ -2060,20 +2140,21 @@ yy_readline_get ()
     }
   else
     {
-      int c = (unsigned char)current_readline_line[current_readline_line_index++];
+      c = (unsigned char)current_readline_line[current_readline_line_index++];
       return (c);
     }
 }
 
 static int
 yy_readline_unget (c)
+     int c;
 {
   if (current_readline_line_index && current_readline_line)
     current_readline_line[--current_readline_line_index] = c;
   return (c);
 }
 
-void  
+void
 with_input_from_stdin ()
 {
   INPUT_STREAM location;
@@ -2104,7 +2185,7 @@ with_input_from_stdin ()
 static int
 yy_string_get ()
 {
-  register unsigned char *string;
+  register char *string;
   register int c;
 
   string = bash_input.location.string;
@@ -2113,7 +2194,7 @@ yy_string_get ()
   /* If the string doesn't exist, or is empty, EOF found. */
   if (string && *string)
     {
-      c = *string++;
+      c = *(unsigned char *)string++;
       bash_input.location.string = string;
     }
   return (c);
@@ -2129,13 +2210,11 @@ yy_string_unget (c)
 
 void
 with_input_from_string (string, name)
-     char *string;
-     char *name;
+     char *string, *name;
 {
   INPUT_STREAM location;
 
   location.string = string;
-
   init_yy_io (yy_string_get, yy_string_unget, st_string, name, location);
 }
 
@@ -2151,11 +2230,14 @@ yy_stream_get ()
   int result = EOF;
 
   if (bash_input.location.file)
-#if defined (NO_READ_RESTART_ON_SIGNAL)
-    result = (unsigned char)getc_with_restart (bash_input.location.file);
-#else
-    result = (unsigned char)getc (bash_input.location.file);
-#endif /* !NO_READ_RESTART_ON_SIGNAL */
+    {
+#if !defined (HAVE_RESTARTABLE_SYSCALLS)
+      result = getc_with_restart (bash_input.location.file);
+#else /* HAVE_RESTARTABLE_SYSCALLS */
+      result = getc (bash_input.location.file);
+      result = (feof (bash_input.location.file)) ? EOF : (unsigned char)result;
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+    }
   return (result);
 }
 
@@ -2163,11 +2245,11 @@ static int
 yy_stream_unget (c)
      int c;
 {
-#if defined (NO_READ_RESTART_ON_SIGNAL)
+#if !defined (HAVE_RESTARTABLE_SYSCALLS)
   return (ungetc_with_restart (c, bash_input.location.file));
-#else
+#else /* HAVE_RESTARTABLE_SYSCALLS */
   return (ungetc (c, bash_input.location.file));
-#endif
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
 }
 
 void
@@ -2195,7 +2277,9 @@ int line_number = 0;
 
 STREAM_SAVER *stream_list = (STREAM_SAVER *)NULL;
 
-push_stream ()
+void
+push_stream (reset_lineno)
+     int reset_lineno;
 {
   STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER));
 
@@ -2215,13 +2299,14 @@ push_stream ()
   bash_input.name = (char *)NULL;
   saver->next = stream_list;
   stream_list = saver;
-  EOF_Reached = line_number = 0;
+  EOF_Reached = 0;
+  if (reset_lineno)
+    line_number = 0;
 }
 
+void
 pop_stream ()
 {
-  int temp;
-
   if (!stream_list)
     EOF_Reached = 1;
   else
@@ -2267,36 +2352,35 @@ pop_stream ()
 /* Return 1 if a stream of type TYPE is saved on the stack. */
 int
 stream_on_stack (type)
-     int type;
+     enum stream_type type;
 {
   register STREAM_SAVER *s;
+
   for (s = stream_list; s; s = s->next)
     if (s->bash_input.type == type)
       return 1;
   return 0;
 }
 
-\f
 /*
  * This is used to inhibit alias expansion and reserved word recognition
- * inside case statement pattern lists.  A `case statement pattern list'
- * is:
+ * inside case statement pattern lists.  A `case statement pattern list' is:
+ *
  *     everything between the `in' in a `case word in' and the next ')'
  *     or `esac'
  *     everything between a `;;' and the next `)' or `esac'
  */
-static int in_case_pattern_list = 0;
 
 #if defined (ALIAS)
+
+#define END_OF_ALIAS 0
+
 /*
  * Pseudo-global variables used in implementing token-wise alias expansion.
  */
 
-static int expand_next_token = 0;
-
 /*
- * Pushing and popping strings.  This works together with shell_getc to 
+ * Pushing and popping strings.  This works together with shell_getc to
  * implement alias expansion on a per-token basis.
  */
 
@@ -2304,13 +2388,12 @@ typedef struct string_saver {
   struct string_saver *next;
   int expand_alias;  /* Value to set expand_alias to when string is popped. */
   char *saved_line;
+  alias_t *expander;   /* alias that caused this line to be pushed. */
   int saved_line_size, saved_line_index, saved_line_terminator;
 } STRING_SAVER;
 
 STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL;
 
-static void save_expansion ();
-
 /*
  * Push the current shell_input_line onto a stack of such lines and make S
  * the current input.  Used when expanding aliases.  EXPAND is used to set
@@ -2320,10 +2403,10 @@ static void save_expansion ();
  * into S; it is saved and used to prevent infinite recursive expansion.
  */
 static void
-push_string (s, expand, token)
+push_string (s, expand, ap)
      char *s;
      int expand;
-     char *token;
+     alias_t *ap;
 {
   STRING_SAVER *temp = (STRING_SAVER *) xmalloc (sizeof (STRING_SAVER));
 
@@ -2332,16 +2415,17 @@ push_string (s, expand, token)
   temp->saved_line_size = shell_input_line_size;
   temp->saved_line_index = shell_input_line_index;
   temp->saved_line_terminator = shell_input_line_terminator;
+  temp->expander = ap;
   temp->next = pushed_string_list;
   pushed_string_list = temp;
 
-  save_expansion (token);
+  ap->flags |= AL_BEINGEXPANDED;
 
   shell_input_line = s;
   shell_input_line_size = strlen (s);
   shell_input_line_index = 0;
   shell_input_line_terminator = '\0';
-  expand_next_token = 0;
+  parser_state &= ~PST_ALEXPNEXT;
 }
 
 /*
@@ -2360,102 +2444,38 @@ pop_string ()
   shell_input_line_index = pushed_string_list->saved_line_index;
   shell_input_line_size = pushed_string_list->saved_line_size;
   shell_input_line_terminator = pushed_string_list->saved_line_terminator;
-  expand_next_token = pushed_string_list->expand_alias;
 
-  t = pushed_string_list;
+  if (pushed_string_list->expand_alias)
+    parser_state |= PST_ALEXPNEXT;
+  else
+    parser_state &= ~PST_ALEXPNEXT;
+
+  t = pushed_string_list;
   pushed_string_list = pushed_string_list->next;
-  free((char *)t);
+
+  t->expander->flags &= ~AL_BEINGEXPANDED;
+
+  free ((char *)t);
 }
 
 static void
 free_string_list ()
 {
-  register STRING_SAVER *t = pushed_string_list, *t1;
+  register STRING_SAVER *t, *t1;
 
-  while (t)
+  for (t = pushed_string_list; t; )
     {
       t1 = t->next;
       FREE (t->saved_line);
+      t->expander->flags &= ~AL_BEINGEXPANDED;
       free ((char *)t);
       t = t1;
     }
   pushed_string_list = (STRING_SAVER *)NULL;
 }
 
-/* This is a stack to save the values of all tokens for which alias
-   expansion has been performed during the current call to read_token ().
-   It is used to prevent alias expansion loops:
-
-      alias foo=bar
-      alias bar=baz
-      alias baz=foo
-
-   Ideally this would be taken care of by push and pop string, but because
-   of when strings are popped the stack will not contain the correct
-   strings to test against.  (The popping is done in shell_getc, so that when
-   the current string is exhausted, shell_getc can simply pop that string off
-   the stack, restore the previous string, and continue with the character
-   following the token whose expansion was originally pushed on the stack.)
-
-   What we really want is a record of all tokens that have been expanded for
-   aliases during the `current' call to read_token().  This does that, at the
-   cost of being somewhat special-purpose (OK, OK vile and unclean). */
-
-typedef struct _exp_saver {
-      struct _exp_saver *next;
-      char *saved_token;
-} EXPANSION_SAVER;
-
-EXPANSION_SAVER *expanded_token_stack = (EXPANSION_SAVER *)NULL;
-
-static void
-save_expansion (s)
-     char *s;
-{
-  EXPANSION_SAVER *t;
-
-  t = (EXPANSION_SAVER *) xmalloc (sizeof (EXPANSION_SAVER));
-  t->saved_token = savestring (s);
-  t->next = expanded_token_stack;
-  expanded_token_stack = t;
-}
-
-/* Return 1 if TOKEN has already been expanded in the current `stack' of
-   expansions.  If it has been expanded already, it will appear as the value
-   of saved_token for some entry in the stack of expansions created for the
-   current token being expanded. */
-static int
-token_has_been_expanded (token)
-     char *token;
-{
-  register EXPANSION_SAVER *t = expanded_token_stack;
-
-  while (t)
-    {
-      if (STREQ (token, t->saved_token))
-       return (1);
-      t = t->next;
-    }
-  return (0);
-}
-
-static void
-free_expansion_stack ()
-{
-  register EXPANSION_SAVER *t = expanded_token_stack, *t1;
-
-  while (t)
-    {
-      t1 = t->next;
-      free (t->saved_token);
-      free (t);
-      t = t1;
-    }
-  expanded_token_stack = (EXPANSION_SAVER *)NULL;
-}
-
 #endif /* ALIAS */
-\f
+
 /* Return a line of text, taken from wherever yylex () reads input.
    If there is no more input, then we return NULL.  If REMOVE_QUOTED_NEWLINE
    is non-zero, we remove unquoted \<newline> pairs.  This is used by
@@ -2468,6 +2488,13 @@ read_a_line (remove_quoted_newline)
   static int buffer_size = 0;
   int indx = 0, c, peekc, pass_next;
 
+#if defined (READLINE)
+  if (interactive && bash_input.type != st_string && no_line_editing)
+#else
+  if (interactive && bash_input.type != st_string)
+#endif
+    print_prompt ();
+
   pass_next = 0;
   while (1)
     {
@@ -2482,17 +2509,15 @@ read_a_line (remove_quoted_newline)
       /* If there is no more input, then we return NULL. */
       if (c == EOF)
        {
+         if (interactive && bash_input.type == st_stream)
+           clearerr (stdin);
          if (indx == 0)
            return ((char *)NULL);
          c = '\n';
        }
 
       /* `+2' in case the final character in the buffer is a newline. */
-      if (indx + 2 > buffer_size)
-       if (!buffer_size)
-         line_buffer = xmalloc (buffer_size = 128);
-       else
-         line_buffer = xrealloc (line_buffer, buffer_size += 128);
+      RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128);
 
       /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a
         here document with an unquoted delimiter.  In this case,
@@ -2542,7 +2567,6 @@ read_secondary_line (remove_quoted_newline)
   return (read_a_line (remove_quoted_newline));
 }
 
-\f
 /* **************************************************************** */
 /*                                                                 */
 /*                             YYLEX ()                            */
@@ -2569,21 +2593,56 @@ STRING_INT_ALIST word_token_alist[] = {
   { "done", DONE },
   { "in", IN },
   { "function", FUNCTION },
+#if defined (COMMAND_TIMING)
+  { "time", TIME },
+#endif
   { "{", '{' },
   { "}", '}' },
   { "!", BANG },
   { (char *)NULL, 0}
 };
 
+/* These are used by read_token_word, but appear up here so that shell_getc
+   can use them to decide when to add otherwise blank lines to the history. */
+
+/* The primary delimiter stack. */
+struct dstack dstack = {  (char *)NULL, 0, 0 };
+
+/* A temporary delimiter stack to be used when decoding prompt strings.
+   This is needed because command substitutions in prompt strings (e.g., PS2)
+   can screw up the parser's quoting state. */
+static struct dstack temp_dstack = { (char *)NULL, 0, 0 };
+
+/* Macro for accessing the top delimiter on the stack.  Returns the
+   delimiter or zero if none. */
+#define current_delimiter(ds) \
+  (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0)
+
+#define push_delimiter(ds, character) \
+  do \
+    { \
+      if (ds.delimiter_depth + 2 > ds.delimiter_space) \
+       ds.delimiters = xrealloc \
+         (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \
+      ds.delimiters[ds.delimiter_depth] = character; \
+      ds.delimiter_depth++; \
+    } \
+  while (0)
+
+#define pop_delimiter(ds)      ds.delimiter_depth--
+
 /* Return the next shell input character.  This always reads characters
    from shell_input_line; when that line is exhausted, it is time to
    read the next line.  This is called by read_token when the shell is
    processing normal command input. */
+
 static int
 shell_getc (remove_quoted_newline)
      int remove_quoted_newline;
 {
+  register int i;
   int c;
+  static int mustpop = 0;
 
   QUIT;
 
@@ -2598,10 +2657,6 @@ shell_getc (remove_quoted_newline)
   if (!shell_input_line || !shell_input_line[shell_input_line_index])
 #endif /* !ALIAS */
     {
-      register int i, l;
-
-      restart_read_next_line:
-
       line_number++;
 
     restart_read:
@@ -2637,16 +2692,14 @@ shell_getc (remove_quoted_newline)
          /* Allow immediate exit if interrupted during input. */
          QUIT;
 
-         if (i + 2 > shell_input_line_size)
-           shell_input_line =
-             xrealloc (shell_input_line, shell_input_line_size += 256);
+         RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256);
 
          if (c == EOF)
            {
              if (bash_input.type == st_stream)
                clearerr (stdin);
 
-             if (!i)
+             if (i == 0)
                shell_input_line_terminator = EOF;
 
              shell_input_line[i] = '\0';
@@ -2666,11 +2719,23 @@ shell_getc (remove_quoted_newline)
       shell_input_line_len = i;                /* == strlen (shell_input_line) */
 
 #if defined (HISTORY)
-      if (interactive && shell_input_line && shell_input_line[0])
+      if (remember_on_history && shell_input_line && shell_input_line[0])
        {
          char *expansions;
-
+#  if defined (BANG_HISTORY)
+         int old_hist;
+
+         /* If the current delimiter is a single quote, we should not be
+            performing history expansion, even if we're on a different
+            line from the original single quote. */
+         old_hist = history_expansion_inhibited;
+         if (current_delimiter (dstack) == '\'')
+           history_expansion_inhibited = 1;
+#  endif
          expansions = pre_process_line (shell_input_line, 1, 1);
+#  if defined (BANG_HISTORY)
+         history_expansion_inhibited = old_hist;
+#  endif
 
          free (shell_input_line);
          shell_input_line = expansions;
@@ -2684,6 +2749,18 @@ shell_getc (remove_quoted_newline)
             true allocated size of shell_input_line anymore. */
          shell_input_line_size = shell_input_line_len;
        }
+      /* XXX - this is grotesque */
+      else if (remember_on_history && shell_input_line &&
+              shell_input_line[0] == '\0' &&
+              current_command_line_count > 1 && current_delimiter (dstack))
+       {
+         /* We know shell_input_line[0] == 0 and we're reading some sort of
+            quoted string.  This means we've got a line consisting of only
+            a newline in a quoted string.  We want to make sure this line
+            gets added to the history. */
+         maybe_add_history (shell_input_line);
+       }
+
 #endif /* HISTORY */
 
       if (shell_input_line)
@@ -2706,17 +2783,15 @@ shell_getc (remove_quoted_newline)
         not already end in an EOF character.  */
       if (shell_input_line_terminator != EOF)
        {
-         l = shell_input_line_len;     /* was a call to strlen */
-
-         if (l + 3 > shell_input_line_size)
+         if (shell_input_line_len + 3 > shell_input_line_size)
            shell_input_line = xrealloc (shell_input_line,
                                        1 + (shell_input_line_size += 2));
 
-         shell_input_line[l] = '\n';
-         shell_input_line[l + 1] = '\0';
+         shell_input_line[shell_input_line_len] = '\n';
+         shell_input_line[shell_input_line_len + 1] = '\0';
        }
     }
-  
+
   c = shell_input_line[shell_input_line_index];
 
   if (c)
@@ -2726,7 +2801,8 @@ shell_getc (remove_quoted_newline)
       shell_input_line[shell_input_line_index] == '\n')
     {
        prompt_again ();
-       goto restart_read_next_line;
+       line_number++;
+       goto restart_read;
     }
 
 #if defined (ALIAS)
@@ -2737,20 +2813,24 @@ shell_getc (remove_quoted_newline)
      to. */
   if (!c && (pushed_string_list != (STRING_SAVER *)NULL))
     {
-      pop_string ();
-      c = shell_input_line[shell_input_line_index];
-      if (c)
-       shell_input_line_index++;
+      if (mustpop)
+        {
+          pop_string ();
+          c = shell_input_line[shell_input_line_index];
+         if (c)
+           shell_input_line_index++;
+         mustpop--;
+        }
+      else
+        {
+          mustpop++;
+          c = ' ';
+        }
     }
 #endif /* ALIAS */
 
   if (!c && shell_input_line_terminator == EOF)
-    {
-      if (shell_input_line_index != 0)
-       return ('\n');
-      else
-       return (EOF);
-    }
+    return ((shell_input_line_index != 0) ? '\n' : EOF);
 
   return ((unsigned char)c);
 }
@@ -2764,7 +2844,15 @@ shell_ungetc (c)
     shell_input_line[--shell_input_line_index] = c;
 }
 
-/* Discard input until CHARACTER is seen. */
+static void
+shell_ungetchar ()
+{
+  if (shell_input_line && shell_input_line_index)
+    shell_input_line_index--;
+}
+
+/* Discard input until CHARACTER is seen, then push that character back
+   onto the input stream. */
 static void
 discard_until (character)
      int character;
@@ -2777,13 +2865,6 @@ discard_until (character)
   if (c != EOF)
     shell_ungetc (c);
 }
-\f
-/* Place to remember the token.  We try to keep the buffer
-   at a reasonable size, but it can grow. */
-static char *token = (char *)NULL;
-
-/* Current size of the token buffer. */
-static int token_buffer_size = 0;
 
 void
 execute_prompt_command (command)
@@ -2811,10 +2892,17 @@ execute_prompt_command (command)
   bind_variable ("_", last_lastarg);
   FREE (last_lastarg);
 
-  if (token_to_read == '\n')
+  if (token_to_read == '\n')   /* reset_parser was called */
     token_to_read = 0;
 }
 
+/* Place to remember the token.  We try to keep the buffer
+   at a reasonable size, but it can grow. */
+static char *token = (char *)NULL;
+
+/* Current size of the token buffer. */
+static int token_buffer_size;
+
 /* Command to read_token () explaining what we want it to do. */
 #define READ 0
 #define RESET 1
@@ -2823,10 +2911,10 @@ execute_prompt_command (command)
 
 /* Function for yyparse to call.  yylex keeps track of
    the last two tokens read, and calls read_token.  */
-
+static int
 yylex ()
 {
-  if (interactive && (!current_token || current_token == '\n'))
+  if (interactive && (current_token == 0 || current_token == '\n'))
     {
       /* Before we print a prompt, we might have to check mailboxes.
         We do this only if it is time to do so. Notice that only here
@@ -2844,35 +2932,16 @@ yylex ()
        prompt_again ();
     }
 
+  two_tokens_ago = token_before_that;
   token_before_that = last_read_token;
   last_read_token = current_token;
   current_token = read_token (READ);
   return (current_token);
 }
 
-/* Called from shell.c when Control-C is typed at top level.  Or
-   by the error rule at top level. */
-reset_parser ()
-{
-  read_token (RESET);
-}
-  
 /* When non-zero, we have read the required tokens
    which allow ESAC to be the next one read. */
-static int allow_esac_as_next = 0;
-
-/* When non-zero, accept single '{' as a token itself. */
-static int allow_open_brace = 0;
-
-/* DELIMITERS is a stack of the nested delimiters that we have
-   encountered so far. */
-static char *delimiters = (char *)NULL;
-
-/* Offset into the stack of delimiters. */
-int delimiter_depth = 0;
-
-/* How many slots are allocated to DELIMITERS. */
-static int delimiter_space = 0;
+static int esacs_needed_count;
 
 void
 gather_here_documents ()
@@ -2885,32 +2954,16 @@ gather_here_documents ()
     }
 }
 
-/* Macro for accessing the top delimiter on the stack.  Returns the
-   delimiter or zero if none. */
-#define current_delimiter() \
-  (delimiter_depth ? delimiters[delimiter_depth - 1] : 0)
-
-#define push_delimiter(character) \
-  do \
-    { \
-      if (delimiter_depth + 2 > delimiter_space) \
-       delimiters = xrealloc \
-         (delimiters, (delimiter_space += 10) * sizeof (char)); \
-      delimiters[delimiter_depth] = character; \
-      delimiter_depth++; \
-    } \
-  while (0)
-
 /* When non-zero, an open-brace used to create a group is awaiting a close
    brace partner. */
-static int open_brace_awaiting_satisfaction = 0;
+static int open_brace_count;
 
 #define command_token_position(token) \
   (((token) == ASSIGNMENT_WORD) || \
    ((token) != SEMI_SEMI && reserved_word_acceptable(token)))
 
 #define assignment_acceptable(token) command_token_position(token) && \
-                                       (in_case_pattern_list == 0)
+                                       ((parser_state & PST_CASEPAT) == 0)
 
 /* Check to see if TOKEN is a reserved word and return the token
    value if it is. */
@@ -2923,101 +2976,217 @@ static int open_brace_awaiting_satisfaction = 0;
        for (i = 0; word_token_alist[i].word != (char *)NULL; i++) \
          if (STREQ (tok, word_token_alist[i].word)) \
            { \
-             if (in_case_pattern_list && (word_token_alist[i].token != ESAC)) \
+             if ((parser_state & PST_CASEPAT) && (word_token_alist[i].token != ESAC)) \
                break; \
-\
              if (word_token_alist[i].token == ESAC) \
-               in_case_pattern_list = 0; \
-\
-             if (word_token_alist[i].token == '{') \
-               open_brace_awaiting_satisfaction++; \
-\
-             if (word_token_alist[i].token == '}' && open_brace_awaiting_satisfaction) \
-               open_brace_awaiting_satisfaction--; \
-\
+               parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \
+             else if (word_token_alist[i].token == CASE) \
+               parser_state |= PST_CASESTMT; \
+             else if (word_token_alist[i].token == '{') \
+               open_brace_count++; \
+             else if (word_token_alist[i].token == '}' && open_brace_count) \
+               open_brace_count--; \
              return (word_token_alist[i].token); \
            } \
       } \
   } while (0)
 
-/* Read the next token.  Command can be READ (normal operation) or 
-   RESET (to normalize state). */
+#if defined (ALIAS)
+
+    /* OK, we have a token.  Let's try to alias expand it, if (and only if)
+       it's eligible.
+
+       It is eligible for expansion if the shell is in interactive mode, and
+       the token is unquoted and the last token read was a command
+       separator (or expand_next_token is set), and we are currently
+       processing an alias (pushed_string_list is non-empty) and this
+       token is not the same as the current or any previously
+       processed alias.
+
+       Special cases that disqualify:
+        In a pattern list in a case statement (parser_state & PST_CASEPAT). */
 static int
-read_token (command)
-     int command;
+alias_expand_token (token)
+     char *token;
 {
-  int character;               /* Current character. */
-  int peek_char;               /* Temporary look-ahead character. */
-  int result;                  /* The thing to return. */
-  WORD_DESC *the_word;         /* The value for YYLVAL when a WORD is read. */
+  char *expanded;
+  alias_t *ap;
 
-  if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE)
+  if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) &&
+       (parser_state & PST_CASEPAT) == 0)
     {
-      FREE (token);
-      token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE);
+      ap = find_alias (token);
+
+      /* Currently expanding this token. */
+      if (ap && (ap->flags & AL_BEINGEXPANDED))
+       return (NO_EXPANSION);
+
+      expanded = ap ? savestring (ap->value) : (char *)NULL;
+      if (expanded)
+       {
+         push_string (expanded, ap->flags & AL_EXPANDNEXT, ap);
+         return (RE_READ_TOKEN);
+       }
+      else
+       /* This is an eligible token that does not have an expansion. */
+       return (NO_EXPANSION);
     }
+  return (NO_EXPANSION);
+}
+#endif /* ALIAS */
 
-  if (command == RESET)
+/* Handle special cases of token recognition:
+       IN is recognized if the last token was WORD and the token
+       before that was FOR or CASE or SELECT.
+
+       DO is recognized if the last token was WORD and the token
+       before that was FOR or SELECT.
+
+       ESAC is recognized if the last token caused `esacs_needed_count'
+       to be set
+
+       `{' is recognized if the last token as WORD and the token
+       before that was FUNCTION.
+
+       `}' is recognized if there is an unclosed `{' prsent.
+*/
+
+static int
+special_case_tokens (token)
+     char *token;
+{
+  if ((last_read_token == WORD) &&
+#if defined (SELECT_COMMAND)
+      ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) &&
+#else
+      ((token_before_that == FOR) || (token_before_that == CASE)) &&
+#endif
+      (token[0] == 'i' && token[1] == 'n' && token[2] == 0))
     {
-      delimiter_depth = 0;     /* No delimiters found so far. */
-      open_brace_awaiting_satisfaction = 0;
-      in_case_pattern_list = 0;
+      if (token_before_that == CASE)
+       {
+         parser_state |= PST_CASEPAT;
+         esacs_needed_count++;
+       }
+      return (IN);
+    }
 
-#if defined (ALIAS)
-      if (pushed_string_list)
+  if (last_read_token == WORD &&
+#if defined (SELECT_COMMAND)
+      (token_before_that == FOR || token_before_that == SELECT) &&
+#else
+      (token_before_that == FOR) &&
+#endif
+      (token[0] == 'd' && token[1] == 'o' && token[2] == '\0'))
+    return (DO);
+
+  /* Ditto for ESAC in the CASE case.
+     Specifically, this handles "case word in esac", which is a legal
+     construct, certainly because someone will pass an empty arg to the
+     case construct, and we don't want it to barf.  Of course, we should
+     insist that the case construct has at least one pattern in it, but
+     the designers disagree. */
+  if (esacs_needed_count)
+    {
+      esacs_needed_count--;
+      if (STREQ (token, "esac"))
        {
-         free_string_list ();
-         pushed_string_list = (STRING_SAVER *)NULL;
+         parser_state &= ~PST_CASEPAT;
+         return (ESAC);
        }
+    }
 
-      if (expanded_token_stack)
+  /* The start of a shell function definition. */
+  if (parser_state & PST_ALLOWOPNBRC)
+    {
+      parser_state &= ~PST_ALLOWOPNBRC;
+      if (token[0] == '{' && token[1] == '\0')         /* } */
        {
-         free_expansion_stack ();
-         expanded_token_stack = (EXPANSION_SAVER *)NULL;
+         open_brace_count++;
+         function_bstart = line_number;
+         return ('{');                                 /* } */
        }
+    }
+
+  if (open_brace_count && reserved_word_acceptable (last_read_token) && token[0] == '}' && !token[1])
+    {
+      open_brace_count--;              /* { */
+      return ('}');
+    }
+
+  /* Handle -p after `time'. */
+  if (last_read_token == TIME && token[0] == '-' && token[1] == 'p' && !token[2])
+    return (TIMEOPT);
+
+  return (-1);
+}
 
-      expand_next_token = 0;
+/* Called from shell.c when Control-C is typed at top level.  Or
+   by the error rule at top level. */
+void
+reset_parser ()
+{
+  dstack.delimiter_depth = 0;  /* No delimiters found so far. */
+  open_brace_count = 0;
+
+  parser_state = 0;
+
+#if defined (ALIAS)
+  if (pushed_string_list)
+    {
+      free_string_list ();
+      pushed_string_list = (STRING_SAVER *)NULL;
+    }
 #endif /* ALIAS */
 
-      if (shell_input_line)
-       {
-         free (shell_input_line);
-         shell_input_line = (char *)NULL;
-         shell_input_line_size = shell_input_line_index = 0;
-       }
-      last_read_token = '\n';
-      token_to_read = '\n';
+  if (shell_input_line)
+    {
+      free (shell_input_line);
+      shell_input_line = (char *)NULL;
+      shell_input_line_size = shell_input_line_index = 0;
+    }
+
+  FREE (word_desc_to_read);
+  word_desc_to_read = (WORD_DESC *)NULL;
+
+  last_read_token = '\n';
+  token_to_read = '\n';
+}
+
+/* Read the next token.  Command can be READ (normal operation) or
+   RESET (to normalize state). */
+static int
+read_token (command)
+     int command;
+{
+  int character;               /* Current character. */
+  int peek_char;               /* Temporary look-ahead character. */
+  int result;                  /* The thing to return. */
+
+  if (command == RESET)
+    {
+      reset_parser ();
       return ('\n');
     }
 
   if (token_to_read)
     {
-      int rt = token_to_read;
+      result = token_to_read;
+      if (token_to_read == WORD || token_to_read == ASSIGNMENT_WORD)
+       yylval.word = word_desc_to_read;
       token_to_read = 0;
-      return (rt);
+      return (result);
     }
 
 #if defined (ALIAS)
-  /* If we hit read_token () and there are no saved strings on the
-     pushed_string_list, then we are no longer currently expanding a
-     token.  This can't be done in pop_stream, because pop_stream
-     may pop the stream before the current token has finished being
-     completely expanded (consider what happens when we alias foo to foo,
-     and then try to expand it). */
-  if (!pushed_string_list && expanded_token_stack)
-    {
-      free_expansion_stack ();
-      expanded_token_stack = (EXPANSION_SAVER *)NULL;
-    }
-
   /* This is a place to jump back to once we have successfully expanded a
      token with an alias and pushed the string with push_string () */
  re_read_token:
-
 #endif /* ALIAS */
 
   /* Read a single word from input.  Start by skipping blanks. */
-  while ((character = shell_getc (1)) != EOF && whitespace (character));
+  while ((character = shell_getc (1)) != EOF && whitespace (character))
+    ;
 
   if (character == EOF)
     {
@@ -3030,17 +3199,7 @@ read_token (command)
       /* A comment.  Discard until EOL or EOF, and then return a newline. */
       discard_until ('\n');
       shell_getc (0);
-
-      /* If we're about to return an unquoted newline, we can go and collect
-        the text of any pending here documents. */
-      if (need_here_doc)
-        gather_here_documents ();
-
-#if defined (ALIAS)
-      expand_next_token = 0;
-#endif /* ALIAS */
-
-      return ('\n');
+      character = '\n';        /* this will take the next if statement and return. */
     }
 
   if (character == '\n')
@@ -3051,31 +3210,30 @@ read_token (command)
        gather_here_documents ();
 
 #if defined (ALIAS)
-      expand_next_token = 0;
+      parser_state &= ~PST_ALEXPNEXT;
 #endif /* ALIAS */
 
       return (character);
     }
 
-  if (member (character, "()<>;&|"))
+  /* Shell meta-characters. */
+  if (shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0))
     {
 #if defined (ALIAS)
       /* Turn off alias tokenization iff this character sequence would
         not leave us ready to read a command. */
       if (character == '<' || character == '>')
-       expand_next_token = 0;
+       parser_state &= ~PST_ALEXPNEXT;
 #endif /* ALIAS */
 
-      /* Please note that the shell does not allow whitespace to
-        appear in between tokens which are character pairs, such as
-        "<<" or ">>".  I believe this is the correct behaviour. */
-      if (character == (peek_char = shell_getc (1)))
+      peek_char = shell_getc (1);
+      if (character == peek_char)
        {
          switch (character)
            {
+           case '<':
              /* If '<' then we could be at "<<" or at "<<-".  We have to
                 look ahead one more character. */
-           case '<':
              peek_char = shell_getc (1);
              if (peek_char == '-')
                return (LESS_LESS_MINUS);
@@ -3089,9 +3247,9 @@ read_token (command)
              return (GREATER_GREATER);
 
            case ';':
-             in_case_pattern_list = 1;
+             parser_state |= PST_CASEPAT;
 #if defined (ALIAS)
-             expand_next_token = 0;
+             parser_state &= ~PST_ALEXPNEXT;
 #endif /* ALIAS */
              return (SEMI_SEMI);
 
@@ -3100,526 +3258,637 @@ read_token (command)
 
            case '|':
              return (OR_OR);
-           }
-       }
-      else
-       {
-         if (peek_char == '&')
-           {
-             switch (character)
+
+#if defined (DPAREN_ARITHMETIC)
+           case '(':           /* ) */
+             if (reserved_word_acceptable (last_read_token))
                {
-               case '<': return (LESS_AND);
-               case '>': return (GREATER_AND);
+                 parser_state |= PST_DBLPAREN;
+                 yylval.word = make_word ("let");
+                 return (WORD);          
                }
+             break;
+#endif
            }
-         if (character == '<' && peek_char == '>')
-           return (LESS_GREATER);
-         if (character == '>' && peek_char == '|')
-           return (GREATER_BAR);
-         if (peek_char == '>' && character == '&')
-           return (AND_GREATER);
        }
+      else if (character == '<' && peek_char == '&')
+       return (LESS_AND);
+      else if (character == '>' && peek_char == '&')
+       return (GREATER_AND);
+      else if (character == '<' && peek_char == '>')
+       return (LESS_GREATER);
+      else if (character == '>' && peek_char == '|')
+       return (GREATER_BAR);
+      else if (peek_char == '>' && character == '&')
+       return (AND_GREATER);
+
       shell_ungetc (peek_char);
 
       /* If we look like we are reading the start of a function
         definition, then let the reader know about it so that
         we will do the right thing with `{'. */
-      if (character == ')' &&
-         last_read_token == '(' && token_before_that == WORD)
+      if (character == ')' && last_read_token == '(' && token_before_that == WORD)
        {
-         allow_open_brace = 1;
+         parser_state |= PST_ALLOWOPNBRC;
 #if defined (ALIAS)
-         expand_next_token = 0;
+         parser_state &= ~PST_ALEXPNEXT;
 #endif /* ALIAS */
+         function_dstart = line_number;
        }
 
-      if (in_case_pattern_list && (character == ')'))
-       in_case_pattern_list = 0;
+      /* case pattern lists may be preceded by an optional left paren.  If
+        we're not trying to parse a case pattern list, the left paren
+        indicates a subshell. */
+      if (character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */
+       parser_state |= PST_SUBSHELL;
+      /*(*/
+      else if ((parser_state & PST_CASEPAT) && character == ')')
+        parser_state &= ~PST_CASEPAT;
+      /*(*/
+      else if ((parser_state & PST_SUBSHELL) && character == ')')
+       parser_state &= ~PST_SUBSHELL;
 
 #if defined (PROCESS_SUBSTITUTION)
       /* Check for the constructs which introduce process substitution.
         Shells running in `posix mode' don't do process substitution. */
       if (posixly_correct ||
-         (((character == '>' || character == '<') && peek_char == '(') == 0))
+         ((character != '>' && character != '<') || peek_char != '('))
 #endif /* PROCESS_SUBSTITUTION */
        return (character);
     }
 
   /* Hack <&- (close stdin) case. */
-  if (character == '-')
-    {
-      switch (last_read_token)
-       {
-       case LESS_AND:
-       case GREATER_AND:
-         return (character);
-       }
-    }
-  
+  if (character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
+    return (character);
+
   /* Okay, if we got this far, we have to read a word.  Read one,
      and then check it against the known ones. */
-  {
-    /* Index into the token that we are building. */
-    int token_index = 0;
-
-    /* ALL_DIGITS becomes zero when we see a non-digit. */
-    int all_digits = digit (character);
-
-    /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
-    int dollar_present = 0;
-
-    /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
-    int quoted = 0;
-
-    /* Non-zero means to ignore the value of the next character, and just
-       to add it no matter what. */
-    int pass_next_character = 0;
+  result = read_token_word (character);
+#if defined (ALIAS)
+  if (result == RE_READ_TOKEN)
+    goto re_read_token;
+#endif
+  return result;
+}
 
-    /* Non-zero means parsing a dollar-paren construct.  It is the count of
-       un-quoted closes we need to see. */
-    int dollar_paren_level = 0;
+/* Match a $(...) or other grouping construct.  This has to handle embedded
+   quoted strings ('', ``, "") and nested constructs.  It also must handle
+   reprompting the user, if necessary, after reading a newline, and returning
+   correct error values if it reads EOF. */
+static char matched_pair_error;
+static char *
+parse_matched_pair (qc, open, close, lenp, flags)
+     int qc;   /* `"' if this construct is within double quotes */
+     int open, close;
+     int *lenp, flags;
+{
+  int count, ch, was_dollar;
+  int pass_next_character, nestlen, start_lineno;
+  char *ret, *nestret;
+  int retind, retsize;
 
-    /* Non-zero means parsing a dollar-bracket construct ($[...]).  It is
-       the count of un-quoted `]' characters we need to see. */
-    int dollar_bracket_level = 0;
+  count = 1;
+  pass_next_character = was_dollar = 0;
 
-    /* Non-zero means parsing a `${' construct.  It is the count of
-       un-quoted `}' we need to see. */
-    int dollar_brace_level = 0;
+  ret = xmalloc (retsize = 64);
+  retind = 0;
 
-    /* A level variable for parsing '${ ... }' constructs inside of double
-       quotes. */
-    int delimited_brace_level = 0;
+  start_lineno = line_number;
+  while (count)
+    {
+      ch = shell_getc (qc != '\'' && pass_next_character == 0);
+      if (ch == EOF)
+       {
+         free (ret);
+         parser_error (start_lineno, "unexpected EOF while looking for matching `%c'", close);
+         EOF_Reached = 1;      /* XXX */
+         return (&matched_pair_error);
+       }
 
-    /* A boolean variable denoting whether or not we are currently parsing
-       a double-quoted string embedded in a $( ) or ${ } construct. */
-    int embedded_quoted_string = 0;
+      /* Possible reprompting. */
+      if (ch == '\n' && interactive &&
+           (bash_input.type == st_stdin || bash_input.type == st_stream))
+       prompt_again ();
 
-    /* Another level variable.  This one is for dollar_parens inside of
-       double-quotes. */
-    int delimited_paren_level = 0;
+      if (pass_next_character)         /* last char was backslash */
+       {
+         pass_next_character = 0;
+         if (qc != '\'' && ch == '\n') /* double-quoted \<newline> disappears. */
+           {
+             if (retind > 0) retind--; /* swallow previously-added backslash */
+             continue;
+           }
 
-    /* The current delimiting character. */
-    int cd;
+         RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+         if (ch == CTLESC || ch == CTLNUL)
+           ret[retind++] = CTLESC;
+         ret[retind++] = ch;
+         continue;
+       }
+      else if (ch == CTLESC || ch == CTLNUL)   /* special shell escapes */
+       {
+         RESIZE_MALLOCED_BUFFER (ret, retind, 2, retsize, 64);
+         ret[retind++] = CTLESC;
+         ret[retind++] = ch;
+         continue;
+       }
+      else if (ch == close)            /* ending delimiter */
+       count--;
+      else if (ch == open)             /* nested begin */
+       count++;
 
-    for (;;)
-      {
-       if (character == EOF)
-         goto got_token;
+      /* Add this character. */
+      RESIZE_MALLOCED_BUFFER (ret, retind, 1, retsize, 64);
+      ret[retind++] = ch;
 
-       if (pass_next_character)
-         {
-           pass_next_character = 0;
-           goto got_character;
-         }
+      if (open == '\'')                        /* '' inside grouping construct */
+       continue;
 
-       cd = current_delimiter ();
+      if (ch == '\\')                  /* backslashes */
+       pass_next_character++;
 
-       if (cd && character == '\\' && cd != '\'')
-         {
-           peek_char = shell_getc (0);
-           if (peek_char != '\\')
-             shell_ungetc (peek_char);
-           else
-             {
-               token[token_index++] = character;
-               goto got_character;
-             }
-         }
-
-       /* Handle backslashes.  Quote lots of things when not inside of
-          double-quotes, quote some things inside of double-quotes. */
-          
-       if (character == '\\' && (!delimiter_depth || cd != '\''))
-         {
-           peek_char = shell_getc (0);
-
-           /* Backslash-newline is ignored in all cases excepting
-              when quoted with single quotes. */
-           if (peek_char == '\n')
-             {
-               character = '\n';
-               goto next_character;
-             }
-           else
-             {
-               shell_ungetc (peek_char);
+      if (open != close)               /* a grouping construct */
+       {
+         if (shellquote (ch))
+           {
+             /* '', ``, or "" inside $(...) or other grouping construct. */
+             push_delimiter (dstack, ch);
+             nestret = parse_matched_pair (ch, ch, ch, &nestlen, 0);
+             pop_delimiter (dstack);
+             if (nestret == &matched_pair_error)
+               {
+                 free (ret);
+                 return &matched_pair_error;
+               }
+             if (nestlen)
+               {
+                 RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64);
+                 strcpy (ret + retind, nestret);
+                 retind += nestlen;
+               }
+             FREE (nestret);
+           }
+       }
+      /* Parse an old-style command substitution within double quotes as a
+        single word. */
+      /* XXX - sh and ksh93 don't do this - XXX */
+      else if (open == '"' && ch == '`')
+       {
+         nestret = parse_matched_pair (0, '`', '`', &nestlen, 0);
+         if (nestret == &matched_pair_error)
+           {
+             free (ret);
+             return &matched_pair_error;
+           }
+         if (nestlen)
+           {
+             RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64);
+             strcpy (ret + retind, nestret);
+             retind += nestlen;
+           }
+         FREE (nestret);
+       }
+      else if (was_dollar && (ch == '(' || ch == '{' || ch == '['))    /* ) } ] */
+       /* check for $(), $[], or ${} inside quoted string. */
+       {
+         if (open == ch)       /* undo previous increment */
+           count--;
+         if (ch == '(')                /* ) */
+           nestret = parse_matched_pair (0, '(', ')', &nestlen, 0);
+         else if (ch == '{')           /* } */
+           nestret = parse_matched_pair (0, '{', '}', &nestlen, 0);
+         else if (ch == '[')           /* ] */
+           nestret = parse_matched_pair (0, '[', ']', &nestlen, 0);
+         if (nestret == &matched_pair_error)
+           {
+             free (ret);
+             return &matched_pair_error;
+           }
+         if (nestlen)
+           {
+             RESIZE_MALLOCED_BUFFER (ret, retind, nestlen, retsize, 64);
+             strcpy (ret + retind, nestret);
+             retind += nestlen;
+           }
+         FREE (nestret);
+       }
+      was_dollar = (ch == '$');
+    }
 
-               /* If the next character is to be quoted, do it now. */
-               if (!cd || cd == '`' ||
-                   (cd == '"' && member (peek_char, slashify_in_quotes)))
-                 {
-                   pass_next_character++;
-                   quoted = 1;
-                   goto got_character;
-                 }
-             }
-         }
-
-       /* This is a hack, in its present form.  If a backquote substitution
-          appears within double quotes, everything within the backquotes
-          should be read as part of a single word.  Jesus.  Now I see why
-          Korn introduced the $() form. */
-       if (delimiter_depth && (cd == '"') && (character == '`'))
-         {
-           push_delimiter (character);
-           goto got_character;
-         }
-
-       cd = current_delimiter ();              /* XXX - may not need */
-       if (delimiter_depth)
-         {
-           if (character == cd)
-             {
-               /* If we see a double quote while parsing a double-quoted
-                 $( ) or ${ }, and we have not seen ) or }, respectively,
-                  note that we are in the middle of reading an embedded
-                  quoted string. */
-               if ((delimited_paren_level || delimited_brace_level) &&
-                   (character == '"'))
-                 {
-                   embedded_quoted_string = !embedded_quoted_string;
-                   goto got_character;
-                 }
-               
-               delimiter_depth--;
-               goto got_character;
-             }
-         }
+  ret[retind] = '\0';
+  if (lenp)
+    *lenp = retind;
+  return ret;
+}
 
-       if (cd != '\'')
-         {
-#if defined (PROCESS_SUBSTITUTION)
-           if (character == '$' || character == '<' || character == '>')
-#else
-           if (character == '$')
-#endif /* !PROCESS_SUBSTITUTION */
-             {
-               /* If we're in the middle of parsing a $( ) or ${ }
-                  construct with an embedded quoted string, don't
-                  bother looking at this character any further. */
-               if (embedded_quoted_string)
-                 goto got_character;
-
-               peek_char = shell_getc (1);
-               shell_ungetc (peek_char);
-               if (peek_char == '(')
-                 {
-                   if (!delimiter_depth)
-                     dollar_paren_level++;
-                   else
-                     delimited_paren_level++;
+static int
+read_token_word (character)
+     int character;
+{
+  /* The value for YYLVAL when a WORD is read. */
+  WORD_DESC *the_word;
 
-                   pass_next_character++;
-                   goto got_character;
-                 }
-               else if (peek_char == '[' && character == '$')
-                 {
-                   if (!delimiter_depth)
-                     dollar_bracket_level++;
+  /* Index into the token that we are building. */
+  int token_index;
 
-                   pass_next_character++;
-                   goto got_character;
-                 }
-               /* This handles ${...} constructs. */
-               else if (peek_char == '{' && character == '$')
-                 {
-                   if (!delimiter_depth)
-                     dollar_brace_level++;
-                   else
-                     delimited_brace_level++;
+  /* ALL_DIGITS becomes zero when we see a non-digit. */
+  int all_digits;
 
-                   pass_next_character++;
-                   goto got_character;
-                 }
-             }
+  /* DOLLAR_PRESENT becomes non-zero if we see a `$'. */
+  int dollar_present;
 
-           /* If we are parsing a $() or $[] construct, we need to balance
-              parens and brackets inside the construct.  This whole function
-              could use a rewrite. */
-           if (character == '(' && !embedded_quoted_string)
-             {
-               if (delimiter_depth && delimited_paren_level)
-                 delimited_paren_level++;
+  /* QUOTED becomes non-zero if we see one of ("), ('), (`), or (\). */
+  int quoted;
 
-               if (!delimiter_depth && dollar_paren_level)
-                 dollar_paren_level++;
-             }
+  /* Non-zero means to ignore the value of the next character, and just
+     to add it no matter what. */
+ int pass_next_character;
 
-           if (character == '[')
-             {
-               if (!delimiter_depth && dollar_bracket_level)
-                 dollar_bracket_level++;
-             }
+  /* The current delimiting character. */
+  int cd;
+  int result, peek_char;
+  char *ttok, *ttrans;
+  int ttoklen, ttranslen;
 
-           if (character == '{' && !embedded_quoted_string)
-             {
-               if (delimiter_depth && delimited_brace_level)
-                 delimited_brace_level++;
+  if (token_buffer_size < TOKEN_DEFAULT_GROW_SIZE)
+    {
+      FREE (token);
+      token = xmalloc (token_buffer_size = TOKEN_DEFAULT_GROW_SIZE);
+    }
 
-               if (!delimiter_depth && dollar_brace_level)
-                 dollar_brace_level++;
-             }
+  token_index = 0;
+  all_digits = digit (character);
+  dollar_present = quoted = pass_next_character = 0;
 
-           /* This code needs to take into account whether we are inside a
-              case statement pattern list, and whether this paren is supposed
-              to terminate it (hey, it could happen).  It's not as simple
-              as just using in_case_pattern_list, because we're not parsing
-              anything while we're reading a $( ) construct.  Maybe we
-              should move that whole mess into the yacc parser. */
-           if (character == ')' && !embedded_quoted_string)
-             {
-               if (delimiter_depth && delimited_paren_level)
-                 delimited_paren_level--;
+  for (;;)
+    {
+      if (character == EOF)
+       goto got_token;
 
-               if (!delimiter_depth && dollar_paren_level)
-                 {
-                   dollar_paren_level--;
-                   goto got_character;
-                 }
-             }
+      if (pass_next_character)
+       {
+         pass_next_character = 0;
+         goto got_character;
+       }
 
-           if (character == ']')
-             {
-               if (!delimiter_depth && dollar_bracket_level)
-                 {
-                   dollar_bracket_level--;
-                   goto got_character;
-                 }
-             }
+      cd = current_delimiter (dstack);
 
-           if (character == '}' && !embedded_quoted_string)
-             {
-               if (delimiter_depth && delimited_brace_level)
-                 delimited_brace_level--;
+      /* Handle backslashes.  Quote lots of things when not inside of
+        double-quotes, quote some things inside of double-quotes. */
+      if (character == '\\')
+       {
+         peek_char = shell_getc (0);
 
-               if (!delimiter_depth && dollar_brace_level)
-                 {
-                   dollar_brace_level--;
-                   goto got_character;
-                 }
-             }
-         }
+         /* Backslash-newline is ignored in all cases except
+            when quoted with single quotes. */
+         if (peek_char == '\n')
+           {
+             character = '\n';
+             goto next_character;
+           }
+         else
+           {
+             shell_ungetc (peek_char);
 
-       if (!dollar_paren_level && !dollar_bracket_level &&
-           !dollar_brace_level && !delimiter_depth &&
-           member (character, " \t\n;&()|<>"))
-         {
-           shell_ungetc (character);
-           goto got_token;
-         }
-    
-       if (!delimiter_depth)
-         {
-           if (character == '"' || character == '`' || character == '\'')
-             {
-               push_delimiter (character);
+             /* If the next character is to be quoted, note it now. */
+             if (cd == 0 || cd == '`' ||
+                 (cd == '"' && member (peek_char, slashify_in_quotes)))
+               pass_next_character++;
 
-               quoted = 1;
-               goto got_character;
-             }
-         }
+             quoted = 1;
+             goto got_character;
+           }
+       }
 
-       if (all_digits)
-         all_digits = digit (character);
-       if (character == '$')
-         dollar_present = 1;
+#if defined (DPAREN_ARITHMETIC)
+      /* Parse a ksh-style ((...)) expression. */
+      if (parser_state & PST_DBLPAREN)
+       {
+         int exp_lineno;
 
-      got_character:
+         /* If we've already consumed a right paren that should be part of
+            the expression, push it back so the paren matching code won't
+            return prematurely. */
+         if (character == '(')         /* ) */
+           shell_ungetc (character);
+         exp_lineno = line_number;
+         ttok = parse_matched_pair (0, '(', ')', &ttoklen, 0);
+         parser_state &= ~PST_DBLPAREN;
+         if (ttok == &matched_pair_error)
+           return -1;
+         /* Check that the next character is the closing right paren.  If
+            not, this is a syntax error. ( */
+         if (shell_getc (0) != ')')
+           {
+             FREE (ttok);      /* ( */
+             parser_error (exp_lineno, "missing closing `)' for arithmetic expression");
+             return -1;
+           }
+         RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 4,
+                                 token_buffer_size, TOKEN_DEFAULT_GROW_SIZE);
+         token[token_index++] = '"';
+         if (character != '(')         /* ) */
+           token[token_index++] = character;
+         strncpy (token + token_index, ttok, ttoklen - 1);
+         token_index += ttoklen - 1;
+         token[token_index++] = '"';
+         FREE (ttok);
+         dollar_present = all_digits = 0;
+         quoted = 1;
+         goto got_token;
+       }
+#endif /* DPAREN_ARITHMETIC */
 
-       if (character == CTLESC || character == CTLNUL)
-         token[token_index++] = CTLESC;
+      /* Parse a matched pair of quote characters. */
+      if (shellquote (character))
+       {
+         push_delimiter (dstack, character);
+         ttok = parse_matched_pair (character, character, character, &ttoklen, 0);
+         pop_delimiter (dstack);
+         if (ttok == &matched_pair_error)
+           return -1;          /* Bail immediately. */
+         RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
+                                 token_buffer_size, TOKEN_DEFAULT_GROW_SIZE);
+         token[token_index++] = character;
+         strcpy (token + token_index, ttok);
+         token_index += ttoklen;
+         all_digits = 0;
+         quoted = 1;
+         dollar_present |= (character == '"' && strchr (ttok, '$') != 0);
+         FREE (ttok);
+         goto next_character;
+       }
 
-       token[token_index++] = character;
+      /* If the delimiter character is not single quote, parse some of
+        the shell expansions that must be read as a single word. */
+#if defined (PROCESS_SUBSTITUTION)
+      if (character == '$' || character == '<' || character == '>')
+#else
+      if (character == '$')
+#endif /* !PROCESS_SUBSTITUTION */
+       {
+         peek_char = shell_getc (1);
+         /* $(...), <(...), >(...), $((...)), ${...}, and $[...] constructs */
+         if (peek_char == '(' ||
+               ((peek_char == '{' || peek_char == '[') && character == '$'))   /* ) ] } */
+           {
+             if (peek_char == '{')             /* } */
+               ttok = parse_matched_pair (cd, '{', '}', &ttoklen, 0);
+             else if (peek_char == '(')                /* ) */
+               ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
+             else
+               ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
+             if (ttok == &matched_pair_error)
+               return -1;              /* Bail immediately. */
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
+                                     token_buffer_size,
+                                     TOKEN_DEFAULT_GROW_SIZE);
+             token[token_index++] = character;
+             token[token_index++] = peek_char;
+             strcpy (token + token_index, ttok);
+             token_index += ttoklen;
+             FREE (ttok);
+             dollar_present = 1;
+             all_digits = 0;
+             goto next_character;
+           }
+         /* This handles $'...' and $"..." new-style quoted strings. */
+         else if (character == '$' && (peek_char == '\'' || peek_char == '"'))
+           {
+             ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0);
+             if (ttok == &matched_pair_error)
+               return -1;
+             if (peek_char == '\'')
+               ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
+             else
+               ttrans = localeexpand (ttok, 0, ttoklen - 1, &ttranslen);
+             free (ttok);
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
+                                     token_buffer_size,
+                                     TOKEN_DEFAULT_GROW_SIZE);
+             token[token_index++] = peek_char;
+             strcpy (token + token_index, ttrans);
+             token_index += ttranslen;
+             token[token_index++] = peek_char;
+             FREE (ttrans);
+             quoted = 1;
+             all_digits = 0;
+             goto next_character;
+           }
+         else
+           shell_ungetc (peek_char);
+       }
 
-       if (token_index == (token_buffer_size - 1))
-         {
-           token_buffer_size += TOKEN_DEFAULT_GROW_SIZE;
-           token = xrealloc (token, token_buffer_size);
-         }
-       next_character:
-       if (character == '\n' && interactive && bash_input.type != st_string)
-         prompt_again ();
+#if defined (ARRAY_VARS)
+      /* Identify possible compound array variable assignment. */
+      else if (character == '=')
+       {
+         peek_char = shell_getc (1);
+         if (peek_char == '(')         /* ) */
+           {
+             ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
+             if (ttok == &matched_pair_error)
+               return -1;              /* Bail immediately. */
+             RESIZE_MALLOCED_BUFFER (token, token_index, ttoklen + 2,
+                                     token_buffer_size,
+                                     TOKEN_DEFAULT_GROW_SIZE);
+             token[token_index++] = character;
+             token[token_index++] = peek_char;
+             strcpy (token + token_index, ttok);
+             token_index += ttoklen;
+             FREE (ttok);
+             all_digits = 0;
+             goto next_character;
+           }
+         else
+           shell_ungetc (peek_char);
+       }
+#endif
 
-       /* We want to remove quoted newlines (that is, a \<newline> pair)
-          unless we are within single quotes or pass_next_character is
-          set (the shell equivalent of literal-next). */
-       character = shell_getc
-         ((current_delimiter () != '\'') && (!pass_next_character));
-      }
+      /* When not parsing a multi-character word construct, shell meta-
+        characters break words. */
+      if (shellbreak (character))
+       {
+         shell_ungetc (character);
+         goto got_token;
+       }
 
-  got_token:
+    got_character:
 
-    token[token_index] = '\0';
-       
-    if ((delimiter_depth || dollar_paren_level || dollar_bracket_level) &&
-       character == EOF)
-      {
-       char reporter = '\0';
+      all_digits &= digit (character);
+      dollar_present |= character == '$';
 
-       if (!delimiter_depth)
-         {
-           if (dollar_paren_level)
-             reporter = ')';
-           else if (dollar_bracket_level)
-             reporter = ']';
-         }
+      if (character == CTLESC || character == CTLNUL)
+       token[token_index++] = CTLESC;
 
-       if (!reporter)
-         reporter = current_delimiter ();
+      token[token_index++] = character;
 
-       report_error ("unexpected EOF while looking for `%c'", reporter);
-       return (-1);
-      }
+      RESIZE_MALLOCED_BUFFER (token, token_index, 1, token_buffer_size,
+                             TOKEN_DEFAULT_GROW_SIZE);
 
-    if (all_digits)
-      {
-       /* Check to see what thing we should return.  If the last_read_token
-          is a `<', or a `&', or the character which ended this token is
-          a '>' or '<', then, and ONLY then, is this input token a NUMBER.
-          Otherwise, it is just a word, and should be returned as such. */
-
-       if (character == '<' || character == '>' ||
-           last_read_token == LESS_AND || last_read_token == GREATER_AND)
-         {
-           yylval.number = atoi (token);
-           return (NUMBER);
-         }
-      }
+    next_character:
+      if (character == '\n' && interactive &&
+       (bash_input.type == st_stdin || bash_input.type == st_stream))
+       prompt_again ();
 
-    /* Handle special case.  IN is recognized if the last token
-       was WORD and the token before that was FOR or CASE. */
-    if ((last_read_token == WORD) &&
-#if defined (SELECT_COMMAND)
-       ((token_before_that == FOR) || (token_before_that == CASE) || (token_before_that == SELECT)) &&
-#else
-       ((token_before_that == FOR) || (token_before_that == CASE)) &&
-#endif
-       (token[0] == 'i' && token[1] == 'n' && !token[2]))
-      {
-       if (token_before_that == CASE)
-         {
-           in_case_pattern_list = 1;
-           allow_esac_as_next++;
-         }
-       return (IN);
-      }
+      /* We want to remove quoted newlines (that is, a \<newline> pair)
+        unless we are within single quotes or pass_next_character is
+        set (the shell equivalent of literal-next). */
+      cd = current_delimiter (dstack);
+      character = shell_getc (cd != '\'' && pass_next_character == 0);
+    }  /* end for (;;) */
 
-    /* Ditto for DO in the FOR case. */
-#if defined (SELECT_COMMAND)
-    if ((last_read_token == WORD) && ((token_before_that == FOR) || (token_before_that == SELECT)) &&
-#else
-    if ((last_read_token == WORD) && (token_before_that == FOR) &&
-#endif
-       (token[0] == 'd' && token[1] == 'o' && !token[2]))
-      return (DO);
-
-    /* Ditto for ESAC in the CASE case. 
-       Specifically, this handles "case word in esac", which is a legal
-       construct, certainly because someone will pass an empty arg to the
-       case construct, and we don't want it to barf.  Of course, we should
-       insist that the case construct has at least one pattern in it, but
-       the designers disagree. */
-    if (allow_esac_as_next)
-      {
-       allow_esac_as_next--;
-       if (STREQ (token, "esac"))
-         {
-           in_case_pattern_list = 0;
-           return (ESAC);
-         }
-      }
+got_token:
 
-    /* Ditto for `{' in the FUNCTION case. */
-    if (allow_open_brace)
+  token[token_index] = '\0';
+
+  /* Check to see what thing we should return.  If the last_read_token
+     is a `<', or a `&', or the character which ended this token is
+     a '>' or '<', then, and ONLY then, is this input token a NUMBER.
+     Otherwise, it is just a word, and should be returned as such. */
+  if (all_digits && (character == '<' || character == '>' ||
+                   last_read_token == LESS_AND ||
+                   last_read_token == GREATER_AND))
       {
-       allow_open_brace = 0;
-       if (token[0] == '{' && !token[1])
-         {
-           open_brace_awaiting_satisfaction++;
-           return ('{');
-         }
+       yylval.number = atoi (token);
+       return (NUMBER);
       }
 
-    if (posixly_correct)
-      CHECK_FOR_RESERVED_WORD (token);
+  /* Check for special case tokens. */
+  result = special_case_tokens (token);
+  if (result >= 0)
+    return result;
 
 #if defined (ALIAS)
-    /* OK, we have a token.  Let's try to alias expand it, if (and only if)
-       it's eligible. 
+  /* Posix.2 does not allow reserved words to be aliased, so check for all
+     of them, including special cases, before expanding the current token
+     as an alias. */
+  if (posixly_correct)
+    CHECK_FOR_RESERVED_WORD (token);
+
+  /* Aliases are expanded iff EXPAND_ALIASES is non-zero, and quoting
+     inhibits alias expansion. */
+  if (expand_aliases && quoted == 0)
+    {
+      result = alias_expand_token (token);
+      if (result == RE_READ_TOKEN)
+       return (RE_READ_TOKEN);
+      else if (result == NO_EXPANSION)
+       parser_state &= ~PST_ALEXPNEXT;
+    }
 
-       It is eligible for expansion if the shell is in interactive mode, and
-       the token is unquoted and the last token read was a command
-       separator (or expand_next_token is set), and we are currently
-       processing an alias (pushed_string_list is non-empty) and this
-       token is not the same as the current or any previously
-       processed alias.
+  /* If not in Posix.2 mode, check for reserved words after alias
+     expansion. */
+  if (posixly_correct == 0)
+#endif
+    CHECK_FOR_RESERVED_WORD (token);
+
+  the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
+  the_word->word = xmalloc (1 + token_index);
+  the_word->flags = 0;
+  strcpy (the_word->word, token);
+  if (dollar_present)
+    the_word->flags |= W_HASDOLLAR;
+  if (quoted)
+    the_word->flags |= W_QUOTED;
+  /* A word is an assignment if it appears at the beginning of a
+     simple command, or after another assignment word.  This is
+     context-dependent, so it cannot be handled in the grammar. */
+  if (assignment (token))
+    {
+      the_word->flags |= W_ASSIGNMENT;
+      /* Don't perform word splitting on assignment statements. */
+      if (assignment_acceptable (last_read_token))
+       the_word->flags |= W_NOSPLIT;
+    }
 
-       Special cases that disqualify:
-        In a pattern list in a case statement (in_case_pattern_list). */
-    if (interactive_shell && !quoted && !in_case_pattern_list &&
-       (expand_next_token || command_token_position (last_read_token)))
-      {
-       char *alias_expand_word (), *expanded;
+  yylval.word = the_word;
 
-       if (expanded_token_stack && token_has_been_expanded (token))
-         goto no_expansion;
+  result = ((the_word->flags & (W_ASSIGNMENT|W_NOSPLIT)) == (W_ASSIGNMENT|W_NOSPLIT))
+               ? ASSIGNMENT_WORD : WORD;
 
-       expanded = alias_expand_word (token);
-       if (expanded)
-         {
-           int len = strlen (expanded), expand_next;
+  if (last_read_token == FUNCTION)
+    {
+      parser_state |= PST_ALLOWOPNBRC;
+      function_dstart = line_number;
+    }
 
-           /* Erase the current token. */
-           token_index = 0;
+  return (result);
+}
+
+/* $'...' ANSI-C expand the portion of STRING between START and END and
+   return the result.  The result cannot be longer than the input string. */
+static char *
+ansiexpand (string, start, end, lenp)
+     char *string;
+     int start, end, *lenp;
+{
+  char *temp, *t;
+  int len, tlen;
 
-           expand_next = (expanded[len - 1] == ' ') ||
-                         (expanded[len - 1] == '\t');
+  temp = xmalloc (end - start + 1);
+  for (tlen = 0, len = start; len < end; )
+    temp[tlen++] = string[len++];
+  temp[tlen] = '\0';
 
-           push_string (expanded, expand_next, token);
-           goto re_read_token;
-         }
-       else
-         /* This is an eligible token that does not have an expansion. */
-no_expansion:
-         expand_next_token = 0;
-      }
-    else
-      {
-       expand_next_token = 0;
-      }
-#endif /* ALIAS */
+  if (*temp)
+    {
+      t = ansicstr (temp, tlen, (int *)NULL);
+      free (temp);
+      if (lenp)
+       *lenp = strlen (t);
+      return (t);
+    }
+  else
+    {
+      if (lenp)
+       *lenp = 0;
+      return (temp);
+    }
+}
 
-    if (!posixly_correct)
-      CHECK_FOR_RESERVED_WORD (token);
+/* $"..." -- Translate the portion of STRING between START and END
+   according to current locale using gettext (if available) and return
+   the result.  The caller will take care of leaving the quotes intact.
+   The string will be left without the leading `$' by the caller.
+   If translation is performed, the translated string will be double-quoted
+   by the caller.  The length of the translated string is returned in LENP,
+   if non-null. */
+static char *
+localeexpand (string, start, end, lenp)
+     char *string;
+     int start, end, *lenp;
+{
+  int len, tlen;
+  char *temp, *t;
 
-    /* What if we are attempting to satisfy an open-brace grouper? */
-    if (open_brace_awaiting_satisfaction && token[0] == '}' && !token[1])
-      {
-       open_brace_awaiting_satisfaction--;
-       return ('}');
-      }
+  temp = xmalloc (end - start + 1);
+  for (tlen = 0, len = start; len < end; )
+    temp[tlen++] = string[len++];
+  temp[tlen] = '\0';
 
-    the_word = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
-    the_word->word = xmalloc (1 + token_index);
-    strcpy (the_word->word, token);
-    the_word->dollar_present = dollar_present;
-    the_word->quoted = quoted;
-    the_word->assignment = assignment (token);
-
-    yylval.word = the_word;
-    result = WORD;
-
-    /* A word is an assignment if it appears at the beginning of a
-       simple command, or after another assignment word.  This is
-       context-dependent, so it cannot be handled in the grammar. */
-    if (assignment_acceptable (last_read_token) && the_word->assignment)
-      result = ASSIGNMENT_WORD;
-
-    if (last_read_token == FUNCTION)
-      allow_open_brace = 1;
-  }
-  return (result);
+  /* If we're just dumping translatable strings, don't do anything. */
+  if (dump_translatable_strings)
+    {
+      printf ("\"%s\"\n", temp);
+      if (lenp)
+       *lenp = tlen;
+      return (temp);
+    }
+  else if (*temp)
+    {
+      t = localetrans (temp, tlen, &len);
+      free (temp);
+      if (lenp)
+       *lenp = len;
+      return (t);
+    }
+  else
+    {
+      if (lenp)
+       *lenp = 0;
+      return (temp);
+    }
 }
 
 /* Return 1 if TOKEN is a token that after being read would allow
@@ -3628,15 +3897,12 @@ static int
 reserved_word_acceptable (token)
      int token;
 {
-#if 0
-  if (member (token, "\n;()|&{") ||
-#else
   if (token == '\n' || token == ';' || token == '(' || token == ')' ||
       token == '|' || token == '&' || token == '{' ||
-#endif
       token == '}' ||                  /* XXX */
       token == AND_AND ||
       token == BANG ||
+      token == TIME || token == TIMEOPT ||
       token == DO ||
       token == ELIF ||
       token == ELSE ||
@@ -3662,12 +3928,13 @@ find_reserved_word (token)
      char *token;
 {
   int i;
-  for (i = 0; word_token_alist[i].word != (char *)NULL; i++)
+  for (i = 0; word_token_alist[i].word; i++)
     if (STREQ (token, word_token_alist[i].word))
       return i;
   return -1;
 }
 
+#if 0
 #if defined (READLINE)
 /* Called after each time readline is called.  This insures that whatever
    the new prompt string is gets propagated to readline's local prompt
@@ -3675,11 +3942,11 @@ find_reserved_word (token)
 static void
 reset_readline_prompt ()
 {
+  char *temp_prompt;
+
   if (prompt_string_pointer)
     {
-      char *temp_prompt;
-
-      temp_prompt = *prompt_string_pointer
+      temp_prompt = (*prompt_string_pointer)
                        ? decode_prompt_string (*prompt_string_pointer)
                        : (char *)NULL;
 
@@ -3690,11 +3957,11 @@ reset_readline_prompt ()
        }
 
       FREE (current_readline_prompt);
-
       current_readline_prompt = temp_prompt;
     }
 }
 #endif /* READLINE */
+#endif /* 0 */
 
 #if defined (HISTORY)
 /* A list of tokens which can be followed by newlines, but not by
@@ -3702,29 +3969,48 @@ reset_readline_prompt ()
    newline separator for such tokens is replaced with a space. */
 static int no_semi_successors[] = {
   '\n', '{', '(', ')', ';', '&', '|',
-  CASE, DO, ELSE, IF, IN, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR,
+  CASE, DO, ELSE, IF, SEMI_SEMI, THEN, UNTIL, WHILE, AND_AND, OR_OR, IN,
   0
 };
 
 /* If we are not within a delimited expression, try to be smart
    about which separators can be semi-colons and which must be
-   newlines. */
+   newlines.  Returns the string that should be added into the
+   history entry. */
 char *
 history_delimiting_chars ()
 {
-  if (!delimiter_depth)
+  register int i;
+
+  if (dstack.delimiter_depth != 0)
+    return ("\n");
+    
+  /* First, handle some special cases. */
+  /*(*/
+  /* If we just read `()', assume it's a function definition, and don't
+     add a semicolon.  If the token before the `)' was not `(', and we're
+     not in the midst of parsing a case statement, assume it's a
+     parenthesized command and add the semicolon. */
+  /*)(*/
+  if (token_before_that == ')')
     {
-      register int i;
+      if (two_tokens_ago == '(')       /*)*/   /* function def */
+       return " ";
+      /* This does not work for subshells inside case statement
+        command lists.  It's a suboptimal solution. */
+      else if (parser_state & PST_CASESTMT)    /* case statement pattern */
+        return " ";
+      else     
+        return "; ";                           /* (...) subshell */
+    }
 
-      for (i = 0; no_semi_successors[i]; i++)
-       {
-         if (token_before_that == no_semi_successors[i])
-           return (" ");
-       }
-      return ("; ");
+  for (i = 0; no_semi_successors[i]; i++)
+    {
+      if (token_before_that == no_semi_successors[i])
+       return (" ");
     }
-  else
-    return ("\n");
+
+  return ("; ");
 }
 #endif /* HISTORY */
 
@@ -3744,7 +4030,7 @@ prompt_again ()
   if (!prompt_string_pointer)
     prompt_string_pointer = &ps1_prompt;
 
-  temp_prompt = (*prompt_string_pointer)
+  temp_prompt = *prompt_string_pointer
                        ? decode_prompt_string (*prompt_string_pointer)
                        : (char *)NULL;
 
@@ -3780,37 +4066,47 @@ print_prompt ()
 
 /* Return a string which will be printed as a prompt.  The string
    may contain special characters which are decoded as follows:
-   
-       \t      the time
-       \d      the date
+
+       \a      bell (ascii 07)
+       \e      escape (ascii 033)
+       \d      the date in Day Mon Date format
+       \h      the hostname up to the first `.'
+       \H      the hostname
        \n      CRLF
        \s      the name of the shell
+       \t      the time in 24-hour hh:mm:ss format
+       \T      the time in 12-hour hh:mm:ss format
+       \@      the time in 12-hour am/pm format
+       \v      the version of bash (e.g., 2.00)
+       \V      the release of bash, version + patchlevel (e.g., 2.00.0)
        \w      the current working directory
-       \W      the last element of PWD
+       \W      the last element of $PWD
        \u      your username
-       \h      the hostname
        \#      the command number of this command
        \!      the history number of this command
        \$      a $ or a # if you are root
-       \<octal> character code in octal
+       \nnn    character code nnn in octal
        \\      a backslash
+       \[      begin a sequence of non-printing chars
+       \]      end a sequence of non-printing chars
 */
 #define PROMPT_GROWTH 50
 char *
 decode_prompt_string (string)
      char *string;
 {
-  int result_size = PROMPT_GROWTH;
-  int result_index = 0;
-  char *result;
-  int c;
-  char *temp = (char *)NULL;
   WORD_LIST *list;
-
+  char *result, *t;
+  struct dstack save_dstack;
 #if defined (PROMPT_STRING_DECODE)
+  int result_size, result_index;
+  int c, n;
+  char *temp, octal_string[4];
+  time_t the_time;
 
-  result = xmalloc (PROMPT_GROWTH);
-  result[0] = 0;
+  result = xmalloc (result_size = PROMPT_GROWTH);
+  result[result_index = 0] = 0;
+  temp = (char *)NULL;
 
   while (c = *string++)
     {
@@ -3831,7 +4127,7 @@ decode_prompt_string (string)
                string--;       /* add_string increments string again. */
                goto add_string;
            }
-       } 
+       }
       if (c == '\\')
        {
          c = *string;
@@ -3846,171 +4142,199 @@ decode_prompt_string (string)
            case '5':
            case '6':
            case '7':
-             {
-               char octal_string[4];
-               int n;
+             strncpy (octal_string, string, 3);
+             octal_string[3] = '\0';
 
-               strncpy (octal_string, string, 3);
-               octal_string[3] = '\0';
+             n = read_octal (octal_string);
+             temp = xmalloc (3);
 
-               n = read_octal (octal_string);
-               temp = xmalloc (3);
+             if (n == CTLESC || n == CTLNUL)
+               {
+                 string += 3;
+                 temp[0] = CTLESC;
+                 temp[1] = n;
+                 temp[2] = '\0';
+               }
+             else if (n == -1)
+               {
+                 temp[0] = '\\';
+                 temp[1] = '\0';
+               }
+             else
+               {
+                 string += 3;
+                 temp[0] = n;
+                 temp[1] = '\0';
+               }
 
-               if (n == CTLESC || n == CTLNUL)
-                 {
-                   string += 3;
-                   temp[0] = CTLESC;
-                   temp[1] = n;
-                   temp[2] = '\0';
-                 }
-               else if (n == -1)
-                 {
-                   temp[0] = '\\';
-                   temp[1] = '\0';
-                 }
-               else
-                 {
-                   string += 3;
-                   temp[0] = n;
-                   temp[1] = '\0';
-                 }
+             c = 0;
+             goto add_string;
 
-               c = 0;
-               goto add_string;
-             }
-         
            case 't':
            case 'd':
+           case 'T':
+           case '@':
              /* Make the current time/date into a string. */
-             {
-               time_t the_time = time (0);
-               char *ttemp = ctime (&the_time);
-               temp = savestring (ttemp);
+             the_time = time (0);
+             temp = ctime (&the_time);
 
-               if (c == 't')
-                 {
-                   strcpy (temp, temp + 11);
-                   temp[8] = '\0';
-                 }
-               else
-                 temp[10] = '\0';
+             temp = (c != 'd') ? savestring (temp + 11) : savestring (temp);
+             temp[(c != 'd') ? 8 : 10] = '\0';
 
-               goto add_string;
-             }
+             /* quick and dirty conversion to 12-hour time */
+             if (c == 'T' || c == '@')
+               {
+                 if (c == '@')
+                   {
+                     temp[5] = 'a';    /* am/pm format */
+                     temp[6] = 'm';
+                     temp[7] = '\0';
+                   }
+                 c = temp[2];
+                 temp[2] = '\0';
+                 n = atoi (temp);
+                 temp[2] = c;
+                 n -= 12;
+                 if (n > 0)
+                   {
+                     temp[0] = (n / 10) + '0';
+                     temp[1] = (n % 10) + '0';
+                   }
+                 if (n >= 0 && temp[5] == 'a')
+                   temp[5] = 'p';
+               }
+             goto add_string;
 
            case 'n':
-             if (!no_line_editing)
-               temp = savestring ("\r\n");
-             else
-               temp = savestring ("\n");
+             temp = xmalloc (3);
+             temp[0] = no_line_editing ? '\n' : '\r';
+             temp[1] = no_line_editing ? '\0' : '\n';
+             temp[2] = '\0';
              goto add_string;
 
            case 's':
-             {
-               temp = base_pathname (shell_name);
-               temp = savestring (temp);
-               goto add_string;
-             }
-       
+             temp = base_pathname (shell_name);
+             temp = savestring (temp);
+             goto add_string;
+
+           case 'v':
+           case 'V':
+             temp = xmalloc (8);
+             if (c == 'v')
+               strcpy (temp, dist_version);
+             else
+               sprintf (temp, "%s.%d", dist_version, patch_level);
+             goto add_string;
+
            case 'w':
            case 'W':
              {
-               /* Use the value of PWD because it is much more effecient. */
-#define EFFICIENT
-#ifdef EFFICIENT
-               char *polite_directory_format (), t_string[MAXPATHLEN];
+               /* Use the value of PWD because it is much more efficient. */
+               char t_string[PATH_MAX];
 
                temp = get_string_value ("PWD");
 
-               if (!temp)
-                 getwd (t_string);
+               if (temp == 0)
+                 {
+                   if (getcwd (t_string, sizeof(t_string)) == 0)
+                     {
+                       t_string[0] = '.';
+                       t_string[1] = '\0';
+                     }
+                 }
                else
                  strcpy (t_string, temp);
-#else
-               getwd (t_string);
-#endif /* EFFICIENT */
 
                if (c == 'W')
                  {
-                   char *dir = (char *)strrchr (t_string, '/');
-                   if (dir && dir != t_string)
-                     strcpy (t_string, dir + 1);
-                   temp = savestring (t_string);
+                   t = strrchr (t_string, '/');
+                   if (t && t != t_string)
+                     strcpy (t_string, t + 1);
                  }
                else
-                 temp = savestring (polite_directory_format (t_string));
+                 strcpy (t_string, polite_directory_format (t_string));
+
+               /* If we're going to be expanding the prompt string later,
+                  quote the directory name. */
+               if (promptvars || posixly_correct)
+                 temp = backslash_quote (t_string);
+               else
+                 temp = savestring (t_string);
+
                goto add_string;
              }
-      
+
            case 'u':
-             {
-               temp = savestring (current_user.user_name);
-               goto add_string;
-             }
+             temp = savestring (current_user.user_name);
+             goto add_string;
 
            case 'h':
-             {
-               char *t_string;
-
-               temp = savestring (current_host_name);
-               if (t_string = (char *)strchr (temp, '.'))
-                 *t_string = '\0';
-               goto add_string;
-             }
+           case 'H':
+             temp = savestring (current_host_name);
+             if (c == 'h' && (t = (char *)strchr (temp, '.')))
+               *t = '\0';
+             goto add_string;
 
            case '#':
-             {
-               temp = itos (current_command_number);
-               goto add_string;
-             }
+             temp = itos (current_command_number);
+             goto add_string;
 
            case '!':
-             {
 #if !defined (HISTORY)
-               temp = savestring ("1");
+             temp = savestring ("1");
 #else /* HISTORY */
-               temp = itos (history_number ());
+             temp = itos (history_number ());
 #endif /* HISTORY */
-               goto add_string;
-             }
+             goto add_string;
 
            case '$':
-             temp = savestring (geteuid () == 0 ? "#" : "$");
+             temp = xmalloc (2);
+             temp[0] = current_user.euid == 0 ? '#' : '$';
+             temp[1] = '\0';
              goto add_string;
 
 #if defined (READLINE)
            case '[':
            case ']':
-             temp = xmalloc(3);
+             temp = xmalloc (3);
              temp[0] = '\001';
              temp[1] = (c == '[') ? RL_PROMPT_START_IGNORE : RL_PROMPT_END_IGNORE;
              temp[2] = '\0';
              goto add_string;
-#endif
+#endif /* READLINE */
 
            case '\\':
-             temp = savestring ("\\");
+             temp = xmalloc (2);
+             temp[0] = c;
+             temp[1] = '\0';
+             goto add_string;
+
+           case 'a':
+           case 'e':
+             temp = xmalloc (2);
+             temp[0] = (c == 'a') ? '\07' : '\033';
+             temp[1] = '\0';
              goto add_string;
 
            default:
-             temp = savestring ("\\ ");
+             temp = xmalloc (3);
+             temp[0] = '\\';
              temp[1] = c;
+             temp[2] = '\0';
 
            add_string:
              if (c)
                string++;
              result =
                sub_append_string (temp, result, &result_index, &result_size);
-             temp = (char *)NULL; /* Free ()'ed in sub_append_string (). */
+             temp = (char *)NULL; /* Freed in sub_append_string (). */
              result[result_index] = '\0';
              break;
            }
        }
       else
        {
-         while (3 + result_index > result_size)
-           result = xrealloc (result, result_size += PROMPT_GROWTH);
-
+         RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, PROMPT_GROWTH);
          result[result_index++] = c;
          result[result_index] = '\0';
        }
@@ -4019,22 +4343,42 @@ decode_prompt_string (string)
   result = savestring (string);
 #endif /* !PROMPT_STRING_DECODE */
 
+  /* Save the delimiter stack and point `dstack' to temp space so any
+     command substitutions in the prompt string won't result in screwing
+     up the parser's quoting state. */
+  save_dstack = dstack;
+  dstack = temp_dstack;
+  dstack.delimiter_depth = 0;
+
   /* Perform variable and parameter expansion and command substitution on
      the prompt string. */
-  list = expand_string_unsplit (result, 1);
-  free (result);
-  result = string_list (list);
-  dispose_words (list);
+  if (promptvars || posixly_correct)
+    {
+      list = expand_string_unsplit (result, Q_DOUBLE_QUOTES);
+      free (result);
+      result = string_list (list);
+      dispose_words (list);
+    }
+  else
+    {
+      t = dequote_string (result);
+      free (result);
+      result = t;
+    }
+
+  dstack = save_dstack;
 
   return (result);
 }
 
 /* Report a syntax error, and restart the parser.  Call here for fatal
    errors. */
+int
 yyerror ()
 {
   report_syntax_error ((char *)NULL);
   reset_parser ();
+  return (0);
 }
 
 /* Report a syntax error with line numbers, etc.
@@ -4045,96 +4389,85 @@ static void
 report_syntax_error (message)
      char *message;
 {
+  char *msg, *t;
+  int token_end, i;
+  char msg2[2];
+
   if (message)
     {
-      if (!interactive)
-       {
-         char *name = bash_input.name ? bash_input.name : "stdin";
-         report_error ("%s: line %d: `%s'", name, line_number, message);
-       }
-      else
-       {
-         if (EOF_Reached)
-           EOF_Reached = 0;
-         report_error ("%s", message);
-       }
-
+      parser_error (line_number, "%s", message);
+      if (interactive && EOF_Reached)
+       EOF_Reached = 0;
       last_command_exit_value = EX_USAGE;
       return;
     }
 
+  /* If the line of input we're reading is not null, try to find the
+     objectionable token. */
   if (shell_input_line && *shell_input_line)
     {
-      char *t = shell_input_line;
-      register int i = shell_input_line_index;
-      int token_end = 0;
+      t = shell_input_line;
+      i = shell_input_line_index;
+      token_end = 0;
 
-      if (!t[i] && i)
+      if (i && t[i] == '\0')
        i--;
 
-      while (i && (t[i] == ' ' || t[i] == '\t' || t[i] == '\n'))
+      while (i && (whitespace (t[i]) || t[i] == '\n'))
        i--;
 
       if (i)
        token_end = i + 1;
 
-      while (i && !member (t[i], " \n\t;|&"))
+      while (i && (member (t[i], " \n\t;|&") == 0))
        i--;
 
-      while (i != token_end && member (t[i], " \t\n"))
+      while (i != token_end && (whitespace (t[i]) || t[i] == '\n'))
        i++;
 
-      if (token_end)
+      /* Print the offending token. */
+      if (token_end || (i == 0 && token_end == 0))
        {
-         char *error_token;
-         error_token = xmalloc (1 + (token_end - i));
-         strncpy (error_token, t + i, token_end - i);
-         error_token[token_end - i] = '\0';
+         if (token_end)
+           {
+             msg = xmalloc (1 + (token_end - i));
+             strncpy (msg, t + i, token_end - i);
+             msg[token_end - i] = '\0';
+           }
+         else  /* one-character token */
+           {
+             msg2[0] = t[i];
+             msg2[1] = '\0';
+             msg = msg2;
+           }
 
-         report_error ("syntax error near unexpected token `%s'", error_token);
-         free (error_token);
-       }
-      else if ((i == 0) && (token_end == 0))   /* a 1-character token */
-       {
-         char etoken[2];
-         etoken[0] = t[i];
-         etoken[1] = '\0';
+         parser_error (line_number, "syntax error near unexpected token `%s'", msg);
 
-         report_error ("syntax error near unexpected token `%s'", etoken);
+         if (msg != msg2)
+           free (msg);
        }
 
-      if (!interactive)
+      /* If not interactive, print the line containing the error. */
+      if (interactive == 0)
        {
-         char *temp = savestring (shell_input_line);
-         char *name = bash_input.name ? bash_input.name : "stdin";
-         int l = strlen (temp);
-
-         while (l && temp[l - 1] == '\n')
-           temp[--l] = '\0';
+         msg = savestring (shell_input_line);
+         token_end = strlen (msg);
+         while (token_end && msg[token_end - 1] == '\n')
+           msg[--token_end] = '\0';
 
-         report_error ("%s: line %d: `%s'", name, line_number, temp);
-         free (temp);
+         parser_error (line_number, "`%s'", msg);
+         free (msg);
        }
     }
   else
     {
-      char *name, *msg;
-      if (!interactive)
-       name = bash_input.name ? bash_input.name : "stdin";
-      if (EOF_Reached)
-       msg = "syntax error: unexpected end of file";
-      else
-       msg = "syntax error";
-      if (!interactive)
-       report_error ("%s: line %d: %s", name, line_number, msg);
-      else
-       {
-         /* This file uses EOF_Reached only for error reporting
-            when the shell is interactive.  Other mechanisms are 
-            used to decide whether or not to exit. */
-         EOF_Reached = 0;
-         report_error (msg);
-       }
+      msg = EOF_Reached ? "syntax error: unexpected end of file" : "syntax error";
+      parser_error (line_number, "%s", msg);
+      /* When the shell is interactive, this file uses EOF_Reached
+        only for error reporting.  Other mechanisms are used to
+        decide whether or not to exit. */
+      if (interactive && EOF_Reached)
+       EOF_Reached = 0;
     }
   last_command_exit_value = EX_USAGE;
 }
@@ -4144,11 +4477,12 @@ report_syntax_error (message)
    allocated objects to the memory pool.  In the case of no error, we want
    to throw away the information about where the allocated objects live.
    (dispose_command () will actually free the command. */
+static void
 discard_parser_constructs (error_p)
      int error_p;
 {
 }
-   
+
 /* Do that silly `type "bye" to exit' stuff.  You know, "ignoreeof". */
 
 /* A flag denoting whether or not ignoreeof is set. */
@@ -4190,7 +4524,7 @@ handle_eof_input_unit ()
              prompt_again ();
              last_read_token = current_token = '\n';
              return;
-           } 
+           }
        }
 
       /* In this case EOF should exit the shell.  Do it now. */