<listitem>
      <para>
       Null values are represented by <literal>_null_</literal>.
+      (Note that there is no way to create a value that is just that
+      string.)
      </para>
     </listitem>
 
 
    <varlistentry>
     <term>
-     <literal>close</literal> <optional><replaceable class="parameter">tablename</replaceable></optional>
+     <literal>close</literal> <replaceable class="parameter">tablename</replaceable>
     </term>
 
     <listitem>
      <para>
-      Close the open table.  The name of the table can be given as a
-      cross-check, but this is not required.
+      Close the open table.  The name of the table must be given as a
+      cross-check.
      </para>
     </listitem>
    </varlistentry>
 
      <para>
       NULL values can be specified using the special key word
-      <literal>_null_</literal>.  Values containing spaces must be
-      double quoted.
+      <literal>_null_</literal>.  Values that do not look like
+      identifiers or digit strings must be double quoted.
      </para>
     </listitem>
    </varlistentry>
 
    List        *list;
    IndexElem   *ielem;
    char        *str;
+   const char  *kw;
    int         ival;
    Oid         oidval;
 }
 %type <oidval> oidspec optoideq optrowtypeoid
 
 %token <str> ID
-%token OPEN XCLOSE XCREATE INSERT_TUPLE
-%token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
 %token COMMA EQUALS LPAREN RPAREN
-%token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID NULLVAL
-%token XFORCE XNOT XNULL
+/* NULLVAL is a reserved keyword */
+%token NULLVAL
+/* All the rest are unreserved, and should be handled in boot_ident! */
+%token <kw> OPEN XCLOSE XCREATE INSERT_TUPLE
+%token <kw> XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
+%token <kw> OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID
+%token <kw> XFORCE XNOT XNULL
 
 %start TopLevel
 
-%nonassoc low
-%nonassoc high
-
 %%
 
 TopLevel:
        ;
 
 Boot_CloseStmt:
-         XCLOSE boot_ident %prec low
+         XCLOSE boot_ident
                {
                    do_start();
                    closerel($2);
                    do_end();
                }
-       | XCLOSE %prec high
-               {
-                   do_start();
-                   closerel(NULL);
-                   do_end();
-               }
        ;
 
 Boot_CreateStmt:
            { InsertOneNull(num_columns_read++); }
        ;
 
-boot_ident :
-         ID    { $$ = yylval.str; }
+boot_ident:
+         ID            { $$ = $1; }
+       | OPEN          { $$ = pstrdup($1); }
+       | XCLOSE        { $$ = pstrdup($1); }
+       | XCREATE       { $$ = pstrdup($1); }
+       | INSERT_TUPLE  { $$ = pstrdup($1); }
+       | XDECLARE      { $$ = pstrdup($1); }
+       | INDEX         { $$ = pstrdup($1); }
+       | ON            { $$ = pstrdup($1); }
+       | USING         { $$ = pstrdup($1); }
+       | XBUILD        { $$ = pstrdup($1); }
+       | INDICES       { $$ = pstrdup($1); }
+       | UNIQUE        { $$ = pstrdup($1); }
+       | XTOAST        { $$ = pstrdup($1); }
+       | OBJ_ID        { $$ = pstrdup($1); }
+       | XBOOTSTRAP    { $$ = pstrdup($1); }
+       | XSHARED_RELATION  { $$ = pstrdup($1); }
+       | XWITHOUT_OIDS { $$ = pstrdup($1); }
+       | XROWTYPE_OID  { $$ = pstrdup($1); }
+       | XFORCE        { $$ = pstrdup($1); }
+       | XNOT          { $$ = pstrdup($1); }
+       | XNULL         { $$ = pstrdup($1); }
        ;
 %%
 
 
 id     [-A-Za-z0-9_]+
 sid        \"([^\"])*\"
 
+/*
+ * Keyword tokens return the keyword text (as a constant string) in yylval.kw,
+ * just in case that's needed because we want to treat the keyword as an
+ * unreserved identifier.  Note that _null_ is not treated as a keyword
+ * for this purpose; it's the one "reserved word" in the bootstrap syntax.
+ *
+ * Notice that all the keywords are case-sensitive, and for historical
+ * reasons some must be upper case.
+ *
+ * String tokens return a palloc'd string in yylval.str.
+ */
+
 %%
 
-open           { return OPEN; }
+open           { yylval.kw = "open"; return OPEN; }
 
-close          { return XCLOSE; }
+close          { yylval.kw = "close"; return XCLOSE; }
 
-create         { return XCREATE; }
+create         { yylval.kw = "create"; return XCREATE; }
 
-OID                { return OBJ_ID; }
-bootstrap      { return XBOOTSTRAP; }
-"shared_relation"  { return XSHARED_RELATION; }
-"without_oids" { return XWITHOUT_OIDS; }
-"rowtype_oid"  { return XROWTYPE_OID; }
-_null_         { return NULLVAL; }
+OID                { yylval.kw = "OID"; return OBJ_ID; }
+bootstrap      { yylval.kw = "bootstrap"; return XBOOTSTRAP; }
+shared_relation    { yylval.kw = "shared_relation"; return XSHARED_RELATION; }
+without_oids   { yylval.kw = "without_oids"; return XWITHOUT_OIDS; }
+rowtype_oid        { yylval.kw = "rowtype_oid"; return XROWTYPE_OID; }
+
+insert         { yylval.kw = "insert"; return INSERT_TUPLE; }
 
-insert         { return INSERT_TUPLE; }
+_null_         { return NULLVAL; }
 
 ","                { return COMMA; }
 "="                { return EQUALS; }
 ")"                { return RPAREN; }
 
 [\n]           { yyline++; }
-[\t]           ;
-" "                ;
-
-^\#[^\n]* ; /* drop everything after "#" for comments */
-
-
-"declare"      { return XDECLARE; }
-"build"            { return XBUILD; }
-"indices"      { return INDICES; }
-"unique"       { return UNIQUE; }
-"index"            { return INDEX; }
-"on"           { return ON; }
-"using"            { return USING; }
-"toast"            { return XTOAST; }
-"FORCE"            { return XFORCE; }
-"NOT"          { return XNOT; }
-"NULL"         { return XNULL; }
+[\r\t ]            ;
+
+^\#[^\n]*      ;       /* drop everything after "#" for comments */
+
+declare            { yylval.kw = "declare"; return XDECLARE; }
+build          { yylval.kw = "build"; return XBUILD; }
+indices            { yylval.kw = "indices"; return INDICES; }
+unique         { yylval.kw = "unique"; return UNIQUE; }
+index          { yylval.kw = "index"; return INDEX; }
+on             { yylval.kw = "on"; return ON; }
+using          { yylval.kw = "using"; return USING; }
+toast          { yylval.kw = "toast"; return XTOAST; }
+FORCE          { yylval.kw = "FORCE"; return XFORCE; }
+NOT                { yylval.kw = "NOT"; return XNOT; }
+NULL           { yylval.kw = "NULL"; return XNULL; }
 
 {id}           {
                    yylval.str = scanstr(yytext);
                    return ID;
                }
 {sid}          {
-                   yytext[strlen(yytext)-1] = '\0'; /* strip off quotes */
+                   /* leading and trailing quotes are not passed to scanstr */
+                   yytext[strlen(yytext) - 1] = '\0';
                    yylval.str = scanstr(yytext+1);
-                   yytext[strlen(yytext)] = '"'; /* restore quotes */
+                   yytext[strlen(yytext)] = '"';   /* restore yytext */
                    return ID;
                }
 
                    elog(ERROR, "syntax error at line %d: unexpected character \"%s\"", yyline, yytext);
                }
 
-
-
 %%
 
 /* LCOV_EXCL_STOP */