BSD 4_4 release
[unix-history] / usr / src / old / dbx / commands.y
index e8d8a48..9b48a61 100644 (file)
@@ -1,8 +1,41 @@
 %{
 
 %{
 
-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 
-static char sccsid[] = "@(#)commands.y 1.3 %G%";
+#ifndef lint
+static char sccsid[] = "@(#)commands.y 5.6 (Berkeley) 6/1/90";
+#endif /* not lint */
 
 /*
  * Yacc grammar for debugger commands.
 
 /*
  * Yacc grammar for debugger commands.
@@ -15,21 +48,23 @@ static char sccsid[] = "@(#)commands.y 1.3 %G%";
 #include "process.h"
 #include "source.h"
 #include "scanner.h"
 #include "process.h"
 #include "source.h"
 #include "scanner.h"
+#include "keywords.h"
 #include "names.h"
 #include "names.h"
+#include "lists.h"
 
 private String curformat = "X";
 
 %}
 
 %term
 
 private String curformat = "X";
 
 %}
 
 %term
-    ALIAS AND ASSIGN AT CALL CATCH CONT DELETE DIV DUMP
+    ALIAS AND ASSIGN AT CALL CATCH CONT DEBUG DELETE DIV DOWN DUMP
     EDIT FILE FUNC GRIPE HELP IF IGNORE IN LIST MOD NEXT NEXTI NIL NOT OR
     EDIT FILE FUNC GRIPE HELP IF IGNORE IN LIST MOD NEXT NEXTI NIL NOT OR
-    PRINT PSYM QUIT RUN SH SKIP SOURCE STATUS STEP STEPI
-    STOP STOPI TRACE TRACEI
-    USE WHATIS WHEN WHERE WHEREIS WHICH
+    PRINT PSYM QUIT RERUN RETURN RUN SET SH SKIP SOURCE STATUS STEP STEPI
+    STOP STOPI TRACE TRACEI UNALIAS UNSET UP USE
+    WHATIS WHEN WHERE WHEREIS WHICH
 
 
-%term INT REAL NAME STRING
-%term LFORMER RFORMER ABSTRACTION ARROW
+%term INT CHAR REAL NAME STRING
+%term ARROW
 
 %right INT
 %binary REDIRECT
 
 %right INT
 %binary REDIRECT
@@ -37,8 +72,8 @@ private String curformat = "X";
 %left '+' '-' OR
 %left UNARYSIGN
 %left '*' '/' DIV MOD AND
 %left '+' '-' OR
 %left UNARYSIGN
 %left '*' '/' DIV MOD AND
-%left NOT '(' '[' '.' '^' ARROW
 %left '\\'
 %left '\\'
+%left NOT '(' '[' '.' '^' ARROW
 
 %union {
     Name y_name;
 
 %union {
     Name y_name;
@@ -47,29 +82,34 @@ private String curformat = "X";
     Integer y_int;
     Operator y_op;
     long y_long;
     Integer y_int;
     Operator y_op;
     long y_long;
+    char y_char;
     double y_real;
     String y_string;
     Boolean y_bool;
     Cmdlist y_cmdlist;
     double y_real;
     String y_string;
     Boolean y_bool;
     Cmdlist y_cmdlist;
+    List y_list;
 };
 
 %type <y_op>       trace stop
 };
 
 %type <y_op>       trace stop
-%type <y_long>     INT count
+%type <y_long>     INT count signal
+%type <y_char>     CHAR
 %type <y_real>     REAL
 %type <y_string>    STRING redirectout filename opt_filename mode
 %type <y_real>     REAL
 %type <y_string>    STRING redirectout filename opt_filename mode
-%type <y_name>     ALIAS AND ASSIGN AT CALL CATCH CONT DELETE DIV DUMP
+%type <y_name>     ALIAS AND ASSIGN AT CALL CATCH CONT
+%type <y_name>     DEBUG DELETE DIV DOWN DUMP
 %type <y_name>     EDIT FILE FUNC GRIPE HELP IF IGNORE IN LIST MOD
 %type <y_name>     NEXT NEXTI NIL NOT OR
 %type <y_name>     EDIT FILE FUNC GRIPE HELP IF IGNORE IN LIST MOD
 %type <y_name>     NEXT NEXTI NIL NOT OR
-%type <y_name>     PRINT PSYM QUIT RUN SH SKIP SOURCE STATUS STEP STEPI
-%type <y_name>     STOP STOPI TRACE TRACEI
-%type <y_name>     USE WHATIS WHEN WHERE WHEREIS WHICH
+%type <y_name>     PRINT PSYM QUIT RERUN RETURN RUN SET SH SKIP SOURCE STATUS
+%type <y_name>     STEP STEPI STOP STOPI TRACE TRACEI
+%type <y_name>     UNALIAS UNSET UP USE WHATIS WHEN WHERE WHEREIS WHICH
 %type <y_name>     name NAME keyword
 %type <y_name>     name NAME keyword
-%type <y_node>      symbol
+%type <y_node>      opt_qual_symbol symbol
 %type <y_node>     command rcommand cmd step what where examine
 %type <y_node>     command rcommand cmd step what where examine
-%type <y_node>     event opt_arglist opt_cond
+%type <y_node>     event opt_exp_list opt_cond
 %type <y_node>     exp_list exp term boolean_exp constant address
 %type <y_node>     exp_list exp term boolean_exp constant address
-%type <y_node>     alias_command list_command line_number
+%type <y_node>     integer_list alias_command list_command line_number
 %type <y_cmdlist>   actions
 %type <y_cmdlist>   actions
+%type <y_list>      sourcepath name_list
 
 %%
 
 
 %%
 
@@ -82,6 +122,9 @@ command_nl:
     command_line '\n'
 |
     command_line ';'
     command_line '\n'
 |
     command_line ';'
+{
+       chkalias = true;
+}
 |
     '\n'
 ;
 |
     '\n'
 ;
@@ -90,7 +133,7 @@ command_line:
     command
 {
        if ($1 != nil) {
     command
 {
        if ($1 != nil) {
-           eval($1);
+           topeval($1);
        }
 }
 |
        }
 }
 |
@@ -99,10 +142,10 @@ command_line:
        if ($1 != nil) {
            if ($2 != nil) {
                setout($2);
        if ($1 != nil) {
            if ($2 != nil) {
                setout($2);
-               eval($1);
+               topeval($1);
                unsetout();
            } else {
                unsetout();
            } else {
-               eval($1);
+               topeval($1);
            }
        }
 }
            }
        }
 }
@@ -128,25 +171,45 @@ command:
        $$ = $1;
 }
 |
        $$ = $1;
 }
 |
-    ASSIGN term '=' exp
+    ASSIGN exp '=' exp
 {
 {
-       $$ = build(O_ASSIGN, $2, $4);
+       $$ = build(O_ASSIGN, unrval($2), $4);
 }
 |
 }
 |
-    CATCH INT
+    CATCH signal
 {
        $$ = build(O_CATCH, $2);
 }
 {
        $$ = build(O_CATCH, $2);
 }
+|
+    CATCH
+{
+       $$ = build(O_CATCH, 0);
+}
 |
     CONT
 {
 |
     CONT
 {
-       $$ = build(O_CONT);
+       $$ = build(O_CONT, (long) DEFSIG);
+}
+|
+    CONT signal
+{
+       $$ = build(O_CONT, $2);
 }
 |
 }
 |
-    DELETE INT
+    DELETE integer_list
 {
        $$ = build(O_DELETE, $2);
 }
 {
        $$ = build(O_DELETE, $2);
 }
+|
+    DOWN
+{
+       $$ = build(O_DOWN, build(O_LCON, (long) 1));
+}
+|
+    DOWN INT
+{
+       $$ = build(O_DOWN, build(O_LCON, (long) $2));
+}
 |
     EDIT shellmode opt_filename
 {
 |
     EDIT shellmode opt_filename
 {
@@ -163,7 +226,7 @@ command:
        $$ = build(O_FUNC, nil);
 }
 |
        $$ = build(O_FUNC, nil);
 }
 |
-    FUNC symbol
+    FUNC opt_qual_symbol
 {
        $$ = build(O_FUNC, $2);
 }
 {
        $$ = build(O_FUNC, $2);
 }
@@ -178,19 +241,24 @@ command:
        $$ = build(O_HELP);
 }
 |
        $$ = build(O_HELP);
 }
 |
-    IGNORE INT
+    IGNORE signal
 {
        $$ = build(O_IGNORE, $2);
 }
 {
        $$ = build(O_IGNORE, $2);
 }
+|
+    IGNORE
+{
+       $$ = build(O_IGNORE, 0);
+}
 |
     list_command
 {
        $$ = $1;
 }
 |
 |
     list_command
 {
        $$ = $1;
 }
 |
-    PSYM term
+    PSYM exp
 {
 {
-       $$ = build(O_PSYM, $2);
+       $$ = build(O_PSYM, unrval($2));
 }
 |
     QUIT
 }
 |
     QUIT
@@ -201,12 +269,37 @@ command:
            $$ = nil;
        }
 }
            $$ = nil;
        }
 }
+|
+    RETURN
+{
+       $$ = build(O_RETURN, nil);
+}
+|
+    RETURN opt_qual_symbol
+{
+       $$ = build(O_RETURN, $2);
+}
 |
     runcommand
 {
        run();
        /* NOTREACHED */
 }
 |
     runcommand
 {
        run();
        /* NOTREACHED */
 }
+|
+    SET name '=' exp
+{
+       $$ = build(O_SET, build(O_NAME, $2), $4);
+}
+|
+    SET name
+{
+       $$ = build(O_SET, build(O_NAME, $2), nil);
+}
+|
+    SET
+{
+       $$ = build(O_SET, nil, nil);
+}
 |
     SH
 {
 |
     SH
 {
@@ -259,7 +352,45 @@ command:
        $$ = build($1, nil, nil, $2);
 }
 |
        $$ = build($1, nil, nil, $2);
 }
 |
-    WHATIS term
+    UNALIAS name
+{
+       $$ = build(O_UNALIAS, build(O_NAME, $2));
+}
+|
+    UNSET name
+{
+       $$ = build(O_UNSET, build(O_NAME, $2));
+}
+|
+    UP
+{
+       $$ = build(O_UP, build(O_LCON, (long) 1));
+}
+|
+    UP INT
+{
+       $$ = build(O_UP, build(O_LCON, (long) $2));
+}
+|
+    USE shellmode sourcepath
+{
+       String dir;
+
+       $$ = nil;
+       if (list_size($3) == 0) {
+           foreach (String, dir, sourcepath)
+               printf("%s ", dir);
+           endfor
+           printf("\n");
+       } else {
+           foreach (String, dir, sourcepath)
+               list_delete(list_curitem(sourcepath), sourcepath);
+           endfor
+           sourcepath = $3;
+       }
+}
+|
+    WHATIS opt_qual_symbol
 {
        $$ = build(O_WHATIS, $2);
 }
 {
        $$ = build(O_WHATIS, $2);
 }
@@ -269,9 +400,9 @@ command:
        $$ = build(O_ADDEVENT, $2, $4);
 }
 |
        $$ = build(O_ADDEVENT, $2, $4);
 }
 |
-    WHEREIS symbol
+    WHEREIS name
 {
 {
-       $$ = build(O_WHEREIS, $2);
+       $$ = build(O_WHEREIS, build(O_SYM, lookup($2)));
 }
 |
     WHICH symbol
 }
 |
     WHICH symbol
@@ -279,34 +410,69 @@ command:
        $$ = build(O_WHICH, $2);
 }
 |
        $$ = build(O_WHICH, $2);
 }
 |
-    USE shellmode sourcepath
+    '/'
 {
 {
-       $$ = nil;
-       if (list_size(sourcepath) == 0) {
-           list_append(list_item("."), nil, sourcepath);
-       }
+       $$ = build(O_SEARCH,
+           build(O_LCON, (long) '/'),
+           build(O_SCON, strdup(scanner_linebuf))
+       );
+       gobble();
+       insertinput("\n");
+}
+|
+    '?'
+{
+       $$ = build(O_SEARCH,
+           build(O_LCON, (long) '?'),
+           build(O_SCON, strdup(scanner_linebuf))
+       );
+       gobble();
+       insertinput("\n");
+}
+;
+signal:
+    INT
+{
+       $$ = $1;
+}
+|
+    name
+{
+       $$ = siglookup(ident($1));
 }
 ;
 runcommand:
 }
 ;
 runcommand:
-    run shellmode arglist
+    run arglist
+|
+    run
 ;
 run:
 ;
 run:
-    RUN
+    RUN shellmode
 {
 {
-       fflush(stdout);
        arginit();
        arginit();
+       fflush(stdout);
+}
+|
+    RERUN shellmode
+{
+       fflush(stdout);
 }
 ;
 arglist:
     arglist arg
 |
 }
 ;
 arglist:
     arglist arg
 |
-    /* empty */
+    arg
 ;
 arg:
     NAME
 {
        newarg(ident($1));
 }
 ;
 arg:
     NAME
 {
        newarg(ident($1));
 }
+|
+    STRING
+{
+       newarg($1);
+}
 |
     '<' NAME
 {
 |
     '<' NAME
 {
@@ -348,16 +514,13 @@ shellmode:
 sourcepath:
     sourcepath NAME
 {
 sourcepath:
     sourcepath NAME
 {
-       list_append(list_item(ident($2)), nil, sourcepath);
+       $$ = $1;
+       list_append(list_item(ident($2)), nil, $$);
 }
 |
     /* empty */
 {
 }
 |
     /* empty */
 {
-       String dir;
-
-       foreach (String, dir, sourcepath)
-           list_delete(list_curitem(sourcepath), sourcepath);
-       endfor
+       $$ = list_alloc();
 }
 ;
 event:
 }
 ;
 event:
@@ -403,14 +566,34 @@ rcommand:
        $$ = $1;
 }
 |
        $$ = $1;
 }
 |
-    CALL term
+    CALL term '(' opt_exp_list ')'
 {
 {
-       $$ = $2;
+       $$ = build(O_CALLPROC, $2, $4);
+}
+|
+    DEBUG INT
+{
+       $$ = build(O_DEBUG, $2);
+}
+|
+    DEBUG '-' INT
+{
+       $$ = build(O_DEBUG, -$3);
+}
+|
+    DUMP opt_qual_symbol
+{
+       $$ = build(O_DUMP, $2);
+}
+|
+    DUMP '.'
+{
+       $$ = build(O_DUMP, nil);
 }
 |
     DUMP
 {
 }
 |
     DUMP
 {
-       $$ = build(O_DUMP);
+       $$ = build(O_DUMP, build(O_SYM, curfunc));
 }
 |
     STATUS
 }
 |
     STATUS
@@ -423,6 +606,19 @@ alias_command:
 {
        $$ = build(O_ALIAS, build(O_NAME, $2), build(O_NAME, $3));
 }
 {
        $$ = build(O_ALIAS, build(O_NAME, $2), build(O_NAME, $3));
 }
+|
+    ALIAS name STRING
+{
+       $$ = build(O_ALIAS, build(O_NAME, $2), build(O_SCON, $3));
+}
+|
+    ALIAS name '(' name_list ')' STRING
+{
+       $$ = build(O_ALIAS,
+           build(O_COMMA, build(O_NAME, $2), (Node) $4),
+           build(O_SCON, $6)
+       );
+}
 |
     ALIAS name
 {
 |
     ALIAS name
 {
@@ -434,6 +630,19 @@ alias_command:
        $$ = build(O_ALIAS, nil, nil);
 }
 ;
        $$ = build(O_ALIAS, nil, nil);
 }
 ;
+name_list:
+    name_list ',' name
+{
+       $$ = $1;
+       list_append(list_item($3), nil, $$);
+}
+|
+    name
+{
+       $$ = list_alloc();
+       list_append(list_item($1), nil, $$);
+}
+;
 trace:
     TRACE
 {
 trace:
     TRACE
 {
@@ -468,14 +677,14 @@ what:
 }
 ;
 where:
 }
 ;
 where:
-    IN term
+    IN exp
 {
 {
-       $$ = $2;
+       $$ = unrval($2);
 }
 |
     AT line_number
 {
 }
 |
     AT line_number
 {
-       $$ = build(O_QLINE, build(O_SCON, cursource), $2);
+       $$ = build(O_QLINE, build(O_SCON, strdup(cursource)), $2);
 }
 |
     AT STRING ':' line_number
 }
 |
     AT STRING ':' line_number
@@ -500,15 +709,15 @@ opt_filename:
        $$ = $1;
 }
 ;
        $$ = $1;
 }
 ;
-opt_arglist:
-    /* empty */
+opt_exp_list:
+    exp_list
 {
 {
-       $$ = nil;
+       $$ = $1;
 }
 |
 }
 |
-    '(' exp_list ')'
+    /* empty */
 {
 {
-       $$ = $2;
+       $$ = nil;
 }
 ;
 list_command:
 }
 ;
 list_command:
@@ -516,7 +725,7 @@ list_command:
 {
        $$ = build(O_LIST,
            build(O_LCON, (long) cursrcline),
 {
        $$ = build(O_LIST,
            build(O_LCON, (long) cursrcline),
-           build(O_LCON, (long) cursrcline + 9)
+           build(O_LCON, (long) cursrcline + srcwindowlen() - 1)
        );
 }
 |
        );
 }
 |
@@ -530,9 +739,20 @@ list_command:
        $$ = build(O_LIST, $2, $4);
 }
 |
        $$ = build(O_LIST, $2, $4);
 }
 |
-    LIST symbol
+    LIST opt_qual_symbol
+{
+       $$ = build(O_LIST, $2, $2);
+}
+;
+integer_list:
+    INT
+{
+       $$ = build(O_LCON, $1);
+}
+|
+    INT integer_list
 {
 {
-       $$ = build(O_LIST, $2);
+       $$ = build(O_COMMA, build(O_LCON, $1), $2);
 }
 ;
 line_number:
 }
 ;
 line_number:
@@ -556,11 +776,6 @@ examine:
 {
        $$ = build(O_EXAMINE, $5, $1, $3, 0);
 }
 {
        $$ = build(O_EXAMINE, $5, $1, $3, 0);
 }
-|
-    '/' count mode
-{
-       $$ = build(O_EXAMINE, $3, build(O_LCON, (long) prtaddr), nil, $2);
-}
 |
     address '=' mode
 {
 |
     address '=' mode
 {
@@ -572,6 +787,11 @@ address:
 {
        $$ = build(O_LCON, $1);
 }
 {
        $$ = build(O_LCON, $1);
 }
+|
+    '.'
+{
+       $$ = build(O_LCON, (long) prtaddr);
+}
 |
     '&' term
 {
 |
     '&' term
 {
@@ -597,12 +817,38 @@ address:
 {
        $$ = build(O_INDIR, $2);
 }
 {
        $$ = build(O_INDIR, $2);
 }
+|
+    '-' address %prec UNARYSIGN
+{
+       $$ = build(O_NEG, $2);
+}
 |
     '(' exp ')'
 {
        $$ = $2;
 }
 ;
 |
     '(' exp ')'
 {
        $$ = $2;
 }
 ;
+term:
+    symbol
+{
+       $$ = $1;
+}
+|
+    term '.' name
+{
+       $$ = unrval(dot($1, $3));
+}
+|
+    term ARROW name
+{
+       $$ = unrval(dot($1, $3));
+}
+|
+    term '[' exp_list ']'
+{
+       $$ = unrval(subscript($1, $3));
+}
+;
 count:
     /* empty */
 {
 count:
     /* empty */
 {
@@ -649,20 +895,55 @@ exp_list:
 }
 ;
 exp:
 }
 ;
 exp:
-    term
+    symbol
 {
        $$ = build(O_RVAL, $1);
 }
 |
 {
        $$ = build(O_RVAL, $1);
 }
 |
-    constant
+    exp '[' exp_list ']'
 {
 {
-       $$ = $1;
+       $$ = subscript(unrval($1), $3);
+}
+|
+    exp '.' name
+{
+       $$ = dot($1, $3);
 }
 |
 }
 |
-    exp '\\' symbol
+    exp ARROW name
+{
+       $$ = dot($1, $3);
+}
+|
+    '*' exp %prec UNARYSIGN
+{
+       $$ = build(O_INDIR, $2);
+}
+|
+    exp '^' %prec UNARYSIGN
+{
+       $$ = build(O_INDIR, $1);
+}
+|
+    exp '\\' opt_qual_symbol
 {
        $$ = build(O_TYPERENAME, $1, $3);
 }
 {
        $$ = build(O_TYPERENAME, $1, $3);
 }
+|
+    exp '\\' '&' opt_qual_symbol %prec '\\'
+{
+       $$ = renameptr($1, $4);
+}
+|
+    exp '(' opt_exp_list ')'
+{
+       $$ = build(O_CALL, unrval($1), $3);
+}
+|
+    constant
+{
+       $$ = $1;
+}
 |
     '+' exp %prec UNARYSIGN
 {
 |
     '+' exp %prec UNARYSIGN
 {
@@ -764,52 +1045,6 @@ exp:
        $$ = $2;
 }
 ;
        $$ = $2;
 }
 ;
-term:
-    symbol
-{
-       $$ = $1;
-}
-|
-    term '[' exp_list ']'
-{
-       $$ = subscript($1, $3);
-}
-|
-    term '.' name
-{
-       $$ = dot($1, $3);
-}
-|
-    term ARROW name
-{
-       $$ = dot($1, $3);
-}
-|
-    '*' term %prec UNARYSIGN
-{
-       $$ = build(O_INDIR, $2);
-}
-|
-    '*' '(' exp ')' %prec UNARYSIGN
-{
-       $$ = build(O_INDIR, $3);
-}
-|
-    term '^' %prec UNARYSIGN
-{
-       $$ = build(O_INDIR, $1);
-}
-|
-    '#' term %prec UNARYSIGN
-{
-       $$ = concrete($2);
-}
-|
-    term '(' exp_list ')'
-{
-       $$ = build(O_CALL, $1, $3);
-}
-;
 boolean_exp:
     exp
 {
 boolean_exp:
     exp
 {
@@ -822,6 +1057,11 @@ constant:
 {
        $$ = build(O_LCON, $1);
 }
 {
        $$ = build(O_LCON, $1);
 }
+|
+    CHAR
+{
+       $$ = build(O_CCON, $1);
+}
 |
     REAL
 {
 |
     REAL
 {
@@ -833,10 +1073,29 @@ constant:
        $$ = build(O_SCON, $1);
 }
 ;
        $$ = build(O_SCON, $1);
 }
 ;
+opt_qual_symbol:
+    symbol
+{
+       $$ = $1;
+}
+|
+    opt_qual_symbol '.' name
+{
+       $$ = dot($1, $3);
+}
+;
 symbol:
     name
 {
 symbol:
     name
 {
-       $$ = build(O_SYM, which($1));
+       $$ = findvar($1);
+       if ($$ == nil) {
+           $$ = build(O_SYM, which($1));
+       }
+}
+|
+    '.' name
+{
+       $$ = dot(build(O_SYM, program), $2);
 }
 ;
 name:
 }
 ;
 name:
@@ -850,10 +1109,10 @@ name:
        $$ = $1;
 }
 keyword:
        $$ = $1;
 }
 keyword:
-    ALIAS | AND | ASSIGN | AT | CALL | CATCH | CONT | DELETE | DIV | DUMP |
-    EDIT | FILE | FUNC | GRIPE | HELP | IGNORE | IN | LIST | MOD |
-    NEXT | NEXTI | NIL | NOT | OR | PRINT | PSYM | QUIT | RUN |
-    SH | SKIP | SOURCE | STATUS | STEP | STEPI |
-    STOP | STOPI | TRACE | TRACEI |
-    USE | WHATIS | WHEN | WHERE | WHICH
+    ALIAS | AND | ASSIGN | AT | CALL | CATCH | CONT | DEBUG | DELETE | DIV | 
+    DOWN | DUMP | EDIT | FILE | FUNC | GRIPE | HELP | IGNORE | IN | LIST |
+    MOD | NEXT | NEXTI | NIL | NOT | OR | PRINT | PSYM | QUIT |
+    RERUN | RETURN | RUN | SET | SH | SKIP | SOURCE | STATUS | STEP | STEPI |
+    STOP | STOPI | TRACE | TRACEI | UNALIAS | UNSET | UP | USE |
+    WHATIS | WHEN | WHERE | WHEREIS | WHICH
 ;
 ;