* defs.h (enum misc_command_type, command_control_type): Enums

for describing the command and control types.
	(struct command_line): Add new fields to keep track of the command
	type and body associated with the command.
	* top.c: Include value.h.  Delete whitespace at the end of lines.
	(build_command_line, get_command_line): New functions.
	(execute_control_command, while_command, if_command): Likewise.
	(realloc_body_list, read_next_line): Likewise.
	(recurse_read_control_structure): Likewise.
	(execute_user_command): Call execute_control_command.
	(read_command_lines): Simplify by calling read_next_line, call
	read_control_structure for "if" and "while" commands.
	(free_command_lines): Free new fields in the command structure.
	(define_command): Reset control_level to zero.
	(init_main): Install command handlers for "if" and "while" commands.
This commit is contained in:
Jeff Law 1994-09-08 05:32:34 +00:00
parent 20c9d49a4e
commit e52bfe0cc4
3 changed files with 649 additions and 97 deletions

View File

@ -1,3 +1,21 @@
Wed Sep 7 23:24:50 1994 Jeff Law (law@snake.cs.utah.edu)
* defs.h (enum misc_command_type, command_control_type): Enums
for describing the command and control types.
(struct command_line): Add new fields to keep track of the command
type and body associated with the command.
* top.c: Include value.h. Delete whitespace at the end of lines.
(build_command_line, get_command_line): New functions.
(execute_control_command, while_command, if_command): Likewise.
(realloc_body_list, read_next_line): Likewise.
(recurse_read_control_structure): Likewise.
(execute_user_command): Call execute_control_command.
(read_command_lines): Simplify by calling read_next_line, call
read_control_structure for "if" and "while" commands.
(free_command_lines): Free new fields in the command structure.
(define_command): Reset control_level to zero.
(init_main): Install command handlers for "if" and "while" commands.
Tue Sep 6 16:24:07 1994 Stan Shebs (shebs@andros.cygnus.com)
* c-typeprint.c (c_type_print_varspec_prefix,

View File

@ -97,6 +97,7 @@ enum language
language_c, /* C */
language_cplus, /* C++ */
language_chill, /* Chill */
language_fortran, /* Fortran */
language_m2, /* Modula-2 */
language_asm /* Assembly language */
};
@ -317,6 +318,26 @@ extern int read_relative_register_raw_bytes PARAMS ((int, char *));
extern char *tilde_expand PARAMS ((char *));
/* Control types for commands */
enum misc_command_type
{
ok_command,
end_command,
else_command,
nop_command,
};
enum command_control_type
{
simple_control,
break_control,
continue_control,
while_control,
if_control,
invalid_control
};
/* Structure for saved commands lines
(for breakpoints, defined commands, etc). */
@ -324,6 +345,9 @@ struct command_line
{
struct command_line *next;
char *line;
enum command_control_type control_type;
int body_count;
struct command_line **body_list;
};
extern struct command_line *read_command_lines PARAMS ((void));

704
gdb/top.c
View File

@ -28,6 +28,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "breakpoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "value.h"
#include "language.h"
#include "terminal.h" /* For job_control. */
#include "annotate.h"
@ -57,80 +58,76 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Prototypes for local functions */
static char *
symbol_completion_function PARAMS ((char *, int));
static char * symbol_completion_function PARAMS ((char *, int));
static void
command_loop_marker PARAMS ((int));
static void command_loop_marker PARAMS ((int));
static void
init_main PARAMS ((void));
static void while_command PARAMS ((char *, int));
static void
init_cmd_lists PARAMS ((void));
static void if_command PARAMS ((char *, int));
static void
float_handler PARAMS ((int));
static enum command_control_type
execute_control_command PARAMS ((struct command_line *));
static void
init_signals PARAMS ((void));
static struct command_line *
build_command_line PARAMS ((enum command_control_type, char *));
static void
set_verbose PARAMS ((char *, int, struct cmd_list_element *));
static struct command_line *
get_command_line PARAMS ((enum command_control_type, char *));
static void
show_history PARAMS ((char *, int));
static void realloc_body_list PARAMS ((struct command_line *, int));
static void
set_history PARAMS ((char *, int));
static enum misc_command_type read_next_line PARAMS ((struct command_line **));
static void
set_history_size_command PARAMS ((char *, int, struct cmd_list_element *));
static enum command_control_type
recurse_read_control_structure PARAMS ((struct command_line *));
static void
show_commands PARAMS ((char *, int));
static void init_main PARAMS ((void));
static void
echo_command PARAMS ((char *, int));
static void init_cmd_lists PARAMS ((void));
static void
pwd_command PARAMS ((char *, int));
static void float_handler PARAMS ((int));
static void
show_version PARAMS ((char *, int));
static void init_signals PARAMS ((void));
static void
document_command PARAMS ((char *, int));
static void set_verbose PARAMS ((char *, int, struct cmd_list_element *));
static void
define_command PARAMS ((char *, int));
static void show_history PARAMS ((char *, int));
static void
validate_comname PARAMS ((char *));
static void set_history PARAMS ((char *, int));
static void
help_command PARAMS ((char *, int));
static void set_history_size_command PARAMS ((char *, int,
struct cmd_list_element *));
static void
show_command PARAMS ((char *, int));
static void show_commands PARAMS ((char *, int));
static void
info_command PARAMS ((char *, int));
static void echo_command PARAMS ((char *, int));
static void
complete_command PARAMS ((char *, int));
static void pwd_command PARAMS ((char *, int));
static void
do_nothing PARAMS ((int));
static void show_version PARAMS ((char *, int));
static int
quit_cover PARAMS ((char *));
static void document_command PARAMS ((char *, int));
static void
disconnect PARAMS ((int));
static void define_command PARAMS ((char *, int));
static void
source_cleanup PARAMS ((FILE *));
static void validate_comname PARAMS ((char *));
static void help_command PARAMS ((char *, int));
static void show_command PARAMS ((char *, int));
static void info_command PARAMS ((char *, int));
static void complete_command PARAMS ((char *, int));
static void do_nothing PARAMS ((int));
static int quit_cover PARAMS ((char *));
static void disconnect PARAMS ((int));
static void source_cleanup PARAMS ((FILE *));
/* If this definition isn't overridden by the header files, assume
that isatty and fileno exist on this system. */
@ -296,6 +293,9 @@ int baud_rate = -1;
int remote_debug = 0;
/* Level of control structure. */
static int control_level;
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
#ifndef STOP_SIGNAL
@ -546,6 +546,221 @@ gdb_init ()
init_ui_hook ();
}
/* Allocate, initialize a new command line structure for one of the
control commands (if/while). */
static struct command_line *
build_command_line (type, args)
enum command_control_type type;
char *args;
{
struct command_line *cmd;
cmd = (struct command_line *)xmalloc (sizeof (struct command_line));
cmd->next = NULL;
cmd->control_type = type;
cmd->body_count = 1;
cmd->body_list
= (struct command_line **)xmalloc (sizeof (struct command_line *)
* cmd->body_count);
memset (cmd->body_list, 0, sizeof (struct command_line *) * cmd->body_count);
cmd->line = savestring (args, strlen (args));
return cmd;
}
/* Build and return a new command structure for the control commands
such as "if" and "while". */
static struct command_line *
get_command_line (type, arg)
enum command_control_type type;
char *arg;
{
struct command_line *cmd;
struct cleanup *old_chain = NULL;
/* Allocate and build a new command line structure. */
cmd = build_command_line (type, arg);
old_chain = make_cleanup (free_command_lines, &cmd);
/* Read in the body of this command. */
if (recurse_read_control_structure (cmd) == invalid_control)
{
warning ("error reading in control structure\n");
do_cleanups (old_chain);
return NULL;
}
discard_cleanups (old_chain);
return cmd;
}
/* Execute the command in CMD. */
static enum command_control_type
execute_control_command (cmd)
struct command_line *cmd;
{
struct expression *expr;
struct command_line *current;
struct cleanup *old_chain = 0;
struct cleanup *tmp_chain;
value_ptr val;
int loop;
enum command_control_type ret;
switch (cmd->control_type)
{
case simple_control:
/* A simple command, execute it and return. */
execute_command (cmd->line, 0);
return cmd->control_type;
case continue_control:
case break_control:
/* Return for "continue", and "break" so we can either
continue the loop at the top, or break out. */
return cmd->control_type;
case while_control:
{
/* Parse the loop control expression for the while statement. */
expr = parse_expression (cmd->line);
tmp_chain = make_cleanup (free_current_contents, &expr);
if (!old_chain)
old_chain = tmp_chain;
ret = simple_control;
loop = true;
/* Keep iterating so long as the expression is true. */
while (loop == true)
{
/* Evaluate the expression. */
val = evaluate_expression (expr);
/* If the value is false, then break out of the loop. */
if (!value_true (val))
break;
/* Execute the body of the while statement. */
current = *cmd->body_list;
while (current)
{
ret = execute_control_command (current);
/* If we got an error, or a "break" command, then stop
looping. */
if (ret == invalid_control || ret == break_control)
{
loop = false;
break;
}
/* If we got a "continue" command, then restart the loop
at this point. */
if (ret == continue_control)
break;
/* Get the next statement. */
current = current->next;
}
}
/* Reset RET so that we don't recurse the break all the way down. */
if (ret == break_control)
ret = simple_control;
break;
}
case if_control:
{
/* Parse the conditional for the if statement. */
expr = parse_expression (cmd->line);
old_chain = make_cleanup (free_current_contents, &expr);
current = NULL;
ret = simple_control;
/* Evaluate the conditional. */
val = evaluate_expression (expr);
/* Choose which arm to take commands from based on the value of the
conditional expression. */
if (value_true (val))
current = *cmd->body_list;
else if (cmd->body_count == 2)
current = *(cmd->body_list + 1);
/* Execute commands in the given arm. */
while (current)
{
ret = execute_control_command (current);
/* If we got an error, get out. */
if (ret != simple_control)
break;
/* Get the next statement in the body. */
current = current->next;
}
break;
}
default:
warning ("Invalid control type in command structure.");
return invalid_control;
}
if (old_chain)
do_cleanups (old_chain);
return ret;
}
/* "while" command support. Executes a body of statements while the
loop condition is nonzero. */
static void
while_command (arg, from_tty)
char *arg;
int from_tty;
{
struct command_line *command = NULL;
control_level = 1;
command = get_command_line (while_control, arg);
if (command == NULL)
return;
execute_control_command (command);
free_command_lines (&command);
}
/* "if" command support. Execute either the true or false arm depending
on the value of the if conditional. */
static void
if_command (arg, from_tty)
char *arg;
int from_tty;
{
struct command_line *command = NULL;
control_level = 1;
command = get_command_line (if_control, arg);
if (command == NULL)
return;
execute_control_command (command);
free_command_lines (&command);
}
void
execute_user_command (c, args)
struct cmd_list_element *c;
@ -553,7 +768,8 @@ execute_user_command (c, args)
{
register struct command_line *cmdlines;
struct cleanup *old_chain;
enum command_control_type ret;
if (args)
error ("User-defined commands cannot take arguments.");
@ -568,7 +784,12 @@ execute_user_command (c, args)
instream = (FILE *) 0;
while (cmdlines)
{
execute_command (cmdlines->line, 0);
ret = execute_control_command (cmdlines);
if (ret != simple_control && ret != break_control)
{
warning ("Error in control structure.\n");
break;
}
cmdlines = cmdlines->next;
}
do_cleanups (old_chain);
@ -591,12 +812,12 @@ execute_command (p, from_tty)
/* This can happen when command_line_input hits end of file. */
if (p == NULL)
return;
while (*p == ' ' || *p == '\t') p++;
if (*p)
{
char *arg;
c = lookup_cmd (&p, cmdlist, "", 0, 1);
/* Pass null arg rather than an empty one. */
arg = *p ? p : 0;
@ -696,7 +917,7 @@ dont_repeat ()
/* Read a line from the stream "instream" without command line editing.
It prints PRROMPT once at the start.
Action is compatible with "readline", e.g. space for the result is
Action is compatible with "readline", e.g. space for the result is
malloc'd and should be freed by the caller.
A NULL return means end of file. */
@ -724,7 +945,7 @@ gdb_readline (prrompt)
/* end-sanitize-mpw */
gdb_flush (gdb_stdout);
}
result = (char *) xmalloc (result_size);
while (1)
@ -1484,6 +1705,256 @@ command_line_input (prrompt, repeat, annotation_suffix)
return linebuffer;
}
/* Expand the body_list of COMMAND so that it can hold NEW_LENGTH
code bodies. This is typically used when we encounter an "else"
clause for an "if" command. */
static void
realloc_body_list (command, new_length)
struct command_line *command;
int new_length;
{
int n;
struct command_line **body_list;
n = command->body_count;
/* Nothing to do? */
if (new_length <= n)
return;
body_list = (struct command_line **)
xmalloc (sizeof (struct command_line *) * new_length);
memcpy (body_list, command->body_list, sizeof (struct command_line *) * n);
free (command->body_list);
command->body_list = body_list;
command->body_count = new_length;
}
/* Read one line from the input stream. If the command is an "else" or
"end", return such an indication to the caller. */
static enum misc_command_type
read_next_line (command)
struct command_line **command;
{
char *p, *p1, *prompt_ptr, control_prompt[256];
int i = 0;
if (control_level >= 254)
error ("Control nesting too deep!\n");
/* Set a prompt based on the nesting of the control commands. */
if (instream == stdin)
{
for (i = 0; i < control_level; i++)
control_prompt[i] = ' ';
control_prompt[i] = '>';
control_prompt[i+1] = '\0';
prompt_ptr = (char *)&control_prompt[0];
}
else
prompt_ptr = NULL;
p = command_line_input (prompt_ptr, instream == stdin, NULL);
/* Not sure what to do here. */
if (p == NULL)
return end_command;
/* Strip leading and trailing whitespace. */
while (*p == ' ' || *p == '\t')
p++;
p1 = p + strlen (p);
while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t'))
p1--;
/* Blanks and comments don't really do anything, but we need to
distinguish them from else, end and other commands which can be
executed. */
if (p1 == p || p[0] == '#')
return nop_command;
/* Is this the end of a simple, while, or if control structure? */
if (p1 - p == 3 && !strncmp (p, "end", 3))
return end_command;
/* Is the else clause of an if control structure? */
if (p1 - p == 4 && !strncmp (p, "else", 4))
return else_command;
/* Check for while, if, break, continue, etc and build a new command
line structure for them. */
if (p1 - p > 5 && !strncmp (p, "while", 5))
*command = build_command_line (while_control, p + 6);
else if (p1 - p > 2 && !strncmp (p, "if", 2))
*command = build_command_line (if_control, p + 3);
else if (p1 - p == 5 && !strncmp (p, "loop_break", 5))
{
*command = (struct command_line *)
xmalloc (sizeof (struct command_line));
(*command)->next = NULL;
(*command)->line = NULL;
(*command)->control_type = break_control;
(*command)->body_count = 0;
(*command)->body_list = NULL;
}
else if (p1 - p == 8 && !strncmp (p, "loop_continue", 8))
{
*command = (struct command_line *)
xmalloc (sizeof (struct command_line));
(*command)->next = NULL;
(*command)->line = NULL;
(*command)->control_type = continue_control;
(*command)->body_count = 0;
(*command)->body_list = NULL;
}
else
{
/* A normal command. */
*command = (struct command_line *)
xmalloc (sizeof (struct command_line));
(*command)->next = NULL;
(*command)->line = savestring (p, p1 - p);
(*command)->control_type = simple_control;
(*command)->body_count = 0;
(*command)->body_list = NULL;
}
/* Nothing special. */
return ok_command;
}
/* Recursively read in the control structures and create a command_line
tructure from them.
The parent_control parameter is the control structure in which the
following commands are nested. */
static enum command_control_type
recurse_read_control_structure (current_cmd)
struct command_line *current_cmd;
{
int current_body, i;
enum misc_command_type val;
enum command_control_type ret;
struct command_line **body_ptr, *child_tail, *next;
struct cleanup *old_chains, *tmp_chains;
old_chains = NULL;
child_tail = NULL;
current_body = 1;
/* Sanity checks. */
if (current_cmd->control_type == simple_control)
{
error ("Recursed on a simple control type\n");
return invalid_control;
}
if (current_body > current_cmd->body_count)
{
error ("Allocated body is smaller than this command type needs\n");
return invalid_control;
}
/* Read lines from the input stream and build control structures. */
while (1)
{
dont_repeat ();
next = NULL;
val = read_next_line (&next);
/* Just skip blanks and comments. */
if (val == nop_command)
continue;
if (val == end_command)
{
if (current_cmd->control_type == while_control
|| current_cmd->control_type == if_control)
{
/* Success reading an entire control structure. */
ret = simple_control;
break;
}
else
{
ret = invalid_control;
break;
}
}
/* Not the end of a control structure. */
if (val == else_command)
{
if (current_cmd->control_type == if_control
&& current_body == 1)
{
realloc_body_list (current_cmd, 2);
current_body = 2;
child_tail = NULL;
continue;
}
else
{
ret = invalid_control;
break;
}
}
if (child_tail)
{
child_tail->next = next;
}
else
{
/* We have just read the first line of the child's control
structure. From now on, arrange to throw away the line
we have if we quit or get an error. */
body_ptr = current_cmd->body_list;
for (i = 1; i < current_body; i++)
body_ptr++;
*body_ptr = next;
tmp_chains = make_cleanup (free_command_lines, body_ptr);
if (!old_chains)
old_chains = tmp_chains;
}
child_tail = next;
/* If the latest line is another control structure, then recurse
on it. */
if (next->control_type == while_control
|| next->control_type == if_control)
{
control_level++;
ret = recurse_read_control_structure (next);
control_level--;
if (ret != simple_control)
break;
}
}
dont_repeat ();
if (ret == invalid_control && old_chains)
do_cleanups (old_chains);
else if (old_chains)
discard_cleanups (old_chains);
return ret;
}
/* Read lines from the input stream
and accumulate them in a chain of struct command_line's
which is then returned. */
@ -1491,54 +1962,71 @@ command_line_input (prrompt, repeat, annotation_suffix)
struct command_line *
read_command_lines ()
{
struct command_line *first = 0;
register struct command_line *next, *tail = 0;
register char *p, *p1;
struct cleanup *old_chain = 0;
struct command_line *head, *tail, *next;
struct cleanup *old_chain;
enum command_control_type ret;
enum misc_command_type val;
head = tail = NULL;
old_chain = NULL;
while (1)
{
dont_repeat ();
p = command_line_input ((char *) NULL, instream == stdin, "commands");
if (p == NULL)
/* Treat end of file like "end". */
break;
val = read_next_line (&next);
/* Ignore blank lines or comments. */
if (val == nop_command)
continue;
if (val == end_command)
{
ret = simple_control;
break;
}
if (val != ok_command)
{
ret = invalid_control;
break;
}
if (next->control_type == while_control
|| next->control_type == if_control)
{
control_level++;
ret = recurse_read_control_structure (next);
control_level--;
if (ret == invalid_control)
break;
}
/* Remove leading and trailing blanks. */
while (*p == ' ' || *p == '\t') p++;
p1 = p + strlen (p);
while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--;
/* Is this "end"? */
if (p1 - p == 3 && !strncmp (p, "end", 3))
break;
/* No => add this line to the chain of command lines. */
next = (struct command_line *) xmalloc (sizeof (struct command_line));
next->line = savestring (p, p1 - p);
next->next = 0;
if (tail)
{
tail->next = next;
}
else
{
/* We just read the first line.
From now on, arrange to throw away the lines we have
if we quit or get an error while inside this function. */
first = next;
old_chain = make_cleanup (free_command_lines, &first);
head = next;
old_chain = make_cleanup (free_command_lines, &head);
}
tail = next;
}
dont_repeat ();
/* Now we are about to return the chain to our caller,
so freeing it becomes his responsibility. */
if (first)
discard_cleanups (old_chain);
return first;
if (head)
{
if (ret != invalid_control)
{
discard_cleanups (old_chain);
return head;
}
else
do_cleanups (old_chain);
}
return NULL;
}
/* Free a chain of struct command_line's. */
@ -1549,9 +2037,17 @@ free_command_lines (lptr)
{
register struct command_line *l = *lptr;
register struct command_line *next;
struct command_line **blist;
int i;
while (l)
{
if (l->body_count > 0)
{
blist = l->body_list;
for (i = 0; i < l->body_count; i++, blist++)
free_command_lines (blist);
}
next = l->next;
free (l->line);
free ((PTR)l);
@ -1718,7 +2214,7 @@ define_command (comname, from_tty)
c = lookup_cmd (&tem, cmdlist, "", -1, 1);
if (c && !STREQ (comname, c->name))
c = 0;
if (c)
{
if (c->class == class_user || c->class == class_alias)
@ -1751,7 +2247,7 @@ define_command (comname, from_tty)
comname = savestring (comname, strlen (comname));
/* If the rest of the commands will be case insensitive, this one
/* If the rest of the commands will be case insensitive, this one
should behave in the same manner. */
for (tem = comname; *tem; tem++)
if (isupper(*tem)) *tem = tolower(*tem);
@ -1763,6 +2259,7 @@ End with a line saying just \"end\".\n", comname);
gdb_flush (gdb_stdout);
}
control_level = 0;
cmds = read_command_lines ();
if (c && c->class == class_user)
@ -2193,7 +2690,7 @@ show_commands (args, from_tty)
/* The next command we want to display is the next one that we haven't
displayed yet. */
num += Hist_print;
/* If the user repeats this command with return, it should do what
"show commands +" does. This is unnecessary if arg is null,
because "show commands +" is not useful after "show commands". */
@ -2246,7 +2743,7 @@ int info_verbose = 0; /* Default verbose msgs off */
/* Called by do_setshow_command. An elaborate joke. */
/* ARGSUSED */
static void
static void
set_verbose (args, from_tty, c)
char *args;
int from_tty;
@ -2254,7 +2751,7 @@ set_verbose (args, from_tty, c)
{
char *cmdname = "verbose";
struct cmd_list_element *showcmd;
showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
if (info_verbose)
@ -2341,7 +2838,7 @@ static void
init_main ()
{
struct cmd_list_element *c;
#ifdef DEFAULT_PROMPT
prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
#else
@ -2352,7 +2849,7 @@ init_main ()
command_editing_p = 1;
history_expansion_p = 0;
write_history_p = 0;
/* Setup important stuff for command line editing. */
rl_completion_entry_function = (int (*)()) symbol_completion_function;
rl_completer_word_break_characters = gdb_completer_word_break_characters;
@ -2401,7 +2898,7 @@ until the next time it is started.", &cmdlist);
"Set gdb's prompt",
&setlist),
&showlist);
add_com ("echo", class_support, echo_command,
"Print a constant string. Give string as argument.\n\
C escape sequences may be used in the argument.\n\
@ -2447,7 +2944,7 @@ when gdb is started.", &cmdlist);
add_show_from_set (c, &showlist);
c->function.sfunc = set_verbose;
set_verbose (NULL, 0, c);
add_show_from_set
(add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
"Set editing of command lines as they are typed.\n\
@ -2518,6 +3015,19 @@ the previous command number shown.",
add_cmd ("version", no_class, show_version,
"Show what version of GDB this is.", &showlist);
add_com ("while", class_support, while_command,
"Execute nested commands WHILE the conditional expression is non zero.\n\
The conditional expression must follow the word `while' and must in turn be\
followed by a new line. The nested commands must be entered one per line,\
and should be terminated by the word `end'.");
add_com ("if", class_support, if_command,
"Execute nested commands once IF the conditional expression is non zero.\n\
The conditional expression must follow the word `if' and must in turn be\
followed by a new line. The nested commands must be entered one per line,\
and should be terminated by the word 'else' or `end'. If an else clause\
is used, the same rules apply to its nested commands as to the first ones.");
/* If target is open when baud changes, it doesn't take effect until the
next open (I think, not sure). */
add_show_from_set (add_set_cmd ("remotebaud", no_class,